Skip to content

Commit 6d3b4dc

Browse files
committed
More interface reuse
1 parent 57b2e67 commit 6d3b4dc

15 files changed

+283
-122
lines changed

control/finder.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package control
2+
3+
import (
4+
"net"
5+
"net/netip"
6+
"unsafe"
7+
8+
"github.com/sagernet/sing/common"
9+
M "github.com/sagernet/sing/common/metadata"
10+
11+
"golang.org/x/exp/slices"
12+
)
13+
14+
type InterfaceFinder interface {
15+
Update() error
16+
Interfaces() []Interface
17+
ByName(name string) (*Interface, error)
18+
ByIndex(index int) (*Interface, error)
19+
ByAddr(addr netip.Addr) (*Interface, error)
20+
}
21+
22+
type Interface struct {
23+
Index int
24+
MTU int
25+
Name string
26+
HardwareAddr net.HardwareAddr
27+
Flags net.Flags
28+
Addresses []netip.Prefix
29+
}
30+
31+
func (i Interface) Equals(other Interface) bool {
32+
return i.Index == other.Index &&
33+
i.MTU == other.MTU &&
34+
i.Name == other.Name &&
35+
slices.Equal(i.HardwareAddr, other.HardwareAddr) &&
36+
i.Flags == other.Flags &&
37+
slices.Equal(i.Addresses, other.Addresses)
38+
}
39+
40+
func (i Interface) NetInterface() net.Interface {
41+
return *(*net.Interface)(unsafe.Pointer(&i))
42+
}
43+
44+
func InterfaceFromNet(iif net.Interface) (Interface, error) {
45+
ifAddrs, err := iif.Addrs()
46+
if err != nil {
47+
return Interface{}, err
48+
}
49+
return InterfaceFromNetAddrs(iif, common.Map(ifAddrs, M.PrefixFromNet)), nil
50+
}
51+
52+
func InterfaceFromNetAddrs(iif net.Interface, addresses []netip.Prefix) Interface {
53+
return Interface{
54+
Index: iif.Index,
55+
MTU: iif.MTU,
56+
Name: iif.Name,
57+
HardwareAddr: iif.HardwareAddr,
58+
Flags: iif.Flags,
59+
Addresses: addresses,
60+
}
61+
}

control/finder_default.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package control
2+
3+
import (
4+
"net"
5+
"net/netip"
6+
7+
E "github.com/sagernet/sing/common/exceptions"
8+
)
9+
10+
var _ InterfaceFinder = (*DefaultInterfaceFinder)(nil)
11+
12+
type DefaultInterfaceFinder struct {
13+
interfaces []Interface
14+
}
15+
16+
func NewDefaultInterfaceFinder() *DefaultInterfaceFinder {
17+
return &DefaultInterfaceFinder{}
18+
}
19+
20+
func (f *DefaultInterfaceFinder) Update() error {
21+
netIfs, err := net.Interfaces()
22+
if err != nil {
23+
return err
24+
}
25+
interfaces := make([]Interface, 0, len(netIfs))
26+
for _, netIf := range netIfs {
27+
var iif Interface
28+
iif, err = InterfaceFromNet(netIf)
29+
if err != nil {
30+
return err
31+
}
32+
interfaces = append(interfaces, iif)
33+
}
34+
f.interfaces = interfaces
35+
return nil
36+
}
37+
38+
func (f *DefaultInterfaceFinder) UpdateInterfaces(interfaces []Interface) {
39+
f.interfaces = interfaces
40+
}
41+
42+
func (f *DefaultInterfaceFinder) Interfaces() []Interface {
43+
return f.interfaces
44+
}
45+
46+
func (f *DefaultInterfaceFinder) ByName(name string) (*Interface, error) {
47+
for _, netInterface := range f.interfaces {
48+
if netInterface.Name == name {
49+
return &netInterface, nil
50+
}
51+
}
52+
_, err := net.InterfaceByName(name)
53+
if err == nil {
54+
err = f.Update()
55+
if err != nil {
56+
return nil, err
57+
}
58+
return f.ByName(name)
59+
}
60+
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: &net.IPAddr{IP: nil}, Err: E.New("no such network interface")}
61+
}
62+
63+
func (f *DefaultInterfaceFinder) ByIndex(index int) (*Interface, error) {
64+
for _, netInterface := range f.interfaces {
65+
if netInterface.Index == index {
66+
return &netInterface, nil
67+
}
68+
}
69+
_, err := net.InterfaceByIndex(index)
70+
if err == nil {
71+
err = f.Update()
72+
if err != nil {
73+
return nil, err
74+
}
75+
return f.ByIndex(index)
76+
}
77+
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: &net.IPAddr{IP: nil}, Err: E.New("no such network interface")}
78+
}
79+
80+
func (f *DefaultInterfaceFinder) ByAddr(addr netip.Addr) (*Interface, error) {
81+
for _, netInterface := range f.interfaces {
82+
for _, prefix := range netInterface.Addresses {
83+
if prefix.Contains(addr) {
84+
return &netInterface, nil
85+
}
86+
}
87+
}
88+
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: &net.IPAddr{IP: addr.AsSlice()}, Err: E.New("no such network interface")}
89+
}

