| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 | 
							- package router
 
- import (
 
- 	"net/netip"
 
- 	"strconv"
 
- 	"github.com/xtls/xray-core/common/net"
 
- 	"go4.org/netipx"
 
- )
 
- type GeoIPMatcher struct {
 
- 	countryCode  string
 
- 	reverseMatch bool
 
- 	ip4          *netipx.IPSet
 
- 	ip6          *netipx.IPSet
 
- }
 
- func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
 
- 	var builder4, builder6 netipx.IPSetBuilder
 
- 	for _, cidr := range cidrs {
 
- 		ip := net.IP(cidr.GetIp())
 
- 		ipPrefixString := ip.String() + "/" + strconv.Itoa(int(cidr.GetPrefix()))
 
- 		ipPrefix, err := netip.ParsePrefix(ipPrefixString)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 		switch len(ip) {
 
- 		case net.IPv4len:
 
- 			builder4.AddPrefix(ipPrefix)
 
- 		case net.IPv6len:
 
- 			builder6.AddPrefix(ipPrefix)
 
- 		}
 
- 	}
 
- 	if ip4, err := builder4.IPSet(); err != nil {
 
- 		return err
 
- 	} else {
 
- 		m.ip4 = ip4
 
- 	}
 
- 	if ip6, err := builder6.IPSet(); err != nil {
 
- 		return err
 
- 	} else {
 
- 		m.ip6 = ip6
 
- 	}
 
- 	return nil
 
- }
 
- func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
 
- 	m.reverseMatch = isReverseMatch
 
- }
 
- func (m *GeoIPMatcher) match4(ip net.IP) bool {
 
- 	nip, ok := netipx.FromStdIP(ip)
 
- 	if !ok {
 
- 		return false
 
- 	}
 
- 	return m.ip4.Contains(nip)
 
- }
 
- func (m *GeoIPMatcher) match6(ip net.IP) bool {
 
- 	nip, ok := netipx.FromStdIP(ip)
 
- 	if !ok {
 
- 		return false
 
- 	}
 
- 	return m.ip6.Contains(nip)
 
- }
 
- // Match returns true if the given ip is included by the GeoIP.
 
- func (m *GeoIPMatcher) Match(ip net.IP) bool {
 
- 	isMatched := false
 
- 	switch len(ip) {
 
- 	case net.IPv4len:
 
- 		isMatched = m.match4(ip)
 
- 	case net.IPv6len:
 
- 		isMatched = m.match6(ip)
 
- 	}
 
- 	if m.reverseMatch {
 
- 		return !isMatched
 
- 	}
 
- 	return isMatched
 
- }
 
- // GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.
 
- type GeoIPMatcherContainer struct {
 
- 	matchers []*GeoIPMatcher
 
- }
 
- // Add adds a new GeoIP set into the container.
 
- // If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one.
 
- func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
 
- 	if len(geoip.CountryCode) > 0 {
 
- 		for _, m := range c.matchers {
 
- 			if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
 
- 				return m, nil
 
- 			}
 
- 		}
 
- 	}
 
- 	m := &GeoIPMatcher{
 
- 		countryCode:  geoip.CountryCode,
 
- 		reverseMatch: geoip.ReverseMatch,
 
- 	}
 
- 	if err := m.Init(geoip.Cidr); err != nil {
 
- 		return nil, err
 
- 	}
 
- 	if len(geoip.CountryCode) > 0 {
 
- 		c.matchers = append(c.matchers, m)
 
- 	}
 
- 	return m, nil
 
- }
 
- var globalGeoIPContainer GeoIPMatcherContainer
 
 
  |