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