opnsense / core

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

interfaces: allow tracking the WAN itself in DHCPv6 mode #5630

Closed meyergru closed 4 months ago

meyergru 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. When using dhcp6c over a PPPoE link, if the ISP hands out IPv6 prefixes only, but no IPv6 interface address (i.e. "send ia-na 0" is not honored), the WAN interface gets no IPv6 assignment at all. Thus, one is limited to the IPv6 addresses of other interfaces that use "track6".

However, without an IPv6 on the WAN interface, FreeBSD does not honor the "highest address" rule of IPv6 in case that several other IPv6 addresses are available for use as a source address. Thus, you basically have no control over which interface's address will get used for outgoing connections from the firewall itself - e.g., assigning a higher IPv6 prefix ID does nothing.

If you register with a dynamic DNS service, you probably want to identify the IPv6 prefix for a specific VLAN interface. The prefix will be arbitrary, though.

Describe the solution you'd like It would be nice if track6 and dhcp6c were not mutually exclusive. If the interface configuration that originates from "track6" could also be generated for "dhcp6c" via a GUI checkbox, one could hand out an IPv6 prefix to the WAN interface even if the ISP does not offer a separate IPv6 for the interface itself. In that case, the WAN IPv6 would get used unconditionally before any other IPv6 addresses.

Describe alternatives you've considered I can see no option to assign IPv6 to the WAN interface in this situation.

Additional context It would also be nice to be able to use IPv6 privacy extensions from the firewall itself. This is not possible with dhcp6c or track6, I believe.

fichtner commented 2 years ago

I think that's what "advanced" is for... check "Identity Association" section of the settings.

meyergru commented 2 years ago

When I use that, the section for "id-assoc pd 0" still does not contain the WAN interface. The content of that section is exactly described by all interfaces that use "track6". I can only modify the sla-len, but not the interfaces listed there.

fichtner commented 2 years ago

Shouldn't you set "Non-Temporary Address Allocation" here for WAN? The prefix (pd) is intended for downstream devices only according to the code.

meyergru commented 2 years ago

Correct. That is my point. My ISP (M-Net) does not honor "send ia-na 0". They give out only a /56 prefix via "send ia-pd 0", but not an additional IPv6 for the PPPoE interface itself. Thus, it would be nice to use part of the prefix range for the PPPoE interface, like I can for all other interfaces. Currently, this is impossible because I cannot use both "track6" and "dhcpc6" for WAN.

fichtner commented 2 years ago

However, without an IPv6 on the WAN interface, FreeBSD does not honor the "highest address" rule of IPv6 in case that several other IPv6 addresses are available for use as a source address.

How is this tested locally on the command line? I'm happy to test.

meyergru commented 2 years ago

I have multiple VLAN interfaces that use track6, like so:

ax0_vlan107: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        description: IOT
        options=4000300<TSO4,TSO6,NOMAP>
        ether f4:90:ea:00:74:49
        inet 192.168.107.1 netmask 0xffffff00 broadcast 192.168.107.255
        inet6 2001:a62:3bbb:207:f690:eaff:fe00:7449 prefixlen 64
        inet6 fe80::f690:eaff:fe00:7449%ax0_vlan107 prefixlen 64 scopeid 0xc
        groups: vlan RESTRICTED
        vlan: 107 vlanproto: 802.1q vlanpcp: 0 parent interface: ax0
        media: Ethernet autoselect (10GBase-SFI <full-duplex,rxpause,txpause>)
        status: active
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
ax0_vlan4: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        description: GAST
        options=4000300<TSO4,TSO6,NOMAP>
        ether f4:90:ea:00:74:49
        inet 192.168.4.1 netmask 0xffffff00 broadcast 192.168.4.255
        inet6 2001:a62:3bbb:204:f690:eaff:fe00:7449 prefixlen 64
        inet6 fe80::f690:eaff:fe00:7449%ax0_vlan4 prefixlen 64 scopeid 0xd
        groups: vlan RESTRICTED
        vlan: 4 vlanproto: 802.1q vlanpcp: 0 parent interface: ax0
        media: Ethernet autoselect (10GBase-SFI <full-duplex,rxpause,txpause>)
        status: active
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
ax0_vlan5: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        description: DMZ
        options=4000300<TSO4,TSO6,NOMAP>
        ether f4:90:ea:00:74:49
        inet 192.168.5.1 netmask 0xffffff00 broadcast 192.168.5.255
        inet6 2001:a62:3bbb:205:f690:eaff:fe00:7449 prefixlen 64
        inet6 fe80::f690:eaff:fe00:7449%ax0_vlan5 prefixlen 64 scopeid 0xe
        groups: vlan RESTRICTED
        vlan: 5 vlanproto: 802.1q vlanpcp: 0 parent interface: ax0
        media: Ethernet autoselect (10GBase-SFI <full-duplex,rxpause,txpause>)
        status: active
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>

