Refactor geo resources

This commit is contained in:
世界 2022-07-05 13:23:47 +08:00
parent 8392567962
commit 2d9203ee74
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
12 changed files with 273 additions and 198 deletions

3
.gitignore vendored
View file

@ -1,5 +1,4 @@
/.idea/ /.idea/
/vendor/ /vendor/
/*.json /*.json
/Country.mmdb /*.db
/geosite.db

View file

@ -6,124 +6,23 @@ import (
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
type ( type ConnectionHandler interface {
ConnectionHandler interface {
NewConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error NewConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
} }
PacketHandler interface {
type PacketHandler interface {
NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata InboundContext) error NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata InboundContext) error
} }
PacketConnectionHandler interface {
type PacketConnectionHandler interface {
NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
} }
UpstreamHandlerAdapter interface {
type UpstreamHandlerAdapter interface {
N.TCPConnectionHandler N.TCPConnectionHandler
N.UDPConnectionHandler N.UDPConnectionHandler
E.Handler 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,
}
}
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)
}

View file

@ -4,25 +4,23 @@ import (
"context" "context"
"net" "net"
"github.com/oschwald/geoip2-golang" "github.com/sagernet/sing-box/common/geoip"
"github.com/sagernet/sing-box/common/geosite" "github.com/sagernet/sing-box/common/geosite"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
type Router interface { type Router interface {
Start() error Service
Close() error
Outbound(tag string) (Outbound, bool) Outbound(tag string) (Outbound, bool)
RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
GeoIPReader() *geoip2.Reader GeoIPReader() *geoip.Reader
GeositeReader() *geosite.Reader GeositeReader() *geosite.Reader
} }
type Rule interface { type Rule interface {
Start() error Service
Close() error UpdateGeosite() error
Match(metadata *InboundContext) bool Match(metadata *InboundContext) bool
Outbound() string Outbound() string
String() string String() string

114
adapter/upstream.go Normal file
View file

@ -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)
}

37
common/geoip/reader.go Normal file
View file

@ -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"
}

View file

@ -14,10 +14,10 @@ type Reader struct {
domainLength map[string]int domainLength map[string]int
} }
func Open(path string) (*Reader, error) { func Open(path string) (*Reader, []string, error) {
content, err := os.Open(path) content, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
reader := &Reader{ reader := &Reader{
reader: content, reader: content,
@ -25,9 +25,13 @@ func Open(path string) (*Reader, error) {
err = reader.readMetadata() err = reader.readMetadata()
if err != nil { if err != nil {
content.Close() 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 { func (r *Reader) readMetadata() error {

View file

@ -9,8 +9,8 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"github.com/oschwald/geoip2-golang"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/geoip"
"github.com/sagernet/sing-box/common/geosite" "github.com/sagernet/sing-box/common/geosite"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
@ -37,11 +37,10 @@ type Router struct {
defaultOutboundForPacketConnection adapter.Outbound defaultOutboundForPacketConnection adapter.Outbound
needGeoIPDatabase bool needGeoIPDatabase bool
geoIPOptions option.GeoIPOptions
geoIPReader *geoip2.Reader
needGeositeDatabase bool needGeositeDatabase bool
geoIPOptions option.GeoIPOptions
geositeOptions option.GeositeOptions geositeOptions option.GeositeOptions
geoIPReader *geoip.Reader
geositeReader *geosite.Reader geositeReader *geosite.Reader
} }
@ -154,17 +153,28 @@ func (r *Router) Start() error {
return err 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 return nil
} }
func (r *Router) Close() error { func (r *Router) Close() error {
return common.Close( return common.Close(
common.PtrOrNil(r.geoIPReader), common.PtrOrNil(r.geoIPReader),
common.PtrOrNil(r.geositeReader),
) )
} }
func (r *Router) GeoIPReader() *geoip2.Reader { func (r *Router) GeoIPReader() *geoip.Reader {
return r.geoIPReader return r.geoIPReader
} }
@ -245,7 +255,7 @@ func (r *Router) prepareGeoIPDatabase() error {
if r.geoIPOptions.Path != "" { if r.geoIPOptions.Path != "" {
geoPath = r.geoIPOptions.Path geoPath = r.geoIPOptions.Path
} else { } else {
geoPath = "Country.mmdb" geoPath = "geoip.db"
if foundPath, loaded := C.Find(geoPath); loaded { if foundPath, loaded := C.Find(geoPath); loaded {
geoPath = foundPath geoPath = foundPath
} }
@ -266,13 +276,12 @@ func (r *Router) prepareGeoIPDatabase() error {
return err return err
} }
} }
geoReader, err := geoip2.Open(geoPath) geoReader, codes, err := geoip.Open(geoPath)
if err == nil { if err != nil {
r.logger.Info("loaded geoip database")
r.geoIPReader = geoReader
} else {
return E.Cause(err, "open geoip database") return E.Cause(err, "open geoip database")
} }
r.logger.Info("loaded geoip database: ", len(codes), " codes")
r.geoIPReader = geoReader
return nil return nil
} }
@ -302,9 +311,9 @@ func (r *Router) prepareGeositeDatabase() error {
return err return err
} }
} }
geoReader, err := geosite.Open(geoPath) geoReader, codes, err := geosite.Open(geoPath)
if err == nil { if err == nil {
r.logger.Info("loaded geosite database") r.logger.Info("loaded geosite database: ", len(codes), " codes")
r.geositeReader = geoReader r.geositeReader = geoReader
} else { } else {
return E.Cause(err, "open geosite database") return E.Cause(err, "open geosite database")
@ -317,7 +326,7 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
if r.geoIPOptions.DownloadURL != "" { if r.geoIPOptions.DownloadURL != "" {
downloadURL = r.geoIPOptions.DownloadURL downloadURL = r.geoIPOptions.DownloadURL
} else { } 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") r.logger.Info("downloading geoip database")
var detour adapter.Outbound var detour adapter.Outbound
@ -342,7 +351,6 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
defer saveFile.Close() defer saveFile.Close()
httpClient := &http.Client{ httpClient := &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{ Transport: &http.Transport{
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
TLSHandshakeTimeout: 5 * time.Second, TLSHandshakeTimeout: 5 * time.Second,
@ -390,7 +398,6 @@ func (r *Router) downloadGeositeDatabase(savePath string) error {
defer saveFile.Close() defer saveFile.Close()
httpClient := &http.Client{ httpClient := &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{ Transport: &http.Transport{
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
TLSHandshakeTimeout: 5 * time.Second, TLSHandshakeTimeout: 5 * time.Second,

View file

@ -44,6 +44,7 @@ type DefaultRule struct {
items []RuleItem items []RuleItem
sourceAddressItems []RuleItem sourceAddressItems []RuleItem
destinationAddressItems []RuleItem destinationAddressItems []RuleItem
allItems []RuleItem
outbound string outbound string
} }
@ -57,12 +58,16 @@ func NewDefaultRule(router adapter.Router, logger log.Logger, options option.Def
outbound: options.Outbound, outbound: options.Outbound,
} }
if len(options.Inbound) > 0 { 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 { if options.IPVersion > 0 {
switch options.IPVersion { switch options.IPVersion {
case 4, 6: 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: default:
return nil, E.New("invalid ip version: ", options.IPVersion) 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 != "" { if options.Network != "" {
switch options.Network { switch options.Network {
case C.NetworkTCP, C.NetworkUDP: 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: default:
return nil, E.New("invalid network: ", options.Network) return nil, E.New("invalid network: ", options.Network)
} }
} }
if len(options.Protocol) > 0 { 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 { 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 { 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 { if len(options.DomainRegex) > 0 {
item, err := NewDomainRegexItem(options.DomainRegex) 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") return nil, E.Cause(err, "domain_regex")
} }
rule.destinationAddressItems = append(rule.destinationAddressItems, item) rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item)
} }
if len(options.Geosite) > 0 { 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 { 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 { 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 { if len(options.SourceIPCIDR) > 0 {
item, err := NewIPCIDRItem(true, options.SourceIPCIDR) 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") return nil, E.Cause(err, "source_ipcidr")
} }
rule.sourceAddressItems = append(rule.sourceAddressItems, item) rule.sourceAddressItems = append(rule.sourceAddressItems, item)
rule.allItems = append(rule.allItems, item)
} }
if len(options.IPCIDR) > 0 { if len(options.IPCIDR) > 0 {
item, err := NewIPCIDRItem(false, options.IPCIDR) 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") return nil, E.Cause(err, "ipcidr")
} }
rule.destinationAddressItems = append(rule.destinationAddressItems, item) rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item)
} }
if len(options.SourcePort) > 0 { 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 { 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 return rule, nil
} }
func (r *DefaultRule) Start() error { func (r *DefaultRule) Start() error {
for _, item := range r.items { for _, item := range r.allItems {
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 {
err := common.Start(item) err := common.Start(item)
if err != nil { if err != nil {
return err return err
@ -146,23 +160,23 @@ func (r *DefaultRule) Start() error {
} }
func (r *DefaultRule) Close() error { func (r *DefaultRule) Close() error {
for _, item := range r.items { for _, item := range r.allItems {
err := common.Close(item) err := common.Close(item)
if err != nil { if err != nil {
return err return err
} }
} }
for _, item := range r.sourceAddressItems { return nil
err := common.Close(item) }
func (r *DefaultRule) UpdateGeosite() error {
for _, item := range r.allItems {
if geositeItem, isSite := item.(*GeositeItem); isSite {
err := geositeItem.Update()
if err != nil { if err != nil {
return err return err
} }
} }
for _, item := range r.destinationAddressItems {
err := common.Close(item)
if err != nil {
return err
}
} }
return nil return nil
} }
@ -208,5 +222,5 @@ func (r *DefaultRule) Outbound() string {
} }
func (r *DefaultRule) String() 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]), " ")
} }

View file

@ -28,11 +28,11 @@ func NewDomainRegexItem(expressions []string) (*DomainRegexItem, error) {
description := "domain_regex=" description := "domain_regex="
eLen := len(expressions) eLen := len(expressions)
if eLen == 1 { if eLen == 1 {
description = expressions[0] description += expressions[0]
} else if eLen > 3 { } else if eLen > 3 {
description = F.ToString("[", strings.Join(expressions[:3], " "), "]") description += F.ToString("[", strings.Join(expressions[:3], " "), "]")
} else { } else {
description = F.ToString("[", strings.Join(expressions, " "), "]") description += F.ToString("[", strings.Join(expressions, " "), "]")
} }
return &DomainRegexItem{matchers, description}, nil return &DomainRegexItem{matchers, description}, nil
} }

View file

@ -39,24 +39,14 @@ func (r *GeoIPItem) Match(metadata *adapter.InboundContext) bool {
} }
if r.isSource { if r.isSource {
if metadata.SourceGeoIPCode == "" { if metadata.SourceGeoIPCode == "" {
country, err := geoReader.Country(metadata.Source.Addr.AsSlice()) metadata.SourceGeoIPCode = geoReader.Lookup(metadata.Source.Addr)
if err != nil {
r.logger.Error("query geoip for ", metadata.Source.Addr, ": ", err)
return false
}
metadata.SourceGeoIPCode = strings.ToLower(country.Country.IsoCode)
} }
} else { } else {
if metadata.Destination.IsFqdn() { if metadata.Destination.IsFqdn() {
return false return false
} }
if metadata.GeoIPCode == "" { if metadata.GeoIPCode == "" {
country, err := geoReader.Country(metadata.Destination.Addr.AsSlice()) metadata.GeoIPCode = geoReader.Lookup(metadata.Destination.Addr)
if err != nil {
r.logger.Error("query geoip for ", metadata.Destination.Addr, ": ", err)
return false
}
metadata.GeoIPCode = strings.ToLower(country.Country.IsoCode)
} }
} }
return r.match(metadata) return r.match(metadata)

View file

@ -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() geositeReader := r.router.GeositeReader()
if geositeReader == nil { if geositeReader == nil {
return E.New("geosite reader is not initialized") 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 { func (r *GeositeItem) Match(metadata *adapter.InboundContext) bool {
if r.matcher == nil {
return false
}
return r.matcher.Match(metadata) return r.matcher.Match(metadata)
} }
@ -57,11 +60,11 @@ func (r *GeositeItem) String() string {
description := "geosite=" description := "geosite="
cLen := len(r.codes) cLen := len(r.codes)
if cLen == 1 { if cLen == 1 {
description = r.codes[0] description += r.codes[0]
} else if cLen > 3 { } else if cLen > 3 {
description = "[" + strings.Join(r.codes[:3], " ") + "...]" description += "[" + strings.Join(r.codes[:3], " ") + "...]"
} else { } else {
description = "[" + strings.Join(r.codes, " ") + "]" description += "[" + strings.Join(r.codes, " ") + "]"
} }
return description return description
} }

View file

@ -20,6 +20,16 @@ type LogicalRule struct {
outbound string 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 { func (r *LogicalRule) Start() error {
for _, rule := range r.rules { for _, rule := range r.rules {
err := rule.Start() err := rule.Start()