github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/dns/fakedns_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/v2fly/v2ray-core/v5"
    12  	"github.com/v2fly/v2ray-core/v5/app/dispatcher"
    13  	. "github.com/v2fly/v2ray-core/v5/app/dns"
    14  	"github.com/v2fly/v2ray-core/v5/app/dns/fakedns"
    15  	"github.com/v2fly/v2ray-core/v5/app/policy"
    16  	"github.com/v2fly/v2ray-core/v5/app/proxyman"
    17  	"github.com/v2fly/v2ray-core/v5/common"
    18  	"github.com/v2fly/v2ray-core/v5/common/net"
    19  	"github.com/v2fly/v2ray-core/v5/common/serial"
    20  	feature_dns "github.com/v2fly/v2ray-core/v5/features/dns"
    21  	"github.com/v2fly/v2ray-core/v5/proxy/freedom"
    22  	"github.com/v2fly/v2ray-core/v5/testing/servers/udp"
    23  )
    24  
    25  func TestFakeDNS(t *testing.T) {
    26  	port := udp.PickPort()
    27  
    28  	dnsServer := dns.Server{
    29  		Addr:    "127.0.0.1:" + port.String(),
    30  		Net:     "udp",
    31  		Handler: &staticHandler{},
    32  		UDPSize: 1200,
    33  	}
    34  
    35  	go dnsServer.ListenAndServe()
    36  	time.Sleep(time.Second)
    37  
    38  	config := &core.Config{
    39  		App: []*anypb.Any{
    40  			serial.ToTypedMessage(&Config{
    41  				NameServer: []*NameServer{
    42  					{ // "fakedns"
    43  						Address: &net.Endpoint{
    44  							Network: net.Network_UDP,
    45  							Address: &net.IPOrDomain{
    46  								Address: &net.IPOrDomain_Domain{
    47  									Domain: "fakedns",
    48  								},
    49  							},
    50  							Port: uint32(53),
    51  						},
    52  					},
    53  					{ // { "address": "127.0.0.1", "port": "<port>", "domains": ["domain:google.com"], "fakedns": "198.19.0.0/16", "fallbackStrategy": "disabled" }
    54  						Address: &net.Endpoint{
    55  							Network: net.Network_UDP,
    56  							Address: &net.IPOrDomain{
    57  								Address: &net.IPOrDomain_Ip{
    58  									Ip: []byte{127, 0, 0, 1},
    59  								},
    60  							},
    61  							Port: uint32(port),
    62  						},
    63  						PrioritizedDomain: []*NameServer_PriorityDomain{
    64  							{Type: DomainMatchingType_Subdomain, Domain: "google.com"},
    65  						},
    66  						FakeDns: &fakedns.FakeDnsPoolMulti{
    67  							Pools: []*fakedns.FakeDnsPool{
    68  								{IpPool: "198.19.0.0/16", LruSize: 256},
    69  							},
    70  						},
    71  						FallbackStrategy: FallbackStrategy_Disabled.Enum(),
    72  					},
    73  				},
    74  				FakeDns: &fakedns.FakeDnsPoolMulti{ // "fakedns": "198.18.0.0/16"
    75  					Pools: []*fakedns.FakeDnsPool{
    76  						{IpPool: "198.18.0.0/16", LruSize: 256},
    77  					},
    78  				},
    79  			}),
    80  			serial.ToTypedMessage(&dispatcher.Config{}),
    81  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
    82  			serial.ToTypedMessage(&policy.Config{}),
    83  		},
    84  		Outbound: []*core.OutboundHandlerConfig{
    85  			{
    86  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
    87  			},
    88  		},
    89  	}
    90  
    91  	v, err := core.New(config)
    92  	common.Must(err)
    93  	common.Must(v.Start())
    94  
    95  	dnsClient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
    96  	fakeClient := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSClient()
    97  
    98  	var fakeIPForFacebook net.IP
    99  	var fakeIPForGoogle net.IP
   100  
   101  	{ // Lookup facebook.com with Fake Client will return 198.18.0.0/16 (global fake pool)
   102  		ips, err := fakeClient.LookupIP("facebook.com")
   103  		if err != nil {
   104  			t.Fatal("unexpected error: ", err)
   105  		}
   106  		for _, ip := range ips {
   107  			if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip) {
   108  				t.Fatal("Lookup facebook.com with fake client not in global pool 198.18.0.0/16")
   109  			}
   110  		}
   111  		fakeIPForFacebook = ips[0]
   112  	}
   113  	{ // Lookup facebook.com with Normal Client with return empty record (because UDP server matching "domain:google.com" are configured with fallback disabled)
   114  		_, err := dnsClient.LookupIP("facebook.com")
   115  		if err != feature_dns.ErrEmptyResponse {
   116  			t.Fatal("Lookup facebook.com with normal client not returning empty response")
   117  		}
   118  	}
   119  	{ // Lookup google.com with Fake Client will return 198.19.0.0/16 (local fake pool)
   120  		ips, err := fakeClient.LookupIP("google.com")
   121  		if err != nil {
   122  			t.Fatal("unexpected error: ", err)
   123  		}
   124  		for _, ip := range ips {
   125  			if !(&net.IPNet{IP: net.IP{198, 19, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip) {
   126  				t.Fatal("Lookup google.com with fake client not in global pool 198.19.0.0/16")
   127  			}
   128  		}
   129  		fakeIPForGoogle = ips[0]
   130  	}
   131  	{ // Lookup google.com with Normal Client will return 8.8.8.8
   132  		ips, err := dnsClient.LookupIP("google.com")
   133  		if err != nil {
   134  			t.Fatal("unexpected error: ", err)
   135  		}
   136  		if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
   137  			t.Fatal("Lookup google.com with normal client not returning 8.8.8.8")
   138  		}
   139  	}
   140  
   141  	fakeEngine := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSEngine().(feature_dns.FakeDNSEngineRev0)
   142  	{
   143  		if !fakeEngine.IsIPInIPPool(net.IPAddress(fakeIPForFacebook)) {
   144  			t.Fatal("Fake IP of domain facebook.com not in FakeDNSEngine's pool.")
   145  		}
   146  		if !fakeEngine.IsIPInIPPool(net.IPAddress(fakeIPForGoogle)) {
   147  			t.Fatal("Fake IP of domain google.com not in FakeDNSEngine's pool.")
   148  		}
   149  	}
   150  	{
   151  		if domain := fakeEngine.GetDomainFromFakeDNS(net.IPAddress(fakeIPForFacebook)); domain != "facebook.com" {
   152  			t.Fatal("Recover fake IP to get domain facebook.com failed.")
   153  		}
   154  		if domain := fakeEngine.GetDomainFromFakeDNS(net.IPAddress(fakeIPForGoogle)); domain != "google.com" {
   155  			t.Fatal("Recover fake IP to get domain google.com failed.")
   156  		}
   157  	}
   158  	{
   159  		ips := fakeEngine.GetFakeIPForDomain("api.google.com")
   160  		for _, ip := range ips {
   161  			if !(&net.IPNet{IP: net.IP{198, 19, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip.IP()) {
   162  				t.Fatal("Fake IP for api.google.com not in local pool 198.19.0.0/16")
   163  			}
   164  		}
   165  	}
   166  	{
   167  		ips := fakeEngine.GetFakeIPForDomain3("v2fly.org", true, false)
   168  		for _, ip := range ips {
   169  			if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip.IP()) {
   170  				t.Fatal("Fake IP for v2fly.org not in global pool 198.18.0.0/16")
   171  			}
   172  		}
   173  	}
   174  }
   175  
   176  func TestFakeDNSEmptyGlobalConfig(t *testing.T) {
   177  	config := &core.Config{
   178  		App: []*anypb.Any{
   179  			serial.ToTypedMessage(&Config{
   180  				NameServer: []*NameServer{
   181  					{ // "fakedns"
   182  						Address: &net.Endpoint{
   183  							Network: net.Network_UDP,
   184  							Address: &net.IPOrDomain{
   185  								Address: &net.IPOrDomain_Domain{
   186  									Domain: "fakedns",
   187  								},
   188  							},
   189  						},
   190  						QueryStrategy: QueryStrategy_USE_IP4.Enum(),
   191  					},
   192  					{ // "localhost"
   193  						Address: &net.Endpoint{
   194  							Network: net.Network_UDP,
   195  							Address: &net.IPOrDomain{
   196  								Address: &net.IPOrDomain_Domain{
   197  									Domain: "localhost",
   198  								},
   199  							},
   200  						},
   201  						QueryStrategy: QueryStrategy_USE_IP6.Enum(),
   202  						PrioritizedDomain: []*NameServer_PriorityDomain{
   203  							{Type: DomainMatchingType_Subdomain, Domain: "google.com"},
   204  						},
   205  						FakeDns: &fakedns.FakeDnsPoolMulti{Pools: []*fakedns.FakeDnsPool{}}, // "fakedns": true
   206  					},
   207  				},
   208  			}),
   209  			serial.ToTypedMessage(&dispatcher.Config{}),
   210  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   211  			serial.ToTypedMessage(&policy.Config{}),
   212  		},
   213  		Outbound: []*core.OutboundHandlerConfig{
   214  			{
   215  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   216  			},
   217  		},
   218  	}
   219  
   220  	v, err := core.New(config)
   221  	common.Must(err)
   222  	common.Must(v.Start())
   223  
   224  	dnsClient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
   225  	fakeClient := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSClient()
   226  
   227  	{ // Lookup facebook.com will return 198.18.0.0/15 (default IPv4 pool)
   228  		ips, err := fakeClient.LookupIP("facebook.com")
   229  		if err != nil {
   230  			t.Fatal("unexpected error: ", err)
   231  		}
   232  		for _, ip := range ips {
   233  			if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(15, 8*net.IPv4len)}).Contains(ip) {
   234  				t.Fatal("Lookup facebook.com with fake client not in default IPv4 pool 198.18.0.0/15")
   235  			}
   236  		}
   237  	}
   238  	{ // Lookup google.com will return fc00::/18 (default IPv6 pool)
   239  		ips, err := fakeClient.LookupIP("google.com")
   240  		if err != nil {
   241  			t.Fatal("unexpected error: ", err)
   242  		}
   243  		for _, ip := range ips {
   244  			if !(&net.IPNet{IP: net.IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Mask: net.CIDRMask(18, 8*net.IPv6len)}).Contains(ip) {
   245  				t.Fatal("Lookup google.com with fake client not in default IPv6 pool fc00::/18")
   246  			}
   247  		}
   248  	}
   249  }