Prechádzať zdrojové kódy

Add embedded DNS server support for host loopback resolver

Signed-off-by: Santhosh Manohar <santhosh@docker.com>
Santhosh Manohar 8 rokov pred
rodič
commit
bf832ec2a7

+ 1 - 0
libnetwork/controller.go

@@ -918,6 +918,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s
 			populatedEndpoints: map[string]struct{}{},
 			populatedEndpoints: map[string]struct{}{},
 			config:             containerConfig{},
 			config:             containerConfig{},
 			controller:         c,
 			controller:         c,
+			extDNS:             []extDNSEntry{},
 		}
 		}
 	}
 	}
 	sBox = sb
 	sBox = sb

+ 10 - 1
libnetwork/resolvconf/dns/resolvconf.go

@@ -4,10 +4,14 @@ import (
 	"regexp"
 	"regexp"
 )
 )
 
 
-// IPLocalhost is a regex patter for localhost IP address range.
+// IPLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
 const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
 const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
 
 
+// IPv4Localhost is a regex pattern for IPv4 localhost address range.
+const IPv4Localhost = `(127\.([0-9]{1,3}\.){2}[0-9]{1,3})`
+
 var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
 var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
+var localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost)
 
 
 // IsLocalhost returns true if ip matches the localhost IP regular expression.
 // IsLocalhost returns true if ip matches the localhost IP regular expression.
 // Used for determining if nameserver settings are being passed which are
 // Used for determining if nameserver settings are being passed which are
@@ -15,3 +19,8 @@ var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
 func IsLocalhost(ip string) bool {
 func IsLocalhost(ip string) bool {
 	return localhostIPRegexp.MatchString(ip)
 	return localhostIPRegexp.MatchString(ip)
 }
 }
+
+// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression.
+func IsIPv4Localhost(ip string) bool {
+	return localhostIPv4Regexp.MatchString(ip)
+}

+ 14 - 9
libnetwork/resolver.go

@@ -29,7 +29,7 @@ type Resolver interface {
 	NameServer() string
 	NameServer() string
 	// SetExtServers configures the external nameservers the resolver
 	// SetExtServers configures the external nameservers the resolver
 	// should use to forward queries
 	// should use to forward queries
-	SetExtServers([]string)
+	SetExtServers([]extDNSEntry)
 	// ResolverOptions returns resolv.conf options that should be set
 	// ResolverOptions returns resolv.conf options that should be set
 	ResolverOptions() []string
 	ResolverOptions() []string
 }
 }
@@ -69,7 +69,8 @@ const (
 )
 )
 
 
 type extDNSEntry struct {
 type extDNSEntry struct {
-	ipStr string
+	ipStr        string
+	hostLoopback bool
 }
 }
 
 
 // resolver implements the Resolver interface
 // resolver implements the Resolver interface
@@ -182,13 +183,13 @@ func (r *resolver) Stop() {
 	r.queryLock = sync.Mutex{}
 	r.queryLock = sync.Mutex{}
 }
 }
 
 
-func (r *resolver) SetExtServers(dns []string) {
-	l := len(dns)
+func (r *resolver) SetExtServers(extDNS []extDNSEntry) {
+	l := len(extDNS)
 	if l > maxExtDNS {
 	if l > maxExtDNS {
 		l = maxExtDNS
 		l = maxExtDNS
 	}
 	}
 	for i := 0; i < l; i++ {
 	for i := 0; i < l; i++ {
-		r.extDNSList[i].ipStr = dns[i]
+		r.extDNSList[i] = extDNS[i]
 	}
 	}
 }
 }
 
 
@@ -417,10 +418,14 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
 				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
 			}
 			}
 
 