My WAN interface has no routable IPv6:

pppoe0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> metric 0 mtu 1492
        description: WAN
        inet6 fe80::f690:eaff:fe00:7446%pppoe0 prefixlen 64 scopeid 0xf
        inet 188.174.51.22 --> 82.135.16.28 netmask 0xffffffff
        nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>

When I try: "curl https://api64.ipify.org", I see:

2001:a62:3bbb:205:f690:eaff:fe00:7449

which is clearly ax0_vlan5 instead of ax0_vlan7, which has a higher IPv6 because I chose 0x07 as the IPv6 Prefix ID for that interface. This is considered general IPv6 behaviour, but not in FreeBSD, see 8.1.1.6, case 3, here: https://docs.freebsd.org/de/books/developers-handbook/ipv6/ . In case 2, where WAN interface has an assigned IPv6, that would be preferred.

While the source cited also says that the choice between equal-ranked interfaces is "up to implementation", it clearly should not be:

https://datatracker.ietf.org/doc/html/rfc6724#page-11

The source address selection should be the highest IPv6 - at least that is what I understood. I have not yet found which interface gets selected, probably the last one assigned? At least I have found no way to influence the choice. This would never be neccessary if PPPoE gets an IPv6 address...

fichtner commented 2 years ago

Looking at https://reviews.freebsd.org/D709 ifconfig supports prefer_source. Have you tried this yet?

Apart from right or wrong I'm still a bit unsure what should be achieved from this. You don't know which interface will take the address / the wrong interfaces takes the address you prefer? If yes, the above could help fix that.

meyergru commented 2 years ago

Yes, I found that one, too. However, it works only if you already know the IPv6, you cannot "prefer_source" an interface by name. So, I cannot do assign the attribute automatically - or this would have to be integrated into OpnSense scripts.

And: yes. I would like to control which address / interface calls out. That way, you could provide to have dyndns for devices behind the firewall (by just changing the prefix part and leaving the hardware part unchanged). OpnSense would do the dyndns updates and devices become addressable over the internet.

This would offer a means to have something like port forwarding, but with IPv6 for ISPs that support only DS-Lite or CGNAT. I guess one could use 72 bits (i.e. 8 Bits Prefix ID plus 64 Bits hardware part) instead as fixed and only modify the /56 Prefix.

fichtner commented 2 years ago

I see your point but it looks like our hands are a bit tied with regard to what the OS is actually offering here. I'm not convinced that tainting the WAN with a PD-subnet is the best course of action.

Another approach would be to add prefix expansion to VIPs (it was discussed a bit last year) which could add the prefer_source flag reliably. Still the prefix merge for a VIP is a little opportunistic since we don't know when a prefix/address appears and when it goes away (indirectly yes but also not 100% reliable).

Cheers, Franco

meyergru commented 2 years ago

