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