|
@@ -14,6 +14,7 @@ import (
|
|
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
"github.com/docker/libnetwork/etchosts"
|
|
|
+ "github.com/docker/libnetwork/netutils"
|
|
|
"github.com/docker/libnetwork/osl"
|
|
|
"github.com/docker/libnetwork/resolvconf"
|
|
|
"github.com/docker/libnetwork/types"
|
|
@@ -322,11 +323,15 @@ func (sb *sandbox) startResolver() {
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
- sb.rebuildDNS()
|
|
|
+ err = sb.rebuildDNS()
|
|
|
+ if err != nil {
|
|
|
+ log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
|
|
|
+ return
|
|
|
+ }
|
|
|
sb.resolver.SetExtServers(sb.extDNS)
|
|
|
|
|
|
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
|
|
|
- if err := sb.resolver.Start(); err != nil {
|
|
|
+ if err = sb.resolver.Start(); err != nil {
|
|
|
log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
|
|
|
}
|
|
|
})
|
|
@@ -427,23 +432,51 @@ func (sb *sandbox) ResolveIP(ip string) string {
|
|
|
|
|
|
func (sb *sandbox) ResolveName(name string) net.IP {
|
|
|
var ip net.IP
|
|
|
- parts := strings.Split(name, ".")
|
|
|
- log.Debugf("To resolve %v", parts)
|
|
|
|
|
|
- reqName := parts[0]
|
|
|
- networkName := ""
|
|
|
- if len(parts) > 1 {
|
|
|
- networkName = parts[1]
|
|
|
+ // Embedded server owns the docker network domain. Resolution should work
|
|
|
+ // for both container_name and container_name.network_name
|
|
|
+ // We allow '.' in service name and network name. For a name a.b.c.d the
|
|
|
+ // following have to tried;
|
|
|
+ // {a.b.c.d in the networks container is connected to}
|
|
|
+ // {a.b.c in network d},
|
|
|
+ // {a.b in network c.d},
|
|
|
+ // {a in network b.c.d},
|
|
|
+
|
|
|
+ name = strings.TrimSuffix(name, ".")
|
|
|
+ reqName := []string{name}
|
|
|
+ networkName := []string{""}
|
|
|
+
|
|
|
+ if strings.Contains(name, ".") {
|
|
|
+ var i int
|
|
|
+ dup := name
|
|
|
+ for {
|
|
|
+ if i = strings.LastIndex(dup, "."); i == -1 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ networkName = append(networkName, name[i+1:])
|
|
|
+ reqName = append(reqName, name[:i])
|
|
|
+
|
|
|
+ dup = dup[:i]
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
epList := sb.getConnectedEndpoints()
|
|
|
- // First check for local container alias
|
|
|
- ip = sb.resolveName(reqName, networkName, epList, true)
|
|
|
- if ip != nil {
|
|
|
- return ip
|
|
|
- }
|
|
|
+ for i := 0; i < len(reqName); i++ {
|
|
|
+ log.Debugf("To resolve: %v in %v", reqName[i], networkName[i])
|
|
|
|
|
|
- // Resolve the actual container name
|
|
|
- return sb.resolveName(reqName, networkName, epList, false)
|
|
|
+ // First check for local container alias
|
|
|
+ ip = sb.resolveName(reqName[i], networkName[i], epList, true)
|
|
|
+ if ip != nil {
|
|
|
+ return ip
|
|
|
+ }
|
|
|
+
|
|
|
+ // Resolve the actual container name
|
|
|
+ ip = sb.resolveName(reqName[i], networkName[i], epList, false)
|
|
|
+ if ip != nil {
|
|
|
+ return ip
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) net.IP {
|
|
@@ -823,7 +856,7 @@ func (sb *sandbox) setupDNS() error {
|
|
|
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
|
|
|
var (
|
|
|
err error
|
|
|
- dnsList = resolvconf.GetNameservers(currRC.Content)
|
|
|
+ dnsList = resolvconf.GetNameservers(currRC.Content, netutils.IP)
|
|
|
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
|
|
|
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
|
|
|
)
|
|
@@ -865,6 +898,11 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
|
|
|
hashFile = sb.config.resolvConfHashFile
|
|
|
)
|
|
|
|
|
|
+ // This is for the host mode networking
|
|
|
+ if sb.config.originResolvConfPath != "" {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
|
|
|
return nil
|
|
|
}
|
|
@@ -897,36 +935,21 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
-
|
|
|
- // for atomic updates to these files, use temporary files with os.Rename:
|
|
|
- dir := path.Dir(sb.config.resolvConfPath)
|
|
|
- tmpHashFile, err := ioutil.TempFile(dir, "hash")
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
|
|
|
+ err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
- // Change the perms to filePerm (0644) since ioutil.TempFile creates it by default as 0600
|
|
|
- if err := os.Chmod(tmpResolvFile.Name(), filePerm); err != nil {
|
|
|
+ // write the new hash in a temp file and rename it to make the update atomic
|
|
|
+ dir := path.Dir(sb.config.resolvConfPath)
|
|
|
+ tmpHashFile, err := ioutil.TempFile(dir, "hash")
|
|
|
+ if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
-
|
|
|
- // write the updates to the temp files
|
|
|
if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- if err = ioutil.WriteFile(tmpResolvFile.Name(), newRC.Content, filePerm); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- // rename the temp files for atomic replace
|
|
|
- if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath)
|
|
|
+ return os.Rename(tmpHashFile.Name(), hashFile)
|
|
|
}
|
|
|
|
|
|
// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
|
|
@@ -941,7 +964,8 @@ func (sb *sandbox) rebuildDNS() error {
|
|
|
}
|
|
|
|
|
|
// localhost entries have already been filtered out from the list
|
|
|
- sb.extDNS = resolvconf.GetNameservers(currRC.Content)
|
|
|
+ // retain only the v4 servers in sb for forwarding the DNS queries
|
|
|
+ sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
|
|
|
|
|
|
var (
|
|
|
dnsList = []string{sb.resolver.NameServer()}
|
|
@@ -949,26 +973,14 @@ func (sb *sandbox) rebuildDNS() error {
|
|
|
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
|
|
|
)
|
|
|
|
|
|
+ // external v6 DNS servers has to be listed in resolv.conf
|
|
|
+ dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
|
|
|
+
|
|
|
// Resolver returns the options in the format resolv.conf expects
|
|
|
dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
|
|
|
|
|
|
- dir := path.Dir(sb.config.resolvConfPath)
|
|
|
- tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- // Change the perms to filePerm (0644) since ioutil.TempFile creates it by default as 0600
|
|
|
- if err := os.Chmod(tmpResolvFile.Name(), filePerm); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- _, err = resolvconf.Build(tmpResolvFile.Name(), dnsList, dnsSearchList, dnsOptionsList)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath)
|
|
|
+ _, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
// joinLeaveStart waits to ensure there are no joins or leaves in progress and
|