IPv4 vs IPv6 priority in Windows
Short version
1 2 3 4 5 6 7 8 9 10 11 12 |
Before September 2012 After September 2012 Precedence Prefix Precedence Prefix ---------- ------------- ---------- ------------- 50 ::1/128 IPv6 loopback 50 ::1/128 IPv6 loopback 40 ::/0 Native IPv6 40 ::/0 Native IPv6 40 fc00::/7 ULAs 35 ::ffff:0:0/96 IPv4 40 fec0::/10 site-local 30 2002::/16 6to4 40 3ffe::/16 6bone 5 2001::/32 Teredo 30 2002::/16 6to4 3 fc00::/7 ULAs 20 ::/96 IPv4compat 1 fec0::/10 site-local 10 ::ffff:0:0/96 IPv4 1 3ffe::/16 6bone 5 2001::/32 Teredo 1 ::/96 IPv4compat |
Long Version
RFC6724 defined a change in how addresses should be preferred. With this change IPv6 is no longer the preferred address in nearly every case :(
This question, which was asked in June of 2012 was “fixed” by an RFC from September 2012. Depending on your Windows version, you either had this new policy out of the box (Windows 8.1), or likely already delivered through an update (Windows 8, Windows 7, Windows Vista).
We’re here because we want to use IPv6; we want that change undone.
How to put it back
If you get multiple IP addresses for a single host, your machine has to decide which address it will use. An example ranking might be:
- IPv6 loopback
- Native IPv6
- Unique-Local addresses (ULAs), e.g. fdxx::
- Site-local, e.g. fec0
- 6bone
- 6to4
- IPv4compat
- IPv4
- Teredo, e.g. 2001
On your Windows machine, this ranking is called the prefix policy.
Prefix policy
You can view your computer’s prefix policy by running:
1 |
>netsh int ipv6 show prefixpolicies |
In the olden times (originally defined by RFC 3484), the prefix policy was:
1 2 3 4 5 6 7 8 9 10 11 |
Precedence Prefix ---------- ------------- 50 ::1/128 IPv6 loopback 40 ::/0 Native IPv6 40 fc00::/7 ULAs 40 fec0::/10 site-local 40 3ffe::/16 6bone 30 2002::/16 6to4 20 ::/96 IPv4compat 10 ::ffff:0:0/96 IPv4 5 2001::/32 Teredo |
So you see it would pretty much always use IPv6 (yay!):
- IPv6 loopback
- Native IPv6, ULAs, site-local, 6one
- 6to4
- IPv4compat
- IPv4
- Teredo
If you went through the effort to deploy IPv6: it just worked.
New Prefix Policy
In 2012 a new preference order was defined by RFC6724. Nowadays the prefix policy pretty much ensures that you’ll never use IPv6:
1 2 3 4 5 6 7 8 9 10 11 |
Precedence Prefix ---------- ------------- 50 ::1/128 40 ::/0 Native IPv6 35 ::ffff:0:0/96 IPv4 30 2002::/16 5 2001::/32 3 fc00::/7 ULAs 1 fec0::/10 site-local 1 3ffe::/16 1 ::/96 |
You’ll see that you will never be able to use your Unique Local Addresses, or site-local address; it’s perpetually broken:
- IPv6 loopback
- Native IPv6
- IPv4
- 6to4
- Teredo
- ULAs
- site-local
- 6bone
- IPv6compat
How to fix it?
What we want is to fix IPv6 so that ULAs are preferred over IPv4. At the very least we want to push the use of ULAs (fc00::/7) above that of IPv4:
1 2 3 4 5 6 7 8 9 10 11 |
Precedence Prefix ---------- ------------- 50 ::1/128 40 ::/0 Native IPv6 37 fc00::/7 ULAs <---------- from 3 up to 37 35 ::ffff:0:0/96 IPv4 30 2002::/16 5 2001::/32 1 fec0::/10 site-local 1 3ffe::/16 1 ::/96 |
Which is done by:
1 |
>netsh interface ipv6 set prefixpolicy prefix=fc00::/7 precedence=37 label=13 store=active |
That will only keep it active until the next reboot. To make the change permanant:
1 |
>netsh interface ipv6 set prefixpolicy fc00::/7 37 13 |
If i:
- went through the effort to generate a ULA global prefix for my /48
- and choose a subnet id for my /64
- and deploy ULAs to every machine in the enterprise
- and update the DNS servers to return IPv6 ULA addresses in addition to IPv4 addresses
the least the computer could do is have the common courtesy to use the address.
Bonus Chatter
The fc00::/7 range is divided into two parts:
- fd00::/8 – GlobalID prefix generated locally
- fc00::/8 – ???
Nobody ever really decided was fc would be good for, and so just sits there.
The fd addresses are defined as:
fd [40-bit random GlobalID] [16-bit subnet] [64-bits for host assignment]
So if you generated a4d7f6dd66 as your cryptoghpcallly random 40-bit GlobalID, that gives you your /48:
- fda4:d7f5:dd66:: /48
- fda4:d7f5:dd66:face:: /64 (in the face subnet)
- fda4:d7f5:dd66:face::825 as a host IP address
SixXS maintained a public database of Unique Local Address GlobalID prefixes in order to reduce the chance of collissions, e.g.:
- fdee:e004:2208::/48: Apple Inc – Leopard OSX
- fdd4:43c8:ba34::/48: TekSavvy – Danny Murray
- fdac:afbd:fea1::/48: IBM Rational Build Forge – Chris Fuller
But due to slowing use, and the dubious value in the first place, SixXS discontinued the service in 2018.
Solution #1: Add a prefix policy to prefer IPv4 addresses over IPv6
Prefix policy table is similar a routing table, it determines which IP addresses are preferred when making a connection. Note that higher precedence in prefix policies is represented by a higher “precedence” value, exactly opposite to routing table “cost” value.
Default Windows prefix policy table:
1 2 3 4 5 6 7 8 9 10 11 |
C:\> netsh interface ipv6 show prefixpolicies Querying active state... Precedence Label Prefix ---------- ----- -------------------------------- 50 0 ::1/128 40 1 ::/0 30 2 2002::/16 20 3 ::/96 10 4 ::ffff:0:0/96 5 5 2001::/32 |
Note that IPv6 addresses (::/0) are preferred over IPv4 addresses (::/96, ::ffff:0:0/96).
We can create a policy that will make Hurricane Electric IPv6 tunnel less favorable than any IPv4 address:
1 |
netsh interface ipv6 add prefixpolicy 2001:470::/32 3 6 |
2001:470::/32 is Hurricane Electric’s prefix, 3 is a Precedence (very low) and 6 is a Label.
I could have used a more generic prefix, but I wanted to make sure that if and when I get direct IPv6 connectivity from an ISP, it will take precedence over IPv4.
If you adapt this solution, you need to substitute an appropriate IPv6 prefix instead of my Hurricane Electric one.
Solution #2: Tweak registry to make Windows always prefer IPv4 over IPv6
This solution is more generic, but more invasive and less standards-compliant. In the end, Windows will still modify the prefix policy table for you.
1)Open RegEdit, navigate to
1 |
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\tcpip6\Parameters |
2)Create DisabledComponents DWORD registry value, set its value to 20 (Hexadecimal).
See
https://support.microsoft.com/kb/929852
for more info about this registry key, especially if DisabledComponents already exists on your system.
3)Reboot.