github.com/v2fly/v2ray-core/v4@v4.45.2/app/router/condition_geoip.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package router 5 6 import ( 7 "inet.af/netaddr" 8 9 "github.com/v2fly/v2ray-core/v4/common/net" 10 ) 11 12 type GeoIPMatcher struct { 13 countryCode string 14 reverseMatch bool 15 ip4 *netaddr.IPSet 16 ip6 *netaddr.IPSet 17 } 18 19 func (m *GeoIPMatcher) Init(cidrs []*CIDR) error { 20 var builder4, builder6 netaddr.IPSetBuilder 21 for _, cidr := range cidrs { 22 netaddrIP, ok := netaddr.FromStdIP(net.IP(cidr.GetIp())) 23 if !ok { 24 return newError("invalid IP address ", cidr) 25 } 26 ipPrefix := netaddr.IPPrefixFrom(netaddrIP, uint8(cidr.GetPrefix())) 27 switch { 28 case netaddrIP.Is4(): 29 builder4.AddPrefix(ipPrefix) 30 case netaddrIP.Is6(): 31 builder6.AddPrefix(ipPrefix) 32 } 33 } 34 35 var err error 36 m.ip4, err = builder4.IPSet() 37 if err != nil { 38 return err 39 } 40 m.ip6, err = builder6.IPSet() 41 if err != nil { 42 return err 43 } 44 45 return nil 46 } 47 48 func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) { 49 m.reverseMatch = isReverseMatch 50 } 51 52 func (m *GeoIPMatcher) match4(ip net.IP) bool { 53 nip, ok := netaddr.FromStdIP(ip) 54 if !ok { 55 return false 56 } 57 return m.ip4.Contains(nip) 58 } 59 60 func (m *GeoIPMatcher) match6(ip net.IP) bool { 61 nip, ok := netaddr.FromStdIP(ip) 62 if !ok { 63 return false 64 } 65 return m.ip6.Contains(nip) 66 } 67 68 // Match returns true if the given ip is included by the GeoIP. 69 func (m *GeoIPMatcher) Match(ip net.IP) bool { 70 isMatched := false 71 switch len(ip) { 72 case net.IPv4len: 73 isMatched = m.match4(ip) 74 case net.IPv6len: 75 isMatched = m.match6(ip) 76 } 77 if m.reverseMatch { 78 return !isMatched 79 } 80 return isMatched 81 } 82 83 // GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code. 84 type GeoIPMatcherContainer struct { 85 matchers []*GeoIPMatcher 86 } 87 88 // Add adds a new GeoIP set into the container. 89 // If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one. 90 func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) { 91 if geoip.CountryCode != "" { 92 for _, m := range c.matchers { 93 if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch { 94 return m, nil 95 } 96 } 97 } 98 99 m := &GeoIPMatcher{ 100 countryCode: geoip.CountryCode, 101 reverseMatch: geoip.ReverseMatch, 102 } 103 if err := m.Init(geoip.Cidr); err != nil { 104 return nil, err 105 } 106 if geoip.CountryCode != "" { 107 c.matchers = append(c.matchers, m) 108 } 109 return m, nil 110 } 111 112 var globalGeoIPContainer GeoIPMatcherContainer