mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-02-16 14:24:31 +00:00
Add route.default_interface option
This commit is contained in:
parent
5a3de62c50
commit
377f3f83a2
|
@ -30,9 +30,10 @@ type Router interface {
|
||||||
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
|
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
|
||||||
|
|
||||||
InterfaceBindManager() control.BindManager
|
InterfaceBindManager() control.BindManager
|
||||||
|
DefaultInterface() string
|
||||||
AutoDetectInterface() bool
|
AutoDetectInterface() bool
|
||||||
DefaultInterfaceName() string
|
AutoDetectInterfaceName() string
|
||||||
DefaultInterfaceIndex() int
|
AutoDetectInterfaceIndex() int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
func BindToInterface(router adapter.Router) control.Func {
|
func BindToInterface(router adapter.Router) control.Func {
|
||||||
return func(network, address string, conn syscall.RawConn) error {
|
return func(network, address string, conn syscall.RawConn) error {
|
||||||
interfaceName := router.DefaultInterfaceName()
|
interfaceName := router.AutoDetectInterfaceName()
|
||||||
if interfaceName == "" {
|
if interfaceName == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func bind6(handle windows.Handle, ifaceIdx int) error {
|
||||||
|
|
||||||
func BindToInterface(router adapter.Router) control.Func {
|
func BindToInterface(router adapter.Router) control.Func {
|
||||||
return func(network, address string, conn syscall.RawConn) error {
|
return func(network, address string, conn syscall.RawConn) error {
|
||||||
interfaceName := router.DefaultInterfaceName()
|
interfaceName := router.AutoDetectInterfaceName()
|
||||||
if interfaceName == "" {
|
if interfaceName == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -47,20 +47,20 @@ func BindToInterface(router adapter.Router) control.Func {
|
||||||
handle := windows.Handle(fd)
|
handle := windows.Handle(fd)
|
||||||
// handle ip empty, e.g. net.Listen("udp", ":0")
|
// handle ip empty, e.g. net.Listen("udp", ":0")
|
||||||
if ipStr == "" {
|
if ipStr == "" {
|
||||||
innerErr = bind4(handle, router.DefaultInterfaceIndex())
|
innerErr = bind4(handle, router.AutoDetectInterfaceIndex())
|
||||||
if innerErr != nil {
|
if innerErr != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6
|
// try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6
|
||||||
bind6(handle, router.DefaultInterfaceIndex())
|
bind6(handle, router.AutoDetectInterfaceIndex())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp4", "udp4", "ip4":
|
case "tcp4", "udp4", "ip4":
|
||||||
innerErr = bind4(handle, router.DefaultInterfaceIndex())
|
innerErr = bind4(handle, router.AutoDetectInterfaceIndex())
|
||||||
case "tcp6", "udp6":
|
case "tcp6", "udp6":
|
||||||
innerErr = bind6(handle, router.DefaultInterfaceIndex())
|
innerErr = bind6(handle, router.AutoDetectInterfaceIndex())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return E.Errors(innerErr, err)
|
return E.Errors(innerErr, err)
|
||||||
|
|
|
@ -29,19 +29,22 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
||||||
} else if router.AutoDetectInterface() {
|
} else if router.AutoDetectInterface() {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
dialer.Control = control.Append(dialer.Control, control.BindToInterfaceIndexFunc(func() int {
|
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 {
|
listener.Control = control.Append(listener.Control, control.BindToInterfaceIndexFunc(func() int {
|
||||||
return router.DefaultInterfaceIndex()
|
return router.AutoDetectInterfaceIndex()
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
dialer.Control = control.Append(dialer.Control, control.BindToInterfaceFunc(router.InterfaceBindManager(), func() string {
|
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 {
|
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 {
|
if options.RoutingMark != 0 {
|
||||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
||||||
|
|
|
@ -47,7 +47,7 @@ Set the default route to the Tun.
|
||||||
|
|
||||||
!!! error ""
|
!!! 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
|
#### hijack_dns
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
"geosite": {},
|
"geosite": {},
|
||||||
"rules": [],
|
"rules": [],
|
||||||
"final": "",
|
"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.
|
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.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -10,7 +10,7 @@ require (
|
||||||
github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0
|
github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619
|
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4
|
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/spf13/cobra v1.5.0
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||||
|
|
4
go.sum
4
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-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 h1:s3yKbPfiNwFFGfcNUs8NcKYzor78HWmZuDl5B0dsVQI=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
|
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-20220715065926-9dc73c0bcc1d h1:wt+OEJA3EiLIjwp+DROTtIXLox+9dwMRsVY/K2MvjXo=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
|
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 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||||
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
|
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=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
|
|
@ -14,6 +14,7 @@ type RouteOptions struct {
|
||||||
Rules []Rule `json:"rules,omitempty"`
|
Rules []Rule `json:"rules,omitempty"`
|
||||||
Final string `json:"final,omitempty"`
|
Final string `json:"final,omitempty"`
|
||||||
AutoDetectInterface bool `json:"auto_detect_interface,omitempty"`
|
AutoDetectInterface bool `json:"auto_detect_interface,omitempty"`
|
||||||
|
DefaultInterface string `json:"default_interface,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o RouteOptions) Equals(other RouteOptions) bool {
|
func (o RouteOptions) Equals(other RouteOptions) bool {
|
||||||
|
|
|
@ -68,6 +68,7 @@ type Router struct {
|
||||||
interfaceBindManager control.BindManager
|
interfaceBindManager control.BindManager
|
||||||
networkMonitor tun.NetworkUpdateMonitor
|
networkMonitor tun.NetworkUpdateMonitor
|
||||||
autoDetectInterface bool
|
autoDetectInterface bool
|
||||||
|
defaultInterface string
|
||||||
interfaceMonitor tun.DefaultInterfaceMonitor
|
interfaceMonitor tun.DefaultInterfaceMonitor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +90,7 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
|
||||||
defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy),
|
defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy),
|
||||||
interfaceBindManager: control.NewBindManager(),
|
interfaceBindManager: control.NewBindManager(),
|
||||||
autoDetectInterface: options.AutoDetectInterface,
|
autoDetectInterface: options.AutoDetectInterface,
|
||||||
|
defaultInterface: options.DefaultInterface,
|
||||||
}
|
}
|
||||||
for i, ruleOptions := range options.Rules {
|
for i, ruleOptions := range options.Rules {
|
||||||
routeRule, err := NewRule(router, logger, ruleOptions)
|
routeRule, err := NewRule(router, logger, ruleOptions)
|
||||||
|
@ -540,14 +542,18 @@ func (r *Router) AutoDetectInterface() bool {
|
||||||
return r.autoDetectInterface
|
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 {
|
if r.interfaceMonitor == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return r.interfaceMonitor.DefaultInterfaceName()
|
return r.interfaceMonitor.DefaultInterfaceName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) DefaultInterfaceIndex() int {
|
func (r *Router) AutoDetectInterfaceIndex() int {
|
||||||
if r.interfaceMonitor == nil {
|
if r.interfaceMonitor == nil {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ require (
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 // 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-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/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/vishvananda/netlink v1.1.0 // indirect
|
github.com/vishvananda/netlink v1.1.0 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||||
|
|
|
@ -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-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 h1:s3yKbPfiNwFFGfcNUs8NcKYzor78HWmZuDl5B0dsVQI=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220715031600-dacfbcd606f4/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
|
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-20220715065926-9dc73c0bcc1d h1:wt+OEJA3EiLIjwp+DROTtIXLox+9dwMRsVY/K2MvjXo=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
|
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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
|
Loading…
Reference in a new issue