diff --git a/adapter/router.go b/adapter/router.go index 91236fed..21a55272 100644 --- a/adapter/router.go +++ b/adapter/router.go @@ -7,6 +7,7 @@ import ( "github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-dns" + "github.com/sagernet/sing/common/control" N "github.com/sagernet/sing/common/network" "golang.org/x/net/dns/dnsmessage" @@ -14,15 +15,21 @@ import ( type Router interface { Service + Outbound(tag string) (Outbound, bool) DefaultOutbound(network string) Outbound + RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error + GeoIPReader() *geoip.Reader LoadGeosite(code string) (Rule, error) + Exchange(ctx context.Context, message *dnsmessage.Message) (*dnsmessage.Message, error) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error) + + InterfaceBindManager() control.BindManager AutoDetectInterface() bool DefaultInterfaceName() string DefaultInterfaceIndex() int diff --git a/common/dialer/default.go b/common/dialer/default.go index eb0567a5..0d835e48 100644 --- a/common/dialer/default.go +++ b/common/dialer/default.go @@ -3,6 +3,7 @@ package dialer import ( "context" "net" + "runtime" "time" "github.com/sagernet/sing-box/adapter" @@ -23,11 +24,24 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia var dialer net.Dialer var listener net.ListenConfig if options.BindInterface != "" { - dialer.Control = control.Append(dialer.Control, control.BindToInterface(options.BindInterface)) - listener.Control = control.Append(listener.Control, control.BindToInterface(options.BindInterface)) + dialer.Control = control.Append(dialer.Control, control.BindToInterface(router.InterfaceBindManager(), options.BindInterface)) + listener.Control = control.Append(listener.Control, control.BindToInterface(router.InterfaceBindManager(), options.BindInterface)) } else if router.AutoDetectInterface() { - dialer.Control = BindToInterface(router) - listener.Control = BindToInterface(router) + if runtime.GOOS == "windows" { + dialer.Control = control.Append(dialer.Control, control.BindToInterfaceIndexFunc(func() int { + return router.DefaultInterfaceIndex() + })) + listener.Control = control.Append(listener.Control, control.BindToInterfaceIndexFunc(func() int { + return router.DefaultInterfaceIndex() + })) + } else { + dialer.Control = control.Append(dialer.Control, control.BindToInterfaceFunc(router.InterfaceBindManager(), func() string { + return router.DefaultInterfaceName() + })) + listener.Control = control.Append(listener.Control, control.BindToInterfaceFunc(router.InterfaceBindManager(), func() string { + return router.DefaultInterfaceName() + })) + } } if options.RoutingMark != 0 { dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark)) diff --git a/go.mod b/go.mod index 5890f800..e5709b81 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,10 @@ require ( github.com/goccy/go-json v0.9.8 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/oschwald/maxminddb-golang v1.9.0 - github.com/sagernet/sing v0.0.0-20220714121943-f8c0f71a89f5 + 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-20220714111527-a6fa7ada6e81 - github.com/sagernet/sing-tun v0.0.0-20220714105342-455aba7939ae + github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361 github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.8.0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d diff --git a/go.sum b/go.sum index 8535de68..889d7af7 100644 --- a/go.sum +++ b/go.sum @@ -25,14 +25,14 @@ github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagernet/sing v0.0.0-20220714121943-f8c0f71a89f5 h1:OdcGVZQxCe8xlb4jc5LWrYFu54Tz4IULxLco44qOnN8= -github.com/sagernet/sing v0.0.0-20220714121943-f8c0f71a89f5/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c= +github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0 h1:8tnMLN6jdqKkjPXwgEekwloPaAmvbxQAMMHdWYOiMj8= +github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk= github.com/sagernet/sing-shadowsocks v0.0.0-20220714111527-a6fa7ada6e81 h1:VuUk/04yCr3dw2uJj0/OFVeVO5O2dwYGlj/RzuEfYDE= github.com/sagernet/sing-shadowsocks v0.0.0-20220714111527-a6fa7ada6e81/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw= -github.com/sagernet/sing-tun v0.0.0-20220714105342-455aba7939ae h1:kTchVdHf8akqVEwuG59JpwGwcUNDQWys8cxP7IVvNbE= -github.com/sagernet/sing-tun v0.0.0-20220714105342-455aba7939ae/go.mod h1:oIK1kg8hkeA5zNSv9BcbTPzdR00bbVBt6eYvJp+rsck= +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/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= diff --git a/route/router.go b/route/router.go index a89af693..5947f898 100644 --- a/route/router.go +++ b/route/router.go @@ -22,10 +22,11 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-dns" - tun "github.com/sagernet/sing-tun" + "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" M "github.com/sagernet/sing/common/metadata" @@ -64,8 +65,10 @@ type Router struct { transports []dns.Transport transportMap map[string]dns.Transport - autoDetectInterface bool - interfaceMonitor tun.InterfaceMonitor + interfaceBindManager control.BindManager + networkMonitor tun.NetworkUpdateMonitor + autoDetectInterface bool + interfaceMonitor tun.DefaultInterfaceMonitor } func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.ContextLogger, options option.RouteOptions, dnsOptions option.DNSOptions) (*Router, error) { @@ -84,6 +87,7 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont defaultDetour: options.Final, dnsClient: dns.NewClient(dns.DomainStrategy(dnsOptions.DNSClientOptions.Strategy), dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire), defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy), + interfaceBindManager: control.NewBindManager(), autoDetectInterface: options.AutoDetectInterface, } for i, ruleOptions := range options.Rules { @@ -192,14 +196,24 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont router.transports = transports router.transportMap = transportMap - if options.AutoDetectInterface { - monitor, err := tun.NewMonitor(func() { + if router.interfaceBindManager != nil || options.AutoDetectInterface { + networkMonitor, err := tun.NewNetworkUpdateMonitor(router) + if err == nil { + router.networkMonitor = networkMonitor + if router.interfaceBindManager != nil { + networkMonitor.RegisterCallback(router.interfaceBindManager.Update) + } + } + } + + if router.networkMonitor != nil && options.AutoDetectInterface { + interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, func() { router.logger.Info("updated default interface ", router.interfaceMonitor.DefaultInterfaceName(), ", index ", router.interfaceMonitor.DefaultInterfaceIndex()) }) if err != nil { return nil, E.New("auto_detect_interface unsupported on current platform") } - router.interfaceMonitor = monitor + router.interfaceMonitor = interfaceMonitor } return router, nil } @@ -329,6 +343,12 @@ func (r *Router) Start() error { return err } } + if r.networkMonitor != nil { + err := r.networkMonitor.Start() + if err != nil { + return err + } + } return nil } @@ -348,6 +368,7 @@ func (r *Router) Close() error { return common.Close( common.PtrOrNil(r.geoIPReader), r.interfaceMonitor, + r.networkMonitor, ) } @@ -511,6 +532,10 @@ func (r *Router) matchDNS(ctx context.Context) dns.Transport { return r.defaultTransport } +func (r *Router) InterfaceBindManager() control.BindManager { + return r.interfaceBindManager +} + func (r *Router) AutoDetectInterface() bool { return r.autoDetectInterface } @@ -524,7 +549,7 @@ func (r *Router) DefaultInterfaceName() string { func (r *Router) DefaultInterfaceIndex() int { if r.interfaceMonitor == nil { - return 0 + return -1 } return r.interfaceMonitor.DefaultInterfaceIndex() } @@ -749,3 +774,7 @@ func (r *Router) downloadGeositeDatabase(savePath string) error { _, err = io.Copy(saveFile, response.Body) return err } + +func (r *Router) NewError(ctx context.Context, err error) { + r.logger.ErrorContext(ctx, err) +} diff --git a/test/clash_test.go b/test/clash_test.go index 76be36b7..f5d31d44 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -17,9 +17,9 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/client" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/sagernet/sing-box/log" ) // kanged from clash @@ -75,7 +75,7 @@ func init() { continue } - logrus.Info("pulling image: ", image) + log.Info("pulling image: ", image) imageStream, err := dockerClient.ImagePull(context.Background(), image, types.ImagePullOptions{}) if err != nil { panic(err) diff --git a/test/go.mod b/test/go.mod index a098068b..98640597 100644 --- a/test/go.mod +++ b/test/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/docker/docker v20.10.17+incompatible github.com/docker/go-connections v0.4.0 - github.com/sagernet/sing v0.0.0-20220714121943-f8c0f71a89f5 + github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0 github.com/sagernet/sing-box v0.0.0 github.com/stretchr/testify v1.8.0 golang.org/x/net v0.0.0-20220708220712-1185a9018129 @@ -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-20220714111527-a6fa7ada6e81 // indirect - github.com/sagernet/sing-tun v0.0.0-20220714105342-455aba7939ae // indirect + github.com/sagernet/sing-tun v0.0.0-20220714151007-c0d248af0361 // 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 diff --git a/test/go.sum b/test/go.sum index dfbff795..cdaba883 100644 --- a/test/go.sum +++ b/test/go.sum @@ -52,14 +52,14 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sagernet/sing v0.0.0-20220714121943-f8c0f71a89f5 h1:OdcGVZQxCe8xlb4jc5LWrYFu54Tz4IULxLco44qOnN8= -github.com/sagernet/sing v0.0.0-20220714121943-f8c0f71a89f5/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c= +github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0 h1:8tnMLN6jdqKkjPXwgEekwloPaAmvbxQAMMHdWYOiMj8= +github.com/sagernet/sing v0.0.0-20220714145306-09b55ce4b6d0/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk= github.com/sagernet/sing-shadowsocks v0.0.0-20220714111527-a6fa7ada6e81 h1:VuUk/04yCr3dw2uJj0/OFVeVO5O2dwYGlj/RzuEfYDE= github.com/sagernet/sing-shadowsocks v0.0.0-20220714111527-a6fa7ada6e81/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw= -github.com/sagernet/sing-tun v0.0.0-20220714105342-455aba7939ae h1:kTchVdHf8akqVEwuG59JpwGwcUNDQWys8cxP7IVvNbE= -github.com/sagernet/sing-tun v0.0.0-20220714105342-455aba7939ae/go.mod h1:oIK1kg8hkeA5zNSv9BcbTPzdR00bbVBt6eYvJp+rsck= +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/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=