windows: Disable DAD and router discovery on the ipv6 interface

Follow-up to #1871, which put a handle on the v6 interface for the first time.

Nothing answers on the far side of the adapter but nebula, and nebula drops the probes. Duplicate address detection only holds the overlay address tentative for a round it can never lose, and router solicitations leave for a multicast group nebula has no host for. Both come off on the v6 handle, the same treatment wireguard-windows gives its adapter.

The v4 handle is untouched: the adapter has no link layer for ARP-based conflict detection, and #1871 deliberately left the v4-only path alone.

Smoke asserts DadTransmits=0 and RouterDiscovery=Disabled on the v6 interface.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J34ExJUUPKWUvr2g5GMREi
This commit is contained in:
JackDoan
2026-09-08 09:40:51 -05:00
co-authored by Claude Fable 5.1
parent 75cbf9358d
commit 8713d4acb1
2 changed files with 15 additions and 1 deletions
@@ -228,6 +228,14 @@ try {
Write-Host "OK: $DevName $family NlMtu=$Mtu" Write-Host "OK: $DevName $family NlMtu=$Mtu"
} }
# Both are set on the same handle as the v6 NlMtu, so by now they are either applied or never will be.
Wait-Until -TimeoutSec 30 -What "$DevName IPv6 DadTransmits=0 RouterDiscovery=Disabled" -Predicate {
if ($lhProc.HasExited) { throw "lighthouse exited (code $($lhProc.ExitCode)) before the v6 interface was configured" }
$rows = @(Get-NetIPInterface -InterfaceAlias $DevName -AddressFamily IPv6 -ErrorAction SilentlyContinue)
$rows.Count -gt 0 -and -not ($rows | Where-Object { $_.DadTransmits -ne 0 -or "$($_.RouterDiscovery)" -ne 'Disabled' })
}
Write-Host "OK: $DevName IPv6 DadTransmits=0 RouterDiscovery=Disabled"
Wait-Until -TimeoutSec 30 -What "WSL nebula1 with $Ip2" -Predicate { Wait-Until -TimeoutSec 30 -What "WSL nebula1 with $Ip2" -Predicate {
if ($peerProc.HasExited) { throw "peer exited (code $($peerProc.ExitCode)) before tun was ready" } if ($peerProc.HasExited) { throw "peer exited (code $($peerProc.ExitCode)) before tun was ready" }
$r = wsl -d $Distro -u root -- bash -c "ip -o addr show nebula1 2>/dev/null | grep -q 'inet $Ip2' && echo yes" $r = wsl -d $Distro -u root -- bash -c "ip -o addr show nebula1 2>/dev/null | grep -q 'inet $Ip2' && echo yes"
+7 -1
View File
@@ -218,7 +218,8 @@ func (t *winTun) addRoutes(logErrors bool) error {
return t.setMTU(luid, foundDefault4, carriesV6) return t.setMTU(luid, foundDefault4, carriesV6)
} }
// setMTU applies tun.mtu per address family. The default route metric rides along on the v4 handle. // setMTU applies tun.mtu per address family. The default route metric rides along on the v4 handle, DAD and
// router discovery come off with the v6 one.
func (t *winTun) setMTU(luid winipcfg.LUID, foundDefault4, carriesV6 bool) error { func (t *winTun) setMTU(luid winipcfg.LUID, foundDefault4, carriesV6 bool) error {
ipif, err := luid.IPInterface(windows.AF_INET) ipif, err := luid.IPInterface(windows.AF_INET)
if err != nil { if err != nil {
@@ -249,6 +250,11 @@ func (t *winTun) setMTU(luid winipcfg.LUID, foundDefault4, carriesV6 bool) error
} }
ipif6.NLMTU = uint32(t.MTU) ipif6.NLMTU = uint32(t.MTU)
// Nothing answers on the far side of this adapter but nebula, which drops the probes. DAD only holds the
// address tentative for a round it can never lose, and solicitations only invite RAs we would drop anyway.
// wireguard-windows turns both off on the same handle.
ipif6.DadTransmits = 0
ipif6.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
if err := ipif6.Set(); err != nil { if err := ipif6.Set(); err != nil {
return fmt.Errorf("failed to set ipv6 interface: %w", err) return fmt.Errorf("failed to set ipv6 interface: %w", err)
} }