Skip to content

Configure IPv6 correctly when IPv4 DHCP is enabled#113

Open
rleigh-codelibre wants to merge 2 commits intofreebsd:masterfrom
rleigh-codelibre:dhcp-ip6-fix
Open

Configure IPv6 correctly when IPv4 DHCP is enabled#113
rleigh-codelibre wants to merge 2 commits intofreebsd:masterfrom
rleigh-codelibre:dhcp-ip6-fix

Conversation

@rleigh-codelibre
Copy link
Copy Markdown

@rleigh-codelibre rleigh-codelibre commented Mar 22, 2026

This PR fixes a long-standing problem with the networking setup. If IPv4 DHCP was enabled, then the IPv6 network address would be blanked out, resulting in a missing IPv6 address even though it was in the jail configuration. I commonly use this setup so I can have working IPv4 but a static IPv6 for external connections for the actual hosted services.

Example configuration:

    "dhcp": 1,
    "interfaces": "vnet0:bridge0",
    "ip4": "new",
    "ip4_saddrsel": 0,
    "ip6": "new",
    "ip6_addr": "vnet0|2001:8b0:860:4669:47e:93ff:fe80:e610/64",
    "ip6_saddrsel": 0,
    "rtsold": 0,
    "vnet": 1,

Current behaviour:

ELF ldconfig path: /lib /usr/lib /usr/lib/compat /usr/local/lib /usr/local/lib/compat/pkg /usr/local/lib/compat /usr/local/lib/compat/pkg /
usr/local/lib/gcc14 /usr/local/lib/perl5/5.42/mach/CORE /usr/local/lib/qt6
32-bit compatibility ldconfig path: /usr/lib32 /usr/local/lib32/compat /usr/local/lib32/gcc14
Starting dhclient.
Starting dhclient.
Starting dhclient.
Starting dhclient.
Starting Network: lo0 epair0b.
lo0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
        options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
        inet 127.0.0.1 netmask 0xff000000
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0xd
        groups: lo
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
epair0b: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
        options=200009<RXCSUM,VLAN_MTU,RXCSUM_IPV6>
        ether 06:7e:93:80:e6:10
        hwaddr 58:9c:fc:10:59:08
        inet 192.168.1.74 netmask 0xffffff00 broadcast 192.168.1.255
        inet6 fe80::47e:93ff:fe80:e610%epair0b prefixlen 64 scopeid 0xf
        groups: epair
        media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
        status: active
        nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
epair0b: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
        options=200009<RXCSUM,VLAN_MTU,RXCSUM_IPV6>
        ether 06:7e:93:80:e6:10
        hwaddr 58:9c:fc:10:59:08
        inet 192.168.1.74 netmask 0xffffff00 broadcast 192.168.1.255
        inet6 fe80::47e:93ff:fe80:e610%epair0b prefixlen 64 scopeid 0xf
        groups: epair
        media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
        status: active
        nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
add host 127.0.0.1: gateway lo0 fib 0: route already in table
add host 127.0.0.1: gateway lo0 fib 0: route already in table
add host 127.0.0.1: gateway lo0 fib 0: route already in table
add host ::1: gateway lo0 fib 0: route already in table
add net fe80::: gateway ::1
add net ff02::: gateway ::1
add net ::ffff:0.0.0.0: gateway ::1
add net ::0.0.0.0: gateway ::1
Clearing /tmp (X related).
Updating /var/run/os-release done.
Creating and/or trimming log files.
Updating motd:.
Starting syslogd.
Performing sanity check on sshd configuration.
Starting sshd.
Starting cron.

Sun Mar 22 17:49:35 UTC 2026

With the fix:

ELF ldconfig path: /lib /usr/lib /usr/lib/compat /usr/local/lib /usr/local/lib/compat/pkg /usr/local/lib/compat /usr/local/lib/compat/pkg /usr/local/lib/gcc14 /usr/local/lib/perl5/5.42/mach/CORE /usr/local/lib/qt6
32-bit compatibility ldconfig path: /usr/lib32 /usr/local/lib32/compat /usr/local/lib32/gcc14
Starting dhclient.
Starting dhclient.
Starting dhclient.
Starting dhclient.
Starting Network: lo0 epair0b.
lo0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
        options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
        inet 127.0.0.1 netmask 0xff000000
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0xd
        groups: lo
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
epair0b: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
        options=200009<RXCSUM,VLAN_MTU,RXCSUM_IPV6>
        ether 06:7e:93:80:e6:10
        hwaddr 58:9c:fc:10:59:08
        inet 192.168.1.74 netmask 0xffffff00 broadcast 192.168.1.255
        inet6 2001:8b0:860:4669:47e:93ff:fe80:e610 prefixlen 64
        inet6 fe80::47e:93ff:fe80:e610%epair0b prefixlen 64 scopeid 0xf
        groups: epair
        media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
        status: active
        nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
epair0b: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
        options=200009<RXCSUM,VLAN_MTU,RXCSUM_IPV6>
        ether 06:7e:93:80:e6:10
        hwaddr 58:9c:fc:10:59:08
        inet 192.168.1.74 netmask 0xffffff00 broadcast 192.168.1.255
        inet6 2001:8b0:860:4669:47e:93ff:fe80:e610 prefixlen 64
        inet6 fe80::47e:93ff:fe80:e610%epair0b prefixlen 64 scopeid 0xf
        groups: epair
        media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
        status: active
        nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
epair0b: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
        options=200009<RXCSUM,VLAN_MTU,RXCSUM_IPV6>
        ether 06:7e:93:80:e6:10
        hwaddr 58:9c:fc:10:59:08
        inet 192.168.1.74 netmask 0xffffff00 broadcast 192.168.1.255
        inet6 2001:8b0:860:4669:47e:93ff:fe80:e610 prefixlen 64
        inet6 fe80::47e:93ff:fe80:e610%epair0b prefixlen 64 scopeid 0xf
        groups: epair
        media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
        status: active
        nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
add host 127.0.0.1: gateway lo0 fib 0: route already in table
add host 127.0.0.1: gateway lo0 fib 0: route already in table
add host 127.0.0.1: gateway lo0 fib 0: route already in table
add host ::1: gateway lo0 fib 0: route already in table
add net fe80::: gateway ::1
add net ff02::: gateway ::1
add net ::ffff:0.0.0.0: gateway ::1
add net ::0.0.0.0: gateway ::1
Clearing /tmp (X related).
Updating /var/run/os-release done.
Creating and/or trimming log files.
Updating motd:.
Starting syslogd.
Performing sanity check on sshd configuration.
Starting sshd.
Starting cron.

Sun Mar 22 18:00:52 UTC 2026

You can see with the fix that the IPv6 address is now correctly configured within the jail.

Full disclosure: I used Claude to investigate the codebase in detail to identify the specific cause of the problem and to develop the solution, plus to write the unit tests to prevent the a regression in the future.

This was tested on FreeBSD-15.0-RELEASE-p2.

rleigh-codelibre and others added 2 commits March 22, 2026 16:55
When dhcp=1 was set for IPv4, two places in the VNET startup code
incorrectly prevented IPv6 static addresses from being configured:

1. start_network_interface_vnet: The DHCP address-spoofing check
   iterated over both IPv4 and IPv6 net_configs, replacing static
   IPv6 addresses with empty strings. Add `not ipv6` guard so the
   spoofing only applies to IPv4 entries.

2. start_network_vnet_addr: The `wants_dhcp` flag (derived from
   IPv4 DHCP settings) gated all ifconfig calls, skipping the
   `ifconfig inet6` command for static IPv6. Change the condition
   to `(ipv6 or not wants_dhcp)` so IPv6 addresses are always
   assigned regardless of IPv4 DHCP state.

This allows the intended configuration of dynamic IPv4 via DHCP
with static IPv6 addresses to work correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests for start_network_vnet_addr cover:
- Static IPv6 assigned when IPv4 DHCP is enabled
- IPv4 ifconfig skipped when DHCP handles it
- Both address families assigned when DHCP is off
- accept_rtadv never triggers ifconfig
- DHCP keyword in ip4_addr string skips IPv4 but not IPv6

Tests for start_network_interface_vnet cover:
- IPv4 DHCP address spoofing does not affect IPv6 entries
- IPv4 addresses are correctly spoofed when DHCP is active
- Both addresses pass through unspoofed when DHCP is off

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant