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