condition_geoip.go 2.5 KB

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