resolver_test.go 7.3 KB

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