condition_geoip_test.go 5.2 KB

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