github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/app/router/condition_test.go (about) 1 package router_test 2 3 import ( 4 "os" 5 "path/filepath" 6 "strconv" 7 "testing" 8 9 proto "github.com/golang/protobuf/proto" 10 11 . "v2ray.com/core/app/router" 12 "v2ray.com/core/common" 13 "v2ray.com/core/common/errors" 14 "v2ray.com/core/common/net" 15 "v2ray.com/core/common/platform" 16 "v2ray.com/core/common/platform/filesystem" 17 "v2ray.com/core/common/protocol" 18 "v2ray.com/core/common/protocol/http" 19 "v2ray.com/core/common/session" 20 "v2ray.com/core/features/routing" 21 routing_session "v2ray.com/core/features/routing/session" 22 ) 23 24 func init() { 25 wd, err := os.Getwd() 26 common.Must(err) 27 28 if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) { 29 common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat"))) 30 } 31 if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) { 32 common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "release", "config", "geosite.dat"))) 33 } 34 } 35 36 func withBackground() routing.Context { 37 return &routing_session.Context{} 38 } 39 40 func withOutbound(outbound *session.Outbound) routing.Context { 41 return &routing_session.Context{Outbound: outbound} 42 } 43 44 func withInbound(inbound *session.Inbound) routing.Context { 45 return &routing_session.Context{Inbound: inbound} 46 } 47 48 func withContent(content *session.Content) routing.Context { 49 return &routing_session.Context{Content: content} 50 } 51 52 func TestRoutingRule(t *testing.T) { 53 type ruleTest struct { 54 input routing.Context 55 output bool 56 } 57 58 cases := []struct { 59 rule *RoutingRule 60 test []ruleTest 61 }{ 62 { 63 rule: &RoutingRule{ 64 Domain: []*Domain{ 65 { 66 Value: "v2ray.com", 67 Type: Domain_Plain, 68 }, 69 { 70 Value: "google.com", 71 Type: Domain_Domain, 72 }, 73 { 74 Value: "^facebook\\.com$", 75 Type: Domain_Regex, 76 }, 77 }, 78 }, 79 test: []ruleTest{ 80 { 81 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)}), 82 output: true, 83 }, 84 { 85 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.v2ray.com.www"), 80)}), 86 output: true, 87 }, 88 { 89 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.co"), 80)}), 90 output: false, 91 }, 92 { 93 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.google.com"), 80)}), 94 output: true, 95 }, 96 { 97 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("facebook.com"), 80)}), 98 output: true, 99 }, 100 { 101 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.facebook.com"), 80)}), 102 output: false, 103 }, 104 { 105 input: withBackground(), 106 output: false, 107 }, 108 }, 109 }, 110 { 111 rule: &RoutingRule{ 112 Cidr: []*CIDR{ 113 { 114 Ip: []byte{8, 8, 8, 8}, 115 Prefix: 32, 116 }, 117 { 118 Ip: []byte{8, 8, 8, 8}, 119 Prefix: 32, 120 }, 121 { 122 Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(), 123 Prefix: 128, 124 }, 125 }, 126 }, 127 test: []ruleTest{ 128 { 129 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}), 130 output: true, 131 }, 132 { 133 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.4.4"), 80)}), 134 output: false, 135 }, 136 { 137 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 80)}), 138 output: true, 139 }, 140 { 141 input: withBackground(), 142 output: false, 143 }, 144 }, 145 }, 146 { 147 rule: &RoutingRule{ 148 Geoip: []*GeoIP{ 149 { 150 Cidr: []*CIDR{ 151 { 152 Ip: []byte{8, 8, 8, 8}, 153 Prefix: 32, 154 }, 155 { 156 Ip: []byte{8, 8, 8, 8}, 157 Prefix: 32, 158 }, 159 { 160 Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(), 161 Prefix: 128, 162 }, 163 }, 164 }, 165 }, 166 }, 167 test: []ruleTest{ 168 { 169 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}), 170 output: true, 171 }, 172 { 173 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.4.4"), 80)}), 174 output: false, 175 }, 176 { 177 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 80)}), 178 output: true, 179 }, 180 { 181 input: withBackground(), 182 output: false, 183 }, 184 }, 185 }, 186 { 187 rule: &RoutingRule{ 188 SourceCidr: []*CIDR{ 189 { 190 Ip: []byte{192, 168, 0, 0}, 191 Prefix: 16, 192 }, 193 }, 194 }, 195 test: []ruleTest{ 196 { 197 input: withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress("192.168.0.1"), 80)}), 198 output: true, 199 }, 200 { 201 input: withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress("10.0.0.1"), 80)}), 202 output: false, 203 }, 204 }, 205 }, 206 { 207 rule: &RoutingRule{ 208 UserEmail: []string{ 209 "admin@v2ray.com", 210 }, 211 }, 212 test: []ruleTest{ 213 { 214 input: withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: "admin@v2ray.com"}}), 215 output: true, 216 }, 217 { 218 input: withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: "love@v2ray.com"}}), 219 output: false, 220 }, 221 { 222 input: withBackground(), 223 output: false, 224 }, 225 }, 226 }, 227 { 228 rule: &RoutingRule{ 229 Protocol: []string{"http"}, 230 }, 231 test: []ruleTest{ 232 { 233 input: withContent(&session.Content{Protocol: (&http.SniffHeader{}).Protocol()}), 234 output: true, 235 }, 236 }, 237 }, 238 { 239 rule: &RoutingRule{ 240 InboundTag: []string{"test", "test1"}, 241 }, 242 test: []ruleTest{ 243 { 244 input: withInbound(&session.Inbound{Tag: "test"}), 245 output: true, 246 }, 247 { 248 input: withInbound(&session.Inbound{Tag: "test2"}), 249 output: false, 250 }, 251 }, 252 }, 253 { 254 rule: &RoutingRule{ 255 PortList: &net.PortList{ 256 Range: []*net.PortRange{ 257 {From: 443, To: 443}, 258 {From: 1000, To: 1100}, 259 }, 260 }, 261 }, 262 test: []ruleTest{ 263 { 264 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 443)}), 265 output: true, 266 }, 267 { 268 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 1100)}), 269 output: true, 270 }, 271 { 272 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 1005)}), 273 output: true, 274 }, 275 { 276 input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.LocalHostIP, 53)}), 277 output: false, 278 }, 279 }, 280 }, 281 { 282 rule: &RoutingRule{ 283 SourcePortList: &net.PortList{ 284 Range: []*net.PortRange{ 285 {From: 123, To: 123}, 286 {From: 9993, To: 9999}, 287 }, 288 }, 289 }, 290 test: []ruleTest{ 291 { 292 input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 123)}), 293 output: true, 294 }, 295 { 296 input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 9999)}), 297 output: true, 298 }, 299 { 300 input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 9994)}), 301 output: true, 302 }, 303 { 304 input: withInbound(&session.Inbound{Source: net.UDPDestination(net.LocalHostIP, 53)}), 305 output: false, 306 }, 307 }, 308 }, 309 { 310 rule: &RoutingRule{ 311 Protocol: []string{"http"}, 312 Attributes: "attrs[':path'].startswith('/test')", 313 }, 314 test: []ruleTest{ 315 { 316 input: withContent(&session.Content{Protocol: "http/1.1", Attributes: map[string]string{":path": "/test/1"}}), 317 output: true, 318 }, 319 }, 320 }, 321 } 322 323 for _, test := range cases { 324 cond, err := test.rule.BuildCondition() 325 common.Must(err) 326 327 for _, subtest := range test.test { 328 actual := cond.Apply(subtest.input) 329 if actual != subtest.output { 330 t.Error("test case failed: ", subtest.input, " expected ", subtest.output, " but got ", actual) 331 } 332 } 333 } 334 } 335 336 func loadGeoSite(country string) ([]*Domain, error) { 337 geositeBytes, err := filesystem.ReadAsset("geosite.dat") 338 if err != nil { 339 return nil, err 340 } 341 var geositeList GeoSiteList 342 if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil { 343 return nil, err 344 } 345 346 for _, site := range geositeList.Entry { 347 if site.CountryCode == country { 348 return site.Domain, nil 349 } 350 } 351 352 return nil, errors.New("country not found: " + country) 353 } 354 355 func TestChinaSites(t *testing.T) { 356 domains, err := loadGeoSite("CN") 357 common.Must(err) 358 359 matcher, err := NewDomainMatcher(domains) 360 common.Must(err) 361 362 type TestCase struct { 363 Domain string 364 Output bool 365 } 366 testCases := []TestCase{ 367 { 368 Domain: "163.com", 369 Output: true, 370 }, 371 { 372 Domain: "163.com", 373 Output: true, 374 }, 375 { 376 Domain: "164.com", 377 Output: false, 378 }, 379 { 380 Domain: "164.com", 381 Output: false, 382 }, 383 } 384 385 for i := 0; i < 1024; i++ { 386 testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false}) 387 } 388 389 for _, testCase := range testCases { 390 r := matcher.ApplyDomain(testCase.Domain) 391 if r != testCase.Output { 392 t.Error("expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r) 393 } 394 } 395 } 396 397 func BenchmarkMultiGeoIPMatcher(b *testing.B) { 398 var geoips []*GeoIP 399 400 { 401 ips, err := loadGeoIP("CN") 402 common.Must(err) 403 geoips = append(geoips, &GeoIP{ 404 CountryCode: "CN", 405 Cidr: ips, 406 }) 407 } 408 409 { 410 ips, err := loadGeoIP("JP") 411 common.Must(err) 412 geoips = append(geoips, &GeoIP{ 413 CountryCode: "JP", 414 Cidr: ips, 415 }) 416 } 417 418 { 419 ips, err := loadGeoIP("CA") 420 common.Must(err) 421 geoips = append(geoips, &GeoIP{ 422 CountryCode: "CA", 423 Cidr: ips, 424 }) 425 } 426 427 { 428 ips, err := loadGeoIP("US") 429 common.Must(err) 430 geoips = append(geoips, &GeoIP{ 431 CountryCode: "US", 432 Cidr: ips, 433 }) 434 } 435 436 matcher, err := NewMultiGeoIPMatcher(geoips, false) 437 common.Must(err) 438 439 ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}) 440 441 b.ResetTimer() 442 443 for i := 0; i < b.N; i++ { 444 _ = matcher.Apply(ctx) 445 } 446 }