condition_geoip.go 2.5 KB

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