condition_geoip.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package router
  2. import (
  3. "net/netip"
  4. "strconv"
  5. "github.com/xtls/xray-core/common/net"
  6. "go4.org/netipx"
  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 []*CIDR) error {
  15. var builder4, builder6 netipx.IPSetBuilder
  16. for _, cidr := range cidrs {
  17. ip := net.IP(cidr.GetIp())
  18. ipPrefixString := ip.String() + "/" + strconv.Itoa(int(cidr.GetPrefix()))
  19. ipPrefix, err := netip.ParsePrefix(ipPrefixString)
  20. if err != nil {
  21. return err
  22. }
  23. switch len(ip) {
  24. case net.IPv4len:
  25. builder4.AddPrefix(ipPrefix)
  26. case net.IPv6len:
  27. builder6.AddPrefix(ipPrefix)
  28. }
  29. }
  30. if ip4, err := builder4.IPSet(); err != nil {
  31. return err
  32. } else {
  33. m.ip4 = ip4
  34. }
  35. if ip6, err := builder6.IPSet(); err != nil {
  36. return err
  37. } else {
  38. m.ip6 = ip6
  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 := netipx.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 := netipx.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 len(geoip.CountryCode) > 0 {
  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 len(geoip.CountryCode) > 0 {
  95. c.matchers = append(c.matchers, m)
  96. }
  97. return m, nil
  98. }
  99. var globalGeoIPContainer GeoIPMatcherContainer