But "tainting the WAN with a PD-subnet" with prefix ID 0x00 is exactly what an AVM Fritzbox does as a fallback (see https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/IPv6_Technical_Note_de.pdf at the end of page 4):

  1. An attempt is made to derive the WAN address from the provider's router advertisement. If information about DNS servers is available in the router advertisement (RFC 5006), this is adopted.
  2. Then, a globally valid prefix (IA_PD) for the home network is requested via DHCPv6. If no global WAN address could be determined for the FRITZ!Box in step 1, such an address is now requested via DHCPv6 (IA_NA). DNS and NTP servers are also requested via DHCPv6 (DNS_SERVERS, NTP_SERVER), if none are known from step 1.
  3. If still no WAN address is known, the first /64 network from the assigned LAN prefix is used for the WAN interface of the FRITZ!Box.

M-Net does neither offer 1 nor honor 2, and OpnSense does not allow 3 - easy as that.

In Germany, there seems to be at least one other ISP like M-Net who does not offer IA_NA: https://forum.openwrt.org/t/solved-how-to-configure-ipv6-pppoe-connectivity/36923

I think a checkbox option to "track6" the dhcp6c interface would be the way to go. That way, the weakness of those providers could be circumvented. AVM does just that, albeit not as an option but automatically. I admit that one still has to go the route of having a fixed 72 Bit wide "prefix id + hardware part" in dynamic DNS in order to make devices on a VLAN with a specific prefix ID available. That in itself is kind of a problem, because limiting access to a specific host can neither be done based upon its IPv6 with dynamic prefixes nor via its MAC, see: https://forum.opnsense.org/index.php?topic=27483.0.

I guess it is difficult to impossible to open an IPv6 port on a host behind OpnSense... or maybe I am trying the wrong way.

fichtner commented 2 years ago

I guess it is difficult to impossible to open an IPv6 port on a host behind OpnSense... or maybe I am trying the wrong way.

For majority of non-business type ISP IPv6 that do not offer fixed IPv6 address/PD... yes.

meyergru commented 2 years ago

Opening up ports via IPv6 would be a nice feature for OpnSense, still (hate to think that AVM has it).

Thank you, Franco!

fichtner commented 2 years ago

Have you seen the forum reply regarding dynamic IPv6 alias yet?

I suppose we can try adding a prefix id input for WAN. It's not mandatory so that's good. We just need to see how it works in practice.I think yours and my setup should give a good baseline for viability.

meyergru commented 2 years ago

I just looked, and I repeat here what I wrote there:

My savior! How can I have overlooked that?

This type of alias is robust against NDP.

Big thanks, Franco!

Explanation as to what I was trying to accomplish: Make accessible a port of an IPv6 host behind OpnSense from the WAN side via a DNS entry. My ISP (M-Net) does not offer IPv6 IA-NA, i.e. I do not get an IPv6 on the WAN interface, but only on the LAN interface via IA-PD.

Thus, I need:

  1. A working firewall rule that is robust against IPv6 prefix changes (now I have it)
  2. Dynamic DNS that can handle a /56 prefix change, but keep the lower 72 bits of the client host (8 bits prefix-ID from "track6" of the LAN interface plus 64 bits interface id derived from the MAC). With this trick, OpnSense can do the dynamic DNS updates for any number of LAN clients and assign different names for them. That, I have too (by implementing my own DynDNS).

So, my setup works for now. To make the firewall availlable in the same way, one can use the interface part of one (V)LAN interface, but adding a prefix ID input for WAN like you suggested is even better,

fichtner commented 2 years ago

Ok, so far so good. :)

but adding a prefix ID input for WAN like you suggested is even better

I agree... let me try to propose something in a week or two (hopefully). If not gentle reminder would be nice.

Cheers, Franco

peloyeje commented 2 years ago

Hi @fichtner, Just joining this issue from #5332, +1 for the prefix ID input for WAN! Thanks, happy to help with testing if needed

fichtner commented 2 years ago

@meyergru @peloyeje

