diff --git a/.gitignore b/.gitignore index c66de3ed..ce9c8fa5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /.idea/ /vendor/ /*.json -/Country.mmdb -/geosite.db \ No newline at end of file +/*.db \ No newline at end of file diff --git a/adapter/handler.go b/adapter/handler.go index d4d76c33..5ec23579 100644 --- a/adapter/handler.go +++ b/adapter/handler.go @@ -6,124 +6,23 @@ import ( "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) -type ( - ConnectionHandler interface { - NewConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error - } - PacketHandler interface { - NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata InboundContext) error - } - PacketConnectionHandler interface { - NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error - } - UpstreamHandlerAdapter interface { - N.TCPConnectionHandler - N.UDPConnectionHandler - E.Handler - } - ConnectionHandlerFunc = func(ctx context.Context, conn net.Conn, metadata InboundContext) error - PacketConnectionHandlerFunc = func(ctx context.Context, conn N.PacketConn, metadata InboundContext) error -) - -func NewUpstreamHandler( - metadata InboundContext, - connectionHandler ConnectionHandlerFunc, - packetHandler PacketConnectionHandlerFunc, - errorHandler E.Handler, -) UpstreamHandlerAdapter { - return &myUpstreamHandlerWrapper{ - metadata: metadata, - connectionHandler: connectionHandler, - packetHandler: packetHandler, - errorHandler: errorHandler, - } +type ConnectionHandler interface { + NewConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error } -var _ UpstreamHandlerAdapter = (*myUpstreamHandlerWrapper)(nil) - -type myUpstreamHandlerWrapper struct { - metadata InboundContext - connectionHandler ConnectionHandlerFunc - packetHandler PacketConnectionHandlerFunc - errorHandler E.Handler +type PacketHandler interface { + NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata InboundContext) error } -func (w *myUpstreamHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { - w.metadata.Destination = metadata.Destination - return w.connectionHandler(ctx, conn, w.metadata) +type PacketConnectionHandler interface { + NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error } -func (w *myUpstreamHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { - w.metadata.Destination = metadata.Destination - return w.packetHandler(ctx, conn, w.metadata) -} - -func (w *myUpstreamHandlerWrapper) NewError(ctx context.Context, err error) { - w.errorHandler.NewError(ctx, err) -} - -var myContextType = (*MetadataContext)(nil) - -type MetadataContext struct { - context.Context - Metadata InboundContext -} - -func (c *MetadataContext) Value(key any) any { - if key == myContextType { - return c - } - return c.Context.Value(key) -} - -func ContextWithMetadata(ctx context.Context, metadata InboundContext) context.Context { - return &MetadataContext{ - Context: ctx, - Metadata: metadata, - } -} - -func UpstreamMetadata(metadata InboundContext) M.Metadata { - return M.Metadata{ - Source: metadata.Source, - Destination: metadata.Destination, - } -} - -type myUpstreamContextHandlerWrapper struct { - connectionHandler ConnectionHandlerFunc - packetHandler PacketConnectionHandlerFunc - errorHandler E.Handler -} - -func NewUpstreamContextHandler( - connectionHandler ConnectionHandlerFunc, - packetHandler PacketConnectionHandlerFunc, - errorHandler E.Handler, -) UpstreamHandlerAdapter { - return &myUpstreamContextHandlerWrapper{ - connectionHandler: connectionHandler, - packetHandler: packetHandler, - errorHandler: errorHandler, - } -} - -func (w *myUpstreamContextHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { - myCtx := ctx.Value(myContextType).(*MetadataContext) - myCtx.Metadata.Destination = metadata.Destination - return w.connectionHandler(ctx, conn, myCtx.Metadata) -} - -func (w *myUpstreamContextHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { - myCtx := ctx.Value(myContextType).(*MetadataContext) - myCtx.Metadata.Destination = metadata.Destination - return w.packetHandler(ctx, conn, myCtx.Metadata) -} - -func (w *myUpstreamContextHandlerWrapper) NewError(ctx context.Context, err error) { - w.errorHandler.NewError(ctx, err) +type UpstreamHandlerAdapter interface { + N.TCPConnectionHandler + N.UDPConnectionHandler + E.Handler } diff --git a/adapter/router.go b/adapter/router.go index 209e4123..38826ed5 100644 --- a/adapter/router.go +++ b/adapter/router.go @@ -4,25 +4,23 @@ import ( "context" "net" - "github.com/oschwald/geoip2-golang" + "github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-box/common/geosite" N "github.com/sagernet/sing/common/network" ) type Router interface { - Start() error - Close() error - + Service Outbound(tag string) (Outbound, bool) RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error - GeoIPReader() *geoip2.Reader + GeoIPReader() *geoip.Reader GeositeReader() *geosite.Reader } type Rule interface { - Start() error - Close() error + Service + UpdateGeosite() error Match(metadata *InboundContext) bool Outbound() string String() string diff --git a/adapter/upstream.go b/adapter/upstream.go new file mode 100644 index 00000000..6a022a8a --- /dev/null +++ b/adapter/upstream.go @@ -0,0 +1,114 @@ +package adapter + +import ( + "context" + "net" + + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type ( + ConnectionHandlerFunc = func(ctx context.Context, conn net.Conn, metadata InboundContext) error + PacketConnectionHandlerFunc = func(ctx context.Context, conn N.PacketConn, metadata InboundContext) error +) + +func NewUpstreamHandler( + metadata InboundContext, + connectionHandler ConnectionHandlerFunc, + packetHandler PacketConnectionHandlerFunc, + errorHandler E.Handler, +) UpstreamHandlerAdapter { + return &myUpstreamHandlerWrapper{ + metadata: metadata, + connectionHandler: connectionHandler, + packetHandler: packetHandler, + errorHandler: errorHandler, + } +} + +var _ UpstreamHandlerAdapter = (*myUpstreamHandlerWrapper)(nil) + +type myUpstreamHandlerWrapper struct { + metadata InboundContext + connectionHandler ConnectionHandlerFunc + packetHandler PacketConnectionHandlerFunc + errorHandler E.Handler +} + +func (w *myUpstreamHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + w.metadata.Destination = metadata.Destination + return w.connectionHandler(ctx, conn, w.metadata) +} + +func (w *myUpstreamHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { + w.metadata.Destination = metadata.Destination + return w.packetHandler(ctx, conn, w.metadata) +} + +func (w *myUpstreamHandlerWrapper) NewError(ctx context.Context, err error) { + w.errorHandler.NewError(ctx, err) +} + +var myContextType = (*MetadataContext)(nil) + +type MetadataContext struct { + context.Context + Metadata InboundContext +} + +func (c *MetadataContext) Value(key any) any { + if key == myContextType { + return c + } + return c.Context.Value(key) +} + +func ContextWithMetadata(ctx context.Context, metadata InboundContext) context.Context { + return &MetadataContext{ + Context: ctx, + Metadata: metadata, + } +} + +func UpstreamMetadata(metadata InboundContext) M.Metadata { + return M.Metadata{ + Source: metadata.Source, + Destination: metadata.Destination, + } +} + +type myUpstreamContextHandlerWrapper struct { + connectionHandler ConnectionHandlerFunc + packetHandler PacketConnectionHandlerFunc + errorHandler E.Handler +} + +func NewUpstreamContextHandler( + connectionHandler ConnectionHandlerFunc, + packetHandler PacketConnectionHandlerFunc, + errorHandler E.Handler, +) UpstreamHandlerAdapter { + return &myUpstreamContextHandlerWrapper{ + connectionHandler: connectionHandler, + packetHandler: packetHandler, + errorHandler: errorHandler, + } +} + +func (w *myUpstreamContextHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + myCtx := ctx.Value(myContextType).(*MetadataContext) + myCtx.Metadata.Destination = metadata.Destination + return w.connectionHandler(ctx, conn, myCtx.Metadata) +} + +func (w *myUpstreamContextHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { + myCtx := ctx.Value(myContextType).(*MetadataContext) + myCtx.Metadata.Destination = metadata.Destination + return w.packetHandler(ctx, conn, myCtx.Metadata) +} + +func (w *myUpstreamContextHandlerWrapper) NewError(ctx context.Context, err error) { + w.errorHandler.NewError(ctx, err) +} diff --git a/common/geoip/reader.go b/common/geoip/reader.go new file mode 100644 index 00000000..b7488ef0 --- /dev/null +++ b/common/geoip/reader.go @@ -0,0 +1,37 @@ +package geoip + +import ( + "net/netip" + + "github.com/oschwald/maxminddb-golang" + E "github.com/sagernet/sing/common/exceptions" + N "github.com/sagernet/sing/common/network" +) + +type Reader struct { + reader *maxminddb.Reader +} + +func Open(path string) (*Reader, []string, error) { + database, err := maxminddb.Open(path) + if err != nil { + return nil, nil, err + } + if database.Metadata.DatabaseType != "sing-geoip" { + database.Close() + return nil, nil, E.New("incorrect database type, expected sing-geoip, got ", database.Metadata.DatabaseType) + } + return &Reader{database}, database.Metadata.Languages, nil +} + +func (r *Reader) Lookup(addr netip.Addr) string { + var code string + _ = r.reader.Lookup(addr.AsSlice(), &code) + if code != "" { + return code + } + if !N.IsPublicAddr(addr) { + return "private" + } + return "unknown" +} diff --git a/common/geosite/reader.go b/common/geosite/reader.go index 4e548323..85b22fa5 100644 --- a/common/geosite/reader.go +++ b/common/geosite/reader.go @@ -14,10 +14,10 @@ type Reader struct { domainLength map[string]int } -func Open(path string) (*Reader, error) { +func Open(path string) (*Reader, []string, error) { content, err := os.Open(path) if err != nil { - return nil, err + return nil, nil, err } reader := &Reader{ reader: content, @@ -25,9 +25,13 @@ func Open(path string) (*Reader, error) { err = reader.readMetadata() if err != nil { content.Close() - return nil, err + return nil, nil, err } - return reader, nil + codes := make([]string, 0, len(reader.domainIndex)) + for code := range reader.domainIndex { + codes = append(codes, code) + } + return reader, codes, nil } func (r *Reader) readMetadata() error { diff --git a/route/router.go b/route/router.go index ea76d14e..17e6a1dd 100644 --- a/route/router.go +++ b/route/router.go @@ -9,8 +9,8 @@ import ( "path/filepath" "time" - "github.com/oschwald/geoip2-golang" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-box/common/geosite" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" @@ -36,12 +36,11 @@ type Router struct { defaultOutboundForConnection adapter.Outbound defaultOutboundForPacketConnection adapter.Outbound - needGeoIPDatabase bool - geoIPOptions option.GeoIPOptions - geoIPReader *geoip2.Reader - + needGeoIPDatabase bool needGeositeDatabase bool + geoIPOptions option.GeoIPOptions geositeOptions option.GeositeOptions + geoIPReader *geoip.Reader geositeReader *geosite.Reader } @@ -154,17 +153,28 @@ func (r *Router) Start() error { return err } } + if r.needGeositeDatabase { + for _, rule := range r.rules { + err := rule.UpdateGeosite() + if err != nil { + r.logger.Error("failed to initialize geosite: ", err) + } + } + err := common.Close(r.geositeReader) + if err != nil { + return err + } + } return nil } func (r *Router) Close() error { return common.Close( common.PtrOrNil(r.geoIPReader), - common.PtrOrNil(r.geositeReader), ) } -func (r *Router) GeoIPReader() *geoip2.Reader { +func (r *Router) GeoIPReader() *geoip.Reader { return r.geoIPReader } @@ -199,7 +209,7 @@ func (r *Router) match(ctx context.Context, metadata adapter.InboundContext, def for i, rule := range r.rules { if rule.Match(&metadata) { detour := rule.Outbound() - r.logger.WithContext(ctx).Info("match [", i, "]", rule.String(), " => ", detour) + r.logger.WithContext(ctx).Info("match[", i, "] ", rule.String(), " => ", detour) if outbound, loaded := r.Outbound(detour); loaded { return outbound } @@ -245,7 +255,7 @@ func (r *Router) prepareGeoIPDatabase() error { if r.geoIPOptions.Path != "" { geoPath = r.geoIPOptions.Path } else { - geoPath = "Country.mmdb" + geoPath = "geoip.db" if foundPath, loaded := C.Find(geoPath); loaded { geoPath = foundPath } @@ -266,13 +276,12 @@ func (r *Router) prepareGeoIPDatabase() error { return err } } - geoReader, err := geoip2.Open(geoPath) - if err == nil { - r.logger.Info("loaded geoip database") - r.geoIPReader = geoReader - } else { + geoReader, codes, err := geoip.Open(geoPath) + if err != nil { return E.Cause(err, "open geoip database") } + r.logger.Info("loaded geoip database: ", len(codes), " codes") + r.geoIPReader = geoReader return nil } @@ -302,9 +311,9 @@ func (r *Router) prepareGeositeDatabase() error { return err } } - geoReader, err := geosite.Open(geoPath) + geoReader, codes, err := geosite.Open(geoPath) if err == nil { - r.logger.Info("loaded geosite database") + r.logger.Info("loaded geosite database: ", len(codes), " codes") r.geositeReader = geoReader } else { return E.Cause(err, "open geosite database") @@ -317,7 +326,7 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error { if r.geoIPOptions.DownloadURL != "" { downloadURL = r.geoIPOptions.DownloadURL } else { - downloadURL = "https://cdn.jsdelivr.net/gh/Dreamacro/maxmind-geoip@release/Country.mmdb" + downloadURL = "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db" } r.logger.Info("downloading geoip database") var detour adapter.Outbound @@ -342,7 +351,6 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error { defer saveFile.Close() httpClient := &http.Client{ - Timeout: 5 * time.Second, Transport: &http.Transport{ ForceAttemptHTTP2: true, TLSHandshakeTimeout: 5 * time.Second, @@ -390,7 +398,6 @@ func (r *Router) downloadGeositeDatabase(savePath string) error { defer saveFile.Close() httpClient := &http.Client{ - Timeout: 5 * time.Second, Transport: &http.Transport{ ForceAttemptHTTP2: true, TLSHandshakeTimeout: 5 * time.Second, diff --git a/route/rule.go b/route/rule.go index 24eb31d7..8a35e281 100644 --- a/route/rule.go +++ b/route/rule.go @@ -44,6 +44,7 @@ type DefaultRule struct { items []RuleItem sourceAddressItems []RuleItem destinationAddressItems []RuleItem + allItems []RuleItem outbound string } @@ -57,12 +58,16 @@ func NewDefaultRule(router adapter.Router, logger log.Logger, options option.Def outbound: options.Outbound, } if len(options.Inbound) > 0 { - rule.items = append(rule.items, NewInboundRule(options.Inbound)) + item := NewInboundRule(options.Inbound) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) } if options.IPVersion > 0 { switch options.IPVersion { case 4, 6: - rule.items = append(rule.items, NewIPVersionItem(options.IPVersion == 6)) + item := NewIPVersionItem(options.IPVersion == 6) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) default: return nil, E.New("invalid ip version: ", options.IPVersion) } @@ -70,19 +75,27 @@ func NewDefaultRule(router adapter.Router, logger log.Logger, options option.Def if options.Network != "" { switch options.Network { case C.NetworkTCP, C.NetworkUDP: - rule.items = append(rule.items, NewNetworkItem(options.Network)) + item := NewNetworkItem(options.Network) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) default: return nil, E.New("invalid network: ", options.Network) } } if len(options.Protocol) > 0 { - rule.items = append(rule.items, NewProtocolItem(options.Protocol)) + item := NewProtocolItem(options.Protocol) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) } if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 { - rule.destinationAddressItems = append(rule.destinationAddressItems, NewDomainItem(options.Domain, options.DomainSuffix)) + item := NewDomainItem(options.Domain, options.DomainSuffix) + rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.DomainKeyword) > 0 { - rule.destinationAddressItems = append(rule.destinationAddressItems, NewDomainKeywordItem(options.DomainKeyword)) + item := NewDomainKeywordItem(options.DomainKeyword) + rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.DomainRegex) > 0 { item, err := NewDomainRegexItem(options.DomainRegex) @@ -90,15 +103,22 @@ func NewDefaultRule(router adapter.Router, logger log.Logger, options option.Def return nil, E.Cause(err, "domain_regex") } rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.Geosite) > 0 { - rule.destinationAddressItems = append(rule.destinationAddressItems, NewGeositeItem(router, logger, options.Geosite)) + item := NewGeositeItem(router, logger, options.Geosite) + rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.SourceGeoIP) > 0 { - rule.sourceAddressItems = append(rule.sourceAddressItems, NewGeoIPItem(router, logger, true, options.SourceGeoIP)) + item := NewGeoIPItem(router, logger, true, options.SourceGeoIP) + rule.sourceAddressItems = append(rule.sourceAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.GeoIP) > 0 { - rule.destinationAddressItems = append(rule.destinationAddressItems, NewGeoIPItem(router, logger, false, options.GeoIP)) + item := NewGeoIPItem(router, logger, false, options.GeoIP) + rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.SourceIPCIDR) > 0 { item, err := NewIPCIDRItem(true, options.SourceIPCIDR) @@ -106,6 +126,7 @@ func NewDefaultRule(router adapter.Router, logger log.Logger, options option.Def return nil, E.Cause(err, "source_ipcidr") } rule.sourceAddressItems = append(rule.sourceAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.IPCIDR) > 0 { item, err := NewIPCIDRItem(false, options.IPCIDR) @@ -113,30 +134,23 @@ func NewDefaultRule(router adapter.Router, logger log.Logger, options option.Def return nil, E.Cause(err, "ipcidr") } rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) } if len(options.SourcePort) > 0 { - rule.items = append(rule.items, NewPortItem(true, options.SourcePort)) + item := NewPortItem(true, options.SourcePort) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) } if len(options.Port) > 0 { - rule.items = append(rule.items, NewPortItem(false, options.Port)) + item := NewPortItem(false, options.Port) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) } return rule, nil } func (r *DefaultRule) Start() error { - for _, item := range r.items { - err := common.Start(item) - if err != nil { - return err - } - } - for _, item := range r.sourceAddressItems { - err := common.Start(item) - if err != nil { - return err - } - } - for _, item := range r.destinationAddressItems { + for _, item := range r.allItems { err := common.Start(item) if err != nil { return err @@ -146,22 +160,22 @@ func (r *DefaultRule) Start() error { } func (r *DefaultRule) Close() error { - for _, item := range r.items { + for _, item := range r.allItems { err := common.Close(item) if err != nil { return err } } - for _, item := range r.sourceAddressItems { - err := common.Close(item) - if err != nil { - return err - } - } - for _, item := range r.destinationAddressItems { - err := common.Close(item) - if err != nil { - return err + return nil +} + +func (r *DefaultRule) UpdateGeosite() error { + for _, item := range r.allItems { + if geositeItem, isSite := item.(*GeositeItem); isSite { + err := geositeItem.Update() + if err != nil { + return err + } } } return nil @@ -208,5 +222,5 @@ func (r *DefaultRule) Outbound() string { } func (r *DefaultRule) String() string { - return strings.Join(common.Map(r.items, F.ToString0[RuleItem]), " ") + return strings.Join(common.Map(r.allItems, F.ToString0[RuleItem]), " ") } diff --git a/route/rule_domain_regex.go b/route/rule_domain_regex.go index ae04b4d9..c9cf788b 100644 --- a/route/rule_domain_regex.go +++ b/route/rule_domain_regex.go @@ -28,11 +28,11 @@ func NewDomainRegexItem(expressions []string) (*DomainRegexItem, error) { description := "domain_regex=" eLen := len(expressions) if eLen == 1 { - description = expressions[0] + description += expressions[0] } else if eLen > 3 { - description = F.ToString("[", strings.Join(expressions[:3], " "), "]") + description += F.ToString("[", strings.Join(expressions[:3], " "), "]") } else { - description = F.ToString("[", strings.Join(expressions, " "), "]") + description += F.ToString("[", strings.Join(expressions, " "), "]") } return &DomainRegexItem{matchers, description}, nil } diff --git a/route/rule_geoip.go b/route/rule_geoip.go index 283288be..cd5831e4 100644 --- a/route/rule_geoip.go +++ b/route/rule_geoip.go @@ -39,24 +39,14 @@ func (r *GeoIPItem) Match(metadata *adapter.InboundContext) bool { } if r.isSource { if metadata.SourceGeoIPCode == "" { - country, err := geoReader.Country(metadata.Source.Addr.AsSlice()) - if err != nil { - r.logger.Error("query geoip for ", metadata.Source.Addr, ": ", err) - return false - } - metadata.SourceGeoIPCode = strings.ToLower(country.Country.IsoCode) + metadata.SourceGeoIPCode = geoReader.Lookup(metadata.Source.Addr) } } else { if metadata.Destination.IsFqdn() { return false } if metadata.GeoIPCode == "" { - country, err := geoReader.Country(metadata.Destination.Addr.AsSlice()) - if err != nil { - r.logger.Error("query geoip for ", metadata.Destination.Addr, ": ", err) - return false - } - metadata.GeoIPCode = strings.ToLower(country.Country.IsoCode) + metadata.GeoIPCode = geoReader.Lookup(metadata.Destination.Addr) } } return r.match(metadata) diff --git a/route/rule_geosite.go b/route/rule_geosite.go index dcbc060d..f9b72f1d 100644 --- a/route/rule_geosite.go +++ b/route/rule_geosite.go @@ -27,7 +27,7 @@ func NewGeositeItem(router adapter.Router, logger log.Logger, codes []string) *G } } -func (r *GeositeItem) Start() error { +func (r *GeositeItem) Update() error { geositeReader := r.router.GeositeReader() if geositeReader == nil { return E.New("geosite reader is not initialized") @@ -50,6 +50,9 @@ func (r *GeositeItem) Start() error { } func (r *GeositeItem) Match(metadata *adapter.InboundContext) bool { + if r.matcher == nil { + return false + } return r.matcher.Match(metadata) } @@ -57,11 +60,11 @@ func (r *GeositeItem) String() string { description := "geosite=" cLen := len(r.codes) if cLen == 1 { - description = r.codes[0] + description += r.codes[0] } else if cLen > 3 { - description = "[" + strings.Join(r.codes[:3], " ") + "...]" + description += "[" + strings.Join(r.codes[:3], " ") + "...]" } else { - description = "[" + strings.Join(r.codes, " ") + "]" + description += "[" + strings.Join(r.codes, " ") + "]" } return description } diff --git a/route/rule_logical.go b/route/rule_logical.go index c9d89ae9..9e912bdd 100644 --- a/route/rule_logical.go +++ b/route/rule_logical.go @@ -20,6 +20,16 @@ type LogicalRule struct { outbound string } +func (r *LogicalRule) UpdateGeosite() error { + for _, rule := range r.rules { + err := rule.UpdateGeosite() + if err != nil { + return err + } + } + return nil +} + func (r *LogicalRule) Start() error { for _, rule := range r.rules { err := rule.Start()