opnsense / core

OPNsense GUI, API and systems backend
https://opnsense.org/
BSD 2-Clause "Simplified" License
3.27k stars 727 forks source link

NPTv6: add dynamic source addresses via track interface #5284

Closed bimbar closed 1 year ago

bimbar commented 2 years ago

Important notices

Before you add a new report, we ask you kindly to acknowledge the following:

Is your feature request related to a problem? Please describe.

The problem hear is small site multihoming. It's very nicely described here: https://blog.ipspace.net/2010/12/small-site-multihoming-in-ipv6-mission.html and can pretty much only be done with local ULA addresses and some sort of address translation toward the WAN interfaces. Right now it can only be done via NA(P)T66, which is the very same as NA(P)T44, and I don't think we want that anymore. Now the implementation problem with it is that with NAT you can do the following:

nat on WAN inet6 from SOME_IP_RANGE to any -> (WAN:0) port 1024:65535

while with NPT (binat) you have to specify a source and a destination network, so some sort of integration into interface newwanipv6 will be necessary.

Describe the solution you like

I would like a "Track Interface" External IPv6 Prefix Option in addition to static External IPv6 Prefix in NPTv6, pretty much just like it is in the interface configuration dialog. Specified would be:

Describe alternatives you considered

Oh so many ones, but none of them work. The best one in clean IPv6 terms so far is to use two independent routers each with their own GUA prefixes which the independently advertise into LAN, only that works only if RFC3484bis is implemented or asymmetric routing is achieved. The one that works is to just do it like in IPv4, with local addresses for LAN, and NA(P)T on the outside interface, but that's hardly the right solution.

Additional context

There's even a very nice RFC for that, namely https://datatracker.ietf.org/doc/html/rfc7157 "IPv6 Multihoming without Network Address Translation" but even they concede that NPTv6 is probably needed for now. For static prefixes this should work nicely with static NPTv6, but if the prefixes are dynamic, it falls down.

bimbar commented 2 years ago

But I'm not sure if that's even possible, it depends on the dhcpcv6 daemon telling someone which prefixess it was assigned.

cnbatch commented 2 years ago

Indeed, this feature should be fully supported by OPNSense ASAP.

FreeBSD itself supports such operation with IPFW, see the part of 'IPv6-to-IPv6 NETWORK PREFIX TRANSLATION (NPTv6)': https://www.freebsd.org/cgi/man.cgi?query=ipfw&sektion=8&format=html

This feature was added on Oct 30 2018: https://reviews.freebsd.org/D17765 by https://github.com/opnsense/core/issues/2544#issuecomment-797369686

One can use a command like ipfw nptv6 NPT create int_prefix fd24:ca16:8eb0:5ab6:: ext_if em0 prefixlen 64 to create NPTv6 mappings and let the system monitor the change of IPv6 addresses.

This IPFW feature can also be used in command line console of OPNSense, but not yet supported in Web Interface.

AdSchellevis commented 2 years ago

