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  }