Преглед на файлове

Add route.default_interface option

世界 преди 3 години
родител
ревизия
377f3f83a2
променени са 12 файла, в които са добавени 45 реда и са изтрити 23 реда
  1. 3 2
      adapter/router.go
  2. 1 1
      common/dialer/auto_linux.go
  3. 5 5
      common/dialer/auto_windows.go
  4. 7 4
      common/dialer/default.go
  5. 1 1
      docs/configuration/inbound/tun.md
  6. 13 2
      docs/configuration/route/index.md
  7. 1 1
      go.mod
  8. 2 2
      go.sum
  9. 1 0
      option/route.go
  10. 8 2
      route/router.go
  11. 1 1
      test/go.mod
  12. 2 2
      test/go.sum

+ 3 - 2
adapter/router.go

@@ -30,9 +30,10 @@ type Router interface {
 	LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
 
 	InterfaceBindManager() control.BindManager
+	DefaultInterface() string
 	AutoDetectInterface() bool
-	DefaultInterfaceName() string
-	DefaultInterfaceIndex() int
+	AutoDetectInterfaceName() string
+	AutoDetectInterfaceIndex() int
 }
 
 type Rule interface {

+ 1 - 1
common/dialer/auto_linux.go

@@ -10,7 +10,7 @@ import (
 
 func BindToInterface(router adapter.Router) control.Func {
 	return func(network, address string, conn syscall.RawConn) error {
-		interfaceName := router.DefaultInterfaceName()
+		interfaceName := router.AutoDetectInterfaceName()
 		if interfaceName == "" {
 			return nil
 		}

+ 5 - 5
common/dialer/auto_windows.go

@@ -32,7 +32,7 @@ func bind6(handle windows.Handle, ifaceIdx int) error {
 
 func BindToInterface(router adapter.Router) control.Func {
 	return func(network, address string, conn syscall.RawConn) error {
-		interfaceName := router.DefaultInterfaceName()
+		interfaceName := router.AutoDetectInterfaceName()
 		if interfaceName == "" {
 			return nil
 		}
@@ -47,20 +47,20 @@ func BindToInterface(router adapter.Router) control.Func {
 			handle := windows.Handle(fd)
 			// handle ip empty, e.g. net.Listen("udp", ":0")
 			if ipStr == "" {
-				innerErr = bind4(handle, router.DefaultInterfaceIndex())
+				innerErr = bind4(handle, router.AutoDetectInterfaceIndex())
 				if innerErr != nil {
 					return
 				}
 				// try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6
-				bind6(handle, router.DefaultInterfaceIndex())
+				bind6(handle, router.AutoDetectInterfaceIndex())
 				return
 			}
 
 			switch network {
 			case "tcp4", "udp4", "ip4":
-				innerErr = bind4(handle, router.DefaultInterfaceIndex())
+				innerErr = bind4(handle, router.AutoDetectInterfaceIndex())
 			case "tcp6", "udp6":
-				innerErr = bind6(handle, router.DefaultInterfaceIndex())
+				innerErr = bind6(handle, router.AutoDetectInterfaceIndex())
 			}
 		})
 		return E.Errors(innerErr, err)

+ 7 - 4
common/dialer/default.go

@@ -29,19 +29,22 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
 	} else if router.AutoDetectInterface() {
 		if runtime.GOOS == "windows" {
 			dialer.Control = control.Append(dialer.Control, control.BindToInterfaceIndexFunc(func() int {
-				return router.DefaultInterfaceIndex()
+				return router.AutoDetectInterfaceIndex()
 			}))
 			listener.Control = control.Append(listener.Control, control.BindToInterfaceIndexFunc(func() int {
-				return router.DefaultInterfaceIndex()
+				return router.AutoDetectInterfaceIndex()
 			}))
 		} else {
 			dialer.Control = control.Append(dialer.Control, control.BindToInterfaceFunc(router.InterfaceBindManager(), func() string {
-				return router.DefaultInterfaceName()
+				return router.AutoDetectInterfaceName()
 			}))
 			listener.Control = control.Append(listener.Control, control.BindToInterfaceFunc(router.InterfaceBindManager(), func() string {
-				return router.DefaultInterfaceName()
+				return router.AutoDetectInterfaceName()
 			}))
 		}
+	} else if router.DefaultInterface() != "" {
+		dialer.Control = control.Append(dialer.Control, control.BindToInterface(router.InterfaceBindManager(), router.DefaultInterface()))
+		listener.Control = control.Append(listener.Control, control.BindToInterface(router.InterfaceBindManager(), router.DefaultInterface()))
 	}
 	if options.RoutingMark != 0 {
 		dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))

+ 1 - 1
docs/configuration/inbound/tun.md

@@ -47,7 +47,7 @@ Set the default route to the Tun.
 
 !!! error ""
 
-    To avoid traffic loopback, set `route.auto_delect_interface` or `outbound.bind_interface`
+    To avoid traffic loopback, set `route.auto_detect_interface` or `route.default_interface` or `outbound.bind_interface`
 
 #### hijack_dns
 

+ 13 - 2
docs/configuration/route/index.md

@@ -7,7 +7,8 @@
     "geosite": {},
     "rules": [],
     "final": "",
-    "auto_detect_interface": false
+    "auto_detect_interface": false,
+    "default_interface": "en0"
   }
 }
 ```
@@ -32,4 +33,14 @@ Default outbound tag. the first outbound will be used if empty.
 
 Bind outbound connections to the default NIC by default to prevent routing loops under Tun.
 
-Takes no effect if `outbound.bind_interface` is set.
+Takes no effect if `outbound.bind_interface` is set.
+
+#### default_interface
+
+!!! error ""
+
+    Linux and Windows only
+
+Bind outbound connections to the specified NIC by default to prevent routing loops under Tun.
+
+Takes no effect if `auto_detect_interface` is set.

+ 1 - 1
go.mod

@@ -10,7 +10,7 @@ require (
 	github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0
 	github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619
 	github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4
-	github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361
+	github.com/sagernet/sing-tun v0.0.0-20220715065926-9dc73c0bcc1d
 	github.com/spf13/cobra v1.5.0
 	github.com/stretchr/testify v1.8.0
 	golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d

+ 2 - 2
go.sum

@@ -31,8 +31,8 @@ github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZ
 github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4 h1:s3yKbPfiNwFFGfcNUs8NcKYzor78HWmZuDl5B0dsVQI=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
-github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361 h1:M6m9mXG5u151voF0wSDLf5JoDwHU5+4FOMrzb/kaRdc=
-github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
+github.com/sagernet/sing-tun v0.0.0-20220715065926-9dc73c0bcc1d h1:wt+OEJA3EiLIjwp+DROTtIXLox+9dwMRsVY/K2MvjXo=
+github.com/sagernet/sing-tun v0.0.0-20220715065926-9dc73c0bcc1d/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
 github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
 github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=

+ 1 - 0
option/route.go

@@ -14,6 +14,7 @@ type RouteOptions struct {
 	Rules               []Rule          `json:"rules,omitempty"`
 	Final               string          `json:"final,omitempty"`
 	AutoDetectInterface bool            `json:"auto_detect_interface,omitempty"`
+	DefaultInterface    string          `json:"default_interface,omitempty"`
 }
 
 func (o RouteOptions) Equals(other RouteOptions) bool {

+ 8 - 2
route/router.go

@@ -68,6 +68,7 @@ type Router struct {
 	interfaceBindManager control.BindManager
 	networkMonitor       tun.NetworkUpdateMonitor
 	autoDetectInterface  bool
+	defaultInterface     string
 	interfaceMonitor     tun.DefaultInterfaceMonitor
 }
 
@@ -89,6 +90,7 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
 		defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy),
 		interfaceBindManager:  control.NewBindManager(),
 		autoDetectInterface:   options.AutoDetectInterface,
+		defaultInterface:      options.DefaultInterface,
 	}
 	for i, ruleOptions := range options.Rules {
 		routeRule, err := NewRule(router, logger, ruleOptions)
@@ -540,14 +542,18 @@ func (r *Router) AutoDetectInterface() bool {
 	return r.autoDetectInterface
 }
 
-func (r *Router) DefaultInterfaceName() string {
+func (r *Router) DefaultInterface() string {
+	return r.defaultInterface
+}
+
+func (r *Router) AutoDetectInterfaceName() string {
 	if r.interfaceMonitor == nil {
 		return ""
 	}
 	return r.interfaceMonitor.DefaultInterfaceName()
 }
 
-func (r *Router) DefaultInterfaceIndex() int {
+func (r *Router) AutoDetectInterfaceIndex() int {
 	if r.interfaceMonitor == nil {
 		return -1
 	}

+ 1 - 1
test/go.mod

@@ -34,7 +34,7 @@ require (
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 // indirect
 	github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4 // indirect
-	github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361 // indirect
+	github.com/sagernet/sing-tun v0.0.0-20220715065926-9dc73c0bcc1d // indirect
 	github.com/sirupsen/logrus v1.8.1 // indirect
 	github.com/vishvananda/netlink v1.1.0 // indirect
 	github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect

+ 2 - 2
test/go.sum

@@ -58,8 +58,8 @@ github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZ
 github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4 h1:s3yKbPfiNwFFGfcNUs8NcKYzor78HWmZuDl5B0dsVQI=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
-github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361 h1:M6m9mXG5u151voF0wSDLf5JoDwHU5+4FOMrzb/kaRdc=
-github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
+github.com/sagernet/sing-tun v0.0.0-20220715065926-9dc73c0bcc1d h1:wt+OEJA3EiLIjwp+DROTtIXLox+9dwMRsVY/K2MvjXo=
+github.com/sagernet/sing-tun v0.0.0-20220715065926-9dc73c0bcc1d/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
 github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=