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 }