github.com/v2fly/v2ray-core/v4@v4.45.2/app/router/condition_geoip_test.go (about) 1 package router_test 2 3 import ( 4 "errors" 5 "io/fs" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "google.golang.org/protobuf/proto" 12 13 "github.com/v2fly/v2ray-core/v4/app/router" 14 "github.com/v2fly/v2ray-core/v4/common" 15 "github.com/v2fly/v2ray-core/v4/common/net" 16 "github.com/v2fly/v2ray-core/v4/common/platform/filesystem" 17 ) 18 19 func init() { 20 const geoipURL = "https://raw.githubusercontent.com/v2fly/geoip/release/geoip.dat" 21 22 wd, err := os.Getwd() 23 common.Must(err) 24 25 tempPath := filepath.Join(wd, "..", "..", "testing", "temp") 26 geoipPath := filepath.Join(tempPath, "geoip.dat") 27 28 os.Setenv("v2ray.location.asset", tempPath) 29 30 if _, err := os.Stat(geoipPath); err != nil && errors.Is(err, fs.ErrNotExist) { 31 common.Must(os.MkdirAll(tempPath, 0o755)) 32 geoipBytes, err := common.FetchHTTPContent(geoipURL) 33 common.Must(err) 34 common.Must(filesystem.WriteFile(geoipPath, geoipBytes)) 35 } 36 } 37 38 func TestGeoIPMatcherContainer(t *testing.T) { 39 container := &router.GeoIPMatcherContainer{} 40 41 m1, err := container.Add(&router.GeoIP{ 42 CountryCode: "CN", 43 }) 44 common.Must(err) 45 46 m2, err := container.Add(&router.GeoIP{ 47 CountryCode: "US", 48 }) 49 common.Must(err) 50 51 m3, err := container.Add(&router.GeoIP{ 52 CountryCode: "CN", 53 }) 54 common.Must(err) 55 56 if m1 != m3 { 57 t.Error("expect same matcher for same geoip, but not") 58 } 59 60 if m1 == m2 { 61 t.Error("expect different matcher for different geoip, but actually same") 62 } 63 } 64 65 func TestGeoIPMatcher(t *testing.T) { 66 cidrList := []*router.CIDR{ 67 {Ip: []byte{0, 0, 0, 0}, Prefix: 8}, 68 {Ip: []byte{10, 0, 0, 0}, Prefix: 8}, 69 {Ip: []byte{100, 64, 0, 0}, Prefix: 10}, 70 {Ip: []byte{127, 0, 0, 0}, Prefix: 8}, 71 {Ip: []byte{169, 254, 0, 0}, Prefix: 16}, 72 {Ip: []byte{172, 16, 0, 0}, Prefix: 12}, 73 {Ip: []byte{192, 0, 0, 0}, Prefix: 24}, 74 {Ip: []byte{192, 0, 2, 0}, Prefix: 24}, 75 {Ip: []byte{192, 168, 0, 0}, Prefix: 16}, 76 {Ip: []byte{192, 18, 0, 0}, Prefix: 15}, 77 {Ip: []byte{198, 51, 100, 0}, Prefix: 24}, 78 {Ip: []byte{203, 0, 113, 0}, Prefix: 24}, 79 {Ip: []byte{8, 8, 8, 8}, Prefix: 32}, 80 {Ip: []byte{91, 108, 4, 0}, Prefix: 16}, 81 } 82 83 matcher := &router.GeoIPMatcher{} 84 common.Must(matcher.Init(cidrList)) 85 86 testCases := []struct { 87 Input string 88 Output bool 89 }{ 90 { 91 Input: "192.168.1.1", 92 Output: true, 93 }, 94 { 95 Input: "192.0.0.0", 96 Output: true, 97 }, 98 { 99 Input: "192.0.1.0", 100 Output: false, 101 }, 102 { 103 Input: "0.1.0.0", 104 Output: true, 105 }, 106 { 107 Input: "1.0.0.1", 108 Output: false, 109 }, 110 { 111 Input: "8.8.8.7", 112 Output: false, 113 }, 114 { 115 Input: "8.8.8.8", 116 Output: true, 117 }, 118 { 119 Input: "2001:cdba::3257:9652", 120 Output: false, 121 }, 122 { 123 Input: "91.108.255.254", 124 Output: true, 125 }, 126 } 127 128 for _, testCase := range testCases { 129 ip := net.ParseAddress(testCase.Input).IP() 130 actual := matcher.Match(ip) 131 if actual != testCase.Output { 132 t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual) 133 } 134 } 135 } 136 137 func TestGeoIPReverseMatcher(t *testing.T) { 138 cidrList := []*router.CIDR{ 139 {Ip: []byte{8, 8, 8, 8}, Prefix: 32}, 140 {Ip: []byte{91, 108, 4, 0}, Prefix: 16}, 141 } 142 matcher := &router.GeoIPMatcher{} 143 matcher.SetReverseMatch(true) // Reverse match 144 common.Must(matcher.Init(cidrList)) 145 146 testCases := []struct { 147 Input string 148 Output bool 149 }{ 150 { 151 Input: "8.8.8.8", 152 Output: false, 153 }, 154 { 155 Input: "2001:cdba::3257:9652", 156 Output: true, 157 }, 158 { 159 Input: "91.108.255.254", 160 Output: false, 161 }, 162 } 163 164 for _, testCase := range testCases { 165 ip := net.ParseAddress(testCase.Input).IP() 166 actual := matcher.Match(ip) 167 if actual != testCase.Output { 168 t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual) 169 } 170 } 171 } 172 173 func TestGeoIPMatcher4CN(t *testing.T) { 174 ips, err := loadGeoIP("CN") 175 common.Must(err) 176 177 matcher := &router.GeoIPMatcher{} 178 common.Must(matcher.Init(ips)) 179 180 if matcher.Match([]byte{8, 8, 8, 8}) { 181 t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does") 182 } 183 } 184 185 func TestGeoIPMatcher6US(t *testing.T) { 186 ips, err := loadGeoIP("US") 187 common.Must(err) 188 189 matcher := &router.GeoIPMatcher{} 190 common.Must(matcher.Init(ips)) 191 192 if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) { 193 t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not") 194 } 195 } 196 197 func loadGeoIP(country string) ([]*router.CIDR, error) { 198 geoipBytes, err := filesystem.ReadAsset("geoip.dat") 199 if err != nil { 200 return nil, err 201 } 202 var geoipList router.GeoIPList 203 if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil { 204 return nil, err 205 } 206 207 for _, geoip := range geoipList.Entry { 208 if strings.EqualFold(geoip.CountryCode, country) { 209 return geoip.Cidr, nil 210 } 211 } 212 213 panic("country not found: " + country) 214 } 215 216 func BenchmarkGeoIPMatcher4CN(b *testing.B) { 217 ips, err := loadGeoIP("CN") 218 common.Must(err) 219 220 matcher := &router.GeoIPMatcher{} 221 common.Must(matcher.Init(ips)) 222 223 b.ResetTimer() 224 225 for i := 0; i < b.N; i++ { 226 _ = matcher.Match([]byte{8, 8, 8, 8}) 227 } 228 } 229 230 func BenchmarkGeoIPMatcher6US(b *testing.B) { 231 ips, err := loadGeoIP("US") 232 common.Must(err) 233 234 matcher := &router.GeoIPMatcher{} 235 common.Must(matcher.Init(ips)) 236 237 b.ResetTimer() 238 239 for i := 0; i < b.N; i++ { 240 _ = matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) 241 } 242 }