In this post we’ll take a detailed look at the properties of the Windows Server 2016 IPv6 stack.
I perform(ed) this exercise for several reasons:
- Server 2016 is the latest OS released by Microsoft so this might give an indication as for their plans & strategy when it comes to supporting certain specifications.
(here you may keep in mind that the ~50 IETF meetings having passed since the publication of RFC 2460 provided ample opportunity for creative minds to come up with ever new ideas for “enhancing” IPv6, without too much real-life feedback/reality checks from enterprise space though, as simply not many of such organizations have deployed it at scale… or are incentivized to send their employees to week-long meetings in expensive hotels on other continents twice a year…).
- as I laid out in this post the configuration approach an organization takes for their servers might depend on the support of specific features.
- obviously for both IPv6 planning and operations it might be helpful to understand the respective behavior of individual operating systems (which is why we researched stuff like this or this in the past).
- many years ago Microsoft published white papers with details as for the TCP/IP parameters of their OSs (incl. stuff like registry parameters to control it etc.) but I’m not aware of such a document for Server 2016 or Windows 10. I hence hope this post can somewhat contribute to public knowledge of the intricacies of their latest IPv6 stack.
This is the Windows version I looked at:
Microsoft Windows [Version 10.0.14393]
As of this article this equates to Windows 10 Anniversary Update but I tested an installation of “Windows Server 2016 Standard”. I assume that except for some settings “tweaked for a server role” (like the creation of temporary addresses being disabled by default) the behavior of Windows 10 will be pretty similar to what’s described below, but one of my colleagues will test this in detail soon (results then presented in an update post to this one, or maybe in a future revision of this Internet Draft).
ISATAP as well Teredo adapters were present after the installation (more precisely: after the first successful installation of a network adapter, see below):
Tunnel adapter isatap.speedport.ip: Media State . . . . . . . . . . . : Media disconnected Connection-specific DNS Suffix . : speedport.ip Tunnel adapter Teredo Tunneling Pseudo-Interface: Connection-specific DNS Suffix . : IPv6 Address. . . . . . . . . . . : 2001:0:5ef5:79fb:4e7:27b0:3f57:fd99 Link-local IPv6 Address . . . . . : fe80::4e7:27b0:3f57:fd99%30 Default Gateway . . . . . . . . . : C:\>netsh int teredo show state Teredo Parameters --------------------------------------------- Type : client Server Name : win10.ipv6.microsoft.com. Client Refresh Interval : 30 seconds Client Port : unspecified State : dormant
Given I don’t think that there’s much need (dynamic) tunnel technologies nowadays (let alone on systems acting as “servers”; one notable exception being servers offering DirectAccess services, as Richard Hicks rightfully pointed out) I did not perform any further investigation on them but immediately disabled both by:
netsh int isatap set state disabled netsh int teredo set state disabled
This can be done in PowerShell, too:
Set-NetTeredoConfiguration -Type Disabled Set-NetIsatapConfiguration -State Disabled
And, of course, this could be done by means of GPOs.
Let’s quickly look at the generation of the system’s DHCPv6 DUID. The installation was done on a laptop from our lab and interestingly both the build-in wireless and wired NICs were not recognized properly in the course of the procedure. This in turn meant that the system performed the first full boot process without any network adapters which had the consequence that no generation of the DUID took place. After installing the drivers for the WiFi interface and rebooting the following DUID was created:
As we can see this is a DUID “Based on Link-layer Address Plus Time [DUID-LLT]” (RFC 3315, sect. 9.2) which actually doesn’t come as a surprise given Windows (like many other OSs) has been using this as default in the past (and RFC 3315 recommends this for systems “that contain some form of writable non-volatile storage”). At a later point (after installation of the drivers for the wired Ethernet NIC) I tried to change the DUID to an LL-type one by deleting the registry key and putting a “00 03 00 01 E4 A7 A0 5B 85 E2” into the key (which should be a valid one according to RFC 3315, sect. 9.4).
The result was that, after another reboot, the DUID was overwritten by a new LLT based one. Interestingly enough this time with the MAC address of the Ethernet interface (the initial one was derived from the Wi-Fi interface, with this being the only one available at the time), even though the Ethernet interface had a higher interface ID/number (as of Windows’s own notation) and was disconnected when the system rebooted.
Overall this means that it seems not possible to modify the DUID generation mechanism on Windows systems at all, which is bad news for people hoping to either change it to LL-based generation in an early system initialization state or at least replace it with an LL-type one later on (e.g. in a scripted way, with MAC addresses fed from a CMDB), in order to facilitate (parsing for) DHCP reservations (so RFC 6939 support might be the only way to realize reservations in an operationally feasible way, as laid out in this post).
This is a particularly interesting section. Some of you may know that, since Windows 8.1, Microsoft OSs send DHCPv6 SOLICIT messages once their IPv6 stacks get initialized, even without being “told” to do so by router advertisements with an M flag. Many people incl. myself think that this somewhat violates RFC 4861 where it’s stated:
“Note: If neither M nor O flags are set, this indicates that no information is available via DHCPv6.”
but one might – rightfully – reply that using the term “indicate” does not constitute language with a claim to be normative…
Anyway Server 2016 shows this behavior as well, and the DHCPv6 Client service is running by default. The latter might be debatable by itself (it’s a “server” operating system which most sysadmins will have a tendency to configure in a way that leads to somewhat predictable – please note I’m avoiding the term “static” – addresses, which DHCPv6 might yield, or not).
In short: running a DHCP client service enabled by default on a “server” system somewhat feels wrong 😉
The more annoying aspect (than the potential deviation from the specs) of this approach is the following one: in segments where the router sends RAs with the O flag set to provision (IPv6) DNS servers and a DHCPv6 server is present (I mean why send RAs with O flag if not with a DHCPv6 server being reachable) but not configured to hand out addresses, this DHCPv6 server will respond to the Windows system’s initial DHCPv6 SOLICIT with a DHCPv6 ADVERTISE message containing a “NoAddrAvail” status code, but still including the option (23) holding the “DNS recursive name server”. Unfortunately the host then seems to ignore this DHCPv6 message/packet in full (which is aligned with RFC 3315, sect. 17.1.3, stating “The client MUST ignore any Advertise message that includes a Status Code option containing the value NoAddrsAvail”) and apparently (I tested this in multiple segments with different routers + RAs and DHCPv6 servers) later never sends a DHCPv6 INFORMATION-REQUEST message (which it should after receiving the RA with O flag set). This in turn means the host never learns the IPv6-related DNS resolvers/servers.
A pcap file showing this behavior can be found here. Please note I’ve stripped it down to the most relevant packets; the critical thing is that no DHCPv6 Inform can be observed, not even in the full capture ;-).
As Windows also ignores Option 25 (RDNSS) in router advertisements (see below) there’s apparently no way of distributing an IPv6 DNS resolver except for fully managed (M flag) DHCPv6.
Some Additional Notes on the DHCPv6 Behavior
Sending out “untriggered” DHCPv6 Solicits as part of the IPv6 stack/interface initialization seems somewhat contradicted when looking (by means of “netsh int ipv6 int $NUMBER”) at the command’s output which states:
Managed Address Configuration : disabled
Other Stateful Configuration : enabled
In fact the most reliable way to identify if this (behavior) is enabled/performed on an interface, from my perspective (feel free to correct me in a comment to the post), is this PowerShell command:
PS C:\> Get-NetIPInterface Ethernet -AddressFamily IPv6 ifIndex InterfaceAlias AddressFamily NlMtu(Bytes) InterfaceMetric Dhcp ConnectionState PolicyStore ------- -------------- ------------- ------------ --------------- ---- --------------- ----------- 13 Ethernet IPv6 1500 35 Enabled Connected ActiveStore
Furthermore if one wants to disable this thing (without stopping the DHCP Client service in full which requires a number of other services to be stopped as well and, more importantly, carries the risk that it is re-started without notice at any moment, e.g. when an interface is dis- & re-enabled) is the following command:
PS C:\> Set-NetIPInterface Ethernet -AddressFamily IPv6 -dhcp disabled
RA Option 25 (RDNSS)
There wasn’t much hope anyway but I nevertheless tested if adding Option 25 (RDNSS) to the RAs could be a way to distribute (IPv6 related) DNS resolver information. The result is: no, Windows still ignores Option 25 in RAs. Assuming that Windows 10 behaves the same way this means that a Windows system cannot get (in a dynamic/automatic manner) any IPv6 DNS resolver information in networks operating with RDNSS via RAs and/or O flag based DHCPv6, which in turn applies to many consumer (broadband or mobile) networks. To be honest I don’t think this is a smart design decision, and it probably won’t help IPv6 deployment (as Windows clients in such networks will be forced to rely on doing DNS resolutions over IPv4).
Implementation of RFC 6980
I was also interested if the stack implements RFC 6980, that means if fragmented neighbor discovery/router advertisement packets (which could circumvent the usual infrastructure based protection against rogue router advertisements, that is “RA Guard“) are ignored (as RFC 6980 sect. 5 mandates).
Here I was very pleasantly surprised that this actually seems to be the case (read: packets are discarded), at least for the vast majority of such packets. With the help of Chiron I managed to sneak around this protection by sending RAs split into two fragments with an added Destination Options header in the fragmentable part, but the good news is that these were not able to circumvent RA Guard (standard implementation on Cisco 2960 switch with a pretty old image) so I’ve not identified any way to make the test system accept rogue RAs in an RA Guard protected setting. I’ll discuss these tests in detail in another post to appear in a few days. Overall I’d say that Server 2016 pretty much fully implements RFC 6980.
For those interested here’s how some internal IPv6 parameters are set right after the installation (note that obviously some depend on the local environment such as the MTU [provisioned from the RA] and some of the timers/lifetimes, so your mileage may vary):
C:\>netsh int ipv6 sh int 11 Interface Wi-Fi Parameters ---------------------------------------------- IfLuid : wireless_32768 IfIndex : 11 State : connected Metric : 50 Link MTU : 1384 bytes Reachable Time : 28000 ms Base Reachable Time : 30000 ms Retransmission Interval : 1000 ms DAD Transmits : 1 Site Prefix Length : 64 Site Id : 1 Forwarding : disabled Advertising : disabled Neighbor Discovery : enabled Neighbor Unreachability Detection : enabled Router Discovery : enabled Managed Address Configuration : disabled Other Stateful Configuration : enabled Weak Host Sends : disabled Weak Host Receives : disabled Use Automatic Metric : enabled Ignore Default Routes : disabled Advertised Router Lifetime : 1800 seconds Advertise Default Route : disabled Current Hop Limit : 255 Force ARPND Wake up patterns : disabled Directed MAC Wake up patterns : disabled ECN capability : application PS C:\> get-netipv6protocol DefaultHopLimit : 128 NeighborCacheLimit(Entries) : 1024 RouteCacheLimit(Entries) : 32768 ReassemblyLimit(Bytes) : 263342688 IcmpRedirects : Enabled SourceRoutingBehavior : DontForward DhcpMediaSense : Enabled MediaSenseEventLog : Disabled MldLevel : All MldVersion : Version2 MulticastForwarding : Disabled GroupForwardedFragments : Disabled RandomizeIdentifiers : Enabled AddressMaskReply : Disabled UseTemporaryAddresses : Disabled MaxTemporaryDadAttempts : 3 MaxTemporaryValidLifetime : 7.00:00:00 MaxTemporaryPreferredLifetime : 1.00:00:00 TemporaryRegenerateTime : 00:00:05 MaxTemporaryDesyncTime : 00:10:00
Here’s a summary of some of the parameters which you might consider relevant:
And here’s a list of immediate tweaks we recommend to perform on the vast majority of Server 2016 based systems:
- Disable Teredo and ISATAP tunnel adapters by respective commands (see above).
- Disable “untriggered” DHCPv6 client behavior on interface basis by respective PowerShell cmdlet (above).
There will be a sequel to this post very soon (looking at some more stuff, e.g. to find out if RFC 7217 based IID generation is supported, and describing the RFC 6980 related tests in more detail). Furthermore I will ask Marcus Keane from Microsoft, whom I’ve met a several occasions and who’s a really nice (and smart) guy, for comments => these might be added then, too. Btw, in the interim you should read his post on their own IPv6 deployment.
Last but not least I will discuss some of these bits in a talk at the Troopers 17 “Next Generation Internet” (NGI) event which includes a dedicated IPv6 security track (being the successor of the IPv6 Security Summit held in the last years).
Have a great week everybody