瀏覽代碼

Defer PTR queries to external servers based on A/AAAA response

Signed-off-by: Santhosh Manohar <santhosh@docker.com>
Santhosh Manohar 8 年之前
父節點
當前提交
879d94edbd
共有 4 個文件被更改,包括 62 次插入20 次删除
  1. 1 1
      libnetwork/libnetwork_internal_test.go
  2. 38 17
      libnetwork/network.go
  3. 16 2
      libnetwork/resolver.go
  4. 7 0
      libnetwork/sandbox.go

+ 1 - 1
libnetwork/libnetwork_internal_test.go

@@ -380,7 +380,7 @@ func TestSRVServiceQuery(t *testing.T) {
 	sr := svcInfo{
 		svcMap:     make(map[string][]net.IP),
 		svcIPv6Map: make(map[string][]net.IP),
-		ipMap:      make(map[string]string),
+		ipMap:      make(map[string]*ipInfo),
 		service:    make(map[string][]servicePorts),
 	}
 	// backing container for the service

+ 38 - 17
libnetwork/network.go

@@ -80,10 +80,18 @@ type NetworkInfo interface {
 // When the function returns true, the walk will stop.
 type EndpointWalker func(ep Endpoint) bool
 
+// ipInfo is the reverse mapping from IP to service name to serve the PTR query.
+// extResolver is set if an externl server resolves a service name to this IP.
+// Its an indication to defer PTR queries also to that external server.
+type ipInfo struct {
+	name        string
+	extResolver bool
+}
+
 type svcInfo struct {
 	svcMap     map[string][]net.IP
 	svcIPv6Map map[string][]net.IP
-	ipMap      map[string]string
+	ipMap      map[string]*ipInfo
 	service    map[string][]servicePorts
 }
 
@@ -1070,10 +1078,12 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool
 	}
 }
 
-func addIPToName(ipMap map[string]string, name string, ip net.IP) {
+func addIPToName(ipMap map[string]*ipInfo, name string, ip net.IP) {
 	reverseIP := netutils.ReverseIP(ip.String())
 	if _, ok := ipMap[reverseIP]; !ok {
-		ipMap[reverseIP] = name
+		ipMap[reverseIP] = &ipInfo{
+			name: name,
+		}
 	}
 }
 
@@ -1117,7 +1127,7 @@ func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUp
 		sr = svcInfo{
 			svcMap:     make(map[string][]net.IP),
 			svcIPv6Map: make(map[string][]net.IP),
-			ipMap:      make(map[string]string),
+			ipMap:      make(map[string]*ipInfo),
 		}
 		c.svcRecords[n.ID()] = sr
 	}
@@ -1612,8 +1622,8 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
 
 	c := n.getController()
 	c.Lock()
+	defer c.Unlock()
 	sr, ok := c.svcRecords[n.ID()]
-	c.Unlock()
 
 	if !ok {
 		return nil, false
@@ -1621,7 +1631,6 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
 
 	req = strings.TrimSuffix(req, ".")
 	var ip []net.IP
-	n.Lock()
 	ip, ok = sr.svcMap[req]
 
 	if ipType == types.IPv6 {
@@ -1634,7 +1643,6 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
 		}
 		ip = sr.svcIPv6Map[req]
 	}
-	n.Unlock()
 
 	if ip != nil {
 		return ip, false
@@ -1643,13 +1651,28 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
 	return nil, ipv6Miss
 }
 
-func (n *network) ResolveIP(ip string) string {
-	var svc string
+func (n *network) HandleQueryResp(name string, ip net.IP) {
+	c := n.getController()
+	c.Lock()
+	defer c.Unlock()
+	sr, ok := c.svcRecords[n.ID()]
 
+	if !ok {
+		return
+	}
+
+	ipStr := netutils.ReverseIP(ip.String())
+
+	if ipInfo, ok := sr.ipMap[ipStr]; ok {
+		ipInfo.extResolver = true
+	}
+}
+
+func (n *network) ResolveIP(ip string) string {
 	c := n.getController()
 	c.Lock()
+	defer c.Unlock()
 	sr, ok := c.svcRecords[n.ID()]
-	c.Unlock()
 
 	if !ok {
 		return ""
@@ -1657,15 +1680,13 @@ func (n *network) ResolveIP(ip string) string {
 
 	nwName := n.Name()
 
-	n.Lock()
-	defer n.Unlock()
-	svc, ok = sr.ipMap[ip]
+	ipInfo, ok := sr.ipMap[ip]
 
-	if ok {
-		return svc + "." + nwName
+	if !ok || ipInfo.extResolver {
+		return ""
 	}
 
-	return svc
+	return ipInfo.name + "." + nwName
 }
 
 func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
@@ -1689,8 +1710,8 @@ func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
 	svcName := strings.Join(parts[2:], ".")
 
 	c.Lock()
+	defer c.Unlock()
 	sr, ok := c.svcRecords[n.ID()]
-	c.Unlock()
 
 	if !ok {
 		return nil, nil

+ 16 - 2
libnetwork/resolver.go

@@ -54,6 +54,9 @@ type DNSBackend interface {
 	ExecFunc(f func()) error
 	//NdotsSet queries the backends ndots dns option settings
 	NdotsSet() bool
+	// HandleQueryResp passes the name & IP from a response to the backend. backend
+	// can use it to maintain any required state about the resolution
+	HandleQueryResp(name string, ip net.IP)
 }
 
 const (
@@ -462,9 +465,20 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 				logrus.Debugf("Read from DNS server failed, %s", err)
 				continue
 			}
-
 			r.forwardQueryEnd()
-
+			if resp != nil {
+				for _, rr := range resp.Answer {
+					h := rr.Header()
+					switch h.Rrtype {
+					case dns.TypeA:
+						ip := rr.(*dns.A).A
+						r.backend.HandleQueryResp(h.Name, ip)
+					case dns.TypeAAAA:
+						ip := rr.(*dns.AAAA).AAAA
+						r.backend.HandleQueryResp(h.Name, ip)
+					}
+				}
+			}
 			resp.Compress = true
 			break
 		}

+ 7 - 0
libnetwork/sandbox.go

@@ -411,6 +411,13 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
 	return nil
 }
 
+func (sb *sandbox) HandleQueryResp(name string, ip net.IP) {
+	for _, ep := range sb.getConnectedEndpoints() {
+		n := ep.getNetwork()
+		n.HandleQueryResp(name, ip)
+	}
+}
+
 func (sb *sandbox) ResolveIP(ip string) string {
 	var svc string
 	logrus.Debugf("IP To resolve %v", ip)