control/warpper.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package control
2+
3+
import (
4+
"net/netip"
5+
"syscall"
6+
7+
"github.com/sagernet/sing/common"
8+
"github.com/sagernet/sing/common/control"
9+
)
10+
11+
func Append(oldFunc control.Func, newFunc control.Func) control.Func {
12+
return control.Append(oldFunc, newFunc)
13+
}
14+
15+
func BindToInterface0(finder InterfaceFinder, conn syscall.RawConn, network string, address string, interfaceName string, interfaceIndex int, preferInterfaceName bool) error {
16+
return control.BindToInterface0(interfaceFinderWrapper{finder}, conn, network, address, interfaceName, interfaceIndex, preferInterfaceName)
17+
}
18+
19+
type interfaceFinderWrapper struct {
20+
finder InterfaceFinder
21+
}
22+
23+
func (i interfaceFinderWrapper) Update() error {
24+
return i.finder.Update()
25+
}
26+
27+
func (i interfaceFinderWrapper) Interfaces() []control.Interface {
28+
return common.Map(i.finder.Interfaces(), controlInterface)
29+
}
30+
31+
func (i interfaceFinderWrapper) InterfaceIndexByName(name string) (int, error) {
32+
if netIf, err := i.finder.ByName(name); err == nil {
33+
return netIf.Index, nil
34+
} else {
35+
return 0, err
36+
}
37+
}
38+
39+
func (i interfaceFinderWrapper) InterfaceNameByIndex(index int) (string, error) {
40+
if netIf, err := i.finder.ByIndex(index); err == nil {
41+
return netIf.Name, nil
42+
} else {
43+
return "", err
44+
}
45+
}
46+
47+
func (i interfaceFinderWrapper) InterfaceByAddr(addr netip.Addr) (*control.Interface, error) {
48+
if netIf, err := i.finder.ByAddr(addr); err == nil {
49+
cif := controlInterface(*netIf)
50+
return &cif, nil
51+
} else {
52+
return nil, err
53+
}
54+
}
55+
56+
var _ control.InterfaceFinder = &interfaceFinderWrapper{}
57+
58+
func controlInterface(i Interface) control.Interface {
59+
return control.Interface{
60+
Index: i.Index,
61+
Name: i.Name,
62+
Flags: i.Flags,
63+
Addresses: i.Addresses,
64+
HardwareAddr: i.HardwareAddr,
65+
}
66+
}

monitor.go

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package tun
22

33
import (
4-
"net/netip"
5-
6-
"github.com/sagernet/sing/common/control"
4+
"github.com/metacubex/sing-tun/control"
75
E "github.com/sagernet/sing/common/exceptions"
86
"github.com/sagernet/sing/common/x/list"
97
)
@@ -12,14 +10,10 @@ var ErrNoRoute = E.New("no route to internet")
1210

1311
type (
1412
NetworkUpdateCallback = func()
15-
DefaultInterfaceUpdateCallback = func(event int)
13+
DefaultInterfaceUpdateCallback = func(defaultInterface *control.Interface, flags int)
1614
)
1715

18-
const (
19-
EventInterfaceUpdate = 1
20-
EventAndroidVPNUpdate = 2
21-
EventNoRoute = 4
22-
)
16+
const FlagAndroidVPNUpdate = 1 << iota
2317

