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