123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- package router
- import (
- "net/netip"
- "strconv"
- "github.com/xtls/xray-core/common/net"
- "go4.org/netipx"
- )
- type GeoIPMatcher struct {
- countryCode string
- reverseMatch bool
- ip4 *netipx.IPSet
- ip6 *netipx.IPSet
- }
- func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
- var builder4, builder6 netipx.IPSetBuilder
- for _, cidr := range cidrs {
- ip := net.IP(cidr.GetIp())
- ipPrefixString := ip.String() + "/" + strconv.Itoa(int(cidr.GetPrefix()))
- ipPrefix, err := netip.ParsePrefix(ipPrefixString)
- if err != nil {
- return err
- }
- switch len(ip) {
- case net.IPv4len:
- builder4.AddPrefix(ipPrefix)
- case net.IPv6len:
- builder6.AddPrefix(ipPrefix)
- }
- }
- if ip4, err := builder4.IPSet(); err != nil {
- return err
- } else {
- m.ip4 = ip4
- }
- if ip6, err := builder6.IPSet(); err != nil {
- return err
- } else {
- m.ip6 = ip6
- }
- return nil
- }
- func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
- m.reverseMatch = isReverseMatch
- }
- func (m *GeoIPMatcher) match4(ip net.IP) bool {
- nip, ok := netipx.FromStdIP(ip)
- if !ok {
- return false
- }
- return m.ip4.Contains(nip)
- }
- func (m *GeoIPMatcher) match6(ip net.IP) bool {
- nip, ok := netipx.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 *GeoIP) (*GeoIPMatcher, error) {
- if len(geoip.CountryCode) > 0 {
- 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
- }
- if len(geoip.CountryCode) > 0 {
- c.matchers = append(c.matchers, m)
- }
- return m, nil
- }
- var globalGeoIPContainer GeoIPMatcherContainer
|