mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 09:18:34 +00:00
Add Fake DNS support (#309)
Co-authored-by: Xiaokang Wang <xiaokangwang@outlook.com> Co-authored-by: loyalsoldier <10487845+Loyalsoldier@users.noreply.github.com> Co-authored-by: kslr <kslrwang@gmail.com>
This commit is contained in:
parent
db32ce6fd9
commit
f50eff5ebb
43 changed files with 1351 additions and 301 deletions
|
@ -68,4 +68,6 @@ message Config {
|
|||
|
||||
// Tag is the inbound tag of DNS client.
|
||||
string tag = 6;
|
||||
|
||||
reserved 7;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dns
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
|
@ -13,7 +14,7 @@ import (
|
|||
|
||||
// Fqdn normalize domain make sure it ends with '.'
|
||||
func Fqdn(domain string) string {
|
||||
if len(domain) > 0 && domain[len(domain)-1] == '.' {
|
||||
if len(domain) > 0 && strings.HasSuffix(domain, ".") {
|
||||
return domain
|
||||
}
|
||||
return domain + "."
|
||||
|
@ -112,7 +113,7 @@ func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource {
|
|||
return opt
|
||||
}
|
||||
|
||||
func buildReqMsgs(domain string, option IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {
|
||||
func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {
|
||||
qA := dnsmessage.Question{
|
||||
Name: dnsmessage.MustNewName(domain),
|
||||
Type: dnsmessage.TypeA,
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/miekg/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
|
@ -92,7 +93,7 @@ func Test_buildReqMsgs(t *testing.T) {
|
|||
}
|
||||
type args struct {
|
||||
domain string
|
||||
option IPOption
|
||||
option dns_feature.IPOption
|
||||
reqOpts *dnsmessage.Resource
|
||||
}
|
||||
tests := []struct {
|
||||
|
@ -100,10 +101,26 @@ func Test_buildReqMsgs(t *testing.T) {
|
|||
args args
|
||||
want int
|
||||
}{
|
||||
{"dual stack", args{"test.com", IPOption{true, true}, nil}, 2},
|
||||
{"ipv4 only", args{"test.com", IPOption{true, false}, nil}, 1},
|
||||
{"ipv6 only", args{"test.com", IPOption{false, true}, nil}, 1},
|
||||
{"none/error", args{"test.com", IPOption{false, false}, nil}, 0},
|
||||
{"dual stack", args{"test.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}, nil}, 2},
|
||||
{"ipv4 only", args{"test.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
}, nil}, 1},
|
||||
{"ipv6 only", args{"test.com", dns_feature.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}, nil}, 1},
|
||||
{"none/error", args{"test.com", dns_feature.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
}, nil}, 0},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -234,7 +234,7 @@ func (s *DoHNameServer) newReqID() uint16 {
|
|||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPOption) {
|
||||
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option dns_feature.IPOption) {
|
||||
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
if s.name+"." == "DOH//"+domain {
|
||||
|
@ -320,7 +320,7 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
|||
return ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
|
||||
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
@ -363,7 +363,7 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option IPOption) ([]net.
|
|||
}
|
||||
|
||||
// QueryIP is called from dns.Server->queryIPTimeout
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, error) { // nolint: dupl
|
||||
fqdn := Fqdn(domain)
|
||||
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
|
|
9
app/dns/fakedns/errors.generated.go
Normal file
9
app/dns/fakedns/errors.generated.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package fakedns
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
136
app/dns/fakedns/fake.go
Normal file
136
app/dns/fakedns/fake.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
// +build !confonly
|
||||
|
||||
package fakedns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"math/big"
|
||||
gonet "net"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/cache"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
type Holder struct {
|
||||
domainToIP cache.Lru
|
||||
ipRange *gonet.IPNet
|
||||
|
||||
config *FakeDnsPool
|
||||
}
|
||||
|
||||
func (*Holder) Type() interface{} {
|
||||
return (*dns.FakeDNSEngine)(nil)
|
||||
}
|
||||
|
||||
func (fkdns *Holder) Start() error {
|
||||
return fkdns.initializeFromConfig()
|
||||
}
|
||||
|
||||
func (fkdns *Holder) Close() error {
|
||||
fkdns.domainToIP = nil
|
||||
fkdns.ipRange = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFakeDNSHolder() (*Holder, error) {
|
||||
var fkdns *Holder
|
||||
var err error
|
||||
|
||||
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
||||
return nil, newError("Unable to create Fake Dns Engine").Base(err).AtError()
|
||||
}
|
||||
err = fkdns.initialize("240.0.0.0/8", 65535)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fkdns, nil
|
||||
}
|
||||
|
||||
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
||||
return &Holder{nil, nil, conf}, nil
|
||||
}
|
||||
|
||||
func (fkdns *Holder) initializeFromConfig() error {
|
||||
return fkdns.initialize(fkdns.config.IpPool, int(fkdns.config.LruSize))
|
||||
}
|
||||
|
||||
func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
||||
var ipRange *gonet.IPNet
|
||||
var err error
|
||||
|
||||
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
|
||||
return newError("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
||||
}
|
||||
|
||||
ones, bits := ipRange.Mask.Size()
|
||||
rooms := bits - ones
|
||||
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
||||
return newError("LRU size is bigger than subnet size").AtError()
|
||||
}
|
||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||
fkdns.ipRange = ipRange
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFakeIPForDomain check and generate a fake IP for a domain name
|
||||
func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
||||
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
||||
return []net.Address{v.(net.Address)}
|
||||
}
|
||||
var currentTimeMillis = uint64(time.Now().UnixNano() / 1e6)
|
||||
ones, bits := fkdns.ipRange.Mask.Size()
|
||||
rooms := bits - ones
|
||||
if rooms < 64 {
|
||||
currentTimeMillis %= (uint64(1) << rooms)
|
||||
}
|
||||
var bigIntIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP)
|
||||
bigIntIP = bigIntIP.Add(bigIntIP, new(big.Int).SetUint64(currentTimeMillis))
|
||||
var ip net.Address
|
||||
for {
|
||||
ip = net.IPAddress(bigIntIP.Bytes())
|
||||
|
||||
// if we run for a long time, we may go back to beginning and start seeing the IP in use
|
||||
if _, ok := fkdns.domainToIP.PeekKeyFromValue(ip); !ok {
|
||||
break
|
||||
}
|
||||
|
||||
bigIntIP = bigIntIP.Add(bigIntIP, big.NewInt(1))
|
||||
if !fkdns.ipRange.Contains(bigIntIP.Bytes()) {
|
||||
bigIntIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP)
|
||||
}
|
||||
}
|
||||
fkdns.domainToIP.Put(domain, ip)
|
||||
return []net.Address{ip}
|
||||
}
|
||||
|
||||
// GetDomainFromFakeDNS check if an IP is a fake IP and have corresponding domain name
|
||||
func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
|
||||
if !ip.Family().IsIP() || !fkdns.ipRange.Contains(ip.IP()) {
|
||||
return ""
|
||||
}
|
||||
if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok {
|
||||
return k.(string)
|
||||
}
|
||||
newError("A fake ip request to ", ip, ", however there is no matching domain name in fake DNS").AtInfo().WriteToLog()
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetFakeIPRange return fake IP range from configuration
|
||||
func (fkdns *Holder) GetFakeIPRange() *gonet.IPNet {
|
||||
return fkdns.ipRange
|
||||
}
|
||||
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*FakeDnsPool)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
var f *Holder
|
||||
var err error
|
||||
if f, err = NewFakeDNSHolderConfigOnly(config.(*FakeDnsPool)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}))
|
||||
}
|
5
app/dns/fakedns/fakedns.go
Normal file
5
app/dns/fakedns/fakedns.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
// +build !confonly
|
||||
|
||||
package fakedns
|
||||
|
||||
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
164
app/dns/fakedns/fakedns.pb.go
Normal file
164
app/dns/fakedns/fakedns.pb.go
Normal file
|
@ -0,0 +1,164 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.13.0
|
||||
// source: app/dns/fakedns/fakedns.proto
|
||||
|
||||
package fakedns
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type FakeDnsPool struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IpPool string `protobuf:"bytes,1,opt,name=ip_pool,json=ipPool,proto3" json:"ip_pool,omitempty"` //CIDR of IP pool used as fake DNS IP
|
||||
LruSize int64 `protobuf:"varint,2,opt,name=lruSize,proto3" json:"lruSize,omitempty"` //Size of Pool for remembering relationship between domain name and IP address
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) Reset() {
|
||||
*x = FakeDnsPool{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*FakeDnsPool) ProtoMessage() {}
|
||||
|
||||
func (x *FakeDnsPool) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FakeDnsPool.ProtoReflect.Descriptor instead.
|
||||
func (*FakeDnsPool) Descriptor() ([]byte, []int) {
|
||||
return file_app_dns_fakedns_fakedns_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) GetIpPool() string {
|
||||
if x != nil {
|
||||
return x.IpPool
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) GetLruSize() int64 {
|
||||
if x != nil {
|
||||
return x.LruSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
|
||||
0x0a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||
0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x0b, 0x46,
|
||||
0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70,
|
||||
0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50,
|
||||
0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x5f, 0x0a,
|
||||
0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x50,
|
||||
0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72,
|
||||
0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||
0x73, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,
|
||||
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescOnce sync.Once
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescData = file_app_dns_fakedns_fakedns_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescOnce.Do(func() {
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dns_fakedns_fakedns_proto_rawDescData)
|
||||
})
|
||||
return file_app_dns_fakedns_fakedns_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_app_dns_fakedns_fakedns_proto_goTypes = []interface{}{
|
||||
(*FakeDnsPool)(nil), // 0: xray.app.dns.fakedns.FakeDnsPool
|
||||
}
|
||||
var file_app_dns_fakedns_fakedns_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_dns_fakedns_fakedns_proto_init() }
|
||||
func file_app_dns_fakedns_fakedns_proto_init() {
|
||||
if File_app_dns_fakedns_fakedns_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_app_dns_fakedns_fakedns_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*FakeDnsPool); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_dns_fakedns_fakedns_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_app_dns_fakedns_fakedns_proto_goTypes,
|
||||
DependencyIndexes: file_app_dns_fakedns_fakedns_proto_depIdxs,
|
||||
MessageInfos: file_app_dns_fakedns_fakedns_proto_msgTypes,
|
||||
}.Build()
|
||||
File_app_dns_fakedns_fakedns_proto = out.File
|
||||
file_app_dns_fakedns_fakedns_proto_rawDesc = nil
|
||||
file_app_dns_fakedns_fakedns_proto_goTypes = nil
|
||||
file_app_dns_fakedns_fakedns_proto_depIdxs = nil
|
||||
}
|
12
app/dns/fakedns/fakedns.proto
Normal file
12
app/dns/fakedns/fakedns.proto
Normal file
|
@ -0,0 +1,12 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package xray.app.dns.fakedns;
|
||||
option csharp_namespace = "Xray.App.Dns.Fakedns";
|
||||
option go_package = "github.com/xtls/xray-core/app/dns/fakedns";
|
||||
option java_package = "com.xray.app.dns.fakedns";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message FakeDnsPool{
|
||||
string ip_pool = 1; //CIDR of IP pool used as fake DNS IP
|
||||
int64 lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address
|
||||
}
|
99
app/dns/fakedns/fakedns_test.go
Normal file
99
app/dns/fakedns/fakedns_test.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
package fakedns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/uuid"
|
||||
)
|
||||
|
||||
func TestNewFakeDnsHolder(_ *testing.T) {
|
||||
_, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMapping(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.", addr[0].IP().String()[0:4])
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingMany(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.", addr[0].IP().String()[0:4])
|
||||
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest2.v2fly.org")
|
||||
assert.Equal(t, "240.", addr2[0].IP().String()[0:4])
|
||||
assert.NotEqual(t, addr[0].IP().String(), addr2[0].IP().String())
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingManyAndResolve(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest2.v2fly.org")
|
||||
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(addr[0])
|
||||
assert.Equal(t, "fakednstest.v2fly.org", result)
|
||||
}
|
||||
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(addr2[0])
|
||||
assert.Equal(t, "fakednstest2.v2fly.org", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingManySingleDomain(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, addr[0].IP().String(), addr2[0].IP().String())
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolderConfigOnly(&FakeDnsPool{
|
||||
IpPool: "240.0.0.0/12",
|
||||
LruSize: 256,
|
||||
})
|
||||
common.Must(err)
|
||||
|
||||
err = fkdns.Start()
|
||||
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest2.v2fly.org")
|
||||
|
||||
for i := 0; i <= 8192; i++ {
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(addr[0])
|
||||
assert.Equal(t, "fakednstest.v2fly.org", result)
|
||||
}
|
||||
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(addr2[0])
|
||||
assert.Equal(t, "fakednstest2.v2fly.org", result)
|
||||
}
|
||||
|
||||
{
|
||||
uuid := uuid.New()
|
||||
domain := uuid.String() + ".fakednstest.v2fly.org"
|
||||
tempAddr := fkdns.GetFakeIPForDomain(domain)
|
||||
rsaddr := tempAddr[0].IP().String()
|
||||
|
||||
result := fkdns.GetDomainFromFakeDNS(net.ParseAddress(rsaddr))
|
||||
assert.Equal(t, domain, result)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/strmatcher"
|
||||
"github.com/xtls/xray-core/features"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
// StaticHosts represents static domain-ip mapping in DNS server.
|
||||
|
@ -92,7 +93,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
|
|||
return sh, nil
|
||||
}
|
||||
|
||||
func filterIP(ips []net.Address, option IPOption) []net.Address {
|
||||
func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
||||
filtered := make([]net.Address, 0, len(ips))
|
||||
for _, ip := range ips {
|
||||
if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {
|
||||
|
@ -106,7 +107,7 @@ func filterIP(ips []net.Address, option IPOption) []net.Address {
|
|||
}
|
||||
|
||||
// LookupIP returns IP address for the given domain, if exists in this StaticHosts.
|
||||
func (h *StaticHosts) LookupIP(domain string, option IPOption) []net.Address {
|
||||
func (h *StaticHosts) LookupIP(domain string, option dns.IPOption) []net.Address {
|
||||
indices := h.matchers.Match(domain)
|
||||
if len(indices) == 0 {
|
||||
return nil
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
func TestStaticHosts(t *testing.T) {
|
||||
|
@ -39,7 +40,7 @@ func TestStaticHosts(t *testing.T) {
|
|||
common.Must(err)
|
||||
|
||||
{
|
||||
ips := hosts.LookupIP("example.com", IPOption{
|
||||
ips := hosts.LookupIP("example.com", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
|
@ -52,7 +53,7 @@ func TestStaticHosts(t *testing.T) {
|
|||
}
|
||||
|
||||
{
|
||||
ips := hosts.LookupIP("www.example.cn", IPOption{
|
||||
ips := hosts.LookupIP("www.example.cn", dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
|
@ -65,7 +66,7 @@ func TestStaticHosts(t *testing.T) {
|
|||
}
|
||||
|
||||
{
|
||||
ips := hosts.LookupIP("baidu.com", IPOption{
|
||||
ips := hosts.LookupIP("baidu.com", dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
|
|
|
@ -4,39 +4,26 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/dns/localdns"
|
||||
)
|
||||
|
||||
// IPOption is an object for IP query options.
|
||||
type IPOption struct {
|
||||
IPv4Enable bool
|
||||
IPv6Enable bool
|
||||
}
|
||||
|
||||
// Client is the interface for DNS client.
|
||||
type Client interface {
|
||||
// Name of the Client.
|
||||
Name() string
|
||||
|
||||
// QueryIP sends IP queries to its configured server.
|
||||
QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error)
|
||||
QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, error)
|
||||
}
|
||||
|
||||
type LocalNameServer struct {
|
||||
client *localdns.Client
|
||||
}
|
||||
|
||||
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {
|
||||
if option.IPv4Enable && option.IPv6Enable {
|
||||
return s.client.LookupIP(domain)
|
||||
}
|
||||
|
||||
if option.IPv4Enable {
|
||||
return s.client.LookupIPv4(domain)
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
return s.client.LookupIPv6(domain)
|
||||
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
if option.IPv4Enable || option.IPv6Enable {
|
||||
return s.client.LookupIP(domain, option)
|
||||
}
|
||||
|
||||
return nil, newError("neither IPv4 nor IPv6 is enabled")
|
||||
|
|
43
app/dns/nameserver_fakedns.go
Normal file
43
app/dns/nameserver_fakedns.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
// +build !confonly
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
type FakeDNSServer struct {
|
||||
fakeDNSEngine dns.FakeDNSEngine
|
||||
}
|
||||
|
||||
func NewFakeDNSServer() *FakeDNSServer {
|
||||
return &FakeDNSServer{}
|
||||
}
|
||||
|
||||
func (FakeDNSServer) Name() string {
|
||||
return "FakeDNS"
|
||||
}
|
||||
|
||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ dns.IPOption) ([]net.IP, error) {
|
||||
if f.fakeDNSEngine == nil {
|
||||
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
|
||||
f.fakeDNSEngine = fd
|
||||
}); err != nil {
|
||||
return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
ips := f.fakeDNSEngine.GetFakeIPForDomain(domain)
|
||||
|
||||
netIP := toNetIP(ips)
|
||||
if netIP == nil {
|
||||
return nil, newError("Unable to convert IP to net ip").AtError()
|
||||
}
|
||||
|
||||
newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||
|
||||
return netIP, nil
|
||||
}
|
|
@ -7,14 +7,16 @@ import (
|
|||
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
func TestLocalNameServer(t *testing.T) {
|
||||
s := NewLocalNameServer()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, err := s.QueryIP(ctx, "google.com", IPOption{
|
||||
ips, err := s.QueryIP(ctx, "google.com", dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
cancel()
|
||||
common.Must(err)
|
||||
|
|
|
@ -31,6 +31,7 @@ type Server struct {
|
|||
hosts *StaticHosts
|
||||
clientIP net.IP
|
||||
clients []Client // clientIdx -> Client
|
||||
ctx context.Context
|
||||
ipIndexMap []*MultiGeoIPMatcher // clientIdx -> *MultiGeoIPMatcher
|
||||
domainRules [][]string // clientIdx -> domainRuleIdx -> DomainRule
|
||||
domainMatcher strmatcher.IndexMatcher
|
||||
|
@ -75,6 +76,7 @@ func generateRandomTag() string {
|
|||
func New(ctx context.Context, config *Config) (*Server, error) {
|
||||
server := &Server{
|
||||
clients: make([]Client, 0, len(config.NameServers)+len(config.NameServer)),
|
||||
ctx: ctx,
|
||||
tag: config.Tag,
|
||||
}
|
||||
if server.tag == "" {
|
||||
|
@ -144,6 +146,9 @@ func New(ctx context.Context, config *Config) (*Server, error) {
|
|||
server.clients[idx] = c
|
||||
}))
|
||||
|
||||
case address.Family().IsDomain() && address.Domain() == "fakedns":
|
||||
server.clients = append(server.clients, NewFakeDNSServer())
|
||||
|
||||
default:
|
||||
// UDP classic DNS mode
|
||||
dest := endpoint.AsDestination()
|
||||
|
@ -295,8 +300,8 @@ func (s *Server) Match(idx int, client Client, domain string, ips []net.IP) ([]n
|
|||
return newIps, nil
|
||||
}
|
||||
|
||||
func (s *Server) queryIPTimeout(idx int, client Client, domain string, option IPOption) ([]net.IP, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*4)
|
||||
func (s *Server) queryIPTimeout(idx int, client Client, domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
ctx, cancel := context.WithTimeout(s.ctx, time.Second*4)
|
||||
if len(s.tag) > 0 {
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Tag: s.tag,
|
||||
|
@ -314,31 +319,7 @@ func (s *Server) queryIPTimeout(idx int, client Client, domain string, option IP
|
|||
return ips, err
|
||||
}
|
||||
|
||||
// LookupIP implements dns.Client.
|
||||
func (s *Server) LookupIP(domain string) ([]net.IP, error) {
|
||||
return s.lookupIPInternal(domain, IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}
|
||||
|
||||
// LookupIPv4 implements dns.IPv4Lookup.
|
||||
func (s *Server) LookupIPv4(domain string) ([]net.IP, error) {
|
||||
return s.lookupIPInternal(domain, IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
}
|
||||
|
||||
// LookupIPv6 implements dns.IPv6Lookup.
|
||||
func (s *Server) LookupIPv6(domain string) ([]net.IP, error) {
|
||||
return s.lookupIPInternal(domain, IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) lookupStatic(domain string, option IPOption, depth int32) []net.Address {
|
||||
func (s *Server) lookupStatic(domain string, option dns.IPOption, depth int32) []net.Address {
|
||||
ips := s.hosts.LookupIP(domain, option)
|
||||
if ips == nil {
|
||||
return nil
|
||||
|
@ -362,14 +343,15 @@ func toNetIP(ips []net.Address) []net.IP {
|
|||
return netips
|
||||
}
|
||||
|
||||
func (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, error) {
|
||||
// LookupIP implements dns.Client.
|
||||
func (s *Server) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
if domain == "" {
|
||||
return nil, newError("empty domain name")
|
||||
}
|
||||
domain = strings.ToLower(domain)
|
||||
|
||||
// normalize the FQDN form query
|
||||
if domain[len(domain)-1] == '.' {
|
||||
if strings.HasSuffix(domain, ".") {
|
||||
domain = domain[:len(domain)-1]
|
||||
}
|
||||
|
||||
|
@ -406,6 +388,10 @@ func (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, err
|
|||
for _, idx := range indices {
|
||||
clientIdx := int(s.matcherInfos[idx].clientIdx)
|
||||
matchedClient = s.clients[clientIdx]
|
||||
if !option.FakeEnable && strings.EqualFold(matchedClient.Name(), "FakeDNS") {
|
||||
newError("skip DNS resolution for domain ", domain, " at server ", matchedClient.Name()).AtDebug().WriteToLog()
|
||||
continue
|
||||
}
|
||||
ips, err := s.queryIPTimeout(clientIdx, matchedClient, domain, option)
|
||||
if len(ips) > 0 {
|
||||
return ips, nil
|
||||
|
@ -425,7 +411,10 @@ func (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, err
|
|||
newError("domain ", domain, " at server ", client.Name(), " idx:", idx, " already lookup failed, just ignore").AtDebug().WriteToLog()
|
||||
continue
|
||||
}
|
||||
|
||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
||||
newError("skip DNS resolution for domain ", domain, " at server ", client.Name()).AtDebug().WriteToLog()
|
||||
continue
|
||||
}
|
||||
ips, err := s.queryIPTimeout(idx, client, domain, option)
|
||||
if len(ips) > 0 {
|
||||
return ips, nil
|
||||
|
|
|
@ -154,7 +154,11 @@ func TestUDPServerSubnet(t *testing.T) {
|
|||
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
ips, err := client.LookupIP("google.com")
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -209,7 +213,11 @@ func TestUDPServer(t *testing.T) {
|
|||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com")
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -220,7 +228,11 @@ func TestUDPServer(t *testing.T) {
|
|||
}
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("facebook.com")
|
||||
ips, err := client.LookupIP("facebook.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -231,7 +243,11 @@ func TestUDPServer(t *testing.T) {
|
|||
}
|
||||
|
||||
{
|
||||
_, err := client.LookupIP("notexist.google.com")
|
||||
_, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("nil error")
|
||||
}
|
||||
|
@ -241,8 +257,11 @@ func TestUDPServer(t *testing.T) {
|
|||
}
|
||||
|
||||
{
|
||||
clientv6 := client.(feature_dns.IPv6Lookup)
|
||||
ips, err := clientv6.LookupIPv6("ipv4only.google.com")
|
||||
ips, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != feature_dns.ErrEmptyResponse {
|
||||
t.Fatal("error: ", err)
|
||||
}
|
||||
|
@ -254,7 +273,11 @@ func TestUDPServer(t *testing.T) {
|
|||
dnsServer.Shutdown()
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com")
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -331,7 +354,11 @@ func TestPrioritizedDomain(t *testing.T) {
|
|||
startTime := time.Now()
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com")
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -390,10 +417,12 @@ func TestUDPServerIPv6(t *testing.T) {
|
|||
common.Must(err)
|
||||
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
client6 := client.(feature_dns.IPv6Lookup)
|
||||
|
||||
{
|
||||
ips, err := client6.LookupIPv6("ipv6.google.com")
|
||||
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -456,7 +485,11 @@ func TestStaticHostDomain(t *testing.T) {
|
|||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("example.com")
|
||||
ips, err := client.LookupIP("example.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -563,7 +596,11 @@ func TestIPMatch(t *testing.T) {
|
|||
startTime := time.Now()
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com")
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -682,7 +719,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
startTime := time.Now()
|
||||
|
||||
{ // Will match dotless:
|
||||
ips, err := client.LookupIP("hostname")
|
||||
ips, err := client.LookupIP("hostname", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -693,7 +734,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match domain:local
|
||||
ips, err := client.LookupIP("hostname.local")
|
||||
ips, err := client.LookupIP("hostname.local", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -704,7 +749,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match static ip
|
||||
ips, err := client.LookupIP("hostnamestatic")
|
||||
ips, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -715,7 +764,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match domain replacing
|
||||
ips, err := client.LookupIP("hostnamealias")
|
||||
ips, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -726,7 +779,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
|
||||
ips, err := client.LookupIP("localhost")
|
||||
ips, err := client.LookupIP("localhost", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -737,7 +794,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, err := client.LookupIP("localhost-a")
|
||||
ips, err := client.LookupIP("localhost-a", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -748,7 +809,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, err := client.LookupIP("localhost-b")
|
||||
ips, err := client.LookupIP("localhost-b", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -759,7 +824,11 @@ func TestLocalDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match dotless:
|
||||
ips, err := client.LookupIP("Mijia Cloud")
|
||||
ips, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -921,7 +990,11 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||
startTime := time.Now()
|
||||
|
||||
{ // Will match server 1,2 and server 1 returns expected ip
|
||||
ips, err := client.LookupIP("google.com")
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -932,8 +1005,11 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
|
||||
clientv4 := client.(feature_dns.IPv4Lookup)
|
||||
ips, err := clientv4.LookupIPv4("ipv6.google.com")
|
||||
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -944,7 +1020,11 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match server 3,1,2 and server 3 returns expected one
|
||||
ips, err := client.LookupIP("api.google.com")
|
||||
ips, err := client.LookupIP("api.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@ -955,7 +1035,11 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
{ // Will match server 4,3,1,2 and server 4 returns expected one
|
||||
ips, err := client.LookupIP("v2.api.google.com")
|
||||
ips, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
|
|||
Execute: s.Cleanup,
|
||||
}
|
||||
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
|
||||
newError("DNS: created udp client inited for ", address.NetAddr()).AtInfo().WriteToLog()
|
||||
newError("DNS: created UDP client initialized for ", address.NetAddr()).AtInfo().WriteToLog()
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
|
|||
s.requests[id] = *req
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, option IPOption) {
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, option dns_feature.IPOption) {
|
||||
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP))
|
||||
|
@ -206,7 +206,7 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, option
|
|||
}
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
|
||||
func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
@ -244,7 +244,8 @@ func (s *ClassicNameServer) findIPsForDomain(domain string, option IPOption) ([]
|
|||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {
|
||||
// QueryIP implements Server.
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue