resolver.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. package libnetwork
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "net"
  6. "strings"
  7. "sync"
  8. "time"
  9. "github.com/docker/docker/libnetwork/types"
  10. "github.com/miekg/dns"
  11. "github.com/sirupsen/logrus"
  12. )
  13. // Resolver represents the embedded DNS server in Docker. It operates
  14. // by listening on container's loopback interface for DNS queries.
  15. type Resolver interface {
  16. // Start starts the name server for the container
  17. Start() error
  18. // Stop stops the name server for the container. Stopped resolver
  19. // can be reused after running the SetupFunc again.
  20. Stop()
  21. // SetupFunc provides the setup function that should be run
  22. // in the container's network namespace.
  23. SetupFunc(int) func()
  24. // NameServer returns the IP of the DNS resolver for the
  25. // containers.
  26. NameServer() string
  27. // SetExtServers configures the external nameservers the resolver
  28. // should use to forward queries
  29. SetExtServers([]extDNSEntry)
  30. // ResolverOptions returns resolv.conf options that should be set
  31. ResolverOptions() []string
  32. }
  33. // DNSBackend represents a backend DNS resolver used for DNS name
  34. // resolution. All the queries to the resolver are forwarded to the
  35. // backend resolver.
  36. type DNSBackend interface {
  37. // ResolveName resolves a service name to an IPv4 or IPv6 address by searching
  38. // the networks the sandbox is connected to. For IPv6 queries, second return
  39. // value will be true if the name exists in docker domain but doesn't have an
  40. // IPv6 address. Such queries shouldn't be forwarded to external nameservers.
  41. ResolveName(name string, iplen int) ([]net.IP, bool)
  42. // ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
  43. // notation; the format used for DNS PTR records
  44. ResolveIP(name string) string
  45. // ResolveService returns all the backend details about the containers or hosts
  46. // backing a service. Its purpose is to satisfy an SRV query
  47. ResolveService(name string) ([]*net.SRV, []net.IP)
  48. // ExecFunc allows a function to be executed in the context of the backend
  49. // on behalf of the resolver.
  50. ExecFunc(f func()) error
  51. // NdotsSet queries the backends ndots dns option settings
  52. NdotsSet() bool
  53. // HandleQueryResp passes the name & IP from a response to the backend. backend
  54. // can use it to maintain any required state about the resolution
  55. HandleQueryResp(name string, ip net.IP)
  56. }
  57. const (
  58. dnsPort = "53"
  59. ptrIPv4domain = ".in-addr.arpa."
  60. ptrIPv6domain = ".ip6.arpa."
  61. respTTL = 600
  62. maxExtDNS = 3 //max number of external servers to try
  63. extIOTimeout = 4 * time.Second
  64. defaultRespSize = 512
  65. maxConcurrent = 1024
  66. logInterval = 2 * time.Second
  67. )
  68. type extDNSEntry struct {
  69. IPStr string
  70. HostLoopback bool
  71. }
  72. // resolver implements the Resolver interface
  73. type resolver struct {
  74. backend DNSBackend
  75. extDNSList [maxExtDNS]extDNSEntry
  76. server *dns.Server
  77. conn *net.UDPConn
  78. tcpServer *dns.Server
  79. tcpListen *net.TCPListener
  80. err error
  81. count int32
  82. tStamp time.Time
  83. queryLock sync.Mutex
  84. listenAddress string
  85. proxyDNS bool
  86. resolverKey string
  87. startCh chan struct{}
  88. }
  89. func init() {
  90. rand.Seed(time.Now().Unix())
  91. }
  92. // NewResolver creates a new instance of the Resolver
  93. func NewResolver(address string, proxyDNS bool, resolverKey string, backend DNSBackend) Resolver {
  94. return &resolver{
  95. backend: backend,
  96. proxyDNS: proxyDNS,
  97. listenAddress: address,
  98. resolverKey: resolverKey,
  99. err: fmt.Errorf("setup not done yet"),
  100. startCh: make(chan struct{}, 1),
  101. }
  102. }
  103. func (r *resolver) SetupFunc(port int) func() {
  104. return func() {
  105. var err error
  106. // DNS operates primarily on UDP
  107. addr := &net.UDPAddr{
  108. IP: net.ParseIP(r.listenAddress),
  109. Port: port,
  110. }
  111. r.conn, err = net.ListenUDP("udp", addr)
  112. if err != nil {
  113. r.err = fmt.Errorf("error in opening name server socket %v", err)
  114. return
  115. }
  116. // Listen on a TCP as well
  117. tcpaddr := &net.TCPAddr{
  118. IP: net.ParseIP(r.listenAddress),
  119. Port: port,
  120. }
  121. r.tcpListen, err = net.ListenTCP("tcp", tcpaddr)
  122. if err != nil {
  123. r.err = fmt.Errorf("error in opening name TCP server socket %v", err)
  124. return
  125. }
  126. r.err = nil
  127. }
  128. }
  129. func (r *resolver) Start() error {
  130. r.startCh <- struct{}{}
  131. defer func() { <-r.startCh }()
  132. // make sure the resolver has been setup before starting
  133. if r.err != nil {
  134. return r.err
  135. }
  136. if err := r.setupIPTable(); err != nil {
  137. return fmt.Errorf("setting up IP table rules failed: %v", err)
  138. }
  139. s := &dns.Server{Handler: r, PacketConn: r.conn}
  140. r.server = s
  141. go func() {
  142. if err := s.ActivateAndServe(); err != nil {
  143. logrus.WithError(err).Error("[resolver] failed to start PacketConn DNS server")
  144. }
  145. }()
  146. tcpServer := &dns.Server{Handler: r, Listener: r.tcpListen}
  147. r.tcpServer = tcpServer
  148. go func() {
  149. if err := tcpServer.ActivateAndServe(); err != nil {
  150. logrus.WithError(err).Error("[resolver] failed to start TCP DNS server")
  151. }
  152. }()
  153. return nil
  154. }
  155. func (r *resolver) Stop() {
  156. r.startCh <- struct{}{}
  157. defer func() { <-r.startCh }()
  158. if r.server != nil {
  159. r.server.Shutdown() // nolint:errcheck
  160. }
  161. if r.tcpServer != nil {
  162. r.tcpServer.Shutdown() // nolint:errcheck
  163. }
  164. r.conn = nil
  165. r.tcpServer = nil
  166. r.err = fmt.Errorf("setup not done yet")
  167. r.tStamp = time.Time{}
  168. r.count = 0
  169. r.queryLock = sync.Mutex{}
  170. }
  171. func (r *resolver) SetExtServers(extDNS []extDNSEntry) {
  172. l := len(extDNS)
  173. if l > maxExtDNS {
  174. l = maxExtDNS
  175. }
  176. for i := 0; i < l; i++ {
  177. r.extDNSList[i] = extDNS[i]
  178. }
  179. }
  180. func (r *resolver) NameServer() string {
  181. return r.listenAddress
  182. }
  183. func (r *resolver) ResolverOptions() []string {
  184. return []string{"ndots:0"}
  185. }
  186. func setCommonFlags(msg *dns.Msg) {
  187. msg.RecursionAvailable = true
  188. }
  189. func shuffleAddr(addr []net.IP) []net.IP {
  190. for i := len(addr) - 1; i > 0; i-- {
  191. r := rand.Intn(i + 1) // nolint:gosec // gosec complains about the use of rand here. It should be fine.
  192. addr[i], addr[r] = addr[r], addr[i]
  193. }
  194. return addr
  195. }
  196. func createRespMsg(query *dns.Msg) *dns.Msg {
  197. resp := new(dns.Msg)
  198. resp.SetReply(query)
  199. setCommonFlags(resp)
  200. return resp
  201. }
  202. func (r *resolver) handleMXQuery(query *dns.Msg) (*dns.Msg, error) {
  203. name := query.Question[0].Name
  204. addrv4, _ := r.backend.ResolveName(name, types.IPv4)
  205. addrv6, _ := r.backend.ResolveName(name, types.IPv6)
  206. if addrv4 == nil && addrv6 == nil {
  207. return nil, nil
  208. }
  209. // We were able to resolve the name. Respond with an empty list with
  210. // RcodeSuccess/NOERROR so that email clients can treat it as "implicit MX"
  211. // [RFC 5321 Section-5.1] and issue a Type A/AAAA query for the name.
  212. resp := createRespMsg(query)
  213. return resp, nil
  214. }
  215. func (r *resolver) handleIPQuery(query *dns.Msg, ipType int) (*dns.Msg, error) {
  216. var (
  217. addr []net.IP
  218. ipv6Miss bool
  219. name = query.Question[0].Name
  220. )
  221. addr, ipv6Miss = r.backend.ResolveName(name, ipType)
  222. if addr == nil && ipv6Miss {
  223. // Send a reply without any Answer sections
  224. logrus.Debugf("[resolver] lookup name %s present without IPv6 address", name)
  225. resp := createRespMsg(query)
  226. return resp, nil
  227. }
  228. if addr == nil {
  229. return nil, nil
  230. }
  231. logrus.Debugf("[resolver] lookup for %s: IP %v", name, addr)
  232. resp := createRespMsg(query)
  233. if len(addr) > 1 {
  234. addr = shuffleAddr(addr)
  235. }
  236. if ipType == types.IPv4 {
  237. for _, ip := range addr {
  238. rr := new(dns.A)
  239. rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
  240. rr.A = ip
  241. resp.Answer = append(resp.Answer, rr)
  242. }
  243. } else {
  244. for _, ip := range addr {
  245. rr := new(dns.AAAA)
  246. rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL}
  247. rr.AAAA = ip
  248. resp.Answer = append(resp.Answer, rr)
  249. }
  250. }
  251. return resp, nil
  252. }
  253. func (r *resolver) handlePTRQuery(query *dns.Msg) (*dns.Msg, error) {
  254. var (
  255. parts []string
  256. ptr = query.Question[0].Name
  257. )
  258. if strings.HasSuffix(ptr, ptrIPv4domain) {
  259. parts = strings.Split(ptr, ptrIPv4domain)
  260. } else if strings.HasSuffix(ptr, ptrIPv6domain) {
  261. parts = strings.Split(ptr, ptrIPv6domain)
  262. } else {
  263. return nil, fmt.Errorf("invalid PTR query, %v", ptr)
  264. }
  265. host := r.backend.ResolveIP(parts[0])
  266. if len(host) == 0 {
  267. return nil, nil
  268. }
  269. logrus.Debugf("[resolver] lookup for IP %s: name %s", parts[0], host)
  270. fqdn := dns.Fqdn(host)
  271. resp := new(dns.Msg)
  272. resp.SetReply(query)
  273. setCommonFlags(resp)
  274. rr := new(dns.PTR)
  275. rr.Hdr = dns.RR_Header{Name: ptr, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL}
  276. rr.Ptr = fqdn
  277. resp.Answer = append(resp.Answer, rr)
  278. return resp, nil
  279. }
  280. func (r *resolver) handleSRVQuery(query *dns.Msg) (*dns.Msg, error) {
  281. svc := query.Question[0].Name
  282. srv, ip := r.backend.ResolveService(svc)
  283. if len(srv) == 0 {
  284. return nil, nil
  285. }
  286. if len(srv) != len(ip) {
  287. return nil, fmt.Errorf("invalid reply for SRV query %s", svc)
  288. }
  289. resp := createRespMsg(query)
  290. for i, r := range srv {
  291. rr := new(dns.SRV)
  292. rr.Hdr = dns.RR_Header{Name: svc, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL}
  293. rr.Port = r.Port
  294. rr.Target = r.Target
  295. resp.Answer = append(resp.Answer, rr)
  296. rr1 := new(dns.A)
  297. rr1.Hdr = dns.RR_Header{Name: r.Target, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
  298. rr1.A = ip[i]
  299. resp.Extra = append(resp.Extra, rr1)
  300. }
  301. return resp, nil
  302. }
  303. func truncateResp(resp *dns.Msg, maxSize int, isTCP bool) {
  304. if !isTCP {
  305. resp.Truncated = true
  306. }
  307. srv := resp.Question[0].Qtype == dns.TypeSRV
  308. // trim the Answer RRs one by one till the whole message fits
  309. // within the reply size
  310. for resp.Len() > maxSize {
  311. resp.Answer = resp.Answer[:len(resp.Answer)-1]
  312. if srv && len(resp.Extra) > 0 {
  313. resp.Extra = resp.Extra[:len(resp.Extra)-1]
  314. }
  315. }
  316. }
  317. func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
  318. var (
  319. extConn net.Conn
  320. resp *dns.Msg
  321. err error
  322. )
  323. if query == nil || len(query.Question) == 0 {
  324. return
  325. }
  326. queryName := query.Question[0].Name
  327. queryType := query.Question[0].Qtype
  328. switch queryType {
  329. case dns.TypeA:
  330. resp, err = r.handleIPQuery(query, types.IPv4)
  331. case dns.TypeAAAA:
  332. resp, err = r.handleIPQuery(query, types.IPv6)
  333. case dns.TypeMX:
  334. resp, err = r.handleMXQuery(query)
  335. case dns.TypePTR:
  336. resp, err = r.handlePTRQuery(query)
  337. case dns.TypeSRV:
  338. resp, err = r.handleSRVQuery(query)
  339. default:
  340. logrus.Debugf("[resolver] query type %s is not supported by the embedded DNS and will be forwarded to external DNS", dns.TypeToString[queryType])
  341. }
  342. if err != nil {
  343. logrus.WithError(err).Errorf("[resolver] failed to handle query: %s (%s) from %s", queryName, dns.TypeToString[queryType], extConn.LocalAddr().String())
  344. return
  345. }
  346. if resp == nil {
  347. // If the backend doesn't support proxying dns request
  348. // fail the response
  349. if !r.proxyDNS {
  350. resp = new(dns.Msg)
  351. resp.SetRcode(query, dns.RcodeServerFailure)
  352. if err := w.WriteMsg(resp); err != nil {
  353. logrus.WithError(err).Error("[resolver] error writing dns response")
  354. }
  355. return
  356. }
  357. // If the user sets ndots > 0 explicitly and the query is
  358. // in the root domain don't forward it out. We will return
  359. // failure and let the client retry with the search domain
  360. // attached
  361. switch queryType {
  362. case dns.TypeA, dns.TypeAAAA:
  363. if r.backend.NdotsSet() && !strings.Contains(strings.TrimSuffix(queryName, "."), ".") {
  364. resp = createRespMsg(query)
  365. }
  366. }
  367. }
  368. proto := w.LocalAddr().Network()
  369. maxSize := 0
  370. if proto == "tcp" {
  371. maxSize = dns.MaxMsgSize - 1
  372. } else if proto == "udp" {
  373. optRR := query.IsEdns0()
  374. if optRR != nil {
  375. maxSize = int(optRR.UDPSize())
  376. }
  377. if maxSize < defaultRespSize {
  378. maxSize = defaultRespSize
  379. }
  380. }
  381. if resp != nil {
  382. if resp.Len() > maxSize {
  383. truncateResp(resp, maxSize, proto == "tcp")
  384. }
  385. } else {
  386. for i := 0; i < maxExtDNS; i++ {
  387. extDNS := &r.extDNSList[i]
  388. if extDNS.IPStr == "" {
  389. break
  390. }
  391. extConnect := func() {
  392. addr := fmt.Sprintf("%s:%d", extDNS.IPStr, 53)
  393. extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
  394. }
  395. if extDNS.HostLoopback {
  396. extConnect()
  397. } else {
  398. execErr := r.backend.ExecFunc(extConnect)
  399. if execErr != nil {
  400. logrus.Warn(execErr)
  401. continue
  402. }
  403. }
  404. if err != nil {
  405. logrus.WithField("retries", i).Warnf("[resolver] connect failed: %s", err)
  406. continue
  407. }
  408. logrus.Debugf("[resolver] query %s (%s) from %s, forwarding to %s:%s", queryName, dns.TypeToString[queryType],
  409. extConn.LocalAddr().String(), proto, extDNS.IPStr)
  410. // Timeout has to be set for every IO operation.
  411. if err := extConn.SetDeadline(time.Now().Add(extIOTimeout)); err != nil {
  412. logrus.WithError(err).Error("[resolver] error setting conn deadline")
  413. }
  414. co := &dns.Conn{
  415. Conn: extConn,
  416. UDPSize: uint16(maxSize),
  417. }
  418. defer co.Close()
  419. // limits the number of outstanding concurrent queries.
  420. if !r.forwardQueryStart() {
  421. old := r.tStamp
  422. r.tStamp = time.Now()
  423. if r.tStamp.Sub(old) > logInterval {
  424. logrus.Errorf("[resolver] more than %v concurrent queries from %s", maxConcurrent, extConn.LocalAddr().String())
  425. }
  426. continue
  427. }
  428. err = co.WriteMsg(query)
  429. if err != nil {
  430. r.forwardQueryEnd()
  431. logrus.Debugf("[resolver] send to DNS server failed, %s", err)
  432. continue
  433. }
  434. resp, err = co.ReadMsg()
  435. // Truncated DNS replies should be sent to the client so that the
  436. // client can retry over TCP
  437. if err != nil && (resp == nil || !resp.Truncated) {
  438. r.forwardQueryEnd()
  439. logrus.WithError(err).Debugf("[resolver] failed to read from DNS server")
  440. continue
  441. }
  442. r.forwardQueryEnd()
  443. if resp == nil {
  444. logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, queryName)
  445. break
  446. }
  447. switch resp.Rcode {
  448. case dns.RcodeServerFailure, dns.RcodeRefused:
  449. // Server returned FAILURE: continue with the next external DNS server
  450. // Server returned REFUSED: this can be a transitional status, so continue with the next external DNS server
  451. logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), queryName)
  452. continue
  453. case dns.RcodeNameError:
  454. // Server returned NXDOMAIN. Stop resolution if it's an authoritative answer (see RFC 8020: https://tools.ietf.org/html/rfc8020#section-2)
  455. logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), queryName)
  456. if resp.Authoritative {
  457. break
  458. }
  459. continue
  460. case dns.RcodeSuccess:
  461. // All is well
  462. default:
  463. // Server gave some error. Log the error, and continue with the next external DNS server
  464. logrus.Debugf("[resolver] external DNS %s:%s responded with %s (code %d) for %q", proto, extDNS.IPStr, statusString(resp.Rcode), resp.Rcode, queryName)
  465. continue
  466. }
  467. answers := 0
  468. for _, rr := range resp.Answer {
  469. h := rr.Header()
  470. switch h.Rrtype {
  471. case dns.TypeA:
  472. answers++
  473. ip := rr.(*dns.A).A
  474. logrus.Debugf("[resolver] received A record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
  475. r.backend.HandleQueryResp(h.Name, ip)
  476. case dns.TypeAAAA:
  477. answers++
  478. ip := rr.(*dns.AAAA).AAAA
  479. logrus.Debugf("[resolver] received AAAA record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
  480. r.backend.HandleQueryResp(h.Name, ip)
  481. }
  482. }
  483. if resp.Answer == nil || answers == 0 {
  484. logrus.Debugf("[resolver] external DNS %s:%s did not return any %s records for %q", proto, extDNS.IPStr, dns.TypeToString[queryType], queryName)
  485. }
  486. resp.Compress = true
  487. break
  488. }
  489. if resp == nil {
  490. return
  491. }
  492. }
  493. if err = w.WriteMsg(resp); err != nil {
  494. logrus.WithError(err).Errorf("[resolver] failed to write response")
  495. }
  496. }
  497. func statusString(responseCode int) string {
  498. if s, ok := dns.RcodeToString[responseCode]; ok {
  499. return s
  500. }
  501. return "UNKNOWN"
  502. }
  503. func (r *resolver) forwardQueryStart() bool {
  504. r.queryLock.Lock()
  505. defer r.queryLock.Unlock()
  506. if r.count == maxConcurrent {
  507. return false
  508. }
  509. r.count++
  510. return true
  511. }
  512. func (r *resolver) forwardQueryEnd() {
  513. r.queryLock.Lock()
  514. defer r.queryLock.Unlock()
  515. if r.count == 0 {
  516. logrus.Error("[resolver] invalid concurrent query count")
  517. } else {
  518. r.count--
  519. }
  520. }