we use pf(4) (https://www.freebsd.org/cgi/man.cgi?pf(4)), sounds similar to https://github.com/opnsense/core/issues/4923, waiting for someone to properly document the feature (https://github.com/opnsense/docs/pull/330#issuecomment-839531339) before any code will be merged.

bimbar commented 2 years ago

Not quite the same, the one is about dynamic firewall rules, the other about dynamic NPTv6 rules

AdSchellevis commented 2 years ago

which is about the same concept, addresses should follow dynamic addresses for which aliases might be used.

bimbar commented 2 years ago

It likely needs much the same infrastructure in the backend.

marjohn56 commented 2 years ago

@bimbar - dhcp6c puts the GUA address on the interface, so you can get the prefix from the GUA address. The trick I think, if I understand NPTv6 correctly - Only looked at this 30 minutes ago - is to assign a ULA address to the interface ( alias is there for that already ) and to use dhcpdv6 and radvd to hand out ULA addresses on the LAN(s). Once you have that done, then would it possible to just NPTv6 the LAN ULA addresses to the GUA prefix for that interface?

bimbar commented 2 years ago

The prefix for the WAN interface is different from the prefix we need. Also, this prefix is not going to be set on any interface. It's not that simple.

marjohn56 commented 2 years ago

You misunderstood me I think. I am talking about the LAN(s) not the WAN. dhcp6c assigns the addresses to the interfaces, the GUAs that is. I quote you

But I'm not sure if that's even possible, it depends on the dhcpcv6 daemon telling someone which prefixess it was assigned.

That information is already available, In /tmp there is also another file, my wan is igb0, therefore the file is called igb0_pdinfo, that will give you the prefix and size. If it's any use I also have a versiion of dhcp6c that will give you the prefix that is assigned to the LANs, but as I said, that info is aleady available.

bimbar commented 2 years ago

Ok, so I have a hypothetical LAN interface with Track Interface WAN and offset 4. Now I want NPTv6 to translate the source prefix to the prefix this hypothetical interface would have been assigned (but it has been given a ULA prefix).

marjohn56 commented 2 years ago

It will also have been given a GUA address, you cannot stop dhcp6c doing that - unles we have some sort of virtual interface, but that's a different story. You can add an Alias to give a ULA address, BUT, dhcp6d and Radvd will give out the GUA addresses. If that was altered so that they gave out the ULA addresses then packets coming back to the LAN interface would have ULA addresses and, in theory, would hit the NPTv6 rule.

bimbar commented 2 years ago

Why can I not stop dhcp6c giving out GUAs? I can configure the interface with static IPv6 ULA. Giving out GUAs makes the whole feature redundant.

marjohn56 commented 2 years ago

Just messing around to prove a point..

So I am using Track Interface, my test router has GUA prefixes on its LANs.. All OK I added a VIP to the LAN of the test router using a ULA address. dhcpdv6 on that interface is disabled, I have also commented out the relevent parts of dhcpd.inc so that no GUA addresses are given out, but ULA ones are, this is what radvd.conf looks like:

interface igb1 { AdvSendAdvert on; MinRtrAdvInterval 200; MaxRtrAdvInterval 600; AdvLinkMTU 1500; AdvDefaultPreference medium; prefix fc01:1::/64 { DeprecatePrefix off; AdvOnLink on; AdvAutonomous on; }; RDNSS 2a02:6b67:605d:3200:4262:31ff:fe00:c1b0 { }; DNSSL localdomain { }; }; It's still using the RDNSS but that doesn't matter in this case.

Then I added an NPTv6 entry, using the GUA /64 prefix from the test router LAN. WAN interface selected. My PC I set to pick up a dhcp6 address and looks like this:

Ethernet adapter traceLAN Test:

Connection-specific DNS Suffix . : localdomain IPv6 Address. . . . . . . . . . . : fc01:1::2e0:4cff:fe67:7b54 Temporary IPv6 Address. . . . . . : fc01:1::c9a6:14fc:c5b:207c Link-local IPv6 Address . . . . . : fe80::2e0:4cff:fe67:7b54%17 IPv4 Address. . . . . . . . . . . : 192.168.1.100 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : fe80::4262:31ff:fe00:c1b0%17 192.168.1.1

And the result is:

C:\Users\marti>tracert -6 www.google.com

Tracing route to www.google.com [2a00:1450:4009:817::2004] over a maximum of 30 hops:

1 <1 ms <1 ms <1 ms OPNsense.localdomain [fc01:1::1] <- test router LAN 2 <1 ms <1 ms <1 ms xxxx:xxxx:605d:0:20e:c4ff:fed2:8143 <- Primary router LAN 3 2 ms 1 ms 2 ms xxxx:xxxx:0:89::1 <- Upstreeam 4 2 ms 2 ms 2 ms 2a02:6b60:0:1:2::66 5 2 ms xge-0-0-0-8.edge1.ld8.lon.network.as201838.net [2a02:6b60:0:1:1::66] 6 3 ms 3 ms 2 ms 2a02:6b60:0:1:3::62 7 2 ms 2a00:1450:80f9::1 8 2 ms 2 ms 2 ms 2001:4860:0:1::41aa 9 2 ms 2001:4860:0:1::248b 10 2 ms 1 ms 1 ms lhr25s26-in-x04.1e100.net [2a00:1450:4009:817::2004]

Trace complete.

So it works, perfectly possible to use the GUA Prefix on the LAN. And If instead of using an address as the external prefix it could use an alias, in the same way as the firewall rules we were working on earlier this year, then that would solve a few problems.

marjohn56 commented 2 years ago

Let's take this a step further. I see the need for the following:

@fichtner & @AdSchellevis - Does this fit the bill?

bimbar commented 2 years ago

Now I'm confused, as far as I can see in your example, you have no GUA prefix on LAN, but only an ULA prefix, yet you write in you conclusion that a GUA prefix on LAN works perfectly.

Anyway, what you tested is pretty much what I was thinking of, only you want to sort of virtually assign the GUA prefix to LAN while not advertising it, which would also be a way to implement it, I guess.

marjohn56 commented 2 years ago

That LAN is my PC's LAN, not the LAN of the router. That looks like this. Note I've change the ULA address to fc00 since yesterday.

igb1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=802028<VLAN_MTU,JUMBO_MTU,WOL_MAGIC> ether 40:62:31:00:c1:b0 inet6 fe80::4262:31ff:fe00:c1b0%igb1 prefixlen 64 scopeid 0x2 inet6 fc00:1::1 prefixlen 64 inet6 xxxx:xxxx:3200:4262:31ff:fe00:c1b0 prefixlen 64 inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255 media: Ethernet autoselect (1000baseT ) status: active nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>

It's the way I'd prefer to do it. It makes life much simpler IMHO.

bimbar commented 2 years ago

@bimbar - dhcp6c puts the GUA address on the interface, so you can get the prefix from the GUA address. The trick I think, if I understand NPTv6 correctly - Only looked at this 30 minutes ago - is to assign a ULA address to the interface ( alias is there for that already ) and to use dhcpdv6 and radvd to hand out ULA addresses on the LAN(s). Once you have that done, then would it possible to just NPTv6 the LAN ULA addresses to the GUA prefix for that interface?

Going back to your initial statement, I get what you want to do there, but, if you have a GUA and an ULA on the LAN, but advertise only the ULA, and translate that over to the GUA, what use is it to configure said GUA on LAN if it's not used. It's only used as a NAT pool and as such should not be configured on any real interface.

marjohn56 commented 2 years ago

What about ISPs that don't give a GUA on the WAN? What if you want multiple LANs etc? The fact is yes you can get the prefix and size from a file that dhcp6c already creates, but the ability to NPTv6 to the GUA on the same LAN makes it simpler in other ways too. There are many ways to skin a cat.

bimbar commented 2 years ago

What about ISPs that don't give a GUA on the WAN? What if you want multiple LANs etc? The fact is yes you can get the prefix and size from a file that dhcp6c already creates, but the ability to NPTv6 to the GUA on the same LAN makes it simpler in other ways too. There are many ways to skin a cat.

You don't understand, instead of configuring some interface as "Track Interface WAN offset 1", you would configure the NPTv6 Destination Prefix as "Track Interface WAN offset 1".

marjohn56 commented 2 years ago

I DO understand I just see benefits of using the real interface. I am well aware that if you know the prefix that's been obtained you could just use that.

ivwang commented 2 years ago

Let's take this a step further. I see the need for the following:

  • Ability to only enable ULA address handouts in dhcpdv6 and radvd.
  • Ability to select the LAN GUA prefix ( as an alias ) in NPTv6
  • Abillity to select the LAN ULA prefix in NPTv6

@fichtner & @AdSchellevis - Does this fit the bill?

This really sounds nice and what I am looking forward to have. Any chance to see it in next few releases? Finger crossed.

Thanks Ivan.

AdSchellevis commented 2 years ago

(from https://github.com/opnsense/core/issues/5284#issuecomment-947566519) we use pf(4) (https://www.freebsd.org/cgi/man.cgi?pf(4)), sounds similar to https://github.com/opnsense/core/issues/4923, waiting for someone to properly document the feature (https://github.com/opnsense/docs/pull/330#issuecomment-839531339) before any code will be merged.

As long as any change in this area fits the boundaries given earlier, I don't mind that much, I just would advise to keep it simple.

We all seem to get lost in this region quickly, which is only solvable if anything we do add will be explained unambiguously.

Speaking for myself (and likely @fichtner as well), I'm not planning to spend time on this before it's absolutely clear, already spend quite some time preparing everything in https://github.com/opnsense/core/tree/FR_4923, after which everything kept circling back.

bimbar commented 2 years ago

I'd propose merging some implementation of something soon, rather than wait for something perfect which may never come.

All with the understanding it may change completely as soon as its shortcomings are understood.

But if nothing is merged, there is no base which can be argued in a wider audience.

Release early, release often.

AdSchellevis commented 2 years ago

Not if the fundamentals are unclear, it's rather simple, someone should write it down (design) before starting to build anything, to prevent future issues impossible to fix further down the road. We spend years refactoring a lot of madness and believe me, trouble starts with vague objectives.

bimbar commented 2 years ago

Well, there's enough ideas, someone ultimately has to decide what to actually do.

ivwang commented 2 years ago

Is it possible to first develop Martin's implementation into a plugin, as a mean to discover what is lacking (if any) down the road?

For my use-case, it's primarily to deploy opnsense and IPv6 reliably with upstream ISPs changing IPv6 PD assignment frequently, in that Insulating LAN side address ranges from those ISPs by NPT and ULA.

So Martin's implementation that

  1. enables dhcp6d/radvd to advertise ULA
  2. allows user to specify NPT by mapping between ULA prefix and IPv6 PD (tracking WAN)
  3. refreshes NPT translation rules automatically when tracked IPv6 PDs are changed. fits the bill. If anything not explicitly stated, is that assigning ULA directly to LAN side physical interfaces without the need to create a virtual one.

Thanks Ivan.

AdSchellevis commented 2 years ago

Is it possible to first develop Martin's implementation into a plugin, as a mean to discover what is lacking (if any) down the road?

I assume you mean the work me and Martin did which is waiting in https://github.com/opnsense/core/tree/FR_4923, but no, you can't easily move that to a plugin as you don't have anything to plug it into. (yes, you can develop a plugin offering this functionality, but I don't expect anyone would like to spend the amount of time needed to convert this to a stand-alone feature).

As soon as the concerns in the doc's PR are cleared (https://github.com/opnsense/docs/pull/330), we can start moving code in, as I've mentioned earlier as well.

marjohn56 commented 2 years ago

@AdSchellevis - No, he means the ability to select an address range to use within dhcpdv6. At present you can only create one range within dhcpdv6 / radvd, thus is you use tracking you can overide and make your own range but if you have a ULA alias on that inferface you cannot use that, as the existing code picks the GUA. What it would need is the ability to force the range entered so that the sanity check is overridden. I do not see the need to be able to have both ULA and GUA ranges handed out by dhcpdv6, but where both exist on an interface, then the ability to select or specify the range would be useful. I did a bit of hacking and forced the ULA in dhcpdv6 then used NATv6 to translate the ULA to the GUA prefix on the LAN, it worked nicely. It sort of comes back to being able to track the GUA again and automagically compensate for a changing pd.

AdSchellevis commented 2 years ago

@marjohn56 ok, clear, sounds like a no as well when it comes to building a plugin.

marjohn56 commented 2 years ago

Yes agreed, but I'm working on a simpler solution... Really, it's just a case of being able to override the auto prefix addition that happens when using override on the tracked interface. So that's the path I am taking, I'm playing with it later this afternoon as it happens.

marjohn56 commented 2 years ago

OK, this is starting to look possible. I'm going to show some snapshots of how I have it looking. It all works but I'll try and explain it too, I think @fichtner would probably want to tidy it up, but the principle seems to work fine. Firstly, this is purely for tracking interfaces, there is no point in this for any other type. So let me explain what needs to happen first. You need to assign a VIP to the LAN interface involved, so it's a tracking interface with a VIP added, that VIP should be a ULA address.

That being done, when you open the dhcpdv6 settings for that interface you would see this: image

You'll see there is now some extra info and an extra checkbox. The checkbox tells the system to use the VIP settings rather than the track settings. If there was no VIP on the interface, those extra items would not be visible. There are no other interface changes. The code behind handles the writing of the dhcpdv6.conf and radvd.conf.

As you can see the GUA's are still there on the interface, but the addresses are not handed out by radvd or dhcpdv6, only the ULA addresses are. This sort of ties up nicely with the work we've been doing on the IPv6 Host Alias. Where you could use that alias to NPTv6 to a ULA address on the LAN. So you have the option, either ULA and a tracking alias or just the GUA Alias as a firewall entry.

TheRealBecks commented 2 years ago

I think you're talking about exactly that feature that many people in Germany need, because many providers change IPv4 addresses and IPv6 prefixes once a day. So my problem seems to be discussed here, but I also found some (annoyance) on my provider router:

WAN 1: GUA/56 static WAN2: GUA/62 dynamic (yes, only 62!) LAN: ULA/64

The static NPT rules for LAN <-> WAN1 is already working perfectly, but the problem is the dynamic one for WAN2. I currently have to create a static NPT rule and change the GUA prefix once a day. Another problem here is that I get the first GUA/64 prefix ("GUA/64 prefix #1") as IPv6 address/prefix on the WAN2 interface, but have to provide an unused one for the NPT rule, so let's say I have to choose "GUA/64 prefix #2". If you implement a dynamic NPT rule the OPNsense needs to pick prefix #2 itself.

Now my provider router comes into play. Have in mind that I get a GUA/62, so can use 4x /64 in total: "GUA/64 prefix #1": Will be used by WAN2 "GUA/64 prefix #2": Is already in use by the provider router internally! Can't be used by OPNsense "GUA/64 prefix #3": Needs to be used for the dynamic NPT rule "GUA/64 prefix #4": free

So I have to use "GUA/64 prefix #3" on the OPNsense NPT gui. Please keep that in mind, because there needs to be a way to pick the 2nd, 3rd, 4th... prefix from the GUA prefix.

(...or is it that the 'offset' you already talked about?)

+1 for this feature, thanks! :)

marjohn56 commented 2 years ago

@fichtner - I'll PR this then we can play with it.

fichtner commented 2 years ago

@marjohn56 I thought this was done... that's why I tagged it?

marjohn56 commented 2 years ago

(...or is it that the 'offset' you already talked about?)

It isn't and it means I'll need to add a drop down selector for the ULA's. I have to say though that because we have completed the tracking dynamic fw rule , this may no longer be needed, but we'll play on. @fichtner - no, not issued a PR yet as I was waiting for feedback on the image I shared above - Is it the way to go?

fichtner commented 2 years ago

@marjohn56 ok I'm moving it to community milestone. Did not want to force a solution for 22.1 as I know you are typically busy. Take your time.

marjohn56 commented 2 years ago

No, we don't need a dropdown, it pulls the ULA from what is assigned to the interface, so it's good. I'll PR it for play and discussion.

marjohn56 commented 2 years ago

@fichtner - #5408

TheRealBecks commented 2 years ago

Any update on this?

fichtner commented 2 years ago

@TheRealBecks Can you be more specific on "any" that's not clear from this issue history?

TheRealBecks commented 2 years ago

@fichtner I don't know. I just need support for dynamic IPv6 GUA addresses that can be used with NPT, because my provider changes the /62 prefix every 24 h. And from that /64 I have to use the third of fourth /64 prefix for NPT as I wrote here. That's a must-have-killer-feature for all German users and FritzBox users that have more than one internet connection (e.g. dual-home-setup).

dlasher commented 2 years ago

Just wanted to add some support to this feature.. As others have correctly summarized, the status of IPv6 is a bit hit-and-miss (with broadband providers), and being able to use NAT66/NPTv6 would push IPv6 adoption on the desktop, while allowing the intelligent firewall to buffer for carrier changes, route changes, address assignment changes etc.

My primary gives IPv6 via DHCPv6, but it randomly stops working for weeks at a time. My secondary gives IPv6 via 6RD, which is incompatible with track, so can't be used (at this time) for NPTv6. HE tunnels work like a charm, have static assignments, can be mapped with NPTv6, and just work.. .would be nice to be able to use the V6 provided by either my primary or my secondary.

+1 - to @ivwang 's suggestion above.. we need both #2 and #3. Right now I have to go hand update the NPT rules every time "primary" changes their IP range. (would for secondary if that worked)


  1. allows user to specify NPT by mapping between ULA prefix and IPv6 PD (tracking WAN)
  2. refreshes NPT translation rules automatically when tracked IPv6 PDs are changed.
ivwang commented 2 years ago

Checking in after a while, it looks like pfSense implements a similar recently https://redmine.pfsense.org/issues/4881 Although its implementation allows mapping multiple internal ipv6 subnet to a single global prefix, which I personally do not prefer, as non-standard ipv6 subnetting may complicate things.

christiankratzer commented 2 years ago

Yes definitely waiting for this as well. Consumer ISPs here in Germany have the habit of dealing out dynamic prefixes which is a mess to manage internally.

bimbar commented 2 years ago

If the objective is just to use a whole network in a firewall rule (which uses GUA handed down by DHCPv6), this might already be possible by the use of the Alias type "Internal (automatic)"

christiankratzer commented 1 year ago

The objective is to be able to hand out static prefixes on the inside and nat to dynamically learned prefix on the wan. Without forcing the dynamic prefix on the WAN interface to the LAN interfaces.

fichtner commented 1 year ago

So for dynamic prefixes is there even any sense to use something other than /64 for the translation? I know the prefix may be bigger but the thing is we'd start natting outside of the scope of the wan interface and it might be possible to coerce pf(4) to accept the automatic :network address if we stick to /64.

fichtner commented 1 year ago

Ok so perhaps someone wants to try:

# opnsense-patch 32c783ca b7a9d0b4 f7e64baa5 17ec3264a

Leave external address empty...

OPNsense-bot commented 1 year ago

This issue has been automatically timed-out (after 180 days of inactivity).

For more information about the policies for this repository, please read https://github.com/opnsense/core/blob/master/CONTRIBUTING.md for further details.

If someone wants to step up and work on this issue, just let us know, so we can reopen the issue and assign an owner to it.

ivwang commented 1 year ago

This is indeed a great addition. So I take it out for a spin, however, I am not quite sure I configure it right. The NPTv6 prefix "sort-of" works in my setup.

Here is the thing, my ISP assigns an IPv6 /64 GUA to opnsense's wan and delegates a dynamic /64 prefix, this is typical and the prefix my lan interface uses by "tracking interface wan"

After patching, I changed my lan to static IPv6 ULA then under Firewall > NAT > NPTv6 added a rule on wan interface with lan's /64 ULA prefix as internal prefix and left external prefix empty.

Then checking test-ipv6.com from one of the lan hosts indeed gets through since the lower 64-bit of ipv6 address shown by test-ipv6.com matches that of lan host's ULA, however, the prefix is the prefix from the /64 GUA on wan instead of the supposedly delegated /64 prefix.

it looks like I missed something, any thoughts?

Thanks a lot