github.com/eagleql/xray-core@v1.4.4/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/eagleql/xray-core/app/dispatcher" 12 dnsapp "github.com/eagleql/xray-core/app/dns" 13 "github.com/eagleql/xray-core/app/policy" 14 "github.com/eagleql/xray-core/app/proxyman" 15 _ "github.com/eagleql/xray-core/app/proxyman/inbound" 16 _ "github.com/eagleql/xray-core/app/proxyman/outbound" 17 "github.com/eagleql/xray-core/common" 18 "github.com/eagleql/xray-core/common/net" 19 "github.com/eagleql/xray-core/common/serial" 20 "github.com/eagleql/xray-core/core" 21 dns_proxy "github.com/eagleql/xray-core/proxy/dns" 22 "github.com/eagleql/xray-core/proxy/dokodemo" 23 "github.com/eagleql/xray-core/testing/servers/tcp" 24 "github.com/eagleql/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 }