-			execErr := r.backend.ExecFunc(extConnect)
-			if execErr != nil {
-				logrus.Warn(execErr)
-				continue
+			if extDNS.hostLoopback {
+				extConnect()
+			} else {
+				execErr := r.backend.ExecFunc(extConnect)
+				if execErr != nil {
+					logrus.Warn(execErr)
+					continue
+				}
 			}
 			}
 			if err != nil {
 			if err != nil {
 				logrus.Warnf("Connect failed: %s", err)
 				logrus.Warnf("Connect failed: %s", err)

+ 1 - 1
libnetwork/sandbox.go

@@ -69,7 +69,7 @@ type sandbox struct {
 	id                 string
 	id                 string
 	containerID        string
 	containerID        string
 	config             containerConfig
 	config             containerConfig
-	extDNS             []string
+	extDNS             []extDNSEntry
 	osSbox             osl.Sandbox
 	osSbox             osl.Sandbox
 	controller         *controller
 	controller         *controller
 	resolver           Resolver
 	resolver           Resolver

+ 28 - 5
libnetwork/sandbox_dns_unix.go

@@ -14,6 +14,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/resolvconf"
+	"github.com/docker/libnetwork/resolvconf/dns"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
 )
 )
 
 
@@ -161,6 +162,20 @@ func (sb *sandbox) restorePath() {
 	}
 	}
 }
 }
 
 
+func (sb *sandbox) setExternalResolvers(content []byte, addrType int, checkLoopback bool) {
+	servers := resolvconf.GetNameservers(content, addrType)
+	for _, ip := range servers {
+		hostLoopback := false
+		if checkLoopback {
+			hostLoopback = dns.IsIPv4Localhost(ip)
+		}
+		sb.extDNS = append(sb.extDNS, extDNSEntry{
+			ipStr:        ip,
+			hostLoopback: hostLoopback,
+		})
+	}
+}
+
 func (sb *sandbox) setupDNS() error {
 func (sb *sandbox) setupDNS() error {
 	var newRC *resolvconf.File
 	var newRC *resolvconf.File
 
 
@@ -208,7 +223,17 @@ func (sb *sandbox) setupDNS() error {
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
+		// After building the resolv.conf from the user config save the
+		// external resolvers in the sandbox. Note that --dns 127.0.0.x
+		// config refers to the loopback in the container namespace
+		sb.setExternalResolvers(newRC.Content, types.IPv4, false)
 	} else {
 	} else {
+		// If the host resolv.conf file has 127.0.0.x container should
+		// use the host restolver for queries. This is supported by the
+		// docker embedded DNS server. Hence save the external resolvers
+		// before filtering it out.
+		sb.setExternalResolvers(currRC.Content, types.IPv4, true)
+
 		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
 		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
 		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
 		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
 			return err
 			return err
@@ -297,7 +322,6 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
 
 
 // Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
 // Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
 // resolv.conf by doing the following
 // resolv.conf by doing the following
-// - Save the external name servers in resolv.conf in the sandbox
 // - Add only the embedded server's IP to container's resolv.conf
 // - Add only the embedded server's IP to container's resolv.conf
 // - If the embedded server needs any resolv.conf options add it to the current list
 // - If the embedded server needs any resolv.conf options add it to the current list
 func (sb *sandbox) rebuildDNS() error {
 func (sb *sandbox) rebuildDNS() error {
@@ -306,10 +330,9 @@ func (sb *sandbox) rebuildDNS() error {
 		return err
 		return err
 	}
 	}
 
 
-	// localhost entries have already been filtered out from the list
-	// retain only the v4 servers in sb for forwarding the DNS queries
-	sb.extDNS = resolvconf.GetNameservers(currRC.Content, types.IPv4)
-
+	if len(sb.extDNS) == 0 {
+		sb.setExternalResolvers(currRC.Content, types.IPv4, false)
+	}
 	var (
 	var (
 		dnsList        = []string{sb.resolver.NameServer()}
 		dnsList        = []string{sb.resolver.NameServer()}
 		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
 		dnsOptionsList = resolvconf.GetOptions(currRC.Content)

+ 1 - 1
libnetwork/sandbox_store.go

@@ -27,7 +27,7 @@ type sbState struct {
 	dbExists   bool
 	dbExists   bool
 	Eps        []epState
 	Eps        []epState
 	EpPriority map[string]int
 	EpPriority map[string]int
-	ExtDNS     []string
+	ExtDNS     []extDNSEntry
 }
 }
 
 
 func (sbs *sbState) Key() []string {
 func (sbs *sbState) Key() []string {