1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
*/
package tunnel
import (
"log"
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLUID winipcfg.LUID, lastLUID *winipcfg.LUID, lastIndex *uint32) error {
r, err := winipcfg.GetIPForwardTable2(family)
if err != nil {
return err
}
lowestMetric := ^uint32(0)
index := uint32(0) // Zero is "unspecified", which for IP_UNICAST_IF resets the value, which is what we want.
luid := winipcfg.LUID(0) // Hopefully luid zero is unspecified, but hard to find docs saying so.
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 {
log.Printf("Found default route for interface %d, but not up, so skipping", r[i].InterfaceIndex)
continue
}
if r[i].Metric < lowestMetric {
lowestMetric = r[i].Metric
index = r[i].InterfaceIndex
luid = r[i].InterfaceLUID
}
}
if luid == *lastLUID && index == *lastIndex {
return nil
}
*lastLUID = luid
*lastIndex = index
if family == windows.AF_INET {
log.Printf("Binding v4 socket to interface %d", index)
return device.BindSocketToInterface4(index)
} else if family == windows.AF_INET6 {
log.Printf("Binding v6 socket to interface %d", index)
return device.BindSocketToInterface6(index)
}
return nil
}
func monitorDefaultRoutes(family winipcfg.AddressFamily, device *device.Device, autoMTU bool, tun *tun.NativeTun) (*winipcfg.RouteChangeCallback, error) {
var minMTU uint32
if family == windows.AF_INET {
minMTU = 576
} else if family == windows.AF_INET6 {
minMTU = 1280
}
ourLUID := winipcfg.LUID(tun.LUID())
lastLUID := winipcfg.LUID(0)
lastIndex := uint32(0)
lastMTU := uint32(0)
doIt := func() error {
err := bindSocketRoute(family, device, ourLUID, &lastLUID, &lastIndex)
if err != nil {
return err
}
if !autoMTU {
return nil
}
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 = mtu - 80
if iface.NLMTU < minMTU {
iface.NLMTU = minMTU
}
err = iface.Set()
if err != nil {
return err
}
tun.ForceMTU(int(iface.NLMTU)) // TODO: having one MTU for both v4 and v6 kind of breaks the windows model, so right now this just gets the second one which is... bad.
lastMTU = mtu
}
return nil
}
err := doIt()
if err != nil {
return nil, err
}
cb, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) {
if route != nil && route.DestinationPrefix.PrefixLength == 0 {
_ = doIt()
}
})
if err != nil {
return nil, err
}
return cb, nil
}
|