diff --git a/app/dns/config.pb.go b/app/dns/config.pb.go index 67fbd84e..d54142ce 100644 --- a/app/dns/config.pb.go +++ b/app/dns/config.pb.go @@ -80,6 +80,7 @@ const ( QueryStrategy_USE_IP QueryStrategy = 0 QueryStrategy_USE_IP4 QueryStrategy = 1 QueryStrategy_USE_IP6 QueryStrategy = 2 + QueryStrategy_USE_SYS QueryStrategy = 3 ) // Enum value maps for QueryStrategy. @@ -88,11 +89,13 @@ var ( 0: "USE_IP", 1: "USE_IP4", 2: "USE_IP6", + 3: "USE_SYS", } QueryStrategy_value = map[string]int32{ "USE_IP": 0, "USE_IP4": 1, "USE_IP6": 2, + "USE_SYS": 3, } ) @@ -128,16 +131,20 @@ type NameServer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - 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"` - SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"` - PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,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"` - QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"` - AllowUnexpectedIPs bool `protobuf:"varint,8,opt,name=allowUnexpectedIPs,proto3" json:"allowUnexpectedIPs,omitempty"` - Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"` - TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,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"` + SkipFallback bool `protobuf:"varint,6,opt,name=skipFallback,proto3" json:"skipFallback,omitempty"` + PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"` + ExpectedGeoip []*router.GeoIP `protobuf:"bytes,3,rep,name=expected_geoip,json=expectedGeoip,proto3" json:"expected_geoip,omitempty"` + OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"` + QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"` + ActPrior bool `protobuf:"varint,8,opt,name=actPrior,proto3" json:"actPrior,omitempty"` + Tag string `protobuf:"bytes,9,opt,name=tag,proto3" json:"tag,omitempty"` + TimeoutMs uint64 `protobuf:"varint,10,opt,name=timeoutMs,proto3" json:"timeoutMs,omitempty"` + DisableCache bool `protobuf:"varint,11,opt,name=disableCache,proto3" json:"disableCache,omitempty"` + FinalQuery bool `protobuf:"varint,12,opt,name=finalQuery,proto3" json:"finalQuery,omitempty"` + UnexpectedGeoip []*router.GeoIP `protobuf:"bytes,13,rep,name=unexpected_geoip,json=unexpectedGeoip,proto3" json:"unexpected_geoip,omitempty"` + ActUnprior bool `protobuf:"varint,14,opt,name=actUnprior,proto3" json:"actUnprior,omitempty"` } func (x *NameServer) Reset() { @@ -198,9 +205,9 @@ func (x *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain { return nil } -func (x *NameServer) GetGeoip() []*router.GeoIP { +func (x *NameServer) GetExpectedGeoip() []*router.GeoIP { if x != nil { - return x.Geoip + return x.ExpectedGeoip } return nil } @@ -219,9 +226,9 @@ func (x *NameServer) GetQueryStrategy() QueryStrategy { return QueryStrategy_USE_IP } -func (x *NameServer) GetAllowUnexpectedIPs() bool { +func (x *NameServer) GetActPrior() bool { if x != nil { - return x.AllowUnexpectedIPs + return x.ActPrior } return false } @@ -240,6 +247,34 @@ func (x *NameServer) GetTimeoutMs() uint64 { return 0 } +func (x *NameServer) GetDisableCache() bool { + if x != nil { + return x.DisableCache + } + return false +} + +func (x *NameServer) GetFinalQuery() bool { + if x != nil { + return x.FinalQuery + } + return false +} + +func (x *NameServer) GetUnexpectedGeoip() []*router.GeoIP { + if x != nil { + return x.UnexpectedGeoip + } + return nil +} + +func (x *NameServer) GetActUnprior() bool { + if x != nil { + return x.ActUnprior + } + return false +} + type Config struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -532,7 +567,7 @@ var file_app_dns_config_proto_rawDesc = []byte{ 0x2e, 0x64, 0x6e, 0x73, 0x1a, 0x1c, 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, 0x17, 0x61, 0x70, 0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x92, 0x05, 0x0a, 0x0a, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x06, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, @@ -546,81 +581,92 @@ var file_app_dns_config_proto_rawDesc = []byte{ 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x11, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, - 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, - 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, - 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, - 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, - 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, - 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, - 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, - 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, - 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x6c, 0x6c, 0x6f, - 0x77, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x49, 0x50, 0x73, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x6e, 0x65, 0x78, 0x70, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x49, 0x50, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, - 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, - 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, - 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, - 0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0b, 0x6e, - 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, - 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, - 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, - 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, - 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x42, - 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, - 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, - 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, - 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16, - 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, - 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, - 0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, - 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, - 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, - 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, - 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, - 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 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, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, - 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, - 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 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, + 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3d, 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x4c, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, + 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, + 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, + 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, + 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74, + 0x50, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x63, 0x74, + 0x50, 0x72, 0x69, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x4d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, + 0x69, 0x6e, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x10, 0x75, 0x6e, 0x65, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0d, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, + 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0f, 0x75, 0x6e, 0x65, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, + 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x1a, 0x5e, 0x0a, 0x0e, + 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, + 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, + 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, + 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x73, 0x69, 0x7a, 0x65, 0x22, 0x9c, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, + 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, + 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, + 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, + 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, + 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, + 0x68, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, + 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, + 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, + 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, + 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, + 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, + 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, + 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, + 0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 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, 0x2a, 0x42, 0x0a, 0x0d, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, + 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, + 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, + 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x10, 0x03, 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 ( @@ -651,19 +697,20 @@ var file_app_dns_config_proto_goTypes = []any{ var file_app_dns_config_proto_depIdxs = []int32{ 7, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint 4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain - 8, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP + 8, // 2: xray.app.dns.NameServer.expected_geoip:type_name -> xray.app.router.GeoIP 5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule 1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy - 2, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer - 6, // 6: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping - 1, // 7: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy - 0, // 8: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType - 0, // 9: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType - 10, // [10:10] is the sub-list for method output_type - 10, // [10:10] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 8, // 5: xray.app.dns.NameServer.unexpected_geoip:type_name -> xray.app.router.GeoIP + 2, // 6: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer + 6, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping + 1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy + 0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType + 0, // 10: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_app_dns_config_proto_init() } diff --git a/app/dns/config.proto b/app/dns/config.proto index 8935ffa8..4317d0d7 100644 --- a/app/dns/config.proto +++ b/app/dns/config.proto @@ -25,12 +25,16 @@ message NameServer { } repeated PriorityDomain prioritized_domain = 2; - repeated xray.app.router.GeoIP geoip = 3; + repeated xray.app.router.GeoIP expected_geoip = 3; repeated OriginalRule original_rules = 4; QueryStrategy query_strategy = 7; - bool allowUnexpectedIPs = 8; + bool actPrior = 8; string tag = 9; uint64 timeoutMs = 10; + bool disableCache = 11; + bool finalQuery = 12; + repeated xray.app.router.GeoIP unexpected_geoip = 13; + bool actUnprior = 14; } enum DomainMatchingType { @@ -44,6 +48,7 @@ enum QueryStrategy { USE_IP = 0; USE_IP4 = 1; USE_IP6 = 2; + USE_SYS = 3; } message Config { diff --git a/app/dns/dns.go b/app/dns/dns.go index 3b9cfbcb..863a3b52 100644 --- a/app/dns/dns.go +++ b/app/dns/dns.go @@ -28,6 +28,7 @@ type DNS struct { ctx context.Context domainMatcher strmatcher.IndexMatcher matcherInfos []*DomainMatcherInfo + checkSystem bool } // DomainMatcherInfo contains information attached to index returned by Server.domainMatcher @@ -47,6 +48,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) { } var ipOption dns.IPOption + checkSystem := false switch config.QueryStrategy { case QueryStrategy_USE_IP: ipOption = dns.IPOption{ @@ -54,6 +56,13 @@ func New(ctx context.Context, config *Config) (*DNS, error) { IPv6Enable: true, FakeEnable: false, } + case QueryStrategy_USE_SYS: + ipOption = dns.IPOption{ + IPv4Enable: true, + IPv6Enable: true, + FakeEnable: false, + } + checkSystem = true case QueryStrategy_USE_IP4: ipOption = dns.IPOption{ IPv4Enable: true, @@ -108,7 +117,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) { myClientIP = net.IP(ns.ClientIp) } - disableCache := config.DisableCache + disableCache := config.DisableCache || ns.DisableCache var tag = defaultTag if len(ns.Tag) > 0 { @@ -118,6 +127,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) { if !clientIPOption.IPv4Enable && !clientIPOption.IPv6Enable { return nil, errors.New("no QueryStrategy available for ", ns.Address) } + client, err := NewClient(ctx, ns, myClientIP, disableCache, tag, clientIPOption, &matcherInfos, updateDomain) if err != nil { return nil, errors.New("failed to create client").Base(err) @@ -139,6 +149,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) { matcherInfos: matcherInfos, disableFallback: config.DisableFallback, disableFallbackIfMatch: config.DisableFallbackIfMatch, + checkSystem: checkSystem, }, nil } @@ -179,8 +190,14 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er return nil, 0, errors.New("empty domain name") } - option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable - option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable + if s.checkSystem { + supportIPv4, supportIPv6 := checkSystemNetwork() + option.IPv4Enable = option.IPv4Enable && supportIPv4 + option.IPv6Enable = option.IPv6Enable && supportIPv6 + } else { + option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable + option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable + } if !option.IPv4Enable && !option.IPv6Enable { return nil, 0, dns.ErrEmptyResponse @@ -227,6 +244,9 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er } errs = append(errs, err) + if client.IsFinalQuery() { + break + } } if len(errs) > 0 { @@ -318,3 +338,22 @@ func init() { return New(ctx, config.(*Config)) })) } + +func checkSystemNetwork() (supportIPv4 bool, supportIPv6 bool) { + conn4, err4 := net.Dial("udp4", "8.8.8.8:53") + if err4 != nil { + supportIPv4 = false + } else { + supportIPv4 = true + conn4.Close() + } + + conn6, err6 := net.Dial("udp6", "[2001:4860:4860::8888]:53") + if err6 != nil { + supportIPv6 = false + } else { + supportIPv6 = true + conn6.Close() + } + return +} diff --git a/app/dns/dns_test.go b/app/dns/dns_test.go index 7ea6fcf8..cb70b0b3 100644 --- a/app/dns/dns_test.go +++ b/app/dns/dns_test.go @@ -539,7 +539,7 @@ func TestIPMatch(t *testing.T) { }, Port: uint32(port), }, - Geoip: []*router.GeoIP{ + ExpectedGeoip: []*router.GeoIP{ { CountryCode: "local", Cidr: []*router.CIDR{ @@ -563,7 +563,7 @@ func TestIPMatch(t *testing.T) { }, Port: uint32(port), }, - Geoip: []*router.GeoIP{ + ExpectedGeoip: []*router.GeoIP{ { CountryCode: "test", Cidr: []*router.CIDR{ @@ -667,7 +667,7 @@ func TestLocalDomain(t *testing.T) { // Equivalent of dotless:localhost {Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"}, }, - Geoip: []*router.GeoIP{ + ExpectedGeoip: []*router.GeoIP{ { // Will match localhost, localhost-a and localhost-b, CountryCode: "local", Cidr: []*router.CIDR{ @@ -897,7 +897,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { Domain: "google.com", }, }, - Geoip: []*router.GeoIP{ + ExpectedGeoip: []*router.GeoIP{ { // Will only match 8.8.8.8 and 8.8.4.4 Cidr: []*router.CIDR{ {Ip: []byte{8, 8, 8, 8}, Prefix: 32}, @@ -922,7 +922,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { Domain: "google.com", }, }, - Geoip: []*router.GeoIP{ + ExpectedGeoip: []*router.GeoIP{ { // Will match 8.8.8.8 and 8.8.8.7, etc Cidr: []*router.CIDR{ {Ip: []byte{8, 8, 8, 7}, Prefix: 24}, @@ -946,7 +946,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { Domain: "api.google.com", }, }, - Geoip: []*router.GeoIP{ + ExpectedGeoip: []*router.GeoIP{ { // Will only match 8.8.7.7 (api.google.com) Cidr: []*router.CIDR{ {Ip: []byte{8, 8, 7, 7}, Prefix: 32}, @@ -970,7 +970,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) { Domain: "v2.api.google.com", }, }, - Geoip: []*router.GeoIP{ + ExpectedGeoip: []*router.GeoIP{ { // Will only match 8.8.7.8 (v2.api.google.com) Cidr: []*router.CIDR{ {Ip: []byte{8, 8, 7, 8}, Prefix: 32}, diff --git a/app/dns/nameserver.go b/app/dns/nameserver.go index 31681c4a..cf1b665b 100644 --- a/app/dns/nameserver.go +++ b/app/dns/nameserver.go @@ -26,14 +26,18 @@ type Server interface { // Client is the interface for DNS client. type Client struct { - server Server - skipFallback bool - domains []string - expectedIPs []*router.GeoIPMatcher - allowUnexpectedIPs bool - tag string - timeoutMs time.Duration - ipOption *dns.IPOption + server Server + skipFallback bool + domains []string + expectedIPs []*router.GeoIPMatcher + unexpectedIPs []*router.GeoIPMatcher + actPrior bool + actUnprior bool + tag string + timeoutMs time.Duration + finalQuery bool + ipOption *dns.IPOption + checkSystem bool } // NewServer creates a name server object according to the network destination url. @@ -150,13 +154,23 @@ func NewClient( } // Establish expected IPs - var matchers []*router.GeoIPMatcher - for _, geoip := range ns.Geoip { + var expectedMatchers []*router.GeoIPMatcher + for _, geoip := range ns.ExpectedGeoip { matcher, err := router.GlobalGeoIPContainer.Add(geoip) if err != nil { - return errors.New("failed to create ip matcher").Base(err).AtWarning() + return errors.New("failed to create expected ip matcher").Base(err).AtWarning() } - matchers = append(matchers, matcher) + expectedMatchers = append(expectedMatchers, matcher) + } + + // Establish unexpected IPs + var unexpectedMatchers []*router.GeoIPMatcher + for _, geoip := range ns.UnexpectedGeoip { + matcher, err := router.GlobalGeoIPContainer.Add(geoip) + if err != nil { + return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning() + } + unexpectedMatchers = append(unexpectedMatchers, matcher) } if len(clientIP) > 0 { @@ -173,14 +187,20 @@ func NewClient( timeoutMs = time.Duration(ns.TimeoutMs) * time.Millisecond } + checkSystem := ns.QueryStrategy == QueryStrategy_USE_SYS + client.server = server client.skipFallback = ns.SkipFallback client.domains = rules - client.expectedIPs = matchers - client.allowUnexpectedIPs = ns.AllowUnexpectedIPs + client.expectedIPs = expectedMatchers + client.unexpectedIPs = unexpectedMatchers + client.actPrior = ns.ActPrior + client.actUnprior = ns.ActUnprior client.tag = tag client.timeoutMs = timeoutMs + client.finalQuery = ns.FinalQuery client.ipOption = &ipOption + client.checkSystem = checkSystem return nil }) return client, err @@ -191,10 +211,21 @@ func (c *Client) Name() string { return c.server.Name() } +func (c *Client) IsFinalQuery() bool { + return c.finalQuery +} + // QueryIP sends DNS query to the name server with the client's IP. func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error) { - option.IPv4Enable = option.IPv4Enable && c.ipOption.IPv4Enable - option.IPv6Enable = option.IPv6Enable && c.ipOption.IPv6Enable + if c.checkSystem { + supportIPv4, supportIPv6 := checkSystemNetwork() + option.IPv4Enable = option.IPv4Enable && supportIPv4 + option.IPv6Enable = option.IPv6Enable && supportIPv6 + } else { + option.IPv4Enable = option.IPv4Enable && c.ipOption.IPv4Enable + option.IPv6Enable = option.IPv6Enable && c.ipOption.IPv6Enable + } + if !option.IPv4Enable && !option.IPv6Enable { return nil, 0, dns.ErrEmptyResponse } @@ -212,39 +243,47 @@ func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption return nil, 0, dns.ErrEmptyResponse } - if len(c.expectedIPs) > 0 { - newIps := c.MatchExpectedIPs(domain, ips) - if len(newIps) == 0 { - if !c.allowUnexpectedIPs { - return nil, 0, dns.ErrEmptyResponse - } - } else { - ips = newIps + if len(c.expectedIPs) > 0 && !c.actPrior { + ips = router.MatchIPs(c.expectedIPs, ips, false) + errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", ips, " matched at server ", c.Name()) + if len(ips) == 0 { + return nil, 0, dns.ErrEmptyResponse + } + } + + if len(c.unexpectedIPs) > 0 && !c.actUnprior { + ips = router.MatchIPs(c.unexpectedIPs, ips, true) + errors.LogDebug(context.Background(), "domain ", domain, " unexpectedIPs ", ips, " matched at server ", c.Name()) + if len(ips) == 0 { + return nil, 0, dns.ErrEmptyResponse + } + } + + if len(c.expectedIPs) > 0 && c.actPrior { + ipsNew := router.MatchIPs(c.expectedIPs, ips, false) + if len(ipsNew) > 0 { + ips = ipsNew + errors.LogDebug(context.Background(), "domain ", domain, " priorIPs ", ips, " matched at server ", c.Name()) + } + } + + if len(c.unexpectedIPs) > 0 && c.actUnprior { + ipsNew := router.MatchIPs(c.unexpectedIPs, ips, true) + if len(ipsNew) > 0 { + ips = ipsNew + errors.LogDebug(context.Background(), "domain ", domain, " unpriorIPs ", ips, " matched at server ", c.Name()) } } return ips, ttl, nil } -// MatchExpectedIPs matches queried domain IPs with expected IPs and returns matched ones. -func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) []net.IP { - var newIps []net.IP - for _, ip := range ips { - for _, matcher := range c.expectedIPs { - if matcher.Match(ip) { - newIps = append(newIps, ip) - break - } - } - } - errors.LogDebug(context.Background(), "domain ", domain, " expectedIPs ", newIps, " matched at server ", c.Name()) - return newIps -} - func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption { switch queryStrategy { case QueryStrategy_USE_IP: return ipOption + case QueryStrategy_USE_SYS: + return ipOption case QueryStrategy_USE_IP4: return dns.IPOption{ IPv4Enable: ipOption.IPv4Enable, diff --git a/app/router/condition_geoip.go b/app/router/condition_geoip.go index 0140cdfb..38f7f0ce 100644 --- a/app/router/condition_geoip.go +++ b/app/router/condition_geoip.go @@ -116,3 +116,29 @@ func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) { } var GlobalGeoIPContainer GeoIPMatcherContainer + +func MatchIPs(matchers []*GeoIPMatcher, ips []net.IP, reverse bool) []net.IP { + if len(matchers) == 0 { + panic("GeoIP matchers should not be empty to avoid ambiguity") + } + newIPs := make([]net.IP, 0, len(ips)) + var isFound bool + for _, ip := range ips { + isFound = false + for _, matcher := range matchers { + if matcher.Match(ip) { + isFound = true + break + } + } + if isFound && !reverse { + newIPs = append(newIPs, ip) + continue + } + if !isFound && reverse { + newIPs = append(newIPs, ip) + continue + } + } + return newIPs +} diff --git a/infra/conf/dns.go b/infra/conf/dns.go index 5e870d1d..cd885ce1 100644 --- a/infra/conf/dns.go +++ b/infra/conf/dns.go @@ -1,8 +1,13 @@ package conf import ( + "bufio" "bytes" "encoding/json" + "os" + "path/filepath" + "runtime" + "sort" "strings" "github.com/xtls/xray-core/app/dns" @@ -12,17 +17,19 @@ import ( ) type NameServerConfig struct { - Address *Address `json:"address"` - ClientIP *Address `json:"clientIp"` - Port uint16 `json:"port"` - SkipFallback bool `json:"skipFallback"` - Domains []string `json:"domains"` - ExpectedIPs StringList `json:"expectedIPs"` - ExpectIPs StringList `json:"expectIPs"` - QueryStrategy string `json:"queryStrategy"` - AllowUnexpectedIPs bool `json:"allowUnexpectedIps"` - Tag string `json:"tag"` - TimeoutMs uint64 `json:"timeoutMs"` + Address *Address `json:"address"` + ClientIP *Address `json:"clientIp"` + Port uint16 `json:"port"` + SkipFallback bool `json:"skipFallback"` + Domains []string `json:"domains"` + ExpectedIPs StringList `json:"expectedIPs"` + ExpectIPs StringList `json:"expectIPs"` + QueryStrategy string `json:"queryStrategy"` + Tag string `json:"tag"` + TimeoutMs uint64 `json:"timeoutMs"` + DisableCache bool `json:"disableCache"` + FinalQuery bool `json:"finalQuery"` + UnexpectedIPs StringList `json:"unexpectedIPs"` } // UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON @@ -34,17 +41,19 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error { } var advanced struct { - Address *Address `json:"address"` - ClientIP *Address `json:"clientIp"` - Port uint16 `json:"port"` - SkipFallback bool `json:"skipFallback"` - Domains []string `json:"domains"` - ExpectedIPs StringList `json:"expectedIPs"` - ExpectIPs StringList `json:"expectIPs"` - QueryStrategy string `json:"queryStrategy"` - AllowUnexpectedIPs bool `json:"allowUnexpectedIps"` - Tag string `json:"tag"` - TimeoutMs uint64 `json:"timeoutMs"` + Address *Address `json:"address"` + ClientIP *Address `json:"clientIp"` + Port uint16 `json:"port"` + SkipFallback bool `json:"skipFallback"` + Domains []string `json:"domains"` + ExpectedIPs StringList `json:"expectedIPs"` + ExpectIPs StringList `json:"expectIPs"` + QueryStrategy string `json:"queryStrategy"` + Tag string `json:"tag"` + TimeoutMs uint64 `json:"timeoutMs"` + DisableCache bool `json:"disableCache"` + FinalQuery bool `json:"finalQuery"` + UnexpectedIPs StringList `json:"unexpectedIPs"` } if err := json.Unmarshal(data, &advanced); err == nil { c.Address = advanced.Address @@ -55,9 +64,11 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error { c.ExpectedIPs = advanced.ExpectedIPs c.ExpectIPs = advanced.ExpectIPs c.QueryStrategy = advanced.QueryStrategy - c.AllowUnexpectedIPs = advanced.AllowUnexpectedIPs c.Tag = advanced.Tag c.TimeoutMs = advanced.TimeoutMs + c.DisableCache = advanced.DisableCache + c.FinalQuery = advanced.FinalQuery + c.UnexpectedIPs = advanced.UnexpectedIPs return nil } @@ -105,13 +116,38 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) { }) } - var expectedIPs = c.ExpectedIPs - if len(expectedIPs) == 0 { - expectedIPs = c.ExpectIPs + if len(c.ExpectedIPs) == 0 { + c.ExpectedIPs = c.ExpectIPs } - geoipList, err := ToCidrList(expectedIPs) + + actPrior := false + var newExpectedIPs StringList + for _, s := range c.ExpectedIPs { + if s == "*" { + actPrior = true + } else { + newExpectedIPs = append(newExpectedIPs, s) + } + } + + actUnprior := false + var newUnexpectedIPs StringList + for _, s := range c.UnexpectedIPs { + if s == "*" { + actUnprior = true + } else { + newUnexpectedIPs = append(newUnexpectedIPs, s) + } + } + + expectedGeoipList, err := ToCidrList(newExpectedIPs) if err != nil { - return nil, errors.New("invalid IP rule: ", expectedIPs).Base(err) + return nil, errors.New("invalid expected IP rule: ", c.ExpectedIPs).Base(err) + } + + unexpectedGeoipList, err := ToCidrList(newUnexpectedIPs) + if err != nil { + return nil, errors.New("invalid unexpected IP rule: ", c.UnexpectedIPs).Base(err) } var myClientIP []byte @@ -128,15 +164,19 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) { Address: c.Address.Build(), Port: uint32(c.Port), }, - ClientIp: myClientIP, - SkipFallback: c.SkipFallback, - PrioritizedDomain: domains, - Geoip: geoipList, - OriginalRules: originalRules, - QueryStrategy: resolveQueryStrategy(c.QueryStrategy), - AllowUnexpectedIPs: c.AllowUnexpectedIPs, - Tag: c.Tag, - TimeoutMs: c.TimeoutMs, + ClientIp: myClientIP, + SkipFallback: c.SkipFallback, + PrioritizedDomain: domains, + ExpectedGeoip: expectedGeoipList, + OriginalRules: originalRules, + QueryStrategy: resolveQueryStrategy(c.QueryStrategy), + ActPrior: actPrior, + Tag: c.Tag, + TimeoutMs: c.TimeoutMs, + DisableCache: c.DisableCache, + FinalQuery: c.FinalQuery, + UnexpectedGeoip: unexpectedGeoipList, + ActUnprior: actUnprior, }, nil } @@ -157,6 +197,7 @@ type DNSConfig struct { DisableCache bool `json:"disableCache"` DisableFallback bool `json:"disableFallback"` DisableFallbackIfMatch bool `json:"disableFallbackIfMatch"` + UseSystemHosts bool `json:"useSystemHosts"` } type HostAddress struct { @@ -418,6 +459,15 @@ func (c *DNSConfig) Build() (*dns.Config, error) { } config.StaticHosts = append(config.StaticHosts, staticHosts...) } + if c.UseSystemHosts { + systemHosts, err := readSystemHosts() + if err != nil { + return nil, errors.New("failed to read system hosts").Base(err) + } + for domain, ips := range systemHosts { + config.StaticHosts = append(config.StaticHosts, &dns.Config_HostMapping{Ip: ips, Domain: domain, Type: dns.DomainMatchingType_Full}) + } + } return config, nil } @@ -430,7 +480,91 @@ func resolveQueryStrategy(queryStrategy string) dns.QueryStrategy { return dns.QueryStrategy_USE_IP4 case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6": return dns.QueryStrategy_USE_IP6 + case "usesys", "usesystem", "use_sys", "use_system", "use-sys", "use-system": + return dns.QueryStrategy_USE_SYS default: return dns.QueryStrategy_USE_IP } } + +func readSystemHosts() (map[string][][]byte, error) { + var hostsPath string + switch runtime.GOOS { + case "windows": + hostsPath = filepath.Join(os.Getenv("SystemRoot"), "System32", "drivers", "etc", "hosts") + default: + hostsPath = "/etc/hosts" + } + + file, err := os.Open(hostsPath) + if err != nil { + return nil, err + } + defer file.Close() + + hostsMap := make(map[string][][]byte) + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if i := strings.IndexByte(line, '#'); i >= 0 { + // Discard comments. + line = line[0:i] + } + f := getFields(line) + if len(f) < 2 { + continue + } + addr := net.ParseAddress(f[0]) + if addr.Family().IsDomain() { + continue + } + ip := addr.IP() + for i := 1; i < len(f); i++ { + domain := strings.TrimSuffix(f[i], ".") + domain = strings.ToLower(domain) + if v, ok := hostsMap[domain]; ok { + hostsMap[domain] = append(v, ip) + } else { + hostsMap[domain] = [][]byte{ip} + } + } + } + if err := scanner.Err(); err != nil { + return nil, err + } + return hostsMap, nil +} + +func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") } + +// Count occurrences in s of any bytes in t. +func countAnyByte(s string, t string) int { + n := 0 + for i := 0; i < len(s); i++ { + if strings.IndexByte(t, s[i]) >= 0 { + n++ + } + } + return n +} + +// Split s at any bytes in t. +func splitAtBytes(s string, t string) []string { + a := make([]string, 1+countAnyByte(s, t)) + n := 0 + last := 0 + for i := 0; i < len(s); i++ { + if strings.IndexByte(t, s[i]) >= 0 { + if last < i { + a[n] = s[last:i] + n++ + } + last = i + 1 + } + } + if last < len(s) { + a[n] = s[last:] + n++ + } + return a[0:n] +} diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index b4ae0801..b5790fe0 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -699,25 +699,34 @@ type CustomSockoptConfig struct { Type string `json:"type"` } +type HappyEyeballsConfig struct { + Enabled bool `json:"enabled"` + PrioritizeIPv6 bool `json:"prioritizeIPv6"` + TryDelayMs uint64 `json:"tryDelayMs"` + Interleave uint32 `json:"interleave"` + MaxConcurrentTry uint32 `json:"maxConcurrentTry"` +} + type SocketConfig struct { - Mark int32 `json:"mark"` - TFO interface{} `json:"tcpFastOpen"` - TProxy string `json:"tproxy"` - AcceptProxyProtocol bool `json:"acceptProxyProtocol"` - DomainStrategy string `json:"domainStrategy"` - DialerProxy string `json:"dialerProxy"` - TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"` - TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"` - TCPCongestion string `json:"tcpCongestion"` - TCPWindowClamp int32 `json:"tcpWindowClamp"` - TCPMaxSeg int32 `json:"tcpMaxSeg"` - Penetrate bool `json:"penetrate"` - TCPUserTimeout int32 `json:"tcpUserTimeout"` - V6only bool `json:"v6only"` - Interface string `json:"interface"` - TcpMptcp bool `json:"tcpMptcp"` - CustomSockopt []*CustomSockoptConfig `json:"customSockopt"` - AddressPortStrategy string `json:"addressPortStrategy"` + Mark int32 `json:"mark"` + TFO interface{} `json:"tcpFastOpen"` + TProxy string `json:"tproxy"` + AcceptProxyProtocol bool `json:"acceptProxyProtocol"` + DomainStrategy string `json:"domainStrategy"` + DialerProxy string `json:"dialerProxy"` + TCPKeepAliveInterval int32 `json:"tcpKeepAliveInterval"` + TCPKeepAliveIdle int32 `json:"tcpKeepAliveIdle"` + TCPCongestion string `json:"tcpCongestion"` + TCPWindowClamp int32 `json:"tcpWindowClamp"` + TCPMaxSeg int32 `json:"tcpMaxSeg"` + Penetrate bool `json:"penetrate"` + TCPUserTimeout int32 `json:"tcpUserTimeout"` + V6only bool `json:"v6only"` + Interface string `json:"interface"` + TcpMptcp bool `json:"tcpMptcp"` + CustomSockopt []*CustomSockoptConfig `json:"customSockopt"` + AddressPortStrategy string `json:"addressPortStrategy"` + HappyEyeballsSettings *HappyEyeballsConfig `json:"happyEyeballs"` } // Build implements Buildable. @@ -809,6 +818,21 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { return nil, errors.New("unsupported address and port strategy: ", c.AddressPortStrategy) } + var happyEyeballs = &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, PrioritizeIpv6: false, TryDelayMs: 250, MaxConcurrentTry: 4} + if c.HappyEyeballsSettings != nil { + happyEyeballs.Enabled = c.HappyEyeballsSettings.Enabled + happyEyeballs.PrioritizeIpv6 = c.HappyEyeballsSettings.PrioritizeIPv6 + if c.HappyEyeballsSettings.Interleave > 0 { + happyEyeballs.Interleave = c.HappyEyeballsSettings.Interleave + } + if c.HappyEyeballsSettings.TryDelayMs > 0 { + happyEyeballs.TryDelayMs = c.HappyEyeballsSettings.TryDelayMs + } + if c.HappyEyeballsSettings.MaxConcurrentTry > 0 { + happyEyeballs.MaxConcurrentTry = c.HappyEyeballsSettings.MaxConcurrentTry + } + } + return &internet.SocketConfig{ Mark: c.Mark, Tfo: tfo, @@ -828,6 +852,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { TcpMptcp: c.TcpMptcp, CustomSockopt: customSockopts, AddressPortStrategy: addressPortStrategy, + HappyEyeballs: happyEyeballs, }, nil } diff --git a/infra/conf/transport_test.go b/infra/conf/transport_test.go index e7470082..0261540d 100644 --- a/infra/conf/transport_test.go +++ b/infra/conf/transport_test.go @@ -26,6 +26,7 @@ func TestSocketConfig(t *testing.T) { Tfo: 256, DomainStrategy: internet.DomainStrategy_USE_IP, DialerProxy: "tag", + HappyEyeballs: &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, TryDelayMs: 250, PrioritizeIpv6: false, MaxConcurrentTry: 4}, } runMultiTestCase(t, []TestCase{ { @@ -45,8 +46,9 @@ func TestSocketConfig(t *testing.T) { // test "tcpFastOpen": false, disabled TFO is expected expectedOutput = &internet.SocketConfig{ - Mark: 0, - Tfo: -1, + Mark: 0, + Tfo: -1, + HappyEyeballs: &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, TryDelayMs: 250, PrioritizeIpv6: false, MaxConcurrentTry: 4}, } runMultiTestCase(t, []TestCase{ { @@ -63,8 +65,9 @@ func TestSocketConfig(t *testing.T) { // test "tcpFastOpen": 65535, queue length 65535 is expected expectedOutput = &internet.SocketConfig{ - Mark: 0, - Tfo: 65535, + Mark: 0, + Tfo: 65535, + HappyEyeballs: &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, TryDelayMs: 250, PrioritizeIpv6: false, MaxConcurrentTry: 4}, } runMultiTestCase(t, []TestCase{ { @@ -81,8 +84,9 @@ func TestSocketConfig(t *testing.T) { // test "tcpFastOpen": -65535, disable TFO is expected expectedOutput = &internet.SocketConfig{ - Mark: 0, - Tfo: -65535, + Mark: 0, + Tfo: -65535, + HappyEyeballs: &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, TryDelayMs: 250, PrioritizeIpv6: false, MaxConcurrentTry: 4}, } runMultiTestCase(t, []TestCase{ { @@ -99,8 +103,9 @@ func TestSocketConfig(t *testing.T) { // test "tcpFastOpen": 0, no operation is expected expectedOutput = &internet.SocketConfig{ - Mark: 0, - Tfo: 0, + Mark: 0, + Tfo: 0, + HappyEyeballs: &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, TryDelayMs: 250, PrioritizeIpv6: false, MaxConcurrentTry: 4}, } runMultiTestCase(t, []TestCase{ { @@ -117,8 +122,9 @@ func TestSocketConfig(t *testing.T) { // test omit "tcpFastOpen", no operation is expected expectedOutput = &internet.SocketConfig{ - Mark: 0, - Tfo: 0, + Mark: 0, + Tfo: 0, + HappyEyeballs: &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, TryDelayMs: 250, PrioritizeIpv6: false, MaxConcurrentTry: 4}, } runMultiTestCase(t, []TestCase{ { @@ -133,8 +139,9 @@ func TestSocketConfig(t *testing.T) { // test "tcpFastOpen": null, no operation is expected expectedOutput = &internet.SocketConfig{ - Mark: 0, - Tfo: 0, + Mark: 0, + Tfo: 0, + HappyEyeballs: &internet.HappyEyeballsConfig{Enabled: true, Interleave: 1, TryDelayMs: 250, PrioritizeIpv6: false, MaxConcurrentTry: 4}, } runMultiTestCase(t, []TestCase{ { diff --git a/transport/internet/config.pb.go b/transport/internet/config.pb.go index 6aa11b3e..31fccde1 100644 --- a/transport/internet/config.pb.go +++ b/transport/internet/config.pb.go @@ -511,24 +511,25 @@ type SocketConfig struct { Tproxy SocketConfig_TProxyMode `protobuf:"varint,3,opt,name=tproxy,proto3,enum=xray.transport.internet.SocketConfig_TProxyMode" json:"tproxy,omitempty"` // ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket // option. This option is for UDP only. - ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"` - BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"` - BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"` - AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"` - DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"` - DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"` - TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"` - TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"` - TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"` - Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"` - V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"` - TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"` - TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"` - TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"` - Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"` - TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"` - CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"` - AddressPortStrategy AddressPortStrategy `protobuf:"varint,21,opt,name=address_port_strategy,json=addressPortStrategy,proto3,enum=xray.transport.internet.AddressPortStrategy" json:"address_port_strategy,omitempty"` + ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"` + BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"` + BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"` + AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"` + DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"` + DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"` + TcpKeepAliveInterval int32 `protobuf:"varint,10,opt,name=tcp_keep_alive_interval,json=tcpKeepAliveInterval,proto3" json:"tcp_keep_alive_interval,omitempty"` + TcpKeepAliveIdle int32 `protobuf:"varint,11,opt,name=tcp_keep_alive_idle,json=tcpKeepAliveIdle,proto3" json:"tcp_keep_alive_idle,omitempty"` + TcpCongestion string `protobuf:"bytes,12,opt,name=tcp_congestion,json=tcpCongestion,proto3" json:"tcp_congestion,omitempty"` + Interface string `protobuf:"bytes,13,opt,name=interface,proto3" json:"interface,omitempty"` + V6Only bool `protobuf:"varint,14,opt,name=v6only,proto3" json:"v6only,omitempty"` + TcpWindowClamp int32 `protobuf:"varint,15,opt,name=tcp_window_clamp,json=tcpWindowClamp,proto3" json:"tcp_window_clamp,omitempty"` + TcpUserTimeout int32 `protobuf:"varint,16,opt,name=tcp_user_timeout,json=tcpUserTimeout,proto3" json:"tcp_user_timeout,omitempty"` + TcpMaxSeg int32 `protobuf:"varint,17,opt,name=tcp_max_seg,json=tcpMaxSeg,proto3" json:"tcp_max_seg,omitempty"` + Penetrate bool `protobuf:"varint,18,opt,name=penetrate,proto3" json:"penetrate,omitempty"` + TcpMptcp bool `protobuf:"varint,19,opt,name=tcp_mptcp,json=tcpMptcp,proto3" json:"tcp_mptcp,omitempty"` + CustomSockopt []*CustomSockopt `protobuf:"bytes,20,rep,name=customSockopt,proto3" json:"customSockopt,omitempty"` + AddressPortStrategy AddressPortStrategy `protobuf:"varint,21,opt,name=address_port_strategy,json=addressPortStrategy,proto3,enum=xray.transport.internet.AddressPortStrategy" json:"address_port_strategy,omitempty"` + HappyEyeballs *HappyEyeballsConfig `protobuf:"bytes,22,opt,name=happy_eyeballs,json=happyEyeballs,proto3" json:"happy_eyeballs,omitempty"` } func (x *SocketConfig) Reset() { @@ -708,6 +709,90 @@ func (x *SocketConfig) GetAddressPortStrategy() AddressPortStrategy { return AddressPortStrategy_None } +func (x *SocketConfig) GetHappyEyeballs() *HappyEyeballsConfig { + if x != nil { + return x.HappyEyeballs + } + return nil +} + +type HappyEyeballsConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + PrioritizeIpv6 bool `protobuf:"varint,2,opt,name=prioritize_ipv6,json=prioritizeIpv6,proto3" json:"prioritize_ipv6,omitempty"` + Interleave uint32 `protobuf:"varint,3,opt,name=interleave,proto3" json:"interleave,omitempty"` + TryDelayMs uint64 `protobuf:"varint,4,opt,name=try_delayMs,json=tryDelayMs,proto3" json:"try_delayMs,omitempty"` + MaxConcurrentTry uint32 `protobuf:"varint,5,opt,name=max_concurrent_try,json=maxConcurrentTry,proto3" json:"max_concurrent_try,omitempty"` +} + +func (x *HappyEyeballsConfig) Reset() { + *x = HappyEyeballsConfig{} + mi := &file_transport_internet_config_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HappyEyeballsConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HappyEyeballsConfig) ProtoMessage() {} + +func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message { + mi := &file_transport_internet_config_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead. +func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) { + return file_transport_internet_config_proto_rawDescGZIP(), []int{5} +} + +func (x *HappyEyeballsConfig) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool { + if x != nil { + return x.PrioritizeIpv6 + } + return false +} + +func (x *HappyEyeballsConfig) GetInterleave() uint32 { + if x != nil { + return x.Interleave + } + return 0 +} + +func (x *HappyEyeballsConfig) GetTryDelayMs() uint64 { + if x != nil { + return x.TryDelayMs + } + return 0 +} + +func (x *HappyEyeballsConfig) GetMaxConcurrentTry() uint32 { + if x != nil { + return x.MaxConcurrentTry + } + return 0 +} + var File_transport_internet_config_proto protoreflect.FileDescriptor var file_transport_internet_config_proto_rawDesc = []byte{ @@ -766,7 +851,7 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0xfd, 0x07, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, + 0x74, 0x79, 0x70, 0x65, 0x22, 0xd2, 0x08, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x74, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x06, 0x74, @@ -827,37 +912,55 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x13, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, - 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, - 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x10, 0x02, 0x2a, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, - 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, - 0x49, 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, - 0x36, 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, - 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, - 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, - 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, - 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, - 0x2a, 0x97, 0x01, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, - 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, - 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, - 0x79, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x72, 0x76, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x72, 0x76, 0x50, 0x6f, - 0x72, 0x74, 0x41, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x03, 0x12, 0x0f, - 0x0a, 0x0b, 0x54, 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x04, 0x12, - 0x12, 0x0a, 0x0e, 0x54, 0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, - 0x79, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x41, 0x6e, - 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x06, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, - 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 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, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x67, 0x79, 0x12, 0x53, 0x0a, 0x0e, 0x68, 0x61, 0x70, 0x70, 0x79, 0x5f, 0x65, 0x79, 0x65, + 0x62, 0x61, 0x6c, 0x6c, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 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, 0x48, 0x61, 0x70, 0x70, 0x79, 0x45, 0x79, 0x65, 0x62, 0x61, + 0x6c, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x68, 0x61, 0x70, 0x70, 0x79, + 0x45, 0x79, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x73, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, + 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, + 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, + 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x22, 0xc7, 0x01, 0x0a, 0x13, 0x48, 0x61, + 0x70, 0x70, 0x79, 0x45, 0x79, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x73, 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, 0x27, 0x0a, 0x0f, 0x70, + 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, 0x5f, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x7a, 0x65, + 0x49, 0x70, 0x76, 0x36, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x65, 0x61, + 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, + 0x65, 0x61, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, 0x79, 0x5f, 0x64, 0x65, 0x6c, 0x61, + 0x79, 0x4d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x72, 0x79, 0x44, 0x65, + 0x6c, 0x61, 0x79, 0x4d, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x54, 0x72, 0x79, 0x2a, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, + 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, + 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, + 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, + 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x10, + 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x07, + 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x08, 0x12, + 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x09, 0x12, + 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, 0x10, 0x0a, 0x2a, + 0x97, 0x01, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x53, + 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, + 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, + 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x72, 0x76, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x72, 0x76, 0x50, 0x6f, 0x72, + 0x74, 0x41, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x03, 0x12, 0x0f, 0x0a, + 0x0b, 0x54, 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x04, 0x12, 0x12, + 0x0a, 0x0e, 0x54, 0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, 0x79, + 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x78, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x41, 0x6e, 0x64, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x06, 0x42, 0x67, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, + 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2c, 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, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x17, 0x58, 0x72, 0x61, 0x79, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -873,7 +976,7 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte { } var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_transport_internet_config_proto_goTypes = []any{ (DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy (AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy @@ -883,24 +986,26 @@ var file_transport_internet_config_proto_goTypes = []any{ (*ProxyConfig)(nil), // 5: xray.transport.internet.ProxyConfig (*CustomSockopt)(nil), // 6: xray.transport.internet.CustomSockopt (*SocketConfig)(nil), // 7: xray.transport.internet.SocketConfig - (*serial.TypedMessage)(nil), // 8: xray.common.serial.TypedMessage - (*net.IPOrDomain)(nil), // 9: xray.common.net.IPOrDomain + (*HappyEyeballsConfig)(nil), // 8: xray.transport.internet.HappyEyeballsConfig + (*serial.TypedMessage)(nil), // 9: xray.common.serial.TypedMessage + (*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain } var file_transport_internet_config_proto_depIdxs = []int32{ - 8, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage - 9, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain - 3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig - 8, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage - 7, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig - 2, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode - 0, // 6: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy - 6, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt - 1, // 8: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy - 9, // [9:9] is the sub-list for method output_type - 9, // [9:9] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 9, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage + 10, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain + 3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig + 9, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage + 7, // 4: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig + 2, // 5: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode + 0, // 6: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy + 6, // 7: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt + 1, // 8: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy + 8, // 9: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_transport_internet_config_proto_init() } @@ -914,7 +1019,7 @@ func file_transport_internet_config_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_transport_internet_config_proto_rawDesc, NumEnums: 3, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/transport/internet/config.proto b/transport/internet/config.proto index cb892c30..d6a981a5 100644 --- a/transport/internet/config.proto +++ b/transport/internet/config.proto @@ -130,4 +130,14 @@ message SocketConfig { repeated CustomSockopt customSockopt = 20; AddressPortStrategy address_port_strategy = 21; + + HappyEyeballsConfig happy_eyeballs = 22; +} + +message HappyEyeballsConfig { + bool enabled = 1; + bool prioritize_ipv6 = 2; + uint32 interleave = 3; + uint64 try_delayMs = 4; + uint32 max_concurrent_try = 5; } diff --git a/transport/internet/dialer.go b/transport/internet/dialer.go index 74e5f0b6..0bc377c8 100644 --- a/transport/internet/dialer.go +++ b/transport/internet/dialer.go @@ -255,9 +255,11 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig if sockopt.DomainStrategy.forceIP() { return nil, err } - } else { + } else if !sockopt.HappyEyeballs.Enabled || len(ips) < 2 || len(sockopt.DialerProxy) > 0 || dest.Network != net.Network_TCP { dest.Address = net.IPAddress(ips[dice.Roll(len(ips))]) errors.LogInfo(ctx, "replace destination with "+dest.String()) + } else { + return TcpRaceDial(ctx, src, ips, dest.Port, sockopt) } } diff --git a/transport/internet/happy_eyeballs.go b/transport/internet/happy_eyeballs.go new file mode 100644 index 00000000..2d795030 --- /dev/null +++ b/transport/internet/happy_eyeballs.go @@ -0,0 +1,165 @@ +package internet + +import ( + "context" + "github.com/xtls/xray-core/common/net" + "time" +) + +type result struct { + err error + conn net.Conn + index int +} + +func TcpRaceDial(ctx context.Context, src net.Address, ips []net.IP, port net.Port, sockopt *SocketConfig) (net.Conn, error) { + if len(ips) < 2 { + panic("at least 2 ips is required to race dial") + } + ips = sortIPs(ips, sockopt.HappyEyeballs.PrioritizeIpv6, sockopt.HappyEyeballs.Interleave) + newCtx, cancel := context.WithCancel(ctx) + defer cancel() + var resultCh = make(chan *result, len(ips)) + nextTryIndex := 0 + activeNum := uint32(0) + timer := time.NewTimer(0) + var winConn net.Conn + for { + select { + case r := <-resultCh: + activeNum-- + select { + case <-ctx.Done(): + cancel() + timer.Stop() + if winConn != nil { + winConn.Close() + } + if r.conn != nil { + r.conn.Close() + } + if activeNum == 0 { + return nil, ctx.Err() + } + continue + default: + if r.conn != nil { + cancel() + timer.Stop() + if winConn == nil { + winConn = r.conn + } else { + r.conn.Close() + } + } + if winConn != nil && activeNum == 0 { + return winConn, nil + } + if winConn != nil { + continue + } + if nextTryIndex < len(ips) { + timer.Reset(0) + continue + } + if activeNum == 0 { + return nil, r.err + } + timer.Stop() + continue + } + + case <-timer.C: + if nextTryIndex == len(ips) || activeNum == sockopt.HappyEyeballs.MaxConcurrentTry { + panic("impossible situation") + } + go tcpTryDial(newCtx, src, sockopt, ips[nextTryIndex], port, nextTryIndex, resultCh) + activeNum++ + nextTryIndex++ + if nextTryIndex == len(ips) || activeNum == sockopt.HappyEyeballs.MaxConcurrentTry { + timer.Stop() + } else { + timer.Reset(time.Duration(sockopt.HappyEyeballs.TryDelayMs) * time.Millisecond) + } + continue + } + } +} + +// sortIPs sort IPs according to rfc 8305. +func sortIPs(ips []net.IP, priorIPv6 bool, interleave uint32) []net.IP { + if len(ips) == 0 { + return ips + } + var ip4 = make([]net.IP, 0, len(ips)) + var ip6 = make([]net.IP, 0, len(ips)) + for _, ip := range ips { + parsedIp := net.IPAddress(ip).IP() + if len(parsedIp) == net.IPv4len { + ip4 = append(ip4, parsedIp) + } else { + ip6 = append(ip6, parsedIp) + } + } + + if len(ip4) == 0 || len(ip6) == 0 { + return ips + } + + var newIPs = make([]net.IP, 0, len(ips)) + consumeIP4 := 0 + consumeIP6 := 0 + consumeTurn := uint32(0) + ip4turn := true + if priorIPv6 { + ip4turn = false + } + for { + if ip4turn { + newIPs = append(newIPs, ip4[consumeIP4]) + consumeIP4++ + if consumeIP4 == len(ip4) { + newIPs = append(newIPs, ip6[consumeIP6:]...) + break + } + consumeTurn++ + if consumeTurn == interleave { + ip4turn = false + consumeTurn = uint32(0) + } + } else { + newIPs = append(newIPs, ip6[consumeIP6]) + consumeIP6++ + if consumeIP6 == len(ip6) { + newIPs = append(newIPs, ip4[consumeIP4:]...) + break + } + consumeTurn++ + if consumeTurn == interleave { + ip4turn = true + consumeTurn = uint32(0) + } + } + } + + return newIPs +} + +func tcpTryDial(ctx context.Context, src net.Address, sockopt *SocketConfig, ip net.IP, port net.Port, index int, resultCh chan<- *result) { + conn, err := effectiveSystemDialer.Dial(ctx, src, net.Destination{Address: net.IPAddress(ip), Network: net.Network_TCP, Port: port}, sockopt) + select { + case <-ctx.Done(): + if conn != nil { + conn.Close() + } + resultCh <- &result{err: ctx.Err(), index: index} + return + default: + if err != nil { + resultCh <- &result{err: err, index: index} + return + } + resultCh <- &result{conn: conn, index: index} + return + } +}