Bläddra i källkod

Merge pull request #870 from sanimej/bugs

Adds AAAA record handling for the embedded DNS
Madhu Venugopal 9 år sedan
förälder
incheckning
22fae3ae2c
4 ändrade filer med 98 tillägg och 48 borttagningar
  1. 1 1
      libnetwork/libnetwork_test.go
  2. 63 30
      libnetwork/network.go
  3. 20 9
      libnetwork/resolver.go
  4. 14 8
      libnetwork/sandbox.go

+ 1 - 1
libnetwork/libnetwork_test.go

@@ -1216,7 +1216,7 @@ func (f *fakeSandbox) SetKey(key string) error {
 	return nil
 }
 
-func (f *fakeSandbox) ResolveName(name string) []net.IP {
+func (f *fakeSandbox) ResolveName(name string, ipType int) []net.IP {
 	return nil
 }
 

+ 63 - 30
libnetwork/network.go

@@ -71,8 +71,9 @@ type NetworkInfo interface {
 type EndpointWalker func(ep Endpoint) bool
 
 type svcInfo struct {
-	svcMap map[string][]net.IP
-	ipMap  map[string]string
+	svcMap     map[string][]net.IP
+	svcIPv6Map map[string][]net.IP
+	ipMap      map[string]string
 }
 
 // IpamConf contains all the ipam related configurations for a network
@@ -894,68 +895,103 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
 }
 
 func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool) {
+	var ipv6 net.IP
 	epName := ep.Name()
 	if iface := ep.Iface(); iface.Address() != nil {
 		myAliases := ep.MyAliases()
+		if iface.AddressIPv6() != nil {
+			ipv6 = iface.AddressIPv6().IP
+		}
+
 		if isAdd {
 			// If anonymous endpoint has an alias use the first alias
 			// for ip->name mapping. Not having the reverse mapping
 			// breaks some apps
 			if ep.isAnonymous() {
 				if len(myAliases) > 0 {
-					n.addSvcRecords(myAliases[0], iface.Address().IP, true)
+					n.addSvcRecords(myAliases[0], iface.Address().IP, ipv6, true)
 				}
 			} else {
-				n.addSvcRecords(epName, iface.Address().IP, true)
+				n.addSvcRecords(epName, iface.Address().IP, ipv6, true)
 			}
 			for _, alias := range myAliases {
-				n.addSvcRecords(alias, iface.Address().IP, false)
+				n.addSvcRecords(alias, iface.Address().IP, ipv6, false)
 			}
 		} else {
 			if ep.isAnonymous() {
 				if len(myAliases) > 0 {
-					n.deleteSvcRecords(myAliases[0], iface.Address().IP, true)
+					n.deleteSvcRecords(myAliases[0], iface.Address().IP, ipv6, true)
 				}
 			} else {
-				n.deleteSvcRecords(epName, iface.Address().IP, true)
+				n.deleteSvcRecords(epName, iface.Address().IP, ipv6, true)
 			}
 			for _, alias := range myAliases {
-				n.deleteSvcRecords(alias, iface.Address().IP, false)
+				n.deleteSvcRecords(alias, iface.Address().IP, ipv6, false)
 			}
 		}
 	}
 }
 
