condition_geoip.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. //go:build !confonly
  2. // +build !confonly
  3. package router
  4. import (
  5. "strconv"
  6. "inet.af/netaddr"
  7. "github.com/v2fly/v2ray-core/v4/common/net"
  8. )
  9. type GeoIPMatcher struct {
  10. countryCode string
  11. reverseMatch bool
  12. ip4 *netaddr.IPSet
  13. ip6 *netaddr.IPSet
  14. }
  15. func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
  16. var builder4, builder6 netaddr.IPSetBuilder
  17. for _, cidr := range cidrs {
  18. ip := net.IP(cidr.GetIp())
  19. ipStr := ip.String() + "/" + strconv.Itoa(int(cidr.GetPrefix()))
  20. ipPrefix, err := netaddr.ParseIPPrefix(ipStr)
  21. if err != nil {
  22. return err
  23. }
  24. switch len(ip) {
  25. case net.IPv4len:
  26. builder4.AddPrefix(ipPrefix)
  27. case net.IPv6len:
  28. builder6.AddPrefix(ipPrefix)
  29. }
  30. }
  31. var err error
  32. m.ip4, err = builder4.IPSet()
  33. if err != nil {
  34. return err
  35. }
  36. m.ip6, err = builder6.IPSet()
  37. if err != nil {
  38. return err
  39. }
  40. return nil
  41. }
  42. func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
  43. m.reverseMatch = isReverseMatch
  44. }
  45. func (m *GeoIPMatcher) match4(ip net.IP) bool {
  46. nip, ok := netaddr.FromStdIP(ip)
  47. if !ok {
  48. return false
  49. }
  50. return m.ip4.Contains(nip)
  51. }
  52. func (m *GeoIPMatcher) match6(ip net.IP) bool {
  53. nip, ok := netaddr.FromStdIP(ip)
  54. if !ok {
  55. return false
  56. }
  57. return m.ip6.Contains(nip)
  58. }
  59. // Match returns true if the given ip is included by the GeoIP.
  60. func (m *GeoIPMatcher) Match(ip net.IP) bool {
  61. isMatched := false
  62. switch len(ip) {
  63. case net.IPv4len:
  64. isMatched = m.match4(ip)
  65. case net.IPv6len:
  66. isMatched = m.match6(ip)
  67. }
  68. if m.reverseMatch {
  69. return !isMatched
  70. }
  71. return isMatched
  72. }
  73. // GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.
  74. type GeoIPMatcherContainer struct {
  75. matchers []*GeoIPMatcher
  76. }
  77. // Add adds a new GeoIP set into the container.
  78. // If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one.
  79. func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
  80. if geoip.CountryCode != "" {
  81. for _, m := range c.matchers {
  82. if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
  83. return m, nil
  84. }
  85. }
  86. }
  87. m := &GeoIPMatcher{
  88. countryCode: geoip.CountryCode,
  89. reverseMatch: geoip.ReverseMatch,
  90. }
  91. if err := m.Init(geoip.Cidr); err != nil {
  92. return nil, err
  93. }
  94. if geoip.CountryCode != "" {
  95. c.matchers = append(c.matchers, m)
  96. }
  97. return m, nil
  98. }
  99. var globalGeoIPContainer GeoIPMatcherContainer