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