github.com/v2fly/v2ray-core/v4@v4.45.2/proxy/dns/dns_test.go (about)

     1  package dns_test
     2  
     3  import (
     4  	"strconv"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/google/go-cmp/cmp"
     9  	"github.com/miekg/dns"
    10  
    11  	core "github.com/v2fly/v2ray-core/v4"
    12  	"github.com/v2fly/v2ray-core/v4/app/dispatcher"
    13  	dnsapp "github.com/v2fly/v2ray-core/v4/app/dns"
    14  	"github.com/v2fly/v2ray-core/v4/app/policy"
    15  	"github.com/v2fly/v2ray-core/v4/app/proxyman"
    16  	_ "github.com/v2fly/v2ray-core/v4/app/proxyman/inbound"
    17  	_ "github.com/v2fly/v2ray-core/v4/app/proxyman/outbound"
    18  	"github.com/v2fly/v2ray-core/v4/common"
    19  	"github.com/v2fly/v2ray-core/v4/common/net"
    20  	"github.com/v2fly/v2ray-core/v4/common/serial"
    21  	dns_proxy "github.com/v2fly/v2ray-core/v4/proxy/dns"
    22  	"github.com/v2fly/v2ray-core/v4/proxy/dokodemo"
    23  	"github.com/v2fly/v2ray-core/v4/testing/servers/tcp"
    24  	"github.com/v2fly/v2ray-core/v4/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 == "facebook.com." && q.Qtype == dns.TypeA:
    57  			rr, _ := dns.NewRR("facebook.com. IN A 9.9.9.9")
    58  			ans.Answer = append(ans.Answer, rr)
    59  
    60  		case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeA:
    61  			rr, err := dns.NewRR("ipv6.google.com. IN A 8.8.8.7")
    62  			common.Must(err)
    63  			ans.Answer = append(ans.Answer, rr)
    64  
    65  		case q.Name == "ipv6.google.com." && q.Qtype == dns.TypeAAAA:
    66  			rr, err := dns.NewRR("ipv6.google.com. IN AAAA 2001:4860:4860::8888")
    67  			common.Must(err)
    68  			ans.Answer = append(ans.Answer, rr)
    69  
    70  		case q.Name == "notexist.google.com." && q.Qtype == dns.TypeAAAA:
    71  			ans.MsgHdr.Rcode = dns.RcodeNameError
    72  		}
    73  	}
    74  	w.WriteMsg(ans)
    75  }
    76  
    77  func TestUDPDNSTunnel(t *testing.T) {
    78  	port := udp.PickPort()
    79  
    80  	dnsServer := dns.Server{
    81  		Addr:    "127.0.0.1:" + port.String(),
    82  		Net:     "udp",
    83  		Handler: &staticHandler{},
    84  		UDPSize: 1200,
    85  	}
    86  	defer dnsServer.Shutdown()
    87  
    88  	go dnsServer.ListenAndServe()
    89  	time.Sleep(time.Second)
    90  
    91  	serverPort := udp.PickPort()
    92  	config := &core.Config{
    93  		App: []*serial.TypedMessage{
    94  			serial.ToTypedMessage(&dnsapp.Config{
    95  				NameServers: []*net.Endpoint{
    96  					{
    97  						Network: net.Network_UDP,
    98  						Address: &net.IPOrDomain{
    99  							Address: &net.IPOrDomain_Ip{
   100  								Ip: []byte{127, 0, 0, 1},
   101  							},
   102  						},
   103  						Port: uint32(port),
   104  					},
   105  				},
   106  			}),
   107  			serial.ToTypedMessage(&dispatcher.Config{}),
   108  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   109  			serial.ToTypedMessage(&proxyman.InboundConfig{}),
   110  			serial.ToTypedMessage(&policy.Config{}),
   111  		},
   112  		Inbound: []*core.InboundHandlerConfig{
   113  			{
   114  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
   115  					Address:  net.NewIPOrDomain(net.LocalHostIP),
   116  					Port:     uint32(port),
   117  					Networks: []net.Network{net.Network_UDP},
   118  				}),
   119  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   120  					PortRange: net.SinglePortRange(serverPort),
   121  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   122  				}),
   123  			},
   124  		},
   125  		Outbound: []*core.OutboundHandlerConfig{
   126  			{
   127  				ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{}),
   128  			},
   129  		},
   130  	}
   131  
   132  	v, err := core.New(config)
   133  	common.Must(err)
   134  	common.Must(v.Start())
   135  	defer v.Close()
   136  
   137  	{
   138  		m1 := new(dns.Msg)
   139  		m1.Id = dns.Id()
   140  		m1.RecursionDesired = true
   141  		m1.Question = make([]dns.Question, 1)
   142  		m1.Question[0] = dns.Question{Name: "google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET}
   143  
   144  		c := new(dns.Client)
   145  		in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
   146  		common.Must(err)
   147  
   148  		if len(in.Answer) != 1 {
   149  			t.Fatal("len(answer): ", len(in.Answer))
   150  		}
   151  
   152  		rr, ok := in.Answer[0].(*dns.A)
   153  		if !ok {
   154  			t.Fatal("not A record")
   155  		}
   156  		if r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != "" {
   157  			t.Error(r)
   158  		}
   159  	}
   160  
   161  	{
   162  		m1 := new(dns.Msg)
   163  		m1.Id = dns.Id()
   164  		m1.RecursionDesired = true
   165  		m1.Question = make([]dns.Question, 1)
   166  		m1.Question[0] = dns.Question{Name: "ipv4only.google.com.", Qtype: dns.TypeAAAA, Qclass: dns.ClassINET}
   167  
   168  		c := new(dns.Client)
   169  		c.Timeout = 10 * time.Second
   170  		in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
   171  		common.Must(err)
   172  
   173  		if len(in.Answer) != 0 {
   174  			t.Fatal("len(answer): ", len(in.Answer))
   175  		}
   176  	}
   177  
   178  	{
   179  		m1 := new(dns.Msg)
   180  		m1.Id = dns.Id()
   181  		m1.RecursionDesired = true
   182  		m1.Question = make([]dns.Question, 1)
   183  		m1.Question[0] = dns.Question{Name: "notexist.google.com.", Qtype: dns.TypeAAAA, Qclass: dns.ClassINET}
   184  
   185  		c := new(dns.Client)
   186  		in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
   187  		common.Must(err)
   188  
   189  		if in.Rcode != dns.RcodeNameError {
   190  			t.Error("expected NameError, but got ", in.Rcode)
   191  		}
   192  	}
   193  }
   194  
   195  func TestTCPDNSTunnel(t *testing.T) {
   196  	port := udp.PickPort()
   197  
   198  	dnsServer := dns.Server{
   199  		Addr:    "127.0.0.1:" + port.String(),
   200  		Net:     "udp",
   201  		Handler: &staticHandler{},
   202  	}
   203  	defer dnsServer.Shutdown()
   204  
   205  	go dnsServer.ListenAndServe()
   206  	time.Sleep(time.Second)
   207  
   208  	serverPort := tcp.PickPort()
   209  	config := &core.Config{
   210  		App: []*serial.TypedMessage{
   211  			serial.ToTypedMessage(&dnsapp.Config{
   212  				NameServer: []*dnsapp.NameServer{
   213  					{
   214  						Address: &net.Endpoint{
   215  							Network: net.Network_UDP,
   216  							Address: &net.IPOrDomain{
   217  								Address: &net.IPOrDomain_Ip{
   218  									Ip: []byte{127, 0, 0, 1},
   219  								},
   220  							},
   221  							Port: uint32(port),
   222  						},
   223  					},
   224  				},
   225  			}),
   226  			serial.ToTypedMessage(&dispatcher.Config{}),
   227  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   228  			serial.ToTypedMessage(&proxyman.InboundConfig{}),
   229  			serial.ToTypedMessage(&policy.Config{}),
   230  		},
   231  		Inbound: []*core.InboundHandlerConfig{
   232  			{
   233  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
   234  					Address:  net.NewIPOrDomain(net.LocalHostIP),
   235  					Port:     uint32(port),
   236  					Networks: []net.Network{net.Network_TCP},
   237  				}),
   238  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   239  					PortRange: net.SinglePortRange(serverPort),
   240  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   241  				}),
   242  			},
   243  		},
   244  		Outbound: []*core.OutboundHandlerConfig{
   245  			{
   246  				ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{}),
   247  			},
   248  		},
   249  	}
   250  
   251  	v, err := core.New(config)
   252  	common.Must(err)
   253  	common.Must(v.Start())
   254  	defer v.Close()
   255  
   256  	m1 := new(dns.Msg)
   257  	m1.Id = dns.Id()
   258  	m1.RecursionDesired = true
   259  	m1.Question = make([]dns.Question, 1)
   260  	m1.Question[0] = dns.Question{Name: "google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET}
   261  
   262  	c := &dns.Client{
   263  		Net: "tcp",
   264  	}
   265  	in, _, err := c.Exchange(m1, "127.0.0.1:"+serverPort.String())
   266  	common.Must(err)
   267  
   268  	if len(in.Answer) != 1 {
   269  		t.Fatal("len(answer): ", len(in.Answer))
   270  	}
   271  
   272  	rr, ok := in.Answer[0].(*dns.A)
   273  	if !ok {
   274  		t.Fatal("not A record")
   275  	}
   276  	if r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != "" {
   277  		t.Error(r)
   278  	}
   279  }
   280  
   281  func TestUDP2TCPDNSTunnel(t *testing.T) {
   282  	port := tcp.PickPort()
   283  
   284  	dnsServer := dns.Server{
   285  		Addr:    "127.0.0.1:" + port.String(),
   286  		Net:     "tcp",
   287  		Handler: &staticHandler{},
   288  	}
   289  	defer dnsServer.Shutdown()
   290  
   291  	go dnsServer.ListenAndServe()
   292  	time.Sleep(time.Second)
   293  
   294  	serverPort := tcp.PickPort()
   295  	config := &core.Config{
   296  		App: []*serial.TypedMessage{
   297  			serial.ToTypedMessage(&dnsapp.Config{
   298  				NameServer: []*dnsapp.NameServer{
   299  					{
   300  						Address: &net.Endpoint{
   301  							Network: net.Network_UDP,
   302  							Address: &net.IPOrDomain{
   303  								Address: &net.IPOrDomain_Ip{
   304  									Ip: []byte{127, 0, 0, 1},
   305  								},
   306  							},
   307  							Port: uint32(port),
   308  						},
   309  					},
   310  				},
   311  			}),
   312  			serial.ToTypedMessage(&dispatcher.Config{}),
   313  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   314  			serial.ToTypedMessage(&proxyman.InboundConfig{}),
   315  			serial.ToTypedMessage(&policy.Config{}),
   316  		},
   317  		Inbound: []*core.InboundHandlerConfig{
   318  			{
   319  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
   320  					Address:  net.NewIPOrDomain(net.LocalHostIP),
   321  					Port:     uint32(port),
   322  					Networks: []net.Network{net.Network_TCP},
   323  				}),
   324  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   325  					PortRange: net.SinglePortRange(serverPort),
   326  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   327  				}),
   328  			},
   329  		},
   330  		Outbound: []*core.OutboundHandlerConfig{
   331  			{
   332  				ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{
   333  					Server: &net.Endpoint{
   334  						Network: net.Network_TCP,
   335  					},
   336  				}),
   337  			},
   338  		},
   339  	}
   340  
   341  	v, err := core.New(config)
   342  	common.Must(err)
   343  	common.Must(v.Start())
   344  	defer v.Close()
   345  
   346  	m1 := new(dns.Msg)
   347  	m1.Id = dns.Id()
   348  	m1.RecursionDesired = true
   349  	m1.Question = make([]dns.Question, 1)
   350  	m1.Question[0] = dns.Question{Name: "google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET}
   351  
   352  	c := &dns.Client{
   353  		Net: "tcp",
   354  	}
   355  	in, _, err := c.Exchange(m1, "127.0.0.1:"+serverPort.String())
   356  	common.Must(err)
   357  
   358  	if len(in.Answer) != 1 {
   359  		t.Fatal("len(answer): ", len(in.Answer))
   360  	}
   361  
   362  	rr, ok := in.Answer[0].(*dns.A)
   363  	if !ok {
   364  		t.Fatal("not A record")
   365  	}
   366  	if r := cmp.Diff(rr.A[:], net.IP{8, 8, 8, 8}); r != "" {
   367  		t.Error(r)
   368  	}
   369  }