forked from SagerNet/sing-tun
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathmonitor_windows.go
127 lines (104 loc) · 2.83 KB
/
monitor_windows.go
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
117
118
119
120
121
122
123
124
125
126
127
package tun
import (
"net/netip"
"sync"
"github.com/metacubex/sing-tun/internal/winipcfg"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/common/x/list"
"golang.org/x/sys/windows"
)
// zeroTierFakeGatewayIp from
// https://github.com/zerotier/ZeroTierOne/blob/1.8.6/osdep/WindowsEthernetTap.cpp#L994
var zeroTierFakeGatewayIp = netip.MustParseAddr("25.255.255.254")
type networkUpdateMonitor struct {
routeListener *winipcfg.RouteChangeCallback
interfaceListener *winipcfg.InterfaceChangeCallback
errorHandler E.Handler
access sync.Mutex
callbacks list.List[NetworkUpdateCallback]
logger logger.Logger
}
func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) {
return &networkUpdateMonitor{
logger: logger,
}, nil
}
func (m *networkUpdateMonitor) Start() error {
routeListener, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) {
m.emit()
})
if err != nil {
return err
}
m.routeListener = routeListener
interfaceListener, err := winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
m.emit()
})
if err != nil {
routeListener.Unregister()
return err
}
m.interfaceListener = interfaceListener
return nil
}
func (m *networkUpdateMonitor) Close() error {
if m.routeListener != nil {
m.routeListener.Unregister()
m.routeListener = nil
}
if m.interfaceListener != nil {
m.interfaceListener.Unregister()
m.interfaceListener = nil
}
return nil
}
func (m *defaultInterfaceMonitor) checkUpdate() error {
rows, err := winipcfg.GetIPForwardTable2(windows.AF_INET)
if err != nil {
return err
}
lowestMetric := ^uint32(0)
alias := ""
var index int
for _, row := range rows {
if row.DestinationPrefix.PrefixLength != 0 {
continue
}
if row.NextHop.Addr() == zeroTierFakeGatewayIp {
continue
}
ifrow, err := row.InterfaceLUID.Interface()
if err != nil || ifrow.OperStatus != winipcfg.IfOperStatusUp {
continue
}
if ifrow.Type == winipcfg.IfTypePropVirtual || ifrow.Type == winipcfg.IfTypeSoftwareLoopback {
continue
}
iface, err := row.InterfaceLUID.IPInterface(windows.AF_INET)
if err != nil {
continue
}
if !iface.Connected {
continue
}
metric := row.Metric + iface.Metric
if metric < lowestMetric {
lowestMetric = metric
alias = ifrow.Alias()
index = int(ifrow.InterfaceIndex)
}
}
if alias == "" {
return ErrNoRoute
}
oldInterface := m.defaultInterfaceName
oldIndex := m.defaultInterfaceIndex
m.defaultInterfaceName = alias
m.defaultInterfaceIndex = index
if oldInterface == m.defaultInterfaceName && oldIndex == m.defaultInterfaceIndex {
return nil
}
m.emit(EventInterfaceUpdate)
return nil
}