github.com/sagernet/sing-box@v1.9.0-rc.20/route/rule_item_geoip.go (about) 1 package route 2 3 import ( 4 "net/netip" 5 "strings" 6 7 "github.com/sagernet/sing-box/adapter" 8 "github.com/sagernet/sing-box/log" 9 N "github.com/sagernet/sing/common/network" 10 ) 11 12 var _ RuleItem = (*GeoIPItem)(nil) 13 14 type GeoIPItem struct { 15 router adapter.Router 16 logger log.ContextLogger 17 isSource bool 18 codes []string 19 codeMap map[string]bool 20 } 21 22 func NewGeoIPItem(router adapter.Router, logger log.ContextLogger, isSource bool, codes []string) *GeoIPItem { 23 codeMap := make(map[string]bool) 24 for _, code := range codes { 25 codeMap[code] = true 26 } 27 return &GeoIPItem{ 28 router: router, 29 logger: logger, 30 codes: codes, 31 isSource: isSource, 32 codeMap: codeMap, 33 } 34 } 35 36 func (r *GeoIPItem) Match(metadata *adapter.InboundContext) bool { 37 var geoipCode string 38 if r.isSource && metadata.SourceGeoIPCode != "" { 39 geoipCode = metadata.SourceGeoIPCode 40 } else if !r.isSource && metadata.GeoIPCode != "" { 41 geoipCode = metadata.GeoIPCode 42 } 43 if geoipCode != "" { 44 return r.codeMap[geoipCode] 45 } 46 var destination netip.Addr 47 if r.isSource { 48 destination = metadata.Source.Addr 49 } else { 50 destination = metadata.Destination.Addr 51 } 52 if destination.IsValid() { 53 return r.match(metadata, destination) 54 } 55 for _, destinationAddress := range metadata.DestinationAddresses { 56 if r.match(metadata, destinationAddress) { 57 return true 58 } 59 } 60 return false 61 } 62 63 func (r *GeoIPItem) match(metadata *adapter.InboundContext, destination netip.Addr) bool { 64 var geoipCode string 65 geoReader := r.router.GeoIPReader() 66 if !N.IsPublicAddr(destination) { 67 geoipCode = "private" 68 } else if geoReader != nil { 69 geoipCode = geoReader.Lookup(destination) 70 } 71 if geoipCode == "" { 72 return false 73 } 74 if r.isSource { 75 metadata.SourceGeoIPCode = geoipCode 76 } else { 77 metadata.GeoIPCode = geoipCode 78 } 79 return r.codeMap[geoipCode] 80 } 81 82 func (r *GeoIPItem) String() string { 83 var description string 84 if r.isSource { 85 description = "source_geoip=" 86 } else { 87 description = "geoip=" 88 } 89 cLen := len(r.codes) 90 if cLen == 1 { 91 description += r.codes[0] 92 } else if cLen > 3 { 93 description += "[" + strings.Join(r.codes[:3], " ") + "...]" 94 } else { 95 description += "[" + strings.Join(r.codes, " ") + "]" 96 } 97 return description 98 }