condition_test.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. package router_test
  2. import (
  3. "context"
  4. "os"
  5. "path/filepath"
  6. "strconv"
  7. "testing"
  8. proto "github.com/golang/protobuf/proto"
  9. "v2ray.com/core/app/dispatcher"
  10. . "v2ray.com/core/app/router"
  11. "v2ray.com/core/common"
  12. "v2ray.com/core/common/errors"
  13. "v2ray.com/core/common/net"
  14. "v2ray.com/core/common/platform"
  15. "v2ray.com/core/common/platform/filesystem"
  16. "v2ray.com/core/common/protocol"
  17. "v2ray.com/core/common/protocol/http"
  18. "v2ray.com/core/common/session"
  19. )
  20. func init() {
  21. wd, err := os.Getwd()
  22. common.Must(err)
  23. common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat")))
  24. common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "release", "config", "geosite.dat")))
  25. }
  26. func withOutbound(outbound *session.Outbound) context.Context {
  27. return session.ContextWithOutbound(context.Background(), outbound)
  28. }
  29. func withInbound(inbound *session.Inbound) context.Context {
  30. return session.ContextWithInbound(context.Background(), inbound)
  31. }
  32. func TestRoutingRule(t *testing.T) {
  33. type ruleTest struct {
  34. input context.Context
  35. output bool
  36. }
  37. cases := []struct {
  38. rule *RoutingRule
  39. test []ruleTest
  40. }{
  41. {
  42. rule: &RoutingRule{
  43. Domain: []*Domain{
  44. {
  45. Value: "v2ray.com",
  46. Type: Domain_Plain,
  47. },
  48. {
  49. Value: "google.com",
  50. Type: Domain_Domain,
  51. },
  52. {
  53. Value: "^facebook\\.com$",
  54. Type: Domain_Regex,
  55. },
  56. },
  57. },
  58. test: []ruleTest{
  59. {
  60. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)}),
  61. output: true,
  62. },
  63. {
  64. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.v2ray.com.www"), 80)}),
  65. output: true,
  66. },
  67. {
  68. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.co"), 80)}),
  69. output: false,
  70. },
  71. {
  72. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.google.com"), 80)}),
  73. output: true,
  74. },
  75. {
  76. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("facebook.com"), 80)}),
  77. output: true,
  78. },
  79. {
  80. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("www.facebook.com"), 80)}),
  81. output: false,
  82. },
  83. {
  84. input: context.Background(),
  85. output: false,
  86. },
  87. },
  88. },
  89. {
  90. rule: &RoutingRule{
  91. Cidr: []*CIDR{
  92. {
  93. Ip: []byte{8, 8, 8, 8},
  94. Prefix: 32,
  95. },
  96. {
  97. Ip: []byte{8, 8, 8, 8},
  98. Prefix: 32,
  99. },
  100. {
  101. Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(),
  102. Prefix: 128,
  103. },
  104. },
  105. },
  106. test: []ruleTest{
  107. {
  108. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}),
  109. output: true,
  110. },
  111. {
  112. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.4.4"), 80)}),
  113. output: false,
  114. },
  115. {
  116. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 80)}),
  117. output: true,
  118. },
  119. {
  120. input: context.Background(),
  121. output: false,
  122. },
  123. },
  124. },
  125. {
  126. rule: &RoutingRule{
  127. Geoip: []*GeoIP{
  128. {
  129. Cidr: []*CIDR{
  130. {
  131. Ip: []byte{8, 8, 8, 8},
  132. Prefix: 32,
  133. },
  134. {
  135. Ip: []byte{8, 8, 8, 8},
  136. Prefix: 32,
  137. },
  138. {
  139. Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(),
  140. Prefix: 128,
  141. },
  142. },
  143. },
  144. },
  145. },
  146. test: []ruleTest{
  147. {
  148. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}),
  149. output: true,
  150. },
  151. {
  152. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.4.4"), 80)}),
  153. output: false,
  154. },
  155. {
  156. input: withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 80)}),
  157. output: true,
  158. },
  159. {
  160. input: context.Background(),
  161. output: false,
  162. },
  163. },
  164. },
  165. {
  166. rule: &RoutingRule{
  167. SourceCidr: []*CIDR{
  168. {
  169. Ip: []byte{192, 168, 0, 0},
  170. Prefix: 16,
  171. },
  172. },
  173. },
  174. test: []ruleTest{
  175. {
  176. input: withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress("192.168.0.1"), 80)}),
  177. output: true,
  178. },
  179. {
  180. input: withInbound(&session.Inbound{Source: net.TCPDestination(net.ParseAddress("10.0.0.1"), 80)}),
  181. output: false,
  182. },
  183. },
  184. },
  185. {
  186. rule: &RoutingRule{
  187. UserEmail: []string{
  188. "admin@v2ray.com",
  189. },
  190. },
  191. test: []ruleTest{
  192. {
  193. input: withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: "admin@v2ray.com"}}),
  194. output: true,
  195. },
  196. {
  197. input: withInbound(&session.Inbound{User: &protocol.MemoryUser{Email: "love@v2ray.com"}}),
  198. output: false,
  199. },
  200. {
  201. input: context.Background(),
  202. output: false,
  203. },
  204. },
  205. },
  206. {
  207. rule: &RoutingRule{
  208. Protocol: []string{"http"},
  209. },
  210. test: []ruleTest{
  211. {
  212. input: dispatcher.ContextWithSniffingResult(context.Background(), &http.SniffHeader{}),
  213. output: true,
  214. },
  215. },
  216. },
  217. {
  218. rule: &RoutingRule{
  219. InboundTag: []string{"test", "test1"},
  220. },
  221. test: []ruleTest{
  222. {
  223. input: withInbound(&session.Inbound{Tag: "test"}),
  224. output: true,
  225. },
  226. {
  227. input: withInbound(&session.Inbound{Tag: "test2"}),
  228. output: false,
  229. },
  230. },
  231. },
  232. }
  233. for _, test := range cases {
  234. cond, err := test.rule.BuildCondition()
  235. common.Must(err)
  236. for _, subtest := range test.test {
  237. actual := cond.Apply(subtest.input)
  238. if actual != subtest.output {
  239. t.Error("test case failed: ", subtest.input, " expected ", subtest.output, " but got ", actual)
  240. }
  241. }
  242. }
  243. }
  244. func loadGeoSite(country string) ([]*Domain, error) {
  245. geositeBytes, err := filesystem.ReadAsset("geosite.dat")
  246. if err != nil {
  247. return nil, err
  248. }
  249. var geositeList GeoSiteList
  250. if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
  251. return nil, err
  252. }
  253. for _, site := range geositeList.Entry {
  254. if site.CountryCode == country {
  255. return site.Domain, nil
  256. }
  257. }
  258. return nil, errors.New("country not found: " + country)
  259. }
  260. func TestChinaSites(t *testing.T) {
  261. domains, err := loadGeoSite("CN")
  262. common.Must(err)
  263. matcher, err := NewDomainMatcher(domains)
  264. common.Must(err)
  265. type TestCase struct {
  266. Domain string
  267. Output bool
  268. }
  269. testCases := []TestCase{
  270. {
  271. Domain: "163.com",
  272. Output: true,
  273. },
  274. {
  275. Domain: "163.com",
  276. Output: true,
  277. },
  278. {
  279. Domain: "164.com",
  280. Output: false,
  281. },
  282. {
  283. Domain: "164.com",
  284. Output: false,
  285. },
  286. }
  287. for i := 0; i < 1024; i++ {
  288. testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
  289. }
  290. for _, testCase := range testCases {
  291. r := matcher.ApplyDomain(testCase.Domain)
  292. if r != testCase.Output {
  293. t.Error("expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
  294. }
  295. }
  296. }
  297. func BenchmarkMultiGeoIPMatcher(b *testing.B) {
  298. var geoips []*GeoIP
  299. {
  300. ips, err := loadGeoIP("CN")
  301. common.Must(err)
  302. geoips = append(geoips, &GeoIP{
  303. CountryCode: "CN",
  304. Cidr: ips,
  305. })
  306. }
  307. {
  308. ips, err := loadGeoIP("JP")
  309. common.Must(err)
  310. geoips = append(geoips, &GeoIP{
  311. CountryCode: "JP",
  312. Cidr: ips,
  313. })
  314. }
  315. {
  316. ips, err := loadGeoIP("CA")
  317. common.Must(err)
  318. geoips = append(geoips, &GeoIP{
  319. CountryCode: "CA",
  320. Cidr: ips,
  321. })
  322. }
  323. {
  324. ips, err := loadGeoIP("US")
  325. common.Must(err)
  326. geoips = append(geoips, &GeoIP{
  327. CountryCode: "US",
  328. Cidr: ips,
  329. })
  330. }
  331. matcher, err := NewMultiGeoIPMatcher(geoips, false)
  332. common.Must(err)
  333. ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})
  334. b.ResetTimer()
  335. for i := 0; i < b.N; i++ {
  336. _ = matcher.Apply(ctx)
  337. }
  338. }