dns_server_test.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. package nebula
  2. import (
  3. "context"
  4. "io"
  5. "net"
  6. "net/netip"
  7. "strconv"
  8. "testing"
  9. "time"
  10. "github.com/miekg/dns"
  11. "github.com/sirupsen/logrus"
  12. "github.com/slackhq/nebula/config"
  13. "github.com/stretchr/testify/assert"
  14. "github.com/stretchr/testify/require"
  15. )
  16. type stubDNSWriter struct{}
  17. func (stubDNSWriter) LocalAddr() net.Addr { return &net.UDPAddr{} }
  18. func (stubDNSWriter) RemoteAddr() net.Addr {
  19. return &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 5353}
  20. }
  21. func (stubDNSWriter) Write([]byte) (int, error) { return 0, nil }
  22. func (stubDNSWriter) WriteMsg(*dns.Msg) error { return nil }
  23. func (stubDNSWriter) Close() error { return nil }
  24. func (stubDNSWriter) TsigStatus() error { return nil }
  25. func (stubDNSWriter) TsigTimersOnly(bool) {}
  26. func (stubDNSWriter) Hijack() {}
  27. func TestParsequery(t *testing.T) {
  28. l := logrus.New()
  29. hostMap := &HostMap{}
  30. ds := &dnsServer{
  31. l: l,
  32. dnsMap4: make(map[string]netip.Addr),
  33. dnsMap6: make(map[string]netip.Addr),
  34. hostMap: hostMap,
  35. }
  36. ds.enabled.Store(true)
  37. addrs := []netip.Addr{
  38. netip.MustParseAddr("1.2.3.4"),
  39. netip.MustParseAddr("1.2.3.5"),
  40. netip.MustParseAddr("fd01::24"),
  41. netip.MustParseAddr("fd01::25"),
  42. }
  43. ds.Add("test.com.com", addrs)
  44. ds.Add("v4only.com.com", []netip.Addr{netip.MustParseAddr("1.2.3.6")})
  45. ds.Add("v6only.com.com", []netip.Addr{netip.MustParseAddr("fd01::26")})
  46. m := &dns.Msg{}
  47. m.SetQuestion("test.com.com", dns.TypeA)
  48. ds.parseQuery(m, nil)
  49. assert.NotNil(t, m.Answer)
  50. assert.Equal(t, "1.2.3.4", m.Answer[0].(*dns.A).A.String())
  51. assert.Equal(t, dns.RcodeSuccess, m.Rcode)
  52. m = &dns.Msg{}
  53. m.SetQuestion("test.com.com", dns.TypeAAAA)
  54. ds.parseQuery(m, nil)
  55. assert.NotNil(t, m.Answer)
  56. assert.Equal(t, "fd01::24", m.Answer[0].(*dns.AAAA).AAAA.String())
  57. assert.Equal(t, dns.RcodeSuccess, m.Rcode)
  58. // A known name with no record of the requested type should return NODATA
  59. // (NOERROR with empty answer), not NXDOMAIN.
  60. m = &dns.Msg{}
  61. m.SetQuestion("v4only.com.com", dns.TypeAAAA)
  62. ds.parseQuery(m, nil)
  63. assert.Empty(t, m.Answer)
  64. assert.Equal(t, dns.RcodeSuccess, m.Rcode)
  65. m = &dns.Msg{}
  66. m.SetQuestion("v6only.com.com", dns.TypeA)
  67. ds.parseQuery(m, nil)
  68. assert.Empty(t, m.Answer)
  69. assert.Equal(t, dns.RcodeSuccess, m.Rcode)
  70. // An unknown name should still return NXDOMAIN.
  71. m = &dns.Msg{}
  72. m.SetQuestion("unknown.com.com", dns.TypeA)
  73. ds.parseQuery(m, nil)
  74. assert.Empty(t, m.Answer)
  75. assert.Equal(t, dns.RcodeNameError, m.Rcode)
  76. // short lookups should not fail
  77. m = &dns.Msg{}
  78. m.Question = []dns.Question{{Name: "", Qtype: dns.TypeTXT, Qclass: dns.ClassINET}}
  79. ds.parseQuery(m, stubDNSWriter{})
  80. assert.Empty(t, m.Answer)
  81. assert.Equal(t, dns.RcodeNameError, m.Rcode)
  82. m = &dns.Msg{}
  83. m.Question = []dns.Question{{Name: ".", Qtype: dns.TypeTXT, Qclass: dns.ClassINET}}
  84. ds.parseQuery(m, stubDNSWriter{})
  85. assert.Empty(t, m.Answer)
  86. assert.Equal(t, dns.RcodeNameError, m.Rcode)
  87. }
  88. func Test_getDnsServerAddr(t *testing.T) {
  89. c := config.NewC(nil)
  90. c.Settings["lighthouse"] = map[string]any{
  91. "dns": map[string]any{
  92. "host": "0.0.0.0",
  93. "port": "1",
  94. },
  95. }
  96. assert.Equal(t, "0.0.0.0:1", getDnsServerAddr(c))
  97. c.Settings["lighthouse"] = map[string]any{
  98. "dns": map[string]any{
  99. "host": "::",
  100. "port": "1",
  101. },
  102. }
  103. assert.Equal(t, "[::]:1", getDnsServerAddr(c))
  104. c.Settings["lighthouse"] = map[string]any{
  105. "dns": map[string]any{
  106. "host": "[::]",
  107. "port": "1",
  108. },
  109. }
  110. assert.Equal(t, "[::]:1", getDnsServerAddr(c))
  111. // Make sure whitespace doesn't mess us up
  112. c.Settings["lighthouse"] = map[string]any{
  113. "dns": map[string]any{
  114. "host": "[::] ",
  115. "port": "1",
  116. },
  117. }
  118. assert.Equal(t, "[::]:1", getDnsServerAddr(c))
  119. }
  120. func newTestDnsServer(t *testing.T) (*dnsServer, *config.C) {
  121. t.Helper()
  122. l := logrus.New()
  123. l.Out = io.Discard
  124. ds := &dnsServer{
  125. l: l,
  126. ctx: context.Background(),
  127. dnsMap4: make(map[string]netip.Addr),
  128. dnsMap6: make(map[string]netip.Addr),
  129. hostMap: &HostMap{},
  130. }
  131. ds.mux = dns.NewServeMux()
  132. ds.mux.HandleFunc(".", ds.handleDnsRequest)
  133. return ds, config.NewC(l)
  134. }
  135. func setDnsConfig(c *config.C, host string, port string, amLighthouse, serveDns bool) {
  136. c.Settings["lighthouse"] = map[string]any{
  137. "am_lighthouse": amLighthouse,
  138. "serve_dns": serveDns,
  139. "dns": map[string]any{
  140. "host": host,
  141. "port": port,
  142. },
  143. }
  144. }
  145. func TestDnsServer_reload_initial_disabled(t *testing.T) {
  146. ds, c := newTestDnsServer(t)
  147. setDnsConfig(c, "127.0.0.1", "0", true, false)
  148. require.NoError(t, ds.reload(c, true))
  149. assert.False(t, ds.enabled.Load())
  150. assert.Equal(t, "127.0.0.1:0", ds.addr)
  151. assert.Nil(t, ds.server)
  152. }
  153. func TestDnsServer_reload_initial_enabled(t *testing.T) {
  154. ds, c := newTestDnsServer(t)
  155. setDnsConfig(c, "127.0.0.1", "0", true, true)
  156. require.NoError(t, ds.reload(c, true))
  157. assert.True(t, ds.enabled.Load())
  158. assert.Equal(t, "127.0.0.1:0", ds.addr)
  159. // initial never starts a runner; that's Control.Start's job
  160. assert.Nil(t, ds.server)
  161. }
  162. func TestDnsServer_reload_initial_serveDnsWithoutLighthouse(t *testing.T) {
  163. ds, c := newTestDnsServer(t)
  164. setDnsConfig(c, "127.0.0.1", "0", false, true)
  165. require.NoError(t, ds.reload(c, true))
  166. // Wants DNS but isn't a lighthouse: gated off, no runner.
  167. assert.False(t, ds.enabled.Load())
  168. }
  169. func TestDnsServer_reload_sameAddr_noOp(t *testing.T) {
  170. ds, c := newTestDnsServer(t)
  171. setDnsConfig(c, "127.0.0.1", "0", true, true)
  172. require.NoError(t, ds.reload(c, true))
  173. // No server running yet, no addr change. Reload should not spawn anything.
  174. require.NoError(t, ds.reload(c, false))
  175. assert.True(t, ds.enabled.Load())
  176. assert.Nil(t, ds.server)
  177. }
  178. func TestDnsServer_StartStop_lifecycle(t *testing.T) {
  179. // Bind to a real (random) UDP port so we exercise the actual
  180. // ListenAndServe + Shutdown plumbing including the started-chan race fix.
  181. port := freeUDPPort(t)
  182. ds, c := newTestDnsServer(t)
  183. setDnsConfig(c, "127.0.0.1", port, true, true)
  184. require.NoError(t, ds.reload(c, true))
  185. done := make(chan struct{})
  186. go func() {
  187. ds.Start()
  188. close(done)
  189. }()
  190. waitFor(t, func() bool {
  191. ds.serverMu.Lock()
  192. started := ds.started
  193. ds.serverMu.Unlock()
  194. if started == nil {
  195. return false
  196. }
  197. select {
  198. case <-started:
  199. return true
  200. default:
  201. return false
  202. }
  203. })
  204. ds.Stop()
  205. select {
  206. case <-done:
  207. case <-time.After(5 * time.Second):
  208. t.Fatal("Start did not return after Stop")
  209. }
  210. }
  211. func TestDnsServer_Stop_beforeBind_doesNotHang(t *testing.T) {
  212. // Stop called immediately after Start should not deadlock even if bind
  213. // hasn't completed yet. This exercises the started-chan close-on-bind-fail
  214. // path: by binding to an obviously bad port (privileged) we get a fast
  215. // bind error before NotifyStartedFunc fires.
  216. ds, c := newTestDnsServer(t)
  217. // Use a port that should fail to bind (negative would be invalid, use a
  218. // host that won't resolve to ensure listenUDP fails quickly).
  219. setDnsConfig(c, "256.256.256.256", "53", true, true)
  220. require.NoError(t, ds.reload(c, true))
  221. done := make(chan struct{})
  222. go func() {
  223. ds.Start()
  224. close(done)
  225. }()
  226. // Give Start a moment to attempt the bind and fail.
  227. select {
  228. case <-done:
  229. // Bind failed and Start returned; Stop should be a no-op.
  230. case <-time.After(time.Second):
  231. t.Fatal("Start did not return after a bad bind")
  232. }
  233. stopped := make(chan struct{})
  234. go func() {
  235. ds.Stop()
  236. close(stopped)
  237. }()
  238. select {
  239. case <-stopped:
  240. case <-time.After(time.Second):
  241. t.Fatal("Stop hung after a failed bind")
  242. }
  243. }
  244. func TestDnsServer_reload_disable_stopsRunningServer(t *testing.T) {
  245. port := freeUDPPort(t)
  246. ds, c := newTestDnsServer(t)
  247. setDnsConfig(c, "127.0.0.1", port, true, true)
  248. require.NoError(t, ds.reload(c, true))
  249. startReturned := make(chan struct{})
  250. go func() {
  251. ds.Start()
  252. close(startReturned)
  253. }()
  254. waitForBind(t, ds)
  255. // Toggle serve_dns off; reload should shut the running server down.
  256. setDnsConfig(c, "127.0.0.1", port, true, false)
  257. require.NoError(t, ds.reload(c, false))
  258. select {
  259. case <-startReturned:
  260. case <-time.After(5 * time.Second):
  261. t.Fatal("Start did not return after reload disabled DNS")
  262. }
  263. assert.False(t, ds.enabled.Load())
  264. }
  265. func freeUDPPort(t *testing.T) string {
  266. t.Helper()
  267. conn, err := net.ListenPacket("udp", "127.0.0.1:0")
  268. require.NoError(t, err)
  269. port := conn.LocalAddr().(*net.UDPAddr).Port
  270. require.NoError(t, conn.Close())
  271. return strconv.Itoa(port)
  272. }
  273. func waitForBind(t *testing.T, ds *dnsServer) {
  274. t.Helper()
  275. waitFor(t, func() bool {
  276. ds.serverMu.Lock()
  277. started := ds.started
  278. ds.serverMu.Unlock()
  279. if started == nil {
  280. return false
  281. }
  282. select {
  283. case <-started:
  284. return true
  285. default:
  286. return false
  287. }
  288. })
  289. }
  290. func waitFor(t *testing.T, cond func() bool) {
  291. t.Helper()
  292. deadline := time.Now().Add(5 * time.Second)
  293. for time.Now().Before(deadline) {
  294. if cond() {
  295. return
  296. }
  297. time.Sleep(5 * time.Millisecond)
  298. }
  299. t.Fatal("timed out waiting for condition")
  300. }