Add embedded DNS server support for host loopback resolver

Signed-off-by: Santhosh Manohar <santhosh@docker.com>
This commit is contained in:
Santhosh Manohar 2016-12-18 18:27:13 -08:00
parent 44b9d2bceb
commit 14ae4337e1
6 changed files with 55 additions and 17 deletions

View File

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

View File

@ -4,10 +4,14 @@ import (
"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)$)`
// 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 localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost)
// IsLocalhost returns true if ip matches the localhost IP regular expression.
// 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 {
return localhostIPRegexp.MatchString(ip)
}
// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression.
func IsIPv4Localhost(ip string) bool {
return localhostIPv4Regexp.MatchString(ip)
}

View File

@ -29,7 +29,7 @@ type Resolver interface {
NameServer() string
// SetExtServers configures the external nameservers the resolver
// should use to forward queries
SetExtServers([]string)
SetExtServers([]extDNSEntry)
// ResolverOptions returns resolv.conf options that should be set
ResolverOptions() []string
}
@ -69,7 +69,8 @@ const (
)
type extDNSEntry struct {
ipStr string
ipStr string
hostLoopback bool
}
// resolver implements the Resolver interface
@ -182,13 +183,13 @@ func (r *resolver) Stop() {
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 {
l = maxExtDNS
}
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)
}
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 {
logrus.Warnf("Connect failed: %s", err)

View File

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

View File

@ -14,6 +14,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/resolvconf"
"github.com/docker/libnetwork/resolvconf/dns"
"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 {
var newRC *resolvconf.File
@ -208,7 +223,17 @@ func (sb *sandbox) setupDNS() error {
if err != nil {
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 {
// 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)
if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
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
// 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
// - If the embedded server needs any resolv.conf options add it to the current list
func (sb *sandbox) rebuildDNS() error {
@ -306,10 +330,9 @@ func (sb *sandbox) rebuildDNS() error {
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 (
dnsList = []string{sb.resolver.NameServer()}
dnsOptionsList = resolvconf.GetOptions(currRC.Content)

View File

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