Skip to content

Commit 2032ec8

Browse files
committed
Improve linux bind interface
1 parent e0ec961 commit 2032ec8

File tree

4 files changed

+64
-37
lines changed

4 files changed

+64
-37
lines changed

common/control/bind.go

+3-30
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package control
22

33
import (
4-
"os"
5-
"runtime"
64
"syscall"
75

6+
E "github.com/sagernet/sing/common/exceptions"
87
M "github.com/sagernet/sing/common/metadata"
98
N "github.com/sagernet/sing/common/network"
109
)
@@ -25,38 +24,12 @@ func BindToInterfaceFunc(finder InterfaceFinder, block func(network string, addr
2524
}
2625
}
2726

28-
const useInterfaceName = runtime.GOOS == "linux" || runtime.GOOS == "android"
29-
3027
func BindToInterface0(finder InterfaceFinder, conn syscall.RawConn, network string, address string, interfaceName string, interfaceIndex int) error {
3128
if interfaceName == "" && interfaceIndex == -1 {
32-
return nil
29+
return E.New("interface not found: ", interfaceName)
3330
}
3431
if addr := M.ParseSocksaddr(address).Addr; addr.IsValid() && N.IsVirtual(addr) {
3532
return nil
3633
}
37-
if interfaceName != "" && useInterfaceName || interfaceIndex != -1 && !useInterfaceName {
38-
return bindToInterface(conn, network, address, interfaceName, interfaceIndex)
39-
}
40-
if finder == nil {
41-
return os.ErrInvalid
42-
}
43-
var err error
44-
if useInterfaceName {
45-
interfaceName, err = finder.InterfaceNameByIndex(interfaceIndex)
46-
} else {
47-
interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
48-
}
49-
if err != nil {
50-
return err
51-
}
52-
if useInterfaceName {
53-
if interfaceName == "" {
54-
return nil
55-
}
56-
} else {
57-
if interfaceIndex == -1 {
58-
return nil
59-
}
60-
}
61-
return bindToInterface(conn, network, address, interfaceName, interfaceIndex)
34+
return bindToInterface(conn, network, address, finder, interfaceName, interfaceIndex)
6235
}

common/control/bind_darwin.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package control
22

33
import (
4+
"os"
45
"syscall"
56

67
"golang.org/x/sys/unix"
78
)
89

9-
func bindToInterface(conn syscall.RawConn, network string, address string, interfaceName string, interfaceIndex int) error {
10-
if interfaceIndex == -1 {
11-
return nil
12-
}
10+
func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int) error {
1311
return Raw(conn, func(fd uintptr) error {
12+
var err error
13+
if interfaceIndex == -1 {
14+
if finder == nil {
15+
return os.ErrInvalid
16+
}
17+
interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
18+
if err != nil {
19+
return err
20+
}
21+
}
1422
switch network {
1523
case "tcp6", "udp6":
1624
return unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, interfaceIndex)

common/control/bind_linux.go

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,48 @@
11
package control
22

33
import (
4+
"os"
45
"syscall"
56

7+
"github.com/sagernet/sing/common/atomic"
8+
E "github.com/sagernet/sing/common/exceptions"
9+
610
"golang.org/x/sys/unix"
711
)
812

9-
func bindToInterface(conn syscall.RawConn, network string, address string, interfaceName string, interfaceIndex int) error {
13+
var ifIndexDisabled atomic.Bool
14+
15+
func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int) error {
1016
return Raw(conn, func(fd uintptr) error {
17+
var err error
18+
if !ifIndexDisabled.Load() {
19+
if interfaceIndex == -1 {
20+
if finder == nil {
21+
return os.ErrInvalid
22+
}
23+
interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
24+
if err != nil {
25+
return err
26+
}
27+
}
28+
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_BINDTOIFINDEX, interfaceIndex)
29+
if err == nil {
30+
return nil
31+
} else if E.IsMulti(err, unix.ENOPROTOOPT, unix.EINVAL) {
32+
ifIndexDisabled.Store(true)
33+
} else {
34+
return err
35+
}
36+
}
37+
if interfaceName == "" {
38+
if finder == nil {
39+
return os.ErrInvalid
40+
}
41+
interfaceName, err = finder.InterfaceNameByIndex(interfaceIndex)
42+
if err != nil {
43+
return err
44+
}
45+
}
1146
return unix.BindToDevice(int(fd), interfaceName)
1247
})
1348
}

common/control/bind_windows.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,28 @@ package control
22

33
import (
44
"encoding/binary"
5+
"os"
56
"syscall"
67
"unsafe"
78

89
M "github.com/sagernet/sing/common/metadata"
910
)
1011

11-
func bindToInterface(conn syscall.RawConn, network string, address string, interfaceName string, interfaceIndex int) error {
12+
func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int) error {
1213
return Raw(conn, func(fd uintptr) error {
14+
var err error
15+
if interfaceIndex == -1 {
16+
if finder == nil {
17+
return os.ErrInvalid
18+
}
19+
interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
20+
if err != nil {
21+
return err
22+
}
23+
}
1324
handle := syscall.Handle(fd)
1425
if M.ParseSocksaddr(address).AddrString() == "" {
15-
err := bind4(handle, interfaceIndex)
26+
err = bind4(handle, interfaceIndex)
1627
if err != nil {
1728
return err
1829
}

0 commit comments

Comments
 (0)