12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349 |
- package route
- import (
- "context"
- "errors"
- "net"
- "net/netip"
- "net/url"
- "os"
- "os/user"
- "runtime"
- "strings"
- "time"
- "github.com/sagernet/sing-box/adapter"
- "github.com/sagernet/sing-box/common/conntrack"
- "github.com/sagernet/sing-box/common/dialer"
- "github.com/sagernet/sing-box/common/geoip"
- "github.com/sagernet/sing-box/common/geosite"
- "github.com/sagernet/sing-box/common/process"
- "github.com/sagernet/sing-box/common/sniff"
- "github.com/sagernet/sing-box/common/taskmonitor"
- C "github.com/sagernet/sing-box/constant"
- "github.com/sagernet/sing-box/experimental/libbox/platform"
- "github.com/sagernet/sing-box/log"
- "github.com/sagernet/sing-box/option"
- "github.com/sagernet/sing-box/outbound"
- "github.com/sagernet/sing-box/transport/fakeip"
- "github.com/sagernet/sing-dns"
- "github.com/sagernet/sing-mux"
- "github.com/sagernet/sing-tun"
- "github.com/sagernet/sing-vmess"
- "github.com/sagernet/sing/common"
- "github.com/sagernet/sing/common/buf"
- "github.com/sagernet/sing/common/bufio"
- "github.com/sagernet/sing/common/bufio/deadline"
- "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"
- N "github.com/sagernet/sing/common/network"
- "github.com/sagernet/sing/common/ntp"
- "github.com/sagernet/sing/common/task"
- "github.com/sagernet/sing/common/uot"
- "github.com/sagernet/sing/common/winpowrprof"
- "github.com/sagernet/sing/service"
- "github.com/sagernet/sing/service/pause"
- )
- var _ adapter.Router = (*Router)(nil)
- type Router struct {
- ctx context.Context
- logger log.ContextLogger
- dnsLogger log.ContextLogger
- inboundByTag map[string]adapter.Inbound
- outbounds []adapter.Outbound
- outboundByTag map[string]adapter.Outbound
- rules []adapter.Rule
- defaultDetour string
- defaultOutboundForConnection adapter.Outbound
- defaultOutboundForPacketConnection adapter.Outbound
- needGeoIPDatabase bool
- needGeositeDatabase bool
- geoIPOptions option.GeoIPOptions
- geositeOptions option.GeositeOptions
- geoIPReader *geoip.Reader
- geositeReader *geosite.Reader
- geositeCache map[string]adapter.Rule
- needFindProcess bool
- dnsClient *dns.Client
- defaultDomainStrategy dns.DomainStrategy
- dnsRules []adapter.DNSRule
- ruleSets []adapter.RuleSet
- ruleSetMap map[string]adapter.RuleSet
- defaultTransport dns.Transport
- transports []dns.Transport
- transportMap map[string]dns.Transport
- transportDomainStrategy map[dns.Transport]dns.DomainStrategy
- dnsReverseMapping *DNSReverseMapping
- fakeIPStore adapter.FakeIPStore
- interfaceFinder *control.DefaultInterfaceFinder
- autoDetectInterface bool
- defaultInterface string
- defaultMark uint32
- autoRedirectOutputMark uint32
- networkMonitor tun.NetworkUpdateMonitor
- interfaceMonitor tun.DefaultInterfaceMonitor
- packageManager tun.PackageManager
- powerListener winpowrprof.EventListener
- processSearcher process.Searcher
- timeService *ntp.Service
- pauseManager pause.Manager
- clashServer adapter.ClashServer
- v2rayServer adapter.V2RayServer
- platformInterface platform.Interface
- needWIFIState bool
- needPackageManager bool
- wifiState adapter.WIFIState
- started bool
- }
- func NewRouter(
- ctx context.Context,
- logFactory log.Factory,
- options option.RouteOptions,
- dnsOptions option.DNSOptions,
- ntpOptions option.NTPOptions,
- inbounds []option.Inbound,
- platformInterface platform.Interface,
- ) (*Router, error) {
- router := &Router{
- ctx: ctx,
- logger: logFactory.NewLogger("router"),
- dnsLogger: logFactory.NewLogger("dns"),
- outboundByTag: make(map[string]adapter.Outbound),
- rules: make([]adapter.Rule, 0, len(options.Rules)),
- dnsRules: make([]adapter.DNSRule, 0, len(dnsOptions.Rules)),
- ruleSetMap: make(map[string]adapter.RuleSet),
- needGeoIPDatabase: hasRule(options.Rules, isGeoIPRule) || hasDNSRule(dnsOptions.Rules, isGeoIPDNSRule),
- needGeositeDatabase: hasRule(options.Rules, isGeositeRule) || hasDNSRule(dnsOptions.Rules, isGeositeDNSRule),
- geoIPOptions: common.PtrValueOrDefault(options.GeoIP),
- geositeOptions: common.PtrValueOrDefault(options.Geosite),
- geositeCache: make(map[string]adapter.Rule),
- needFindProcess: hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess,
- defaultDetour: options.Final,
- defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy),
- interfaceFinder: control.NewDefaultInterfaceFinder(),
- autoDetectInterface: options.AutoDetectInterface,
- defaultInterface: options.DefaultInterface,
- defaultMark: options.DefaultMark,
- pauseManager: service.FromContext[pause.Manager](ctx),
- platformInterface: platformInterface,
- needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule),
- needPackageManager: common.Any(inbounds, func(inbound option.Inbound) bool {
- return len(inbound.TunOptions.IncludePackage) > 0 || len(inbound.TunOptions.ExcludePackage) > 0
- }),
- }
- router.dnsClient = dns.NewClient(dns.ClientOptions{
- DisableCache: dnsOptions.DNSClientOptions.DisableCache,
- DisableExpire: dnsOptions.DNSClientOptions.DisableExpire,
- IndependentCache: dnsOptions.DNSClientOptions.IndependentCache,
- RDRC: func() dns.RDRCStore {
- cacheFile := service.FromContext[adapter.CacheFile](ctx)
- if cacheFile == nil {
- return nil
- }
- if !cacheFile.StoreRDRC() {
- return nil
- }
- return cacheFile
- },
- Logger: router.dnsLogger,
- })
- for i, ruleOptions := range options.Rules {
- routeRule, err := NewRule(router, router.logger, ruleOptions, true)
- if err != nil {
- return nil, E.Cause(err, "parse rule[", i, "]")
- }
- router.rules = append(router.rules, routeRule)
- }
- for i, dnsRuleOptions := range dnsOptions.Rules {
- dnsRule, err := NewDNSRule(router, router.logger, dnsRuleOptions, true)
- if err != nil {
- return nil, E.Cause(err, "parse dns rule[", i, "]")
- }
- router.dnsRules = append(router.dnsRules, dnsRule)
- }
- for i, ruleSetOptions := range options.RuleSet {
- if _, exists := router.ruleSetMap[ruleSetOptions.Tag]; exists {
- return nil, E.New("duplicate rule-set tag: ", ruleSetOptions.Tag)
- }
- ruleSet, err := NewRuleSet(ctx, router, router.logger, ruleSetOptions)
- if err != nil {
- return nil, E.Cause(err, "parse rule-set[", i, "]")
- }
- router.ruleSets = append(router.ruleSets, ruleSet)
- router.ruleSetMap[ruleSetOptions.Tag] = ruleSet
- }
- transports := make([]dns.Transport, len(dnsOptions.Servers))
- dummyTransportMap := make(map[string]dns.Transport)
- transportMap := make(map[string]dns.Transport)
- transportTags := make([]string, len(dnsOptions.Servers))
- transportTagMap := make(map[string]bool)
- transportDomainStrategy := make(map[dns.Transport]dns.DomainStrategy)
- for i, server := range dnsOptions.Servers {
- var tag string
- if server.Tag != "" {
- tag = server.Tag
- } else {
- tag = F.ToString(i)
- }
- if transportTagMap[tag] {
- return nil, E.New("duplicate dns server tag: ", tag)
- }
- transportTags[i] = tag
- transportTagMap[tag] = true
- }
- ctx = adapter.ContextWithRouter(ctx, router)
- for {
- lastLen := len(dummyTransportMap)
- for i, server := range dnsOptions.Servers {
- tag := transportTags[i]
- if _, exists := dummyTransportMap[tag]; exists {
- continue
- }
- var detour N.Dialer
- if server.Detour == "" {
- detour = dialer.NewRouter(router)
- } else {
- detour = dialer.NewDetour(router, server.Detour)
- }
- switch server.Address {
- case "local":
- default:
- serverURL, _ := url.Parse(server.Address)
- var serverAddress string
- if serverURL != nil {
- serverAddress = serverURL.Hostname()
- }
- if serverAddress == "" {
- serverAddress = server.Address
- }
- notIpAddress := !M.ParseSocksaddr(serverAddress).Addr.IsValid()
- if server.AddressResolver != "" {
- if !transportTagMap[server.AddressResolver] {
- return nil, E.New("parse dns server[", tag, "]: address resolver not found: ", server.AddressResolver)
- }
- if upstream, exists := dummyTransportMap[server.AddressResolver]; exists {
- detour = dns.NewDialerWrapper(detour, router.dnsClient, upstream, dns.DomainStrategy(server.AddressStrategy), time.Duration(server.AddressFallbackDelay))
- } else {
- continue
- }
- } else if notIpAddress && strings.Contains(server.Address, ".") {
- return nil, E.New("parse dns server[", tag, "]: missing address_resolver")
- }
- }
- var clientSubnet netip.Prefix
- if server.ClientSubnet != nil {
- clientSubnet = server.ClientSubnet.Build()
- } else if dnsOptions.ClientSubnet != nil {
- clientSubnet = dnsOptions.ClientSubnet.Build()
- }
- transport, err := dns.CreateTransport(dns.TransportOptions{
- Context: ctx,
- Logger: logFactory.NewLogger(F.ToString("dns/transport[", tag, "]")),
- Name: tag,
- Dialer: detour,
- Address: server.Address,
- ClientSubnet: clientSubnet,
- })
- if err != nil {
- return nil, E.Cause(err, "parse dns server[", tag, "]")
- }
- transports[i] = transport
- dummyTransportMap[tag] = transport
- if server.Tag != "" {
- transportMap[server.Tag] = transport
- }
- strategy := dns.DomainStrategy(server.Strategy)
- if strategy != dns.DomainStrategyAsIS {
- transportDomainStrategy[transport] = strategy
- }
- }
- if len(transports) == len(dummyTransportMap) {
- break
- }
- if lastLen != len(dummyTransportMap) {
- continue
- }
- unresolvedTags := common.MapIndexed(common.FilterIndexed(dnsOptions.Servers, func(index int, server option.DNSServerOptions) bool {
- _, exists := dummyTransportMap[transportTags[index]]
- return !exists
- }), func(index int, server option.DNSServerOptions) string {
- return transportTags[index]
- })
- if len(unresolvedTags) == 0 {
- panic(F.ToString("unexpected unresolved dns servers: ", len(transports), " ", len(dummyTransportMap), " ", len(transportMap)))
- }
- return nil, E.New("found circular reference in dns servers: ", strings.Join(unresolvedTags, " "))
- }
- var defaultTransport dns.Transport
- if dnsOptions.Final != "" {
- defaultTransport = dummyTransportMap[dnsOptions.Final]
- if defaultTransport == nil {
- return nil, E.New("default dns server not found: ", dnsOptions.Final)
- }
- }
- if defaultTransport == nil {
- if len(transports) == 0 {
- transports = append(transports, common.Must1(dns.CreateTransport(dns.TransportOptions{
- Context: ctx,
- Name: "local",
- Address: "local",
- Dialer: common.Must1(dialer.NewDefault(router, option.DialerOptions{})),
- })))
- }
- defaultTransport = transports[0]
- }
- if _, isFakeIP := defaultTransport.(adapter.FakeIPTransport); isFakeIP {
- return nil, E.New("default DNS server cannot be fakeip")
- }
- router.defaultTransport = defaultTransport
- router.transports = transports
- router.transportMap = transportMap
- router.transportDomainStrategy = transportDomainStrategy
- if dnsOptions.ReverseMapping {
- router.dnsReverseMapping = NewDNSReverseMapping()
- }
- if fakeIPOptions := dnsOptions.FakeIP; fakeIPOptions != nil && dnsOptions.FakeIP.Enabled {
- var inet4Range netip.Prefix
- var inet6Range netip.Prefix
- if fakeIPOptions.Inet4Range != nil {
- inet4Range = *fakeIPOptions.Inet4Range
- }
- if fakeIPOptions.Inet6Range != nil {
- inet6Range = *fakeIPOptions.Inet6Range
- }
- router.fakeIPStore = fakeip.NewStore(ctx, router.logger, inet4Range, inet6Range)
- }
- usePlatformDefaultInterfaceMonitor := platformInterface != nil && platformInterface.UsePlatformDefaultInterfaceMonitor()
- needInterfaceMonitor := options.AutoDetectInterface || common.Any(inbounds, func(inbound option.Inbound) bool {
- return inbound.HTTPOptions.SetSystemProxy || inbound.MixedOptions.SetSystemProxy || inbound.TunOptions.AutoRoute
- })
- if !usePlatformDefaultInterfaceMonitor {
- networkMonitor, err := tun.NewNetworkUpdateMonitor(router.logger)
- if !((err != nil && !needInterfaceMonitor) || errors.Is(err, os.ErrInvalid)) {
- if err != nil {
- return nil, err
- }
- router.networkMonitor = networkMonitor
- networkMonitor.RegisterCallback(func() {
- _ = router.interfaceFinder.Update()
- })
- interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, router.logger, tun.DefaultInterfaceMonitorOptions{
- OverrideAndroidVPN: options.OverrideAndroidVPN,
- UnderNetworkExtension: platformInterface != nil && platformInterface.UnderNetworkExtension(),
- })
- if err != nil {
- return nil, E.New("auto_detect_interface unsupported on current platform")
- }
- interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
- router.interfaceMonitor = interfaceMonitor
- }
- } else {
- interfaceMonitor := platformInterface.CreateDefaultInterfaceMonitor(router.logger)
- interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
- router.interfaceMonitor = interfaceMonitor
- }
- if ntpOptions.Enabled {
- ntpDialer, err := dialer.New(router, ntpOptions.DialerOptions)
- if err != nil {
- return nil, E.Cause(err, "create NTP service")
- }
- timeService := ntp.NewService(ntp.Options{
- Context: ctx,
- Dialer: ntpDialer,
- Logger: logFactory.NewLogger("ntp"),
- Server: ntpOptions.ServerOptions.Build(),
- Interval: time.Duration(ntpOptions.Interval),
- WriteToSystem: ntpOptions.WriteToSystem,
- })
- service.MustRegister[ntp.TimeService](ctx, timeService)
- router.timeService = timeService
- }
- return router, nil
- }
- func (r *Router) Initialize(inbounds []adapter.Inbound, outbounds []adapter.Outbound, defaultOutbound func() adapter.Outbound) error {
- inboundByTag := make(map[string]adapter.Inbound)
- for _, inbound := range inbounds {
- inboundByTag[inbound.Tag()] = inbound
- }
- outboundByTag := make(map[string]adapter.Outbound)
- for _, detour := range outbounds {
- outboundByTag[detour.Tag()] = detour
- }
- var defaultOutboundForConnection adapter.Outbound
- var defaultOutboundForPacketConnection adapter.Outbound
- if r.defaultDetour != "" {
- detour, loaded := outboundByTag[r.defaultDetour]
- if !loaded {
- return E.New("default detour not found: ", r.defaultDetour)
- }
- if common.Contains(detour.Network(), N.NetworkTCP) {
- defaultOutboundForConnection = detour
- }
- if common.Contains(detour.Network(), N.NetworkUDP) {
- defaultOutboundForPacketConnection = detour
- }
- }
- if defaultOutboundForConnection == nil {
- for _, detour := range outbounds {
- if common.Contains(detour.Network(), N.NetworkTCP) {
- defaultOutboundForConnection = detour
- break
- }
- }
- }
- if defaultOutboundForPacketConnection == nil {
- for _, detour := range outbounds {
- if common.Contains(detour.Network(), N.NetworkUDP) {
- defaultOutboundForPacketConnection = detour
- break
- }
- }
- }
- if defaultOutboundForConnection == nil || defaultOutboundForPacketConnection == nil {
- detour := defaultOutbound()
- if defaultOutboundForConnection == nil {
- defaultOutboundForConnection = detour
- }
- if defaultOutboundForPacketConnection == nil {
- defaultOutboundForPacketConnection = detour
- }
- outbounds = append(outbounds, detour)
- outboundByTag[detour.Tag()] = detour
- }
- r.inboundByTag = inboundByTag
- r.outbounds = outbounds
- r.defaultOutboundForConnection = defaultOutboundForConnection
- r.defaultOutboundForPacketConnection = defaultOutboundForPacketConnection
- r.outboundByTag = outboundByTag
- for i, rule := range r.rules {
- if _, loaded := outboundByTag[rule.Outbound()]; !loaded {
- return E.New("outbound not found for rule[", i, "]: ", rule.Outbound())
- }
- }
- return nil
- }
- func (r *Router) Outbounds() []adapter.Outbound {
- if !r.started {
- return nil
- }
- return r.outbounds
- }
- func (r *Router) PreStart() error {
- monitor := taskmonitor.New(r.logger, C.StartTimeout)
- if r.interfaceMonitor != nil {
- monitor.Start("initialize interface monitor")
- err := r.interfaceMonitor.Start()
- monitor.Finish()
- if err != nil {
- return err
- }
- }
- if r.networkMonitor != nil {
- monitor.Start("initialize network monitor")
- err := r.networkMonitor.Start()
- monitor.Finish()
- if err != nil {
- return err
- }
- }
- if r.fakeIPStore != nil {
- monitor.Start("initialize fakeip store")
- err := r.fakeIPStore.Start()
- monitor.Finish()
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (r *Router) Start() error {
- monitor := taskmonitor.New(r.logger, C.StartTimeout)
- if r.needGeoIPDatabase {
- monitor.Start("initialize geoip database")
- err := r.prepareGeoIPDatabase()
- monitor.Finish()
- if err != nil {
- return err
- }
- }
- if r.needGeositeDatabase {
- monitor.Start("initialize geosite database")
- err := r.prepareGeositeDatabase()
- monitor.Finish()
- if err != nil {
- return err
- }
- }
- if r.needGeositeDatabase {
- for _, rule := range r.rules {
- err := rule.UpdateGeosite()
- if err != nil {
- r.logger.Error("failed to initialize geosite: ", err)
- }
- }
- for _, rule := range r.dnsRules {
- err := rule.UpdateGeosite()
- if err != nil {
- r.logger.Error("failed to initialize geosite: ", err)
- }
- }
- err := common.Close(r.geositeReader)
- if err != nil {
- return err
- }
- r.geositeCache = nil
- r.geositeReader = nil
- }
- if runtime.GOOS == "windows" {
- powerListener, err := winpowrprof.NewEventListener(r.notifyWindowsPowerEvent)
- if err == nil {
- r.powerListener = powerListener
- } else {
- r.logger.Warn("initialize power listener: ", err)
- }
- }
- if r.powerListener != nil {
- monitor.Start("start power listener")
- err := r.powerListener.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "start power listener")
- }
- }
- monitor.Start("initialize DNS client")
- r.dnsClient.Start()
- monitor.Finish()
- if C.IsAndroid && r.platformInterface == nil {
- monitor.Start("initialize package manager")
- packageManager, err := tun.NewPackageManager(tun.PackageManagerOptions{
- Callback: r,
- Logger: r.logger,
- })
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "create package manager")
- }
- if r.needPackageManager {
- monitor.Start("start package manager")
- err = packageManager.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "start package manager")
- }
- }
- r.packageManager = packageManager
- }
- for i, rule := range r.dnsRules {
- monitor.Start("initialize DNS rule[", i, "]")
- err := rule.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "initialize DNS rule[", i, "]")
- }
- }
- for i, transport := range r.transports {
- monitor.Start("initialize DNS transport[", i, "]")
- err := transport.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "initialize DNS server[", i, "]")
- }
- }
- if r.timeService != nil {
- monitor.Start("initialize time service")
- err := r.timeService.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "initialize time service")
- }
- }
- return nil
- }
- func (r *Router) Close() error {
- monitor := taskmonitor.New(r.logger, C.StopTimeout)
- var err error
- for i, rule := range r.rules {
- monitor.Start("close rule[", i, "]")
- err = E.Append(err, rule.Close(), func(err error) error {
- return E.Cause(err, "close rule[", i, "]")
- })
- monitor.Finish()
- }
- for i, rule := range r.dnsRules {
- monitor.Start("close dns rule[", i, "]")
- err = E.Append(err, rule.Close(), func(err error) error {
- return E.Cause(err, "close dns rule[", i, "]")
- })
- monitor.Finish()
- }
- for i, transport := range r.transports {
- monitor.Start("close dns transport[", i, "]")
- err = E.Append(err, transport.Close(), func(err error) error {
- return E.Cause(err, "close dns transport[", i, "]")
- })
- monitor.Finish()
- }
- if r.geoIPReader != nil {
- monitor.Start("close geoip reader")
- err = E.Append(err, r.geoIPReader.Close(), func(err error) error {
- return E.Cause(err, "close geoip reader")
- })
- monitor.Finish()
- }
- if r.interfaceMonitor != nil {
- monitor.Start("close interface monitor")
- err = E.Append(err, r.interfaceMonitor.Close(), func(err error) error {
- return E.Cause(err, "close interface monitor")
- })
- monitor.Finish()
- }
- if r.networkMonitor != nil {
- monitor.Start("close network monitor")
- err = E.Append(err, r.networkMonitor.Close(), func(err error) error {
- return E.Cause(err, "close network monitor")
- })
- monitor.Finish()
- }
- if r.packageManager != nil {
- monitor.Start("close package manager")
- err = E.Append(err, r.packageManager.Close(), func(err error) error {
- return E.Cause(err, "close package manager")
- })
- monitor.Finish()
- }
- if r.powerListener != nil {
- monitor.Start("close power listener")
- err = E.Append(err, r.powerListener.Close(), func(err error) error {
- return E.Cause(err, "close power listener")
- })
- monitor.Finish()
- }
- if r.timeService != nil {
- monitor.Start("close time service")
- err = E.Append(err, r.timeService.Close(), func(err error) error {
- return E.Cause(err, "close time service")
- })
- monitor.Finish()
- }
- if r.fakeIPStore != nil {
- monitor.Start("close fakeip store")
- err = E.Append(err, r.fakeIPStore.Close(), func(err error) error {
- return E.Cause(err, "close fakeip store")
- })
- monitor.Finish()
- }
- return err
- }
- func (r *Router) PostStart() error {
- monitor := taskmonitor.New(r.logger, C.StopTimeout)
- if len(r.ruleSets) > 0 {
- monitor.Start("initialize rule-set")
- ruleSetStartContext := NewRuleSetStartContext()
- var ruleSetStartGroup task.Group
- for i, ruleSet := range r.ruleSets {
- ruleSetInPlace := ruleSet
- ruleSetStartGroup.Append0(func(ctx context.Context) error {
- err := ruleSetInPlace.StartContext(ctx, ruleSetStartContext)
- if err != nil {
- return E.Cause(err, "initialize rule-set[", i, "]")
- }
- return nil
- })
- }
- ruleSetStartGroup.Concurrency(5)
- ruleSetStartGroup.FastFail()
- err := ruleSetStartGroup.Run(r.ctx)
- monitor.Finish()
- if err != nil {
- return err
- }
- ruleSetStartContext.Close()
- }
- needFindProcess := r.needFindProcess
- needWIFIState := r.needWIFIState
- for _, ruleSet := range r.ruleSets {
- metadata := ruleSet.Metadata()
- if metadata.ContainsProcessRule {
- needFindProcess = true
- }
- if metadata.ContainsWIFIRule {
- needWIFIState = true
- }
- }
- if C.IsAndroid && r.platformInterface == nil && !r.needPackageManager {
- if needFindProcess {
- monitor.Start("start package manager")
- err := r.packageManager.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "start package manager")
- }
- } else {
- r.packageManager = nil
- }
- }
- if needFindProcess {
- if r.platformInterface != nil {
- r.processSearcher = r.platformInterface
- } else {
- monitor.Start("initialize process searcher")
- searcher, err := process.NewSearcher(process.Config{
- Logger: r.logger,
- PackageManager: r.packageManager,
- })
- monitor.Finish()
- if err != nil {
- if err != os.ErrInvalid {
- r.logger.Warn(E.Cause(err, "create process searcher"))
- }
- } else {
- r.processSearcher = searcher
- }
- }
- }
- if needWIFIState && r.platformInterface != nil {
- monitor.Start("initialize WIFI state")
- r.needWIFIState = true
- r.interfaceMonitor.RegisterCallback(func(_ int) {
- r.updateWIFIState()
- })
- r.updateWIFIState()
- monitor.Finish()
- }
- for i, rule := range r.rules {
- monitor.Start("initialize rule[", i, "]")
- err := rule.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "initialize rule[", i, "]")
- }
- }
- for _, ruleSet := range r.ruleSets {
- monitor.Start("post start rule_set[", ruleSet.Name(), "]")
- err := ruleSet.PostStart()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "post start rule_set[", ruleSet.Name(), "]")
- }
- }
- r.started = true
- return nil
- }
- func (r *Router) Cleanup() error {
- for _, ruleSet := range r.ruleSetMap {
- ruleSet.Cleanup()
- }
- runtime.GC()
- return nil
- }
- func (r *Router) Outbound(tag string) (adapter.Outbound, bool) {
- outbound, loaded := r.outboundByTag[tag]
- return outbound, loaded
- }
- func (r *Router) DefaultOutbound(network string) (adapter.Outbound, error) {
- if network == N.NetworkTCP {
- if r.defaultOutboundForConnection == nil {
- return nil, E.New("missing default outbound for TCP connections")
- }
- return r.defaultOutboundForConnection, nil
- } else {
- if r.defaultOutboundForPacketConnection == nil {
- return nil, E.New("missing default outbound for UDP connections")
- }
- return r.defaultOutboundForPacketConnection, nil
- }
- }
- func (r *Router) FakeIPStore() adapter.FakeIPStore {
- return r.fakeIPStore
- }
- func (r *Router) RuleSet(tag string) (adapter.RuleSet, bool) {
- ruleSet, loaded := r.ruleSetMap[tag]
- return ruleSet, loaded
- }
- func (r *Router) NeedWIFIState() bool {
- return r.needWIFIState
- }
- func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
- if r.pauseManager.IsDevicePaused() {
- return E.New("reject connection to ", metadata.Destination, " while device paused")
- }
- if metadata.InboundDetour != "" {
- if metadata.LastInbound == metadata.InboundDetour {
- return E.New("routing loop on detour: ", metadata.InboundDetour)
- }
- detour := r.inboundByTag[metadata.InboundDetour]
- if detour == nil {
- return E.New("inbound detour not found: ", metadata.InboundDetour)
- }
- injectable, isInjectable := detour.(adapter.InjectableInbound)
- if !isInjectable {
- return E.New("inbound detour is not injectable: ", metadata.InboundDetour)
- }
- if !common.Contains(injectable.Network(), N.NetworkTCP) {
- return E.New("inject: TCP unsupported")
- }
- metadata.LastInbound = metadata.Inbound
- metadata.Inbound = metadata.InboundDetour
- metadata.InboundDetour = ""
- err := injectable.NewConnection(ctx, conn, metadata)
- if err != nil {
- return E.Cause(err, "inject ", detour.Tag())
- }
- return nil
- }
- conntrack.KillerCheck()
- metadata.Network = N.NetworkTCP
- switch metadata.Destination.Fqdn {
- case mux.Destination.Fqdn:
- return E.New("global multiplex is deprecated since sing-box v1.7.0, enable multiplex in inbound options instead.")
- case vmess.MuxDestination.Fqdn:
- return E.New("global multiplex (v2ray legacy) not supported since sing-box v1.7.0.")
- case uot.MagicAddress:
- return E.New("global UoT not supported since sing-box v1.7.0.")
- case uot.LegacyMagicAddress:
- return E.New("global UoT (legacy) not supported since sing-box v1.7.0.")
- }
- if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) {
- domain, loaded := r.fakeIPStore.Lookup(metadata.Destination.Addr)
- if !loaded {
- return E.New("missing fakeip context")
- }
- metadata.OriginDestination = metadata.Destination
- metadata.Destination = M.Socksaddr{
- Fqdn: domain,
- Port: metadata.Destination.Port,
- }
- metadata.FakeIP = true
- r.logger.DebugContext(ctx, "found fakeip domain: ", domain)
- }
- if deadline.NeedAdditionalReadDeadline(conn) {
- conn = deadline.NewConn(conn)
- }
- if metadata.InboundOptions.SniffEnabled && !sniff.Skip(metadata) {
- buffer := buf.NewPacket()
- err := sniff.PeekStream(
- ctx,
- &metadata,
- conn,
- buffer,
- time.Duration(metadata.InboundOptions.SniffTimeout),
- sniff.StreamDomainNameQuery,
- sniff.TLSClientHello,
- sniff.HTTPHost,
- sniff.BitTorrent,
- )
- if err == nil {
- if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
- metadata.Destination = M.Socksaddr{
- Fqdn: metadata.Domain,
- Port: metadata.Destination.Port,
- }
- }
- if metadata.Domain != "" {
- r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
- } else {
- r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol)
- }
- }
- if !buffer.IsEmpty() {
- conn = bufio.NewCachedConn(conn, buffer)
- } else {
- buffer.Release()
- }
- }
- if r.dnsReverseMapping != nil && metadata.Domain == "" {
- domain, loaded := r.dnsReverseMapping.Query(metadata.Destination.Addr)
- if loaded {
- metadata.Domain = domain
- r.logger.DebugContext(ctx, "found reserve mapped domain: ", metadata.Domain)
- }
- }
- if metadata.Destination.IsFqdn() && dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS {
- addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, dns.DomainStrategy(metadata.InboundOptions.DomainStrategy))
- if err != nil {
- return err
- }
- metadata.DestinationAddresses = addresses
- r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]")
- }
- if metadata.Destination.IsIPv4() {
- metadata.IPVersion = 4
- } else if metadata.Destination.IsIPv6() {
- metadata.IPVersion = 6
- }
- ctx, matchedRule, detour, err := r.match(ctx, &metadata, r.defaultOutboundForConnection)
- if err != nil {
- return err
- }
- if !common.Contains(detour.Network(), N.NetworkTCP) {
- return E.New("missing supported outbound, closing connection")
- }
- if r.clashServer != nil {
- trackerConn, tracker := r.clashServer.RoutedConnection(ctx, conn, metadata, matchedRule)
- defer tracker.Leave()
- conn = trackerConn
- }
- if r.v2rayServer != nil {
- if statsService := r.v2rayServer.StatsService(); statsService != nil {
- conn = statsService.RoutedConnection(metadata.Inbound, detour.Tag(), metadata.User, conn)
- }
- }
- return detour.NewConnection(ctx, conn, metadata)
- }
- func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
- if r.pauseManager.IsDevicePaused() {
- return E.New("reject packet connection to ", metadata.Destination, " while device paused")
- }
- if metadata.InboundDetour != "" {
- if metadata.LastInbound == metadata.InboundDetour {
- return E.New("routing loop on detour: ", metadata.InboundDetour)
- }
- detour := r.inboundByTag[metadata.InboundDetour]
- if detour == nil {
- return E.New("inbound detour not found: ", metadata.InboundDetour)
- }
- injectable, isInjectable := detour.(adapter.InjectableInbound)
- if !isInjectable {
- return E.New("inbound detour is not injectable: ", metadata.InboundDetour)
- }
- if !common.Contains(injectable.Network(), N.NetworkUDP) {
- return E.New("inject: UDP unsupported")
- }
- metadata.LastInbound = metadata.Inbound
- metadata.Inbound = metadata.InboundDetour
- metadata.InboundDetour = ""
- err := injectable.NewPacketConnection(ctx, conn, metadata)
- if err != nil {
- return E.Cause(err, "inject ", detour.Tag())
- }
- return nil
- }
- conntrack.KillerCheck()
- metadata.Network = N.NetworkUDP
- if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) {
- domain, loaded := r.fakeIPStore.Lookup(metadata.Destination.Addr)
- if !loaded {
- return E.New("missing fakeip context")
- }
- metadata.OriginDestination = metadata.Destination
- metadata.Destination = M.Socksaddr{
- Fqdn: domain,
- Port: metadata.Destination.Port,
- }
- metadata.FakeIP = true
- r.logger.DebugContext(ctx, "found fakeip domain: ", domain)
- }
- // Currently we don't have deadline usages for UDP connections
- /*if deadline.NeedAdditionalReadDeadline(conn) {
- conn = deadline.NewPacketConn(bufio.NewNetPacketConn(conn))
- }*/
- if metadata.InboundOptions.SniffEnabled || metadata.Destination.Addr.IsUnspecified() {
- var bufferList []*buf.Buffer
- for {
- var (
- buffer = buf.NewPacket()
- destination M.Socksaddr
- done = make(chan struct{})
- err error
- )
- go func() {
- sniffTimeout := C.ReadPayloadTimeout
- if metadata.InboundOptions.SniffTimeout > 0 {
- sniffTimeout = time.Duration(metadata.InboundOptions.SniffTimeout)
- }
- conn.SetReadDeadline(time.Now().Add(sniffTimeout))
- destination, err = conn.ReadPacket(buffer)
- conn.SetReadDeadline(time.Time{})
- close(done)
- }()
- select {
- case <-done:
- case <-ctx.Done():
- conn.Close()
- return ctx.Err()
- }
- if err != nil {
- buffer.Release()
- if !errors.Is(err, os.ErrDeadlineExceeded) {
- return err
- }
- } else {
- if metadata.Destination.Addr.IsUnspecified() {
- metadata.Destination = destination
- }
- if metadata.InboundOptions.SniffEnabled {
- if len(bufferList) > 0 {
- err = sniff.PeekPacket(
- ctx,
- &metadata,
- buffer.Bytes(),
- sniff.QUICClientHello,
- )
- } else {
- err = sniff.PeekPacket(
- ctx, &metadata,
- buffer.Bytes(),
- sniff.DomainNameQuery,
- sniff.QUICClientHello,
- sniff.STUNMessage,
- sniff.UTP,
- sniff.UDPTracker,
- sniff.DTLSRecord)
- }
- if E.IsMulti(err, sniff.ErrClientHelloFragmented) && len(bufferList) == 0 {
- bufferList = append(bufferList, buffer)
- r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello")
- continue
- }
- if metadata.Protocol != "" {
- if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
- metadata.Destination = M.Socksaddr{
- Fqdn: metadata.Domain,
- Port: metadata.Destination.Port,
- }
- }
- if metadata.Domain != "" && metadata.Client != "" {
- r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain, ", client: ", metadata.Client)
- } else if metadata.Domain != "" {
- r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
- } else if metadata.Client != "" {
- r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", client: ", metadata.Client)
- } else {
- r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
- }
- }
- }
- conn = bufio.NewCachedPacketConn(conn, buffer, destination)
- }
- for _, cachedBuffer := range common.Reverse(bufferList) {
- conn = bufio.NewCachedPacketConn(conn, cachedBuffer, destination)
- }
- break
- }
- }
- if r.dnsReverseMapping != nil && metadata.Domain == "" {
- domain, loaded := r.dnsReverseMapping.Query(metadata.Destination.Addr)
- if loaded {
- metadata.Domain = domain
- r.logger.DebugContext(ctx, "found reserve mapped domain: ", metadata.Domain)
- }
- }
- if metadata.Destination.IsFqdn() && dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS {
- addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, dns.DomainStrategy(metadata.InboundOptions.DomainStrategy))
- if err != nil {
- return err
- }
- metadata.DestinationAddresses = addresses
- r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]")
- }
- if metadata.Destination.IsIPv4() {
- metadata.IPVersion = 4
- } else if metadata.Destination.IsIPv6() {
- metadata.IPVersion = 6
- }
- ctx, matchedRule, detour, err := r.match(ctx, &metadata, r.defaultOutboundForPacketConnection)
- if err != nil {
- return err
- }
- if !common.Contains(detour.Network(), N.NetworkUDP) {
- return E.New("missing supported outbound, closing packet connection")
- }
- if r.clashServer != nil {
- trackerConn, tracker := r.clashServer.RoutedPacketConnection(ctx, conn, metadata, matchedRule)
- defer tracker.Leave()
- conn = trackerConn
- }
- if r.v2rayServer != nil {
- if statsService := r.v2rayServer.StatsService(); statsService != nil {
- conn = statsService.RoutedPacketConnection(metadata.Inbound, detour.Tag(), metadata.User, conn)
- }
- }
- if metadata.FakeIP {
- conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, metadata.Destination)
- }
- return detour.NewPacketConnection(ctx, conn, metadata)
- }
- func (r *Router) match(ctx context.Context, metadata *adapter.InboundContext, defaultOutbound adapter.Outbound) (context.Context, adapter.Rule, adapter.Outbound, error) {
- matchRule, matchOutbound := r.match0(ctx, metadata, defaultOutbound)
- if contextOutbound, loaded := outbound.TagFromContext(ctx); loaded {
- if contextOutbound == matchOutbound.Tag() {
- return nil, nil, nil, E.New("connection loopback in outbound/", matchOutbound.Type(), "[", matchOutbound.Tag(), "]")
- }
- }
- ctx = outbound.ContextWithTag(ctx, matchOutbound.Tag())
- return ctx, matchRule, matchOutbound, nil
- }
- func (r *Router) match0(ctx context.Context, metadata *adapter.InboundContext, defaultOutbound adapter.Outbound) (adapter.Rule, adapter.Outbound) {
- if r.processSearcher != nil {
- var originDestination netip.AddrPort
- if metadata.OriginDestination.IsValid() {
- originDestination = metadata.OriginDestination.AddrPort()
- } else if metadata.Destination.IsIP() {
- originDestination = metadata.Destination.AddrPort()
- }
- processInfo, err := process.FindProcessInfo(r.processSearcher, ctx, metadata.Network, metadata.Source.AddrPort(), originDestination)
- if err != nil {
- r.logger.InfoContext(ctx, "failed to search process: ", err)
- } else {
- if processInfo.ProcessPath != "" {
- r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath)
- } else if processInfo.PackageName != "" {
- r.logger.InfoContext(ctx, "found package name: ", processInfo.PackageName)
- } else if processInfo.UserId != -1 {
- if /*needUserName &&*/ true {
- osUser, _ := user.LookupId(F.ToString(processInfo.UserId))
- if osUser != nil {
- processInfo.User = osUser.Username
- }
- }
- if processInfo.User != "" {
- r.logger.InfoContext(ctx, "found user: ", processInfo.User)
- } else {
- r.logger.InfoContext(ctx, "found user id: ", processInfo.UserId)
- }
- }
- metadata.ProcessInfo = processInfo
- }
- }
- for i, rule := range r.rules {
- metadata.ResetRuleCache()
- if rule.Match(metadata) {
- detour := rule.Outbound()
- r.logger.DebugContext(ctx, "match[", i, "] ", rule.String(), " => ", detour)
- if outbound, loaded := r.Outbound(detour); loaded {
- return rule, outbound
- }
- r.logger.ErrorContext(ctx, "outbound not found: ", detour)
- }
- }
- return nil, defaultOutbound
- }
- func (r *Router) InterfaceFinder() control.InterfaceFinder {
- return r.interfaceFinder
- }
- func (r *Router) UpdateInterfaces() error {
- if r.platformInterface == nil || !r.platformInterface.UsePlatformInterfaceGetter() {
- return r.interfaceFinder.Update()
- } else {
- interfaces, err := r.platformInterface.Interfaces()
- if err != nil {
- return err
- }
- r.interfaceFinder.UpdateInterfaces(interfaces)
- return nil
- }
- }
- func (r *Router) AutoDetectInterface() bool {
- return r.autoDetectInterface
- }
- func (r *Router) AutoDetectInterfaceFunc() control.Func {
- if r.platformInterface != nil && r.platformInterface.UsePlatformAutoDetectInterfaceControl() {
- return r.platformInterface.AutoDetectInterfaceControl()
- } else {
- if r.interfaceMonitor == nil {
- return nil
- }
- return control.BindToInterfaceFunc(r.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int, err error) {
- remoteAddr := M.ParseSocksaddr(address).Addr
- if C.IsLinux {
- interfaceName, interfaceIndex = r.InterfaceMonitor().DefaultInterface(remoteAddr)
- if interfaceIndex == -1 {
- err = tun.ErrNoRoute
- }
- } else {
- interfaceIndex = r.InterfaceMonitor().DefaultInterfaceIndex(remoteAddr)
- if interfaceIndex == -1 {
- err = tun.ErrNoRoute
- }
- }
- return
- })
- }
- }
- func (r *Router) RegisterAutoRedirectOutputMark(mark uint32) error {
- if r.autoRedirectOutputMark > 0 {
- return E.New("only one auto-redirect can be configured")
- }
- r.autoRedirectOutputMark = mark
- return nil
- }
- func (r *Router) AutoRedirectOutputMark() uint32 {
- return r.autoRedirectOutputMark
- }
- func (r *Router) DefaultInterface() string {
- return r.defaultInterface
- }
- func (r *Router) DefaultMark() uint32 {
- return r.defaultMark
- }
- func (r *Router) Rules() []adapter.Rule {
- return r.rules
- }
- func (r *Router) WIFIState() adapter.WIFIState {
- return r.wifiState
- }
- func (r *Router) NetworkMonitor() tun.NetworkUpdateMonitor {
- return r.networkMonitor
- }
- func (r *Router) InterfaceMonitor() tun.DefaultInterfaceMonitor {
- return r.interfaceMonitor
- }
- func (r *Router) PackageManager() tun.PackageManager {
- return r.packageManager
- }
- func (r *Router) ClashServer() adapter.ClashServer {
- return r.clashServer
- }
- func (r *Router) SetClashServer(server adapter.ClashServer) {
- r.clashServer = server
- }
- func (r *Router) V2RayServer() adapter.V2RayServer {
- return r.v2rayServer
- }
- func (r *Router) SetV2RayServer(server adapter.V2RayServer) {
- r.v2rayServer = server
- }
- func (r *Router) OnPackagesUpdated(packages int, sharedUsers int) {
- r.logger.Info("updated packages list: ", packages, " packages, ", sharedUsers, " shared users")
- }
- func (r *Router) NewError(ctx context.Context, err error) {
- common.Close(err)
- if E.IsClosedOrCanceled(err) {
- r.logger.DebugContext(ctx, "connection closed: ", err)
- return
- }
- r.logger.ErrorContext(ctx, err)
- }
- func (r *Router) notifyNetworkUpdate(event int) {
- if event == tun.EventNoRoute {
- r.pauseManager.NetworkPause()
- r.logger.Error("missing default interface")
- } else {
- r.pauseManager.NetworkWake()
- if C.IsAndroid && r.platformInterface == nil {
- var vpnStatus string
- if r.interfaceMonitor.AndroidVPNEnabled() {
- vpnStatus = "enabled"
- } else {
- vpnStatus = "disabled"
- }
- r.logger.Info("updated default interface ", r.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", r.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()), ", vpn ", vpnStatus)
- } else {
- r.logger.Info("updated default interface ", r.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", r.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()))
- }
- }
- if !r.started {
- return
- }
- _ = r.ResetNetwork()
- }
- func (r *Router) ResetNetwork() error {
- conntrack.Close()
- for _, outbound := range r.outbounds {
- listener, isListener := outbound.(adapter.InterfaceUpdateListener)
- if isListener {
- listener.InterfaceUpdated()
- }
- }
- for _, transport := range r.transports {
- transport.Reset()
- }
- return nil
- }
- func (r *Router) updateWIFIState() {
- if r.platformInterface == nil {
- return
- }
- state := r.platformInterface.ReadWIFIState()
- if state != r.wifiState {
- r.wifiState = state
- if state.SSID == "" && state.BSSID == "" {
- r.logger.Info("updated WIFI state: disconnected")
- } else {
- r.logger.Info("updated WIFI state: SSID=", state.SSID, ", BSSID=", state.BSSID)
- }
- }
- }
- func (r *Router) notifyWindowsPowerEvent(event int) {
- switch event {
- case winpowrprof.EVENT_SUSPEND:
- r.pauseManager.DevicePause()
- _ = r.ResetNetwork()
- case winpowrprof.EVENT_RESUME:
- if !r.pauseManager.IsDevicePaused() {
- return
- }
- fallthrough
- case winpowrprof.EVENT_RESUME_AUTOMATIC:
- r.pauseManager.DeviceWake()
- _ = r.ResetNetwork()
- }
- }
|