RFC6724 describes two algorithms, one for source address selection and one for destination address selection.
By default, the following policy table should be applied for destination-address selection when multiple alternatives are possible:
Prefix Precedence Label
::1/128 50 0
::/0 40 1
::ffff:0:0/96 35 4
2002::/16 30 2
2001::/32 5 5
fc00::/7 3 13
::/96 1 3
fec0::/10 1 11
3ffe::/16 1 12
In this context, IPv4 addresses are matched with the ::ffff:0:0/96 prefix.
Nevertheless, on an OpenWrt 21.02.0-rc1, as well as on a 19.07.6, with the device having dual-stack Internet connectivity, trying to ping google.com results in OpenWrt using IPv4 by default, where it should be using IPv6.
┌──[SSH://root@openwrt]──[~]────────
# ping -c 1 google.com
PING google.com (142.250.179.142): 56 data bytes
64 bytes from 142.250.179.142: seq=0 ttl=120 time=15.062 ms
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 15.062/15.062/15.062 ms
┌──[SSH://root@openwrt]──[~]────────
# ping -c 1 -6 google.com
PING google.com (2a00:1450:400e:801::200e): 56 data bytes
64 bytes from 2a00:1450:400e:801::200e: seq=0 ttl=119 time=13.799 ms
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 13.799/13.799/13.799 ms
A packet capture running in parrallel confirms the first ping command triggered a DNS query for both IPv4 & IPv6 entries and got a answer to both of them.
The second ping only triggers a query for the IPv6 record, as expected, and shows OpenWrt has working IPv6 connectivity.
┌──[SSH://root@openwrt]──[~]────────
# tcpdump -ni lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
21:50:10.073341 IP 127.0.0.1.58926 > 127.0.0.1.53: 43035+ A? google.com. (28)
21:50:10.075040 IP 127.0.0.1.53 > 127.0.0.1.58926: 43035 1/0/0 A 142.250.179.142 (44)
21:50:10.075850 IP 127.0.0.1.58926 > 127.0.0.1.53: 45993+ AAAA? google.com. (28)
21:50:10.077293 IP 127.0.0.1.53 > 127.0.0.1.58926: 45993 1/0/0 AAAA 2a00:1450:400e:801::200e (56)
21:50:12.241738 IP 127.0.0.1.54021 > 127.0.0.1.53: 3640+ AAAA? google.com. (28)
21:50:12.243066 IP 127.0.0.1.53 > 127.0.0.1.54021: 3640 1/0/0 AAAA 2a00:1450:400e:801::200e (56)
^C
6 packets captured
12 packets received by filter
0 packets dropped by kernel
The same behavior is also displayed when doing an opkg update: DNS query shows both A & AAAA records being returned, but OpenWRT defaults once again to IPv4 to connect to the mirror.
# tcpdump -ni lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
22:04:53.133567 IP 127.0.0.1.34433 > 127.0.0.1.53: 1424+ A? downloads.openwrt.org. (39)
22:04:53.133704 IP 127.0.0.1.34433 > 127.0.0.1.53: 3717+ AAAA? downloads.openwrt.org. (39)
22:04:53.134797 IP 127.0.0.1.53 > 127.0.0.1.34433: 1424 2/0/0 CNAME mirror-02.infra.openwrt.org., A 168.119.138.211 (96)
22:04:53.136103 IP 127.0.0.1.53 > 127.0.0.1.34433: 3717 2/0/0 CNAME mirror-02.infra.openwrt.org., AAAA 2a01:4f8:251:321::2 (108)
Even if I completely purge all IPv4 IP addresses from the different interfaces, which incidently also purges the IPv4 routing table, OpenWRT still uses IPv4 as default stack, which results in failure to communicate with the remote host, which would be reachable if OpenWrt conformed to RFC6724.
┌──[SSH://root@openwrt]──[~]────────
# for i in $(ip addr | grep inet | grep -v inet6 | grep -v 127.0.0.1 | cut -d " " -f 6); do ip addr del $i dev $(ip addr show | grep $i | cut -d " " -f 11); done
┌──[SSH://root@openwrt]──[~]────────
# ip addr | grep inet | grep -v inet6
inet 127.0.0.1/8 scope host lo
┌──[SSH://root@openwrt]──[~]────────
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
┌──[SSH://root@openwrt]──[~]────────
# ping -c 1 google.com
PING google.com (172.217.17.46): 56 data bytes
ping: sendto: Network unreachable
┌──[SSH://root@openwrt]──[~]────────
# ping -c 1 google.com -6
PING google.com (2a00:1450:400e:808::200e): 56 data bytes
64 bytes from 2a00:1450:400e:808::200e: seq=0 ttl=119 time=13.324 ms
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 13.324/13.324/13.324 ms
┌──[SSH://root@openwrt]──[~]────────
# ip addr del 127.0.0.1 dev lo
┌──[SSH://root@openwrt]──[~]────────
# ip addr | grep inet | grep -v inet6
┌──[SSH://root@openwrt]──[~]────────
# ping -c 1 google.com
PING google.com (172.217.17.110): 56 data bytes
ping: sendto: Network unreachable
┌──[SSH://root@openwrt]──[~]────────
# ping -c 1 google.com -6
PING google.com (2a00:1450:400e:80c::200e): 56 data bytes
64 bytes from 2a00:1450:400e:80c::200e: seq=0 ttl=119 time=13.721 ms
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 13.721/13.721/13.721 ms
With the corresponding packet capture on DNS queries:
┌──[SSH://root@openwrt]──[~]────────
# tcpdump -ni lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
09:57:54.897536 IP6 ::1.43623 > ::1.53: 60427+ A? google.com. (28)
09:57:54.899395 IP6 ::1.43623 > ::1.53: 996+ AAAA? google.com. (28)
09:57:54.899822 IP6 ::1.53 > ::1.43623: 60427 1/0/0 A 172.217.168.206 (44)
09:57:54.902244 IP6 ::1.53 > ::1.43623: 996 1/0/0 AAAA 2a00:1450:400e:80d::200e (56)
09:57:56.892449 IP6 ::1.49613 > ::1.53: 50860+ AAAA? google.com. (28)
09:57:56.894695 IP6 ::1.53 > ::1.49613: 50860 1/0/0 AAAA 2a00:1450:400e:80d::200e (56)
I tried configuring a custom policy by creating /etc/gai.conf and filling it.
This wasn't documented anywhere in the OpenWRT documentation but seems to be the default location to configure the policy on linux systems, so I thought it'd be worth a shot...
Unfortunately, this didn't lead to any behaviour change.
┌──[SSH://root@openwrt]──[~]────────
# cat /etc/gai.conf
label ::1/128 0
label ::/0 1
label 2002::/16 2
label ::/96 3
label ::ffff:0:0/96 4
precedence ::1/128 50
precedence ::/0 40
precedence 2002::/16 30
precedence ::/96 20
precedence ::ffff:0:0/96 10
I digged in the OpenWRT documentation (wiki & forum), but couln't find a way to display openwrt default policy nor a way to change it.
Any idea as to wether or not this is possible in current builds ?