Solved Failed to configure IPv6 for the internal interfaces via SLAAC

Hi there,

I have a FreeBSD 12.1 server, which has 2 network interfaces:
  • re0: the only physical ethernet interface, connecting with the internal devices
  • tun0: the external interface, to be assigned IPv6 prefix by ISP via PPPoE
And here's the configuration snippet for them:

# /etc/rc.conf ipv6_enable="YES" ipv6_gateway_enable="YES" ipv6_activate_all_interfaces="YES" # /etc/ppp/ppp.conf default: set log Phase Chat LCP IPCP tun command telcom: set device PPPoE:re0 add default HISADDR6 # /etc/sysctl.conf net.inet6.ip6.accept_rtadv=1 # /etc/pf.conf pass inet6 all

First of all, tun0 can get the IPv6 address from ISP via SLAAC(ICMPv6 RS/RA) and it works correctly so far.


# ifconfig tun0 inet6 tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1492 options=80000<LINKSTATE> inet6 fe80::76d0:2b60:a19c:cb9a%tun0 prefixlen 64 scopeid 0x4 inet6 AAAA:BBBB:CCCC:DDDD:76d0:2b60:a19c:cb9a prefixlen 64 autoconf nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL> Opened by PID 77027 # ping6 -c 1 2606:4700:4700::1111 PING6(56=40+8+8 bytes) AAAA:BBBB:CCCC:DDDD:76d0:2b60:a19c:cb9a --> 2606:4700:4700::1111 16 bytes from 2606:4700:4700::1111, icmp_seq=0 hlim=55 time=138.142 ms --- 2606:4700:4700::1111 ping6 statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/std-dev = 138.142/138.142/138.142/0.000 ms

Now, what i'm going to do is to let the devices located in the intranet get the IPv6 address from ISP via SLAAC. That means the FreeBSD should forward RS from re0 to tun0, and RA from tun0 to re0. Please give me some hints.

Here are 2 ways I tried but failed.

  • Using PF:
pass in on tun0 inet6 proto icmp6 icmp6-type routeradv dup-to (re0 ff02::1) pass in on re0 inet6 proto icmp6 icmp6-type routersol dup-to (tun0 ff02::2)
But it seems not working, and pfctl(5) complained syntax error.

# ifconfig re0 inet6 AAAA:BBBB:CCCC:DDDD:1::3/80 # ifconfig re0 inet6 re0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=82099<RXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE> inet6 fe80::76d0:2bff:fe9c:cb9a%re0 prefixlen 64 scopeid 0x1 inet6 AAAA:BBBB:CCCC:DDDD:1::3 prefixlen 80 nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL> # # cat /etc/rtadvd.conf re0:\ :addr="AAAA:BBBB:CCCC:DDDD:1::":prefixlen#80: # # rtadvd -dDf re0 rtadvd 27484 - - <sock_open> enter rtadvd 27484 - - <update_ifinfo> enter rtadvd 27484 - - <update_ifinfo> ifm = 0x800684000, lim = 0x8006851f8, diff = 4600 rtadvd 27484 - - <update_ifinfo> RTM_IFINFO found. ifm_index = 1, ifindex = 0 ... rtadvd 27484 - - <getconfig> re0 isn't defined in the configuration file or the configuration file doesn't exist. Treat it as default rtadvd 27484 - - <get_prefix> add AAAA:BBBB:CCCC:DDDD:1::/80 to prefix list on re0 rtadvd 27484 - - <sock_mc_join> enter rtadvd 27484 - - <sock_mc_join> re0: join link-local all-routers MC group rtadvd 27484 - - <ra_timer_update> RA timer on re0 is set to 16:0 rtadvd 27484 - - <getconfig> ifname=re0 marked as TRANSITIVE (initial burst). rtadvd 27484 - - <loadconfig_ifname> tun0 is not a target interface. Ignored at this moment. rtadvd 27484 - - configuration file reloaded. rtadvd 33911 - - <main> set timer to 16:0. waiting for inputs or timeout rtadvd 33911 - - <rtadvd_input> enter rtadvd 33911 - - <rs_input> RS received from fe80::840:136a:c967:820c on re0 rtadvd 33911 - - <main> set timer to 11:750772. waiting for inputs or timeout

It seems that rtadvd(8) received RS but didn't reply with RA.

OK, that's all. Any comments are welcome.
 
I updated /etc/pf.conf, and RS can be correctly forwarded from re0 to tun0, but RA can not be forwarded oppositely. Here's the configuration file:
pass in log quick route-to (re0 ff02::1) inet6 proto icmp6 icmp6-type routeradv pass in log quick route-to (tun0 ff02::2) inet6 proto icmp6 icmp6-type routersol
From the output of pflog(4), we can see both of RS and RA matched the PF rules:
# tcpdump -tXni pflog0 'icmp6[0]==133 or icmp6[0]==134' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 262144 bytes IP6 fe80::840:136a:c967:820c > ff02::2: ICMP6, router solicitation, length 16 0x0000: 6005 d2f1 0010 3aff fe80 0000 0000 0000 `.....:......... 0x0010: 0840 136a c967 820c ff02 0000 0000 0000 .@.j.g.......... 0x0020: 0000 0000 0000 0002 8500 bb25 0000 0000 ...........%.... 0x0030: 0101 f018 9861 d16f .....a.o IP6 fe80::8238:bcff:fe0b:cdd3 > ff02::1: ICMP6, router advertisement, length 64 0x0000: 6000 0000 0040 3aff fe80 0000 0000 0000 `....@:......... 0x0010: 8238 bcff fe0b cdd3 ff02 0000 0000 0000 .8.............. 0x0020: 0000 0000 0000 0001 8600 5116 0040 0708 ..........Q..@.. 0x0030: 0000 0000 0000 0000 0101 8038 bc0b cdd3 ...........8.... 0x0040: 0501 0000 0000 05d4 0304 40c0 0003 f480 ..........@..... 0x0050: 0002 a300 0000 0000 aaaa bbbb cccc dddd ................ 0x0060: 0000 0000 0000 0000 ........
If I capture on tun0, I can also get both of RS and RA:
# tcpdump -tXni tun0 'icmp6[0]==133 or icmp6[0]==134' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on tun0, link-type NULL (BSD loopback), capture size 262144 bytes IP6 fe80::840:136a:c967:820c > ff02::2: ICMP6, router solicitation, length 16 0x0000: 6005 d2f1 0010 3aff fe80 0000 0000 0000 `.....:......... 0x0010: 0840 136a c967 820c ff02 0000 0000 0000 .@.j.g.......... 0x0020: 0000 0000 0000 0002 8500 bb25 0000 0000 ...........%.... 0x0030: 0101 f018 9861 d16f .....a.o IP6 fe80::8238:bcff:fe0b:cdd3 > ff02::1: ICMP6, router advertisement, length 64 0x0000: 6000 0000 0040 3aff fe80 0000 0000 0000 `....@:......... 0x0010: 8238 bcff fe0b cdd3 ff02 0000 0000 0000 .8.............. 0x0020: 0000 0000 0000 0001 8600 5116 0040 0708 ..........Q..@.. 0x0030: 0000 0000 0000 0000 0101 8038 bc0b cdd3 ...........8.... 0x0040: 0501 0000 0000 05d4 0304 40c0 0003 f480 ..........@..... 0x0050: 0002 a300 0000 0000 aaaa bbbb cccc dddd ................ 0x0060: 0000 0000 0000 0000 ........
I think RS was correctly forwarded because both of RS packets have the same source address(fe80::840:136a:c967:820c), which is the link local address of the device in intranet. But unfortunately, I can't capture any RA on re0.
# tcpdump -tXni re0 'icmp6[0]==133 or icmp6[0]==134' tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on re0, link-type EN10MB (Ethernet), capture size 262144 bytes IP6 fe80::840:136a:c967:820c > ff02::2: ICMP6, router solicitation, length 16 0x0000: 6005 d2f1 0010 3aff fe80 0000 0000 0000 `.....:......... 0x0010: 0840 136a c967 820c ff02 0000 0000 0000 .@.j.g.......... 0x0020: 0000 0000 0000 0002 8500 bb25 0000 0000 ...........%.... 0x0030: 0101 f018 9861 d16f .....a.o IP6 fe80::840:136a:c967:820c > ff02::2: ICMP6, router solicitation, length 16 0x0000: 6005 d2f1 0010 3aff fe80 0000 0000 0000 `.....:......... 0x0010: 0840 136a c967 820c ff02 0000 0000 0000 .@.j.g.......... 0x0020: 0000 0000 0000 0002 8500 bb25 0000 0000 ...........%.... 0x0030: 0101 f018 9861 d16f .....a.o
 