2418
type NetworkUpdateMonitor interface {
2519
Start() error
@@ -31,9 +25,7 @@ type NetworkUpdateMonitor interface {
3125
type DefaultInterfaceMonitor interface {
3226
Start() error
3327
Close() error
34-
DefaultInterfaceName(destination netip.Addr) string
35-
DefaultInterfaceIndex(destination netip.Addr) int
36-
DefaultInterface(destination netip.Addr) (string, int)
28+
DefaultInterface() *control.Interface
3729
OverrideAndroidVPN() bool
3830
AndroidVPNEnabled() bool
3931
RegisterCallback(callback DefaultInterfaceUpdateCallback) *list.Element[DefaultInterfaceUpdateCallback]

monitor_android.go

+11-12
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,21 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
5151
return err
5252
}
5353

54-
oldInterface := m.defaultInterfaceName
55-
oldIndex := m.defaultInterfaceIndex
56-
57-
m.defaultInterfaceName = link.Attrs().Name
58-
m.defaultInterfaceIndex = link.Attrs().Index
54+
oldInterface := m.defaultInterface.Load()
55+
newInterface, err := m.interfaceFinder.ByIndex(link.Attrs().Index)
56+
if err != nil {
57+
return E.Cause(err, "find updated interface: ", link.Attrs().Name)
58+
}
59+
m.defaultInterface.Store(newInterface)
5960

60-
var event int
61-
if oldInterface != m.defaultInterfaceName || oldIndex != m.defaultInterfaceIndex {
62-
event |= EventInterfaceUpdate
61+
if oldInterface != nil && oldInterface.Equals(*newInterface) && oldVPNEnabled == m.androidVPNEnabled {
62+
return nil
6363
}
64+
var flags int
6465
if oldVPNEnabled != m.androidVPNEnabled {
65-
event |= EventAndroidVPNUpdate
66-
}
67-
if event != 0 {
68-
m.emit(event)
66+
flags = FlagAndroidVPNUpdate
6967
}
68+
m.emit(newInterface, flags)
7069

7170
return nil
7271
}

monitor_darwin.go

+14-30
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"sync"
88
"time"
99

10+
"github.com/metacubex/sing-tun/control"
1011
"github.com/sagernet/sing/common/buf"
1112
E "github.com/sagernet/sing/common/exceptions"
1213
"github.com/sagernet/sing/common/logger"
@@ -107,11 +108,11 @@ func (m *networkUpdateMonitor) Close() error {
107108

108109
func (m *defaultInterfaceMonitor) checkUpdate() error {
109110
var (
110-
defaultInterface *net.Interface
111+
defaultInterface *control.Interface
111112
err error
112113
)
113114
if m.underNetworkExtension {
114-
defaultInterface, err = getDefaultInterfaceBySocket()
115+
defaultInterface, err = m.getDefaultInterfaceBySocket()
115116
if err != nil {
116117
return err
117118
}
@@ -144,7 +145,7 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
144145
if ones != 0 {
145146
continue
146147
}
147-
routeInterface, err := net.InterfaceByIndex(routeMessage.Index)
148+
routeInterface, err := m.interfaceFinder.ByIndex(routeMessage.Index)
148149
if err != nil {
149150
return err
150151
}
@@ -167,18 +168,20 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
167168
if defaultInterface == nil {
168169
return ErrNoRoute
169170
}
170-
oldInterface := m.defaultInterfaceName
171-
oldIndex := m.defaultInterfaceIndex
172-
m.defaultInterfaceIndex = defaultInterface.Index
173-
m.defaultInterfaceName = defaultInterface.Name
174-
if oldInterface == m.defaultInterfaceName && oldIndex == m.defaultInterfaceIndex {
171+
oldInterface := m.defaultInterface.Load()
172+
newInterface, err := m.interfaceFinder.ByIndex(defaultInterface.Index)
173+
if err != nil {
174+
return E.Cause(err, "find updated interface: ", defaultInterface.Name)
175+
}
176+
m.defaultInterface.Store(newInterface)
177+
if oldInterface != nil && oldInterface.Equals(*newInterface) {
175178
return nil
176179
}
177-
m.emit(EventInterfaceUpdate)
180+
m.emit(newInterface, 0)
178181
return nil
179182
}
180183

181-
func getDefaultInterfaceBySocket() (*net.Interface, error) {
184+
func (m *defaultInterfaceMonitor) getDefaultInterfaceBySocket() (*control.Interface, error) {
182185
socketFd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
183186
if err != nil {
184187
return nil, E.Cause(err, "create file descriptor")
@@ -221,24 +224,5 @@ func getDefaultInterfaceBySocket() (*net.Interface, error) {
221224
case <-time.After(time.Second):
222225
return nil, nil
223226
}
224-
interfaces, err := net.Interfaces()
225-
if err != nil {
226-
return nil, E.Cause(err, "net.Interfaces")
227-
}
228-
for _, netInterface := range interfaces {
229-
interfaceAddrs, err := netInterface.Addrs()
230-
if err != nil {
231-
return nil, E.Cause(err, "net.Interfaces.Addrs")
232-
}
233-
for _, interfaceAddr := range interfaceAddrs {
234-
ipNet, isIPNet := interfaceAddr.(*net.IPNet)
235-
if !isIPNet {
236-
continue
237-
}
238-
if ipNet.Contains(selectedAddr.AsSlice()) {
239-
return &netInterface, nil
240-
}
241-
}
242-
}
243-
return nil, E.New("no interface found for address ", selectedAddr)
227+
return m.interfaceFinder.ByAddr(selectedAddr)
244228
}

0 commit comments

Comments
 (0)