Signed-off-by: Santhosh Manohar <santhosh@docker.com>
| ... | ... |
@@ -27,7 +27,7 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de |
| 27 | 27 |
clone git github.com/imdario/mergo 0.2.1 |
| 28 | 28 |
|
| 29 | 29 |
#get libnetwork packages |
| 30 |
-clone git github.com/docker/libnetwork v0.6.0-rc1 |
|
| 30 |
+clone git github.com/docker/libnetwork v0.6.0-rc2 |
|
| 31 | 31 |
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| 32 | 32 |
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b |
| 33 | 33 |
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 |
| ... | ... |
@@ -1,5 +1,11 @@ |
| 1 | 1 |
# Changelog |
| 2 | 2 |
|
| 3 |
+## 0.6.0-rc2 (2016-01-21) |
|
| 4 |
+- Fixes docker/docker#19376 |
|
| 5 |
+- Fixes docker/docker#15819 |
|
| 6 |
+- Fixes libnetwork/#885, Not filter v6 DNS servers from resolv.conf |
|
| 7 |
+- Fixes docker/docker #19448, also handles the . in service and network names correctly. |
|
| 8 |
+ |
|
| 3 | 9 |
## 0.6.0-rc1 (2016-01-14) |
| 4 | 10 |
- Fixes docker/docker#19404 |
| 5 | 11 |
- Fixes the ungraceful daemon restart issue in systemd with remote network plugin |
| ... | ... |
@@ -14,6 +14,13 @@ import ( |
| 14 | 14 |
"github.com/docker/libnetwork/types" |
| 15 | 15 |
) |
| 16 | 16 |
|
| 17 |
+// constants for the IP address type |
|
| 18 |
+const ( |
|
| 19 |
+ IP = iota // IPv4 and IPv6 |
|
| 20 |
+ IPv4 |
|
| 21 |
+ IPv6 |
|
| 22 |
+) |
|
| 23 |
+ |
|
| 17 | 24 |
var ( |
| 18 | 25 |
// ErrNetworkOverlapsWithNameservers preformatted error |
| 19 | 26 |
ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
|
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
|
| 11 | 11 |
"github.com/Sirupsen/logrus" |
| 12 | 12 |
"github.com/docker/docker/pkg/ioutils" |
| 13 |
+ "github.com/docker/libnetwork/netutils" |
|
| 13 | 14 |
"github.com/docker/libnetwork/resolvconf/dns" |
| 14 | 15 |
) |
| 15 | 16 |
|
| ... | ... |
@@ -29,6 +30,8 @@ var ( |
| 29 | 29 |
localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`) |
| 30 | 30 |
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`) |
| 31 | 31 |
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`) |
| 32 |
+ nsIPv6Regexpmatch = regexp.MustCompile(`^\s*nameserver\s*((` + ipv6Address + `))\s*$`) |
|
| 33 |
+ nsIPv4Regexpmatch = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `))\s*$`) |
|
| 32 | 34 |
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`) |
| 33 | 35 |
optionsRegexp = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`) |
| 34 | 36 |
) |
| ... | ... |
@@ -119,7 +122,7 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) {
|
| 119 | 119 |
} |
| 120 | 120 |
// if the resulting resolvConf has no more nameservers defined, add appropriate |
| 121 | 121 |
// default DNS servers for IPv4 and (optionally) IPv6 |
| 122 |
- if len(GetNameservers(cleanedResolvConf)) == 0 {
|
|
| 122 |
+ if len(GetNameservers(cleanedResolvConf, netutils.IP)) == 0 {
|
|
| 123 | 123 |
logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers : %v", defaultIPv4Dns)
|
| 124 | 124 |
dns := defaultIPv4Dns |
| 125 | 125 |
if ipv6Enabled {
|
| ... | ... |
@@ -151,10 +154,17 @@ func getLines(input []byte, commentMarker []byte) [][]byte {
|
| 151 | 151 |
} |
| 152 | 152 |
|
| 153 | 153 |
// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf |
| 154 |
-func GetNameservers(resolvConf []byte) []string {
|
|
| 154 |
+func GetNameservers(resolvConf []byte, kind int) []string {
|
|
| 155 | 155 |
nameservers := []string{}
|
| 156 | 156 |
for _, line := range getLines(resolvConf, []byte("#")) {
|
| 157 |
- var ns = nsRegexp.FindSubmatch(line) |
|
| 157 |
+ var ns [][]byte |
|
| 158 |
+ if kind == netutils.IP {
|
|
| 159 |
+ ns = nsRegexp.FindSubmatch(line) |
|
| 160 |
+ } else if kind == netutils.IPv4 {
|
|
| 161 |
+ ns = nsIPv4Regexpmatch.FindSubmatch(line) |
|
| 162 |
+ } else if kind == netutils.IPv6 {
|
|
| 163 |
+ ns = nsIPv6Regexpmatch.FindSubmatch(line) |
|
| 164 |
+ } |
|
| 158 | 165 |
if len(ns) > 0 {
|
| 159 | 166 |
nameservers = append(nameservers, string(ns[1])) |
| 160 | 167 |
} |
| ... | ... |
@@ -167,7 +177,7 @@ func GetNameservers(resolvConf []byte) []string {
|
| 167 | 167 |
// This function's output is intended for net.ParseCIDR |
| 168 | 168 |
func GetNameserversAsCIDR(resolvConf []byte) []string {
|
| 169 | 169 |
nameservers := []string{}
|
| 170 |
- for _, nameserver := range GetNameservers(resolvConf) {
|
|
| 170 |
+ for _, nameserver := range GetNameservers(resolvConf, netutils.IP) {
|
|
| 171 | 171 |
nameservers = append(nameservers, nameserver+"/32") |
| 172 | 172 |
} |
| 173 | 173 |
return nameservers |
| ... | ... |
@@ -36,6 +36,7 @@ const ( |
| 36 | 36 |
ptrIPv4domain = ".in-addr.arpa." |
| 37 | 37 |
ptrIPv6domain = ".ip6.arpa." |
| 38 | 38 |
respTTL = 1800 |
| 39 |
+ maxExtDNS = 3 //max number of external servers to try |
|
| 39 | 40 |
) |
| 40 | 41 |
|
| 41 | 42 |
// resolver implements the Resolver interface |
| ... | ... |
@@ -188,15 +189,24 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
|
| 188 | 188 |
if len(r.extDNS) == 0 {
|
| 189 | 189 |
return |
| 190 | 190 |
} |
| 191 |
- log.Debugf("Querying ext dns %s for %s[%d]", r.extDNS[0], name, query.Question[0].Qtype)
|
|
| 192 | 191 |
|
| 193 |
- c := &dns.Client{Net: "udp"}
|
|
| 194 |
- addr := fmt.Sprintf("%s:%d", r.extDNS[0], 53)
|
|
| 192 |
+ num := maxExtDNS |
|
| 193 |
+ if len(r.extDNS) < maxExtDNS {
|
|
| 194 |
+ num = len(r.extDNS) |
|
| 195 |
+ } |
|
| 196 |
+ for i := 0; i < num; i++ {
|
|
| 197 |
+ log.Debugf("Querying ext dns %s for %s[%d]", r.extDNS[i], name, query.Question[0].Qtype)
|
|
| 195 | 198 |
|
| 196 |
- // TODO: iterate over avilable servers in case of error |
|
| 197 |
- resp, _, err = c.Exchange(query, addr) |
|
| 198 |
- if err != nil {
|
|
| 199 |
+ c := &dns.Client{Net: "udp"}
|
|
| 200 |
+ addr := fmt.Sprintf("%s:%d", r.extDNS[i], 53)
|
|
| 201 |
+ |
|
| 202 |
+ resp, _, err = c.Exchange(query, addr) |
|
| 203 |
+ if err == nil {
|
|
| 204 |
+ break |
|
| 205 |
+ } |
|
| 199 | 206 |
log.Errorf("external resolution failed, %s", err)
|
| 207 |
+ } |
|
| 208 |
+ if resp == nil {
|
|
| 200 | 209 |
return |
| 201 | 210 |
} |
| 202 | 211 |
} |
| ... | ... |
@@ -14,6 +14,7 @@ import ( |
| 14 | 14 |
|
| 15 | 15 |
log "github.com/Sirupsen/logrus" |
| 16 | 16 |
"github.com/docker/libnetwork/etchosts" |
| 17 |
+ "github.com/docker/libnetwork/netutils" |
|
| 17 | 18 |
"github.com/docker/libnetwork/osl" |
| 18 | 19 |
"github.com/docker/libnetwork/resolvconf" |
| 19 | 20 |
"github.com/docker/libnetwork/types" |
| ... | ... |
@@ -322,11 +323,15 @@ func (sb *sandbox) startResolver() {
|
| 322 | 322 |
} |
| 323 | 323 |
}() |
| 324 | 324 |
|
| 325 |
- sb.rebuildDNS() |
|
| 325 |
+ err = sb.rebuildDNS() |
|
| 326 |
+ if err != nil {
|
|
| 327 |
+ log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
|
|
| 328 |
+ return |
|
| 329 |
+ } |
|
| 326 | 330 |
sb.resolver.SetExtServers(sb.extDNS) |
| 327 | 331 |
|
| 328 | 332 |
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc()) |
| 329 |
- if err := sb.resolver.Start(); err != nil {
|
|
| 333 |
+ if err = sb.resolver.Start(); err != nil {
|
|
| 330 | 334 |
log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
|
| 331 | 335 |
} |
| 332 | 336 |
}) |
| ... | ... |
@@ -427,23 +432,51 @@ func (sb *sandbox) ResolveIP(ip string) string {
|
| 427 | 427 |
|
| 428 | 428 |
func (sb *sandbox) ResolveName(name string) net.IP {
|
| 429 | 429 |
var ip net.IP |
| 430 |
- parts := strings.Split(name, ".") |
|
| 431 |
- log.Debugf("To resolve %v", parts)
|
|
| 432 | 430 |
|
| 433 |
- reqName := parts[0] |
|
| 434 |
- networkName := "" |
|
| 435 |
- if len(parts) > 1 {
|
|
| 436 |
- networkName = parts[1] |
|
| 431 |
+ // Embedded server owns the docker network domain. Resolution should work |
|
| 432 |
+ // for both container_name and container_name.network_name |
|
| 433 |
+ // We allow '.' in service name and network name. For a name a.b.c.d the |
|
| 434 |
+ // following have to tried; |
|
| 435 |
+ // {a.b.c.d in the networks container is connected to}
|
|
| 436 |
+ // {a.b.c in network d},
|
|
| 437 |
+ // {a.b in network c.d},
|
|
| 438 |
+ // {a in network b.c.d},
|
|
| 439 |
+ |
|
| 440 |
+ name = strings.TrimSuffix(name, ".") |
|
| 441 |
+ reqName := []string{name}
|
|
| 442 |
+ networkName := []string{""}
|
|
| 443 |
+ |
|
| 444 |
+ if strings.Contains(name, ".") {
|
|
| 445 |
+ var i int |
|
| 446 |
+ dup := name |
|
| 447 |
+ for {
|
|
| 448 |
+ if i = strings.LastIndex(dup, "."); i == -1 {
|
|
| 449 |
+ break |
|
| 450 |
+ } |
|
| 451 |
+ networkName = append(networkName, name[i+1:]) |
|
| 452 |
+ reqName = append(reqName, name[:i]) |
|
| 453 |
+ |
|
| 454 |
+ dup = dup[:i] |
|
| 455 |
+ } |
|
| 437 | 456 |
} |
| 457 |
+ |
|
| 438 | 458 |
epList := sb.getConnectedEndpoints() |
| 439 |
- // First check for local container alias |
|
| 440 |
- ip = sb.resolveName(reqName, networkName, epList, true) |
|
| 441 |
- if ip != nil {
|
|
| 442 |
- return ip |
|
| 443 |
- } |
|
| 459 |
+ for i := 0; i < len(reqName); i++ {
|
|
| 460 |
+ log.Debugf("To resolve: %v in %v", reqName[i], networkName[i])
|
|
| 444 | 461 |
|
| 445 |
- // Resolve the actual container name |
|
| 446 |
- return sb.resolveName(reqName, networkName, epList, false) |
|
| 462 |
+ // First check for local container alias |
|
| 463 |
+ ip = sb.resolveName(reqName[i], networkName[i], epList, true) |
|
| 464 |
+ if ip != nil {
|
|
| 465 |
+ return ip |
|
| 466 |
+ } |
|
| 467 |
+ |
|
| 468 |
+ // Resolve the actual container name |
|
| 469 |
+ ip = sb.resolveName(reqName[i], networkName[i], epList, false) |
|
| 470 |
+ if ip != nil {
|
|
| 471 |
+ return ip |
|
| 472 |
+ } |
|
| 473 |
+ } |
|
| 474 |
+ return nil |
|
| 447 | 475 |
} |
| 448 | 476 |
|
| 449 | 477 |
func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) net.IP {
|
| ... | ... |
@@ -823,7 +856,7 @@ func (sb *sandbox) setupDNS() error {
|
| 823 | 823 |
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
|
| 824 | 824 |
var ( |
| 825 | 825 |
err error |
| 826 |
- dnsList = resolvconf.GetNameservers(currRC.Content) |
|
| 826 |
+ dnsList = resolvconf.GetNameservers(currRC.Content, netutils.IP) |
|
| 827 | 827 |
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content) |
| 828 | 828 |
dnsOptionsList = resolvconf.GetOptions(currRC.Content) |
| 829 | 829 |
) |
| ... | ... |
@@ -865,6 +898,11 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
|
| 865 | 865 |
hashFile = sb.config.resolvConfHashFile |
| 866 | 866 |
) |
| 867 | 867 |
|
| 868 |
+ // This is for the host mode networking |
|
| 869 |
+ if sb.config.originResolvConfPath != "" {
|
|
| 870 |
+ return nil |
|
| 871 |
+ } |
|
| 872 |
+ |
|
| 868 | 873 |
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
|
| 869 | 874 |
return nil |
| 870 | 875 |
} |
| ... | ... |
@@ -897,36 +935,21 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
|
| 897 | 897 |
if err != nil {
|
| 898 | 898 |
return err |
| 899 | 899 |
} |
| 900 |
- |
|
| 901 |
- // for atomic updates to these files, use temporary files with os.Rename: |
|
| 902 |
- dir := path.Dir(sb.config.resolvConfPath) |
|
| 903 |
- tmpHashFile, err := ioutil.TempFile(dir, "hash") |
|
| 904 |
- if err != nil {
|
|
| 905 |
- return err |
|
| 906 |
- } |
|
| 907 |
- tmpResolvFile, err := ioutil.TempFile(dir, "resolv") |
|
| 900 |
+ err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644) |
|
| 908 | 901 |
if err != nil {
|
| 909 | 902 |
return err |
| 910 | 903 |
} |
| 911 | 904 |
|
| 912 |
- // Change the perms to filePerm (0644) since ioutil.TempFile creates it by default as 0600 |
|
| 913 |
- if err := os.Chmod(tmpResolvFile.Name(), filePerm); err != nil {
|
|
| 905 |
+ // write the new hash in a temp file and rename it to make the update atomic |
|
| 906 |
+ dir := path.Dir(sb.config.resolvConfPath) |
|
| 907 |
+ tmpHashFile, err := ioutil.TempFile(dir, "hash") |
|
| 908 |
+ if err != nil {
|
|
| 914 | 909 |
return err |
| 915 | 910 |
} |
| 916 |
- |
|
| 917 |
- // write the updates to the temp files |
|
| 918 | 911 |
if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
|
| 919 | 912 |
return err |
| 920 | 913 |
} |
| 921 |
- if err = ioutil.WriteFile(tmpResolvFile.Name(), newRC.Content, filePerm); err != nil {
|
|
| 922 |
- return err |
|
| 923 |
- } |
|
| 924 |
- |
|
| 925 |
- // rename the temp files for atomic replace |
|
| 926 |
- if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
|
|
| 927 |
- return err |
|
| 928 |
- } |
|
| 929 |
- return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath) |
|
| 914 |
+ return os.Rename(tmpHashFile.Name(), hashFile) |
|
| 930 | 915 |
} |
| 931 | 916 |
|
| 932 | 917 |
// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's |
| ... | ... |
@@ -941,7 +964,8 @@ func (sb *sandbox) rebuildDNS() error {
|
| 941 | 941 |
} |
| 942 | 942 |
|
| 943 | 943 |
// localhost entries have already been filtered out from the list |
| 944 |
- sb.extDNS = resolvconf.GetNameservers(currRC.Content) |
|
| 944 |
+ // retain only the v4 servers in sb for forwarding the DNS queries |
|
| 945 |
+ sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4) |
|
| 945 | 946 |
|
| 946 | 947 |
var ( |
| 947 | 948 |
dnsList = []string{sb.resolver.NameServer()}
|
| ... | ... |
@@ -949,26 +973,14 @@ func (sb *sandbox) rebuildDNS() error {
|
| 949 | 949 |
dnsSearchList = resolvconf.GetSearchDomains(currRC.Content) |
| 950 | 950 |
) |
| 951 | 951 |
|
| 952 |
+ // external v6 DNS servers has to be listed in resolv.conf |
|
| 953 |
+ dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...) |
|
| 954 |
+ |
|
| 952 | 955 |
// Resolver returns the options in the format resolv.conf expects |
| 953 | 956 |
dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...) |
| 954 | 957 |
|
| 955 |
- dir := path.Dir(sb.config.resolvConfPath) |
|
| 956 |
- tmpResolvFile, err := ioutil.TempFile(dir, "resolv") |
|
| 957 |
- if err != nil {
|
|
| 958 |
- return err |
|
| 959 |
- } |
|
| 960 |
- |
|
| 961 |
- // Change the perms to filePerm (0644) since ioutil.TempFile creates it by default as 0600 |
|
| 962 |
- if err := os.Chmod(tmpResolvFile.Name(), filePerm); err != nil {
|
|
| 963 |
- return err |
|
| 964 |
- } |
|
| 965 |
- |
|
| 966 |
- _, err = resolvconf.Build(tmpResolvFile.Name(), dnsList, dnsSearchList, dnsOptionsList) |
|
| 967 |
- if err != nil {
|
|
| 968 |
- return err |
|
| 969 |
- } |
|
| 970 |
- |
|
| 971 |
- return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath) |
|
| 958 |
+ _, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList) |
|
| 959 |
+ return err |
|
| 972 | 960 |
} |
| 973 | 961 |
|
| 974 | 962 |
// joinLeaveStart waits to ensure there are no joins or leaves in progress and |