-func (n *network) addSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
+func addIPToName(ipMap map[string]string, name string, ip net.IP) {
+	reverseIP := netutils.ReverseIP(ip.String())
+	if _, ok := ipMap[reverseIP]; !ok {
+		ipMap[reverseIP] = name
+	}
+}
+
+func addNameToIP(svcMap map[string][]net.IP, name string, epIP net.IP) {
+	ipList := svcMap[name]
+	for _, ip := range ipList {
+		if ip.Equal(epIP) {
+			return
+		}
+	}
+	svcMap[name] = append(svcMap[name], epIP)
+}
+
+func delNameToIP(svcMap map[string][]net.IP, name string, epIP net.IP) {
+	ipList := svcMap[name]
+	for i, ip := range ipList {
+		if ip.Equal(epIP) {
+			ipList = append(ipList[:i], ipList[i+1:]...)
+			break
+		}
+	}
+	svcMap[name] = ipList
+
+	if len(ipList) == 0 {
+		delete(svcMap, name)
+	}
+}
+
+func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool) {
 	c := n.getController()
 	c.Lock()
 	defer c.Unlock()
 	sr, ok := c.svcDb[n.ID()]
 	if !ok {
 		sr = svcInfo{
-			svcMap: make(map[string][]net.IP),
-			ipMap:  make(map[string]string),
+			svcMap:     make(map[string][]net.IP),
+			svcIPv6Map: make(map[string][]net.IP),
+			ipMap:      make(map[string]string),
 		}
 		c.svcDb[n.ID()] = sr
 	}
 
 	if ipMapUpdate {
-		reverseIP := netutils.ReverseIP(epIP.String())
-		if _, ok := sr.ipMap[reverseIP]; !ok {
-			sr.ipMap[reverseIP] = name
+		addIPToName(sr.ipMap, name, epIP)
+		if epIPv6 != nil {
+			addIPToName(sr.ipMap, name, epIPv6)
 		}
 	}
 
-	ipList := sr.svcMap[name]
-	for _, ip := range ipList {
-		if ip.Equal(epIP) {
-			return
-		}
+	addNameToIP(sr.svcMap, name, epIP)
+	if epIPv6 != nil {
+		addNameToIP(sr.svcIPv6Map, name, epIPv6)
 	}
-	sr.svcMap[name] = append(sr.svcMap[name], epIP)
 }
 
-func (n *network) deleteSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
+func (n *network) deleteSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool) {
 	c := n.getController()
 	c.Lock()
 	defer c.Unlock()
@@ -966,19 +1002,16 @@ func (n *network) deleteSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
 
 	if ipMapUpdate {
 		delete(sr.ipMap, netutils.ReverseIP(epIP.String()))
-	}
 
-	ipList := sr.svcMap[name]
-	for i, ip := range ipList {
-		if ip.Equal(epIP) {
-			ipList = append(ipList[:i], ipList[i+1:]...)
-			break
+		if epIPv6 != nil {
+			delete(sr.ipMap, netutils.ReverseIP(epIPv6.String()))
 		}
 	}
-	sr.svcMap[name] = ipList
 
-	if len(ipList) == 0 {
-		delete(sr.svcMap, name)
+	delNameToIP(sr.svcMap, name, epIP)
+
+	if epIPv6 != nil {
+		delNameToIP(sr.svcIPv6Map, name, epIPv6)
 	}
 }
 

+ 20 - 9
libnetwork/resolver.go

@@ -10,6 +10,7 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/iptables"
+	"github.com/docker/libnetwork/netutils"
 	"github.com/miekg/dns"
 )
 
@@ -185,8 +186,8 @@ func shuffleAddr(addr []net.IP) []net.IP {
 	return addr
 }
 
-func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
-	addr := r.sb.ResolveName(name)
+func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) {
+	addr := r.sb.ResolveName(name, ipType)
 	if addr == nil {
 		return nil, nil
 	}
@@ -200,12 +201,20 @@ func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error
 	if len(addr) > 1 {
 		addr = shuffleAddr(addr)
 	}
-
-	for _, ip := range addr {
-		rr := new(dns.A)
-		rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
-		rr.A = ip
-		resp.Answer = append(resp.Answer, rr)
+	if ipType == netutils.IPv4 {
+		for _, ip := range addr {
+			rr := new(dns.A)
+			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
+			rr.A = ip
+			resp.Answer = append(resp.Answer, rr)
+		}
+	} else {
+		for _, ip := range addr {
+			rr := new(dns.AAAA)
+			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL}
+			rr.AAAA = ip
+			resp.Answer = append(resp.Answer, rr)
+		}
 	}
 	return resp, nil
 }
@@ -264,7 +273,9 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 	}
 	name := query.Question[0].Name
 	if query.Question[0].Qtype == dns.TypeA {
-		resp, err = r.handleIPv4Query(name, query)
+		resp, err = r.handleIPQuery(name, query, netutils.IPv4)
+	} else if query.Question[0].Qtype == dns.TypeAAAA {
+		resp, err = r.handleIPQuery(name, query, netutils.IPv6)
 	} else if query.Question[0].Qtype == dns.TypePTR {
 		resp, err = r.handlePTRQuery(name, query)
 	}

+ 14 - 8
libnetwork/sandbox.go

@@ -11,6 +11,7 @@ import (
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
 )
@@ -36,9 +37,9 @@ type Sandbox interface {
 	Rename(name string) error
 	// Delete destroys this container after detaching it from all connected endpoints.
 	Delete() error
-	// ResolveName searches for the service name in the networks to which the sandbox
-	// is connected to.
-	ResolveName(name string) []net.IP
+	// ResolveName resolves a service name to an IPv4 or IPv6 address by searching the
+	// networks the sandbox is connected to.
+	ResolveName(name string, iplen int) []net.IP
 	// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
 	// notation; the format used for DNS PTR records
 	ResolveIP(name string) string
@@ -418,7 +419,7 @@ func (sb *sandbox) execFunc(f func()) {
 	sb.osSbox.InvokeFunc(f)
 }
 
-func (sb *sandbox) ResolveName(name string) []net.IP {
+func (sb *sandbox) ResolveName(name string, ipType int) []net.IP {
 	var ip []net.IP
 
 	// Embedded server owns the docker network domain. Resolution should work
@@ -453,13 +454,13 @@ func (sb *sandbox) ResolveName(name string) []net.IP {
 		log.Debugf("To resolve: %v in %v", reqName[i], networkName[i])
 
 		// First check for local container alias
-		ip = sb.resolveName(reqName[i], networkName[i], epList, true)
+		ip = sb.resolveName(reqName[i], networkName[i], epList, true, ipType)
 		if ip != nil {
 			return ip
 		}
 
 		// Resolve the actual container name
-		ip = sb.resolveName(reqName[i], networkName[i], epList, false)
+		ip = sb.resolveName(reqName[i], networkName[i], epList, false, ipType)
 		if ip != nil {
 			return ip
 		}
@@ -467,7 +468,7 @@ func (sb *sandbox) ResolveName(name string) []net.IP {
 	return nil
 }
 
-func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) []net.IP {
+func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool, ipType int) []net.IP {
 	for _, ep := range epList {
 		name := req
 		n := ep.getNetwork()
@@ -504,8 +505,13 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
 			continue
 		}
 
+		var ip []net.IP
 		n.Lock()
-		ip, ok := sr.svcMap[name]
+		if ipType == netutils.IPv6 {
+			ip, ok = sr.svcIPv6Map[name]
+		} else {
+			ip, ok = sr.svcMap[name]
+		}
 		n.Unlock()
 		if ok {
 			return ip