Ok so for me this doesn't work as I still only get a SLAAC address on WAN but maybe there is a mistake here still

# opnsense-patch ca2f7b0ffa 7583ce5 b34ba9a61

Cheers, Franco

kevinchalet commented 2 years ago

I gave it a try too and even after tweaking interfaces.inc to generate the prefix-interface [wan] section when advanced configuration is used, it didn't work. The generated configuration looks good to me, so maybe the issue is elsewhere? (does dhcp6c support that?)

interface re0_vlan832 {
  send ia-pd 0;
  ... other options ...
  script "/var/etc/dhcp6c_wan_script.sh";
};
id-assoc pd 0 {
  prefix-interface re0_vlan832 {
    sla-id 3;
    sla-len 8;
  };
  prefix-interface em0 {
    sla-id 0;
    sla-len 8;
  };
  prefix-interface em0_vlan111 {
    sla-id 2;
    sla-len 8;
  };
  prefix-interface em0_vlan832 {
    sla-id 1;
    sla-len 8;
  };
};
fichtner commented 2 years ago

@kevinchalet was asking myself the same question, yes. need to wait for @meyergru first and see what we can do then

meyergru commented 2 years ago

Hi Folks, I am on a vacation and can only try in a few days…

fichtner commented 2 years ago

No rush, please do enjoy your vacation :)

peloyeje commented 2 years ago

@fichtner @kevinchalet thanks for the patches! I may be doing something wrong but I can't find a way to setup the configuration options in the UI so that the generated dhcp6c conf retains all prefix-interface configuration blocks AND the raw-options...

Should I also apply the patches you mentioned in #5332?

fichtner commented 2 years ago

@peloyeje you are right the advanced section is not yet supported in this scope. I want to wait to see if it works before doing more work here.

peloyeje commented 2 years ago

@fichtner Yep you're right, sorry I'm afraid I can't help for testing at this point then, my php-fu isn't as sharp as @kevinchalet :)

kevinchalet commented 2 years ago

@fichtner Yep you're right, sorry I'm afraid I can't help for testing at this point then, my php-fu isn't as sharp as @kevinchalet :)

Haha, PHP brings back sweet memories to me (I started developing with PHP before switching to .NET 😄)

If you want to give it a try with the advanced mode enabled, you can add the following lines in interfaces.inc after line 2995:

if (isset($wancfg['dhcp6-prefix-id']) && is_numeric($wancfg['dhcp6-prefix-id'])) {
    $id_assoc_statement_prefix .= "  prefix-interface {$wanif} {\n";
    $id_assoc_statement_prefix .= "    sla-id {$wancfg['dhcp6-prefix-id']};\n";
    $id_assoc_statement_prefix .= "    sla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
    $id_assoc_statement_prefix .= "  };\n";
}

You'll need to configure the prefix ID in the "basic" tab before switching to "advanced" exactly like you did with the "only request PD" option.

But sadly, this isn't enough to make things work (it's possible we're not using the correct approach or that additional work will be required in dhcp6c).

meyergru commented 2 years ago

I tried it with just the three patches Franco mentioned. After I created a prefix id for the WAN interface (pppoe0 in my case), I got no IPv6 assignment. When I tried to find out why, I stopped dhcp6c manually, trying to restart it with debugging on, but could not (the process exits right away).

My configuration show what I would deem correct, namely an added section:

interface pppoe0 {
  send ia-pd 0; # request prefix delegation
  request domain-name-servers;
  request domain-name;
  script "/var/etc/dhcp6c_wan_script.sh"; # we'd like some nameservers please
};
id-assoc pd 0 {
  prefix ::/56 infinity;
  prefix-interface pppoe0 {
    sla-id 0;
    sla-len 8;
  };

But it seems dhcp6c cannot handle that when pppoe0 is the interface as well. This shows in /var/log/system/latest.log (with debugging enabled like so: '/usr/local/sbin/dhcp6c -d -c /var/etc/dhcp6c.conf -p /var/run/dhcp6c.pid'):

<29>1 2022-04-06T22:58:11+02:00 OPNsense.mgsoft dhcp6c 4735 - [meta sequenceId="98"] link layer address is too short (pppoe0)
<29>1 2022-04-06T22:58:11+02:00 OPNsense.mgsoft dhcp6c 4735 - [meta sequenceId="99"] failed to get default IF ID for pppoe0
<29>1 2022-04-06T22:58:11+02:00 OPNsense.mgsoft dhcp6c 4735 - [meta sequenceId="100"] called
<27>1 2022-04-06T22:58:11+02:00 OPNsense.mgsoft dhcp6c 4735 - [meta sequenceId="101"] failed to parse configuration file

Thus there are at least two visible problems:

  1. there seems to be a problem with the "recursive" definition of interfaces and/or special properties of PPPoE interfaces (i.e. they have no link-layer address) and
  2. directly after applying a configuration change in the GUI, the dhcp6c still ran, whereas it barked with a configuration error afterwards upon restart. This makes me think that dhcp6c is probably not (re-)started right after the config is applied.
fichtner commented 2 years ago

Hi @meyergru

For 1. the code seems to fail if no link address can be found which is true for PPPoE for sure. One could be mocked as this pertains to configuration parsing alone.

For 2. SIGHUP is used to reload dhcp6c and it keeps the old config until restart so that explains that (and should be ok).

Let me try to adjust dhcp6c to see if it starts working on PPPoE or else we can likely stop looking into this direction? So far 0/3 cases reported success. :(

Cheers, Franco

meyergru commented 2 years ago

Ad 1: I think that there is more to it than just the configuration - the lladdr is also needed for the EUI64 calculation to create an IPv6 from the /56 prefix plus the 8-bit prefix from the WAN configuration, so it must be mocked (see https://github.com/opnsense/dhcp6c/blob/master/config.c line 1328).

I tried to get around this by supplying an lladdr to the pppoe0 interface directly before starting dhcp6c, but ifconfig denies that.

It is worth a try, since at least there seems to be no principal problem with having a "recursive" setup.

If that does not work and if you have to modify dhcp6c anyway, another possibility would be to use the ISP prefix to assign an IPv6 directly, like dhcp6c would do if an IA_NA was supplied.

fichtner commented 2 years ago

After some reflection 249afc5 removes the part where this is attempted to be implemented due to the challenges involved. I don't want to discourage extending dhcp6c but I don't have the time to do it.

Cheers, Franco

luckman212 commented 2 years ago

related: https://forum.netgate.com/topic/174980/fios-getting-56-pd-via-dhcp6-but-no-v6-is-assigned-to-wan

fichtner commented 2 years ago

@luckman212 thanks for the heads-up. Interested in seeing a solution for this as dhcp6c not being able to do it is "suboptimal. Manual solutions like your script https://github.com/luckman212/assign-gua-from-iapd look promising, yet ideally a neatly integrated option (exposed via GUI) might be nicer for future users in the long run

Cheers, Franco

luckman212 commented 2 years ago

@fichtner I agree, I wish I knew my way around C well enough to add the required feature myself. Hopefully someone with bigger chops can tackle it someday.

fichtner commented 2 years ago

With the recent interest of FreeBSD in (eventually) migrating to dhcpcd which is supposed to handle DHCP both in IPv4 and IPv6 a lot better it may already work there. With that effort, dhcp6(c) will likely die in the long-term.

shmerl commented 2 years ago

I saw some suggestion that these kind of issues can be related to ISPs using RFC 6603.

I see that FreeBSD mentioned it for dhcpd: https://www.freebsd.org/cgi/man.cgi?query=dhcpcd.conf

Did Opnsense pick that up or not yet?

fichtner commented 2 years ago

Dhcpd is not part of FreeBSD base yet. Integration is questionable.

shmerl commented 2 years ago

May be it's better to keep this open then to track when things won't need these kind of script workarounds anymore?

fichtner commented 2 years ago

I have no plans to work on dhcpcd for at least all of 2023 since it holds no relevancy for this project. As a general rule we avoid tickets that imply we do something we might not actually be doing. If someone wants to work on it a PR can always be opened regardless.

fichtner commented 6 months ago

Reviving this for 24.7, also see https://forum.opnsense.org/index.php?topic=37813.msg197098#msg197098

fichtner commented 6 months ago

Updated dhcp6c:

https://github.com/opnsense/dhcp6c/commit/369b4dcf5a https://github.com/opnsense/dhcp6c/commit/94c633227 https://github.com/opnsense/ports/commit/913dd9aa20

To install this version:

# opnsense-revert -z dhcp6c
fichtner commented 6 months ago

The newly introduced "Use SLAAC address" option appears nice on the surface, but has the fatal drawback that we only receive an IPv6 router from rtsold which... drumroll... requires to accept router advertisements and for now I don't know about a way to just avoid the SLAAC addressing.

fichtner commented 6 months ago

For reference: https://forums.freebsd.org/threads/allow-router-advertisements-on-a-nic-without-getting-slaac-address.68372/

fichtner commented 6 months ago

I've added https://github.com/opnsense/core/commit/9d2ee6178bacd2b69c0fa7234ea0c96ecc39576d (this needs another commit 44e3bafce211) to test this further. So far it doesn't have a bad impact even though the SLAAC address could disappear here for a couple of minutes but we don't appear to rely on it (unless we are in full SLAAC mode).

kevinchalet commented 6 months ago

@fichtner woooo, looks extremely promising. Are you looking for beta testers? If so, I'm interested in giving it a try 😃

To test it, I guess we just need to run opnsense-revert -z dhcp6c and opnsense-patch 369b4dc 35dc38c f5b298e 9dad0b2 9d2ee61, right?

fichtner commented 6 months ago

@kevinchalet hey! hope you are doing good. I lost track a bit but the current master state is alright.. for some reason my SLAAC address isn't coming back but I also don't really miss it. I've created a backport as 18803127e54 for 24.1.8:

# opnsense-patch 18803127e54 && opnsense-revert -z dhcp6c

Best do a clean reboot instead of an interface apply after adding a prefix ID to the WAN. Currently it's not a setting in the advanced section... are you with Orange?

Cheers, Franco

kevinchalet commented 6 months ago

@kevinchalet hey! hope you are doing good.

Hey, doing well, thanks for asking! Hope you're doing good too 😃

Currently it's not a setting in the advanced section... are you with Orange?

Ah yeah, I am! Would setting it in the basic tab before switching to "advanced" work? I'm pretty sure it worked when we tested that 2 years ago.

fichtner commented 6 months ago

It could get scrubbed, but probably also not going to render in the config. Let me fix that for you tomorrow.

kevinchalet commented 6 months ago

I lost track a bit but the current master state is alright.. for some reason my SLAAC address isn't coming back but I also don't really miss it.

FWIW, it's not something I'll be able to test on my end as Orange doesn't use SLAAC at all: their RA only contains the MTU of the link and the LL address of the gateway (very likely a Nokia/Alcatel-Lucent 7750 here 😄):

image

fichtner commented 6 months ago

@kevinchalet that's not a big issue. I've been a bit swamped today so I'll have to try again tomorrow. Sorry.

kevinchalet commented 6 months ago

Haha, no worries @fichtner! 😃

fichtner commented 6 months ago

@kevinchalet ok can you try this?

# opnsense-patch 18803127e54 bc34a38 && && opnsense-revert -z dhcp6c

Do you use the "Prefix Interface Site-Level Aggregation Length" option? What's your input there? I tied it to the setting like the tracking LANs do, but I was wondering what the complication with this is all about.

Cheers, Franco