tailscale/tailscale

Windows firewall uses incorrect IPv6 link-local prefix (ff80::/10 instead of fe80::/10), breaking NDP/DHCPv6 matching

Summary

  • Context: The Windows firewall code in wf/firewall.go defines IPv6 address ranges used to match legitimate network traffic for NDP (Neighbor Discovery Protocol) and DHCPv6 firewall rules.

  • Bug: The linkLocalRange variable is defined as ff80::/10 instead of fe80::/10.

  • Actual vs. expected: The range ff80::/10 falls within the IPv6 multicast range (ff00::/8), not the link-local unicast range, causing firewall rules to fail to match legitimate IPv6 link-local traffic from addresses starting with fe80::.

  • Impact: Critical IPv6 protocols will be blocked, preventing IPv6 networking from functioning on Windows systems using this firewall.

Code with bug

linkLocalRange = netip.MustParsePrefix("ff80::/10") // BUG 🔴 Should be fe80::/10 per RFC 4291

This incorrect range is used in four firewall rules:

// Router Advertisement messages (ICMPv6 type 134) - line 382
rule.RemoteAddresses = []string{linkLocalRange.String()}

// Redirect messages (ICMPv6 type 137) - line 409
rule.RemoteAddresses = []string{linkLocalRange.String()}

// DHCPv6 request matching - line 427
rule.RemoteAddresses = []string{linkLocalRange.String()}

// DHCPv6 response matching - line 453
rule.LocalAddresses = []string{linkLocalRange.String

Codebase inconsistency

The code itself contains a TODO comment at line 363 that explicitly specifies the correct range:

/* TODO: actually handle the hop limit somehow! The rules should vaguely be:
 *  - icmpv6 134: must be incoming, src must be FE80::/10, hop limit must be 255
 *  - icmpv6 137: must be incoming, src must be FE80::/10, hop limit must be 255
 */

The comment correctly states FE80::/10 for ICMPv6 types 134 (Router Advertisement) and 137 (Redirect), contradicting the actual implementation which uses FF80::/10.

Example

Testing with typical IPv6 link-local addresses confirms they do not match the current range:


Per RFC 4291 (IPv6 Addressing Architecture), the correct ranges are:

  • fe80::/10 - Link-Local Unicast addresses

  • ff00::/8 - Multicast addresses

The value ff80::/10 is within the multicast range, not the link-local range. All legitimate link-local traffic (starting with fe80::) will fail to match the firewall rules, blocking:

  • NDP Router Advertisements (breaking IPv6 routing configuration)

  • NDP Redirect Messages (breaking route optimization)

  • DHCPv6 traffic (breaking IPv6 address autoconfiguration)

Recommended fix

Change the single character from ff to fe:

linkLocalRange = netip.MustParsePrefix("fe80::/10") // <-- FIX 🟢