I'm running the latest version of Windows 10 as of this writing (1903) and I have a working dual-stack connection. If I ping the hostname of a dual-stack device from the command line, Windows prefers the IPv4 address. If I turn off IPv4, it will use the IPv6 address. According to numerous sources (including this answer), Windows should prefer IPv6.
1 Answer
As described in this answer, I followed these steps to get a trace of the network stack:
netsh trace start provider=Microsoft-Windows-TCPIP level=5 keywords=ut:TcpipRoute
ping -n 1 www.google.com
netsh trace stop
netsh trace convert %TEMP%\NetTraces\NetTrace.etl
The resulting text file contained the following line:
[2]0910.3710::2019-08-10 01:27:15.198580000 [Microsoft-Windows-TCPIP]IP: Address pair (::ffff:10.0.12.67, ::ffff:172.217.7.132) is preferred over (fd85:741f:6df1:212:50df:dc26:f469:4d4c, 2607:f8b0:4004:800::2004) by SortOptions: 0, Reason: Prefer Matching Label (Rule D 5.0).
The key part of that is
Reason: Prefer Matching Label
This is described in RFC 3484 Section 5 "Source Address Selection". Basically, prefixes can have "labels", and a source/destination address pair where the source and destination labels match is preferred over a pair where they do not match.
I can see the prefix/label mappings on my computer by running
netsh interface ipv6 show prefixpolicies
I get
Precedence Label Prefix
---------- ----- --------------------------------
50 0 ::1/128
40 1 ::/0
35 4 ::ffff:0:0/96
30 2 2002::/16
5 5 2001::/32
3 13 fc00::/7
1 12 3ffe::/16
1 11 fec0::/10
1 3 ::/96
As my source IPv6 address, fd85:741f:6df1:212:50df:dc26:f469:4d4c, is a ULA address (I'm using NPt to allow failover between two different WAN connections), it falls within fc00::/7 and gets a label of 13. My destination address is within ::/0 and gets a label of 1. Those do not match, hence preferring IPv4 where they both fall within ::ffff:0:0/96 and get a label of 4.
To fix this, I just need to add a prefix policy that sets my source address's label to 1. I can do that by running the following command in an administrative command prompt:
netsh interface ipv6 add prefixpolicy fd00::/8 3 1
That adds a policy for fd00::/8 (the entire ULA prefix) which has a precedence of 3 and a label of 1. Here's the updated prefix policy table:
Precedence Label Prefix
---------- ----- --------------------------------
50 0 ::1/128
40 1 ::/0
35 4 ::ffff:0:0/96
30 2 2002::/16
5 5 2001::/32
3 13 fc00::/7
3 1 fd00::/8
1 12 3ffe::/16
1 11 fec0::/10
1 3 ::/96
And now when I ping a dual-stack hostname, it prefers the IPv6 address.