Now, what i'm going to do is to let the devices located in the intranet get the IPv6 address from ISP via SLAAC. That means the FreeBSD should forward RS from re0 to tun0, and RA from tun0 to re0.
That's not how you do it. Router solicitation / router discovery works on link local addresses for a reason, you cannot just forward such traffic.

The usual way to go about this is prefix delegation via dhcp6. You will need a dhcp6 client, like dhcp6c(8) from net/dhcp6, to request a prefix from your ISPs dhcp6 server. This prefix is then configured on your internal network interface (re0) where rtadvd(8) takes care of announcing that prefix via RA messages to the attached network.
 
The usual way to go about this is prefix delegation via dhcp6. You will need a dhcp6 client...
Yes, I hope so. Using PF is the second option if rtadvd(8) can work correctly.
I tried dhcp6c(8) and I think it was working. Here's my configuration:
Code:
interface tun0 {
    send    ia-na 1;
    send    ia-pd 1;
    send    rapid-commit;
};
id-assoc pd 1 {
    prefix ::/64 1800;
    prefix-interface re0 {
        sla-id 0;
        sla-len 8;
    };
};
id-assoc na 1 {
};
But rtadvd(8) doesn't response any RS yet by using this simple configuration:
Code:
re0:\
     :prefixlen#64:
 
Yes, I hope so. Using PF is the second option if rtadvd(8) can work correctly.
I tried dhcp6c(8) and I think it was working. Here's my configuration:
Code:
interface tun0 {
    send    ia-na 1;
    send    ia-pd 1;
    send    rapid-commit;
};
id-assoc pd 1 {
    prefix ::/64 1800;
    prefix-interface re0 {
        sla-id 0;
        sla-len 8;
    };
};
id-assoc na 1 {
};
Remove the na statements, you are not going to request an address via dhcp6, just a prefix. You already got the address for your tun0 interface via SLAAC. So your config should look something like this:
Code:
interface tun0 {
    send    ia-pd 0;
    send    rapid-commit;
};
id-assoc pd 0 {
    prefix ::/64 infinity;

    prefix-interface re0 {
        sla-id 0;
        sla-len 0;
    };
};
This will request a /64 prefix from your ISP with the maximum allowed lease time and assign it to interface re0. If you are interested in addresses of IPv6 DNS servers, you might want to add the following to the interface tun0 section: request domain-name-servers;

But rtadvd(8) doesn't response any RS yet by using this simple configuration:
Code:
re0:\
     :prefixlen#64:
The default prefix length is 64, so there is no need to explicitly specify it, and you are not going to specify a fixed prefix anyways, as you don't have one, because it's dynamically assigned. Try this simple configuration which basically just sets the router preference:
Code:
default:\
        :raflags="h":

re0:\
        :tc=default:
