فهرست منبع

libnetwork: extract fn for external DNS forwarding

Signed-off-by: Cory Snider <csnider@mirantis.com>
Cory Snider 2 سال پیش
والد
کامیت
92aa6e6282
1فایلهای تغییر یافته به همراه118 افزوده شده و 108 حذف شده
  1. 118 108
      libnetwork/resolver.go

+ 118 - 108
libnetwork/resolver.go

@@ -371,9 +371,8 @@ func truncateResp(resp *dns.Msg, maxSize int, isTCP bool) {
 
 func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 	var (
-		extConn net.Conn
-		resp    *dns.Msg
-		err     error
+		resp *dns.Msg
+		err  error
 	)
 
 	if query == nil || len(query.Question) == 0 {
@@ -446,127 +445,138 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 			truncateResp(resp, maxSize, proto == "tcp")
 		}
 	} else {
-		for i := 0; i < maxExtDNS; i++ {
-			extDNS := &r.extDNSList[i]
-			if extDNS.IPStr == "" {
-				break
-			}
-			extConnect := func() {
-				port := extDNS.port
-				if port == 0 {
-					port = 53
-				}
-				addr := fmt.Sprintf("%s:%d", extDNS.IPStr, port)
-				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
-			}
+		resp = r.forwardExtDNS(proto, maxSize, query)
+		if resp == nil {
+			return
+		}
+	}
 
-			if extDNS.HostLoopback {
-				extConnect()
-			} else {
-				execErr := r.backend.ExecFunc(extConnect)
-				if execErr != nil {
-					logrus.Warn(execErr)
-					continue
-				}
-			}
-			if err != nil {
-				logrus.WithField("retries", i).Warnf("[resolver] connect failed: %s", err)
-				continue
-			}
-			logrus.Debugf("[resolver] query %s (%s) from %s, forwarding to %s:%s", queryName, dns.TypeToString[queryType],
-				extConn.LocalAddr().String(), proto, extDNS.IPStr)
+	if err = w.WriteMsg(resp); err != nil {
+		logrus.WithError(err).Errorf("[resolver] failed to write response")
+	}
+}
 
