Compare commits

..

3 Commits

Author SHA1 Message Date
秋のかえで
e14a4dc10b chore: regenerate protobufs 2021-04-14 23:37:45 +08:00
秋のかえで
ab3b0f843d Merge branch 'dns' into features-looutbound 2021-04-14 23:24:22 +08:00
AkinoKaede
98050aaf02 feat: add loopback outbound
Co-authored-by: Shelikhoo <xiaokangwang@outlook.com>
2021-04-14 23:22:18 +08:00
75 changed files with 2396 additions and 3842 deletions

View File

@@ -178,8 +178,8 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool { func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
domain := result.Domain() domain := result.Domain()
if request.ExcludedDomainMatcher != nil { for _, d := range request.ExcludeForDomain {
if request.ExcludedDomainMatcher.ApplyDomain(domain) { if domain == d {
return false return false
} }
} }
@@ -205,16 +205,6 @@ func shouldOverride(ctx context.Context, result SniffResult, request session.Sni
return false return false
} }
func canSniff(ctx context.Context, req session.SniffingRequest, destination net.Destination) bool {
if destination.Address.Family().IsIP() && req.ExcludedIPMatcher != nil {
if req.ExcludedIPMatcher.MatchIP(destination.Address.IP()) {
return false
}
}
return true
}
// Dispatch implements routing.Dispatcher. // Dispatch implements routing.Dispatcher.
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (*transport.Link, error) { func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (*transport.Link, error) {
if !destination.IsValid() { if !destination.IsValid() {
@@ -232,12 +222,6 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
} }
sniffingRequest := content.SniffingRequest sniffingRequest := content.SniffingRequest
if !canSniff(ctx, sniffingRequest, destination) {
newError("skip sniffing for ip ", destination.Address.String()).AtDebug().WriteToLog()
sniffingRequest.Enabled = false
}
switch { switch {
case !sniffingRequest.Enabled: case !sniffingRequest.Enabled:
go d.routedDispatch(ctx, outbound, destination) go d.routedDispatch(ctx, outbound, destination)

View File

@@ -1,32 +1,31 @@
package dns package dns
import ( import (
dm "github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/str"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/common/uuid"
) )
var typeMap = map[dm.MatchingType]str.Type{ var typeMap = map[DomainMatchingType]strmatcher.Type{
dm.MatchingType_Keyword: str.Substr, DomainMatchingType_Full: strmatcher.Full,
dm.MatchingType_Regex: str.Regex, DomainMatchingType_Subdomain: strmatcher.Domain,
dm.MatchingType_Subdomain: str.Domain, DomainMatchingType_Keyword: strmatcher.Substr,
dm.MatchingType_Full: str.Full, DomainMatchingType_Regex: strmatcher.Regex,
} }
// References: // References:
// https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml // https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
// https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan // https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan
var localTLDsAndDotlessDomains = []*dm.Domain{ var localTLDsAndDotlessDomains = []*NameServer_PriorityDomain{
{Type: dm.MatchingType_Regex, Value: "^[^.]+$"}, // This will only match domains without any dot {Type: DomainMatchingType_Regex, Domain: "^[^.]+$"}, // This will only match domains without any dot
{Type: dm.MatchingType_Subdomain, Value: "local"}, {Type: DomainMatchingType_Subdomain, Domain: "local"},
{Type: dm.MatchingType_Subdomain, Value: "localdomain"}, {Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
{Type: dm.MatchingType_Subdomain, Value: "localhost"}, {Type: DomainMatchingType_Subdomain, Domain: "localhost"},
{Type: dm.MatchingType_Subdomain, Value: "lan"}, {Type: DomainMatchingType_Subdomain, Domain: "lan"},
{Type: dm.MatchingType_Subdomain, Value: "home.arpa"}, {Type: DomainMatchingType_Subdomain, Domain: "home.arpa"},
{Type: dm.MatchingType_Subdomain, Value: "example"}, {Type: DomainMatchingType_Subdomain, Domain: "example"},
{Type: dm.MatchingType_Subdomain, Value: "invalid"}, {Type: DomainMatchingType_Subdomain, Domain: "invalid"},
{Type: dm.MatchingType_Subdomain, Value: "test"}, {Type: DomainMatchingType_Subdomain, Domain: "test"},
} }
var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{ var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
@@ -34,7 +33,7 @@ var localTLDsAndDotlessDomainsRule = &NameServer_OriginalRule{
Size: uint32(len(localTLDsAndDotlessDomains)), Size: uint32(len(localTLDsAndDotlessDomains)),
} }
func toStrMatcher(t dm.MatchingType, domain string) (str.Matcher, error) { func toStrMatcher(t DomainMatchingType, domain string) (strmatcher.Matcher, error) {
strMType, f := typeMap[t] strMType, f := typeMap[t]
if !f { if !f {
return nil, newError("unknown mapping type", t).AtWarning() return nil, newError("unknown mapping type", t).AtWarning()

View File

@@ -1,14 +1,14 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.26.0 // protoc-gen-go v1.25.0
// protoc v3.15.8 // protoc v3.15.8
// source: app/dns/config.proto // source: app/dns/config.proto
package dns package dns
import ( import (
domain "github.com/xtls/xray-core/common/matcher/domain" proto "github.com/golang/protobuf/proto"
geoip "github.com/xtls/xray-core/common/matcher/geoip" router "github.com/xtls/xray-core/app/router"
net "github.com/xtls/xray-core/common/net" net "github.com/xtls/xray-core/common/net"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
@@ -23,6 +23,62 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
) )
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type DomainMatchingType int32
const (
DomainMatchingType_Full DomainMatchingType = 0
DomainMatchingType_Subdomain DomainMatchingType = 1
DomainMatchingType_Keyword DomainMatchingType = 2
DomainMatchingType_Regex DomainMatchingType = 3
)
// Enum value maps for DomainMatchingType.
var (
DomainMatchingType_name = map[int32]string{
0: "Full",
1: "Subdomain",
2: "Keyword",
3: "Regex",
}
DomainMatchingType_value = map[string]int32{
"Full": 0,
"Subdomain": 1,
"Keyword": 2,
"Regex": 3,
}
)
func (x DomainMatchingType) Enum() *DomainMatchingType {
p := new(DomainMatchingType)
*p = x
return p
}
func (x DomainMatchingType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (DomainMatchingType) Descriptor() protoreflect.EnumDescriptor {
return file_app_dns_config_proto_enumTypes[0].Descriptor()
}
func (DomainMatchingType) Type() protoreflect.EnumType {
return &file_app_dns_config_proto_enumTypes[0]
}
func (x DomainMatchingType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use DomainMatchingType.Descriptor instead.
func (DomainMatchingType) EnumDescriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0}
}
type QueryStrategy int32 type QueryStrategy int32
const ( const (
@@ -56,11 +112,11 @@ func (x QueryStrategy) String() string {
} }
func (QueryStrategy) Descriptor() protoreflect.EnumDescriptor { func (QueryStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_app_dns_config_proto_enumTypes[0].Descriptor() return file_app_dns_config_proto_enumTypes[1].Descriptor()
} }
func (QueryStrategy) Type() protoreflect.EnumType { func (QueryStrategy) Type() protoreflect.EnumType {
return &file_app_dns_config_proto_enumTypes[0] return &file_app_dns_config_proto_enumTypes[1]
} }
func (x QueryStrategy) Number() protoreflect.EnumNumber { func (x QueryStrategy) Number() protoreflect.EnumNumber {
@@ -69,7 +125,7 @@ func (x QueryStrategy) Number() protoreflect.EnumNumber {
// Deprecated: Use QueryStrategy.Descriptor instead. // Deprecated: Use QueryStrategy.Descriptor instead.
func (QueryStrategy) EnumDescriptor() ([]byte, []int) { func (QueryStrategy) EnumDescriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0} return file_app_dns_config_proto_rawDescGZIP(), []int{1}
} }
type CacheStrategy int32 type CacheStrategy int32
@@ -105,11 +161,11 @@ func (x CacheStrategy) String() string {
} }
func (CacheStrategy) Descriptor() protoreflect.EnumDescriptor { func (CacheStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_app_dns_config_proto_enumTypes[1].Descriptor() return file_app_dns_config_proto_enumTypes[2].Descriptor()
} }
func (CacheStrategy) Type() protoreflect.EnumType { func (CacheStrategy) Type() protoreflect.EnumType {
return &file_app_dns_config_proto_enumTypes[1] return &file_app_dns_config_proto_enumTypes[2]
} }
func (x CacheStrategy) Number() protoreflect.EnumNumber { func (x CacheStrategy) Number() protoreflect.EnumNumber {
@@ -118,7 +174,7 @@ func (x CacheStrategy) Number() protoreflect.EnumNumber {
// Deprecated: Use CacheStrategy.Descriptor instead. // Deprecated: Use CacheStrategy.Descriptor instead.
func (CacheStrategy) EnumDescriptor() ([]byte, []int) { func (CacheStrategy) EnumDescriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{1} return file_app_dns_config_proto_rawDescGZIP(), []int{2}
} }
type NameServer struct { type NameServer struct {
@@ -126,12 +182,12 @@ type NameServer struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"` ClientIp []byte `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"` SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"`
PrioritizedDomain []*domain.Domain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"` PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
Geoip []*geoip.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"` Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"` OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
} }
func (x *NameServer) Reset() { func (x *NameServer) Reset() {
@@ -187,14 +243,14 @@ func (x *NameServer) GetSkipFallback() bool {
return false return false
} }
func (x *NameServer) GetPrioritizedDomain() []*domain.Domain { func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
if x != nil { if x != nil {
return x.PrioritizedDomain return x.PrioritizedDomain
} }
return nil return nil
} }
func (x *NameServer) GetGeoip() []*geoip.GeoIP { func (x *NameServer) GetGeoip() []*router.GeoIP {
if x != nil { if x != nil {
return x.Geoip return x.Geoip
} }
@@ -335,6 +391,61 @@ func (x *Config) GetDisableFallback() bool {
return false return false
} }
type NameServer_PriorityDomain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.dns.DomainMatchingType" json:"type,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
}
func (x *NameServer_PriorityDomain) Reset() {
*x = NameServer_PriorityDomain{}
if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NameServer_PriorityDomain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NameServer_PriorityDomain) ProtoMessage() {}
func (x *NameServer_PriorityDomain) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NameServer_PriorityDomain.ProtoReflect.Descriptor instead.
func (*NameServer_PriorityDomain) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0, 0}
}
func (x *NameServer_PriorityDomain) GetType() DomainMatchingType {
if x != nil {
return x.Type
}
return DomainMatchingType_Full
}
func (x *NameServer_PriorityDomain) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
type NameServer_OriginalRule struct { type NameServer_OriginalRule struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -347,7 +458,7 @@ type NameServer_OriginalRule struct {
func (x *NameServer_OriginalRule) Reset() { func (x *NameServer_OriginalRule) Reset() {
*x = NameServer_OriginalRule{} *x = NameServer_OriginalRule{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[2] mi := &file_app_dns_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -360,7 +471,7 @@ func (x *NameServer_OriginalRule) String() string {
func (*NameServer_OriginalRule) ProtoMessage() {} func (*NameServer_OriginalRule) ProtoMessage() {}
func (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message { func (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[2] mi := &file_app_dns_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -373,7 +484,7 @@ func (x *NameServer_OriginalRule) ProtoReflect() protoreflect.Message {
// Deprecated: Use NameServer_OriginalRule.ProtoReflect.Descriptor instead. // Deprecated: Use NameServer_OriginalRule.ProtoReflect.Descriptor instead.
func (*NameServer_OriginalRule) Descriptor() ([]byte, []int) { func (*NameServer_OriginalRule) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{0, 0} return file_app_dns_config_proto_rawDescGZIP(), []int{0, 1}
} }
func (x *NameServer_OriginalRule) GetRule() string { func (x *NameServer_OriginalRule) GetRule() string {
@@ -395,9 +506,9 @@ type Config_HostMapping struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Type domain.MatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=xray.common.matcher.domain.MatchingType" json:"type,omitempty"` Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=xray.app.dns.DomainMatchingType" json:"type,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"` Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"`
// ProxiedDomain indicates the mapped domain has the same IP address on this // ProxiedDomain indicates the mapped domain has the same IP address on this
// domain. Xray will use this domain for IP queries. // domain. Xray will use this domain for IP queries.
ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"` ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"`
@@ -406,7 +517,7 @@ type Config_HostMapping struct {
func (x *Config_HostMapping) Reset() { func (x *Config_HostMapping) Reset() {
*x = Config_HostMapping{} *x = Config_HostMapping{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_app_dns_config_proto_msgTypes[4] mi := &file_app_dns_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -419,7 +530,7 @@ func (x *Config_HostMapping) String() string {
func (*Config_HostMapping) ProtoMessage() {} func (*Config_HostMapping) ProtoMessage() {}
func (x *Config_HostMapping) ProtoReflect() protoreflect.Message { func (x *Config_HostMapping) ProtoReflect() protoreflect.Message {
mi := &file_app_dns_config_proto_msgTypes[4] mi := &file_app_dns_config_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -435,11 +546,11 @@ func (*Config_HostMapping) Descriptor() ([]byte, []int) {
return file_app_dns_config_proto_rawDescGZIP(), []int{1, 1} return file_app_dns_config_proto_rawDescGZIP(), []int{1, 1}
} }
func (x *Config_HostMapping) GetType() domain.MatchingType { func (x *Config_HostMapping) GetType() DomainMatchingType {
if x != nil { if x != nil {
return x.Type return x.Type
} }
return domain.MatchingType_Full return DomainMatchingType_Full
} }
func (x *Config_HostMapping) GetDomain() string { func (x *Config_HostMapping) GetDomain() string {
@@ -471,96 +582,103 @@ var file_app_dns_config_proto_rawDesc = []byte{
0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x22, 0x63, 0x6f, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70,
0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x64, 0x6f, 0x6d, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x61, 0x69, 0x6e, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x03, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65,
0x1a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x74, 0x6f, 0x22, 0x93, 0x03, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c,
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b,
0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x56, 0x0a, 0x12, 0x70, 0x72,
0x74, 0x49, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x51, 0x0a, 0x12, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61,
0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28,
0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x36, 0x0a, 0x05, 0x67, 0x65, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70,
0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x67, 0x65, 0x6f, 0x69, 0x70, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76,
0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52,
0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x5e,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20,
0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f,
0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65,
0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36,
0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xdf, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12,
0x66, 0x69, 0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75,
0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xd7, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x69, 0x6e, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
0x76, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
0x39, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a,
0x02, 0x18, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78,
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x02, 0x18,
0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69,
0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f,
0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72,
0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x42, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x0a, 0x0e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73,
0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x42, 0x0a, 0x0e,
0x65, 0x67, 0x79, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x08,
0x67, 0x79, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x79, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72,
0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61,
0x1a, 0x55, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64,
0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x1a, 0x55,
0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x9a, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e,
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61,
0x69, 0x6e, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e,
0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64,
0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52,
0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64,
0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f,
0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08,
0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69,
0x02, 0x2a, 0x44, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00,
0x67, 0x79, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x41, 0x4c, 0x4c, 0x10, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12,
0x00, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x4e, 0x4f, 0x45, 0x52, 0x52, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05,
0x4f, 0x52, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x44, 0x49, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79,
0x53, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x2a, 0x44,
0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x0d, 0x0a, 0x09, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x41, 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x11,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x4e, 0x4f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10,
0x01, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42,
0x4c, 0x45, 0x10, 0x02, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 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, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c,
0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -575,40 +693,41 @@ func file_app_dns_config_proto_rawDescGZIP() []byte {
return file_app_dns_config_proto_rawDescData return file_app_dns_config_proto_rawDescData
} }
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_app_dns_config_proto_goTypes = []interface{}{ var file_app_dns_config_proto_goTypes = []interface{}{
(QueryStrategy)(0), // 0: xray.app.dns.QueryStrategy (DomainMatchingType)(0), // 0: xray.app.dns.DomainMatchingType
(CacheStrategy)(0), // 1: xray.app.dns.CacheStrategy (QueryStrategy)(0), // 1: xray.app.dns.QueryStrategy
(*NameServer)(nil), // 2: xray.app.dns.NameServer (CacheStrategy)(0), // 2: xray.app.dns.CacheStrategy
(*Config)(nil), // 3: xray.app.dns.Config (*NameServer)(nil), // 3: xray.app.dns.NameServer
(*NameServer_OriginalRule)(nil), // 4: xray.app.dns.NameServer.OriginalRule (*Config)(nil), // 4: xray.app.dns.Config
nil, // 5: xray.app.dns.Config.HostsEntry (*NameServer_PriorityDomain)(nil), // 5: xray.app.dns.NameServer.PriorityDomain
(*Config_HostMapping)(nil), // 6: xray.app.dns.Config.HostMapping (*NameServer_OriginalRule)(nil), // 6: xray.app.dns.NameServer.OriginalRule
(*net.Endpoint)(nil), // 7: xray.common.net.Endpoint nil, // 7: xray.app.dns.Config.HostsEntry
(*domain.Domain)(nil), // 8: xray.common.matcher.domain.Domain (*Config_HostMapping)(nil), // 8: xray.app.dns.Config.HostMapping
(*geoip.GeoIP)(nil), // 9: xray.common.matcher.geoip.GeoIP (*net.Endpoint)(nil), // 9: xray.common.net.Endpoint
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain (*router.GeoIP)(nil), // 10: xray.app.router.GeoIP
(domain.MatchingType)(0), // 11: xray.common.matcher.domain.MatchingType (*net.IPOrDomain)(nil), // 11: xray.common.net.IPOrDomain
} }
var file_app_dns_config_proto_depIdxs = []int32{ var file_app_dns_config_proto_depIdxs = []int32{
7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint 9, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
8, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.common.matcher.domain.Domain 5, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
9, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.common.matcher.geoip.GeoIP 10, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
4, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule 6, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
7, // 4: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint 9, // 4: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint
2, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer 3, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
5, // 6: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry 7, // 6: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry
6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping 8, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
1, // 8: xray.app.dns.Config.cache_strategy:type_name -> xray.app.dns.CacheStrategy 2, // 8: xray.app.dns.Config.cache_strategy:type_name -> xray.app.dns.CacheStrategy
0, // 9: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy 1, // 9: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
10, // 10: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain 0, // 10: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
11, // 11: xray.app.dns.Config.HostMapping.type:type_name -> xray.common.matcher.domain.MatchingType 11, // 11: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain
12, // [12:12] is the sub-list for method output_type 0, // 12: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
12, // [12:12] is the sub-list for method input_type 13, // [13:13] is the sub-list for method output_type
12, // [12:12] is the sub-list for extension type_name 13, // [13:13] is the sub-list for method input_type
12, // [12:12] is the sub-list for extension extendee 13, // [13:13] is the sub-list for extension type_name
0, // [0:12] is the sub-list for field type_name 13, // [13:13] is the sub-list for extension extendee
0, // [0:13] is the sub-list for field type_name
} }
func init() { file_app_dns_config_proto_init() } func init() { file_app_dns_config_proto_init() }
@@ -642,6 +761,18 @@ func file_app_dns_config_proto_init() {
} }
} }
file_app_dns_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { file_app_dns_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NameServer_PriorityDomain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_dns_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NameServer_OriginalRule); i { switch v := v.(*NameServer_OriginalRule); i {
case 0: case 0:
return &v.state return &v.state
@@ -653,7 +784,7 @@ func file_app_dns_config_proto_init() {
return nil return nil
} }
} }
file_app_dns_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { file_app_dns_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config_HostMapping); i { switch v := v.(*Config_HostMapping); i {
case 0: case 0:
return &v.state return &v.state
@@ -671,8 +802,8 @@ func file_app_dns_config_proto_init() {
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_dns_config_proto_rawDesc, RawDescriptor: file_app_dns_config_proto_rawDesc,
NumEnums: 2, NumEnums: 3,
NumMessages: 5, NumMessages: 6,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@@ -8,24 +8,35 @@ option java_multiple_files = true;
import "common/net/address.proto"; import "common/net/address.proto";
import "common/net/destination.proto"; import "common/net/destination.proto";
import "common/matcher/domain/domain.proto"; import "app/router/config.proto";
import "common/matcher/geoip/geoip.proto";
message NameServer { message NameServer {
xray.common.net.Endpoint address = 1; xray.common.net.Endpoint address = 1;
bytes client_ip = 5; bytes client_ip = 5;
bool skipFallback = 6; bool skipFallback = 6;
message PriorityDomain {
DomainMatchingType type = 1;
string domain = 2;
}
message OriginalRule { message OriginalRule {
string rule = 1; string rule = 1;
uint32 size = 2; uint32 size = 2;
} }
repeated xray.common.matcher.domain.Domain prioritized_domain = 2; repeated PriorityDomain prioritized_domain = 2;
repeated xray.common.matcher.geoip.GeoIP geoip = 3; repeated xray.app.router.GeoIP geoip = 3;
repeated OriginalRule original_rules = 4; repeated OriginalRule original_rules = 4;
} }
enum DomainMatchingType {
Full = 0;
Subdomain = 1;
Keyword = 2;
Regex = 3;
}
enum QueryStrategy { enum QueryStrategy {
USE_IP = 0; USE_IP = 0;
USE_IP4 = 1; USE_IP4 = 1;
@@ -56,7 +67,7 @@ message Config {
bytes client_ip = 3; bytes client_ip = 3;
message HostMapping { message HostMapping {
xray.common.matcher.domain.MatchingType type = 1; DomainMatchingType type = 1;
string domain = 2; string domain = 2;
repeated bytes ip = 3; repeated bytes ip = 3;

View File

@@ -9,12 +9,12 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/matcher/str"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features" "github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
) )
@@ -29,7 +29,7 @@ type DNS struct {
hosts *StaticHosts hosts *StaticHosts
clients []*Client clients []*Client
ctx context.Context ctx context.Context
domainMatcher str.IndexMatcher domainMatcher strmatcher.IndexMatcher
matcherInfos []DomainMatcherInfo matcherInfos []DomainMatcherInfo
} }
@@ -91,8 +91,8 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1 // MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1) matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1)
domainMatcher := &str.MatcherGroup{} domainMatcher := &strmatcher.MatcherGroup{}
geoipContainer := geoip.GeoIPMatcherContainer{} geoipContainer := router.GeoIPMatcherContainer{}
for _, endpoint := range config.NameServers { for _, endpoint := range config.NameServers {
features.PrintDeprecatedFeatureWarning("simple DNS server") features.PrintDeprecatedFeatureWarning("simple DNS server")
@@ -105,7 +105,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
for _, ns := range config.NameServer { for _, ns := range config.NameServer {
clientIdx := len(clients) clientIdx := len(clients)
updateDomain := func(domainRule str.Matcher, originalRuleIdx int, matcherInfos []DomainMatcherInfo) error { updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []DomainMatcherInfo) error {
midx := domainMatcher.Add(domainRule) midx := domainMatcher.Add(domainRule)
matcherInfos[midx] = DomainMatcherInfo{ matcherInfos[midx] = DomainMatcherInfo{
clientIdx: uint16(clientIdx), clientIdx: uint16(clientIdx),

View File

@@ -12,9 +12,8 @@ import (
"github.com/xtls/xray-core/app/policy" "github.com/xtls/xray-core/app/policy"
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
_ "github.com/xtls/xray-core/app/proxyman/outbound" _ "github.com/xtls/xray-core/app/proxyman/outbound"
"github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -304,10 +303,10 @@ func TestPrioritizedDomain(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*NameServer_PriorityDomain{
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Value: "google.com", Domain: "google.com",
}, },
}, },
}, },
@@ -433,7 +432,7 @@ func TestStaticHostDomain(t *testing.T) {
}, },
StaticHosts: []*Config_HostMapping{ StaticHosts: []*Config_HostMapping{
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Domain: "example.com", Domain: "example.com",
ProxiedDomain: "google.com", ProxiedDomain: "google.com",
}, },
@@ -497,10 +496,10 @@ func TestIPMatch(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ {
CountryCode: "local", CountryCode: "local",
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
// inner ip, will not match // inner ip, will not match
Ip: []byte{192, 168, 11, 1}, Ip: []byte{192, 168, 11, 1},
@@ -521,10 +520,10 @@ func TestIPMatch(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ {
CountryCode: "test", CountryCode: "test",
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
Ip: []byte{8, 8, 8, 8}, Ip: []byte{8, 8, 8, 8},
Prefix: 32, Prefix: 32,
@@ -533,7 +532,7 @@ func TestIPMatch(t *testing.T) {
}, },
{ {
CountryCode: "test", CountryCode: "test",
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
Ip: []byte{8, 8, 8, 4}, Ip: []byte{8, 8, 8, 4},
Prefix: 32, Prefix: 32,
@@ -617,14 +616,14 @@ func TestLocalDomain(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*NameServer_PriorityDomain{
// Equivalent of dotless:localhost // Equivalent of dotless:localhost
{Type: domain.MatchingType_Regex, Value: "^[^.]*localhost[^.]*$"}, {Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
}, },
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ // Will match localhost, localhost-a and localhost-b, { // Will match localhost, localhost-a and localhost-b,
CountryCode: "local", CountryCode: "local",
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{Ip: []byte{127, 0, 0, 2}, Prefix: 32}, {Ip: []byte{127, 0, 0, 2}, Prefix: 32},
{Ip: []byte{127, 0, 0, 3}, Prefix: 32}, {Ip: []byte{127, 0, 0, 3}, Prefix: 32},
{Ip: []byte{127, 0, 0, 4}, Prefix: 32}, {Ip: []byte{127, 0, 0, 4}, Prefix: 32},
@@ -642,22 +641,22 @@ func TestLocalDomain(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*NameServer_PriorityDomain{
// Equivalent of dotless: and domain:local // Equivalent of dotless: and domain:local
{Type: domain.MatchingType_Regex, Value: "^[^.]*$"}, {Type: DomainMatchingType_Regex, Domain: "^[^.]*$"},
{Type: domain.MatchingType_Subdomain, Value: "local"}, {Type: DomainMatchingType_Subdomain, Domain: "local"},
{Type: domain.MatchingType_Subdomain, Value: "localdomain"}, {Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
}, },
}, },
}, },
StaticHosts: []*Config_HostMapping{ StaticHosts: []*Config_HostMapping{
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Domain: "hostnamestatic", Domain: "hostnamestatic",
Ip: [][]byte{{127, 0, 0, 53}}, Ip: [][]byte{{127, 0, 0, 53}},
}, },
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Domain: "hostnamealias", Domain: "hostnamealias",
ProxiedDomain: "hostname.localdomain", ProxiedDomain: "hostname.localdomain",
}, },
@@ -813,15 +812,15 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*NameServer_PriorityDomain{
{ {
Type: domain.MatchingType_Subdomain, Type: DomainMatchingType_Subdomain,
Value: "google.com", Domain: "google.com",
}, },
}, },
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ // Will only match 8.8.8.8 and 8.8.4.4 { // Will only match 8.8.8.8 and 8.8.4.4
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 8, 8}, Prefix: 32}, {Ip: []byte{8, 8, 8, 8}, Prefix: 32},
{Ip: []byte{8, 8, 4, 4}, Prefix: 32}, {Ip: []byte{8, 8, 4, 4}, Prefix: 32},
}, },
@@ -838,15 +837,15 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*NameServer_PriorityDomain{
{ {
Type: domain.MatchingType_Subdomain, Type: DomainMatchingType_Subdomain,
Value: "google.com", Domain: "google.com",
}, },
}, },
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ // Will match 8.8.8.8 and 8.8.8.7, etc { // Will match 8.8.8.8 and 8.8.8.7, etc
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 8, 7}, Prefix: 24}, {Ip: []byte{8, 8, 8, 7}, Prefix: 24},
}, },
}, },
@@ -862,15 +861,15 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*NameServer_PriorityDomain{
{ {
Type: domain.MatchingType_Subdomain, Type: DomainMatchingType_Subdomain,
Value: "api.google.com", Domain: "api.google.com",
}, },
}, },
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ // Will only match 8.8.7.7 (api.google.com) { // Will only match 8.8.7.7 (api.google.com)
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 7, 7}, Prefix: 32}, {Ip: []byte{8, 8, 7, 7}, Prefix: 32},
}, },
}, },
@@ -886,15 +885,15 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
}, },
Port: uint32(port), Port: uint32(port),
}, },
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*NameServer_PriorityDomain{
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Value: "v2.api.google.com", Domain: "v2.api.google.com",
}, },
}, },
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ // Will only match 8.8.7.8 (v2.api.google.com) { // Will only match 8.8.7.8 (v2.api.google.com)
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{Ip: []byte{8, 8, 7, 8}, Prefix: 32}, {Ip: []byte{8, 8, 7, 8}, Prefix: 32},
}, },
}, },

View File

@@ -2,8 +2,8 @@ package dns
import ( import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/str"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features" "github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
) )
@@ -11,12 +11,12 @@ import (
// StaticHosts represents static domain-ip mapping in DNS server. // StaticHosts represents static domain-ip mapping in DNS server.
type StaticHosts struct { type StaticHosts struct {
ips [][]net.Address ips [][]net.Address
matchers *str.MatcherGroup matchers *strmatcher.MatcherGroup
} }
// NewStaticHosts creates a new StaticHosts instance. // NewStaticHosts creates a new StaticHosts instance.
func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) { func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) {
g := new(str.MatcherGroup) g := new(strmatcher.MatcherGroup)
sh := &StaticHosts{ sh := &StaticHosts{
ips: make([][]net.Address, len(hosts)+len(legacy)+16), ips: make([][]net.Address, len(hosts)+len(legacy)+16),
matchers: g, matchers: g,
@@ -26,7 +26,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
features.PrintDeprecatedFeatureWarning("simple host mapping") features.PrintDeprecatedFeatureWarning("simple host mapping")
for domain, ip := range legacy { for domain, ip := range legacy {
matcher, err := str.Full.New(domain) matcher, err := strmatcher.Full.New(domain)
common.Must(err) common.Must(err)
id := g.Add(matcher) id := g.Add(matcher)

View File

@@ -7,7 +7,6 @@ import (
. "github.com/xtls/xray-core/app/dns" . "github.com/xtls/xray-core/app/dns"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
) )
@@ -15,14 +14,14 @@ import (
func TestStaticHosts(t *testing.T) { func TestStaticHosts(t *testing.T) {
pb := []*Config_HostMapping{ pb := []*Config_HostMapping{
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Domain: "example.com", Domain: "example.com",
Ip: [][]byte{ Ip: [][]byte{
{1, 1, 1, 1}, {1, 1, 1, 1},
}, },
}, },
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Domain: "proxy.example.com", Domain: "proxy.example.com",
Ip: [][]byte{ Ip: [][]byte{
{1, 2, 3, 4}, {1, 2, 3, 4},
@@ -31,19 +30,19 @@ func TestStaticHosts(t *testing.T) {
ProxiedDomain: "another-proxy.example.com", ProxiedDomain: "another-proxy.example.com",
}, },
{ {
Type: domain.MatchingType_Full, Type: DomainMatchingType_Full,
Domain: "proxy2.example.com", Domain: "proxy2.example.com",
ProxiedDomain: "proxy.example.com", ProxiedDomain: "proxy.example.com",
}, },
{ {
Type: domain.MatchingType_Subdomain, Type: DomainMatchingType_Subdomain,
Domain: "example.cn", Domain: "example.cn",
Ip: [][]byte{ Ip: [][]byte{
{2, 2, 2, 2}, {2, 2, 2, 2},
}, },
}, },
{ {
Type: domain.MatchingType_Subdomain, Type: DomainMatchingType_Subdomain,
Domain: "baidu.com", Domain: "baidu.com",
Ip: [][]byte{ Ip: [][]byte{
{127, 0, 0, 1}, {127, 0, 0, 1},

View File

@@ -6,10 +6,10 @@ import (
"strings" "strings"
"time" "time"
"github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/matcher/str"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
@@ -29,7 +29,7 @@ type Client struct {
clientIP net.IP clientIP net.IP
skipFallback bool skipFallback bool
domains []string domains []string
expectIPs []*geoip.GeoIPMatcher expectIPs []*router.GeoIPMatcher
} }
var errExpectedIPNonMatch = errors.New("expectIPs not match") var errExpectedIPNonMatch = errors.New("expectIPs not match")
@@ -64,7 +64,7 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err
} }
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs. // NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container geoip.GeoIPMatcherContainer, matcherInfos *[]DomainMatcherInfo, updateDomainRule func(str.Matcher, int, []DomainMatcherInfo) error) (*Client, error) { func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, matcherInfos *[]DomainMatcherInfo, updateDomainRule func(strmatcher.Matcher, int, []DomainMatcherInfo) error) (*Client, error) {
client := &Client{} client := &Client{}
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
@@ -95,7 +95,7 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container g
ruleCurr := 0 ruleCurr := 0
ruleIter := 0 ruleIter := 0
for _, domain := range ns.PrioritizedDomain { for _, domain := range ns.PrioritizedDomain {
domainRule, err := toStrMatcher(domain.Type, domain.Value) domainRule, err := toStrMatcher(domain.Type, domain.Domain)
if err != nil { if err != nil {
return newError("failed to create prioritized domain").Base(err).AtWarning() return newError("failed to create prioritized domain").Base(err).AtWarning()
} }
@@ -121,7 +121,7 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container g
} }
// Establish expected IPs // Establish expected IPs
var matchers []*geoip.GeoIPMatcher var matchers []*router.GeoIPMatcher
for _, geoip := range ns.Geoip { for _, geoip := range ns.Geoip {
matcher, err := container.Add(geoip) matcher, err := container.Add(geoip)
if err != nil { if err != nil {

View File

@@ -1,12 +1,5 @@
package proxyman package proxyman
import (
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geoip"
)
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
func (s *AllocationStrategy) GetConcurrencyValue() uint32 { func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
if s == nil || s.Concurrency == nil { if s == nil || s.Concurrency == nil {
return 3 return 3
@@ -44,32 +37,3 @@ func (c *ReceiverConfig) GetEffectiveSniffingSettings() *SniffingConfig {
return nil return nil
} }
type SniffingMatcher struct {
ExDomain *domain.DomainMatcher
ExIP *geoip.MultiGeoIPMatcher
}
func NewSniffingMatcher(sc *SniffingConfig) (*SniffingMatcher, error) {
m := new(SniffingMatcher)
if sc == nil {
return m, nil
}
if sc.DomainsExcluded != nil {
exDomain, err := domain.NewDomainMatcher(sc.DomainsExcluded)
if err != nil {
return nil, newError("failed to parse domain").Base(err)
}
m.ExDomain = exDomain
}
if sc.IpsExcluded != nil {
exIP, err := geoip.NewMultiGeoIPMatcher(sc.IpsExcluded, true)
if err != nil {
return nil, newError("failed to parse ip").Base(err)
}
m.ExIP = exIP
}
return m, nil
}

View File

@@ -1,15 +1,13 @@
// 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 (unknown)
// source: app/proxyman/config.proto // source: app/proxyman/config.proto
package proxyman package proxyman
import ( import (
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
domain "github.com/xtls/xray-core/common/matcher/domain"
geoip "github.com/xtls/xray-core/common/matcher/geoip"
net "github.com/xtls/xray-core/common/net" net "github.com/xtls/xray-core/common/net"
serial "github.com/xtls/xray-core/common/serial" serial "github.com/xtls/xray-core/common/serial"
internet "github.com/xtls/xray-core/transport/internet" internet "github.com/xtls/xray-core/transport/internet"
@@ -242,9 +240,8 @@ type SniffingConfig struct {
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
// Override target destination if sniff'ed protocol is in the given list. // Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls", "fakedns". // Supported values are "http", "tls", "fakedns".
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"` DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
DomainsExcluded []*domain.Domain `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"` DomainsExcluded []string `protobuf:"bytes,3,rep,name=domains_excluded,json=domainsExcluded,proto3" json:"domains_excluded,omitempty"`
IpsExcluded []*geoip.GeoIP `protobuf:"bytes,5,rep,name=ips_excluded,json=ipsExcluded,proto3" json:"ips_excluded,omitempty"`
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first message. // Can be used to support SMTP like protocol where server send the first message.
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"` MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
@@ -296,20 +293,13 @@ func (x *SniffingConfig) GetDestinationOverride() []string {
return nil return nil
} }
func (x *SniffingConfig) GetDomainsExcluded() []*domain.Domain { func (x *SniffingConfig) GetDomainsExcluded() []string {
if x != nil { if x != nil {
return x.DomainsExcluded return x.DomainsExcluded
} }
return nil return nil
} }
func (x *SniffingConfig) GetIpsExcluded() []*geoip.GeoIP {
if x != nil {
return x.IpsExcluded
}
return nil
}
func (x *SniffingConfig) GetMetadataOnly() bool { func (x *SniffingConfig) GetMetadataOnly() bool {
if x != nil { if x != nil {
return x.MetadataOnly return x.MetadataOnly
@@ -748,144 +738,133 @@ var File_app_proxyman_config_proto protoreflect.FileDescriptor
var file_app_proxyman_config_proto_rawDesc = []byte{ var file_app_proxyman_config_proto_rawDesc = []byte{
0x0a, 0x19, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63, 0x0a, 0x19, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x78, 0x72, 0x61, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x1a, 0x22, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x1a, 0x18,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x64, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x74, 0x6f, 0x1a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x65, 0x72, 0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2e, 0x70, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xae, 0x03, 0x0a, 0x12, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x3e, 0x0a, 0x04, 0x74,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x49, 0x6e, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xae, 0x03, 0x0a, 0x12, 0x41,
0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
0x79, 0x12, 0x3e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x2a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70,
0x65, 0x12, 0x65, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c,
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e,
0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x59, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72,
0x65, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c,
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x63,
0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a, 0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x32, 0x43, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
0x65, 0x6e, 0x63, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19, 0x41, 0x6c, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72,
0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x63, 0x79, 0x12, 0x59, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66,
0x72, 0x65, 0x73, 0x68, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x1a, 0x35, 0x0a,
0x1d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74,
0x65, 0x67, 0x79, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x1a, 0x31, 0x0a, 0x19, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73,
0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xad, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65,
0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73,
0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c,
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74,
0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61,
0x6e, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c,
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0x96, 0x02, 0x0a, 0x0e, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67,
0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f,
0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69,
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65,
0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x4d, 0x0a, 0x10, 0x64, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02,
0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
0x69, 0x6e, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x64, 0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73,
0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0c, 0x69, 0x70, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
0x73, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x6e, 0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2e, 0x47, 0x65, 0x6f, 0x52, 0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x49, 0x50, 0x52, 0x0b, 0x69, 0x70, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x12, 0x67, 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62,
0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x74, 0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20,
0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x67, 0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74,
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e,
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d,
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72,
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50,
0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a,
0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72,
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73,
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a,
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b,
0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18,
0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54,
0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02, 0x0a,
0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a,
0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f,
0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f,
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d,
0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x22, 0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x63, 0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07,
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61,
0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x01, 0x5a, 0x26, 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, 0x61, 0x70, 0x70,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79,
0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -915,37 +894,33 @@ var file_app_proxyman_config_proto_goTypes = []interface{}{
(*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig (*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency (*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh (*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*domain.Domain)(nil), // 12: xray.common.matcher.domain.Domain (*net.PortRange)(nil), // 12: xray.common.net.PortRange
(*geoip.GeoIP)(nil), // 13: xray.common.matcher.geoip.GeoIP (*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain
(*net.PortRange)(nil), // 14: xray.common.net.PortRange (*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig
(*net.IPOrDomain)(nil), // 15: xray.common.net.IPOrDomain (*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage
(*internet.StreamConfig)(nil), // 16: xray.transport.internet.StreamConfig (*internet.ProxyConfig)(nil), // 16: xray.transport.internet.ProxyConfig
(*serial.TypedMessage)(nil), // 17: xray.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 18: xray.transport.internet.ProxyConfig
} }
var file_app_proxyman_config_proto_depIdxs = []int32{ var file_app_proxyman_config_proto_depIdxs = []int32{
1, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type 1, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
10, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency 10, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh 11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
12, // 3: xray.app.proxyman.SniffingConfig.domains_excluded:type_name -> xray.common.matcher.domain.Domain 12, // 3: xray.app.proxyman.ReceiverConfig.port_range:type_name -> xray.common.net.PortRange
13, // 4: xray.app.proxyman.SniffingConfig.ips_excluded:type_name -> xray.common.matcher.geoip.GeoIP 13, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
14, // 5: xray.app.proxyman.ReceiverConfig.port_range:type_name -> xray.common.net.PortRange 3, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
15, // 6: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain 14, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
3, // 7: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy 0, // 7: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols
16, // 8: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 4, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
0, // 9: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols 15, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
4, // 10: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig 15, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
17, // 11: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage 13, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
17, // 12: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage 14, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
15, // 13: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain 16, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
16, // 14: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig 9, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
18, // 15: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig 15, // [15:15] is the sub-list for method output_type
9, // 16: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig 15, // [15:15] is the sub-list for method input_type
17, // [17:17] is the sub-list for method output_type 15, // [15:15] is the sub-list for extension type_name
17, // [17:17] is the sub-list for method input_type 15, // [15:15] is the sub-list for extension extendee
17, // [17:17] is the sub-list for extension type_name 0, // [0:15] is the sub-list for field type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
} }
func init() { file_app_proxyman_config_proto_init() } func init() { file_app_proxyman_config_proto_init() }

View File

@@ -6,8 +6,6 @@ option go_package = "github.com/xtls/xray-core/app/proxyman";
option java_package = "com.xray.app.proxyman"; option java_package = "com.xray.app.proxyman";
option java_multiple_files = true; option java_multiple_files = true;
import "common/matcher/domain/domain.proto";
import "common/matcher/geoip/geoip.proto";
import "common/net/address.proto"; import "common/net/address.proto";
import "common/net/port.proto"; import "common/net/port.proto";
import "transport/internet/config.proto"; import "transport/internet/config.proto";
@@ -58,9 +56,7 @@ message SniffingConfig {
// Override target destination if sniff'ed protocol is in the given list. // Override target destination if sniff'ed protocol is in the given list.
// Supported values are "http", "tls", "fakedns". // Supported values are "http", "tls", "fakedns".
repeated string destination_override = 2; repeated string destination_override = 2;
repeated string domains_excluded = 3;
repeated xray.common.matcher.domain.Domain domains_excluded = 3;
repeated xray.common.matcher.geoip.GeoIP ips_excluded = 5;
// Whether should only try to sniff metadata without waiting for client input. // Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first message. // Can be used to support SMTP like protocol where server send the first message.

View File

@@ -91,20 +91,13 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
if net.HasNetwork(nl, net.Network_UNIX) { if net.HasNetwork(nl, net.Network_UNIX) {
newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog() newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog()
sc := receiverConfig.GetEffectiveSniffingSettings()
sm, err := proxyman.NewSniffingMatcher(sc)
if err != nil {
return nil, err
}
worker := &dsWorker{ worker := &dsWorker{
address: address, address: address,
proxy: p, proxy: p,
stream: mss, stream: mss,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: sc, sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
sniffingMatcher: sm,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,
@@ -117,12 +110,6 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
if net.HasNetwork(nl, net.Network_TCP) { if net.HasNetwork(nl, net.Network_TCP) {
newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog() newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog()
sc := receiverConfig.GetEffectiveSniffingSettings()
sm, err := proxyman.NewSniffingMatcher(sc)
if err != nil {
return nil, err
}
worker := &tcpWorker{ worker := &tcpWorker{
address: address, address: address,
port: net.Port(port), port: net.Port(port),
@@ -131,8 +118,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
recvOrigDest: receiverConfig.ReceiveOriginalDestination, recvOrigDest: receiverConfig.ReceiveOriginalDestination,
tag: tag, tag: tag,
dispatcher: h.mux, dispatcher: h.mux,
sniffingConfig: sc, sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
sniffingMatcher: sm,
uplinkCounter: uplinkCounter, uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter, downlinkCounter: downlinkCounter,
ctx: ctx, ctx: ctx,

View File

@@ -39,7 +39,6 @@ type tcpWorker struct {
tag string tag string
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
sniffingConfig *proxyman.SniffingConfig sniffingConfig *proxyman.SniffingConfig
sniffingMatcher *proxyman.SniffingMatcher
uplinkCounter stats.Counter uplinkCounter stats.Counter
downlinkCounter stats.Counter downlinkCounter stats.Counter
@@ -98,8 +97,7 @@ func (w *tcpWorker) callback(conn internet.Connection) {
if w.sniffingConfig != nil { if w.sniffingConfig != nil {
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludedDomainMatcher = w.sniffingMatcher.ExDomain content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.ExcludedIPMatcher = w.sniffingMatcher.ExIP
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
} }
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)
@@ -430,7 +428,6 @@ type dsWorker struct {
tag string tag string
dispatcher routing.Dispatcher dispatcher routing.Dispatcher
sniffingConfig *proxyman.SniffingConfig sniffingConfig *proxyman.SniffingConfig
sniffingMatcher *proxyman.SniffingMatcher
uplinkCounter stats.Counter uplinkCounter stats.Counter
downlinkCounter stats.Counter downlinkCounter stats.Counter
@@ -462,8 +459,7 @@ func (w *dsWorker) callback(conn internet.Connection) {
if w.sniffingConfig != nil { if w.sniffingConfig != nil {
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludedDomainMatcher = w.sniffingMatcher.ExDomain content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.ExcludedIPMatcher = w.sniffingMatcher.ExIP
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
} }
ctx = session.ContextWithContent(ctx, content) ctx = session.ContextWithContent(ctx, content)

View File

@@ -12,8 +12,6 @@ import (
. "github.com/xtls/xray-core/app/router/command" . "github.com/xtls/xray-core/app/router/command"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/testing/mocks" "github.com/xtls/xray-core/testing/mocks"
@@ -233,11 +231,11 @@ func TestSerivceTestRoute(t *testing.T) {
TargetTag: &router.RoutingRule_Tag{Tag: "out"}, TargetTag: &router.RoutingRule_Tag{Tag: "out"},
}, },
{ {
Domain: []*domain.Domain{{Type: domain.MatchingType_Subdomain, Value: "com"}}, Domain: []*router.Domain{{Type: router.Domain_Domain, Value: "com"}},
TargetTag: &router.RoutingRule_Tag{Tag: "out"}, TargetTag: &router.RoutingRule_Tag{Tag: "out"},
}, },
{ {
SourceGeoip: []*geoip.GeoIP{{CountryCode: "private", Cidr: []*geoip.CIDR{{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}}, SourceGeoip: []*router.GeoIP{{CountryCode: "private", Cidr: []*router.CIDR{{Ip: []byte{127, 0, 0, 0}, Prefix: 8}}}},
TargetTag: &router.RoutingRule_Tag{Tag: "out"}, TargetTag: &router.RoutingRule_Tag{Tag: "out"},
}, },
{ {

View File

@@ -7,6 +7,7 @@ import (
"go.starlark.net/syntax" "go.starlark.net/syntax"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
) )
@@ -40,6 +41,100 @@ func (v *ConditionChan) Len() int {
return len(*v) return len(*v)
} }
var matcherTypeMap = map[Domain_Type]strmatcher.Type{
Domain_Plain: strmatcher.Substr,
Domain_Regex: strmatcher.Regex,
Domain_Domain: strmatcher.Domain,
Domain_Full: strmatcher.Full,
}
func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
matcherType, f := matcherTypeMap[domain.Type]
if !f {
return nil, newError("unsupported domain type", domain.Type)
}
matcher, err := matcherType.New(domain.Value)
if err != nil {
return nil, newError("failed to create domain matcher").Base(err)
}
return matcher, nil
}
type DomainMatcher struct {
matchers strmatcher.IndexMatcher
}
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
g := new(strmatcher.MatcherGroup)
for _, d := range domains {
m, err := domainToMatcher(d)
if err != nil {
return nil, err
}
g.Add(m)
}
return &DomainMatcher{
matchers: g,
}, nil
}
func (m *DomainMatcher) ApplyDomain(domain string) bool {
return len(m.matchers.Match(domain)) > 0
}
// Apply implements Condition.
func (m *DomainMatcher) Apply(ctx routing.Context) bool {
domain := ctx.GetTargetDomain()
if len(domain) == 0 {
return false
}
return m.ApplyDomain(strings.ToLower(domain))
}
type MultiGeoIPMatcher struct {
matchers []*GeoIPMatcher
onSource bool
}
func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
var matchers []*GeoIPMatcher
for _, geoip := range geoips {
matcher, err := globalGeoIPContainer.Add(geoip)
if err != nil {
return nil, err
}
matchers = append(matchers, matcher)
}
matcher := &MultiGeoIPMatcher{
matchers: matchers,
onSource: onSource,
}
return matcher, nil
}
// Apply implements Condition.
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
var ips []net.IP
if m.onSource {
ips = ctx.GetSourceIPs()
} else {
ips = ctx.GetTargetIPs()
}
for _, ip := range ips {
for _, matcher := range m.matchers {
if matcher.Match(ip) {
return true
}
}
}
return false
}
type PortMatcher struct { type PortMatcher struct {
port net.MemoryPortList port net.MemoryPortList
onSource bool onSource bool

View File

@@ -1,4 +1,4 @@
package geoip package router
import ( import (
"encoding/binary" "encoding/binary"
@@ -7,24 +7,17 @@ import (
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
) )
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
type ipv6 struct { type ipv6 struct {
a uint64 a uint64
b uint64 b uint64
} }
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 {
@@ -154,17 +147,8 @@ 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]),
@@ -184,15 +168,14 @@ 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 && m.reverseMatch == geoip.ReverseMatch { if m.countryCode == geoip.CountryCode {
return m, nil return m, nil
} }
} }
} }
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
@@ -204,5 +187,5 @@ func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
} }
var ( var (
GlobalGeoIPContainer GeoIPMatcherContainer globalGeoIPContainer GeoIPMatcherContainer
) )

View File

@@ -1,16 +1,16 @@
package geoip_test package router_test
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/common/platform/filesystem"
"google.golang.org/protobuf/proto"
) )
func init() { func init() {
@@ -18,47 +18,27 @@ func init() {
common.Must(err) common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) { if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "..", "resources", "geoip.dat"))) common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat")))
}
if _, err := os.Stat(platform.GetAssetLocation("geoiptestrouter.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoiptestrouter.dat"), filepath.Join(wd, "..", "..", "..", "resources", "geoip.dat")))
} }
if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) { if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "..", "resources", "geosite.dat"))) common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "resources", "geosite.dat")))
}
}
func TestParseIPList(t *testing.T) {
ips := []string{
"geoip:us",
"geoip:cn",
"geoip:!cn",
"ext:geoiptestrouter.dat:!cn",
"ext:geoiptestrouter.dat:ca",
"ext-ip:geoiptestrouter.dat:!cn",
"ext-ip:geoiptestrouter.dat:!ca",
}
_, err := ParseIPList(ips)
if err != nil {
t.Fatalf("Failed to parse geoip list, got %s", err)
} }
} }
func TestGeoIPMatcherContainer(t *testing.T) { func TestGeoIPMatcherContainer(t *testing.T) {
container := &GeoIPMatcherContainer{} container := &router.GeoIPMatcherContainer{}
m1, err := container.Add(&GeoIP{ m1, err := container.Add(&router.GeoIP{
CountryCode: "CN", CountryCode: "CN",
}) })
common.Must(err) common.Must(err)
m2, err := container.Add(&GeoIP{ m2, err := container.Add(&router.GeoIP{
CountryCode: "US", CountryCode: "US",
}) })
common.Must(err) common.Must(err)
m3, err := container.Add(&GeoIP{ m3, err := container.Add(&router.GeoIP{
CountryCode: "CN", CountryCode: "CN",
}) })
common.Must(err) common.Must(err)
@@ -73,7 +53,7 @@ func TestGeoIPMatcherContainer(t *testing.T) {
} }
func TestGeoIPMatcher(t *testing.T) { func TestGeoIPMatcher(t *testing.T) {
cidrList := CIDRList{ cidrList := router.CIDRList{
{Ip: []byte{0, 0, 0, 0}, Prefix: 8}, {Ip: []byte{0, 0, 0, 0}, Prefix: 8},
{Ip: []byte{10, 0, 0, 0}, Prefix: 8}, {Ip: []byte{10, 0, 0, 0}, Prefix: 8},
{Ip: []byte{100, 64, 0, 0}, Prefix: 10}, {Ip: []byte{100, 64, 0, 0}, Prefix: 10},
@@ -90,7 +70,7 @@ func TestGeoIPMatcher(t *testing.T) {
{Ip: []byte{91, 108, 4, 0}, Prefix: 16}, {Ip: []byte{91, 108, 4, 0}, Prefix: 16},
} }
matcher := &GeoIPMatcher{} matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(cidrList)) common.Must(matcher.Init(cidrList))
testCases := []struct { testCases := []struct {
@@ -143,47 +123,11 @@ func TestGeoIPMatcher(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 TestGeoIPMatcher4CN(t *testing.T) { func TestGeoIPMatcher4CN(t *testing.T) {
ips, err := loadGeoIP("CN") ips, err := loadGeoIP("CN")
common.Must(err) common.Must(err)
matcher := &GeoIPMatcher{} matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips)) common.Must(matcher.Init(ips))
if matcher.Match([]byte{8, 8, 8, 8}) { if matcher.Match([]byte{8, 8, 8, 8}) {
@@ -195,7 +139,7 @@ func TestGeoIPMatcher6US(t *testing.T) {
ips, err := loadGeoIP("US") ips, err := loadGeoIP("US")
common.Must(err) common.Must(err)
matcher := &GeoIPMatcher{} matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips)) common.Must(matcher.Init(ips))
if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) { if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
@@ -203,12 +147,12 @@ func TestGeoIPMatcher6US(t *testing.T) {
} }
} }
func loadGeoIP(country string) ([]*CIDR, error) { func loadGeoIP(country string) ([]*router.CIDR, error) {
geoipBytes, err := filesystem.ReadAsset("geoip.dat") geoipBytes, err := filesystem.ReadAsset("geoip.dat")
if err != nil { if err != nil {
return nil, err return nil, err
} }
var geoipList GeoIPList var geoipList router.GeoIPList
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil { if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
return nil, err return nil, err
} }
@@ -226,7 +170,7 @@ func BenchmarkGeoIPMatcher4CN(b *testing.B) {
ips, err := loadGeoIP("CN") ips, err := loadGeoIP("CN")
common.Must(err) common.Must(err)
matcher := &GeoIPMatcher{} matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips)) common.Must(matcher.Init(ips))
b.ResetTimer() b.ResetTimer()
@@ -240,7 +184,7 @@ func BenchmarkGeoIPMatcher6US(b *testing.B) {
ips, err := loadGeoIP("US") ips, err := loadGeoIP("US")
common.Must(err) common.Must(err)
matcher := &GeoIPMatcher{} matcher := &router.GeoIPMatcher{}
common.Must(matcher.Init(ips)) common.Must(matcher.Init(ips))
b.ResetTimer() b.ResetTimer()

View File

@@ -11,9 +11,6 @@ import (
. "github.com/xtls/xray-core/app/router" . "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/matcher/geosite"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/common/platform/filesystem"
@@ -29,10 +26,10 @@ func init() {
common.Must(err) common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) { if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat"))) common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat")))
} }
if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) { if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "resources", "geosite.dat"))) common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "release", "config", "geosite.dat")))
} }
} }
@@ -64,18 +61,18 @@ func TestRoutingRule(t *testing.T) {
}{ }{
{ {
rule: &RoutingRule{ rule: &RoutingRule{
Domain: []*domain.Domain{ Domain: []*Domain{
{ {
Value: "example.com", Value: "example.com",
Type: domain.MatchingType_Keyword, Type: Domain_Plain,
}, },
{ {
Value: "google.com", Value: "google.com",
Type: domain.MatchingType_Subdomain, Type: Domain_Domain,
}, },
{ {
Value: "^facebook\\.com$", Value: "^facebook\\.com$",
Type: domain.MatchingType_Regex, Type: Domain_Regex,
}, },
}, },
}, },
@@ -112,7 +109,7 @@ func TestRoutingRule(t *testing.T) {
}, },
{ {
rule: &RoutingRule{ rule: &RoutingRule{
Cidr: []*geoip.CIDR{ Cidr: []*CIDR{
{ {
Ip: []byte{8, 8, 8, 8}, Ip: []byte{8, 8, 8, 8},
Prefix: 32, Prefix: 32,
@@ -148,9 +145,9 @@ func TestRoutingRule(t *testing.T) {
}, },
{ {
rule: &RoutingRule{ rule: &RoutingRule{
Geoip: []*geoip.GeoIP{ Geoip: []*GeoIP{
{ {
Cidr: []*geoip.CIDR{ Cidr: []*CIDR{
{ {
Ip: []byte{8, 8, 8, 8}, Ip: []byte{8, 8, 8, 8},
Prefix: 32, Prefix: 32,
@@ -188,7 +185,7 @@ func TestRoutingRule(t *testing.T) {
}, },
{ {
rule: &RoutingRule{ rule: &RoutingRule{
SourceCidr: []*geoip.CIDR{ SourceCidr: []*CIDR{
{ {
Ip: []byte{192, 168, 0, 0}, Ip: []byte{192, 168, 0, 0},
Prefix: 16, Prefix: 16,
@@ -336,19 +333,19 @@ func TestRoutingRule(t *testing.T) {
} }
} }
func loadGeoSite(country string) ([]*domain.Domain, error) { func loadGeoSite(country string) ([]*Domain, error) {
geositeBytes, err := filesystem.ReadAsset("geosite.dat") geositeBytes, err := filesystem.ReadAsset("geosite.dat")
if err != nil { if err != nil {
return nil, err return nil, err
} }
var geositeList geosite.GeoSiteList var geositeList GeoSiteList
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil { if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
return nil, err return nil, err
} }
for _, site := range geositeList.Entry { for _, site := range geositeList.Entry {
if site.CountryCode == country { if site.CountryCode == country {
return geosite.ToDomains(site.Domain), nil return site.Domain, nil
} }
} }
@@ -359,10 +356,7 @@ func TestChinaSites(t *testing.T) {
domains, err := loadGeoSite("CN") domains, err := loadGeoSite("CN")
common.Must(err) common.Must(err)
matcher, err := domain.NewDomainMatcher(domains) matcher, err := NewDomainMatcher(domains)
common.Must(err)
acMatcher, err := domain.NewMphMatcherGroup(domains)
common.Must(err) common.Must(err)
type TestCase struct { type TestCase struct {
@@ -393,126 +387,20 @@ func TestChinaSites(t *testing.T) {
} }
for _, testCase := range testCases { for _, testCase := range testCases {
r1 := matcher.ApplyDomain(testCase.Domain) r := matcher.ApplyDomain(testCase.Domain)
r2 := acMatcher.ApplyDomain(testCase.Domain) if r != testCase.Output {
if r1 != testCase.Output { t.Error("expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
t.Error("DomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r1)
} else if r2 != testCase.Output {
t.Error("ACDomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r2)
} }
} }
} }
func BenchmarkMphDomainMatcher(b *testing.B) {
domains, err := loadGeoSite("CN")
common.Must(err)
matcher, err := domain.NewMphMatcherGroup(domains)
common.Must(err)
type TestCase struct {
Domain string
Output bool
}
testCases := []TestCase{
{
Domain: "163.com",
Output: true,
},
{
Domain: "163.com",
Output: true,
},
{
Domain: "164.com",
Output: false,
},
{
Domain: "164.com",
Output: false,
},
}
for i := 0; i < 1024; i++ {
testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, testCase := range testCases {
_ = matcher.ApplyDomain(testCase.Domain)
}
}
}
func BenchmarkDomainMatcher(b *testing.B) {
domains, err := loadGeoSite("CN")
common.Must(err)
matcher, err := domain.NewDomainMatcher(domains)
common.Must(err)
type TestCase struct {
Domain string
Output bool
}
testCases := []TestCase{
{
Domain: "163.com",
Output: true,
},
{
Domain: "163.com",
Output: true,
},
{
Domain: "164.com",
Output: false,
},
{
Domain: "164.com",
Output: false,
},
}
for i := 0; i < 1024; i++ {
testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, testCase := range testCases {
_ = matcher.ApplyDomain(testCase.Domain)
}
}
}
func loadGeoIP(country string) ([]*geoip.CIDR, error) {
geoipBytes, err := filesystem.ReadAsset("dat")
if err != nil {
return nil, err
}
var geoipList geoip.GeoIPList
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
return nil, err
}
for _, geoip := range geoipList.Entry {
if geoip.CountryCode == country {
return geoip.Cidr, nil
}
}
panic("country not found: " + country)
}
func BenchmarkMultiGeoIPMatcher(b *testing.B) { func BenchmarkMultiGeoIPMatcher(b *testing.B) {
var geoips []*geoip.GeoIP var geoips []*GeoIP
{ {
ips, err := loadGeoIP("CN") ips, err := loadGeoIP("CN")
common.Must(err) common.Must(err)
geoips = append(geoips, &geoip.GeoIP{ geoips = append(geoips, &GeoIP{
CountryCode: "CN", CountryCode: "CN",
Cidr: ips, Cidr: ips,
}) })
@@ -521,7 +409,7 @@ func BenchmarkMultiGeoIPMatcher(b *testing.B) {
{ {
ips, err := loadGeoIP("JP") ips, err := loadGeoIP("JP")
common.Must(err) common.Must(err)
geoips = append(geoips, &geoip.GeoIP{ geoips = append(geoips, &GeoIP{
CountryCode: "JP", CountryCode: "JP",
Cidr: ips, Cidr: ips,
}) })
@@ -530,7 +418,7 @@ func BenchmarkMultiGeoIPMatcher(b *testing.B) {
{ {
ips, err := loadGeoIP("CA") ips, err := loadGeoIP("CA")
common.Must(err) common.Must(err)
geoips = append(geoips, &geoip.GeoIP{ geoips = append(geoips, &GeoIP{
CountryCode: "CA", CountryCode: "CA",
Cidr: ips, Cidr: ips,
}) })
@@ -539,13 +427,13 @@ func BenchmarkMultiGeoIPMatcher(b *testing.B) {
{ {
ips, err := loadGeoIP("US") ips, err := loadGeoIP("US")
common.Must(err) common.Must(err)
geoips = append(geoips, &geoip.GeoIP{ geoips = append(geoips, &GeoIP{
CountryCode: "US", CountryCode: "US",
Cidr: ips, Cidr: ips,
}) })
} }
matcher, err := geoip.NewMultiGeoIPMatcher(geoips, false) matcher, err := NewMultiGeoIPMatcher(geoips, false)
common.Must(err) common.Must(err)
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)}) ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.ParseAddress("8.8.8.8"), 80)})

View File

@@ -1,13 +1,50 @@
package router package router
import ( import (
dm "github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing" "github.com/xtls/xray-core/features/routing"
) )
// CIDRList is an alias of []*CIDR to provide sort.Interface.
type CIDRList []*CIDR
// Len implements sort.Interface.
func (l *CIDRList) Len() int {
return len(*l)
}
// Less implements sort.Interface.
func (l *CIDRList) Less(i int, j int) bool {
ci := (*l)[i]
cj := (*l)[j]
if len(ci.Ip) < len(cj.Ip) {
return true
}
if len(ci.Ip) > len(cj.Ip) {
return false
}
for k := 0; k < len(ci.Ip); k++ {
if ci.Ip[k] < cj.Ip[k] {
return true
}
if ci.Ip[k] > cj.Ip[k] {
return false
}
}
return ci.Prefix < cj.Prefix
}
// Swap implements sort.Interface.
func (l *CIDRList) Swap(i int, j int) {
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
}
type Rule struct { type Rule struct {
Tag string Tag string
Balancer *Balancer Balancer *Balancer
@@ -30,24 +67,11 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
conds := NewConditionChan() conds := NewConditionChan()
if len(rr.Domain) > 0 { if len(rr.Domain) > 0 {
switch rr.DomainMatcher { matcher, err := NewDomainMatcher(rr.Domain)
case "linear": if err != nil {
matcher, err := dm.NewDomainMatcher(rr.Domain) return nil, newError("failed to build domain condition").Base(err)
if err != nil {
return nil, newError("failed to build domain condition").Base(err)
}
conds.Add(matcher)
case "mph", "hybrid":
fallthrough
default:
matcher, err := dm.NewMphMatcherGroup(rr.Domain)
if err != nil {
return nil, newError("failed to build domain condition with MphDomainMatcher").Base(err)
}
newError("MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)").AtDebug().WriteToLog()
conds.Add(matcher)
} }
conds.Add(matcher)
} }
if len(rr.UserEmail) > 0 { if len(rr.UserEmail) > 0 {
@@ -75,13 +99,13 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
} }
if len(rr.Geoip) > 0 { if len(rr.Geoip) > 0 {
cond, err := geoip.NewMultiGeoIPMatcher(rr.Geoip, false) cond, err := NewMultiGeoIPMatcher(rr.Geoip, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
conds.Add(cond) conds.Add(cond)
} else if len(rr.Cidr) > 0 { } else if len(rr.Cidr) > 0 {
cond, err := geoip.NewMultiGeoIPMatcher([]*geoip.GeoIP{{Cidr: rr.Cidr}}, false) cond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.Cidr}}, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -89,13 +113,13 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
} }
if len(rr.SourceGeoip) > 0 { if len(rr.SourceGeoip) > 0 {
cond, err := geoip.NewMultiGeoIPMatcher(rr.SourceGeoip, true) cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
conds.Add(cond) conds.Add(cond)
} else if len(rr.SourceCidr) > 0 { } else if len(rr.SourceCidr) > 0 {
cond, err := geoip.NewMultiGeoIPMatcher([]*geoip.GeoIP{{Cidr: rr.SourceCidr}}, true) cond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.SourceCidr}}, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,66 @@ option java_multiple_files = true;
import "common/net/port.proto"; import "common/net/port.proto";
import "common/net/network.proto"; import "common/net/network.proto";
import "common/matcher/domain/domain.proto";
import "common/matcher/geoip/geoip.proto"; // Domain for routing decision.
message Domain {
// Type of domain value.
enum Type {
// The value is used as is.
Plain = 0;
// The value is used as a regular expression.
Regex = 1;
// The value is a root domain.
Domain = 2;
// The value is a domain.
Full = 3;
}
// Domain matching type.
Type type = 1;
// Domain value.
string value = 2;
message Attribute {
string key = 1;
oneof typed_value {
bool bool_value = 2;
int64 int_value = 3;
}
}
// Attributes of this domain. May be used for filtering.
repeated Attribute attribute = 3;
}
// IP for routing decision, in CIDR form.
message CIDR {
// IP address, should be either 4 or 16 bytes.
bytes ip = 1;
// Number of leading ones in the network mask.
uint32 prefix = 2;
}
message GeoIP {
string country_code = 1;
repeated CIDR cidr = 2;
}
message GeoIPList {
repeated GeoIP entry = 1;
}
message GeoSite {
string country_code = 1;
repeated Domain domain = 2;
}
message GeoSiteList {
repeated GeoSite entry = 1;
}
message RoutingRule { message RoutingRule {
oneof target_tag { oneof target_tag {
@@ -21,17 +79,17 @@ message RoutingRule {
} }
// List of domains for target domain matching. // List of domains for target domain matching.
repeated xray.common.matcher.domain.Domain domain = 2; repeated Domain domain = 2;
// List of CIDRs for target IP address matching. // List of CIDRs for target IP address matching.
// Deprecated. Use geoip below. // Deprecated. Use geoip below.
repeated xray.common.matcher.geoip.CIDR cidr = 3 [deprecated = true]; repeated CIDR cidr = 3 [deprecated = true];
// List of GeoIPs for target IP address matching. If this entry exists, the // List of GeoIPs for target IP address matching. If this entry exists, the
// cidr above will have no effect. GeoIP fields with the same country code are // cidr above will have no effect. GeoIP fields with the same country code are
// supposed to contain exactly same content. They will be merged during // supposed to contain exactly same content. They will be merged during
// runtime. For customized GeoIPs, please leave country code empty. // runtime. For customized GeoIPs, please leave country code empty.
repeated xray.common.matcher.geoip.GeoIP geoip = 10; repeated GeoIP geoip = 10;
// A range of port [from, to]. If the destination port is in this range, this // A range of port [from, to]. If the destination port is in this range, this
// rule takes effect. Deprecated. Use port_list. // rule takes effect. Deprecated. Use port_list.
@@ -47,11 +105,11 @@ message RoutingRule {
repeated xray.common.net.Network networks = 13; repeated xray.common.net.Network networks = 13;
// List of CIDRs for source IP address matching. // List of CIDRs for source IP address matching.
repeated xray.common.matcher.geoip.CIDR source_cidr = 6 [deprecated = true]; repeated CIDR source_cidr = 6 [deprecated = true];
// List of GeoIPs for source IP address matching. If this entry exists, the // List of GeoIPs for source IP address matching. If this entry exists, the
// source_cidr above will have no effect. // source_cidr above will have no effect.
repeated xray.common.matcher.geoip.GeoIP source_geoip = 11; repeated GeoIP source_geoip = 11;
// List of ports for source port matching. // List of ports for source port matching.
xray.common.net.PortList source_port_list = 16; xray.common.net.PortList source_port_list = 16;
@@ -61,8 +119,6 @@ message RoutingRule {
repeated string protocol = 9; repeated string protocol = 9;
string attributes = 15; string attributes = 15;
string domain_matcher = 17;
} }
message BalancingRule { message BalancingRule {

View File

@@ -7,7 +7,6 @@ import (
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
. "github.com/xtls/xray-core/app/router" . "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
@@ -102,7 +101,7 @@ func TestIPOnDemand(t *testing.T) {
TargetTag: &RoutingRule_Tag{ TargetTag: &RoutingRule_Tag{
Tag: "test", Tag: "test",
}, },
Cidr: []*geoip.CIDR{ Cidr: []*CIDR{
{ {
Ip: []byte{192, 168, 0, 0}, Ip: []byte{192, 168, 0, 0},
Prefix: 16, Prefix: 16,
@@ -137,7 +136,7 @@ func TestIPIfNonMatchDomain(t *testing.T) {
TargetTag: &RoutingRule_Tag{ TargetTag: &RoutingRule_Tag{
Tag: "test", Tag: "test",
}, },
Cidr: []*geoip.CIDR{ Cidr: []*CIDR{
{ {
Ip: []byte{192, 168, 0, 0}, Ip: []byte{192, 168, 0, 0},
Prefix: 16, Prefix: 16,
@@ -172,7 +171,7 @@ func TestIPIfNonMatchIP(t *testing.T) {
TargetTag: &RoutingRule_Tag{ TargetTag: &RoutingRule_Tag{
Tag: "test", Tag: "test",
}, },
Cidr: []*geoip.CIDR{ Cidr: []*CIDR{
{ {
Ip: []byte{127, 0, 0, 0}, Ip: []byte{127, 0, 0, 0},
Prefix: 8, Prefix: 8,

View File

@@ -11,7 +11,7 @@ import (
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/str" "github.com/xtls/xray-core/common/strmatcher"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
feature_stats "github.com/xtls/xray-core/features/stats" feature_stats "github.com/xtls/xray-core/features/stats"
) )
@@ -49,7 +49,7 @@ func (s *statsServer) GetStats(ctx context.Context, request *GetStatsRequest) (*
} }
func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) { func (s *statsServer) QueryStats(ctx context.Context, request *QueryStatsRequest) (*QueryStatsResponse, error) {
matcher, err := str.Substr.New(request.Pattern) matcher, err := strmatcher.Substr.New(request.Pattern)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,3 +0,0 @@
package conf
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen

View File

@@ -1,94 +0,0 @@
package conf
import (
"strings"
dm "github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geosite"
)
func ParseDomainRule(domain string) ([]*dm.Domain, error) {
if strings.HasPrefix(domain, "geosite:") {
country := strings.ToUpper(domain[8:])
domains, err := geosite.LoadGeositeWithAttr("geosite.dat", country)
if err != nil {
return nil, newError("failed to load geosite: ", country).Base(err)
}
return domains, nil
}
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(domain, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-domain:"
if strings.HasPrefix(domain, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(domain[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", domain)
}
filename := kv[0]
country := kv[1]
domains, err := geosite.LoadGeositeWithAttr(filename, country)
if err != nil {
return nil, newError("failed to load external sites: ", country, " from ", filename).Base(err)
}
return domains, nil
}
domainRule := new(dm.Domain)
switch {
case strings.HasPrefix(domain, "regexp:"):
regexpVal := domain[7:]
if len(regexpVal) == 0 {
return nil, newError("empty regexp type of rule: ", domain)
}
domainRule.Type = dm.MatchingType_Regex
domainRule.Value = regexpVal
case strings.HasPrefix(domain, "domain:"):
domainName := domain[7:]
if len(domainName) == 0 {
return nil, newError("empty domain type of rule: ", domain)
}
domainRule.Type = dm.MatchingType_Subdomain
domainRule.Value = domainName
case strings.HasPrefix(domain, "full:"):
fullVal := domain[5:]
if len(fullVal) == 0 {
return nil, newError("empty full domain type of rule: ", domain)
}
domainRule.Type = dm.MatchingType_Full
domainRule.Value = fullVal
case strings.HasPrefix(domain, "keyword:"):
keywordVal := domain[8:]
if len(keywordVal) == 0 {
return nil, newError("empty keyword type of rule: ", domain)
}
domainRule.Type = dm.MatchingType_Keyword
domainRule.Value = keywordVal
case strings.HasPrefix(domain, "dotless:"):
domainRule.Type = dm.MatchingType_Regex
switch substr := domain[8:]; {
case substr == "":
domainRule.Value = "^[^.]*$"
case !strings.Contains(substr, "."):
domainRule.Value = "^[^.]*" + substr + "[^.]*$"
default:
return nil, newError("substr in dotless rule should not contain a dot: ", substr)
}
default:
domainRule.Type = dm.MatchingType_Keyword
domainRule.Value = domain
}
return []*dm.Domain{domainRule}, nil
}

View File

@@ -1,9 +0,0 @@
package conf
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,3 +0,0 @@
package domain
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen

View File

@@ -1,229 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.15.6
// source: common/matcher/domain/domain.proto
package domain
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type MatchingType int32
const (
MatchingType_Full MatchingType = 0
MatchingType_Subdomain MatchingType = 1
MatchingType_Keyword MatchingType = 2
MatchingType_Regex MatchingType = 3
)
// Enum value maps for MatchingType.
var (
MatchingType_name = map[int32]string{
0: "Full",
1: "Subdomain",
2: "Keyword",
3: "Regex",
}
MatchingType_value = map[string]int32{
"Full": 0,
"Subdomain": 1,
"Keyword": 2,
"Regex": 3,
}
)
func (x MatchingType) Enum() *MatchingType {
p := new(MatchingType)
*p = x
return p
}
func (x MatchingType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (MatchingType) Descriptor() protoreflect.EnumDescriptor {
return file_common_matcher_domain_domain_proto_enumTypes[0].Descriptor()
}
func (MatchingType) Type() protoreflect.EnumType {
return &file_common_matcher_domain_domain_proto_enumTypes[0]
}
func (x MatchingType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use MatchingType.Descriptor instead.
func (MatchingType) EnumDescriptor() ([]byte, []int) {
return file_common_matcher_domain_domain_proto_rawDescGZIP(), []int{0}
}
type Domain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Domain matching type.
Type MatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=xray.common.matcher.domain.MatchingType" json:"type,omitempty"`
// Domain value.
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *Domain) Reset() {
*x = Domain{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_domain_domain_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Domain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Domain) ProtoMessage() {}
func (x *Domain) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_domain_domain_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Domain.ProtoReflect.Descriptor instead.
func (*Domain) Descriptor() ([]byte, []int) {
return file_common_matcher_domain_domain_proto_rawDescGZIP(), []int{0}
}
func (x *Domain) GetType() MatchingType {
if x != nil {
return x.Type
}
return MatchingType_Full
}
func (x *Domain) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
var File_common_matcher_domain_domain_proto protoreflect.FileDescriptor
var file_common_matcher_domain_domain_proto_rawDesc = []byte{
0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x22, 0x5c, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3c, 0x0a, 0x04, 0x74, 0x79,
0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79,
0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x3f,
0x0a, 0x0c, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08,
0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f,
0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x42,
0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x50, 0x01, 0x5a, 0x2f, 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, 0x64, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0xaa, 0x02, 0x1a, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_matcher_domain_domain_proto_rawDescOnce sync.Once
file_common_matcher_domain_domain_proto_rawDescData = file_common_matcher_domain_domain_proto_rawDesc
)
func file_common_matcher_domain_domain_proto_rawDescGZIP() []byte {
file_common_matcher_domain_domain_proto_rawDescOnce.Do(func() {
file_common_matcher_domain_domain_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_matcher_domain_domain_proto_rawDescData)
})
return file_common_matcher_domain_domain_proto_rawDescData
}
var file_common_matcher_domain_domain_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_common_matcher_domain_domain_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_matcher_domain_domain_proto_goTypes = []interface{}{
(MatchingType)(0), // 0: xray.common.matcher.domain.MatchingType
(*Domain)(nil), // 1: xray.common.matcher.domain.Domain
}
var file_common_matcher_domain_domain_proto_depIdxs = []int32{
0, // 0: xray.common.matcher.domain.Domain.type:type_name -> xray.common.matcher.domain.MatchingType
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_common_matcher_domain_domain_proto_init() }
func file_common_matcher_domain_domain_proto_init() {
if File_common_matcher_domain_domain_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_matcher_domain_domain_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Domain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_matcher_domain_domain_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_matcher_domain_domain_proto_goTypes,
DependencyIndexes: file_common_matcher_domain_domain_proto_depIdxs,
EnumInfos: file_common_matcher_domain_domain_proto_enumTypes,
MessageInfos: file_common_matcher_domain_domain_proto_msgTypes,
}.Build()
File_common_matcher_domain_domain_proto = out.File
file_common_matcher_domain_domain_proto_rawDesc = nil
file_common_matcher_domain_domain_proto_goTypes = nil
file_common_matcher_domain_domain_proto_depIdxs = nil
}

View File

@@ -1,39 +0,0 @@
syntax = "proto3";
package xray.common.matcher.domain;
option csharp_namespace = "Xray.Common.Matcher.Domain";
option go_package = "github.com/xtls/xray-core/common/matcher/domain";
option java_package = "com.xray.common.matcher.domain";
option java_multiple_files = true;
enum MatchingType {
Full = 0;
Subdomain = 1;
Keyword = 2;
Regex = 3;
}
message Domain {
// Domain matching type.
MatchingType type = 1;
// Domain value.
string value = 2;
}
/*
func toDomainMatchingType(t router.Domain_Type) dns.DomainMatchingType {
switch t {
case router.Domain_Domain:
return dns.DomainMatchingType_Subdomain
case router.Domain_Full:
return dns.DomainMatchingType_Full
case router.Domain_Plain:
return dns.DomainMatchingType_Keyword
case router.Domain_Regex:
return dns.DomainMatchingType_Regex
default:
panic("unknown domain type")
}
}
*/

View File

@@ -1,9 +0,0 @@
package domain
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,79 +0,0 @@
package domain
import (
"strings"
"github.com/xtls/xray-core/common/matcher/str"
"github.com/xtls/xray-core/features/routing"
)
var matcherTypeMap = map[MatchingType]str.Type{
MatchingType_Keyword: str.Substr,
MatchingType_Regex: str.Regex,
MatchingType_Subdomain: str.Domain,
MatchingType_Full: str.Full,
}
func domainToMatcher(domain *Domain) (str.Matcher, error) {
matcherType, f := matcherTypeMap[domain.Type]
if !f {
return nil, newError("unsupported domain type", domain.Type)
}
matcher, err := matcherType.New(domain.Value)
if err != nil {
return nil, newError("failed to create domain matcher").Base(err)
}
return matcher, nil
}
type DomainMatcher struct {
matchers str.IndexMatcher
}
func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
g := str.NewMphMatcherGroup()
for _, d := range domains {
matcherType, f := matcherTypeMap[d.Type]
if !f {
return nil, newError("unsupported domain type", d.Type)
}
_, err := g.AddPattern(d.Value, matcherType)
if err != nil {
return nil, err
}
}
g.Build()
return &DomainMatcher{
matchers: g,
}, nil
}
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
g := new(str.MatcherGroup)
for _, d := range domains {
m, err := domainToMatcher(d)
if err != nil {
return nil, err
}
g.Add(m)
}
return &DomainMatcher{
matchers: g,
}, nil
}
func (m *DomainMatcher) ApplyDomain(domain string) bool {
return len(m.matchers.Match(strings.ToLower(domain))) > 0
}
// Apply implements Condition.
func (m *DomainMatcher) Apply(ctx routing.Context) bool {
domain := ctx.GetTargetDomain()
if len(domain) == 0 {
return false
}
return m.ApplyDomain(domain)
}

View File

@@ -1,224 +0,0 @@
package geoip
import (
"runtime"
"strconv"
"strings"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform/filesystem"
)
var (
FileCache = make(map[string][]byte)
IPCache = make(map[string]*GeoIP)
)
func LoadGeoIP(code string) ([]*CIDR, error) {
return LoadIPFile("geoip.dat", code)
}
func LoadIPFile(file, code string) ([]*CIDR, error) {
index := file + ":" + code
if IPCache[index] == nil {
bs, err := loadFile(file)
if err != nil {
return nil, newError("failed to load file: ", file).Base(err)
}
bs = find(bs, []byte(code))
if bs == nil {
return nil, newError("code not found in ", file, ": ", code)
}
var geoipdat GeoIP
if err := proto.Unmarshal(bs, &geoipdat); err != nil {
return nil, newError("error unmarshal IP in ", file, ": ", code).Base(err)
}
defer runtime.GC() // or debug.FreeOSMemory()
return geoipdat.Cidr, nil // do not cache geoip
// IPCache[index] = &geoipdat
}
return IPCache[index].Cidr, nil
}
func loadFile(file string) ([]byte, error) {
if FileCache[file] == nil {
bs, err := filesystem.ReadAsset(file)
if err != nil {
return nil, newError("failed to open file: ", file).Base(err)
}
if len(bs) == 0 {
return nil, newError("empty file: ", file)
}
// Do not cache file, may save RAM when there
// are many files, but consume CPU each time.
return bs, nil
// FileCache[file] = bs
}
return FileCache[file], nil
}
func find(data, code []byte) []byte {
codeL := len(code)
if codeL == 0 {
return nil
}
for {
dataL := len(data)
if dataL < 2 {
return nil
}
x, y := proto.DecodeVarint(data[1:])
if x == 0 && y == 0 {
return nil
}
headL, bodyL := 1+y, int(x)
dataL -= headL
if dataL < bodyL {
return nil
}
data = data[headL:]
if int(data[1]) == codeL {
for i := 0; i < codeL && data[2+i] == code[i]; i++ {
if i+1 == codeL {
return data[:bodyL]
}
}
}
if dataL == bodyL {
return nil
}
data = data[bodyL:]
}
}
func ParseIPList(ips []string) ([]*GeoIP, error) {
var geoipList []*GeoIP
var customCidrs []*CIDR
for _, ip := range ips {
if strings.HasPrefix(ip, "geoip:") {
country := ip[6:]
isReverseMatch := false
if strings.HasPrefix(country, "!") {
country = country[1:]
isReverseMatch = true
}
geoipc, err := LoadGeoIP(strings.ToUpper(country))
if err != nil {
return nil, newError("failed to load GeoIP: ", country).Base(err)
}
geoipList = append(geoipList, &GeoIP{
CountryCode: strings.ToUpper(country),
Cidr: geoipc,
ReverseMatch: isReverseMatch,
})
continue
}
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(ip, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-ip:"
if strings.HasPrefix(ip, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(ip[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", ip)
}
filename := kv[0]
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))
if err != nil {
return nil, newError("failed to load IPs: ", country, " from ", filename).Base(err)
}
geoipList = append(geoipList, &GeoIP{
CountryCode: strings.ToUpper(filename + "_" + country),
Cidr: geoipc,
ReverseMatch: isReverseMatch,
})
continue
}
ipRule, err := ParseIP(ip)
if err != nil {
return nil, newError("invalid IP: ", ip).Base(err)
}
customCidrs = append(customCidrs, ipRule)
}
if len(customCidrs) > 0 {
geoipList = append(geoipList, &GeoIP{
Cidr: customCidrs,
})
}
return geoipList, nil
}
func ParseIP(s string) (*CIDR, error) {
var addr, mask string
i := strings.Index(s, "/")
if i < 0 {
addr = s
} else {
addr = s[:i]
mask = s[i+1:]
}
ip := net.ParseAddress(addr)
switch ip.Family() {
case net.AddressFamilyIPv4:
bits := uint32(32)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 32 {
return nil, newError("invalid network mask for router: ", bits)
}
return &CIDR{
Ip: ip.IP(),
Prefix: bits,
}, nil
case net.AddressFamilyIPv6:
bits := uint32(128)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 128 {
return nil, newError("invalid network mask for router: ", bits)
}
return &CIDR{
Ip: ip.IP(),
Prefix: bits,
}, nil
default:
return nil, newError("unsupported address for router: ", s)
}
}

View File

@@ -1,40 +0,0 @@
package geoip
// CIDRList is an alias of []*CIDR to provide sort.Interface.
type CIDRList []*CIDR
// Len implements sort.Interface.
func (l *CIDRList) Len() int {
return len(*l)
}
// Less implements sort.Interface.
func (l *CIDRList) Less(i int, j int) bool {
ci := (*l)[i]
cj := (*l)[j]
if len(ci.Ip) < len(cj.Ip) {
return true
}
if len(ci.Ip) > len(cj.Ip) {
return false
}
for k := 0; k < len(ci.Ip); k++ {
if ci.Ip[k] < cj.Ip[k] {
return true
}
if ci.Ip[k] > cj.Ip[k] {
return false
}
}
return ci.Prefix < cj.Prefix
}
// Swap implements sort.Interface.
func (l *CIDRList) Swap(i int, j int) {
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
}

View File

@@ -1,9 +0,0 @@
package geoip
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,317 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.15.7
// source: common/matcher/geoip/geoip.proto
package geoip
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// IP for routing decision, in CIDR form.
type CIDR struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// IP address, should be either 4 or 16 bytes.
Ip []byte `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"`
// Number of leading ones in the network mask.
Prefix uint32 `protobuf:"varint,2,opt,name=prefix,proto3" json:"prefix,omitempty"`
}
func (x *CIDR) Reset() {
*x = CIDR{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_geoip_geoip_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CIDR) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CIDR) ProtoMessage() {}
func (x *CIDR) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_geoip_geoip_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CIDR.ProtoReflect.Descriptor instead.
func (*CIDR) Descriptor() ([]byte, []int) {
return file_common_matcher_geoip_geoip_proto_rawDescGZIP(), []int{0}
}
func (x *CIDR) GetIp() []byte {
if x != nil {
return x.Ip
}
return nil
}
func (x *CIDR) GetPrefix() uint32 {
if x != nil {
return x.Prefix
}
return 0
}
type GeoIP struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
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"`
ReverseMatch bool `protobuf:"varint,3,opt,name=reverse_match,json=reverseMatch,proto3" json:"reverse_match,omitempty"`
}
func (x *GeoIP) Reset() {
*x = GeoIP{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_geoip_geoip_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoIP) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoIP) ProtoMessage() {}
func (x *GeoIP) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_geoip_geoip_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoIP.ProtoReflect.Descriptor instead.
func (*GeoIP) Descriptor() ([]byte, []int) {
return file_common_matcher_geoip_geoip_proto_rawDescGZIP(), []int{1}
}
func (x *GeoIP) GetCountryCode() string {
if x != nil {
return x.CountryCode
}
return ""
}
func (x *GeoIP) GetCidr() []*CIDR {
if x != nil {
return x.Cidr
}
return nil
}
func (x *GeoIP) GetReverseMatch() bool {
if x != nil {
return x.ReverseMatch
}
return false
}
type GeoIPList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Entry []*GeoIP `protobuf:"bytes,1,rep,name=entry,proto3" json:"entry,omitempty"`
}
func (x *GeoIPList) Reset() {
*x = GeoIPList{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_geoip_geoip_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoIPList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoIPList) ProtoMessage() {}
func (x *GeoIPList) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_geoip_geoip_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoIPList.ProtoReflect.Descriptor instead.
func (*GeoIPList) Descriptor() ([]byte, []int) {
return file_common_matcher_geoip_geoip_proto_rawDescGZIP(), []int{2}
}
func (x *GeoIPList) GetEntry() []*GeoIP {
if x != nil {
return x.Entry
}
return nil
}
var File_common_matcher_geoip_geoip_proto protoreflect.FileDescriptor
var file_common_matcher_geoip_geoip_proto_rawDesc = []byte{
0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x19, 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, 0x22, 0x2e, 0x0a,
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,
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x84, 0x01,
0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x63, 0x69,
0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 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, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12,
0x23, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68,
0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x4d,
0x61, 0x74, 0x63, 0x68, 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, 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 (
file_common_matcher_geoip_geoip_proto_rawDescOnce sync.Once
file_common_matcher_geoip_geoip_proto_rawDescData = file_common_matcher_geoip_geoip_proto_rawDesc
)
func file_common_matcher_geoip_geoip_proto_rawDescGZIP() []byte {
file_common_matcher_geoip_geoip_proto_rawDescOnce.Do(func() {
file_common_matcher_geoip_geoip_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_matcher_geoip_geoip_proto_rawDescData)
})
return file_common_matcher_geoip_geoip_proto_rawDescData
}
var file_common_matcher_geoip_geoip_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_common_matcher_geoip_geoip_proto_goTypes = []interface{}{
(*CIDR)(nil), // 0: xray.common.matcher.geoip.CIDR
(*GeoIP)(nil), // 1: xray.common.matcher.geoip.GeoIP
(*GeoIPList)(nil), // 2: xray.common.matcher.geoip.GeoIPList
}
var file_common_matcher_geoip_geoip_proto_depIdxs = []int32{
0, // 0: xray.common.matcher.geoip.GeoIP.cidr:type_name -> xray.common.matcher.geoip.CIDR
1, // 1: xray.common.matcher.geoip.GeoIPList.entry:type_name -> xray.common.matcher.geoip.GeoIP
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_common_matcher_geoip_geoip_proto_init() }
func file_common_matcher_geoip_geoip_proto_init() {
if File_common_matcher_geoip_geoip_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_matcher_geoip_geoip_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CIDR); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_matcher_geoip_geoip_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoIP); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_matcher_geoip_geoip_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoIPList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_matcher_geoip_geoip_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_matcher_geoip_geoip_proto_goTypes,
DependencyIndexes: file_common_matcher_geoip_geoip_proto_depIdxs,
MessageInfos: file_common_matcher_geoip_geoip_proto_msgTypes,
}.Build()
File_common_matcher_geoip_geoip_proto = out.File
file_common_matcher_geoip_geoip_proto_rawDesc = nil
file_common_matcher_geoip_geoip_proto_goTypes = nil
file_common_matcher_geoip_geoip_proto_depIdxs = nil
}

View File

@@ -1,26 +0,0 @@
syntax = "proto3";
package xray.common.matcher.geoip;
option csharp_namespace = "Xray.Common.Matcher.GeoIP";
option go_package = "github.com/xtls/xray-core/common/matcher/geoip";
option java_package = "com.xray.common.matcher.geoip";
option java_multiple_files = true;
// IP for routing decision, in CIDR form.
message CIDR {
// IP address, should be either 4 or 16 bytes.
bytes ip = 1;
// Number of leading ones in the network mask.
uint32 prefix = 2;
}
message GeoIP {
string country_code = 1;
repeated CIDR cidr = 2;
bool reverse_match =3;
}
message GeoIPList {
repeated GeoIP entry = 1;
}

View File

@@ -1,57 +0,0 @@
package geoip
import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/routing"
)
type MultiGeoIPMatcher struct {
matchers []*GeoIPMatcher
onSource bool
}
func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
var matchers []*GeoIPMatcher
for _, geoip := range geoips {
matcher, err := GlobalGeoIPContainer.Add(geoip)
if err != nil {
return nil, err
}
matchers = append(matchers, matcher)
}
matcher := &MultiGeoIPMatcher{
matchers: matchers,
onSource: onSource,
}
return matcher, nil
}
// Apply implements Condition.
func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
var ips []net.IP
if m.onSource {
ips = ctx.GetSourceIPs()
} else {
ips = ctx.GetTargetIPs()
}
for _, ip := range ips {
for _, matcher := range m.matchers {
if matcher.Match(ip) {
return true
}
}
}
return false
}
// MatchIP match given ip.
func (m *MultiGeoIPMatcher) MatchIP(ip net.IP) bool {
for _, matcher := range m.matchers {
if matcher.Match(ip) {
return true
}
}
return false
}

View File

@@ -1,35 +0,0 @@
package geosite
import "strings"
type AttributeList struct {
matcher []AttributeMatcher
}
func (al *AttributeList) Match(domain *Domain) bool {
for _, matcher := range al.matcher {
if !matcher.Match(domain) {
return false
}
}
return true
}
func (al *AttributeList) IsEmpty() bool {
return len(al.matcher) == 0
}
type AttributeMatcher interface {
Match(*Domain) bool
}
type BooleanMatcher string
func (m BooleanMatcher) Match(domain *Domain) bool {
for _, attr := range domain.Attribute {
if strings.EqualFold(attr.GetKey(), string(m)) {
return true
}
}
return false
}

View File

@@ -1,42 +0,0 @@
package geosite
import (
"strings"
dm "github.com/xtls/xray-core/common/matcher/domain"
)
func LoadGeositeWithAttr(file string, siteWithAttr string) ([]*dm.Domain, error) {
parts := strings.Split(siteWithAttr, "@")
if len(parts) == 0 {
return nil, newError("empty site")
}
country := strings.ToUpper(parts[0])
attrs := parseAttrs(parts[1:])
domains, err := loadSite(file, country)
if err != nil {
return nil, err
}
if attrs.IsEmpty() {
return ToDomains(domains), nil
}
filteredDomains := make([]*dm.Domain, 0, len(domains))
for _, domain := range domains {
if attrs.Match(domain) {
filteredDomains = append(filteredDomains, domain.ToDomain())
}
}
return filteredDomains, nil
}
func parseAttrs(attrs []string) *AttributeList {
al := new(AttributeList)
for _, attr := range attrs {
lc := strings.ToLower(attr)
al.matcher = append(al.matcher, BooleanMatcher(lc))
}
return al
}

View File

@@ -1,9 +0,0 @@
package geosite
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -1,86 +0,0 @@
package geosite
import (
"runtime"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common/platform/filesystem"
)
var (
SiteCache = make(map[string]*GeoSite)
FileCache = make(map[string][]byte)
)
func loadFile(file string) ([]byte, error) {
if FileCache[file] == nil {
bs, err := filesystem.ReadAsset(file)
if err != nil {
return nil, newError("failed to open file: ", file).Base(err)
}
if len(bs) == 0 {
return nil, newError("empty file: ", file)
}
// Do not cache file, may save RAM when there
// are many files, but consume CPU each time.
return bs, nil
FileCache[file] = bs
}
return FileCache[file], nil
}
func loadSite(file, code string) ([]*Domain, error) {
index := file + ":" + code
if SiteCache[index] == nil {
bs, err := loadFile(file)
if err != nil {
return nil, newError("failed to load file: ", file).Base(err)
}
bs = find(bs, []byte(code))
if bs == nil {
return nil, newError("list not found in ", file, ": ", code)
}
var ges GeoSite
if err := proto.Unmarshal(bs, &ges); err != nil {
return nil, newError("error unmarshal Site in ", file, ": ", code).Base(err)
}
defer runtime.GC() // or debug.FreeOSMemory()
return ges.Domain, nil // do not cache geosite
SiteCache[index] = &ges
}
return SiteCache[index].Domain, nil
}
func find(data, code []byte) []byte {
codeL := len(code)
if codeL == 0 {
return nil
}
for {
dataL := len(data)
if dataL < 2 {
return nil
}
x, y := proto.DecodeVarint(data[1:])
if x == 0 && y == 0 {
return nil
}
headL, bodyL := 1+y, int(x)
dataL -= headL
if dataL < bodyL {
return nil
}
data = data[headL:]
if int(data[1]) == codeL {
for i := 0; i < codeL && data[2+i] == code[i]; i++ {
if i+1 == codeL {
return data[:bodyL]
}
}
}
if dataL == bodyL {
return nil
}
data = data[bodyL:]
}
}

View File

@@ -1,33 +0,0 @@
package geosite
import "github.com/xtls/xray-core/common/matcher/domain"
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
func ToDomains(dms []*Domain) []*domain.Domain {
dm := make([]*domain.Domain, len(dms))
for idx, entry := range dms {
dm[idx] = entry.ToDomain()
}
return dm
}
func (d *Domain) ToDomain() *domain.Domain {
return &domain.Domain{Type: d.Type.ToMatchingType(), Value: d.Value}
}
func (t Domain_Type) ToMatchingType() domain.MatchingType {
switch t {
case Domain_Plain:
return domain.MatchingType_Keyword
case Domain_Regex:
return domain.MatchingType_Regex
case Domain_Domain:
return domain.MatchingType_Subdomain
case Domain_Full:
return domain.MatchingType_Full
}
panic("impossible")
}

View File

@@ -1,501 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.15.6
// source: common/matcher/geosite/geosite.proto
package geosite
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Domain_Type int32
const (
// The value is used as is.
Domain_Plain Domain_Type = 0
// The value is used as a regular expression.
Domain_Regex Domain_Type = 1
// The value is a root domain.
Domain_Domain Domain_Type = 2
// The value is a domain.
Domain_Full Domain_Type = 3
)
// Enum value maps for Domain_Type.
var (
Domain_Type_name = map[int32]string{
0: "Plain",
1: "Regex",
2: "Domain",
3: "Full",
}
Domain_Type_value = map[string]int32{
"Plain": 0,
"Regex": 1,
"Domain": 2,
"Full": 3,
}
)
func (x Domain_Type) Enum() *Domain_Type {
p := new(Domain_Type)
*p = x
return p
}
func (x Domain_Type) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Domain_Type) Descriptor() protoreflect.EnumDescriptor {
return file_common_matcher_geosite_geosite_proto_enumTypes[0].Descriptor()
}
func (Domain_Type) Type() protoreflect.EnumType {
return &file_common_matcher_geosite_geosite_proto_enumTypes[0]
}
func (x Domain_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Domain_Type.Descriptor instead.
func (Domain_Type) EnumDescriptor() ([]byte, []int) {
return file_common_matcher_geosite_geosite_proto_rawDescGZIP(), []int{0, 0}
}
type Domain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Domain matching type.
Type Domain_Type `protobuf:"varint,1,opt,name=type,proto3,enum=xray.common.matcher.geosite.Domain_Type" json:"type,omitempty"`
// Domain value.
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
// Attributes of this domain. May be used for filtering.
Attribute []*Domain_Attribute `protobuf:"bytes,3,rep,name=attribute,proto3" json:"attribute,omitempty"`
}
func (x *Domain) Reset() {
*x = Domain{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Domain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Domain) ProtoMessage() {}
func (x *Domain) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Domain.ProtoReflect.Descriptor instead.
func (*Domain) Descriptor() ([]byte, []int) {
return file_common_matcher_geosite_geosite_proto_rawDescGZIP(), []int{0}
}
func (x *Domain) GetType() Domain_Type {
if x != nil {
return x.Type
}
return Domain_Plain
}
func (x *Domain) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
func (x *Domain) GetAttribute() []*Domain_Attribute {
if x != nil {
return x.Attribute
}
return nil
}
type GeoSite struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
}
func (x *GeoSite) Reset() {
*x = GeoSite{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoSite) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoSite) ProtoMessage() {}
func (x *GeoSite) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoSite.ProtoReflect.Descriptor instead.
func (*GeoSite) Descriptor() ([]byte, []int) {
return file_common_matcher_geosite_geosite_proto_rawDescGZIP(), []int{1}
}
func (x *GeoSite) GetCountryCode() string {
if x != nil {
return x.CountryCode
}
return ""
}
func (x *GeoSite) GetDomain() []*Domain {
if x != nil {
return x.Domain
}
return nil
}
type GeoSiteList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Entry []*GeoSite `protobuf:"bytes,1,rep,name=entry,proto3" json:"entry,omitempty"`
}
func (x *GeoSiteList) Reset() {
*x = GeoSiteList{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GeoSiteList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GeoSiteList) ProtoMessage() {}
func (x *GeoSiteList) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GeoSiteList.ProtoReflect.Descriptor instead.
func (*GeoSiteList) Descriptor() ([]byte, []int) {
return file_common_matcher_geosite_geosite_proto_rawDescGZIP(), []int{2}
}
func (x *GeoSiteList) GetEntry() []*GeoSite {
if x != nil {
return x.Entry
}
return nil
}
type Domain_Attribute struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
// Types that are assignable to TypedValue:
// *Domain_Attribute_BoolValue
// *Domain_Attribute_IntValue
TypedValue isDomain_Attribute_TypedValue `protobuf_oneof:"typed_value"`
}
func (x *Domain_Attribute) Reset() {
*x = Domain_Attribute{}
if protoimpl.UnsafeEnabled {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Domain_Attribute) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Domain_Attribute) ProtoMessage() {}
func (x *Domain_Attribute) ProtoReflect() protoreflect.Message {
mi := &file_common_matcher_geosite_geosite_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Domain_Attribute.ProtoReflect.Descriptor instead.
func (*Domain_Attribute) Descriptor() ([]byte, []int) {
return file_common_matcher_geosite_geosite_proto_rawDescGZIP(), []int{0, 0}
}
func (x *Domain_Attribute) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (m *Domain_Attribute) GetTypedValue() isDomain_Attribute_TypedValue {
if m != nil {
return m.TypedValue
}
return nil
}
func (x *Domain_Attribute) GetBoolValue() bool {
if x, ok := x.GetTypedValue().(*Domain_Attribute_BoolValue); ok {
return x.BoolValue
}
return false
}
func (x *Domain_Attribute) GetIntValue() int64 {
if x, ok := x.GetTypedValue().(*Domain_Attribute_IntValue); ok {
return x.IntValue
}
return 0
}
type isDomain_Attribute_TypedValue interface {
isDomain_Attribute_TypedValue()
}
type Domain_Attribute_BoolValue struct {
BoolValue bool `protobuf:"varint,2,opt,name=bool_value,json=boolValue,proto3,oneof"`
}
type Domain_Attribute_IntValue struct {
IntValue int64 `protobuf:"varint,3,opt,name=int_value,json=intValue,proto3,oneof"`
}
func (*Domain_Attribute_BoolValue) isDomain_Attribute_TypedValue() {}
func (*Domain_Attribute_IntValue) isDomain_Attribute_TypedValue() {}
var File_common_matcher_geosite_geosite_proto protoreflect.FileDescriptor
var file_common_matcher_geosite_geosite_proto_rawDesc = []byte{
0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
0x2f, 0x67, 0x65, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x67, 0x65, 0x6f, 0x73, 0x69, 0x74, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x73,
0x69, 0x74, 0x65, 0x22, 0xcb, 0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3c,
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68,
0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x12, 0x4b, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x73,
0x69, 0x74, 0x65, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x1a,
0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1f,
0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12,
0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0d,
0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x32, 0x0a,
0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x10, 0x00,
0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10,
0x03, 0x22, 0x69, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12,
0x3b, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x23, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61,
0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x67, 0x65, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x49, 0x0a, 0x0b,
0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x05, 0x65,
0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
0x2e, 0x67, 0x65, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65,
0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x73, 0x0a, 0x1f, 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, 0x73, 0x69, 0x74, 0x65, 0x50, 0x01, 0x5a, 0x30, 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, 0x73, 0x69, 0x74, 0x65, 0xaa, 0x02,
0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x74,
0x63, 0x68, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_matcher_geosite_geosite_proto_rawDescOnce sync.Once
file_common_matcher_geosite_geosite_proto_rawDescData = file_common_matcher_geosite_geosite_proto_rawDesc
)
func file_common_matcher_geosite_geosite_proto_rawDescGZIP() []byte {
file_common_matcher_geosite_geosite_proto_rawDescOnce.Do(func() {
file_common_matcher_geosite_geosite_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_matcher_geosite_geosite_proto_rawDescData)
})
return file_common_matcher_geosite_geosite_proto_rawDescData
}
var file_common_matcher_geosite_geosite_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_common_matcher_geosite_geosite_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_common_matcher_geosite_geosite_proto_goTypes = []interface{}{
(Domain_Type)(0), // 0: xray.common.matcher.geosite.Domain.Type
(*Domain)(nil), // 1: xray.common.matcher.geosite.Domain
(*GeoSite)(nil), // 2: xray.common.matcher.geosite.GeoSite
(*GeoSiteList)(nil), // 3: xray.common.matcher.geosite.GeoSiteList
(*Domain_Attribute)(nil), // 4: xray.common.matcher.geosite.Domain.Attribute
}
var file_common_matcher_geosite_geosite_proto_depIdxs = []int32{
0, // 0: xray.common.matcher.geosite.Domain.type:type_name -> xray.common.matcher.geosite.Domain.Type
4, // 1: xray.common.matcher.geosite.Domain.attribute:type_name -> xray.common.matcher.geosite.Domain.Attribute
1, // 2: xray.common.matcher.geosite.GeoSite.domain:type_name -> xray.common.matcher.geosite.Domain
2, // 3: xray.common.matcher.geosite.GeoSiteList.entry:type_name -> xray.common.matcher.geosite.GeoSite
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_common_matcher_geosite_geosite_proto_init() }
func file_common_matcher_geosite_geosite_proto_init() {
if File_common_matcher_geosite_geosite_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_matcher_geosite_geosite_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Domain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_matcher_geosite_geosite_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoSite); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_matcher_geosite_geosite_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GeoSiteList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_common_matcher_geosite_geosite_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Domain_Attribute); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_common_matcher_geosite_geosite_proto_msgTypes[3].OneofWrappers = []interface{}{
(*Domain_Attribute_BoolValue)(nil),
(*Domain_Attribute_IntValue)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_matcher_geosite_geosite_proto_rawDesc,
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_matcher_geosite_geosite_proto_goTypes,
DependencyIndexes: file_common_matcher_geosite_geosite_proto_depIdxs,
EnumInfos: file_common_matcher_geosite_geosite_proto_enumTypes,
MessageInfos: file_common_matcher_geosite_geosite_proto_msgTypes,
}.Build()
File_common_matcher_geosite_geosite_proto = out.File
file_common_matcher_geosite_geosite_proto_rawDesc = nil
file_common_matcher_geosite_geosite_proto_goTypes = nil
file_common_matcher_geosite_geosite_proto_depIdxs = nil
}

View File

@@ -1,46 +0,0 @@
syntax = "proto3";
package xray.common.matcher.geosite;
option csharp_namespace = "Xray.Common.Matcher.GeoSite";
option go_package = "github.com/xtls/xray-core/common/matcher/geosite";
option java_package = "com.xray.common.matcher.geosite";
option java_multiple_files = true;
message Domain {
enum Type {
// The value is used as is.
Plain = 0;
// The value is used as a regular expression.
Regex = 1;
// The value is a root domain.
Domain = 2;
// The value is a domain.
Full = 3;
}
// Domain matching type.
Type type = 1;
// Domain value.
string value = 2;
message Attribute {
string key = 1;
oneof typed_value {
bool bool_value = 2;
int64 int_value = 3;
}
}
// Attributes of this domain. May be used for filtering.
repeated Attribute attribute = 3;
}
message GeoSite {
string country_code = 1;
repeated Domain domain = 2;
}
message GeoSiteList {
repeated GeoSite entry = 1;
}

View File

@@ -1,243 +0,0 @@
package str
import (
"container/list"
)
const validCharCount = 53
type MatchType struct {
matchType Type
exist bool
}
const (
TrieEdge bool = true
FailEdge bool = false
)
type Edge struct {
edgeType bool
nextNode int
}
type ACAutomaton struct {
trie [][validCharCount]Edge
fail []int
exists []MatchType
count int
}
func newNode() [validCharCount]Edge {
var s [validCharCount]Edge
for i := range s {
s[i] = Edge{
edgeType: FailEdge,
nextNode: 0,
}
}
return s
}
var char2Index = []int{
'A': 0,
'a': 0,
'B': 1,
'b': 1,
'C': 2,
'c': 2,
'D': 3,
'd': 3,
'E': 4,
'e': 4,
'F': 5,
'f': 5,
'G': 6,
'g': 6,
'H': 7,
'h': 7,
'I': 8,
'i': 8,
'J': 9,
'j': 9,
'K': 10,
'k': 10,
'L': 11,
'l': 11,
'M': 12,
'm': 12,
'N': 13,
'n': 13,
'O': 14,
'o': 14,
'P': 15,
'p': 15,
'Q': 16,
'q': 16,
'R': 17,
'r': 17,
'S': 18,
's': 18,
'T': 19,
't': 19,
'U': 20,
'u': 20,
'V': 21,
'v': 21,
'W': 22,
'w': 22,
'X': 23,
'x': 23,
'Y': 24,
'y': 24,
'Z': 25,
'z': 25,
'!': 26,
'$': 27,
'&': 28,
'\'': 29,
'(': 30,
')': 31,
'*': 32,
'+': 33,
',': 34,
';': 35,
'=': 36,
':': 37,
'%': 38,
'-': 39,
'.': 40,
'_': 41,
'~': 42,
'0': 43,
'1': 44,
'2': 45,
'3': 46,
'4': 47,
'5': 48,
'6': 49,
'7': 50,
'8': 51,
'9': 52,
}
func NewACAutomaton() *ACAutomaton {
var ac = new(ACAutomaton)
ac.trie = append(ac.trie, newNode())
ac.fail = append(ac.fail, 0)
ac.exists = append(ac.exists, MatchType{
matchType: Full,
exist: false,
})
return ac
}
func (ac *ACAutomaton) Add(domain string, t Type) {
var node = 0
for i := len(domain) - 1; i >= 0; i-- {
var idx = char2Index[domain[i]]
if ac.trie[node][idx].nextNode == 0 {
ac.count++
if len(ac.trie) < ac.count+1 {
ac.trie = append(ac.trie, newNode())
ac.fail = append(ac.fail, 0)
ac.exists = append(ac.exists, MatchType{
matchType: Full,
exist: false,
})
}
ac.trie[node][idx] = Edge{
edgeType: TrieEdge,
nextNode: ac.count,
}
}
node = ac.trie[node][idx].nextNode
}
ac.exists[node] = MatchType{
matchType: t,
exist: true,
}
switch t {
case Domain:
ac.exists[node] = MatchType{
matchType: Full,
exist: true,
}
var idx = char2Index['.']
if ac.trie[node][idx].nextNode == 0 {
ac.count++
if len(ac.trie) < ac.count+1 {
ac.trie = append(ac.trie, newNode())
ac.fail = append(ac.fail, 0)
ac.exists = append(ac.exists, MatchType{
matchType: Full,
exist: false,
})
}
ac.trie[node][idx] = Edge{
edgeType: TrieEdge,
nextNode: ac.count,
}
}
node = ac.trie[node][idx].nextNode
ac.exists[node] = MatchType{
matchType: t,
exist: true,
}
default:
break
}
}
func (ac *ACAutomaton) Build() {
var queue = list.New()
for i := 0; i < validCharCount; i++ {
if ac.trie[0][i].nextNode != 0 {
queue.PushBack(ac.trie[0][i])
}
}
for {
var front = queue.Front()
if front == nil {
break
} else {
var node = front.Value.(Edge).nextNode
queue.Remove(front)
for i := 0; i < validCharCount; i++ {
if ac.trie[node][i].nextNode != 0 {
ac.fail[ac.trie[node][i].nextNode] = ac.trie[ac.fail[node]][i].nextNode
queue.PushBack(ac.trie[node][i])
} else {
ac.trie[node][i] = Edge{
edgeType: FailEdge,
nextNode: ac.trie[ac.fail[node]][i].nextNode,
}
}
}
}
}
}
func (ac *ACAutomaton) Match(s string) bool {
var node = 0
var fullMatch = true
// 1. the match string is all through trie edge. FULL MATCH or DOMAIN
// 2. the match string is through a fail edge. NOT FULL MATCH
// 2.1 Through a fail edge, but there exists a valid node. SUBSTR
for i := len(s) - 1; i >= 0; i-- {
var idx = char2Index[s[i]]
fullMatch = fullMatch && ac.trie[node][idx].edgeType
node = ac.trie[node][idx].nextNode
switch ac.exists[node].matchType {
case Substr:
return true
case Domain:
if fullMatch {
return true
}
default:
break
}
}
return fullMatch && ac.exists[node].exist
}

View File

@@ -1,301 +0,0 @@
package str
import (
"math/bits"
"regexp"
"sort"
"strings"
"unsafe"
)
// PrimeRK is the prime base used in Rabin-Karp algorithm.
const PrimeRK = 16777619
// calculate the rolling murmurHash of given string
func RollingHash(s string) uint32 {
h := uint32(0)
for i := len(s) - 1; i >= 0; i-- {
h = h*PrimeRK + uint32(s[i])
}
return h
}
// A MphMatcherGroup is divided into three parts:
// 1. `full` and `domain` patterns are matched by Rabin-Karp algorithm and minimal perfect hash table;
// 2. `substr` patterns are matched by ac automaton;
// 3. `regex` patterns are matched with the regex library.
type MphMatcherGroup struct {
ac *ACAutomaton
otherMatchers []matcherEntry
rules []string
level0 []uint32
level0Mask int
level1 []uint32
level1Mask int
count uint32
ruleMap *map[string]uint32
}
func (g *MphMatcherGroup) AddFullOrDomainPattern(pattern string, t Type) {
h := RollingHash(pattern)
switch t {
case Domain:
(*g.ruleMap)["."+pattern] = h*PrimeRK + uint32('.')
fallthrough
case Full:
(*g.ruleMap)[pattern] = h
default:
}
}
func NewMphMatcherGroup() *MphMatcherGroup {
return &MphMatcherGroup{
ac: nil,
otherMatchers: nil,
rules: nil,
level0: nil,
level0Mask: 0,
level1: nil,
level1Mask: 0,
count: 1,
ruleMap: &map[string]uint32{},
}
}
// AddPattern adds a pattern to MphMatcherGroup
func (g *MphMatcherGroup) AddPattern(pattern string, t Type) (uint32, error) {
switch t {
case Substr:
if g.ac == nil {
g.ac = NewACAutomaton()
}
g.ac.Add(pattern, t)
case Full, Domain:
pattern = strings.ToLower(pattern)
g.AddFullOrDomainPattern(pattern, t)
case Regex:
r, err := regexp.Compile(pattern)
if err != nil {
return 0, err
}
g.otherMatchers = append(g.otherMatchers, matcherEntry{
m: &regexMatcher{pattern: r},
id: g.count,
})
default:
panic("Unknown type")
}
return g.count, nil
}
// Build builds a minimal perfect hash table and ac automaton from insert rules
func (g *MphMatcherGroup) Build() {
if g.ac != nil {
g.ac.Build()
}
keyLen := len(*g.ruleMap)
if keyLen == 0 {
keyLen = 1
(*g.ruleMap)["empty___"] = RollingHash("empty___")
}
g.level0 = make([]uint32, nextPow2(keyLen/4))
g.level0Mask = len(g.level0) - 1
g.level1 = make([]uint32, nextPow2(keyLen))
g.level1Mask = len(g.level1) - 1
var sparseBuckets = make([][]int, len(g.level0))
var ruleIdx int
for rule, hash := range *g.ruleMap {
n := int(hash) & g.level0Mask
g.rules = append(g.rules, rule)
sparseBuckets[n] = append(sparseBuckets[n], ruleIdx)
ruleIdx++
}
g.ruleMap = nil
var buckets []indexBucket
for n, vals := range sparseBuckets {
if len(vals) > 0 {
buckets = append(buckets, indexBucket{n, vals})
}
}
sort.Sort(bySize(buckets))
occ := make([]bool, len(g.level1))
var tmpOcc []int
for _, bucket := range buckets {
var seed = uint32(0)
for {
findSeed := true
tmpOcc = tmpOcc[:0]
for _, i := range bucket.vals {
n := int(strhashFallback(unsafe.Pointer(&g.rules[i]), uintptr(seed))) & g.level1Mask
if occ[n] {
for _, n := range tmpOcc {
occ[n] = false
}
seed++
findSeed = false
break
}
occ[n] = true
tmpOcc = append(tmpOcc, n)
g.level1[n] = uint32(i)
}
if findSeed {
g.level0[bucket.n] = seed
break
}
}
}
}
func nextPow2(v int) int {
if v <= 1 {
return 1
}
const MaxUInt = ^uint(0)
n := (MaxUInt >> bits.LeadingZeros(uint(v))) + 1
return int(n)
}
// Lookup searches for s in t and returns its index and whether it was found.
func (g *MphMatcherGroup) Lookup(h uint32, s string) bool {
i0 := int(h) & g.level0Mask
seed := g.level0[i0]
i1 := int(strhashFallback(unsafe.Pointer(&s), uintptr(seed))) & g.level1Mask
n := g.level1[i1]
return s == g.rules[int(n)]
}
// Match implements IndexMatcher.Match.
func (g *MphMatcherGroup) Match(pattern string) []uint32 {
result := []uint32{}
hash := uint32(0)
for i := len(pattern) - 1; i >= 0; i-- {
hash = hash*PrimeRK + uint32(pattern[i])
if pattern[i] == '.' {
if g.Lookup(hash, pattern[i:]) {
result = append(result, 1)
return result
}
}
}
if g.Lookup(hash, pattern) {
result = append(result, 1)
return result
}
if g.ac != nil && g.ac.Match(pattern) {
result = append(result, 1)
return result
}
for _, e := range g.otherMatchers {
if e.m.Match(pattern) {
result = append(result, e.id)
return result
}
}
return nil
}
type indexBucket struct {
n int
vals []int
}
type bySize []indexBucket
func (s bySize) Len() int { return len(s) }
func (s bySize) Less(i, j int) bool { return len(s[i].vals) > len(s[j].vals) }
func (s bySize) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type stringStruct struct {
str unsafe.Pointer
len int
}
func strhashFallback(a unsafe.Pointer, h uintptr) uintptr {
x := (*stringStruct)(a)
return memhashFallback(x.str, h, uintptr(x.len))
}
const (
// Constants for multiplication: four random odd 64-bit numbers.
m1 = 16877499708836156737
m2 = 2820277070424839065
m3 = 9497967016996688599
m4 = 15839092249703872147
)
var hashkey = [4]uintptr{1, 1, 1, 1}
func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr {
h := uint64(seed + s*hashkey[0])
tail:
switch {
case s == 0:
case s < 4:
h ^= uint64(*(*byte)(p))
h ^= uint64(*(*byte)(add(p, s>>1))) << 8
h ^= uint64(*(*byte)(add(p, s-1))) << 16
h = rotl31(h*m1) * m2
case s <= 8:
h ^= uint64(readUnaligned32(p))
h ^= uint64(readUnaligned32(add(p, s-4))) << 32
h = rotl31(h*m1) * m2
case s <= 16:
h ^= readUnaligned64(p)
h = rotl31(h*m1) * m2
h ^= readUnaligned64(add(p, s-8))
h = rotl31(h*m1) * m2
case s <= 32:
h ^= readUnaligned64(p)
h = rotl31(h*m1) * m2
h ^= readUnaligned64(add(p, 8))
h = rotl31(h*m1) * m2
h ^= readUnaligned64(add(p, s-16))
h = rotl31(h*m1) * m2
h ^= readUnaligned64(add(p, s-8))
h = rotl31(h*m1) * m2
default:
v1 := h
v2 := uint64(seed * hashkey[1])
v3 := uint64(seed * hashkey[2])
v4 := uint64(seed * hashkey[3])
for s >= 32 {
v1 ^= readUnaligned64(p)
v1 = rotl31(v1*m1) * m2
p = add(p, 8)
v2 ^= readUnaligned64(p)
v2 = rotl31(v2*m2) * m3
p = add(p, 8)
v3 ^= readUnaligned64(p)
v3 = rotl31(v3*m3) * m4
p = add(p, 8)
v4 ^= readUnaligned64(p)
v4 = rotl31(v4*m4) * m1
p = add(p, 8)
s -= 32
}
h = v1 ^ v2 ^ v3 ^ v4
goto tail
}
h ^= h >> 29
h *= m3
h ^= h >> 32
return uintptr(h)
}
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(p) + x)
}
func readUnaligned32(p unsafe.Pointer) uint32 {
q := (*[4]byte)(p)
return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24
}
func rotl31(x uint64) uint64 {
return (x << 31) | (x >> (64 - 31))
}
func readUnaligned64(p unsafe.Pointer) uint64 {
q := (*[8]byte)(p)
return uint64(q[0]) | uint64(q[1])<<8 | uint64(q[2])<<16 | uint64(q[3])<<24 | uint64(q[4])<<32 | uint64(q[5])<<40 | uint64(q[6])<<48 | uint64(q[7])<<56
}

View File

@@ -1,262 +0,0 @@
package str_test
import (
"reflect"
"testing"
"github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/common/matcher/str"
)
func TestMatcherGroup(t *testing.T) {
rules := []struct {
Type Type
Domain string
}{
{
Type: Regex,
Domain: "apis\\.us$",
},
{
Type: Substr,
Domain: "apis",
},
{
Type: Domain,
Domain: "googleapis.com",
},
{
Type: Domain,
Domain: "com",
},
{
Type: Full,
Domain: "www.baidu.com",
},
{
Type: Substr,
Domain: "apis",
},
{
Type: Domain,
Domain: "googleapis.com",
},
{
Type: Full,
Domain: "fonts.googleapis.com",
},
{
Type: Full,
Domain: "www.baidu.com",
},
{
Type: Domain,
Domain: "example.com",
},
}
cases := []struct {
Input string
Output []uint32
}{
{
Input: "www.baidu.com",
Output: []uint32{5, 9, 4},
},
{
Input: "fonts.googleapis.com",
Output: []uint32{8, 3, 7, 4, 2, 6},
},
{
Input: "example.googleapis.com",
Output: []uint32{3, 7, 4, 2, 6},
},
{
Input: "testapis.us",
Output: []uint32{1, 2, 6},
},
{
Input: "example.com",
Output: []uint32{10, 4},
},
}
matcherGroup := &MatcherGroup{}
for _, rule := range rules {
matcher, err := rule.Type.New(rule.Domain)
common.Must(err)
matcherGroup.Add(matcher)
}
for _, test := range cases {
if m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) {
t.Error("unexpected output: ", m, " for test case ", test)
}
}
}
func TestACAutomaton(t *testing.T) {
cases1 := []struct {
pattern string
mType Type
input string
output bool
}{
{
pattern: "xtls.github.io",
mType: Domain,
input: "www.xtls.github.io",
output: true,
},
{
pattern: "xtls.github.io",
mType: Domain,
input: "xtls.github.io",
output: true,
},
{
pattern: "xtls.github.io",
mType: Domain,
input: "www.xtis.github.io",
output: false,
},
{
pattern: "xtls.github.io",
mType: Domain,
input: "tls.github.io",
output: false,
},
{
pattern: "xtls.github.io",
mType: Domain,
input: "xxtls.github.io",
output: false,
},
{
pattern: "xtls.github.io",
mType: Full,
input: "xtls.github.io",
output: true,
},
{
pattern: "xtls.github.io",
mType: Full,
input: "xxtls.github.io",
output: false,
},
}
for _, test := range cases1 {
var ac = NewACAutomaton()
ac.Add(test.pattern, test.mType)
ac.Build()
if m := ac.Match(test.input); m != test.output {
t.Error("unexpected output: ", m, " for test case ", test)
}
}
{
cases2Input := []struct {
pattern string
mType Type
}{
{
pattern: "163.com",
mType: Domain,
},
{
pattern: "m.126.com",
mType: Full,
},
{
pattern: "3.com",
mType: Full,
},
{
pattern: "google.com",
mType: Substr,
},
{
pattern: "vgoogle.com",
mType: Substr,
},
}
var ac = NewACAutomaton()
for _, test := range cases2Input {
ac.Add(test.pattern, test.mType)
}
ac.Build()
cases2Output := []struct {
pattern string
res bool
}{
{
pattern: "126.com",
res: false,
},
{
pattern: "m.163.com",
res: true,
},
{
pattern: "mm163.com",
res: false,
},
{
pattern: "m.126.com",
res: true,
},
{
pattern: "163.com",
res: true,
},
{
pattern: "63.com",
res: false,
},
{
pattern: "oogle.com",
res: false,
},
{
pattern: "vvgoogle.com",
res: true,
},
}
for _, test := range cases2Output {
if m := ac.Match(test.pattern); m != test.res {
t.Error("unexpected output: ", m, " for test case ", test)
}
}
}
{
cases3Input := []struct {
pattern string
mType Type
}{
{
pattern: "video.google.com",
mType: Domain,
},
{
pattern: "gle.com",
mType: Domain,
},
}
var ac = NewACAutomaton()
for _, test := range cases3Input {
ac.Add(test.pattern, test.mType)
}
ac.Build()
cases3Output := []struct {
pattern string
res bool
}{
{
pattern: "google.com",
res: false,
},
}
for _, test := range cases3Output {
if m := ac.Match(test.pattern); m != test.res {
t.Error("unexpected output: ", m, " for test case ", test)
}
}
}
}

View File

@@ -102,7 +102,7 @@ func ReadClientHello(data []byte, h *SniffHeader) error {
return errNotClientHello return errNotClientHello
} }
if nameType == 0 { if nameType == 0 {
serverName := string(d[:nameLen]) serverName := strings.ToLower(string(d[:nameLen]))
// An SNI value may not include a // An SNI value may not include a
// trailing dot. See // trailing dot. See
// https://tools.ietf.org/html/rfc6066#section-3. // https://tools.ietf.org/html/rfc6066#section-3.

View File

@@ -6,8 +6,6 @@ import (
"math/rand" "math/rand"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/signal" "github.com/xtls/xray-core/common/signal"
@@ -62,8 +60,7 @@ type Outbound struct {
// SniffingRequest controls the behavior of content sniffing. // SniffingRequest controls the behavior of content sniffing.
type SniffingRequest struct { type SniffingRequest struct {
ExcludedDomainMatcher *domain.DomainMatcher ExcludeForDomain []string
ExcludedIPMatcher *geoip.MultiGeoIPMatcher
OverrideDestinationForProtocol []string OverrideDestinationForProtocol []string
Enabled bool Enabled bool
MetadataOnly bool MetadataOnly bool

View File

@@ -1,26 +1,13 @@
package str_test package strmatcher_test
import ( import (
"strconv" "strconv"
"testing" "testing"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/common/matcher/str" . "github.com/xtls/xray-core/common/strmatcher"
) )
func BenchmarkACAutomaton(b *testing.B) {
ac := NewACAutomaton()
for i := 1; i <= 1024; i++ {
ac.Add(strconv.Itoa(i)+".xray.com", Domain)
}
ac.Build()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = ac.Match("0.xray.com")
}
}
func BenchmarkDomainMatcherGroup(b *testing.B) { func BenchmarkDomainMatcherGroup(b *testing.B) {
g := new(DomainMatcherGroup) g := new(DomainMatcherGroup)

View File

@@ -1,4 +1,4 @@
package str package strmatcher
import "strings" import "strings"

View File

@@ -1,10 +1,10 @@
package str_test package strmatcher_test
import ( import (
"reflect" "reflect"
"testing" "testing"
. "github.com/xtls/xray-core/common/matcher/str" . "github.com/xtls/xray-core/common/strmatcher"
) )
func TestDomainMatcherGroup(t *testing.T) { func TestDomainMatcherGroup(t *testing.T) {

View File

@@ -1,4 +1,4 @@
package str package strmatcher
type FullMatcherGroup struct { type FullMatcherGroup struct {
matchers map[string][]uint32 matchers map[string][]uint32

View File

@@ -1,10 +1,10 @@
package str_test package strmatcher_test
import ( import (
"reflect" "reflect"
"testing" "testing"
. "github.com/xtls/xray-core/common/matcher/str" . "github.com/xtls/xray-core/common/strmatcher"
) )
func TestFullMatcherGroup(t *testing.T) { func TestFullMatcherGroup(t *testing.T) {

View File

@@ -1,4 +1,4 @@
package str package strmatcher
import ( import (
"regexp" "regexp"

View File

@@ -1,10 +1,10 @@
package str_test package strmatcher_test
import ( import (
"testing" "testing"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/common/matcher/str" . "github.com/xtls/xray-core/common/strmatcher"
) )
func TestMatcher(t *testing.T) { func TestMatcher(t *testing.T) {

View File

@@ -1,4 +1,4 @@
package str package strmatcher
import ( import (
"regexp" "regexp"
@@ -27,7 +27,6 @@ const (
// New creates a new Matcher based on the given pattern. // New creates a new Matcher based on the given pattern.
func (t Type) New(pattern string) (Matcher, error) { func (t Type) New(pattern string) (Matcher, error) {
// 1. regex matching is case-sensitive
switch t { switch t {
case Full: case Full:
return fullMatcher(pattern), nil return fullMatcher(pattern), nil

View File

@@ -0,0 +1,93 @@
package strmatcher_test
import (
"reflect"
"testing"
"github.com/xtls/xray-core/common"
. "github.com/xtls/xray-core/common/strmatcher"
)
func TestMatcherGroup(t *testing.T) {
rules := []struct {
Type Type
Domain string
}{
{
Type: Regex,
Domain: "apis\\.us$",
},
{
Type: Substr,
Domain: "apis",
},
{
Type: Domain,
Domain: "googleapis.com",
},
{
Type: Domain,
Domain: "com",
},
{
Type: Full,
Domain: "www.baidu.com",
},
{
Type: Substr,
Domain: "apis",
},
{
Type: Domain,
Domain: "googleapis.com",
},
{
Type: Full,
Domain: "fonts.googleapis.com",
},
{
Type: Full,
Domain: "www.baidu.com",
},
{
Type: Domain,
Domain: "example.com",
},
}
cases := []struct {
Input string
Output []uint32
}{
{
Input: "www.baidu.com",
Output: []uint32{5, 9, 4},
},
{
Input: "fonts.googleapis.com",
Output: []uint32{8, 3, 7, 4, 2, 6},
},
{
Input: "example.googleapis.com",
Output: []uint32{3, 7, 4, 2, 6},
},
{
Input: "testapis.us",
Output: []uint32{1, 2, 6},
},
{
Input: "example.com",
Output: []uint32{10, 4},
},
}
matcherGroup := &MatcherGroup{}
for _, rule := range rules {
matcher, err := rule.Type.New(rule.Domain)
common.Must(err)
matcherGroup.Add(matcher)
}
for _, test := range cases {
if m := matcherGroup.Match(test.Input); !reflect.DeepEqual(m, test.Output) {
t.Error("unexpected output: ", m, " for test case ", test)
}
}
}

View File

@@ -9,8 +9,6 @@ import (
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
) )
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
type StringList []string type StringList []string
func NewStringList(raw []string) *StringList { func NewStringList(raw []string) *StringList {

View File

@@ -2,7 +2,6 @@ package conf_test
import ( import (
"encoding/json" "encoding/json"
"github.com/xtls/xray-core/infra/conf"
"os" "os"
"testing" "testing"
@@ -12,11 +11,12 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
. "github.com/xtls/xray-core/infra/conf"
) )
func TestStringListUnmarshalError(t *testing.T) { func TestStringListUnmarshalError(t *testing.T) {
rawJSON := `1234` rawJSON := `1234`
list := new(conf.StringList) list := new(StringList)
err := json.Unmarshal([]byte(rawJSON), list) err := json.Unmarshal([]byte(rawJSON), list)
if err == nil { if err == nil {
t.Error("expected error, but got nil") t.Error("expected error, but got nil")
@@ -25,7 +25,7 @@ func TestStringListUnmarshalError(t *testing.T) {
func TestStringListLen(t *testing.T) { func TestStringListLen(t *testing.T) {
rawJSON := `"a, b, c, d"` rawJSON := `"a, b, c, d"`
var list conf.StringList var list StringList
err := json.Unmarshal([]byte(rawJSON), &list) err := json.Unmarshal([]byte(rawJSON), &list)
common.Must(err) common.Must(err)
if r := cmp.Diff([]string(list), []string{"a", " b", " c", " d"}); r != "" { if r := cmp.Diff([]string(list), []string{"a", " b", " c", " d"}); r != "" {
@@ -35,7 +35,7 @@ func TestStringListLen(t *testing.T) {
func TestIPParsing(t *testing.T) { func TestIPParsing(t *testing.T) {
rawJSON := "\"8.8.8.8\"" rawJSON := "\"8.8.8.8\""
var address conf.Address var address Address
err := json.Unmarshal([]byte(rawJSON), &address) err := json.Unmarshal([]byte(rawJSON), &address)
common.Must(err) common.Must(err)
if r := cmp.Diff(address.IP(), net.IP{8, 8, 8, 8}); r != "" { if r := cmp.Diff(address.IP(), net.IP{8, 8, 8, 8}); r != "" {
@@ -45,7 +45,7 @@ func TestIPParsing(t *testing.T) {
func TestDomainParsing(t *testing.T) { func TestDomainParsing(t *testing.T) {
rawJSON := "\"example.com\"" rawJSON := "\"example.com\""
var address conf.Address var address Address
common.Must(json.Unmarshal([]byte(rawJSON), &address)) common.Must(json.Unmarshal([]byte(rawJSON), &address))
if address.Domain() != "example.com" { if address.Domain() != "example.com" {
t.Error("domain: ", address.Domain()) t.Error("domain: ", address.Domain())
@@ -55,7 +55,7 @@ func TestDomainParsing(t *testing.T) {
func TestURLParsing(t *testing.T) { func TestURLParsing(t *testing.T) {
{ {
rawJSON := "\"https://dns.google/dns-query\"" rawJSON := "\"https://dns.google/dns-query\""
var address conf.Address var address Address
common.Must(json.Unmarshal([]byte(rawJSON), &address)) common.Must(json.Unmarshal([]byte(rawJSON), &address))
if address.Domain() != "https://dns.google/dns-query" { if address.Domain() != "https://dns.google/dns-query" {
t.Error("URL: ", address.Domain()) t.Error("URL: ", address.Domain())
@@ -63,7 +63,7 @@ func TestURLParsing(t *testing.T) {
} }
{ {
rawJSON := "\"https+local://dns.google/dns-query\"" rawJSON := "\"https+local://dns.google/dns-query\""
var address conf.Address var address Address
common.Must(json.Unmarshal([]byte(rawJSON), &address)) common.Must(json.Unmarshal([]byte(rawJSON), &address))
if address.Domain() != "https+local://dns.google/dns-query" { if address.Domain() != "https+local://dns.google/dns-query" {
t.Error("URL: ", address.Domain()) t.Error("URL: ", address.Domain())
@@ -73,7 +73,7 @@ func TestURLParsing(t *testing.T) {
func TestInvalidAddressJson(t *testing.T) { func TestInvalidAddressJson(t *testing.T) {
rawJSON := "1234" rawJSON := "1234"
var address conf.Address var address Address
err := json.Unmarshal([]byte(rawJSON), &address) err := json.Unmarshal([]byte(rawJSON), &address)
if err == nil { if err == nil {
t.Error("nil error") t.Error("nil error")
@@ -81,7 +81,7 @@ func TestInvalidAddressJson(t *testing.T) {
} }
func TestStringNetwork(t *testing.T) { func TestStringNetwork(t *testing.T) {
var network conf.Network var network Network
common.Must(json.Unmarshal([]byte(`"tcp"`), &network)) common.Must(json.Unmarshal([]byte(`"tcp"`), &network))
if v := network.Build(); v != net.Network_TCP { if v := network.Build(); v != net.Network_TCP {
t.Error("network: ", v) t.Error("network: ", v)
@@ -89,7 +89,7 @@ func TestStringNetwork(t *testing.T) {
} }
func TestArrayNetworkList(t *testing.T) { func TestArrayNetworkList(t *testing.T) {
var list conf.NetworkList var list NetworkList
common.Must(json.Unmarshal([]byte("[\"Tcp\"]"), &list)) common.Must(json.Unmarshal([]byte("[\"Tcp\"]"), &list))
nlist := list.Build() nlist := list.Build()
@@ -102,7 +102,7 @@ func TestArrayNetworkList(t *testing.T) {
} }
func TestStringNetworkList(t *testing.T) { func TestStringNetworkList(t *testing.T) {
var list conf.NetworkList var list NetworkList
common.Must(json.Unmarshal([]byte("\"TCP, ip\""), &list)) common.Must(json.Unmarshal([]byte("\"TCP, ip\""), &list))
nlist := list.Build() nlist := list.Build()
@@ -115,7 +115,7 @@ func TestStringNetworkList(t *testing.T) {
} }
func TestInvalidNetworkJson(t *testing.T) { func TestInvalidNetworkJson(t *testing.T) {
var list conf.NetworkList var list NetworkList
err := json.Unmarshal([]byte("0"), &list) err := json.Unmarshal([]byte("0"), &list)
if err == nil { if err == nil {
t.Error("nil error") t.Error("nil error")
@@ -123,10 +123,10 @@ func TestInvalidNetworkJson(t *testing.T) {
} }
func TestIntPort(t *testing.T) { func TestIntPort(t *testing.T) {
var portRange conf.PortRange var portRange PortRange
common.Must(json.Unmarshal([]byte("1234"), &portRange)) common.Must(json.Unmarshal([]byte("1234"), &portRange))
if r := cmp.Diff(portRange, conf.PortRange{ if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 1234, From: 1234, To: 1234,
}); r != "" { }); r != "" {
t.Error(r) t.Error(r)
@@ -134,7 +134,7 @@ func TestIntPort(t *testing.T) {
} }
func TestOverRangeIntPort(t *testing.T) { func TestOverRangeIntPort(t *testing.T) {
var portRange conf.PortRange var portRange PortRange
err := json.Unmarshal([]byte("70000"), &portRange) err := json.Unmarshal([]byte("70000"), &portRange)
if err == nil { if err == nil {
t.Error("nil error") t.Error("nil error")
@@ -149,10 +149,10 @@ func TestOverRangeIntPort(t *testing.T) {
func TestEnvPort(t *testing.T) { func TestEnvPort(t *testing.T) {
common.Must(os.Setenv("PORT", "1234")) common.Must(os.Setenv("PORT", "1234"))
var portRange conf.PortRange var portRange PortRange
common.Must(json.Unmarshal([]byte("\"env:PORT\""), &portRange)) common.Must(json.Unmarshal([]byte("\"env:PORT\""), &portRange))
if r := cmp.Diff(portRange, conf.PortRange{ if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 1234, From: 1234, To: 1234,
}); r != "" { }); r != "" {
t.Error(r) t.Error(r)
@@ -160,10 +160,10 @@ func TestEnvPort(t *testing.T) {
} }
func TestSingleStringPort(t *testing.T) { func TestSingleStringPort(t *testing.T) {
var portRange conf.PortRange var portRange PortRange
common.Must(json.Unmarshal([]byte("\"1234\""), &portRange)) common.Must(json.Unmarshal([]byte("\"1234\""), &portRange))
if r := cmp.Diff(portRange, conf.PortRange{ if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 1234, From: 1234, To: 1234,
}); r != "" { }); r != "" {
t.Error(r) t.Error(r)
@@ -171,10 +171,10 @@ func TestSingleStringPort(t *testing.T) {
} }
func TestStringPairPort(t *testing.T) { func TestStringPairPort(t *testing.T) {
var portRange conf.PortRange var portRange PortRange
common.Must(json.Unmarshal([]byte("\"1234-5678\""), &portRange)) common.Must(json.Unmarshal([]byte("\"1234-5678\""), &portRange))
if r := cmp.Diff(portRange, conf.PortRange{ if r := cmp.Diff(portRange, PortRange{
From: 1234, To: 5678, From: 1234, To: 5678,
}); r != "" { }); r != "" {
t.Error(r) t.Error(r)
@@ -182,7 +182,7 @@ func TestStringPairPort(t *testing.T) {
} }
func TestOverRangeStringPort(t *testing.T) { func TestOverRangeStringPort(t *testing.T) {
var portRange conf.PortRange var portRange PortRange
err := json.Unmarshal([]byte("\"65536\""), &portRange) err := json.Unmarshal([]byte("\"65536\""), &portRange)
if err == nil { if err == nil {
t.Error("nil error") t.Error("nil error")
@@ -205,7 +205,7 @@ func TestOverRangeStringPort(t *testing.T) {
} }
func TestUserParsing(t *testing.T) { func TestUserParsing(t *testing.T) {
user := new(conf.User) user := new(User)
common.Must(json.Unmarshal([]byte(`{ common.Must(json.Unmarshal([]byte(`{
"id": "96edb838-6d68-42ef-a933-25f7ac3a9d09", "id": "96edb838-6d68-42ef-a933-25f7ac3a9d09",
"email": "love@example.com", "email": "love@example.com",
@@ -223,7 +223,7 @@ func TestUserParsing(t *testing.T) {
} }
func TestInvalidUserJson(t *testing.T) { func TestInvalidUserJson(t *testing.T) {
user := new(conf.User) user := new(User)
err := json.Unmarshal([]byte(`{"email": 1234}`), user) err := json.Unmarshal([]byte(`{"email": 1234}`), user)
if err == nil { if err == nil {
t.Error("nil error") t.Error("nil error")

View File

@@ -2,15 +2,11 @@ package conf
import ( import (
"encoding/json" "encoding/json"
"sort" "sort"
"strings" "strings"
"github.com/xtls/xray-core/app/dns" "github.com/xtls/xray-core/app/dns"
dm "github.com/xtls/xray-core/common/matcher/domain" "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common/matcher/domain/conf"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/matcher/geosite"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
) )
@@ -51,24 +47,39 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
return newError("failed to parse name server: ", string(data)) return newError("failed to parse name server: ", string(data))
} }
func toDomainMatchingType(t router.Domain_Type) dns.DomainMatchingType {
switch t {
case router.Domain_Domain:
return dns.DomainMatchingType_Subdomain
case router.Domain_Full:
return dns.DomainMatchingType_Full
case router.Domain_Plain:
return dns.DomainMatchingType_Keyword
case router.Domain_Regex:
return dns.DomainMatchingType_Regex
default:
panic("unknown domain type")
}
}
func (c *NameServerConfig) Build() (*dns.NameServer, error) { func (c *NameServerConfig) Build() (*dns.NameServer, error) {
if c.Address == nil { if c.Address == nil {
return nil, newError("NameServer address is not specified.") return nil, newError("NameServer address is not specified.")
} }
var domains []*dm.Domain var domains []*dns.NameServer_PriorityDomain
var originalRules []*dns.NameServer_OriginalRule var originalRules []*dns.NameServer_OriginalRule
for _, rule := range c.Domains { for _, rule := range c.Domains {
parsedDomain, err := conf.ParseDomainRule(rule) parsedDomain, err := parseDomainRule(rule)
if err != nil { if err != nil {
return nil, newError("invalid domain rule: ", rule).Base(err) return nil, newError("invalid domain rule: ", rule).Base(err)
} }
for _, pd := range parsedDomain { for _, pd := range parsedDomain {
domains = append(domains, &dm.Domain{ domains = append(domains, &dns.NameServer_PriorityDomain{
Type: pd.Type, Type: toDomainMatchingType(pd.Type),
Value: pd.Value, Domain: pd.Value,
}) })
} }
originalRules = append(originalRules, &dns.NameServer_OriginalRule{ originalRules = append(originalRules, &dns.NameServer_OriginalRule{
@@ -77,7 +88,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
}) })
} }
geoipList, err := geoip.ParseIPList(c.ExpectIPs) geoipList, err := toCidrList(c.ExpectIPs)
if err != nil { if err != nil {
return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err) return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err)
} }
@@ -103,6 +114,13 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
}, nil }, nil
} }
var typeMap = map[router.Domain_Type]dns.DomainMatchingType{
router.Domain_Full: dns.DomainMatchingType_Full,
router.Domain_Domain: dns.DomainMatchingType_Subdomain,
router.Domain_Plain: dns.DomainMatchingType_Keyword,
router.Domain_Regex: dns.DomainMatchingType_Regex,
}
// DNSConfig is a JSON serializable object for dns.Config. // DNSConfig is a JSON serializable object for dns.Config.
type DNSConfig struct { type DNSConfig struct {
Servers []*NameServerConfig `json:"servers"` Servers []*NameServerConfig `json:"servers"`
@@ -224,7 +242,7 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
return nil, newError("empty domain type of rule: ", domain) return nil, newError("empty domain type of rule: ", domain)
} }
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dm.MatchingType_Subdomain mapping.Type = dns.DomainMatchingType_Subdomain
mapping.Domain = domainName mapping.Domain = domainName
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
@@ -233,13 +251,13 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
if len(listName) == 0 { if len(listName) == 0 {
return nil, newError("empty geosite rule: ", domain) return nil, newError("empty geosite rule: ", domain)
} }
domains, err := geosite.LoadGeositeWithAttr("geosite.dat", listName) domains, err := loadGeositeWithAttr("geosite.dat", listName)
if err != nil { if err != nil {
return nil, newError("failed to load geosite: ", listName).Base(err) return nil, newError("failed to load geosite: ", listName).Base(err)
} }
for _, d := range domains { for _, d := range domains {
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = d.Type mapping.Type = typeMap[d.Type]
mapping.Domain = d.Value mapping.Domain = d.Value
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
} }
@@ -250,7 +268,7 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
return nil, newError("empty regexp type of rule: ", domain) return nil, newError("empty regexp type of rule: ", domain)
} }
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dm.MatchingType_Regex mapping.Type = dns.DomainMatchingType_Regex
mapping.Domain = regexpVal mapping.Domain = regexpVal
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
@@ -260,7 +278,7 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
return nil, newError("empty keyword type of rule: ", domain) return nil, newError("empty keyword type of rule: ", domain)
} }
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dm.MatchingType_Keyword mapping.Type = dns.DomainMatchingType_Keyword
mapping.Domain = keywordVal mapping.Domain = keywordVal
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
@@ -270,13 +288,13 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
return nil, newError("empty full domain type of rule: ", domain) return nil, newError("empty full domain type of rule: ", domain)
} }
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dm.MatchingType_Full mapping.Type = dns.DomainMatchingType_Full
mapping.Domain = fullVal mapping.Domain = fullVal
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "dotless:"): case strings.HasPrefix(domain, "dotless:"):
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dm.MatchingType_Regex mapping.Type = dns.DomainMatchingType_Regex
switch substr := domain[8:]; { switch substr := domain[8:]; {
case substr == "": case substr == "":
mapping.Domain = "^[^.]*$" mapping.Domain = "^[^.]*$"
@@ -294,20 +312,20 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
} }
filename := kv[0] filename := kv[0]
list := kv[1] list := kv[1]
domains, err := geosite.LoadGeositeWithAttr(filename, list) domains, err := loadGeositeWithAttr(filename, list)
if err != nil { if err != nil {
return nil, newError("failed to load domain list: ", list, " from ", filename).Base(err) return nil, newError("failed to load domain list: ", list, " from ", filename).Base(err)
} }
for _, d := range domains { for _, d := range domains {
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = d.Type mapping.Type = typeMap[d.Type]
mapping.Domain = d.Value mapping.Domain = d.Value
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
} }
default: default:
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dm.MatchingType_Full mapping.Type = dns.DomainMatchingType_Full
mapping.Domain = domain mapping.Domain = domain
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
} }

View File

@@ -8,9 +8,8 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/dns" "github.com/xtls/xray-core/app/dns"
"github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geosite"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/common/platform/filesystem"
@@ -31,12 +30,12 @@ func init() {
common.Must(err) common.Must(err)
defer geositeFile.Close() defer geositeFile.Close()
list := &geosite.GeoSiteList{ list := &router.GeoSiteList{
Entry: []*geosite.GeoSite{ Entry: []*router.GeoSite{
{ {
CountryCode: "TEST", CountryCode: "TEST",
Domain: []*geosite.Domain{ Domain: []*router.Domain{
{Type: geosite.Domain_Full, Value: "example.com"}, {Type: router.Domain_Full, Value: "example.com"},
}, },
}, },
}, },
@@ -101,10 +100,10 @@ func TestDNSConfigParsing(t *testing.T) {
}, },
ClientIp: []byte{10, 0, 0, 1}, ClientIp: []byte{10, 0, 0, 1},
SkipFallback: true, SkipFallback: true,
PrioritizedDomain: []*domain.Domain{ PrioritizedDomain: []*dns.NameServer_PriorityDomain{
{ {
Type: domain.MatchingType_Subdomain, Type: dns.DomainMatchingType_Subdomain,
Value: "example.com", Domain: "example.com",
}, },
}, },
OriginalRules: []*dns.NameServer_OriginalRule{ OriginalRules: []*dns.NameServer_OriginalRule{
@@ -117,32 +116,32 @@ func TestDNSConfigParsing(t *testing.T) {
}, },
StaticHosts: []*dns.Config_HostMapping{ StaticHosts: []*dns.Config_HostMapping{
{ {
Type: domain.MatchingType_Subdomain, Type: dns.DomainMatchingType_Subdomain,
Domain: "example.com", Domain: "example.com",
ProxiedDomain: "google.com", ProxiedDomain: "google.com",
}, },
{ {
Type: domain.MatchingType_Full, Type: dns.DomainMatchingType_Full,
Domain: "example.com", Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}}, Ip: [][]byte{{127, 0, 0, 1}},
}, },
{ {
Type: domain.MatchingType_Full, Type: dns.DomainMatchingType_Full,
Domain: "example.com", Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}, {127, 0, 0, 2}}, Ip: [][]byte{{127, 0, 0, 1}, {127, 0, 0, 2}},
}, },
{ {
Type: domain.MatchingType_Keyword, Type: dns.DomainMatchingType_Keyword,
Domain: "google", Domain: "google",
Ip: [][]byte{{8, 8, 8, 8}, {8, 8, 4, 4}}, Ip: [][]byte{{8, 8, 8, 8}, {8, 8, 4, 4}},
}, },
{ {
Type: domain.MatchingType_Regex, Type: dns.DomainMatchingType_Regex,
Domain: ".*\\.com", Domain: ".*\\.com",
Ip: [][]byte{{8, 8, 4, 4}}, Ip: [][]byte{{8, 8, 4, 4}},
}, },
{ {
Type: domain.MatchingType_Full, Type: dns.DomainMatchingType_Full,
Domain: "xtls.github.io", Domain: "xtls.github.io",
Ip: [][]byte{{1, 2, 3, 4}, {5, 6, 7, 8}}, Ip: [][]byte{{1, 2, 3, 4}, {5, 6, 7, 8}},
}, },

14
infra/conf/loopback.go Normal file
View File

@@ -0,0 +1,14 @@
package conf
import (
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/proxy/loopback"
)
type LoopbackConfig struct {
InboundTag string `json:"inboundTag"`
}
func (l LoopbackConfig) Build() (proto.Message, error) {
return &loopback.Config{InboundTag: l.InboundTag}, nil
}

View File

@@ -2,14 +2,15 @@ package conf
import ( import (
"encoding/json" "encoding/json"
"runtime"
"strconv" "strconv"
"strings" "strings"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common/matcher/domain/conf"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/matcher/geosite"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform/filesystem"
) )
type RouterRulesConfig struct { type RouterRulesConfig struct {
@@ -52,11 +53,11 @@ func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
} }
switch strings.ToLower(ds) { switch strings.ToLower(ds) {
case "alwaysip", "always_ip", "always-ip": case "alwaysip":
return router.Config_UseIp return router.Config_UseIp
case "ipifnonmatch", "ip_if_non_match", "ip-if-non-match": case "ipifnonmatch":
return router.Config_IpIfNonMatch return router.Config_IpIfNonMatch
case "ipondemand", "ip_on_demand", "ip-on-demand": case "ipondemand":
return router.Config_IpOnDemand return router.Config_IpOnDemand
default: default:
return router.Config_AsIs return router.Config_AsIs
@@ -94,13 +95,12 @@ func (c *RouterConfig) Build() (*router.Config, error) {
} }
type RouterRule struct { type RouterRule struct {
Type string `json:"type"` Type string `json:"type"`
OutboundTag string `json:"outboundTag"` OutboundTag string `json:"outboundTag"`
BalancerTag string `json:"balancerTag"` BalancerTag string `json:"balancerTag"`
DomainMatcher string `json:"domainMatcher"`
} }
func ParseIP(s string) (*geoip.CIDR, error) { func ParseIP(s string) (*router.CIDR, error) {
var addr, mask string var addr, mask string
i := strings.Index(s, "/") i := strings.Index(s, "/")
if i < 0 { if i < 0 {
@@ -123,7 +123,7 @@ func ParseIP(s string) (*geoip.CIDR, error) {
if bits > 32 { if bits > 32 {
return nil, newError("invalid network mask for router: ", bits) return nil, newError("invalid network mask for router: ", bits)
} }
return &geoip.CIDR{ return &router.CIDR{
Ip: []byte(ip.IP()), Ip: []byte(ip.IP()),
Prefix: bits, Prefix: bits,
}, nil }, nil
@@ -139,8 +139,8 @@ func ParseIP(s string) (*geoip.CIDR, error) {
if bits > 128 { if bits > 128 {
return nil, newError("invalid network mask for router: ", bits) return nil, newError("invalid network mask for router: ", bits)
} }
return &geoip.CIDR{ return &router.CIDR{
Ip: ip.IP(), Ip: []byte(ip.IP()),
Prefix: bits, Prefix: bits,
}, nil }, nil
default: default:
@@ -148,6 +148,314 @@ func ParseIP(s string) (*geoip.CIDR, error) {
} }
} }
func loadGeoIP(code string) ([]*router.CIDR, error) {
return loadIP("geoip.dat", code)
}
var (
FileCache = make(map[string][]byte)
IPCache = make(map[string]*router.GeoIP)
SiteCache = make(map[string]*router.GeoSite)
)
func loadFile(file string) ([]byte, error) {
if FileCache[file] == nil {
bs, err := filesystem.ReadAsset(file)
if err != nil {
return nil, newError("failed to open file: ", file).Base(err)
}
if len(bs) == 0 {
return nil, newError("empty file: ", file)
}
// Do not cache file, may save RAM when there
// are many files, but consume CPU each time.
return bs, nil
FileCache[file] = bs
}
return FileCache[file], nil
}
func loadIP(file, code string) ([]*router.CIDR, error) {
index := file + ":" + code
if IPCache[index] == nil {
bs, err := loadFile(file)
if err != nil {
return nil, newError("failed to load file: ", file).Base(err)
}
bs = find(bs, []byte(code))
if bs == nil {
return nil, newError("code not found in ", file, ": ", code)
}
var geoip router.GeoIP
if err := proto.Unmarshal(bs, &geoip); err != nil {
return nil, newError("error unmarshal IP in ", file, ": ", code).Base(err)
}
defer runtime.GC() // or debug.FreeOSMemory()
return geoip.Cidr, nil // do not cache geoip
IPCache[index] = &geoip
}
return IPCache[index].Cidr, nil
}
func loadSite(file, code string) ([]*router.Domain, error) {
index := file + ":" + code
if SiteCache[index] == nil {
bs, err := loadFile(file)
if err != nil {
return nil, newError("failed to load file: ", file).Base(err)
}
bs = find(bs, []byte(code))
if bs == nil {
return nil, newError("list not found in ", file, ": ", code)
}
var geosite router.GeoSite
if err := proto.Unmarshal(bs, &geosite); err != nil {
return nil, newError("error unmarshal Site in ", file, ": ", code).Base(err)
}
defer runtime.GC() // or debug.FreeOSMemory()
return geosite.Domain, nil // do not cache geosite
SiteCache[index] = &geosite
}
return SiteCache[index].Domain, nil
}
func find(data, code []byte) []byte {
codeL := len(code)
if codeL == 0 {
return nil
}
for {
dataL := len(data)
if dataL < 2 {
return nil
}
x, y := proto.DecodeVarint(data[1:])
if x == 0 && y == 0 {
return nil
}
headL, bodyL := 1+y, int(x)
dataL -= headL
if dataL < bodyL {
return nil
}
data = data[headL:]
if int(data[1]) == codeL {
for i := 0; i < codeL && data[2+i] == code[i]; i++ {
if i+1 == codeL {
return data[:bodyL]
}
}
}
if dataL == bodyL {
return nil
}
data = data[bodyL:]
}
}
type AttributeMatcher interface {
Match(*router.Domain) bool
}
type BooleanMatcher string
func (m BooleanMatcher) Match(domain *router.Domain) bool {
for _, attr := range domain.Attribute {
if attr.Key == string(m) {
return true
}
}
return false
}
type AttributeList struct {
matcher []AttributeMatcher
}
func (al *AttributeList) Match(domain *router.Domain) bool {
for _, matcher := range al.matcher {
if !matcher.Match(domain) {
return false
}
}
return true
}
func (al *AttributeList) IsEmpty() bool {
return len(al.matcher) == 0
}
func parseAttrs(attrs []string) *AttributeList {
al := new(AttributeList)
for _, attr := range attrs {
lc := strings.ToLower(attr)
al.matcher = append(al.matcher, BooleanMatcher(lc))
}
return al
}
func loadGeositeWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) {
parts := strings.Split(siteWithAttr, "@")
if len(parts) == 0 {
return nil, newError("empty site")
}
country := strings.ToUpper(parts[0])
attrs := parseAttrs(parts[1:])
domains, err := loadSite(file, country)
if err != nil {
return nil, err
}
if attrs.IsEmpty() {
return domains, nil
}
filteredDomains := make([]*router.Domain, 0, len(domains))
for _, domain := range domains {
if attrs.Match(domain) {
filteredDomains = append(filteredDomains, domain)
}
}
return filteredDomains, nil
}
func parseDomainRule(domain string) ([]*router.Domain, error) {
if strings.HasPrefix(domain, "geosite:") {
country := strings.ToUpper(domain[8:])
domains, err := loadGeositeWithAttr("geosite.dat", country)
if err != nil {
return nil, newError("failed to load geosite: ", country).Base(err)
}
return domains, nil
}
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(domain, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-domain:"
if strings.HasPrefix(domain, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(domain[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", domain)
}
filename := kv[0]
country := kv[1]
domains, err := loadGeositeWithAttr(filename, country)
if err != nil {
return nil, newError("failed to load external sites: ", country, " from ", filename).Base(err)
}
return domains, nil
}
domainRule := new(router.Domain)
switch {
case strings.HasPrefix(domain, "regexp:"):
domainRule.Type = router.Domain_Regex
domainRule.Value = domain[7:]
case strings.HasPrefix(domain, "domain:"):
domainRule.Type = router.Domain_Domain
domainRule.Value = domain[7:]
case strings.HasPrefix(domain, "full:"):
domainRule.Type = router.Domain_Full
domainRule.Value = domain[5:]
case strings.HasPrefix(domain, "keyword:"):
domainRule.Type = router.Domain_Plain
domainRule.Value = domain[8:]
case strings.HasPrefix(domain, "dotless:"):
domainRule.Type = router.Domain_Regex
switch substr := domain[8:]; {
case substr == "":
domainRule.Value = "^[^.]*$"
case !strings.Contains(substr, "."):
domainRule.Value = "^[^.]*" + substr + "[^.]*$"
default:
return nil, newError("substr in dotless rule should not contain a dot: ", substr)
}
default:
domainRule.Type = router.Domain_Plain
domainRule.Value = domain
}
return []*router.Domain{domainRule}, nil
}
func toCidrList(ips StringList) ([]*router.GeoIP, error) {
var geoipList []*router.GeoIP
var customCidrs []*router.CIDR
for _, ip := range ips {
if strings.HasPrefix(ip, "geoip:") {
country := ip[6:]
geoip, err := loadGeoIP(strings.ToUpper(country))
if err != nil {
return nil, newError("failed to load GeoIP: ", country).Base(err)
}
geoipList = append(geoipList, &router.GeoIP{
CountryCode: strings.ToUpper(country),
Cidr: geoip,
})
continue
}
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(ip, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-ip:"
if strings.HasPrefix(ip, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(ip[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", ip)
}
filename := kv[0]
country := kv[1]
geoip, err := loadIP(filename, strings.ToUpper(country))
if err != nil {
return nil, newError("failed to load IPs: ", country, " from ", filename).Base(err)
}
geoipList = append(geoipList, &router.GeoIP{
CountryCode: strings.ToUpper(filename + "_" + country),
Cidr: geoip,
})
continue
}
ipRule, err := ParseIP(ip)
if err != nil {
return nil, newError("invalid IP: ", ip).Base(err)
}
customCidrs = append(customCidrs, ipRule)
}
if len(customCidrs) > 0 {
geoipList = append(geoipList, &router.GeoIP{
Cidr: customCidrs,
})
}
return geoipList, nil
}
func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) { func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
type RawFieldRule struct { type RawFieldRule struct {
RouterRule RouterRule
@@ -183,13 +491,9 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
return nil, newError("neither outboundTag nor balancerTag is specified in routing rule") return nil, newError("neither outboundTag nor balancerTag is specified in routing rule")
} }
if rawFieldRule.DomainMatcher != "" {
rule.DomainMatcher = rawFieldRule.DomainMatcher
}
if rawFieldRule.Domain != nil { if rawFieldRule.Domain != nil {
for _, domain := range *rawFieldRule.Domain { for _, domain := range *rawFieldRule.Domain {
rules, err := conf.ParseDomainRule(domain) rules, err := parseDomainRule(domain)
if err != nil { if err != nil {
return nil, newError("failed to parse domain rule: ", domain).Base(err) return nil, newError("failed to parse domain rule: ", domain).Base(err)
} }
@@ -199,7 +503,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
if rawFieldRule.Domains != nil { if rawFieldRule.Domains != nil {
for _, domain := range *rawFieldRule.Domains { for _, domain := range *rawFieldRule.Domains {
rules, err := conf.ParseDomainRule(domain) rules, err := parseDomainRule(domain)
if err != nil { if err != nil {
return nil, newError("failed to parse domain rule: ", domain).Base(err) return nil, newError("failed to parse domain rule: ", domain).Base(err)
} }
@@ -208,7 +512,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
} }
if rawFieldRule.IP != nil { if rawFieldRule.IP != nil {
geoipList, err := geoip.ParseIPList(*rawFieldRule.IP) geoipList, err := toCidrList(*rawFieldRule.IP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -224,7 +528,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
} }
if rawFieldRule.SourceIP != nil { if rawFieldRule.SourceIP != nil {
geoipList, err := geoip.ParseIPList(*rawFieldRule.SourceIP) geoipList, err := toCidrList(*rawFieldRule.SourceIP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -266,21 +570,21 @@ func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
if err != nil { if err != nil {
return nil, newError("invalid router rule").Base(err) return nil, newError("invalid router rule").Base(err)
} }
if strings.EqualFold(rawRule.Type, "field") { if rawRule.Type == "field" {
fieldrule, err := parseFieldRule(msg) fieldrule, err := parseFieldRule(msg)
if err != nil { if err != nil {
return nil, newError("invalid field rule").Base(err) return nil, newError("invalid field rule").Base(err)
} }
return fieldrule, nil return fieldrule, nil
} }
if strings.EqualFold(rawRule.Type, "chinaip") { if rawRule.Type == "chinaip" {
chinaiprule, err := parseChinaIPRule(msg) chinaiprule, err := parseChinaIPRule(msg)
if err != nil { if err != nil {
return nil, newError("invalid chinaip rule").Base(err) return nil, newError("invalid chinaip rule").Base(err)
} }
return chinaiprule, nil return chinaiprule, nil
} }
if strings.EqualFold(rawRule.Type, "chinasites") { if rawRule.Type == "chinasites" {
chinasitesrule, err := parseChinaSitesRule(msg) chinasitesrule, err := parseChinaSitesRule(msg)
if err != nil { if err != nil {
return nil, newError("invalid chinasites rule").Base(err) return nil, newError("invalid chinasites rule").Base(err)
@@ -296,7 +600,7 @@ func parseChinaIPRule(data []byte) (*router.RoutingRule, error) {
if err != nil { if err != nil {
return nil, newError("invalid router rule").Base(err) return nil, newError("invalid router rule").Base(err)
} }
chinaIPs, err := geoip.LoadGeoIP("CN") chinaIPs, err := loadGeoIP("CN")
if err != nil { if err != nil {
return nil, newError("failed to load geoip:cn").Base(err) return nil, newError("failed to load geoip:cn").Base(err)
} }
@@ -314,7 +618,7 @@ func parseChinaSitesRule(data []byte) (*router.RoutingRule, error) {
if err != nil { if err != nil {
return nil, newError("invalid router rule").Base(err).AtError() return nil, newError("invalid router rule").Base(err).AtError()
} }
domains, err := geosite.LoadGeositeWithAttr("geosite.dat", "CN") domains, err := loadGeositeWithAttr("geosite.dat", "CN")
if err != nil { if err != nil {
return nil, newError("failed to load geosite:cn.").Base(err) return nil, newError("failed to load geosite:cn.").Base(err)
} }

View File

@@ -7,8 +7,6 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
. "github.com/xtls/xray-core/infra/conf" . "github.com/xtls/xray-core/infra/conf"
) )
@@ -75,13 +73,13 @@ func TestRouterConfig(t *testing.T) {
}, },
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Domain: []*domain.Domain{ Domain: []*router.Domain{
{ {
Type: domain.MatchingType_Keyword, Type: router.Domain_Plain,
Value: "baidu.com", Value: "baidu.com",
}, },
{ {
Type: domain.MatchingType_Keyword, Type: router.Domain_Plain,
Value: "qq.com", Value: "qq.com",
}, },
}, },
@@ -90,9 +88,9 @@ func TestRouterConfig(t *testing.T) {
}, },
}, },
{ {
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ {
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
Ip: []byte{10, 0, 0, 0}, Ip: []byte{10, 0, 0, 0},
Prefix: 8, Prefix: 8,
@@ -163,13 +161,13 @@ func TestRouterConfig(t *testing.T) {
DomainStrategy: router.Config_IpIfNonMatch, DomainStrategy: router.Config_IpIfNonMatch,
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Domain: []*domain.Domain{ Domain: []*router.Domain{
{ {
Type: domain.MatchingType_Keyword, Type: router.Domain_Plain,
Value: "baidu.com", Value: "baidu.com",
}, },
{ {
Type: domain.MatchingType_Keyword, Type: router.Domain_Plain,
Value: "qq.com", Value: "qq.com",
}, },
}, },
@@ -178,9 +176,9 @@ func TestRouterConfig(t *testing.T) {
}, },
}, },
{ {
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ {
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
Ip: []byte{10, 0, 0, 0}, Ip: []byte{10, 0, 0, 0},
Prefix: 8, Prefix: 8,
@@ -226,13 +224,13 @@ func TestRouterConfig(t *testing.T) {
DomainStrategy: router.Config_AsIs, DomainStrategy: router.Config_AsIs,
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Domain: []*domain.Domain{ Domain: []*router.Domain{
{ {
Type: domain.MatchingType_Keyword, Type: router.Domain_Plain,
Value: "baidu.com", Value: "baidu.com",
}, },
{ {
Type: domain.MatchingType_Keyword, Type: router.Domain_Plain,
Value: "qq.com", Value: "qq.com",
}, },
}, },
@@ -241,9 +239,9 @@ func TestRouterConfig(t *testing.T) {
}, },
}, },
{ {
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ {
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
Ip: []byte{10, 0, 0, 0}, Ip: []byte{10, 0, 0, 0},
Prefix: 8, Prefix: 8,

View File

@@ -2,20 +2,17 @@ package conf
import ( import (
"encoding/json" "encoding/json"
"log" "log"
"os" "os"
"strings" "strings"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/app/dispatcher" "github.com/xtls/xray-core/app/dispatcher"
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/app/stats" "github.com/xtls/xray-core/app/stats"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/matcher/domain/conf"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
core "github.com/xtls/xray-core/core" core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/xtls" "github.com/xtls/xray-core/transport/internet/xtls"
) )
@@ -42,6 +39,7 @@ var (
"trojan": func() interface{} { return new(TrojanClientConfig) }, "trojan": func() interface{} { return new(TrojanClientConfig) },
"mtproto": func() interface{} { return new(MTProtoClientConfig) }, "mtproto": func() interface{} { return new(MTProtoClientConfig) },
"dns": func() interface{} { return new(DNSOutboundConfig) }, "dns": func() interface{} { return new(DNSOutboundConfig) },
"loopback": func() interface{} { return new(LoopbackConfig) },
}, "protocol", "settings") }, "protocol", "settings")
ctllog = log.New(os.Stderr, "xctl> ", 0) ctllog = log.New(os.Stderr, "xctl> ", 0)
@@ -66,7 +64,6 @@ type SniffingConfig struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
DestOverride *StringList `json:"destOverride"` DestOverride *StringList `json:"destOverride"`
DomainsExcluded *StringList `json:"domainsExcluded"` DomainsExcluded *StringList `json:"domainsExcluded"`
IPsExcluded *StringList `json:"ipsExcluded"`
MetadataOnly bool `json:"metadataOnly"` MetadataOnly bool `json:"metadataOnly"`
} }
@@ -88,31 +85,17 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
} }
} }
var exDomain []*domain.Domain var d []string
if c.DomainsExcluded != nil { if c.DomainsExcluded != nil {
for _, dmr := range *c.DomainsExcluded { for _, domain := range *c.DomainsExcluded {
if dm, err := conf.ParseDomainRule(dmr); err == nil { d = append(d, strings.ToLower(domain))
exDomain = append(exDomain, dm...)
} else {
return nil, newError("failed to parse excluded domain").Base(err)
}
} }
} }
var exIP []*geoip.GeoIP
if c.IPsExcluded != nil {
exip, err := geoip.ParseIPList(*c.IPsExcluded)
if err != nil {
return nil, newError("failed to parse excluded ip").Base(err)
}
exIP = exip
}
return &proxyman.SniffingConfig{ return &proxyman.SniffingConfig{
Enabled: c.Enabled, Enabled: c.Enabled,
DestinationOverride: p, DestinationOverride: p,
DomainsExcluded: exDomain, DomainsExcluded: d,
IpsExcluded: exIP,
MetadataOnly: c.MetadataOnly, MetadataOnly: c.MetadataOnly,
}, nil }, nil
} }

View File

@@ -2,7 +2,6 @@ package conf_test
import ( import (
"encoding/json" "encoding/json"
"github.com/xtls/xray-core/common/matcher/domain"
"reflect" "reflect"
"testing" "testing"
@@ -14,7 +13,6 @@ import (
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
clog "github.com/xtls/xray-core/common/log" clog "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
@@ -156,9 +154,9 @@ func TestXrayConfig(t *testing.T) {
DomainStrategy: router.Config_AsIs, DomainStrategy: router.Config_AsIs,
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Geoip: []*geoip.GeoIP{ Geoip: []*router.GeoIP{
{ {
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
Ip: []byte{10, 0, 0, 0}, Ip: []byte{10, 0, 0, 0},
Prefix: 8, Prefix: 8,
@@ -373,52 +371,6 @@ func TestMuxConfig_Build(t *testing.T) {
} }
} }
func TestSniffingConfig_Build(t *testing.T) {
tests := []struct {
name string
fields string
want *proxyman.SniffingConfig
}{
{"default", `
{
"enabled": true,
"destOverride": ["tls"],
"domainsExcluded": ["domain:google.com"],
"ipsExcluded": ["8.8.8.8"]
}`, &proxyman.SniffingConfig{
Enabled: true,
DestinationOverride: []string{"tls"},
DomainsExcluded: []*domain.Domain{
{
Type: domain.MatchingType_Subdomain,
Value: "google.com",
},
},
IpsExcluded: []*geoip.GeoIP{
{
Cidr: []*geoip.CIDR{{Ip: []byte{8, 8, 8, 8}, Prefix: 32}},
},
},
}},
{"empty def", `{}`, &proxyman.SniffingConfig{
Enabled: false,
}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &SniffingConfig{}
common.Must(json.Unmarshal([]byte(tt.fields), m))
got, err := m.Build()
if err != nil {
t.Errorf("%v", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("SniffingConfig.Build() = %v, want %v", got, tt.want)
}
})
}
}
func TestConfig_Override(t *testing.T) { func TestConfig_Override(t *testing.T) {
tests := []struct { tests := []struct {
name string name string

149
proxy/loopback/config.pb.go Normal file
View File

@@ -0,0 +1,149 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.15.8
// source: proxy/loopback/config.proto
package loopback
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
InboundTag string `protobuf:"bytes,1,opt,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_loopback_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_loopback_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_loopback_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetInboundTag() string {
if x != nil {
return x.InboundTag
}
return ""
}
var File_proxy_loopback_config_proto protoreflect.FileDescriptor
var file_proxy_loopback_config_proto_rawDesc = []byte{
0x0a, 0x1b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61,
0x63, 0x6b, 0x22, 0x29, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x0a, 0x0b,
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x42, 0x5b, 0x0a,
0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x50, 0x01, 0x5a, 0x28, 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, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x6c, 0x6f, 0x6f, 0x70,
0x62, 0x61, 0x63, 0x6b, 0xaa, 0x02, 0x13, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78,
0x79, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_proxy_loopback_config_proto_rawDescOnce sync.Once
file_proxy_loopback_config_proto_rawDescData = file_proxy_loopback_config_proto_rawDesc
)
func file_proxy_loopback_config_proto_rawDescGZIP() []byte {
file_proxy_loopback_config_proto_rawDescOnce.Do(func() {
file_proxy_loopback_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_loopback_config_proto_rawDescData)
})
return file_proxy_loopback_config_proto_rawDescData
}
var file_proxy_loopback_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_proxy_loopback_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: xray.proxy.loopback.Config
}
var file_proxy_loopback_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_proxy_loopback_config_proto_init() }
func file_proxy_loopback_config_proto_init() {
if File_proxy_loopback_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_loopback_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_loopback_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_loopback_config_proto_goTypes,
DependencyIndexes: file_proxy_loopback_config_proto_depIdxs,
MessageInfos: file_proxy_loopback_config_proto_msgTypes,
}.Build()
File_proxy_loopback_config_proto = out.File
file_proxy_loopback_config_proto_rawDesc = nil
file_proxy_loopback_config_proto_goTypes = nil
file_proxy_loopback_config_proto_depIdxs = nil
}

View File

@@ -0,0 +1,11 @@
syntax = "proto3";
package xray.proxy.loopback;
option csharp_namespace = "Xray.Proxy.Loopback";
option go_package = "github.com/xtls/xray-core/proxy/loopback";
option java_package = "com.xray.proxy.loopback";
option java_multiple_files = true;
message Config {
string inbound_tag = 1;
}

View File

@@ -1,4 +1,4 @@
package proxyman package loopback
import "github.com/xtls/xray-core/common/errors" import "github.com/xtls/xray-core/common/errors"

121
proxy/loopback/lookback.go Normal file
View File

@@ -0,0 +1,121 @@
package loopback
import (
"context"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/retry"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/task"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
)
type Loopback struct {
config *Config
dispatcherInstance routing.Dispatcher
}
func (l *Loopback) Process(ctx context.Context, link *transport.Link, _ internet.Dialer) error {
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified.")
}
destination := outbound.Target
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
input := link.Reader
output := link.Writer
var conn internet.Connection
err := retry.ExponentialBackoff(5, 100).On(func() error {
dialDest := destination
content := new(session.Content)
content.SkipDNSResolve = true
ctx = session.ContextWithContent(ctx, content)
inbound := session.InboundFromContext(ctx)
inbound.Tag = l.config.InboundTag
ctx = session.ContextWithInbound(ctx, inbound)
rawConn, err := l.dispatcherInstance.Dispatch(ctx, dialDest)
if err != nil {
return err
}
var readerOpt cnc.ConnectionOption
if dialDest.Network == net.Network_TCP {
readerOpt = cnc.ConnectionOutputMulti(rawConn.Reader)
} else {
readerOpt = cnc.ConnectionOutputMultiUDP(rawConn.Reader)
}
conn = cnc.NewConnection(cnc.ConnectionInputMulti(rawConn.Writer), readerOpt)
return nil
})
if err != nil {
return newError("failed to open connection to ", destination).Base(err)
}
defer conn.Close()
requestDone := func() error {
var writer buf.Writer
if destination.Network == net.Network_TCP {
writer = buf.NewWriter(conn)
} else {
writer = &buf.SequentialWriter{Writer: conn}
}
if err := buf.Copy(input, writer); err != nil {
return newError("failed to process request").Base(err)
}
return nil
}
responseDone := func() error {
var reader buf.Reader
if destination.Network == net.Network_TCP {
reader = buf.NewReader(conn)
} else {
reader = buf.NewPacketReader(conn)
}
if err := buf.Copy(reader, output); err != nil {
return newError("failed to process response").Base(err)
}
return nil
}
if err := task.Run(ctx, requestDone, task.OnSuccess(responseDone, task.Close(output))); err != nil {
return newError("connection ends").Base(err)
}
return nil
}
func (l *Loopback) init(config *Config, dispatcherInstance routing.Dispatcher) error {
l.dispatcherInstance = dispatcherInstance
l.config = config
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
l := new(Loopback)
err := core.RequireFeatures(ctx, func(dispatcherInstance routing.Dispatcher) error {
return l.init(config.(*Config), dispatcherInstance)
})
return l, err
}))
}

View File

@@ -0,0 +1,3 @@
package loopback
//go:generate go run github.com/xray/xray-core/common/errors/errorgen

View File

@@ -9,7 +9,6 @@ import (
"github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/matcher/geoip"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -40,7 +39,7 @@ func TestResolveIP(t *testing.T) {
DomainStrategy: router.Config_IpIfNonMatch, DomainStrategy: router.Config_IpIfNonMatch,
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Cidr: []*geoip.CIDR{ Cidr: []*router.CIDR{
{ {
Ip: []byte{127, 0, 0, 0}, Ip: []byte{127, 0, 0, 0},
Prefix: 8, Prefix: 8,

View File

@@ -13,7 +13,6 @@ import (
"github.com/xtls/xray-core/app/router" "github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
clog "github.com/xtls/xray-core/common/log" clog "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/matcher/domain"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
@@ -54,8 +53,8 @@ func TestReverseProxy(t *testing.T) {
serial.ToTypedMessage(&router.Config{ serial.ToTypedMessage(&router.Config{
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Domain: []*domain.Domain{ Domain: []*router.Domain{
{Type: domain.MatchingType_Full, Value: "test.example.com"}, {Type: router.Domain_Full, Value: "test.example.com"},
}, },
TargetTag: &router.RoutingRule_Tag{ TargetTag: &router.RoutingRule_Tag{
Tag: "portal", Tag: "portal",
@@ -123,8 +122,8 @@ func TestReverseProxy(t *testing.T) {
serial.ToTypedMessage(&router.Config{ serial.ToTypedMessage(&router.Config{
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Domain: []*domain.Domain{ Domain: []*router.Domain{
{Type: domain.MatchingType_Full, Value: "test.example.com"}, {Type: router.Domain_Full, Value: "test.example.com"},
}, },
TargetTag: &router.RoutingRule_Tag{ TargetTag: &router.RoutingRule_Tag{
Tag: "reverse", Tag: "reverse",
@@ -239,8 +238,8 @@ func TestReverseProxyLongRunning(t *testing.T) {
serial.ToTypedMessage(&router.Config{ serial.ToTypedMessage(&router.Config{
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Domain: []*domain.Domain{ Domain: []*router.Domain{
{Type: domain.MatchingType_Full, Value: "test.example.com"}, {Type: router.Domain_Full, Value: "test.example.com"},
}, },
TargetTag: &router.RoutingRule_Tag{ TargetTag: &router.RoutingRule_Tag{
Tag: "portal", Tag: "portal",
@@ -322,8 +321,8 @@ func TestReverseProxyLongRunning(t *testing.T) {
serial.ToTypedMessage(&router.Config{ serial.ToTypedMessage(&router.Config{
Rule: []*router.RoutingRule{ Rule: []*router.RoutingRule{
{ {
Domain: []*domain.Domain{ Domain: []*router.Domain{
{Type: domain.MatchingType_Full, Value: "test.example.com"}, {Type: router.Domain_Full, Value: "test.example.com"},
}, },
TargetTag: &router.RoutingRule_Tag{ TargetTag: &router.RoutingRule_Tag{
Tag: "reverse", Tag: "reverse",