mihomo/rule/geodata/router/condition_geoip.go

111 lines
2.3 KiB
Go
Raw Normal View History

2021-07-01 22:49:29 +08:00
package router
import (
"fmt"
"net"
2021-10-15 14:11:14 +08:00
"inet.af/netaddr"
)
2021-07-01 22:49:29 +08:00
type GeoIPMatcher struct {
countryCode string
reverseMatch bool
2021-10-15 14:11:14 +08:00
ip4 *netaddr.IPSet
ip6 *netaddr.IPSet
2021-07-01 22:49:29 +08:00
}
func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
2021-10-15 14:11:14 +08:00
var builder4, builder6 netaddr.IPSetBuilder
2021-07-01 22:49:29 +08:00
for _, cidr := range cidrs {
2021-10-15 14:11:14 +08:00
netaddrIP, ok := netaddr.FromStdIP(net.IP(cidr.GetIp()))
if !ok {
return fmt.Errorf("invalid IP address %v", cidr)
}
ipPrefix := netaddr.IPPrefixFrom(netaddrIP, uint8(cidr.GetPrefix()))
switch {
case netaddrIP.Is4():
builder4.AddPrefix(ipPrefix)
case netaddrIP.Is6():
builder6.AddPrefix(ipPrefix)
2021-07-01 22:49:29 +08:00
}
}
2021-10-15 14:11:14 +08:00
var err error
m.ip4, err = builder4.IPSet()
if err != nil {
return err
}
m.ip6, err = builder6.IPSet()
if err != nil {
return err
2021-07-01 22:49:29 +08:00
}
return nil
}
func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
m.reverseMatch = isReverseMatch
}
2021-10-15 14:11:14 +08:00
func (m *GeoIPMatcher) match4(ip net.IP) bool {
nip, ok := netaddr.FromStdIP(ip)
if !ok {
2021-07-01 22:49:29 +08:00
return false
}
2021-10-15 14:11:14 +08:00
return m.ip4.Contains(nip)
2021-07-01 22:49:29 +08:00
}
2021-10-15 14:11:14 +08:00
func (m *GeoIPMatcher) match6(ip net.IP) bool {
nip, ok := netaddr.FromStdIP(ip)
if !ok {
2021-07-01 22:49:29 +08:00
return false
}
2021-10-15 14:11:14 +08:00
return m.ip6.Contains(nip)
2021-07-01 22:49:29 +08:00
}
// Match returns true if the given ip is included by the GeoIP.
func (m *GeoIPMatcher) Match(ip net.IP) bool {
2021-10-15 14:11:14 +08:00
isMatched := false
2021-07-01 22:49:29 +08:00
switch len(ip) {
2021-10-15 14:11:14 +08:00
case net.IPv4len:
isMatched = m.match4(ip)
case net.IPv6len:
isMatched = m.match6(ip)
}
if m.reverseMatch {
return !isMatched
2021-07-01 22:49:29 +08:00
}
2021-10-15 14:11:14 +08:00
return isMatched
2021-07-01 22:49:29 +08:00
}
// 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 *GeoIP) (*GeoIPMatcher, error) {
2021-10-15 14:11:14 +08:00
if geoip.CountryCode != "" {
2021-07-01 22:49:29 +08:00
for _, m := range c.matchers {
if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
return m, nil
}
}
}
m := &GeoIPMatcher{
countryCode: geoip.CountryCode,
reverseMatch: geoip.ReverseMatch,
}
if err := m.Init(geoip.Cidr); err != nil {
return nil, err
}
2021-10-15 14:11:14 +08:00
if geoip.CountryCode != "" {
2021-07-01 22:49:29 +08:00
c.matchers = append(c.matchers, m)
}
return m, nil
}
var globalGeoIPContainer GeoIPMatcherContainer