condition_geoip.go 2.4 KB

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