resolver_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. package libnetwork
  2. import (
  3. "net"
  4. "runtime"
  5. "syscall"
  6. "testing"
  7. "time"
  8. "github.com/docker/docker/libnetwork/testutils"
  9. "github.com/miekg/dns"
  10. "github.com/sirupsen/logrus"
  11. "gotest.tools/v3/skip"
  12. )
  13. // a simple/null address type that will be used to fake a local address for unit testing
  14. type tstaddr struct {
  15. }
  16. func (a *tstaddr) Network() string { return "tcp" }
  17. func (a *tstaddr) String() string { return "127.0.0.1" }
  18. // a simple writer that implements dns.ResponseWriter for unit testing purposes
  19. type tstwriter struct {
  20. msg *dns.Msg
  21. }
  22. func (w *tstwriter) WriteMsg(m *dns.Msg) (err error) {
  23. w.msg = m
  24. return nil
  25. }
  26. func (w *tstwriter) Write(m []byte) (int, error) { return 0, nil }
  27. func (w *tstwriter) LocalAddr() net.Addr { return new(tstaddr) }
  28. func (w *tstwriter) RemoteAddr() net.Addr { return new(tstaddr) }
  29. func (w *tstwriter) TsigStatus() error { return nil }
  30. func (w *tstwriter) TsigTimersOnly(b bool) {}
  31. func (w *tstwriter) Hijack() {}
  32. func (w *tstwriter) Close() error { return nil }
  33. func (w *tstwriter) GetResponse() *dns.Msg { return w.msg }
  34. func (w *tstwriter) ClearResponse() { w.msg = nil }
  35. func checkNonNullResponse(t *testing.T, m *dns.Msg) {
  36. if m == nil {
  37. t.Fatal("Null DNS response found. Non Null response msg expected.")
  38. }
  39. }
  40. func checkDNSAnswersCount(t *testing.T, m *dns.Msg, expected int) {
  41. answers := len(m.Answer)
  42. if answers != expected {
  43. t.Fatalf("Expected number of answers in response: %d. Found: %d", expected, answers)
  44. }
  45. }
  46. func checkDNSResponseCode(t *testing.T, m *dns.Msg, expected int) {
  47. if m.MsgHdr.Rcode != expected {
  48. t.Fatalf("Expected DNS response code: %d. Found: %d", expected, m.MsgHdr.Rcode)
  49. }
  50. }
  51. func checkDNSRRType(t *testing.T, actual, expected uint16) {
  52. if actual != expected {
  53. t.Fatalf("Expected DNS Rrtype: %d. Found: %d", expected, actual)
  54. }
  55. }
  56. func TestDNSIPQuery(t *testing.T) {
  57. skip.If(t, runtime.GOOS == "windows", "test only works on linux")
  58. defer testutils.SetupTestOSContext(t)()
  59. c, err := New()
  60. if err != nil {
  61. t.Fatal(err)
  62. }
  63. defer c.Stop()
  64. n, err := c.NewNetwork("bridge", "dtnet1", "", nil)
  65. if err != nil {
  66. t.Fatal(err)
  67. }
  68. defer func() {
  69. if err := n.Delete(); err != nil {
  70. t.Fatal(err)
  71. }
  72. }()
  73. ep, err := n.CreateEndpoint("testep")
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. sb, err := c.NewSandbox("c1")
  78. if err != nil {
  79. t.Fatal(err)
  80. }
  81. defer func() {
  82. if err := sb.Delete(); err != nil {
  83. t.Fatal(err)
  84. }
  85. }()
  86. // we need the endpoint only to populate ep_list for the sandbox as part of resolve_name
  87. // it is not set as a target for name resolution and does not serve any other purpose
  88. err = ep.Join(sb)
  89. if err != nil {
  90. t.Fatal(err)
  91. }
  92. // add service records which are used to resolve names. These are the real targets for the DNS querries
  93. n.(*network).addSvcRecords("ep1", "name1", "svc1", net.ParseIP("192.168.0.1"), net.IP{}, true, "test")
  94. w := new(tstwriter)
  95. // the unit tests right now will focus on non-proxyed DNS requests
  96. r := NewResolver(resolverIPSandbox, false, sb.Key(), sb.(*sandbox))
  97. // test name1's IP is resolved correctly with the default A type query
  98. // Also make sure DNS lookups are case insensitive
  99. names := []string{"name1", "NaMe1"}
  100. for _, name := range names {
  101. q := new(dns.Msg)
  102. q.SetQuestion(name, dns.TypeA)
  103. r.(*resolver).ServeDNS(w, q)
  104. resp := w.GetResponse()
  105. checkNonNullResponse(t, resp)
  106. t.Log("Response: ", resp.String())
  107. checkDNSResponseCode(t, resp, dns.RcodeSuccess)
  108. checkDNSAnswersCount(t, resp, 1)
  109. checkDNSRRType(t, resp.Answer[0].Header().Rrtype, dns.TypeA)
  110. if answer, ok := resp.Answer[0].(*dns.A); ok {
  111. if !answer.A.Equal(net.ParseIP("192.168.0.1")) {
  112. t.Fatalf("IP response in Answer %v does not match 192.168.0.1", answer.A)
  113. }
  114. } else {
  115. t.Fatal("Answer of type A not found")
  116. }
  117. w.ClearResponse()
  118. }
  119. // test MX query with name1 results in Success response with 0 answer records
  120. q := new(dns.Msg)
  121. q.SetQuestion("name1", dns.TypeMX)
  122. r.(*resolver).ServeDNS(w, q)
  123. resp := w.GetResponse()
  124. checkNonNullResponse(t, resp)
  125. t.Log("Response: ", resp.String())
  126. checkDNSResponseCode(t, resp, dns.RcodeSuccess)
  127. checkDNSAnswersCount(t, resp, 0)
  128. w.ClearResponse()
  129. // test MX query with non existent name results in ServFail response with 0 answer records
  130. // since this is a unit test env, we disable proxying DNS above which results in ServFail rather than NXDOMAIN
  131. q = new(dns.Msg)
  132. q.SetQuestion("nonexistent", dns.TypeMX)
  133. r.(*resolver).ServeDNS(w, q)
  134. resp = w.GetResponse()
  135. checkNonNullResponse(t, resp)
  136. t.Log("Response: ", resp.String())
  137. checkDNSResponseCode(t, resp, dns.RcodeServerFailure)
  138. w.ClearResponse()
  139. }
  140. func newDNSHandlerServFailOnce(requests *int) func(w dns.ResponseWriter, r *dns.Msg) {
  141. return func(w dns.ResponseWriter, r *dns.Msg) {
  142. m := new(dns.Msg)
  143. m.SetReply(r)
  144. m.Compress = false
  145. if *requests == 0 {
  146. m.SetRcode(r, dns.RcodeServerFailure)
  147. }
  148. *requests = *requests + 1
  149. if err := w.WriteMsg(m); err != nil {
  150. logrus.WithError(err).Error("Error writing dns response")
  151. }
  152. }
  153. }
  154. func waitForLocalDNSServer(t *testing.T) {
  155. retries := 0
  156. maxRetries := 10
  157. for retries < maxRetries {
  158. t.Log("Try connecting to DNS server ...")
  159. // this test and retry mechanism only works for TCP. With UDP there is no
  160. // connection and the test becomes inaccurate leading to unpredictable results
  161. tconn, err := net.DialTimeout("tcp", "127.0.0.1:53", 10*time.Second)
  162. retries = retries + 1
  163. if err != nil {
  164. if oerr, ok := err.(*net.OpError); ok {
  165. // server is probably initializing
  166. if oerr.Err == syscall.ECONNREFUSED {
  167. continue
  168. }
  169. } else {
  170. // something is wrong: we should stop for analysis
  171. t.Fatal(err)
  172. }
  173. }
  174. if tconn != nil {
  175. tconn.Close()
  176. break
  177. }
  178. }
  179. }
  180. func TestDNSProxyServFail(t *testing.T) {
  181. skip.If(t, runtime.GOOS == "windows", "test only works on linux")
  182. osctx := testutils.SetupTestOSContextEx(t)
  183. defer osctx.Cleanup(t)
  184. c, err := New()
  185. if err != nil {
  186. t.Fatal(err)
  187. }
  188. defer c.Stop()
  189. n, err := c.NewNetwork("bridge", "dtnet2", "", nil)
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. defer func() {
  194. if err := n.Delete(); err != nil {
  195. t.Fatal(err)
  196. }
  197. }()
  198. sb, err := c.NewSandbox("c1")
  199. if err != nil {
  200. t.Fatal(err)
  201. }
  202. defer func() {
  203. if err := sb.Delete(); err != nil {
  204. t.Fatal(err)
  205. }
  206. }()
  207. var nRequests int
  208. // initialize a local DNS server and configure it to fail the first query
  209. dns.HandleFunc(".", newDNSHandlerServFailOnce(&nRequests))
  210. // use TCP for predictable results. Connection tests (to figure out DNS server initialization) don't work with UDP
  211. server := &dns.Server{Addr: "127.0.0.1:53", Net: "tcp"}
  212. srvErrCh := make(chan error, 1)
  213. osctx.Go(t, func() {
  214. srvErrCh <- server.ListenAndServe()
  215. })
  216. defer func() {
  217. server.Shutdown() //nolint:errcheck
  218. if err := <-srvErrCh; err != nil {
  219. t.Error(err)
  220. }
  221. }()
  222. waitForLocalDNSServer(t)
  223. t.Log("DNS Server can be reached")
  224. w := new(tstwriter)
  225. r := NewResolver(resolverIPSandbox, true, sb.Key(), sb.(*sandbox))
  226. q := new(dns.Msg)
  227. q.SetQuestion("name1.", dns.TypeA)
  228. var localDNSEntries []extDNSEntry
  229. extTestDNSEntry := extDNSEntry{IPStr: "127.0.0.1", HostLoopback: true}
  230. // configure two external DNS entries and point both to local DNS server thread
  231. localDNSEntries = append(localDNSEntries, extTestDNSEntry)
  232. localDNSEntries = append(localDNSEntries, extTestDNSEntry)
  233. // this should generate two requests: the first will fail leading to a retry
  234. r.(*resolver).SetExtServers(localDNSEntries)
  235. r.(*resolver).ServeDNS(w, q)
  236. if nRequests != 2 {
  237. t.Fatalf("Expected 2 DNS querries. Found: %d", nRequests)
  238. }
  239. t.Logf("Expected number of DNS requests generated")
  240. }