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