/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2019-2026 WireGuard LLC. All Rights Reserved.
*/
package tunnel
import (
"sync"
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
func findDefaultRoute(family winipcfg.AddressFamily, ourLUID winipcfg.LUID) (winipcfg.LUID, uint32, error) {
r, err := winipcfg.GetIPForwardTable2(family)
if err != nil {
return 0, 0, err
}
lowestMetric := ^uint64(0)
index := uint32(0)
luid := winipcfg.LUID(0)
for i := range r {
if r[i].DestinationPrefix.PrefixLength != 0 || r[i].InterfaceLUID == ourLUID {
continue
}
ifrow, err := r[i].InterfaceLUID.Interface()
if err != nil || ifrow.OperStatus != winipcfg.IfOperStatusUp {
continue
}
iface, err := r[i].InterfaceLUID.IPInterface(family)
if err != nil {
continue
}
combinedMetric := uint64(r[i].Metric) + uint64(iface.Metric)
if combinedMetric < lowestMetric {
lowestMetric = combinedMetric
index = r[i].InterfaceIndex
luid = r[i].InterfaceLUID
}
}
return luid, index, nil
}
func monitorMTU(family winipcfg.AddressFamily, ourLUID winipcfg.LUID) ([]winipcfg.ChangeCallback, error) {
var minMTU int
if family == windows.AF_INET {
minMTU = 576
} else if family == windows.AF_INET6 {
minMTU = 1280
}
var mu sync.Mutex
lastLUID := winipcfg.LUID(0)
lastMTU := uint32(0)
doIt := func() error {
mu.Lock()
defer mu.Unlock()
luid, _, err := findDefaultRoute(family, ourLUID)
if err != nil {
return err
}
lastLUID = luid
mtu := uint32(0)
if lastLUID != 0 {
iface, err := lastLUID.Interface()
if err != nil {
return err
}
if iface.MTU > 0 {
mtu = iface.MTU
}
}
if mtu > 0 && lastMTU != mtu {
iface, err := ourLUID.IPInterface(family)
if err != nil {
return err
}
iface.NLMTU = uint32(max(int(mtu)-80, minMTU))
err = iface.Set()
if err != nil {
return err
}
lastMTU = mtu
}
return nil
}
err := doIt()
if err != nil {
return nil, err
}
cbr, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) {
if route != nil && route.DestinationPrefix.PrefixLength == 0 {
doIt()
}
})
if err != nil {
return nil, err
}
cbi, err := winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
if notificationType == winipcfg.MibParameterNotification {
doIt()
}
})
if err != nil {
cbr.Unregister()
return nil, err
}
return []winipcfg.ChangeCallback{cbr, cbi}, nil
}