github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/app/router/condition_geoip.go (about) 1 // +build !confonly 2 3 package router 4 5 import ( 6 "encoding/binary" 7 "sort" 8 9 "v2ray.com/core/common/net" 10 ) 11 12 type ipv6 struct { 13 a uint64 14 b uint64 15 } 16 17 type GeoIPMatcher struct { 18 countryCode string 19 ip4 []uint32 20 prefix4 []uint8 21 ip6 []ipv6 22 prefix6 []uint8 23 } 24 25 func normalize4(ip uint32, prefix uint8) uint32 { 26 return (ip >> (32 - prefix)) << (32 - prefix) 27 } 28 29 func normalize6(ip ipv6, prefix uint8) ipv6 { 30 if prefix <= 64 { 31 ip.a = (ip.a >> (64 - prefix)) << (64 - prefix) 32 ip.b = 0 33 } else { 34 ip.b = (ip.b >> (128 - prefix)) << (128 - prefix) 35 } 36 return ip 37 } 38 39 func (m *GeoIPMatcher) Init(cidrs []*CIDR) error { 40 ip4Count := 0 41 ip6Count := 0 42 43 for _, cidr := range cidrs { 44 ip := cidr.Ip 45 switch len(ip) { 46 case 4: 47 ip4Count++ 48 case 16: 49 ip6Count++ 50 default: 51 return newError("unexpect ip length: ", len(ip)) 52 } 53 } 54 55 cidrList := CIDRList(cidrs) 56 sort.Sort(&cidrList) 57 58 m.ip4 = make([]uint32, 0, ip4Count) 59 m.prefix4 = make([]uint8, 0, ip4Count) 60 m.ip6 = make([]ipv6, 0, ip6Count) 61 m.prefix6 = make([]uint8, 0, ip6Count) 62 63 for _, cidr := range cidrs { 64 ip := cidr.Ip 65 prefix := uint8(cidr.Prefix) 66 switch len(ip) { 67 case 4: 68 m.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix)) 69 m.prefix4 = append(m.prefix4, prefix) 70 case 16: 71 ip6 := ipv6{ 72 a: binary.BigEndian.Uint64(ip[0:8]), 73 b: binary.BigEndian.Uint64(ip[8:16]), 74 } 75 ip6 = normalize6(ip6, prefix) 76 77 m.ip6 = append(m.ip6, ip6) 78 m.prefix6 = append(m.prefix6, prefix) 79 } 80 } 81 82 return nil 83 } 84 85 func (m *GeoIPMatcher) match4(ip uint32) bool { 86 if len(m.ip4) == 0 { 87 return false 88 } 89 90 if ip < m.ip4[0] { 91 return false 92 } 93 94 size := uint32(len(m.ip4)) 95 l := uint32(0) 96 r := size 97 for l < r { 98 x := ((l + r) >> 1) 99 if ip < m.ip4[x] { 100 r = x 101 continue 102 } 103 104 nip := normalize4(ip, m.prefix4[x]) 105 if nip == m.ip4[x] { 106 return true 107 } 108 109 l = x + 1 110 } 111 112 return l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1] 113 } 114 115 func less6(a ipv6, b ipv6) bool { 116 return a.a < b.a || (a.a == b.a && a.b < b.b) 117 } 118 119 func (m *GeoIPMatcher) match6(ip ipv6) bool { 120 if len(m.ip6) == 0 { 121 return false 122 } 123 124 if less6(ip, m.ip6[0]) { 125 return false 126 } 127 128 size := uint32(len(m.ip6)) 129 l := uint32(0) 130 r := size 131 for l < r { 132 x := (l + r) / 2 133 if less6(ip, m.ip6[x]) { 134 r = x 135 continue 136 } 137 138 if normalize6(ip, m.prefix6[x]) == m.ip6[x] { 139 return true 140 } 141 142 l = x + 1 143 } 144 145 return l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1] 146 } 147 148 // Match returns true if the given ip is included by the GeoIP. 149 func (m *GeoIPMatcher) Match(ip net.IP) bool { 150 switch len(ip) { 151 case 4: 152 return m.match4(binary.BigEndian.Uint32(ip)) 153 case 16: 154 return m.match6(ipv6{ 155 a: binary.BigEndian.Uint64(ip[0:8]), 156 b: binary.BigEndian.Uint64(ip[8:16]), 157 }) 158 default: 159 return false 160 } 161 } 162 163 // GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code. 164 type GeoIPMatcherContainer struct { 165 matchers []*GeoIPMatcher 166 } 167 168 // Add adds a new GeoIP set into the container. 169 // If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one. 170 func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) { 171 if len(geoip.CountryCode) > 0 { 172 for _, m := range c.matchers { 173 if m.countryCode == geoip.CountryCode { 174 return m, nil 175 } 176 } 177 } 178 179 m := &GeoIPMatcher{ 180 countryCode: geoip.CountryCode, 181 } 182 if err := m.Init(geoip.Cidr); err != nil { 183 return nil, err 184 } 185 if len(geoip.CountryCode) > 0 { 186 c.matchers = append(c.matchers, m) 187 } 188 return m, nil 189 } 190 191 var ( 192 globalGeoIPContainer GeoIPMatcherContainer 193 )