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
|