-			// Timeout has to be set for every IO operation.
-			if err := extConn.SetDeadline(time.Now().Add(extIOTimeout)); err != nil {
-				logrus.WithError(err).Error("[resolver] error setting conn deadline")
-			}
-			co := &dns.Conn{
-				Conn:    extConn,
-				UDPSize: uint16(maxSize),
-			}
-			defer co.Close()
-
-			// limits the number of outstanding concurrent queries.
-			if !r.forwardQueryStart() {
-				old := r.tStamp
-				r.tStamp = time.Now()
-				if r.tStamp.Sub(old) > logInterval {
-					logrus.Errorf("[resolver] more than %v concurrent queries from %s", maxConcurrent, extConn.LocalAddr().String())
-				}
-				continue
+func (r *resolver) forwardExtDNS(proto string, maxSize int, query *dns.Msg) *dns.Msg {
+	queryName, queryType := query.Question[0].Name, query.Question[0].Qtype
+	var resp *dns.Msg
+	for i := 0; i < maxExtDNS; i++ {
+		extDNS := &r.extDNSList[i]
+		if extDNS.IPStr == "" {
+			break
+		}
+		var (
+			extConn net.Conn
+			err     error
+		)
+		extConnect := func() {
+			port := extDNS.port
+			if port == 0 {
+				port = 53
 			}
+			addr := fmt.Sprintf("%s:%d", extDNS.IPStr, port)
+			extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
+		}
 
-			err = co.WriteMsg(query)
-			if err != nil {
-				r.forwardQueryEnd()
-				logrus.Debugf("[resolver] send to DNS server failed, %s", err)
+		if extDNS.HostLoopback {
+			extConnect()
+		} else {
+			execErr := r.backend.ExecFunc(extConnect)
+			if execErr != nil {
+				logrus.Warn(execErr)
 				continue
 			}
+		}
+		if err != nil {
+			logrus.WithField("retries", i).Warnf("[resolver] connect failed: %s", err)
+			continue
+		}
+		logrus.Debugf("[resolver] query %s (%s) from %s, forwarding to %s:%s", queryName, dns.TypeToString[queryType],
+			extConn.LocalAddr().String(), proto, extDNS.IPStr)
 
-			resp, err = co.ReadMsg()
-			// Truncated DNS replies should be sent to the client so that the
-			// client can retry over TCP
-			if err != nil && (resp == nil || !resp.Truncated) {
-				r.forwardQueryEnd()
-				logrus.WithError(err).Warnf("[resolver] failed to read from DNS server: %s, query: %s", extConn.RemoteAddr().String(), query.Question[0].String())
-				continue
+		// Timeout has to be set for every IO operation.
+		if err := extConn.SetDeadline(time.Now().Add(extIOTimeout)); err != nil {
+			logrus.WithError(err).Error("[resolver] error setting conn deadline")
+		}
+		co := &dns.Conn{
+			Conn:    extConn,
+			UDPSize: uint16(maxSize),
+		}
+		defer co.Close()
+
+		// limits the number of outstanding concurrent queries.
+		if !r.forwardQueryStart() {
+			old := r.tStamp
+			r.tStamp = time.Now()
+			if r.tStamp.Sub(old) > logInterval {
+				logrus.Errorf("[resolver] more than %v concurrent queries from %s", maxConcurrent, extConn.LocalAddr().String())
 			}
+			continue
+		}
+
+		err = co.WriteMsg(query)
+		if err != nil {
 			r.forwardQueryEnd()
+			logrus.Debugf("[resolver] send to DNS server failed, %s", err)
+			continue
+		}
 
-			if resp == nil {
-				logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, queryName)
+		resp, err = co.ReadMsg()
+		// Truncated DNS replies should be sent to the client so that the
+		// client can retry over TCP
+		if err != nil && (resp == nil || !resp.Truncated) {
+			r.forwardQueryEnd()
+			logrus.WithError(err).Warnf("[resolver] failed to read from DNS server: %s, query: %s", extConn.RemoteAddr().String(), query.Question[0].String())
+			continue
+		}
+		r.forwardQueryEnd()
+
+		if resp == nil {
+			logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, queryName)
+			break
+		}
+		switch resp.Rcode {
+		case dns.RcodeServerFailure, dns.RcodeRefused:
+			// Server returned FAILURE: continue with the next external DNS server
+			// Server returned REFUSED: this can be a transitional status, so continue with the next external DNS server
+			logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), queryName)
+			continue
+		case dns.RcodeNameError:
+			// Server returned NXDOMAIN. Stop resolution if it's an authoritative answer (see RFC 8020: https://tools.ietf.org/html/rfc8020#section-2)
+			logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), queryName)
+			if resp.Authoritative {
 				break
 			}
-			switch resp.Rcode {
-			case dns.RcodeServerFailure, dns.RcodeRefused:
-				// Server returned FAILURE: continue with the next external DNS server
-				// Server returned REFUSED: this can be a transitional status, so continue with the next external DNS server
-				logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), queryName)
-				continue
-			case dns.RcodeNameError:
-				// Server returned NXDOMAIN. Stop resolution if it's an authoritative answer (see RFC 8020: https://tools.ietf.org/html/rfc8020#section-2)
-				logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), queryName)
-				if resp.Authoritative {
-					break
-				}
-				continue
-			case dns.RcodeSuccess:
-				// All is well
-			default:
-				// Server gave some error. Log the error, and continue with the next external DNS server
-				logrus.Debugf("[resolver] external DNS %s:%s responded with %s (code %d) for %q", proto, extDNS.IPStr, statusString(resp.Rcode), resp.Rcode, queryName)
-				continue
-			}
-			answers := 0
-			for _, rr := range resp.Answer {
-				h := rr.Header()
-				switch h.Rrtype {
-				case dns.TypeA:
-					answers++
-					ip := rr.(*dns.A).A
-					logrus.Debugf("[resolver] received A record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
-					r.backend.HandleQueryResp(h.Name, ip)
-				case dns.TypeAAAA:
-					answers++
-					ip := rr.(*dns.AAAA).AAAA
-					logrus.Debugf("[resolver] received AAAA record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
-					r.backend.HandleQueryResp(h.Name, ip)
-				}
-			}
-			if resp.Answer == nil || answers == 0 {
-				logrus.Debugf("[resolver] external DNS %s:%s did not return any %s records for %q", proto, extDNS.IPStr, dns.TypeToString[queryType], queryName)
+			continue
+		case dns.RcodeSuccess:
+			// All is well
+		default:
+			// Server gave some error. Log the error, and continue with the next external DNS server
+			logrus.Debugf("[resolver] external DNS %s:%s responded with %s (code %d) for %q", proto, extDNS.IPStr, statusString(resp.Rcode), resp.Rcode, queryName)
+			continue
+		}
+		answers := 0
+		for _, rr := range resp.Answer {
+			h := rr.Header()
+			switch h.Rrtype {
+			case dns.TypeA:
+				answers++
+				ip := rr.(*dns.A).A
+				logrus.Debugf("[resolver] received A record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
+				r.backend.HandleQueryResp(h.Name, ip)
+			case dns.TypeAAAA:
+				answers++
+				ip := rr.(*dns.AAAA).AAAA
+				logrus.Debugf("[resolver] received AAAA record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
+				r.backend.HandleQueryResp(h.Name, ip)
 			}
-			resp.Compress = true
-			break
 		}
-		if resp == nil {
-			return
+		if resp.Answer == nil || answers == 0 {
+			logrus.Debugf("[resolver] external DNS %s:%s did not return any %s records for %q", proto, extDNS.IPStr, dns.TypeToString[queryType], queryName)
 		}
+		resp.Compress = true
+		break
 	}
-
-	if err = w.WriteMsg(resp); err != nil {
-		logrus.WithError(err).Errorf("[resolver] failed to write response")
-	}
+	return resp
 }
 
 func statusString(responseCode int) string {