diff --git a/app/dns/config.pb.go b/app/dns/config.pb.go index d5bc18d2..8a066a9e 100644 --- a/app/dns/config.pb.go +++ b/app/dns/config.pb.go @@ -134,6 +134,7 @@ type NameServer struct { 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"` } func (x *NameServer) Reset() { @@ -210,6 +211,13 @@ func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule { return nil } +func (x *NameServer) GetQueryStrategy() QueryStrategy { + if x != nil { + return x.QueryStrategy + } + return QueryStrategy_USE_IP +} + type Config struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -538,7 +546,7 @@ var file_app_dns_config_proto_rawDesc = []byte{ 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, 0xee, 0x03, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x04, 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, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, @@ -559,77 +567,81 @@ var file_app_dns_config_proto_rawDesc = []byte{ 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, 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, 0xef, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, - 0x18, 0x01, 0x20, 0x03, 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, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x73, 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, 0x39, 0x0a, - 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 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, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x02, 0x18, - 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 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, 0x55, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 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, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 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, + 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, 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, 0xef, 0x05, 0x0a, 0x06, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 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, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 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, 0x39, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1f, 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, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 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, 0x55, 0x0a, 0x0a, 0x48, 0x6f, + 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 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, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 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, } var ( @@ -664,19 +676,20 @@ var file_app_dns_config_proto_depIdxs = []int32{ 4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain 9, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP 5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule - 8, // 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 - 6, // 6: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry - 7, // 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 - 10, // 10: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain - 0, // 11: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType - 12, // [12:12] is the sub-list for method output_type - 12, // [12:12] is the sub-list for method input_type - 12, // [12:12] is the sub-list for extension type_name - 12, // [12:12] is the sub-list for extension extendee - 0, // [0:12] is the sub-list for field type_name + 1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy + 8, // 5: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint + 2, // 6: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer + 6, // 7: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry + 7, // 8: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping + 1, // 9: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy + 0, // 10: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType + 10, // 11: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain + 0, // 12: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType + 13, // [13:13] is the sub-list for method output_type + 13, // [13:13] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension 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() } diff --git a/app/dns/config.proto b/app/dns/config.proto index e2059e38..2c420651 100644 --- a/app/dns/config.proto +++ b/app/dns/config.proto @@ -28,6 +28,7 @@ message NameServer { repeated PriorityDomain prioritized_domain = 2; repeated xray.app.router.GeoIP geoip = 3; repeated OriginalRule original_rules = 4; + QueryStrategy query_strategy = 7; } enum DomainMatchingType { diff --git a/app/dns/nameserver.go b/app/dns/nameserver.go index d6f9b272..d5423b84 100644 --- a/app/dns/nameserver.go +++ b/app/dns/nameserver.go @@ -35,7 +35,7 @@ type Client struct { var errExpectedIPNonMatch = errors.New("expectIPs not match") // NewServer creates a name server object according to the network destination url. -func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, error) { +func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (Server, error) { if address := dest.Address; address.Family().IsDomain() { u, err := url.Parse(address.Domain()) if err != nil { @@ -45,15 +45,15 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err case strings.EqualFold(u.String(), "localhost"): return NewLocalNameServer(), nil case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode - return NewDoHNameServer(u, dispatcher) + return NewDoHNameServer(u, dispatcher, queryStrategy) case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode - return NewDoHLocalNameServer(u), nil + return NewDoHLocalNameServer(u, queryStrategy), nil case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode - return NewQUICNameServer(u) + return NewQUICNameServer(u, queryStrategy) case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode - return NewTCPNameServer(u, dispatcher) + return NewTCPNameServer(u, dispatcher, queryStrategy) case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode - return NewTCPLocalNameServer(u) + return NewTCPLocalNameServer(u, queryStrategy) case strings.EqualFold(u.String(), "fakedns"): return NewFakeDNSServer(), nil } @@ -68,12 +68,19 @@ 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. -func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, matcherInfos *[]*DomainMatcherInfo, updateDomainRule func(strmatcher.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{} err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { // Create a new server for each client for now - server, err := NewServer(ns.Address.AsDestination(), dispatcher) + server, err := NewServer(ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy()) if err != nil { return newError("failed to create nameserver").Base(err).AtWarning() } @@ -160,7 +167,7 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container r func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.IP) (*Client, error) { client := &Client{} err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { - server, err := NewServer(endpoint.AsDestination(), dispatcher) + server, err := NewServer(endpoint.AsDestination(), dispatcher, QueryStrategy_USE_IP) if err != nil { return newError("failed to create nameserver").Base(err).AtWarning() } @@ -218,3 +225,24 @@ func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error) newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog() return newIps, nil } + +func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption { + switch queryStrategy { + case QueryStrategy_USE_IP: + return ipOption + case QueryStrategy_USE_IP4: + return dns.IPOption{ + IPv4Enable: ipOption.IPv4Enable, + IPv6Enable: false, + FakeEnable: false, + } + case QueryStrategy_USE_IP6: + return dns.IPOption{ + IPv4Enable: false, + IPv6Enable: ipOption.IPv6Enable, + FakeEnable: false, + } + default: + return ipOption + } +} diff --git a/app/dns/nameserver_doh.go b/app/dns/nameserver_doh.go index fecc5efb..8657e3fb 100644 --- a/app/dns/nameserver_doh.go +++ b/app/dns/nameserver_doh.go @@ -31,19 +31,20 @@ import ( type DoHNameServer struct { dispatcher routing.Dispatcher sync.RWMutex - ips map[string]*record - pub *pubsub.Service - cleanup *task.Periodic - reqID uint32 - httpClient *http.Client - dohURL string - name string + ips map[string]*record + pub *pubsub.Service + cleanup *task.Periodic + reqID uint32 + httpClient *http.Client + dohURL string + name string + queryStrategy QueryStrategy } // NewDoHNameServer creates DOH server object for remote resolving. -func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServer, error) { +func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) { newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog() - s := baseDOHNameServer(url, "DOH") + s := baseDOHNameServer(url, "DOH", queryStrategy) s.dispatcher = dispatcher tr := &http.Transport{ @@ -90,9 +91,9 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServ } // NewDoHLocalNameServer creates DOH client object for local resolving -func NewDoHLocalNameServer(url *url.URL) *DoHNameServer { +func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer { url.Scheme = "https" - s := baseDOHNameServer(url, "DOHL") + s := baseDOHNameServer(url, "DOHL", queryStrategy) tr := &http.Transport{ IdleConnTimeout: 90 * time.Second, ForceAttemptHTTP2: true, @@ -122,12 +123,13 @@ func NewDoHLocalNameServer(url *url.URL) *DoHNameServer { return s } -func baseDOHNameServer(url *url.URL, prefix string) *DoHNameServer { +func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer { s := &DoHNameServer{ - ips: make(map[string]*record), - pub: pubsub.NewService(), - name: prefix + "//" + url.Host, - dohURL: url.String(), + ips: make(map[string]*record), + pub: pubsub.NewService(), + name: prefix + "//" + url.Host, + dohURL: url.String(), + queryStrategy: queryStrategy, } s.cleanup = &task.Periodic{ Interval: time.Minute, @@ -353,6 +355,10 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt // QueryIP implements Server. func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { // nolint: dupl fqdn := Fqdn(domain) + option = ResolveIpOptionOverride(s.queryStrategy, option) + if !option.IPv4Enable && !option.IPv6Enable { + return nil, dns_feature.ErrEmptyResponse + } if disableCache { newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() diff --git a/app/dns/nameserver_doh_test.go b/app/dns/nameserver_doh_test.go index f5cae5a6..ae4f9cc7 100644 --- a/app/dns/nameserver_doh_test.go +++ b/app/dns/nameserver_doh_test.go @@ -17,7 +17,7 @@ func TestDOHNameServer(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url) + s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -34,7 +34,7 @@ func TestDOHNameServerWithCache(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url) + s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -57,3 +57,49 @@ func TestDOHNameServerWithCache(t *testing.T) { t.Fatal(r) } } + +func TestDOHNameServerWithIPv4Override(t *testing.T) { + url, err := url.Parse("https+local://1.1.1.1/dns-query") + common.Must(err) + + s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ + IPv4Enable: true, + IPv6Enable: true, + }, false) + cancel() + common.Must(err) + if len(ips) == 0 { + t.Error("expect some ips, but got 0") + } + + for _, ip := range ips { + if len(ip) != net.IPv4len { + t.Error("expect only IPv4 response from DNS query") + } + } +} + +func TestDOHNameServerWithIPv6Override(t *testing.T) { + url, err := url.Parse("https+local://1.1.1.1/dns-query") + common.Must(err) + + s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ + IPv4Enable: true, + IPv6Enable: true, + }, false) + cancel() + common.Must(err) + if len(ips) == 0 { + t.Error("expect some ips, but got 0") + } + + for _, ip := range ips { + if len(ip) != net.IPv6len { + t.Error("expect only IPv6 response from DNS query") + } + } +} diff --git a/app/dns/nameserver_quic.go b/app/dns/nameserver_quic.go index e82a6a3d..9e702564 100644 --- a/app/dns/nameserver_quic.go +++ b/app/dns/nameserver_quic.go @@ -31,17 +31,18 @@ const handshakeTimeout = time.Second * 8 // QUICNameServer implemented DNS over QUIC type QUICNameServer struct { sync.RWMutex - ips map[string]*record - pub *pubsub.Service - cleanup *task.Periodic - reqID uint32 - name string - destination *net.Destination - connection quic.Connection + ips map[string]*record + pub *pubsub.Service + cleanup *task.Periodic + reqID uint32 + name string + destination *net.Destination + connection quic.Connection + queryStrategy QueryStrategy } // NewQUICNameServer creates DNS-over-QUIC client object for local resolving -func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) { +func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) { newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog() var err error @@ -55,10 +56,11 @@ func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) { dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port) s := &QUICNameServer{ - ips: make(map[string]*record), - pub: pubsub.NewService(), - name: url.String(), - destination: &dest, + ips: make(map[string]*record), + pub: pubsub.NewService(), + name: url.String(), + destination: &dest, + queryStrategy: queryStrategy, } s.cleanup = &task.Periodic{ Interval: time.Minute, @@ -269,6 +271,10 @@ func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOp // QueryIP is called from dns.Server->queryIPTimeout func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { fqdn := Fqdn(domain) + option = ResolveIpOptionOverride(s.queryStrategy, option) + if !option.IPv4Enable && !option.IPv6Enable { + return nil, dns_feature.ErrEmptyResponse + } if disableCache { newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() diff --git a/app/dns/nameserver_quic_test.go b/app/dns/nameserver_quic_test.go index cf445b43..ef50d7d9 100644 --- a/app/dns/nameserver_quic_test.go +++ b/app/dns/nameserver_quic_test.go @@ -16,7 +16,7 @@ import ( func TestQUICNameServer(t *testing.T) { url, err := url.Parse("quic://dns.adguard.com") common.Must(err) - s, err := NewQUICNameServer(url) + s, err := NewQUICNameServer(url, QueryStrategy_USE_IP) common.Must(err) ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{ @@ -40,3 +40,49 @@ func TestQUICNameServer(t *testing.T) { t.Fatal(r) } } + +func TestQUICNameServerWithIPv4Override(t *testing.T) { + url, err := url.Parse("quic://dns.adguard.com") + common.Must(err) + s, err := NewQUICNameServer(url, QueryStrategy_USE_IP4) + common.Must(err) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{ + IPv4Enable: true, + IPv6Enable: true, + }, false) + cancel() + common.Must(err) + if len(ips) == 0 { + t.Error("expect some ips, but got 0") + } + + for _, ip := range ips { + if len(ip) != net.IPv4len { + t.Error("expect only IPv4 response from DNS query") + } + } +} + +func TestQUICNameServerWithIPv6Override(t *testing.T) { + url, err := url.Parse("quic://dns.adguard.com") + common.Must(err) + s, err := NewQUICNameServer(url, QueryStrategy_USE_IP6) + common.Must(err) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{ + IPv4Enable: true, + IPv6Enable: true, + }, false) + cancel() + common.Must(err) + if len(ips) == 0 { + t.Error("expect some ips, but got 0") + } + + for _, ip := range ips { + if len(ip) != net.IPv6len { + t.Error("expect only IPv6 response from DNS query") + } + } +} diff --git a/app/dns/nameserver_tcp.go b/app/dns/nameserver_tcp.go index cf63ac21..4ed723e1 100644 --- a/app/dns/nameserver_tcp.go +++ b/app/dns/nameserver_tcp.go @@ -27,18 +27,23 @@ import ( // TCPNameServer implemented DNS over TCP (RFC7766). type TCPNameServer struct { sync.RWMutex - name string - destination *net.Destination - ips map[string]*record - pub *pubsub.Service - cleanup *task.Periodic - reqID uint32 - dial func(context.Context) (net.Conn, error) + name string + destination *net.Destination + ips map[string]*record + pub *pubsub.Service + cleanup *task.Periodic + reqID uint32 + dial func(context.Context) (net.Conn, error) + queryStrategy QueryStrategy } // NewTCPNameServer creates DNS over TCP server object for remote resolving. -func NewTCPNameServer(url *url.URL, dispatcher routing.Dispatcher) (*TCPNameServer, error) { - s, err := baseTCPNameServer(url, "TCP") +func NewTCPNameServer( + url *url.URL, + dispatcher routing.Dispatcher, + queryStrategy QueryStrategy, +) (*TCPNameServer, error) { + s, err := baseTCPNameServer(url, "TCP", queryStrategy) if err != nil { return nil, err } @@ -59,8 +64,8 @@ func NewTCPNameServer(url *url.URL, dispatcher routing.Dispatcher) (*TCPNameServ } // NewTCPLocalNameServer creates DNS over TCP client object for local resolving -func NewTCPLocalNameServer(url *url.URL) (*TCPNameServer, error) { - s, err := baseTCPNameServer(url, "TCPL") +func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameServer, error) { + s, err := baseTCPNameServer(url, "TCPL", queryStrategy) if err != nil { return nil, err } @@ -72,22 +77,22 @@ func NewTCPLocalNameServer(url *url.URL) (*TCPNameServer, error) { return s, nil } -func baseTCPNameServer(url *url.URL, prefix string) (*TCPNameServer, error) { - var err error +func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) (*TCPNameServer, error) { port := net.Port(53) if url.Port() != "" { - port, err = net.PortFromString(url.Port()) - if err != nil { + var err error + if port, err = net.PortFromString(url.Port()); err != nil { return nil, err } } dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port) s := &TCPNameServer{ - destination: &dest, - ips: make(map[string]*record), - pub: pubsub.NewService(), - name: prefix + "//" + dest.NetAddr(), + destination: &dest, + ips: make(map[string]*record), + pub: pubsub.NewService(), + name: prefix + "//" + dest.NetAddr(), + queryStrategy: queryStrategy, } s.cleanup = &task.Periodic{ Interval: time.Minute, @@ -308,6 +313,10 @@ func (s *TCPNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt // QueryIP implements Server. func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { fqdn := Fqdn(domain) + option = ResolveIpOptionOverride(s.queryStrategy, option) + if !option.IPv4Enable && !option.IPv6Enable { + return nil, dns_feature.ErrEmptyResponse + } if disableCache { newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog() diff --git a/app/dns/nameserver_tcp_test.go b/app/dns/nameserver_tcp_test.go index da362355..6b2b2465 100644 --- a/app/dns/nameserver_tcp_test.go +++ b/app/dns/nameserver_tcp_test.go @@ -16,7 +16,7 @@ import ( func TestTCPLocalNameServer(t *testing.T) { url, err := url.Parse("tcp+local://8.8.8.8") common.Must(err) - s, err := NewTCPLocalNameServer(url) + s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP) common.Must(err) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ @@ -33,7 +33,7 @@ func TestTCPLocalNameServer(t *testing.T) { func TestTCPLocalNameServerWithCache(t *testing.T) { url, err := url.Parse("tcp+local://8.8.8.8") common.Must(err) - s, err := NewTCPLocalNameServer(url) + s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP) common.Must(err) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ @@ -57,3 +57,51 @@ func TestTCPLocalNameServerWithCache(t *testing.T) { t.Fatal(r) } } + +func TestTCPLocalNameServerWithIPv4Override(t *testing.T) { + url, err := url.Parse("tcp+local://8.8.8.8") + common.Must(err) + s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP4) + common.Must(err) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ + IPv4Enable: true, + IPv6Enable: true, + }, false) + cancel() + common.Must(err) + + if len(ips) == 0 { + t.Error("expect some ips, but got 0") + } + + for _, ip := range ips { + if len(ip) != net.IPv4len { + t.Error("expect only IPv4 response from DNS query") + } + } +} + +func TestTCPLocalNameServerWithIPv6Override(t *testing.T) { + url, err := url.Parse("tcp+local://8.8.8.8") + common.Must(err) + s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP6) + common.Must(err) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ + IPv4Enable: true, + IPv6Enable: true, + }, false) + cancel() + common.Must(err) + + if len(ips) == 0 { + t.Error("expect some ips, but got 0") + } + + for _, ip := range ips { + if len(ip) != net.IPv6len { + t.Error("expect only IPv6 response from DNS query") + } + } +} diff --git a/infra/conf/dns.go b/infra/conf/dns.go index 3265b819..a0f3155c 100644 --- a/infra/conf/dns.go +++ b/infra/conf/dns.go @@ -11,12 +11,13 @@ import ( ) type NameServerConfig struct { - Address *Address - ClientIP *Address - Port uint16 - SkipFallback bool - Domains []string - ExpectIPs StringList + Address *Address + ClientIP *Address + Port uint16 + SkipFallback bool + Domains []string + ExpectIPs StringList + QueryStrategy string } func (c *NameServerConfig) UnmarshalJSON(data []byte) error { @@ -27,12 +28,13 @@ 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"` - ExpectIPs StringList `json:"expectIps"` + Address *Address `json:"address"` + ClientIP *Address `json:"clientIp"` + Port uint16 `json:"port"` + SkipFallback bool `json:"skipFallback"` + Domains []string `json:"domains"` + ExpectIPs StringList `json:"expectIps"` + QueryStrategy string `json:"queryStrategy"` } if err := json.Unmarshal(data, &advanced); err == nil { c.Address = advanced.Address @@ -41,6 +43,7 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error { c.SkipFallback = advanced.SkipFallback c.Domains = advanced.Domains c.ExpectIPs = advanced.ExpectIPs + c.QueryStrategy = advanced.QueryStrategy return nil } @@ -112,6 +115,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) { PrioritizedDomain: domains, Geoip: geoipList, OriginalRules: originalRules, + QueryStrategy: resolveQueryStrategy(c.QueryStrategy), }, nil } @@ -311,6 +315,7 @@ func (c *DNSConfig) Build() (*dns.Config, error) { DisableCache: c.DisableCache, DisableFallback: c.DisableFallback, DisableFallbackIfMatch: c.DisableFallbackIfMatch, + QueryStrategy: resolveQueryStrategy(c.QueryStrategy), } if c.ClientIP != nil { @@ -320,16 +325,6 @@ func (c *DNSConfig) Build() (*dns.Config, error) { config.ClientIp = []byte(c.ClientIP.IP()) } - config.QueryStrategy = dns.QueryStrategy_USE_IP - switch strings.ToLower(c.QueryStrategy) { - case "useip", "use_ip", "use-ip": - config.QueryStrategy = dns.QueryStrategy_USE_IP - case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4": - config.QueryStrategy = dns.QueryStrategy_USE_IP4 - case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6": - config.QueryStrategy = dns.QueryStrategy_USE_IP6 - } - for _, server := range c.Servers { ns, err := server.Build() if err != nil { @@ -348,3 +343,16 @@ func (c *DNSConfig) Build() (*dns.Config, error) { return config, nil } + +func resolveQueryStrategy(queryStrategy string) dns.QueryStrategy { + switch strings.ToLower(queryStrategy) { + case "useip", "use_ip", "use-ip": + return dns.QueryStrategy_USE_IP + case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4": + 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 + default: + return dns.QueryStrategy_USE_IP + } +}