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