diff --git a/app/dns/dns_test.go b/app/dns/dns_test.go index c065056e..067ff445 100644 --- a/app/dns/dns_test.go +++ b/app/dns/dns_test.go @@ -548,15 +548,8 @@ func TestIPMatch(t *testing.T) { Port: uint32(port), }, ExpectedIp: []*geodata.IPRule{ - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - // inner ip, will not match - Ip: []byte{192, 168, 11, 1}, - Prefix: 32, - }, - }, - }, + // inner ip, will not match + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{192, 168, 11, 1}, Prefix: 32}}}}, }, }, // second dns, match ip @@ -571,22 +564,8 @@ func TestIPMatch(t *testing.T) { Port: uint32(port), }, ExpectedIp: []*geodata.IPRule{ - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 8, 8}, - Prefix: 32, - }, - }, - }, - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 8, 4}, - Prefix: 32, - }, - }, - }, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32}}}}, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 4}, Prefix: 32}}}}, }, }, }, @@ -676,9 +655,9 @@ func TestLocalDomain(t *testing.T) { }, ExpectedIp: []*geodata.IPRule{ // Will match localhost, localhost-a and localhost-b, - {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDR{Ip: []byte{127, 0, 0, 2}, Prefix: 32}}}, - {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDR{Ip: []byte{127, 0, 0, 3}, Prefix: 32}}}, - {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDR{Ip: []byte{127, 0, 0, 4}, Prefix: 32}}}, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 2}, Prefix: 32}}}}, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 3}, Prefix: 32}}}}, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 4}, Prefix: 32}}}}, }, }, { @@ -901,22 +880,8 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { }, ExpectedIp: []*geodata.IPRule{ // Will only match 8.8.8.8 and 8.8.4.4 - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 8, 8}, - Prefix: 32, - }, - }, - }, - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 4, 4}, - Prefix: 32, - }, - }, - }, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32}}}}, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 4, 4}, Prefix: 32}}}}, }, }, { @@ -936,14 +901,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { }, ExpectedIp: []*geodata.IPRule{ // Will match 8.8.8.8 and 8.8.8.7, etc - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 8, 7}, - Prefix: 24, - }, - }, - }, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 7}, Prefix: 24}}}}, }, }, { @@ -963,14 +921,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { }, ExpectedIp: []*geodata.IPRule{ // Will only match 8.8.7.7 (api.google.com) - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 7, 7}, - Prefix: 32, - }, - }, - }, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 7, 7}, Prefix: 32}}}}, }, }, { @@ -990,14 +941,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { }, ExpectedIp: []*geodata.IPRule{ // Will only match 8.8.7.8 (v2.api.google.com) - { - Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 7, 8}, - Prefix: 32, - }, - }, - }, + {Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{8, 8, 7, 8}, Prefix: 32}}}}, }, }, }, diff --git a/app/router/command/command_test.go b/app/router/command/command_test.go index e6706df8..adfe07dc 100644 --- a/app/router/command/command_test.go +++ b/app/router/command/command_test.go @@ -308,7 +308,7 @@ func TestServiceTestRoute(t *testing.T) { TargetTag: &router.RoutingRule_Tag{Tag: "out"}, }, { - SourceIp: []*geodata.IPRule{{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDR{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}}, + SourceIp: []*geodata.IPRule{{Value: &geodata.IPRule_Custom{Custom: &geodata.CIDRRule{Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}}}, TargetTag: &router.RoutingRule_Tag{Tag: "out"}, }, { diff --git a/app/router/condition_test.go b/app/router/condition_test.go index 9e57aa91..1b94bb8e 100644 --- a/app/router/condition_test.go +++ b/app/router/condition_test.go @@ -92,25 +92,22 @@ func TestRoutingRule(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 8, 8}, - Prefix: 32, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32}, }, }, }, { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{8, 8, 8, 8}, - Prefix: 32, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{8, 8, 8, 8}, Prefix: 32}, }, }, }, { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(), - Prefix: 128, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: net.ParseAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334").IP(), Prefix: 128}, }, }, }, @@ -140,9 +137,8 @@ func TestRoutingRule(t *testing.T) { SourceIp: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{192, 168, 0, 0}, - Prefix: 16, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{192, 168, 0, 0}, Prefix: 16}, }, }, }, diff --git a/app/router/router_test.go b/app/router/router_test.go index f038937f..323e9a62 100644 --- a/app/router/router_test.go +++ b/app/router/router_test.go @@ -159,9 +159,8 @@ func TestIPOnDemand(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{192, 168, 0, 0}, - Prefix: 16, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{192, 168, 0, 0}, Prefix: 16}, }, }, }, @@ -204,9 +203,8 @@ func TestIPIfNonMatchDomain(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{192, 168, 0, 0}, - Prefix: 16, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{192, 168, 0, 0}, Prefix: 16}, }, }, }, @@ -249,9 +247,8 @@ func TestIPIfNonMatchIP(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{127, 0, 0, 0}, - Prefix: 8, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 0}, Prefix: 8}, }, }, }, diff --git a/common/geodata/geodat.pb.go b/common/geodata/geodat.pb.go index b5cc2797..369839c5 100644 --- a/common/geodata/geodat.pb.go +++ b/common/geodata/geodat.pb.go @@ -433,6 +433,58 @@ func (x *CIDR) GetPrefix() uint32 { return 0 } +type CIDRRule struct { + state protoimpl.MessageState `protogen:"open.v1"` + Cidr *CIDR `protobuf:"bytes,1,opt,name=cidr,proto3" json:"cidr,omitempty"` + ReverseMatch bool `protobuf:"varint,2,opt,name=reverse_match,json=reverseMatch,proto3" json:"reverse_match,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CIDRRule) Reset() { + *x = CIDRRule{} + mi := &file_common_geodata_geodat_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CIDRRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CIDRRule) ProtoMessage() {} + +func (x *CIDRRule) ProtoReflect() protoreflect.Message { + mi := &file_common_geodata_geodat_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CIDRRule.ProtoReflect.Descriptor instead. +func (*CIDRRule) Descriptor() ([]byte, []int) { + return file_common_geodata_geodat_proto_rawDescGZIP(), []int{6} +} + +func (x *CIDRRule) GetCidr() *CIDR { + if x != nil { + return x.Cidr + } + return nil +} + +func (x *CIDRRule) GetReverseMatch() bool { + if x != nil { + return x.ReverseMatch + } + return false +} + type GeoIP struct { state protoimpl.MessageState `protogen:"open.v1"` Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` @@ -444,7 +496,7 @@ type GeoIP struct { func (x *GeoIP) Reset() { *x = GeoIP{} - mi := &file_common_geodata_geodat_proto_msgTypes[6] + mi := &file_common_geodata_geodat_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -456,7 +508,7 @@ func (x *GeoIP) String() string { func (*GeoIP) ProtoMessage() {} func (x *GeoIP) ProtoReflect() protoreflect.Message { - mi := &file_common_geodata_geodat_proto_msgTypes[6] + mi := &file_common_geodata_geodat_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -469,7 +521,7 @@ func (x *GeoIP) ProtoReflect() protoreflect.Message { // Deprecated: Use GeoIP.ProtoReflect.Descriptor instead. func (*GeoIP) Descriptor() ([]byte, []int) { - return file_common_geodata_geodat_proto_rawDescGZIP(), []int{6} + return file_common_geodata_geodat_proto_rawDescGZIP(), []int{7} } func (x *GeoIP) GetCode() string { @@ -502,7 +554,7 @@ type GeoIPList struct { func (x *GeoIPList) Reset() { *x = GeoIPList{} - mi := &file_common_geodata_geodat_proto_msgTypes[7] + mi := &file_common_geodata_geodat_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -514,7 +566,7 @@ func (x *GeoIPList) String() string { func (*GeoIPList) ProtoMessage() {} func (x *GeoIPList) ProtoReflect() protoreflect.Message { - mi := &file_common_geodata_geodat_proto_msgTypes[7] + mi := &file_common_geodata_geodat_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -527,7 +579,7 @@ func (x *GeoIPList) ProtoReflect() protoreflect.Message { // Deprecated: Use GeoIPList.ProtoReflect.Descriptor instead. func (*GeoIPList) Descriptor() ([]byte, []int) { - return file_common_geodata_geodat_proto_rawDescGZIP(), []int{7} + return file_common_geodata_geodat_proto_rawDescGZIP(), []int{8} } func (x *GeoIPList) GetEntry() []*GeoIP { @@ -548,7 +600,7 @@ type GeoIPRule struct { func (x *GeoIPRule) Reset() { *x = GeoIPRule{} - mi := &file_common_geodata_geodat_proto_msgTypes[8] + mi := &file_common_geodata_geodat_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -560,7 +612,7 @@ func (x *GeoIPRule) String() string { func (*GeoIPRule) ProtoMessage() {} func (x *GeoIPRule) ProtoReflect() protoreflect.Message { - mi := &file_common_geodata_geodat_proto_msgTypes[8] + mi := &file_common_geodata_geodat_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -573,7 +625,7 @@ func (x *GeoIPRule) ProtoReflect() protoreflect.Message { // Deprecated: Use GeoIPRule.ProtoReflect.Descriptor instead. func (*GeoIPRule) Descriptor() ([]byte, []int) { - return file_common_geodata_geodat_proto_rawDescGZIP(), []int{8} + return file_common_geodata_geodat_proto_rawDescGZIP(), []int{9} } func (x *GeoIPRule) GetFile() string { @@ -610,7 +662,7 @@ type IPRule struct { func (x *IPRule) Reset() { *x = IPRule{} - mi := &file_common_geodata_geodat_proto_msgTypes[9] + mi := &file_common_geodata_geodat_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -622,7 +674,7 @@ func (x *IPRule) String() string { func (*IPRule) ProtoMessage() {} func (x *IPRule) ProtoReflect() protoreflect.Message { - mi := &file_common_geodata_geodat_proto_msgTypes[9] + mi := &file_common_geodata_geodat_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -635,7 +687,7 @@ func (x *IPRule) ProtoReflect() protoreflect.Message { // Deprecated: Use IPRule.ProtoReflect.Descriptor instead. func (*IPRule) Descriptor() ([]byte, []int) { - return file_common_geodata_geodat_proto_rawDescGZIP(), []int{9} + return file_common_geodata_geodat_proto_rawDescGZIP(), []int{10} } func (x *IPRule) GetValue() isIPRule_Value { @@ -654,7 +706,7 @@ func (x *IPRule) GetGeoip() *GeoIPRule { return nil } -func (x *IPRule) GetCustom() *CIDR { +func (x *IPRule) GetCustom() *CIDRRule { if x != nil { if x, ok := x.Value.(*IPRule_Custom); ok { return x.Custom @@ -672,7 +724,7 @@ type IPRule_Geoip struct { } type IPRule_Custom struct { - Custom *CIDR `protobuf:"bytes,2,opt,name=custom,proto3,oneof"` + Custom *CIDRRule `protobuf:"bytes,2,opt,name=custom,proto3,oneof"` } func (*IPRule_Geoip) isIPRule_Value() {} @@ -693,7 +745,7 @@ type Domain_Attribute struct { func (x *Domain_Attribute) Reset() { *x = Domain_Attribute{} - mi := &file_common_geodata_geodat_proto_msgTypes[10] + mi := &file_common_geodata_geodat_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -705,7 +757,7 @@ func (x *Domain_Attribute) String() string { func (*Domain_Attribute) ProtoMessage() {} func (x *Domain_Attribute) ProtoReflect() protoreflect.Message { - mi := &file_common_geodata_geodat_proto_msgTypes[10] + mi := &file_common_geodata_geodat_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -807,7 +859,10 @@ const file_common_geodata_geodat_proto_rawDesc = "" + "\x05value\".\n" + "\x04CIDR\x12\x0e\n" + "\x02ip\x18\x01 \x01(\fR\x02ip\x12\x16\n" + - "\x06prefix\x18\x02 \x01(\rR\x06prefix\"o\n" + + "\x06prefix\x18\x02 \x01(\rR\x06prefix\"^\n" + + "\bCIDRRule\x12-\n" + + "\x04cidr\x18\x01 \x01(\v2\x19.xray.common.geodata.CIDRR\x04cidr\x12#\n" + + "\rreverse_match\x18\x02 \x01(\bR\freverseMatch\"o\n" + "\x05GeoIP\x12\x12\n" + "\x04code\x18\x01 \x01(\tR\x04code\x12-\n" + "\x04cidr\x18\x02 \x03(\v2\x19.xray.common.geodata.CIDRR\x04cidr\x12#\n" + @@ -817,10 +872,10 @@ const file_common_geodata_geodat_proto_rawDesc = "" + "\tGeoIPRule\x12\x12\n" + "\x04file\x18\x01 \x01(\tR\x04file\x12\x12\n" + "\x04code\x18\x02 \x01(\tR\x04code\x12#\n" + - "\rreverse_match\x18\x03 \x01(\bR\freverseMatch\"~\n" + + "\rreverse_match\x18\x03 \x01(\bR\freverseMatch\"\x82\x01\n" + "\x06IPRule\x126\n" + - "\x05geoip\x18\x01 \x01(\v2\x1e.xray.common.geodata.GeoIPRuleH\x00R\x05geoip\x123\n" + - "\x06custom\x18\x02 \x01(\v2\x19.xray.common.geodata.CIDRH\x00R\x06customB\a\n" + + "\x05geoip\x18\x01 \x01(\v2\x1e.xray.common.geodata.GeoIPRuleH\x00R\x05geoip\x127\n" + + "\x06custom\x18\x02 \x01(\v2\x1d.xray.common.geodata.CIDRRuleH\x00R\x06customB\a\n" + "\x05valueB[\n" + "\x17com.xray.common.geodataP\x01Z(github.com/xtls/xray-core/common/geodata\xaa\x02\x13Xray.Common.Geodatab\x06proto3" @@ -837,7 +892,7 @@ func file_common_geodata_geodat_proto_rawDescGZIP() []byte { } var file_common_geodata_geodat_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_common_geodata_geodat_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_common_geodata_geodat_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_common_geodata_geodat_proto_goTypes = []any{ (Domain_Type)(0), // 0: xray.common.geodata.Domain.Type (*Domain)(nil), // 1: xray.common.geodata.Domain @@ -846,28 +901,30 @@ var file_common_geodata_geodat_proto_goTypes = []any{ (*GeoSiteRule)(nil), // 4: xray.common.geodata.GeoSiteRule (*DomainRule)(nil), // 5: xray.common.geodata.DomainRule (*CIDR)(nil), // 6: xray.common.geodata.CIDR - (*GeoIP)(nil), // 7: xray.common.geodata.GeoIP - (*GeoIPList)(nil), // 8: xray.common.geodata.GeoIPList - (*GeoIPRule)(nil), // 9: xray.common.geodata.GeoIPRule - (*IPRule)(nil), // 10: xray.common.geodata.IPRule - (*Domain_Attribute)(nil), // 11: xray.common.geodata.Domain.Attribute + (*CIDRRule)(nil), // 7: xray.common.geodata.CIDRRule + (*GeoIP)(nil), // 8: xray.common.geodata.GeoIP + (*GeoIPList)(nil), // 9: xray.common.geodata.GeoIPList + (*GeoIPRule)(nil), // 10: xray.common.geodata.GeoIPRule + (*IPRule)(nil), // 11: xray.common.geodata.IPRule + (*Domain_Attribute)(nil), // 12: xray.common.geodata.Domain.Attribute } var file_common_geodata_geodat_proto_depIdxs = []int32{ 0, // 0: xray.common.geodata.Domain.type:type_name -> xray.common.geodata.Domain.Type - 11, // 1: xray.common.geodata.Domain.attribute:type_name -> xray.common.geodata.Domain.Attribute + 12, // 1: xray.common.geodata.Domain.attribute:type_name -> xray.common.geodata.Domain.Attribute 1, // 2: xray.common.geodata.GeoSite.domain:type_name -> xray.common.geodata.Domain 2, // 3: xray.common.geodata.GeoSiteList.entry:type_name -> xray.common.geodata.GeoSite 4, // 4: xray.common.geodata.DomainRule.geosite:type_name -> xray.common.geodata.GeoSiteRule 1, // 5: xray.common.geodata.DomainRule.custom:type_name -> xray.common.geodata.Domain - 6, // 6: xray.common.geodata.GeoIP.cidr:type_name -> xray.common.geodata.CIDR - 7, // 7: xray.common.geodata.GeoIPList.entry:type_name -> xray.common.geodata.GeoIP - 9, // 8: xray.common.geodata.IPRule.geoip:type_name -> xray.common.geodata.GeoIPRule - 6, // 9: xray.common.geodata.IPRule.custom:type_name -> xray.common.geodata.CIDR - 10, // [10:10] is the sub-list for method output_type - 10, // [10:10] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 6, // 6: xray.common.geodata.CIDRRule.cidr:type_name -> xray.common.geodata.CIDR + 6, // 7: xray.common.geodata.GeoIP.cidr:type_name -> xray.common.geodata.CIDR + 8, // 8: xray.common.geodata.GeoIPList.entry:type_name -> xray.common.geodata.GeoIP + 10, // 9: xray.common.geodata.IPRule.geoip:type_name -> xray.common.geodata.GeoIPRule + 7, // 10: xray.common.geodata.IPRule.custom:type_name -> xray.common.geodata.CIDRRule + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_common_geodata_geodat_proto_init() } @@ -879,11 +936,11 @@ func file_common_geodata_geodat_proto_init() { (*DomainRule_Geosite)(nil), (*DomainRule_Custom)(nil), } - file_common_geodata_geodat_proto_msgTypes[9].OneofWrappers = []any{ + file_common_geodata_geodat_proto_msgTypes[10].OneofWrappers = []any{ (*IPRule_Geoip)(nil), (*IPRule_Custom)(nil), } - file_common_geodata_geodat_proto_msgTypes[10].OneofWrappers = []any{ + file_common_geodata_geodat_proto_msgTypes[11].OneofWrappers = []any{ (*Domain_Attribute_BoolValue)(nil), (*Domain_Attribute_IntValue)(nil), } @@ -893,7 +950,7 @@ func file_common_geodata_geodat_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_common_geodata_geodat_proto_rawDesc), len(file_common_geodata_geodat_proto_rawDesc)), NumEnums: 1, - NumMessages: 11, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, diff --git a/common/geodata/geodat.proto b/common/geodata/geodat.proto index 1828b917..be91853e 100644 --- a/common/geodata/geodat.proto +++ b/common/geodata/geodat.proto @@ -66,6 +66,11 @@ message CIDR { uint32 prefix = 2; } +message CIDRRule { + CIDR cidr = 1; + bool reverse_match = 2; +} + message GeoIP { string code = 1; repeated CIDR cidr = 2; @@ -85,6 +90,6 @@ message GeoIPRule { message IPRule { oneof value { GeoIPRule geoip = 1; - CIDR custom = 2; + CIDRRule custom = 2; } } diff --git a/common/geodata/ip_matcher.go b/common/geodata/ip_matcher.go index 565b38ea..315ce040 100644 --- a/common/geodata/ip_matcher.go +++ b/common/geodata/ip_matcher.go @@ -940,45 +940,58 @@ func (f *IPSetFactory) createFrom(yield func(func(*CIDR)) error) (*IPSet, error) func buildOptimizedIPMatcher(f *IPSetFactory, rules []*IPRule) (IPMatcher, error) { n := len(rules) - custom := make([]*CIDR, 0, n) - pos := make([]*GeoIPRule, 0, n) - neg := make([]*GeoIPRule, 0, n) + posCustom := make([]*CIDR, 0, n) + negCustom := make([]*CIDR, 0, n) + posGeoip := make([]*GeoIPRule, 0, n) + negGeoip := make([]*GeoIPRule, 0, n) for _, r := range rules { switch v := r.Value.(type) { case *IPRule_Custom: - custom = append(custom, v.Custom) + if !v.Custom.ReverseMatch { + posCustom = append(posCustom, v.Custom.Cidr) + } else { + negCustom = append(negCustom, v.Custom.Cidr) + } case *IPRule_Geoip: if !v.Geoip.ReverseMatch { - pos = append(pos, v.Geoip) + posGeoip = append(posGeoip, v.Geoip) } else { - neg = append(neg, v.Geoip) + negGeoip = append(negGeoip, v.Geoip) } default: panic("unknown ip rule type") } } - subs := make([]*HeuristicIPMatcher, 0, 3) + subs := make([]*HeuristicIPMatcher, 0, 4) - if len(custom) > 0 { - ipset, err := f.CreateFromCIDRs(custom) + if len(posCustom) > 0 { + ipset, err := f.CreateFromCIDRs(posCustom) if err != nil { return nil, err } subs = append(subs, &HeuristicIPMatcher{ipset: ipset, reverse: false}) } - if len(pos) > 0 { - ipset, err := f.GetOrCreateFromGeoIPRules(pos) + if len(negCustom) > 0 { + ipset, err := f.CreateFromCIDRs(negCustom) + if err != nil { + return nil, err + } + subs = append(subs, &HeuristicIPMatcher{ipset: ipset, reverse: true}) + } + + if len(posGeoip) > 0 { + ipset, err := f.GetOrCreateFromGeoIPRules(posGeoip) if err != nil { return nil, err } subs = append(subs, &HeuristicIPMatcher{ipset: ipset, reverse: false}) } - if len(neg) > 0 { - ipset, err := f.GetOrCreateFromGeoIPRules(neg) + if len(negGeoip) > 0 { + ipset, err := f.GetOrCreateFromGeoIPRules(negGeoip) if err != nil { return nil, err } diff --git a/common/geodata/ip_matcher_test.go b/common/geodata/ip_matcher_test.go index ac627506..d1dc2de2 100644 --- a/common/geodata/ip_matcher_test.go +++ b/common/geodata/ip_matcher_test.go @@ -189,6 +189,34 @@ func TestIPReverseMatcher2(t *testing.T) { } } +func TestIPCustomReverseMatcher(t *testing.T) { + matcher := buildIPMatcher("!8.8.8.8/32") + + testCases := []struct { + Input string + Output bool + }{ + { + Input: "8.8.8.8", + Output: false, + }, + { + Input: "1.1.1.1", + Output: true, + }, + { + Input: "2001:cdba::3257:9652", + Output: false, + }, + } + + for _, test := range testCases { + if v := matcher.Match(xnet.ParseAddress(test.Input).IP()); v != test.Output { + t.Error("unexpected output: ", v, " for test case ", test) + } + } +} + func TestIPMatcherAnyMatchAndMatches(t *testing.T) { matcher := buildIPMatcher( "8.8.8.8/32", diff --git a/common/geodata/rule_parser.go b/common/geodata/rule_parser.go index 1184f553..c05fed31 100644 --- a/common/geodata/rule_parser.go +++ b/common/geodata/rule_parser.go @@ -17,6 +17,8 @@ func ParseIPRules(rules []string) ([]*IPRule, error) { var ipRules []*IPRule for i, r := range rules { + r, reverse := cutReversePrefix(r) + if strings.HasPrefix(r, "geoip:") { r = "ext:" + DefaultGeoIPDat + ":" + r[len("geoip:"):] } @@ -32,9 +34,9 @@ func ParseIPRules(rules []string) ([]*IPRule, error) { var rule isIPRule_Value var err error if prefix > 0 { - rule, err = parseGeoIPRule(r[prefix:]) + rule, err = parseGeoIPRule(r[prefix:], reverse) } else { - rule, err = parseCustomIPRule(r) + rule, err = parseCustomIPRule(r, reverse) } if err != nil { return nil, errors.New("illegal ip rule: ", rules[i]).Base(err) @@ -45,7 +47,16 @@ func ParseIPRules(rules []string) ([]*IPRule, error) { return ipRules, nil } -func parseGeoIPRule(rule string) (*IPRule_Geoip, error) { +func cutReversePrefix(s string) (string, bool) { + reverse := false + for strings.HasPrefix(s, "!") { + s = s[1:] + reverse = !reverse + } + return s, reverse +} + +func parseGeoIPRule(rule string, reverse bool) (*IPRule_Geoip, error) { file, code, ok := strings.Cut(rule, ":") if !ok { return nil, errors.New("syntax error") @@ -55,11 +66,8 @@ func parseGeoIPRule(rule string) (*IPRule_Geoip, error) { return nil, errors.New("empty file") } - reverse := false - if strings.HasPrefix(code, "!") { - code = code[1:] - reverse = true - } + code, codeReverse := cutReversePrefix(code) + reverse = reverse != codeReverse if code == "" { return nil, errors.New("empty code") } @@ -78,13 +86,16 @@ func parseGeoIPRule(rule string) (*IPRule_Geoip, error) { }, nil } -func parseCustomIPRule(rule string) (*IPRule_Custom, error) { +func parseCustomIPRule(rule string, reverse bool) (*IPRule_Custom, error) { cidr, err := parseCIDR(rule) if err != nil { return nil, err } return &IPRule_Custom{ - Custom: cidr, + Custom: &CIDRRule{ + Cidr: cidr, + ReverseMatch: reverse, + }, }, nil } diff --git a/common/geodata/rule_parser_test.go b/common/geodata/rule_parser_test.go index 87dbaaab..7aaf44c5 100644 --- a/common/geodata/rule_parser_test.go +++ b/common/geodata/rule_parser_test.go @@ -13,12 +13,20 @@ func TestParseIPRules(t *testing.T) { rules := []string{ "geoip:us", "geoip:cn", + "!geoip:cn", + "!!geoip:cn", "geoip:!cn", + "geoip:!!cn", + "!geoip:!cn", "ext:geoip.dat:!cn", + "ext:geoip.dat:!!cn", "ext:geoip.dat:ca", "ext-ip:geoip.dat:!cn", "ext-ip:geoip.dat:!ca", "192.168.0.0/24", + "!192.168.0.0/24", + "!!192.168.0.0/24", + "!!!192.168.0.0/24", "192.168.0.1", "fe80::/64", "fe80::", @@ -30,6 +38,53 @@ func TestParseIPRules(t *testing.T) { } } +func TestParseIPRuleReverse(t *testing.T) { + t.Setenv("xray.location.asset", filepath.Join("..", "..", "resources")) + + for _, tt := range []struct { + rule string + reverse bool + }{ + {rule: "!192.168.0.0/24", reverse: true}, + {rule: "!!192.168.0.0/24", reverse: false}, + {rule: "!!!192.168.0.0/24", reverse: true}, + {rule: "!!!!192.168.0.0/24", reverse: false}, + {rule: "geoip:cn", reverse: false}, + {rule: "!geoip:cn", reverse: true}, + {rule: "!!geoip:cn", reverse: false}, + {rule: "geoip:!cn", reverse: true}, + {rule: "geoip:!!cn", reverse: false}, + {rule: "!geoip:!cn", reverse: false}, + {rule: "!!geoip:!cn", reverse: true}, + {rule: "!geoip:!!cn", reverse: true}, + {rule: "ext:geoip.dat:!!!cn", reverse: true}, + } { + t.Run(tt.rule, func(t *testing.T) { + rules, err := geodata.ParseIPRules([]string{tt.rule}) + if err != nil { + t.Fatalf("Failed to parse ip rules, got %s", err) + } + + if len(rules) != 1 { + t.Fatalf("Expected 1 rule, got %d", len(rules)) + } + + switch rule := rules[0]; { + case rule.GetGeoip() != nil: + if rule.GetGeoip().GetReverseMatch() != tt.reverse { + t.Fatalf("Expected geoip reverse match to be %t", tt.reverse) + } + case rule.GetCustom() != nil: + if rule.GetCustom().GetReverseMatch() != tt.reverse { + t.Fatalf("Expected custom reverse match to be %t", tt.reverse) + } + default: + t.Fatal("Expected ip rule") + } + }) + } +} + func TestParseDomainRules(t *testing.T) { t.Setenv("xray.location.asset", filepath.Join("..", "..", "resources")) diff --git a/infra/conf/router_test.go b/infra/conf/router_test.go index 26ebff1c..130cf4f7 100644 --- a/infra/conf/router_test.go +++ b/infra/conf/router_test.go @@ -135,17 +135,15 @@ func TestRouterConfig(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{10, 0, 0, 0}, - Prefix: 8, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{10, 0, 0, 0}, Prefix: 8}, }, }, }, { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, - Prefix: 128, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, Prefix: 128}, }, }, }, @@ -216,17 +214,15 @@ func TestRouterConfig(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{10, 0, 0, 0}, - Prefix: 8, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{10, 0, 0, 0}, Prefix: 8}, }, }, }, { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, - Prefix: 128, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, Prefix: 128}, }, }, }, diff --git a/infra/conf/xray_test.go b/infra/conf/xray_test.go index d415f937..d4ff7126 100644 --- a/infra/conf/xray_test.go +++ b/infra/conf/xray_test.go @@ -99,9 +99,8 @@ func TestXrayConfig(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{10, 0, 0, 0}, - Prefix: 8, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{10, 0, 0, 0}, Prefix: 8}, }, }, }, @@ -216,8 +215,12 @@ func TestSniffingConfig_Build(t *testing.T) { if rule == nil { t.Fatalf("SniffingConfig.Build() produced a non-custom ip rule at index %d", i) } - if !reflect.DeepEqual(rule.Ip, tc.ip) || rule.Prefix != tc.prefix { - t.Fatalf("SniffingConfig.Build() produced wrong ip rule at index %d: got (%v, %d), want (%v, %d)", i, rule.Ip, rule.Prefix, tc.ip, tc.prefix) + cidr := rule.GetCidr() + if cidr == nil { + t.Fatalf("SniffingConfig.Build() produced a custom ip rule without cidr at index %d", i) + } + if !reflect.DeepEqual(cidr.Ip, tc.ip) || cidr.Prefix != tc.prefix { + t.Fatalf("SniffingConfig.Build() produced wrong ip rule at index %d: got (%v, %d), want (%v, %d)", i, cidr.Ip, cidr.Prefix, tc.ip, tc.prefix) } } } diff --git a/testing/scenarios/dns_test.go b/testing/scenarios/dns_test.go index 4f7fad5d..9be19a7d 100644 --- a/testing/scenarios/dns_test.go +++ b/testing/scenarios/dns_test.go @@ -47,9 +47,8 @@ func TestResolveIP(t *testing.T) { Ip: []*geodata.IPRule{ { Value: &geodata.IPRule_Custom{ - Custom: &geodata.CIDR{ - Ip: []byte{127, 0, 0, 0}, - Prefix: 8, + Custom: &geodata.CIDRRule{ + Cidr: &geodata.CIDR{Ip: []byte{127, 0, 0, 0}, Prefix: 8}, }, }, },