github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/app/dns/dns_test.go (about)

     1  package dns_test
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/miekg/dns"
     9  	"github.com/xtls/xray-core/app/dispatcher"
    10  	. "github.com/xtls/xray-core/app/dns"
    11  	"github.com/xtls/xray-core/app/policy"
    12  	"github.com/xtls/xray-core/app/proxyman"
    13  	_ "github.com/xtls/xray-core/app/proxyman/outbound"
    14  	"github.com/xtls/xray-core/app/router"
    15  	"github.com/xtls/xray-core/common"
    16  	"github.com/xtls/xray-core/common/errors"
    17  	"github.com/xtls/xray-core/common/net"
    18  	"github.com/xtls/xray-core/common/serial"
    19  	"github.com/xtls/xray-core/core"
    20  	feature_dns "github.com/xtls/xray-core/features/dns"
    21  	"github.com/xtls/xray-core/proxy/freedom"
    22  	"github.com/xtls/xray-core/testing/servers/udp"
    23  )
    24  
    25  type staticHandler struct{}
    26  
    27  func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
    28  	ans := new(dns.Msg)
    29  	ans.Id = r.Id
    30  
    31  	var clientIP net.IP
    32  
    33  	opt := r.IsEdns0()
    34  	if opt != nil {
    35  		for _, o := range opt.Option {
    36  			if o.Option() == dns.EDNS0SUBNET {
    37  				subnet := o.(*dns.EDNS0_SUBNET)
    38  				clientIP = subnet.Address
    39  			}
    40  		}
    41  	}
    42  
    43  	for _, q := range r.Question {
    44  		switch {
    45  		case q.Name == "google.com." && q.Qtype == dns.TypeA:
    46  			if clientIP == nil {
    47  				rr, _ := dns.NewRR("google.com. IN A 8.8.8.8")
    48  				ans.Answer = append(ans.Answer, rr)
    49  			} else {
    50  				rr, _ := dns.NewRR("google.com. IN A 8.8.4.4")
    51  				ans.Answer = append(ans.Answer, rr)
    52  			}
    53  
    54  		case q.Name == "api.google.com." && q.Qtype == dns.TypeA:
    55  			rr, _ := dns.NewRR("api.google.com. IN A 8.8.7.7")
    56  			ans.Answer = append(ans.Answer, rr)
    57  
    58  		case q.Name == "v2.api.google.com." && q.Qtype == dns.TypeA:
    59  			rr, _ := dns.NewRR("v2.api.google.com. IN A 8.8.7.8")
    60  			ans.Answer = append(ans.Answer, rr)
    61  
    62  		case q.Name == "facebook.com." && q.Qtype == dns.TypeA:
    63  			rr, _ := dns.NewRR("facebook.com. IN A 9.9.9.9")
    64  			ans.Answer = append(ans.Answer, rr)
    65  
    66  		case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeA:
    67  			rr, err := dns.NewRR("ipv6.google.com. IN A 8.8.8.7")
    68  			common.Must(err)
    69  			ans.Answer = append(ans.Answer, rr)
    70  
    71  		case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeAAAA:
    72  			rr, err := dns.NewRR("ipv6.google.com. IN AAAA 2001:4860:4860::8888")
    73  			common.Must(err)
    74  			ans.Answer = append(ans.Answer, rr)
    75  
    76  		case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
    77  			ans.MsgHdr.Rcode = dns.RcodeNameError
    78  
    79  		case q.Name == "hostname." && q.Qtype == dns.TypeA:
    80  			rr, _ := dns.NewRR("hostname. IN A 127.0.0.1")
    81  			ans.Answer = append(ans.Answer, rr)
    82  
    83  		case q.Name == "hostname.local." && q.Qtype == dns.TypeA:
    84  			rr, _ := dns.NewRR("hostname.local. IN A 127.0.0.1")
    85  			ans.Answer = append(ans.Answer, rr)
    86  
    87  		case q.Name == "hostname.localdomain." && q.Qtype == dns.TypeA:
    88  			rr, _ := dns.NewRR("hostname.localdomain. IN A 127.0.0.1")
    89  			ans.Answer = append(ans.Answer, rr)
    90  
    91  		case q.Name == "localhost." && q.Qtype == dns.TypeA:
    92  			rr, _ := dns.NewRR("localhost. IN A 127.0.0.2")
    93  			ans.Answer = append(ans.Answer, rr)
    94  
    95  		case q.Name == "localhost-a." && q.Qtype == dns.TypeA:
    96  			rr, _ := dns.NewRR("localhost-a. IN A 127.0.0.3")
    97  			ans.Answer = append(ans.Answer, rr)
    98  
    99  		case q.Name == "localhost-b." && q.Qtype == dns.TypeA:
   100  			rr, _ := dns.NewRR("localhost-b. IN A 127.0.0.4")
   101  			ans.Answer = append(ans.Answer, rr)
   102  
   103  		case q.Name == "Mijia\\ Cloud." && q.Qtype == dns.TypeA:
   104  			rr, _ := dns.NewRR("Mijia\\ Cloud. IN A 127.0.0.1")
   105  			ans.Answer = append(ans.Answer, rr)
   106  		}
   107  	}
   108  	w.WriteMsg(ans)
   109  }
   110  
   111  func TestUDPServerSubnet(t *testing.T) {
   112  	port := udp.PickPort()
   113  
   114  	dnsServer := dns.Server{
   115  		Addr:    "127.0.0.1:" + port.String(),
   116  		Net:     "udp",
   117  		Handler: &staticHandler{},
   118  		UDPSize: 1200,
   119  	}
   120  
   121  	go dnsServer.ListenAndServe()
   122  	time.Sleep(time.Second)
   123  
   124  	config := &core.Config{
   125  		App: []*serial.TypedMessage{
   126  			serial.ToTypedMessage(&Config{
   127  				NameServers: []*net.Endpoint{
   128  					{
   129  						Network: net.Network_UDP,
   130  						Address: &net.IPOrDomain{
   131  							Address: &net.IPOrDomain_Ip{
   132  								Ip: []byte{127, 0, 0, 1},
   133  							},
   134  						},
   135  						Port: uint32(port),
   136  					},
   137  				},
   138  				ClientIp: []byte{7, 8, 9, 10},
   139  			}),
   140  			serial.ToTypedMessage(&dispatcher.Config{}),
   141  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   142  			serial.ToTypedMessage(&policy.Config{}),
   143  		},
   144  		Outbound: []*core.OutboundHandlerConfig{
   145  			{
   146  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   147  			},
   148  		},
   149  	}
   150  
   151  	v, err := core.New(config)
   152  	common.Must(err)
   153  
   154  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   155  
   156  	ips, err := client.LookupIP("google.com", feature_dns.IPOption{
   157  		IPv4Enable: true,
   158  		IPv6Enable: true,
   159  		FakeEnable: false,
   160  	})
   161  	if err != nil {
   162  		t.Fatal("unexpected error: ", err)
   163  	}
   164  
   165  	if r := cmp.Diff(ips, []net.IP{{8, 8, 4, 4}}); r != "" {
   166  		t.Fatal(r)
   167  	}
   168  }
   169  
   170  func TestUDPServer(t *testing.T) {
   171  	port := udp.PickPort()
   172  
   173  	dnsServer := dns.Server{
   174  		Addr:    "127.0.0.1:" + port.String(),
   175  		Net:     "udp",
   176  		Handler: &staticHandler{},
   177  		UDPSize: 1200,
   178  	}
   179  
   180  	go dnsServer.ListenAndServe()
   181  	time.Sleep(time.Second)
   182  
   183  	config := &core.Config{
   184  		App: []*serial.TypedMessage{
   185  			serial.ToTypedMessage(&Config{
   186  				NameServers: []*net.Endpoint{
   187  					{
   188  						Network: net.Network_UDP,
   189  						Address: &net.IPOrDomain{
   190  							Address: &net.IPOrDomain_Ip{
   191  								Ip: []byte{127, 0, 0, 1},
   192  							},
   193  						},
   194  						Port: uint32(port),
   195  					},
   196  				},
   197  			}),
   198  			serial.ToTypedMessage(&dispatcher.Config{}),
   199  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   200  			serial.ToTypedMessage(&policy.Config{}),
   201  		},
   202  		Outbound: []*core.OutboundHandlerConfig{
   203  			{
   204  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   205  			},
   206  		},
   207  	}
   208  
   209  	v, err := core.New(config)
   210  	common.Must(err)
   211  
   212  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   213  
   214  	{
   215  		ips, err := client.LookupIP("google.com", feature_dns.IPOption{
   216  			IPv4Enable: true,
   217  			IPv6Enable: true,
   218  			FakeEnable: false,
   219  		})
   220  		if err != nil {
   221  			t.Fatal("unexpected error: ", err)
   222  		}
   223  
   224  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
   225  			t.Fatal(r)
   226  		}
   227  	}
   228  
   229  	{
   230  		ips, err := client.LookupIP("facebook.com", feature_dns.IPOption{
   231  			IPv4Enable: true,
   232  			IPv6Enable: true,
   233  			FakeEnable: false,
   234  		})
   235  		if err != nil {
   236  			t.Fatal("unexpected error: ", err)
   237  		}
   238  
   239  		if r := cmp.Diff(ips, []net.IP{{9, 9, 9, 9}}); r != "" {
   240  			t.Fatal(r)
   241  		}
   242  	}
   243  
   244  	{
   245  		_, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
   246  			IPv4Enable: true,
   247  			IPv6Enable: true,
   248  			FakeEnable: false,
   249  		})
   250  		if err == nil {
   251  			t.Fatal("nil error")
   252  		}
   253  		if r := feature_dns.RCodeFromError(err); r != uint16(dns.RcodeNameError) {
   254  			t.Fatal("expected NameError, but got ", r)
   255  		}
   256  	}
   257  
   258  	{
   259  		ips, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
   260  			IPv4Enable: false,
   261  			IPv6Enable: true,
   262  			FakeEnable: false,
   263  		})
   264  		if !errors.AllEqual(feature_dns.ErrEmptyResponse, errors.Cause(err)) {
   265  			t.Fatal("error: ", err)
   266  		}
   267  		if len(ips) != 0 {
   268  			t.Fatal("ips: ", ips)
   269  		}
   270  	}
   271  
   272  	dnsServer.Shutdown()
   273  
   274  	{
   275  		ips, err := client.LookupIP("google.com", feature_dns.IPOption{
   276  			IPv4Enable: true,
   277  			IPv6Enable: true,
   278  			FakeEnable: false,
   279  		})
   280  		if err != nil {
   281  			t.Fatal("unexpected error: ", err)
   282  		}
   283  
   284  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
   285  			t.Fatal(r)
   286  		}
   287  	}
   288  }
   289  
   290  func TestPrioritizedDomain(t *testing.T) {
   291  	port := udp.PickPort()
   292  
   293  	dnsServer := dns.Server{
   294  		Addr:    "127.0.0.1:" + port.String(),
   295  		Net:     "udp",
   296  		Handler: &staticHandler{},
   297  		UDPSize: 1200,
   298  	}
   299  
   300  	go dnsServer.ListenAndServe()
   301  	time.Sleep(time.Second)
   302  
   303  	config := &core.Config{
   304  		App: []*serial.TypedMessage{
   305  			serial.ToTypedMessage(&Config{
   306  				NameServers: []*net.Endpoint{
   307  					{
   308  						Network: net.Network_UDP,
   309  						Address: &net.IPOrDomain{
   310  							Address: &net.IPOrDomain_Ip{
   311  								Ip: []byte{127, 0, 0, 1},
   312  							},
   313  						},
   314  						Port: 9999, /* unreachable */
   315  					},
   316  				},
   317  				NameServer: []*NameServer{
   318  					{
   319  						Address: &net.Endpoint{
   320  							Network: net.Network_UDP,
   321  							Address: &net.IPOrDomain{
   322  								Address: &net.IPOrDomain_Ip{
   323  									Ip: []byte{127, 0, 0, 1},
   324  								},
   325  							},
   326  							Port: uint32(port),
   327  						},
   328  						PrioritizedDomain: []*NameServer_PriorityDomain{
   329  							{
   330  								Type:   DomainMatchingType_Full,
   331  								Domain: "google.com",
   332  							},
   333  						},
   334  					},
   335  				},
   336  			}),
   337  			serial.ToTypedMessage(&dispatcher.Config{}),
   338  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   339  			serial.ToTypedMessage(&policy.Config{}),
   340  		},
   341  		Outbound: []*core.OutboundHandlerConfig{
   342  			{
   343  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   344  			},
   345  		},
   346  	}
   347  
   348  	v, err := core.New(config)
   349  	common.Must(err)
   350  
   351  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   352  
   353  	startTime := time.Now()
   354  
   355  	{
   356  		ips, err := client.LookupIP("google.com", feature_dns.IPOption{
   357  			IPv4Enable: true,
   358  			IPv6Enable: true,
   359  			FakeEnable: false,
   360  		})
   361  		if err != nil {
   362  			t.Fatal("unexpected error: ", err)
   363  		}
   364  
   365  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
   366  			t.Fatal(r)
   367  		}
   368  	}
   369  
   370  	endTime := time.Now()
   371  	if startTime.After(endTime.Add(time.Second * 2)) {
   372  		t.Error("DNS query doesn't finish in 2 seconds.")
   373  	}
   374  }
   375  
   376  func TestUDPServerIPv6(t *testing.T) {
   377  	port := udp.PickPort()
   378  
   379  	dnsServer := dns.Server{
   380  		Addr:    "127.0.0.1:" + port.String(),
   381  		Net:     "udp",
   382  		Handler: &staticHandler{},
   383  		UDPSize: 1200,
   384  	}
   385  
   386  	go dnsServer.ListenAndServe()
   387  	time.Sleep(time.Second)
   388  
   389  	config := &core.Config{
   390  		App: []*serial.TypedMessage{
   391  			serial.ToTypedMessage(&Config{
   392  				NameServers: []*net.Endpoint{
   393  					{
   394  						Network: net.Network_UDP,
   395  						Address: &net.IPOrDomain{
   396  							Address: &net.IPOrDomain_Ip{
   397  								Ip: []byte{127, 0, 0, 1},
   398  							},
   399  						},
   400  						Port: uint32(port),
   401  					},
   402  				},
   403  			}),
   404  			serial.ToTypedMessage(&dispatcher.Config{}),
   405  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   406  			serial.ToTypedMessage(&policy.Config{}),
   407  		},
   408  		Outbound: []*core.OutboundHandlerConfig{
   409  			{
   410  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   411  			},
   412  		},
   413  	}
   414  
   415  	v, err := core.New(config)
   416  	common.Must(err)
   417  
   418  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   419  	{
   420  		ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
   421  			IPv4Enable: false,
   422  			IPv6Enable: true,
   423  			FakeEnable: false,
   424  		})
   425  		if err != nil {
   426  			t.Fatal("unexpected error: ", err)
   427  		}
   428  
   429  		if r := cmp.Diff(ips, []net.IP{{32, 1, 72, 96, 72, 96, 0, 0, 0, 0, 0, 0, 0, 0, 136, 136}}); r != "" {
   430  			t.Fatal(r)
   431  		}
   432  	}
   433  }
   434  
   435  func TestStaticHostDomain(t *testing.T) {
   436  	port := udp.PickPort()
   437  
   438  	dnsServer := dns.Server{
   439  		Addr:    "127.0.0.1:" + port.String(),
   440  		Net:     "udp",
   441  		Handler: &staticHandler{},
   442  		UDPSize: 1200,
   443  	}
   444  
   445  	go dnsServer.ListenAndServe()
   446  	time.Sleep(time.Second)
   447  
   448  	config := &core.Config{
   449  		App: []*serial.TypedMessage{
   450  			serial.ToTypedMessage(&Config{
   451  				NameServers: []*net.Endpoint{
   452  					{
   453  						Network: net.Network_UDP,
   454  						Address: &net.IPOrDomain{
   455  							Address: &net.IPOrDomain_Ip{
   456  								Ip: []byte{127, 0, 0, 1},
   457  							},
   458  						},
   459  						Port: uint32(port),
   460  					},
   461  				},
   462  				StaticHosts: []*Config_HostMapping{
   463  					{
   464  						Type:          DomainMatchingType_Full,
   465  						Domain:        "example.com",
   466  						ProxiedDomain: "google.com",
   467  					},
   468  				},
   469  			}),
   470  			serial.ToTypedMessage(&dispatcher.Config{}),
   471  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   472  			serial.ToTypedMessage(&policy.Config{}),
   473  		},
   474  		Outbound: []*core.OutboundHandlerConfig{
   475  			{
   476  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   477  			},
   478  		},
   479  	}
   480  
   481  	v, err := core.New(config)
   482  	common.Must(err)
   483  
   484  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   485  
   486  	{
   487  		ips, err := client.LookupIP("example.com", feature_dns.IPOption{
   488  			IPv4Enable: true,
   489  			IPv6Enable: true,
   490  			FakeEnable: false,
   491  		})
   492  		if err != nil {
   493  			t.Fatal("unexpected error: ", err)
   494  		}
   495  
   496  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
   497  			t.Fatal(r)
   498  		}
   499  	}
   500  
   501  	dnsServer.Shutdown()
   502  }
   503  
   504  func TestIPMatch(t *testing.T) {
   505  	port := udp.PickPort()
   506  
   507  	dnsServer := dns.Server{
   508  		Addr:    "127.0.0.1:" + port.String(),
   509  		Net:     "udp",
   510  		Handler: &staticHandler{},
   511  		UDPSize: 1200,
   512  	}
   513  
   514  	go dnsServer.ListenAndServe()
   515  	time.Sleep(time.Second)
   516  
   517  	config := &core.Config{
   518  		App: []*serial.TypedMessage{
   519  			serial.ToTypedMessage(&Config{
   520  				NameServer: []*NameServer{
   521  					// private dns, not match
   522  					{
   523  						Address: &net.Endpoint{
   524  							Network: net.Network_UDP,
   525  							Address: &net.IPOrDomain{
   526  								Address: &net.IPOrDomain_Ip{
   527  									Ip: []byte{127, 0, 0, 1},
   528  								},
   529  							},
   530  							Port: uint32(port),
   531  						},
   532  						Geoip: []*router.GeoIP{
   533  							{
   534  								CountryCode: "local",
   535  								Cidr: []*router.CIDR{
   536  									{
   537  										// inner ip, will not match
   538  										Ip:     []byte{192, 168, 11, 1},
   539  										Prefix: 32,
   540  									},
   541  								},
   542  							},
   543  						},
   544  					},
   545  					// second dns, match ip
   546  					{
   547  						Address: &net.Endpoint{
   548  							Network: net.Network_UDP,
   549  							Address: &net.IPOrDomain{
   550  								Address: &net.IPOrDomain_Ip{
   551  									Ip: []byte{127, 0, 0, 1},
   552  								},
   553  							},
   554  							Port: uint32(port),
   555  						},
   556  						Geoip: []*router.GeoIP{
   557  							{
   558  								CountryCode: "test",
   559  								Cidr: []*router.CIDR{
   560  									{
   561  										Ip:     []byte{8, 8, 8, 8},
   562  										Prefix: 32,
   563  									},
   564  								},
   565  							},
   566  							{
   567  								CountryCode: "test",
   568  								Cidr: []*router.CIDR{
   569  									{
   570  										Ip:     []byte{8, 8, 8, 4},
   571  										Prefix: 32,
   572  									},
   573  								},
   574  							},
   575  						},
   576  					},
   577  				},
   578  			}),
   579  			serial.ToTypedMessage(&dispatcher.Config{}),
   580  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   581  			serial.ToTypedMessage(&policy.Config{}),
   582  		},
   583  		Outbound: []*core.OutboundHandlerConfig{
   584  			{
   585  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   586  			},
   587  		},
   588  	}
   589  
   590  	v, err := core.New(config)
   591  	common.Must(err)
   592  
   593  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   594  
   595  	startTime := time.Now()
   596  
   597  	{
   598  		ips, err := client.LookupIP("google.com", feature_dns.IPOption{
   599  			IPv4Enable: true,
   600  			IPv6Enable: true,
   601  			FakeEnable: false,
   602  		})
   603  		if err != nil {
   604  			t.Fatal("unexpected error: ", err)
   605  		}
   606  
   607  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
   608  			t.Fatal(r)
   609  		}
   610  	}
   611  
   612  	endTime := time.Now()
   613  	if startTime.After(endTime.Add(time.Second * 2)) {
   614  		t.Error("DNS query doesn't finish in 2 seconds.")
   615  	}
   616  }
   617  
   618  func TestLocalDomain(t *testing.T) {
   619  	port := udp.PickPort()
   620  
   621  	dnsServer := dns.Server{
   622  		Addr:    "127.0.0.1:" + port.String(),
   623  		Net:     "udp",
   624  		Handler: &staticHandler{},
   625  		UDPSize: 1200,
   626  	}
   627  
   628  	go dnsServer.ListenAndServe()
   629  	time.Sleep(time.Second)
   630  
   631  	config := &core.Config{
   632  		App: []*serial.TypedMessage{
   633  			serial.ToTypedMessage(&Config{
   634  				NameServers: []*net.Endpoint{
   635  					{
   636  						Network: net.Network_UDP,
   637  						Address: &net.IPOrDomain{
   638  							Address: &net.IPOrDomain_Ip{
   639  								Ip: []byte{127, 0, 0, 1},
   640  							},
   641  						},
   642  						Port: 9999, /* unreachable */
   643  					},
   644  				},
   645  				NameServer: []*NameServer{
   646  					{
   647  						Address: &net.Endpoint{
   648  							Network: net.Network_UDP,
   649  							Address: &net.IPOrDomain{
   650  								Address: &net.IPOrDomain_Ip{
   651  									Ip: []byte{127, 0, 0, 1},
   652  								},
   653  							},
   654  							Port: uint32(port),
   655  						},
   656  						PrioritizedDomain: []*NameServer_PriorityDomain{
   657  							// Equivalent of dotless:localhost
   658  							{Type: DomainMatchingType_Regex, Domain: "^[^.]*localhost[^.]*$"},
   659  						},
   660  						Geoip: []*router.GeoIP{
   661  							{ // Will match localhost, localhost-a and localhost-b,
   662  								CountryCode: "local",
   663  								Cidr: []*router.CIDR{
   664  									{Ip: []byte{127, 0, 0, 2}, Prefix: 32},
   665  									{Ip: []byte{127, 0, 0, 3}, Prefix: 32},
   666  									{Ip: []byte{127, 0, 0, 4}, Prefix: 32},
   667  								},
   668  							},
   669  						},
   670  					},
   671  					{
   672  						Address: &net.Endpoint{
   673  							Network: net.Network_UDP,
   674  							Address: &net.IPOrDomain{
   675  								Address: &net.IPOrDomain_Ip{
   676  									Ip: []byte{127, 0, 0, 1},
   677  								},
   678  							},
   679  							Port: uint32(port),
   680  						},
   681  						PrioritizedDomain: []*NameServer_PriorityDomain{
   682  							// Equivalent of dotless: and domain:local
   683  							{Type: DomainMatchingType_Regex, Domain: "^[^.]*$"},
   684  							{Type: DomainMatchingType_Subdomain, Domain: "local"},
   685  							{Type: DomainMatchingType_Subdomain, Domain: "localdomain"},
   686  						},
   687  					},
   688  				},
   689  				StaticHosts: []*Config_HostMapping{
   690  					{
   691  						Type:   DomainMatchingType_Full,
   692  						Domain: "hostnamestatic",
   693  						Ip:     [][]byte{{127, 0, 0, 53}},
   694  					},
   695  					{
   696  						Type:          DomainMatchingType_Full,
   697  						Domain:        "hostnamealias",
   698  						ProxiedDomain: "hostname.localdomain",
   699  					},
   700  				},
   701  			}),
   702  			serial.ToTypedMessage(&dispatcher.Config{}),
   703  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   704  			serial.ToTypedMessage(&policy.Config{}),
   705  		},
   706  		Outbound: []*core.OutboundHandlerConfig{
   707  			{
   708  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   709  			},
   710  		},
   711  	}
   712  
   713  	v, err := core.New(config)
   714  	common.Must(err)
   715  
   716  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   717  
   718  	startTime := time.Now()
   719  
   720  	{ // Will match dotless:
   721  		ips, err := client.LookupIP("hostname", feature_dns.IPOption{
   722  			IPv4Enable: true,
   723  			IPv6Enable: true,
   724  			FakeEnable: false,
   725  		})
   726  		if err != nil {
   727  			t.Fatal("unexpected error: ", err)
   728  		}
   729  
   730  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
   731  			t.Fatal(r)
   732  		}
   733  	}
   734  
   735  	{ // Will match domain:local
   736  		ips, err := client.LookupIP("hostname.local", feature_dns.IPOption{
   737  			IPv4Enable: true,
   738  			IPv6Enable: true,
   739  			FakeEnable: false,
   740  		})
   741  		if err != nil {
   742  			t.Fatal("unexpected error: ", err)
   743  		}
   744  
   745  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
   746  			t.Fatal(r)
   747  		}
   748  	}
   749  
   750  	{ // Will match static ip
   751  		ips, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
   752  			IPv4Enable: true,
   753  			IPv6Enable: true,
   754  			FakeEnable: false,
   755  		})
   756  		if err != nil {
   757  			t.Fatal("unexpected error: ", err)
   758  		}
   759  
   760  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 53}}); r != "" {
   761  			t.Fatal(r)
   762  		}
   763  	}
   764  
   765  	{ // Will match domain replacing
   766  		ips, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
   767  			IPv4Enable: true,
   768  			IPv6Enable: true,
   769  			FakeEnable: false,
   770  		})
   771  		if err != nil {
   772  			t.Fatal("unexpected error: ", err)
   773  		}
   774  
   775  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
   776  			t.Fatal(r)
   777  		}
   778  	}
   779  
   780  	{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
   781  		ips, err := client.LookupIP("localhost", feature_dns.IPOption{
   782  			IPv4Enable: true,
   783  			IPv6Enable: true,
   784  			FakeEnable: false,
   785  		})
   786  		if err != nil {
   787  			t.Fatal("unexpected error: ", err)
   788  		}
   789  
   790  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 2}}); r != "" {
   791  			t.Fatal(r)
   792  		}
   793  	}
   794  
   795  	{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
   796  		ips, err := client.LookupIP("localhost-a", feature_dns.IPOption{
   797  			IPv4Enable: true,
   798  			IPv6Enable: true,
   799  			FakeEnable: false,
   800  		})
   801  		if err != nil {
   802  			t.Fatal("unexpected error: ", err)
   803  		}
   804  
   805  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 3}}); r != "" {
   806  			t.Fatal(r)
   807  		}
   808  	}
   809  
   810  	{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
   811  		ips, err := client.LookupIP("localhost-b", feature_dns.IPOption{
   812  			IPv4Enable: true,
   813  			IPv6Enable: true,
   814  			FakeEnable: false,
   815  		})
   816  		if err != nil {
   817  			t.Fatal("unexpected error: ", err)
   818  		}
   819  
   820  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 4}}); r != "" {
   821  			t.Fatal(r)
   822  		}
   823  	}
   824  
   825  	{ // Will match dotless:
   826  		ips, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
   827  			IPv4Enable: true,
   828  			IPv6Enable: true,
   829  			FakeEnable: false,
   830  		})
   831  		if err != nil {
   832  			t.Fatal("unexpected error: ", err)
   833  		}
   834  
   835  		if r := cmp.Diff(ips, []net.IP{{127, 0, 0, 1}}); r != "" {
   836  			t.Fatal(r)
   837  		}
   838  	}
   839  
   840  	endTime := time.Now()
   841  	if startTime.After(endTime.Add(time.Second * 2)) {
   842  		t.Error("DNS query doesn't finish in 2 seconds.")
   843  	}
   844  }
   845  
   846  func TestMultiMatchPrioritizedDomain(t *testing.T) {
   847  	port := udp.PickPort()
   848  
   849  	dnsServer := dns.Server{
   850  		Addr:    "127.0.0.1:" + port.String(),
   851  		Net:     "udp",
   852  		Handler: &staticHandler{},
   853  		UDPSize: 1200,
   854  	}
   855  
   856  	go dnsServer.ListenAndServe()
   857  	time.Sleep(time.Second)
   858  
   859  	config := &core.Config{
   860  		App: []*serial.TypedMessage{
   861  			serial.ToTypedMessage(&Config{
   862  				NameServers: []*net.Endpoint{
   863  					{
   864  						Network: net.Network_UDP,
   865  						Address: &net.IPOrDomain{
   866  							Address: &net.IPOrDomain_Ip{
   867  								Ip: []byte{127, 0, 0, 1},
   868  							},
   869  						},
   870  						Port: 9999, /* unreachable */
   871  					},
   872  				},
   873  				NameServer: []*NameServer{
   874  					{
   875  						Address: &net.Endpoint{
   876  							Network: net.Network_UDP,
   877  							Address: &net.IPOrDomain{
   878  								Address: &net.IPOrDomain_Ip{
   879  									Ip: []byte{127, 0, 0, 1},
   880  								},
   881  							},
   882  							Port: uint32(port),
   883  						},
   884  						PrioritizedDomain: []*NameServer_PriorityDomain{
   885  							{
   886  								Type:   DomainMatchingType_Subdomain,
   887  								Domain: "google.com",
   888  							},
   889  						},
   890  						Geoip: []*router.GeoIP{
   891  							{ // Will only match 8.8.8.8 and 8.8.4.4
   892  								Cidr: []*router.CIDR{
   893  									{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
   894  									{Ip: []byte{8, 8, 4, 4}, Prefix: 32},
   895  								},
   896  							},
   897  						},
   898  					},
   899  					{
   900  						Address: &net.Endpoint{
   901  							Network: net.Network_UDP,
   902  							Address: &net.IPOrDomain{
   903  								Address: &net.IPOrDomain_Ip{
   904  									Ip: []byte{127, 0, 0, 1},
   905  								},
   906  							},
   907  							Port: uint32(port),
   908  						},
   909  						PrioritizedDomain: []*NameServer_PriorityDomain{
   910  							{
   911  								Type:   DomainMatchingType_Subdomain,
   912  								Domain: "google.com",
   913  							},
   914  						},
   915  						Geoip: []*router.GeoIP{
   916  							{ // Will match 8.8.8.8 and 8.8.8.7, etc
   917  								Cidr: []*router.CIDR{
   918  									{Ip: []byte{8, 8, 8, 7}, Prefix: 24},
   919  								},
   920  							},
   921  						},
   922  					},
   923  					{
   924  						Address: &net.Endpoint{
   925  							Network: net.Network_UDP,
   926  							Address: &net.IPOrDomain{
   927  								Address: &net.IPOrDomain_Ip{
   928  									Ip: []byte{127, 0, 0, 1},
   929  								},
   930  							},
   931  							Port: uint32(port),
   932  						},
   933  						PrioritizedDomain: []*NameServer_PriorityDomain{
   934  							{
   935  								Type:   DomainMatchingType_Subdomain,
   936  								Domain: "api.google.com",
   937  							},
   938  						},
   939  						Geoip: []*router.GeoIP{
   940  							{ // Will only match 8.8.7.7 (api.google.com)
   941  								Cidr: []*router.CIDR{
   942  									{Ip: []byte{8, 8, 7, 7}, Prefix: 32},
   943  								},
   944  							},
   945  						},
   946  					},
   947  					{
   948  						Address: &net.Endpoint{
   949  							Network: net.Network_UDP,
   950  							Address: &net.IPOrDomain{
   951  								Address: &net.IPOrDomain_Ip{
   952  									Ip: []byte{127, 0, 0, 1},
   953  								},
   954  							},
   955  							Port: uint32(port),
   956  						},
   957  						PrioritizedDomain: []*NameServer_PriorityDomain{
   958  							{
   959  								Type:   DomainMatchingType_Full,
   960  								Domain: "v2.api.google.com",
   961  							},
   962  						},
   963  						Geoip: []*router.GeoIP{
   964  							{ // Will only match 8.8.7.8 (v2.api.google.com)
   965  								Cidr: []*router.CIDR{
   966  									{Ip: []byte{8, 8, 7, 8}, Prefix: 32},
   967  								},
   968  							},
   969  						},
   970  					},
   971  				},
   972  			}),
   973  			serial.ToTypedMessage(&dispatcher.Config{}),
   974  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   975  			serial.ToTypedMessage(&policy.Config{}),
   976  		},
   977  		Outbound: []*core.OutboundHandlerConfig{
   978  			{
   979  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   980  			},
   981  		},
   982  	}
   983  
   984  	v, err := core.New(config)
   985  	common.Must(err)
   986  
   987  	client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   988  
   989  	startTime := time.Now()
   990  
   991  	{ // Will match server 1,2 and server 1 returns expected ip
   992  		ips, err := client.LookupIP("google.com", feature_dns.IPOption{
   993  			IPv4Enable: true,
   994  			IPv6Enable: true,
   995  			FakeEnable: false,
   996  		})
   997  		if err != nil {
   998  			t.Fatal("unexpected error: ", err)
   999  		}
  1000  
  1001  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
  1002  			t.Fatal(r)
  1003  		}
  1004  	}
  1005  
  1006  	{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
  1007  		ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
  1008  			IPv4Enable: true,
  1009  			IPv6Enable: false,
  1010  			FakeEnable: false,
  1011  		})
  1012  		if err != nil {
  1013  			t.Fatal("unexpected error: ", err)
  1014  		}
  1015  
  1016  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 7}}); r != "" {
  1017  			t.Fatal(r)
  1018  		}
  1019  	}
  1020  
  1021  	{ // Will match server 3,1,2 and server 3 returns expected one
  1022  		ips, err := client.LookupIP("api.google.com", feature_dns.IPOption{
  1023  			IPv4Enable: true,
  1024  			IPv6Enable: true,
  1025  			FakeEnable: false,
  1026  		})
  1027  		if err != nil {
  1028  			t.Fatal("unexpected error: ", err)
  1029  		}
  1030  
  1031  		if r := cmp.Diff(ips, []net.IP{{8, 8, 7, 7}}); r != "" {
  1032  			t.Fatal(r)
  1033  		}
  1034  	}
  1035  
  1036  	{ // Will match server 4,3,1,2 and server 4 returns expected one
  1037  		ips, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
  1038  			IPv4Enable: true,
  1039  			IPv6Enable: true,
  1040  			FakeEnable: false,
  1041  		})
  1042  		if err != nil {
  1043  			t.Fatal("unexpected error: ", err)
  1044  		}
  1045  
  1046  		if r := cmp.Diff(ips, []net.IP{{8, 8, 7, 8}}); r != "" {
  1047  			t.Fatal(r)
  1048  		}
  1049  	}
  1050  
  1051  	endTime := time.Now()
  1052  	if startTime.After(endTime.Add(time.Second * 2)) {
  1053  		t.Error("DNS query doesn't finish in 2 seconds.")
  1054  	}
  1055  }