Solved Routable IPv6 DHCP-PD on WAN

TL/DR: I would like to configure a PD on my WAN interface but my ISP's DHCP server doesn't support RFC6603; I can configure this manually but I am looking for a more programatic solution.

My ISP provides a /60 which I am able to split into multiple /64's. I am currently using dhcpcd to configure one of those /64's on a WireGuard interface - once the interface is configured via dhcpcd, I am able to ping to the outside world (via ping -S ...), access the WireGuard instance remotely, etc.

At this stage, I only have the desire to configure IPv6 addresses on my FreeBSD firewalls. As such, I would like is to configure one of the /64's on my WAN interface but unfortunately, my ISP's DHCP6 servers do not support RFC6603, "Prefix Exclude Option" (as indicated by "DHCPv6 server does not support OPTION_PD_EXCLUDE" in dhcpcd's output). Consequently, the following dhcpcd.conf will only configure one /64 on the WireGuard interface:

Code:
duid
slaac hwaddr
nooption domain_name_servers, domain_name, domain_search, host_name
option rapid_commit
ipv6only
noipv6rs

hostname -
vendclass 40712 .
script ""

allowinterfaces igb4
interface igb4
  ipv6rs
  ia_na 0
  ia_pd 1 igb4/1/64 wg1/2/64

However, once dhcpcd has forked into the background, I can manually configure an IPv6 alias on my WAN interface which then allows me normal IPv6 Internet access from the firewall:

Code:
ifconfig igb4 inet6 2600:d34d:b33f:12e1::1 prefixlen 64 alias

I understand that dhcpcd provides the ability to run scripts at different stages of the IP address acquisition process - I was thinking I could run a script to manually add an IPv6 address to my WAN interface based on the address assigned to the WireGuard interface.

I am wondering if anyone else has experienced the same issue and has a better solution for configuring a globally accessible IPv6 address on their WAN interface.
 
I don't fully understand the issue. Looking into RFC 6603, I understand this is for the case when the provider gives only one v6 prefix to the customer, and pieces of that have to be used for the uplink and the lan. (Here I am getting a /64 for the uplink and a separate /56 for my lan.)

So this would be mainly an issue on the upstream side - but if you can manually configure it as intended, then apparently is no issue on the upstream side.
 
I'm using net/dhcp6 on my ISP connection.

/usr/local/etc/dhcp6c.conf:
Code:
interface ng0 {
        send ia-na 0;
        send ia-pd 0;
};

id-assoc na {
};

id-assoc pd {
        prefix-interface em1.10 {
                sla-id 16;
        };
};

My WAN is ng0 and from MPD, I need to set up a PPPoE connection. em1.10 is the internal LAN interface. Works like a charm. Have rtadvd(8) running, that'll provide SLAAC addresses for the LAN systems.
 
I don't fully understand the issue. Looking into RFC 6603, I understand this is for the case when the provider gives only one v6 prefix to the customer, and pieces of that have to be used for the uplink and the lan. (Here I am getting a /64 for the uplink and a separate /56 for my lan.)

So this would be mainly an issue on the upstream side - but if you can manually configure it as intended, then apparently is no issue on the upstream side.
Part of the issue is that I am still working to understand how to properly deploy and manage a dual-stack network. What I ultimately want is my firewall to be able to communicate to the Internet at large via a routable IPv6 address - I am however, having trouble figuring out how to accomplish this.

I am able to receive a normal IPv6 address on my WAN interface but that does not allow me to communicate outside of my network.

I'm using net/dhcp6 on my ISP connection.

/usr/local/etc/dhcp6c.conf:
Code:
interface ng0 {
        send ia-na 0;
        send ia-pd 0;
};

id-assoc na {
};

id-assoc pd {
        prefix-interface em1.10 {
                sla-id 16;
        };
};

My WAN is ng0 and from MPD, I need to set up a PPPoE connection. em1.10 is the internal LAN interface. Works like a charm. Have rtadvd(8) running, that'll provide SLAAC addresses for the LAN systems.
Thank you for your input - when I try to acquire an IPv6 address with your adapted configuration, I receive the following, repeating messages:

Code:
Dec/23/2023 17:13:41: failed to open /usr/local/etc/dhcp6cctlkey: No such file or directory
Dec/23/2023 17:13:41: failed initialize control message authentication
Dec/23/2023 17:13:41: skip opening control port
Dec/23/2023 17:13:42: Sending Solicit
Dec/23/2023 17:13:42: unexpected advertise
Dec/23/2023 17:13:43: Sending Request
Dec/23/2023 17:13:43: dhcp6c Received REQUEST
Dec/23/2023 17:13:43: status code for PD-0: no prefixes
Dec/23/2023 17:13:43: add an address 2001:XXX:XXX:XXX::1/128 on igb4
Dec/23/2023 17:13:43: Sending Solicit
Dec/23/2023 17:13:43: unexpected advertise
Dec/23/2023 17:13:44: Sending Request
Dec/23/2023 17:13:44: dhcp6c Received REQUEST
Dec/23/2023 17:13:44: status code for PD-0: no prefixes

Thank you both for you replies and any addition input you might be able to provide.
 
Part of the issue is that I am still working to understand how to properly deploy and manage a dual-stack network. What I ultimately want is my firewall to be able to communicate to the Internet at large via a routable IPv6 address - I am however, having trouble figuring out how to accomplish this.
Okay, that is understandable.

I am able to receive a normal IPv6 address on my WAN interface but that does not allow me to communicate outside of my network.
So You have a wan interface and get an IPv6 onto it, and apparently that IPv6 is good enough to talk to the upstream DHCP server, but not to the remainder of the world?
That's a bit strange - is it a global-unicast or a private address or a linklocal?

Then, You say, you can get a /60 prefix via DHCPv6 PD. Is the IPv6 that appears on the wan interface contained within this /60, or is it a separate block? If the latter, then you're fine and don't need RFC6603.

Then, as soon as you have received that /60, you can distribute it, or desired parts of it, across you lan network in any desired fashion. You can do that with dhcpcd, or by other means, scripting or whatever.
dhcpcd has a lot of fancy intelligence built in, and it does not always do what we want it to do. It certainly knows the wan interface as the one from where it receives the DHCP messages, and may not be willing to distribute a new subnet as an alias back onto that same interface that does already work and is the logical upstream. The delegation prefix parts are, contrarily, to be distributed to the logical downstream, i.e. deeper into your lan.
So, I doubt that your intended configuration can work as such. This will need to be done manually from dhcpcd.enter-hook

I did work myself through that whole crap once, with a bit more difficult conditions:
  1. I have nested subnets, so there is, say, a /62 given to some subnet, and then in that subnet split again into /64 and these distributed to the sub-subnets.
  2. I get only a dynamic prefix, that is, the IP can change at any time, and that must then be handled throughout the entire lan, automated, within seconds.
  3. sandwich firewall, VPN, NPTv6, and a few more...
There is a paper how I made this work (because I don't know anymore), it describes a bit of the config and various gotchas, there might be one or the other interesting paragraph. It likely contains a bunch of errors as well, and is not concurrently updated, but free to read: https://tech.daemon.contact/articles/X3OyjgTpuv
 
Thank you for linking that post, it's a very interesting read.

So You have a wan interface and get an IPv6 onto it, and apparently that IPv6 is good enough to talk to the upstream DHCP server, but not to the remainder of the world?
That's a bit strange - is it a global-unicast or a private address or a linklocal?

dhcpcd is configuring a global unicast address on my WAN interface. You're absolutely correct: this is just enough to communicate with the upstream DHCP servers, but not the rest of the IPv6 Internet. Here's the full output from dhcpcd:

Code:
dhcpcd-10.0.6 starting
DUID 00:...
igb4: IAID XX:XX:XX:91
igb4: IA type 3 IAID 00:00:00:00
igb4: IA type 25 IAID 00:00:00:01
igb4: adding address fe80::XXXX:XXXX:XXXX:XX91
igb4: soliciting an IPv6 router
igb4: soliciting a DHCPv6 lease
wg1: activating for delegation
wg1: IAID 77:...
wg1: ipv6_start: Operation not supported
igb4: ADV 2001:XXX:XXX:XXX::1/128 from fe80::...
igb4: Router Advertisement from fe80::XXX:XXXX:XXXX:XX88
igb4: no global addresses for default route
igb4: REPLY6 received from fe80::XXX:XXXX:XXXX:XX88
igb4: adding address 2001:XXXX:XXXX:XXXX::1/128
igb4: renew in 1800, rebind in 2880, expire in 3600 seconds
lo0: adding reject route to 2600:XXXX:XXXX:XXX0::/60 via ::1
igb4: delegated prefix 2600:XXXX:XXXX:XXX0::/60
wg1: adding address 2600:XXXX:XXXX:XXX2::1/64
wg1: adding route to 2600:XXXX:XXXX:XXX2::/64
igb4: adding default route via fe80::XXX:XXXX:XXXX:XX88


With the global unicast address configured on the WAN interface, I am able to to run a traceroute to Google's DNS and I receive replies from two hops upstream, but no further. Both of the replies are from servers related to my ISP, so I presume these are the DHCP servers.

So, I doubt that your intended configuration can work as such. This will need to be done manually from dhcpcd.enter-hook

I appreciate your input - it sounds like my best bet is going to be to somehow script adding the alias address to my WAN interface for IPv6 Internet connectivity.
 
There is a paper how I made this work (because I don't know anymore), it describes a bit of the config and various gotchas, there might be one or the other interesting paragraph. It likely contains a bunch of errors as well, and is not concurrently updated, but free to read: https://tech.daemon.contact/articles/X3OyjgTpuv
Thanks very much for this, it's quite useful. Would you be able to share the relevant bits of rc.conf on the "outbound router", specifically for tun0 & vtnet0? I'm trying to setup something similar with VNET jails on bridge0 (replacing your tutorial's vtnet0).
 
Thanks very much for this, it's quite useful. Would you be able to share the relevant bits of rc.conf on the "outbound router", specifically for tun0 & vtnet0? I'm trying to setup something similar with VNET jails
Hmja... there isn't much special. The tun0 seems created and maintained by /usr/sbin/ppp - there is no mention at all in rc.conf except:
Code:
ppp_profile="adsl"
ppp_adsl_unit="0"
Inside the ppp.conf is
Code:
  add default HISADDR
  add default HISADDR6

And natd is started on tun0 with -dynamic.

vtnet0 gets the local addresses: some 192.168.12.34, some hardcoded fe80::x:y:z (no actual need, it could as well get one via auto_linklocal) and an fd12::34:56 for internal traffic. No features. no options.
dhcpcd then assigns some subnet from the delegated prefix, and rtadv sends that to the inside peer.

Further:
Code:
gateway_enable="YES"
ipv6_gateway_enable="YES"

# routes pointing to the inside peer:
static_routes="lan4 lan6"
route_lan4="-net 192.168.12.0/21 192.168.12.35"
route_lan6="-6 -net fd12::/64 fd12::3457"  # should actually be done with the linklocal

netwait_enable="YES"
netwait_ip="8.8.8.8" # something wellknown
netwait_timeout="210"

rtadvd_enable="YES"
rtadvd_interfaces="vtnet0"

dhcpcd_enable="YES"

No extra rc.d script, but then lots of ugly thing inside ipfw: reconfiguration tables, computing for NPTv6, etc. That's for the advanced class. ;)


I think it should be possible to run this in a VNET jail as well. At times I did, and the main reason that I moved to a guest was dummynet: until rather recently dummynet (i.e. traffic shaping) was not VNET-aware.
 
dhcpcd then assigns some subnet from the delegated prefix, and rtadv sends that to the inside peer.
Thank you!! That helped me solve this riddle: an IPv6-only VPS with VNET iocage jails on a bridge, passing in config from the upstream IPv6 router.

The "weird" thing is ndproxy: without it the jails would successfully configure via SLAAC, but were unable to reach the internet nor ping each other nor the host (unless the host pinged the jail first).

Here's the setup:
  • vtnet0: gets IPv6 via dhcp, proxies via ndproxy
  • bridge0: advertises router info via rtadvd
  • epair0b_ipv6: gets IPv6 in jail via rtsold
  • no firewall enabled yet
Is there a way to avoid ndprelay? Perhaps it is needed here, because net.link.bridge.allow_llz_overlap breaks multicast over the bridge? However, without allow_llz_overlap I could get no IPv6 routing working at all.

Code:
host's /etc/rc.conf:
ipv6_activate_all_interfaces="YES"
ipv6_gateway_enable="YES"
ipv6_cpe_wanif="vtnet0"
ifconfig_vtnet0="SYNCDHCP"    #includes an IPv4 for remote access
create_args_bridge0="inet6 auto_linklocal"
cloned_interfaces="bridge0"
rtadvd_enable="YES"
rtadvd_interfaces="bridge0"
ndproxy_enable="YES"
ndproxy_uplink_interface="vtnet0"
ndproxy_downlink_mac_address="58:9c:fc:00:2c:ee"
ndproxy_uplink_ipv6_addresses="fe80::beef:ff:fe27:1c72"
ndproxy_exception_ipv6_addresses="fe80::beef:ff:fe27:1c71;2001:bc8:1210:affe:beef:ff:fe27:1c71"

Code:
host's /etc/sysctl.conf:
security.jail.sysvipc_allowed=1
security.jail.allow_raw_sockets=1
net.link.bridge.pfil_onlyip=0  # Only pass IP packets when pfil is enabled
net.link.bridge.pfil_bridge=0  # Packet filter on the bridge interface
net.link.bridge.pfil_member=0  # Packet filter on the member interface
net.link.bridge.allow_llz_overlap=1 #stop iocage's bridge setup from removing ext_if's IPv6 address

Code:
jail's iocage config.json:
  "vnet": 1,
  "bpf": 1,
  "dhcp": 0,
  "ip4_addr": "none",
  "ip6_addr": "vnet0|accept_rtadv",

Code:
jail's /etc/rc.conf:
ipv6_activate_all_interfaces="YES"
rtsold_enable="YES"
ifconfig_epair0b_ipv6="inet6 accept_rtadv auto_linklocal autoconf -ifdisabled"
 
Back
Top