mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-15 01:09:20 +02:00
Feat: add reverse match for GeoIP
This commit is contained in:
parent
8a7cd65fc2
commit
68201a8898
|
@ -99,6 +99,7 @@ func ParaseIPList(ips []string) ([]*GeoIP, error) {
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
if strings.HasPrefix(ip, "geoip:") {
|
if strings.HasPrefix(ip, "geoip:") {
|
||||||
country := ip[6:]
|
country := ip[6:]
|
||||||
|
isReverseMatch := false
|
||||||
geoipc, err := LoadGeoIP(strings.ToUpper(country))
|
geoipc, err := LoadGeoIP(strings.ToUpper(country))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("failed to load GeoIP: ", country).Base(err)
|
return nil, newError("failed to load GeoIP: ", country).Base(err)
|
||||||
|
@ -107,6 +108,7 @@ func ParaseIPList(ips []string) ([]*GeoIP, error) {
|
||||||
geoipList = append(geoipList, &GeoIP{
|
geoipList = append(geoipList, &GeoIP{
|
||||||
CountryCode: strings.ToUpper(country),
|
CountryCode: strings.ToUpper(country),
|
||||||
Cidr: geoipc,
|
Cidr: geoipc,
|
||||||
|
ReverseMatch: isReverseMatch,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -129,6 +131,15 @@ func ParaseIPList(ips []string) ([]*GeoIP, error) {
|
||||||
|
|
||||||
filename := kv[0]
|
filename := kv[0]
|
||||||
country := kv[1]
|
country := kv[1]
|
||||||
|
if len(filename) == 0 || len(country) == 0 {
|
||||||
|
return nil, newError("empty filename or empty country in rule")
|
||||||
|
}
|
||||||
|
|
||||||
|
isReverseMatch := false
|
||||||
|
if strings.HasPrefix(country, "!") {
|
||||||
|
country = country[1:]
|
||||||
|
isReverseMatch = true
|
||||||
|
}
|
||||||
geoipc, err := LoadIPFile(filename, strings.ToUpper(country))
|
geoipc, err := LoadIPFile(filename, strings.ToUpper(country))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("failed to load IPs: ", country, " from ", filename).Base(err)
|
return nil, newError("failed to load IPs: ", country, " from ", filename).Base(err)
|
||||||
|
@ -137,6 +148,7 @@ func ParaseIPList(ips []string) ([]*GeoIP, error) {
|
||||||
geoipList = append(geoipList, &GeoIP{
|
geoipList = append(geoipList, &GeoIP{
|
||||||
CountryCode: strings.ToUpper(filename + "_" + country),
|
CountryCode: strings.ToUpper(filename + "_" + country),
|
||||||
Cidr: geoipc,
|
Cidr: geoipc,
|
||||||
|
ReverseMatch: isReverseMatch,
|
||||||
})
|
})
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -16,12 +16,17 @@ type ipv6 struct {
|
||||||
|
|
||||||
type GeoIPMatcher struct {
|
type GeoIPMatcher struct {
|
||||||
countryCode string
|
countryCode string
|
||||||
|
reverseMatch bool
|
||||||
ip4 []uint32
|
ip4 []uint32
|
||||||
prefix4 []uint8
|
prefix4 []uint8
|
||||||
ip6 []ipv6
|
ip6 []ipv6
|
||||||
prefix6 []uint8
|
prefix6 []uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
|
||||||
|
m.reverseMatch = isReverseMatch
|
||||||
|
}
|
||||||
|
|
||||||
func normalize4(ip uint32, prefix uint8) uint32 {
|
func normalize4(ip uint32, prefix uint8) uint32 {
|
||||||
return (ip >> (32 - prefix)) << (32 - prefix)
|
return (ip >> (32 - prefix)) << (32 - prefix)
|
||||||
}
|
}
|
||||||
|
@ -149,8 +154,17 @@ func (m *GeoIPMatcher) match6(ip ipv6) bool {
|
||||||
func (m *GeoIPMatcher) Match(ip net.IP) bool {
|
func (m *GeoIPMatcher) Match(ip net.IP) bool {
|
||||||
switch len(ip) {
|
switch len(ip) {
|
||||||
case 4:
|
case 4:
|
||||||
|
if m.reverseMatch {
|
||||||
|
return !m.match4(binary.BigEndian.Uint32(ip))
|
||||||
|
}
|
||||||
return m.match4(binary.BigEndian.Uint32(ip))
|
return m.match4(binary.BigEndian.Uint32(ip))
|
||||||
case 16:
|
case 16:
|
||||||
|
if m.reverseMatch {
|
||||||
|
return !m.match6(ipv6{
|
||||||
|
a: binary.BigEndian.Uint64(ip[0:8]),
|
||||||
|
b: binary.BigEndian.Uint64(ip[8:16]),
|
||||||
|
})
|
||||||
|
}
|
||||||
return m.match6(ipv6{
|
return m.match6(ipv6{
|
||||||
a: binary.BigEndian.Uint64(ip[0:8]),
|
a: binary.BigEndian.Uint64(ip[0:8]),
|
||||||
b: binary.BigEndian.Uint64(ip[8:16]),
|
b: binary.BigEndian.Uint64(ip[8:16]),
|
||||||
|
@ -170,7 +184,7 @@ type GeoIPMatcherContainer struct {
|
||||||
func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
|
func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
|
||||||
if len(geoip.CountryCode) > 0 {
|
if len(geoip.CountryCode) > 0 {
|
||||||
for _, m := range c.matchers {
|
for _, m := range c.matchers {
|
||||||
if m.countryCode == geoip.CountryCode {
|
if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,6 +192,7 @@ func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
|
||||||
|
|
||||||
m := &GeoIPMatcher{
|
m := &GeoIPMatcher{
|
||||||
countryCode: geoip.CountryCode,
|
countryCode: geoip.CountryCode,
|
||||||
|
reverseMatch: geoip.ReverseMatch,
|
||||||
}
|
}
|
||||||
if err := m.Init(geoip.Cidr); err != nil {
|
if err := m.Init(geoip.Cidr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.25.0
|
// protoc-gen-go v1.25.0
|
||||||
// protoc v3.15.6
|
// protoc v3.15.7
|
||||||
// source: common/matcher/geoip/geoip.proto
|
// source: common/matcher/geoip/geoip.proto
|
||||||
|
|
||||||
package geoip
|
package geoip
|
||||||
|
@ -90,6 +90,7 @@ type GeoIP struct {
|
||||||
|
|
||||||
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
|
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
|
||||||
Cidr []*CIDR `protobuf:"bytes,2,rep,name=cidr,proto3" json:"cidr,omitempty"`
|
Cidr []*CIDR `protobuf:"bytes,2,rep,name=cidr,proto3" json:"cidr,omitempty"`
|
||||||
|
ReverseMatch bool `protobuf:"varint,3,opt,name=reverse_match,json=reverseMatch,proto3" json:"reverse_match,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GeoIP) Reset() {
|
func (x *GeoIP) Reset() {
|
||||||
|
@ -138,6 +139,13 @@ func (x *GeoIP) GetCidr() []*CIDR {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *GeoIP) GetReverseMatch() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.ReverseMatch
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type GeoIPList struct {
|
type GeoIPList struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
@ -194,25 +202,27 @@ var file_common_matcher_geoip_geoip_proto_rawDesc = []byte{
|
||||||
0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x22, 0x2e, 0x0a,
|
0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x22, 0x2e, 0x0a,
|
||||||
0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
|
0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18,
|
0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18,
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x5f, 0x0a,
|
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x84, 0x01,
|
||||||
0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72,
|
0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
||||||
0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f,
|
0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63,
|
||||||
0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x63, 0x69, 0x64,
|
0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x63, 0x69,
|
||||||
0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65,
|
|
||||||
0x6f, 0x69, 0x70, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x22, 0x43,
|
|
||||||
0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x05, 0x65,
|
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
|
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
|
|
||||||
0x2e, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e,
|
|
||||||
0x74, 0x72, 0x79, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
|
||||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67,
|
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67,
|
||||||
0x65, 0x6f, 0x69, 0x70, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
0x65, 0x6f, 0x69, 0x70, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12,
|
||||||
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
|
0x23, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68,
|
||||||
0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x4d,
|
||||||
0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f,
|
0x61, 0x74, 0x63, 0x68, 0x22, 0x43, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c, 0x69, 0x73,
|
||||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f,
|
0x74, 0x12, 0x36, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x49, 0x50, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d,
|
||||||
|
0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2e, 0x47, 0x65, 0x6f,
|
||||||
|
0x49, 0x50, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d,
|
||||||
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74,
|
||||||
|
0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69,
|
||||||
|
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
|
||||||
|
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d,
|
||||||
|
0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0xaa, 0x02, 0x19, 0x58,
|
||||||
|
0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68,
|
||||||
|
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -18,6 +18,7 @@ message CIDR {
|
||||||
message GeoIP {
|
message GeoIP {
|
||||||
string country_code = 1;
|
string country_code = 1;
|
||||||
repeated CIDR cidr = 2;
|
repeated CIDR cidr = 2;
|
||||||
|
bool reverse_match =3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GeoIPList {
|
message GeoIPList {
|
||||||
|
|
|
@ -135,6 +135,42 @@ func TestGeoIPMatcher4CN(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGeoIPReverseMatcher(t *testing.T) {
|
||||||
|
cidrList := CIDRList{
|
||||||
|
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||||
|
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
||||||
|
}
|
||||||
|
matcher := &GeoIPMatcher{}
|
||||||
|
matcher.SetReverseMatch(true) // Reverse match
|
||||||
|
common.Must(matcher.Init(cidrList))
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
Input string
|
||||||
|
Output bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Input: "8.8.8.8",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "2001:cdba::3257:9652",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: "91.108.255.254",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
ip := net.ParseAddress(testCase.Input).IP()
|
||||||
|
actual := matcher.Match(ip)
|
||||||
|
if actual != testCase.Output {
|
||||||
|
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGeoIPMatcher6US(t *testing.T) {
|
func TestGeoIPMatcher6US(t *testing.T) {
|
||||||
ips, err := loadGeoIP("US")
|
ips, err := loadGeoIP("US")
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
Loading…
Reference in New Issue