resolver_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. package libnetwork
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "errors"
  6. "net"
  7. "runtime"
  8. "syscall"
  9. "testing"
  10. "time"
  11. "github.com/containerd/containerd/log"
  12. "github.com/docker/docker/libnetwork/testutils"
  13. "github.com/miekg/dns"
  14. "github.com/sirupsen/logrus"
  15. "gotest.tools/v3/assert"
  16. is "gotest.tools/v3/assert/cmp"
  17. "gotest.tools/v3/skip"
  18. )
  19. // a simple/null address type that will be used to fake a local address for unit testing
  20. type tstaddr struct {
  21. network string
  22. }
  23. func (a *tstaddr) Network() string {
  24. if a.network != "" {
  25. return a.network
  26. }
  27. return "tcp"
  28. }
  29. func (a *tstaddr) String() string { return "(fake)" }
  30. // a simple writer that implements dns.ResponseWriter for unit testing purposes
  31. type tstwriter struct {
  32. network string
  33. msg *dns.Msg
  34. }
  35. func (w *tstwriter) WriteMsg(m *dns.Msg) (err error) {
  36. w.msg = m
  37. return nil
  38. }
  39. func (w *tstwriter) Write(m []byte) (int, error) { return 0, nil }
  40. func (w *tstwriter) LocalAddr() net.Addr {
  41. return &tstaddr{network: w.network}
  42. }
  43. func (w *tstwriter) RemoteAddr() net.Addr {
  44. return &tstaddr{network: w.network}
  45. }
  46. func (w *tstwriter) TsigStatus() error { return nil }
  47. func (w *tstwriter) TsigTimersOnly(b bool) {}
  48. func (w *tstwriter) Hijack() {}
  49. func (w *tstwriter) Close() error { return nil }
  50. func (w *tstwriter) GetResponse() *dns.Msg { return w.msg }
  51. func (w *tstwriter) ClearResponse() { w.msg = nil }
  52. func checkNonNullResponse(t *testing.T, m *dns.Msg) {
  53. t.Helper()
  54. if m == nil {
  55. t.Fatal("Null DNS response found. Non Null response msg expected.")
  56. }
  57. }
  58. func checkDNSAnswersCount(t *testing.T, m *dns.Msg, expected int) {
  59. t.Helper()
  60. answers := len(m.Answer)
  61. if answers != expected {
  62. t.Fatalf("Expected number of answers in response: %d. Found: %d", expected, answers)
  63. }
  64. }
  65. func checkDNSResponseCode(t *testing.T, m *dns.Msg, expected int) {
  66. t.Helper()
  67. if m.MsgHdr.Rcode != expected {
  68. t.Fatalf("Expected DNS response code: %d. Found: %d", expected, m.MsgHdr.Rcode)
  69. }
  70. }
  71. func checkDNSRRType(t *testing.T, actual, expected uint16) {
  72. t.Helper()
  73. if actual != expected {
  74. t.Fatalf("Expected DNS Rrtype: %d. Found: %d", expected, actual)
  75. }
  76. }
  77. func TestDNSIPQuery(t *testing.T) {
  78. skip.If(t, runtime.GOOS == "windows", "test only works on linux")
  79. defer testutils.SetupTestOSContext(t)()
  80. c, err := New()
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. defer c.Stop()
  85. n, err := c.NewNetwork("bridge", "dtnet1", "", nil)
  86. if err != nil {
  87. t.Fatal(err)
  88. }
  89. defer func() {
  90. if err := n.Delete(); err != nil {
  91. t.Fatal(err)
  92. }
  93. }()
  94. ep, err := n.CreateEndpoint("testep")
  95. if err != nil {
  96. t.Fatal(err)
  97. }
  98. sb, err := c.NewSandbox("c1")
  99. if err != nil {
  100. t.Fatal(err)
  101. }
  102. defer func() {
  103. if err := sb.Delete(); err != nil {
  104. t.Fatal(err)
  105. }
  106. }()
  107. // we need the endpoint only to populate ep_list for the sandbox as part of resolve_name
  108. // it is not set as a target for name resolution and does not serve any other purpose
  109. err = ep.Join(sb)
  110. if err != nil {
  111. t.Fatal(err)
  112. }
  113. // add service records which are used to resolve names. These are the real targets for the DNS querries
  114. n.addSvcRecords("ep1", "name1", "svc1", net.ParseIP("192.168.0.1"), net.IP{}, true, "test")
  115. w := new(tstwriter)
  116. // the unit tests right now will focus on non-proxyed DNS requests
  117. r := NewResolver(resolverIPSandbox, false, sb)
  118. // test name1's IP is resolved correctly with the default A type query
  119. // Also make sure DNS lookups are case insensitive
  120. names := []string{"name1", "NaMe1"}
  121. for _, name := range names {
  122. q := new(dns.Msg)
  123. q.SetQuestion(name, dns.TypeA)
  124. r.serveDNS(w, q)
  125. resp := w.GetResponse()
  126. checkNonNullResponse(t, resp)
  127. t.Log("Response: ", resp.String())
  128. checkDNSResponseCode(t, resp, dns.RcodeSuccess)
  129. checkDNSAnswersCount(t, resp, 1)
  130. checkDNSRRType(t, resp.Answer[0].Header().Rrtype, dns.TypeA)
  131. if answer, ok := resp.Answer[0].(*dns.A); ok {
  132. if !answer.A.Equal(net.ParseIP("192.168.0.1")) {
  133. t.Fatalf("IP response in Answer %v does not match 192.168.0.1", answer.A)
  134. }
  135. } else {
  136. t.Fatal("Answer of type A not found")
  137. }
  138. w.ClearResponse()
  139. }
  140. // test MX query with name1 results in Success response with 0 answer records
  141. q := new(dns.Msg)
  142. q.SetQuestion("name1", dns.TypeMX)
  143. r.serveDNS(w, q)
  144. resp := w.GetResponse()
  145. checkNonNullResponse(t, resp)
  146. t.Log("Response: ", resp.String())
  147. checkDNSResponseCode(t, resp, dns.RcodeSuccess)
  148. checkDNSAnswersCount(t, resp, 0)
  149. w.ClearResponse()
  150. // test MX query with non existent name results in ServFail response with 0 answer records
  151. // since this is a unit test env, we disable proxying DNS above which results in ServFail rather than NXDOMAIN
  152. q = new(dns.Msg)
  153. q.SetQuestion("nonexistent", dns.TypeMX)
  154. r.serveDNS(w, q)
  155. resp = w.GetResponse()
  156. checkNonNullResponse(t, resp)
  157. t.Log("Response: ", resp.String())
  158. checkDNSResponseCode(t, resp, dns.RcodeServerFailure)
  159. w.ClearResponse()
  160. }
  161. func newDNSHandlerServFailOnce(requests *int) func(w dns.ResponseWriter, r *dns.Msg) {
  162. return func(w dns.ResponseWriter, r *dns.Msg) {
  163. m := new(dns.Msg)
  164. m.SetReply(r)
  165. m.Compress = false
  166. if *requests == 0 {
  167. m.SetRcode(r, dns.RcodeServerFailure)
  168. }
  169. *requests = *requests + 1
  170. if err := w.WriteMsg(m); err != nil {
  171. log.G(context.TODO()).WithError(err).Error("Error writing dns response")
  172. }
  173. }
  174. }
  175. func waitForLocalDNSServer(t *testing.T) {
  176. retries := 0
  177. maxRetries := 10
  178. for retries < maxRetries {
  179. t.Log("Try connecting to DNS server ...")
  180. // this test and retry mechanism only works for TCP. With UDP there is no
  181. // connection and the test becomes inaccurate leading to unpredictable results
  182. tconn, err := net.DialTimeout("tcp", "127.0.0.1:53", 10*time.Second)
  183. retries = retries + 1
  184. if err != nil {
  185. if oerr, ok := err.(*net.OpError); ok {
  186. // server is probably initializing
  187. if oerr.Err == syscall.ECONNREFUSED {
  188. continue
  189. }
  190. } else {
  191. // something is wrong: we should stop for analysis
  192. t.Fatal(err)
  193. }
  194. }
  195. if tconn != nil {
  196. tconn.Close()
  197. break
  198. }
  199. }
  200. }
  201. func TestDNSProxyServFail(t *testing.T) {
  202. skip.If(t, runtime.GOOS == "windows", "test only works on linux")
  203. osctx := testutils.SetupTestOSContextEx(t)
  204. defer osctx.Cleanup(t)
  205. c, err := New()
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. defer c.Stop()
  210. n, err := c.NewNetwork("bridge", "dtnet2", "", nil)
  211. if err != nil {
  212. t.Fatal(err)
  213. }
  214. defer func() {
  215. if err := n.Delete(); err != nil {
  216. t.Fatal(err)
  217. }
  218. }()
  219. sb, err := c.NewSandbox("c1")
  220. if err != nil {
  221. t.Fatal(err)
  222. }
  223. defer func() {
  224. if err := sb.Delete(); err != nil {
  225. t.Fatal(err)
  226. }
  227. }()
  228. var nRequests int
  229. // initialize a local DNS server and configure it to fail the first query
  230. dns.HandleFunc(".", newDNSHandlerServFailOnce(&nRequests))
  231. // use TCP for predictable results. Connection tests (to figure out DNS server initialization) don't work with UDP
  232. server := &dns.Server{Addr: "127.0.0.1:53", Net: "tcp"}
  233. srvErrCh := make(chan error, 1)
  234. osctx.Go(t, func() {
  235. srvErrCh <- server.ListenAndServe()
  236. })
  237. defer func() {
  238. server.Shutdown() //nolint:errcheck
  239. if err := <-srvErrCh; err != nil {
  240. t.Error(err)
  241. }
  242. }()
  243. waitForLocalDNSServer(t)
  244. t.Log("DNS Server can be reached")
  245. w := new(tstwriter)
  246. r := NewResolver(resolverIPSandbox, true, sb)
  247. q := new(dns.Msg)
  248. q.SetQuestion("name1.", dns.TypeA)
  249. var localDNSEntries []extDNSEntry
  250. extTestDNSEntry := extDNSEntry{IPStr: "127.0.0.1", HostLoopback: true}
  251. // configure two external DNS entries and point both to local DNS server thread
  252. localDNSEntries = append(localDNSEntries, extTestDNSEntry)
  253. localDNSEntries = append(localDNSEntries, extTestDNSEntry)
  254. // this should generate two requests: the first will fail leading to a retry
  255. r.SetExtServers(localDNSEntries)
  256. r.serveDNS(w, q)
  257. if nRequests != 2 {
  258. t.Fatalf("Expected 2 DNS querries. Found: %d", nRequests)
  259. }
  260. t.Logf("Expected number of DNS requests generated")
  261. }
  262. // Packet 24 extracted from
  263. // https://gist.github.com/vojtad/3bac63b8c91b1ec50e8d8b36047317fa/raw/7d75eb3d3448381bf252ae55ea5123a132c46658/host.pcap
  264. // (https://github.com/moby/moby/issues/44575)
  265. // which is a non-compliant DNS reply > 512B (w/o EDNS(0)) to the query
  266. //
  267. // s3.amazonaws.com. IN A
  268. const oversizedDNSReplyMsg = "\xf5\x11\x81\x80\x00\x01\x00\x20\x00\x00\x00\x00\x02\x73\x33\x09" +
  269. "\x61\x6d\x61\x7a\x6f\x6e\x61\x77\x73\x03\x63\x6f\x6d\x00\x00\x01" +
  270. "\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
  271. "\x11\x9e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  272. "\x4c\x66\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  273. "\xda\x10\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
  274. "\x01\x3e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
  275. "\x88\x68\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
  276. "\x66\x9e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
  277. "\x5f\x28\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  278. "\x8e\x4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x36\xe7" +
  279. "\x84\xf0\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd8" +
  280. "\x92\x45\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  281. "\x8f\xa6\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x36\xe7" +
  282. "\xc0\xd0\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
  283. "\xfe\x28\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  284. "\xaa\x3d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  285. "\x4e\x56\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
  286. "\xea\xb0\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  287. "\x6d\xed\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
  288. "\x28\x00\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd9" +
  289. "\xe9\x78\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd9" +
  290. "\x6e\x9e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd9" +
  291. "\x45\x86\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd8" +
  292. "\x30\x38\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x36\xe7" +
  293. "\xc6\xa8\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x03\x05" +
  294. "\x01\x9d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
  295. "\xa8\xe8\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
  296. "\x64\xa6\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd8" +
  297. "\x3c\x48\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd8" +
  298. "\x35\x20\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
  299. "\x54\xf6\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
  300. "\x5d\x36\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
  301. "\x30\x36\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x36\xe7" +
  302. "\x83\x90"
  303. // Regression test for https://github.com/moby/moby/issues/44575
  304. func TestOversizedDNSReply(t *testing.T) {
  305. srv, err := net.ListenPacket("udp", "127.0.0.1:0")
  306. assert.NilError(t, err)
  307. defer srv.Close()
  308. go func() {
  309. buf := make([]byte, 65536)
  310. for {
  311. n, src, err := srv.ReadFrom(buf)
  312. if errors.Is(err, net.ErrClosed) {
  313. return
  314. }
  315. t.Logf("[<-%v]\n%s", src, hex.Dump(buf[:n]))
  316. if n < 2 {
  317. continue
  318. }
  319. resp := []byte(oversizedDNSReplyMsg)
  320. resp[0], resp[1] = buf[0], buf[1] // Copy query ID into response.
  321. _, err = srv.WriteTo(resp, src)
  322. if errors.Is(err, net.ErrClosed) {
  323. return
  324. }
  325. if err != nil {
  326. t.Log(err)
  327. }
  328. }
  329. }()
  330. srvAddr := srv.LocalAddr().(*net.UDPAddr)
  331. rsv := NewResolver("", true, noopDNSBackend{})
  332. // The resolver logs lots of valuable info at level debug. Redirect it
  333. // to t.Log() so the log spew is emitted only if the test fails.
  334. rsv.logger = testLogger(t)
  335. rsv.SetExtServers([]extDNSEntry{
  336. {IPStr: srvAddr.IP.String(), port: uint16(srvAddr.Port), HostLoopback: true},
  337. })
  338. w := &tstwriter{network: srvAddr.Network()}
  339. q := new(dns.Msg).SetQuestion("s3.amazonaws.com.", dns.TypeA)
  340. rsv.serveDNS(w, q)
  341. resp := w.GetResponse()
  342. checkNonNullResponse(t, resp)
  343. t.Log("Response: ", resp.String())
  344. checkDNSResponseCode(t, resp, dns.RcodeSuccess)
  345. assert.Assert(t, len(resp.Answer) >= 1)
  346. checkDNSRRType(t, resp.Answer[0].Header().Rrtype, dns.TypeA)
  347. }
  348. func testLogger(t *testing.T) *logrus.Logger {
  349. logger := logrus.New()
  350. logger.SetLevel(logrus.DebugLevel)
  351. logger.SetOutput(tlogWriter{t})
  352. return logger
  353. }
  354. type tlogWriter struct{ t *testing.T }
  355. func (w tlogWriter) Write(p []byte) (n int, err error) {
  356. w.t.Logf("%s", p)
  357. return len(p), nil
  358. }
  359. type noopDNSBackend struct{ DNSBackend }
  360. func (noopDNSBackend) ResolveName(name string, iplen int) ([]net.IP, bool) { return nil, false }
  361. func (noopDNSBackend) ExecFunc(f func()) error { f(); return nil }
  362. func (noopDNSBackend) NdotsSet() bool { return false }
  363. func (noopDNSBackend) HandleQueryResp(name string, ip net.IP) {}
  364. func TestReplySERVFAIL(t *testing.T) {
  365. cases := []struct {
  366. name string
  367. q *dns.Msg
  368. proxyDNS bool
  369. }{
  370. {
  371. name: "InternalError",
  372. q: new(dns.Msg).SetQuestion("_sip._tcp.example.com.", dns.TypeSRV),
  373. },
  374. {
  375. name: "ProxyDNS=false",
  376. q: new(dns.Msg).SetQuestion("example.com.", dns.TypeA),
  377. },
  378. {
  379. name: "ProxyDNS=true", // No extDNS servers configured -> no answer from any upstream
  380. q: new(dns.Msg).SetQuestion("example.com.", dns.TypeA),
  381. proxyDNS: true,
  382. },
  383. }
  384. for _, tt := range cases {
  385. t.Run(tt.name, func(t *testing.T) {
  386. rsv := NewResolver("", tt.proxyDNS, badSRVDNSBackend{})
  387. rsv.logger = testLogger(t)
  388. w := &tstwriter{}
  389. rsv.serveDNS(w, tt.q)
  390. resp := w.GetResponse()
  391. checkNonNullResponse(t, resp)
  392. t.Log("Response: ", resp.String())
  393. checkDNSResponseCode(t, resp, dns.RcodeServerFailure)
  394. })
  395. }
  396. }
  397. type badSRVDNSBackend struct{ noopDNSBackend }
  398. func (badSRVDNSBackend) ResolveService(name string) ([]*net.SRV, []net.IP) {
  399. return []*net.SRV{nil, nil, nil}, nil // Mismatched slice lengths
  400. }
  401. func TestProxyNXDOMAIN(t *testing.T) {
  402. mockSOA, err := dns.NewRR(". 86367 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2023051800 1800 900 604800 86400\n")
  403. assert.NilError(t, err)
  404. assert.Assert(t, mockSOA != nil)
  405. serveStarted := make(chan struct{})
  406. srv := &dns.Server{
  407. Net: "udp",
  408. Addr: "127.0.0.1:0",
  409. Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
  410. msg := new(dns.Msg).SetRcode(r, dns.RcodeNameError)
  411. msg.Ns = append(msg.Ns, dns.Copy(mockSOA))
  412. w.WriteMsg(msg)
  413. }),
  414. NotifyStartedFunc: func() { close(serveStarted) },
  415. }
  416. serveDone := make(chan error, 1)
  417. go func() {
  418. defer close(serveDone)
  419. serveDone <- srv.ListenAndServe()
  420. }()
  421. select {
  422. case err := <-serveDone:
  423. t.Fatal(err)
  424. case <-serveStarted:
  425. }
  426. defer func() {
  427. if err := srv.Shutdown(); err != nil {
  428. t.Error(err)
  429. }
  430. <-serveDone
  431. }()
  432. // This test, by virtue of running a server and client in different
  433. // not-locked-to-thread goroutines, happens to be a good canary for
  434. // whether we are leaking unlocked OS threads set to the wrong network
  435. // namespace. Make a best-effort attempt to detect that situation so we
  436. // are not left chasing ghosts next time.
  437. testutils.AssertSocketSameNetNS(t, srv.PacketConn.(*net.UDPConn))
  438. srvAddr := srv.PacketConn.LocalAddr().(*net.UDPAddr)
  439. rsv := NewResolver("", true, noopDNSBackend{})
  440. rsv.SetExtServers([]extDNSEntry{
  441. {IPStr: srvAddr.IP.String(), port: uint16(srvAddr.Port), HostLoopback: true},
  442. })
  443. // The resolver logs lots of valuable info at level debug. Redirect it
  444. // to t.Log() so the log spew is emitted only if the test fails.
  445. rsv.logger = testLogger(t)
  446. w := &tstwriter{network: srvAddr.Network()}
  447. q := new(dns.Msg).SetQuestion("example.net.", dns.TypeA)
  448. rsv.serveDNS(w, q)
  449. resp := w.GetResponse()
  450. checkNonNullResponse(t, resp)
  451. t.Log("Response:\n" + resp.String())
  452. checkDNSResponseCode(t, resp, dns.RcodeNameError)
  453. assert.Assert(t, is.Len(resp.Answer, 0))
  454. assert.Assert(t, is.Len(resp.Ns, 1))
  455. assert.Equal(t, resp.Ns[0].String(), mockSOA.String())
  456. }