condition_geoip_test.go 5.2 KB

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