When it's working so far that you get a prefix via dhcp6 and rtadvd is running, check that your firewall does not block any of the icmp6 messages, i.e. tcpdump -netttti pflog0 icmp6
 
The default prefix length is 64, so there is no need to explicitly specify it, and you are not going to specify a fixed prefix anyways, as you don't have one, because it's dynamically assigned. Try this simple configuration which basically just sets the router preference:
Code:
default:\
        :raflags="h":
re0:\
        :tc=default:
I tried it. rtadvd(8) came up to response RA for the RS packet. But the RA doesn't contain the IPv6 prefix, whether I set it in rtadvd(5) or not.
Code:
default:\
    :raflags="h":
re0:\
    :addr="aaaa:bbbb:cccc:dddd::":prefixlen#64:tc=default:
When it's working so far that you get a prefix via dhcp6 and rtadvd is running, check that your firewall does not block any of the icmp6 messages, i.e. tcpdump -netttti pflog0 icmp6
I don't think pf(4) blocks these packets.
Code:
# pfctl -sr
➜  ~ pfctl -sr
block drop in on tun0 all
pass log quick inet6 all flags S/SA keep state
...
# tcpdump -tXni re0 'icmp6[0]==133 or icmp6[0]==134'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on re0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP6 fe80::840:136a:c967:820c > ff02::2: ICMP6, router solicitation, length 16
        0x0000:  6001 bea0 0010 3aff fe80 0000 0000 0000  `.....:.........
        0x0010:  0840 136a c967 820c ff02 0000 0000 0000  .@.j.g..........
        0x0020:  0000 0000 0000 0002 8500 bb25 0000 0000  ...........%....
        0x0030:  0101 f018 9861 d16f                      .....a.o
IP6 fe80::76d0:2bff:fe9c:cb9a > ff02::1: ICMP6, router advertisement, length 24
        0x0000:  6000 0000 0018 3aff fe80 0000 0000 0000  `.....:.........
        0x0010:  76d0 2bff fe9c cb9a ff02 0000 0000 0000  v.+.............
        0x0020:  0000 0000 0000 0001 8600 5b10 4000 0708  ..........[.@...
        0x0030:  0000 0000 0000 0000 0101 74d0 2b9c cb9a  ..........t.+...
And I can capture RA on my MacBook.
1.png
 
I tried it. rtadvd(8) came up to response RA for the RS packet. But the RA doesn't contain the IPv6 prefix, whether I set it in rtadvd(5) or not.
Code:
default:\
    :raflags="h":
re0:\
    :addr="aaaa:bbbb:cccc:dddd::":prefixlen#64:tc=default:
According to your screenshot the RA also doesn't contain the router preference high attribute, so something aint right here. Make sure rtadvd(8) uses the right configuration file. Default configuration file location is /etc/rtadvd.conf unless you change that by specifying -c <configfile> option. Consider running rtadvd(8) in the foreground with debug messages enabled to check for potential problems: rtadvd -fd or rtadvd -fD. Before you start to mess with rtadvd(8) make sure that your re0 interface actually gets assigned an IPv6 prefix by dhcp6c(8). If it doesn't have one, there is nothing for rtadvd(8) to announce. Do not specify a fixed prefix in rtadvd.conf(5), your prefix is dynamically assigned by dhcp6c(8) and could change anytime.

I don't think pf(4) blocks these packets.
Code:
# pfctl -sr
➜  ~ pfctl -sr
block drop in on tun0 all
pass log quick inet6 all flags S/SA keep state
...
I'm actually not quite sure whether your pass rule will apply to icmp6 traffic. It doesn't specify tcp but it does specify flags S/SA. If you add a log keyword to all your block rules you should see any blocked packets on your pflog0 device, where you can track blocked packets using tcpdump -netttti pflog0.
 
Do not specify a fixed prefix in rtadvd.conf(5), your prefix is dynamically assigned by dhcp6c(8) and could change anytime.
OK, got it. It's working now. dhcp6c(8) can assign address to re0, and rtadvd(8) also advertises RA, which seems correctly.
Code:
# cat /etc/rc.conf
rtadvd_enable="YES"
rtadvd_interfaces="re0"
dhcp6c_enable="YES"
dhcp6c_interfaces="tun0"
...
#
# cat /etc/rtadvd.conf
default:\
    :raflags="h":
re0:\
    :tc=default:
#
# cat /usr/local/etc/dhcp6c.conf
interface tun0 {
  send    ia-pd 0;
  send    rapid-commit;
};

id-assoc pd 0 {
  prefix ::/64 infinity;
  prefix-interface re0 {
    sla-id 0;
    sla-len 0;
  };
};
#
# ifconfig tun0 inet6 | grep prefixlen
        inet6 fe80::76d0:2b52:819c:cb9a%tun0 prefixlen 64 scopeid 0x4
        inet6 aaaa:bbbb:cccc:dddd:76d0:2b52:819c:cb9a prefixlen 64 autoconf
#
# service dhcp6c start
# service rtadvd start
#
# ifconfig re0 inet6 | grep prefixlen
        inet6 fe80::76d0:2bff:fe9c:cb9a%re0 prefixlen 64 scopeid 0x1
        inet6 aaaa:bbbb:cccc:dddd:76d0:2bff:fe9c:cb9a prefixlen 60
As you can see, the prefixlen of these interfaces are different. The tun0 one, assigned via SLAAC, is 64, while the re0 one, assigned via dhcp6c(8), is 60. To confirm that, I captured DHCPv6 datagram,
Code:
# tcpdump -Xtni tun0 -c 2 'ip6 and (udp port 546 or udp port 547)'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type NULL (BSD loopback), capture size 262144 bytes
IP6 fe80::76d0:2b52:819c:cb9a.546 > ff02::1:2.547: dhcp6 solicit
        0x0000:  6000 0000 0038 1101 fe80 0000 0000 0000  `....8..........
        0x0010:  76d0 2b52 819c cb9a ff02 0000 0000 0000  v.+R............
        0x0020:  0000 0000 0001 0002 0222 0223 0038 24a4  .........".#.8$.
        0x0030:  01ae 307a 0001 000e 0001 0001 26ec 244a  ..0z........&.$J
        0x0040:  74d0 2b9c cb9a 000e 0000 0008 0002 0000  t.+.............
        0x0050:  0019 000c 0000 0001 0000 0000 0000 0000  ................
IP6 fe80::8238:bcff:fe0b:cdd3.547 > fe80::76d0:2b52:819c:cb9a.546: dhcp6 advertise
        0x0000:  6000 0000 0093 11ff fe80 0000 0000 0000  `...............
        0x0010:  8238 bcff fe0b cdd3 fe80 0000 0000 0000  .8..............
        0x0020:  76d0 2b52 819c cb9a 0223 0222 0093 4b0f  v.+R.....#."..K.
        0x0030:  02ae 307a 0001 000e 0001 0001 26ec 244a  ..0z........&.$J
        0x0040:  74d0 2b9c cb9a 0002 000e 0001 0006 4c62  t.+...........Lb
        0x0050:  944a 8038 bc0b cdd3 0007 0001 ff00 1900  .J.8............
        0x0060:  3600 0000 0100 0151 8000 021c 0000 1a00  6......Q........
        0x0070:  1900 02a3 0000 03f4 803c aaaa bbbb cccc  .........<......
        0x0080:  dddd 0000 0000 0000 0000 000d 0009 0000  ................
        0x0090:  5375 6363 6573 7300 1700 2026 0647 0047  Success....&.G.G
        0x00a0:  0000 0000 0000 0000 0011 1126 0647 0047  ...........&.G.G
        0x00b0:  0000 0000 0000 0000 0010 01              ...........
It's clear that the prefixlen in DHCP6-Advertise datagram is 60(0x3c). As a result, rtadvd(8) advertises aaaa:bbbb:cccc:dddd/60 IPv6 prefix for the RS packets. Unfortunately, all of the devices are NOT going to accept this 60 prefix, even if RA is received. It's going to work if I explicitly set an addr in rtadvd.conf(5):
Code:
# cat /etc/rtadvd.conf.notworking
default:\
    :raflags="h":
re0:\
    :tc=default:
#
# cat /etc/rtadvd.conf.working
default:\
    :raflags="h":
re0:\
    :addr="aaaa:bbbb:cccc:dddd::":prefixlen#64:tc=default:
I'm actually not quite sure whether your pass rule will apply to icmp6 traffic. It doesn't specify tcp but it does specify flags S/SA. If you add a log keyword to all your block rules you should see any blocked packets on your pflog0 device, where you can track blocked packets using tcpdump -netttti pflog0.
Don't care about flags S/SA. It's specified by pf(4), not by me. Well, I also checked via pflog(4), even used service pf stop to disable pf(4). I think it has nothing to with pf(4).
 
So your config should look something like this:
Code:
interface tun0 {
    send    ia-pd 0;
    send    rapid-commit;
};
id-assoc pd 0 {
    prefix ::/64 infinity;

    prefix-interface re0 {
        sla-id 0;
        sla-len 0;
    };
};
I've read dhcp6c.conf(5) and RFC3633. I found that I set incorrect sla-len, which is supposed to be 4, at least.
Thanks for your comments.
 
I've read dhcp6c.conf(5) and RFC3633. I found that I set incorrect sla-len, which is supposed to be 4, at least.
Thanks for your comments.
The manual page dhcp6c.conf(5) and also my logic says otherwise:
Code:
             sla-len length ;
                     This statement specifies the length of the SLA ID in
                     bits.  length must be a decimal number between 0 and 128.
                     If the length is not specified by this statement, the
                     default value 16 will be used.
You would need a prefix < 64 and sla-len > 0 if you want to further subdivide the leased prefix into multiple /64 subprefixes for multiple interfaces (i.e. lan, wlan). In that case your lan interface would be sla-id 0 and the wlan sla-id 1, etc, up to the maximum that can be addressed in sla-len bits. So if you get a /60 prefix you would use slan-len 4 and with a /56 prefix sla-len 8. But as you only got a single ethernet interface re0, all you need is a /64 prefix that does not get further subdivided. Maybe your ISP refuses to assign any prefix larger than /60? In that case sla-id 0 and sla-len 4 should be correct. In any case, you should end up with a /64 prefix being assigned to re0, not /60.
 
You would need a prefix < 64 and sla-len > 0 if you want to further subdivide the leased prefix into multiple /64 subprefixes for multiple interfaces (i.e. lan, wlan). In that case your lan interface would be sla-id 0 and the wlan sla-id 1, etc, up to the maximum that can be addressed in sla-len bits.
I think so. My ISP gives tun0 an IPv6 address with /64 prefix via SLAAC and re0 with /60 prefix via DHCPv6. They are supposed to be located in the separated IPv6 networks. And furthermore, It gives me a choice to divide the /60 network into smaller ones.
So if you get a /60 prefix you would use slan-len 4 and with a /56 prefix sla-len 8. But as you only got a single ethernet interface re0, all you need is a /64 prefix that does not get further subdivided.
Yes, I can understand now. For example, I can divide the /60 network given by my ISP into 16 * /64 networks by using sla-len = 4, the /64 network with sla-id = 0 for all the physical devices connected on re0, the network with sla-id = 1 for the Jails grouped on re1 if I have, and so on.
Maybe your ISP refuses to assign any prefix larger than /60?
I'm not sure about that. But anyway, it doesn't matter. Thank you for the very detailed comments.
 
Back
Top