diff --git a/features/dns/client.go b/features/dns/client.go index 3fc9dce0..80494627 100644 --- a/features/dns/client.go +++ b/features/dns/client.go @@ -94,6 +94,12 @@ var ( d.FakeEnable = true return d } + LookupFakeOnly = func(d *IPOption) *IPOption { + d.FakeEnable = true + d.IPv4Enable = false + d.IPv6Enable = false + return d + } LookupNoFake = func(d *IPOption) *IPOption { d.FakeEnable = false return d diff --git a/infra/conf/dns_proxy.go b/infra/conf/dns_proxy.go index 922d32ba..439b95d7 100644 --- a/infra/conf/dns_proxy.go +++ b/infra/conf/dns_proxy.go @@ -1,15 +1,18 @@ package conf import ( + "strings" + "github.com/golang/protobuf/proto" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/proxy/dns" ) type DNSOutboundConfig struct { - Network Network `json:"network"` - Address *Address `json:"address"` - Port uint16 `json:"port"` + Network Network `json:"network"` + Address *Address `json:"address"` + Port uint16 `json:"port"` + DomainStrategy string `json:"domainStrategy"` } func (c *DNSOutboundConfig) Build() (proto.Message, error) { @@ -22,5 +25,12 @@ func (c *DNSOutboundConfig) Build() (proto.Message, error) { if c.Address != nil { config.Server.Address = c.Address.Build() } + config.DomainStrategy = dns.Config_USE_ALL + switch strings.ToLower(c.DomainStrategy) { + case "useip", "use_ip", "use-ip": + config.DomainStrategy = dns.Config_USE_IP + case "fake", "fakedns": + config.DomainStrategy = dns.Config_USE_FAKE + } return config, nil } diff --git a/infra/conf/dns_proxy_test.go b/infra/conf/dns_proxy_test.go index 805ac323..204f29c8 100644 --- a/infra/conf/dns_proxy_test.go +++ b/infra/conf/dns_proxy_test.go @@ -27,6 +27,7 @@ func TestDnsProxyConfig(t *testing.T) { Address: net.NewIPOrDomain(net.IPAddress([]byte{8, 8, 8, 8})), Port: 53, }, + DomainStrategy: dns.Config_USE_ALL, }, }, }) diff --git a/proxy/dns/config.pb.go b/proxy/dns/config.pb.go index 62b7bf8d..52fb2e3a 100644 --- a/proxy/dns/config.pb.go +++ b/proxy/dns/config.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 -// protoc v3.14.0 +// protoc v3.15.8 // source: proxy/dns/config.proto package dns @@ -26,6 +26,55 @@ const ( // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 +type Config_DomainStrategy int32 + +const ( + Config_USE_ALL Config_DomainStrategy = 0 + Config_USE_IP Config_DomainStrategy = 1 + Config_USE_FAKE Config_DomainStrategy = 2 +) + +// Enum value maps for Config_DomainStrategy. +var ( + Config_DomainStrategy_name = map[int32]string{ + 0: "USE_ALL", + 1: "USE_IP", + 2: "USE_FAKE", + } + Config_DomainStrategy_value = map[string]int32{ + "USE_ALL": 0, + "USE_IP": 1, + "USE_FAKE": 2, + } +) + +func (x Config_DomainStrategy) Enum() *Config_DomainStrategy { + p := new(Config_DomainStrategy) + *p = x + return p +} + +func (x Config_DomainStrategy) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor { + return file_proxy_dns_config_proto_enumTypes[0].Descriptor() +} + +func (Config_DomainStrategy) Type() protoreflect.EnumType { + return &file_proxy_dns_config_proto_enumTypes[0] +} + +func (x Config_DomainStrategy) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Config_DomainStrategy.Descriptor instead. +func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) { + return file_proxy_dns_config_proto_rawDescGZIP(), []int{0, 0} +} + type Config struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -33,7 +82,8 @@ type Config struct { // Server is the DNS server address. If specified, this address overrides the // original one. - Server *net.Endpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"` + Server *net.Endpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"` + DomainStrategy Config_DomainStrategy `protobuf:"varint,2,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.proxy.dns.Config_DomainStrategy" json:"domain_strategy,omitempty"` } func (x *Config) Reset() { @@ -75,6 +125,13 @@ func (x *Config) GetServer() *net.Endpoint { return nil } +func (x *Config) GetDomainStrategy() Config_DomainStrategy { + if x != nil { + return x.DomainStrategy + } + return Config_USE_ALL +} + var File_proxy_dns_config_proto protoreflect.FileDescriptor var file_proxy_dns_config_proto_rawDesc = []byte{ @@ -82,16 +139,25 @@ var file_proxy_dns_config_proto_rawDesc = []byte{ 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 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, 0x22, 0x3b, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 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, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x42, 0x4c, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x23, 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, 0x64, 0x6e, 0x73, - 0xaa, 0x02, 0x0e, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x6e, - 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc4, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 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, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, + 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x22, 0x37, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, + 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x41, 0x4c, + 0x4c, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, + 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, 0x46, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x42, 0x4c, 0x0a, + 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, + 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x23, 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, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0e, 0x58, 0x72, 0x61, + 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -106,18 +172,21 @@ func file_proxy_dns_config_proto_rawDescGZIP() []byte { return file_proxy_dns_config_proto_rawDescData } +var file_proxy_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_proxy_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_proxy_dns_config_proto_goTypes = []interface{}{ - (*Config)(nil), // 0: xray.proxy.dns.Config - (*net.Endpoint)(nil), // 1: xray.common.net.Endpoint + (Config_DomainStrategy)(0), // 0: xray.proxy.dns.Config.DomainStrategy + (*Config)(nil), // 1: xray.proxy.dns.Config + (*net.Endpoint)(nil), // 2: xray.common.net.Endpoint } var file_proxy_dns_config_proto_depIdxs = []int32{ - 1, // 0: xray.proxy.dns.Config.server:type_name -> xray.common.net.Endpoint - 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 + 2, // 0: xray.proxy.dns.Config.server:type_name -> xray.common.net.Endpoint + 0, // 1: xray.proxy.dns.Config.domain_strategy:type_name -> xray.proxy.dns.Config.DomainStrategy + 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_proxy_dns_config_proto_init() } @@ -144,13 +213,14 @@ func file_proxy_dns_config_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proxy_dns_config_proto_rawDesc, - NumEnums: 0, + NumEnums: 1, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_proxy_dns_config_proto_goTypes, DependencyIndexes: file_proxy_dns_config_proto_depIdxs, + EnumInfos: file_proxy_dns_config_proto_enumTypes, MessageInfos: file_proxy_dns_config_proto_msgTypes, }.Build() File_proxy_dns_config_proto = out.File diff --git a/proxy/dns/config.proto b/proxy/dns/config.proto index d4f4a308..5fa8b4fe 100644 --- a/proxy/dns/config.proto +++ b/proxy/dns/config.proto @@ -12,4 +12,10 @@ message Config { // Server is the DNS server address. If specified, this address overrides the // original one. xray.common.net.Endpoint server = 1; + enum DomainStrategy { + USE_ALL = 0; + USE_IP = 1; + USE_FAKE = 2; + } + DomainStrategy domain_strategy = 2; } diff --git a/proxy/dns/dns.go b/proxy/dns/dns.go index 8b9fd957..6830079a 100644 --- a/proxy/dns/dns.go +++ b/proxy/dns/dns.go @@ -39,6 +39,7 @@ type Handler struct { client dns.Client ownLinkVerifier ownLinkVerifier server net.Destination + DomainStrategy Config_DomainStrategy } func (h *Handler) Init(config *Config, dnsClient dns.Client) error { @@ -199,16 +200,24 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, var err error var ttl uint32 = 600 - var opt dns.Option + var opt []dns.Option - switch qType { - case dnsmessage.TypeA: - opt = dns.LookupIPv4Only - case dnsmessage.TypeAAAA: - opt = dns.LookupIPv6Only + if h.DomainStrategy == Config_USE_FAKE { + opt = append(opt, dns.LookupFakeOnly) + } else { + switch qType { + case dnsmessage.TypeA: + opt = append(opt, dns.LookupIPv4Only) + case dnsmessage.TypeAAAA: + opt = append(opt, dns.LookupIPv6Only) + } } - ips, err = h.client.LookupOptions(domain, opt, dns.LookupFake) + if h.DomainStrategy == Config_USE_ALL { + opt = append(opt, dns.LookupFake) + } + + ips, err = h.client.LookupOptions(domain, opt...) rcode := dns.RCodeFromError(err) if rcode == 0 && len(ips) == 0 && err != dns.ErrEmptyResponse { newError("ip query").Base(err).WriteToLog()