condition_geoip.go 2.5 KB

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