Why is connecting to a web server listening on an IPv6 link-local address unreliable / How is IPv6 neighbor discovery expected to work

ipv6

I've got the following setup:

  • My Windows 7 development box (or a freshly installed Windows 7 VM)
  • A Windows Embedded CE 6.0 based device with IPv6 enabled and a web server running
  • A USB RNDIS connection between the two

On both sides of the connection, there is a link-local IPv6 address configured automatically as expected and I can ping in both directions using the scope ID.
I can enter the device's IPv6 address URI with the scope ID into Internet Explorer and can connect to the web server immediately.

However, having to input the scope ID is not the way IPv6 is expected to work for a user and consequently, Firefox does not support IPv6 address URIs with a scope ID. But: Connecting to the web server without the scope ID is very unreliable and I get a lot of connection timeouts in IE / Firefox and several retries with cygwin's wget.

Here is what I have found out so far

  • There is no other adapter configured to have the Windows CE's link-local IPv6 address on any of the other networks attached to my computer (Ethernet, VMware adapters…)
  • When the neighbor cache (netsh interface ipv6 show neighbors) shows the IPv6 address on the RNDIS interface as "Reachable", the web server connection succeeds immediately. I can trigger this by doing a ping prior to the browser request.
  • When the neighbor cache shows the IPv6 address on the RNDIS interface as "Stale", the connection times out. The other interfaces show the IPv6 address in various states: Usually "Unreachable" and "Incomplete".
  • I can watch the RNDIS interface with Wireshark while wget goes through several retries. There is no traffic on the interface besides ICPMv6 "Multicast Listener Report Message v2", LLMNR "Standard query" and DHCPv6 "Solicit", all originating from my PC. Then by the third or fourth retry of wget, there is an ICMPv6 "Neighbor solicitation" which the Windows CE device immediately responds to with a "Neighbor advertisement". This is when wget finally TCP-connects to the web server and downloads the requested page.
  • By that time, the neighbor cache shows the IPv6 address as Reachable and immediate subsequent requests succeed as well
  • While wget tries to connect to the web server, there are various Neighbor solicitation requests on my other interfaces

MSDN documents going through the interfaces one at a time when trying to find a neighbor, so I can understand the Neighbor solicitation requests on the other interfaces in principle, but I cannot believe that this is the way IPv6 Neighbor discovery is expected to work.

Is there a good way to make this scenario work reliably?

Best Answer

With link-local addresses, you must use the scope ID. The addresses are meaningless without it. It should not have been possible for you to get it to work at all without the scope ID.

In response to the comment from David Schwartz, there's no problem with using link-local addresses for this purpose, and it should work fine. It's especially useful for a web server running on an embedded appliance. I've used this for example to access a web server running on an embedded appliance for maintenance with a back-to-back ethernet connection to the appliance from a laptop. There were no other IP addresses on the wire but link-local.

But you're right: browsers have trouble with it. I believe that some older versions of Firefox work and newer ones don't. This is a bug in Firefox. Incidentally, it is a bug in Google Chrome too.

There's nothing you can do to make this reliable until the browser makers fix the bug. When I've needed to, I've managed to work around it with a port forward (e.g. ssh or socat).