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