瀏覽代碼

Merge pull request #886 from sanimej/v6

Retain V6 DNS server in resolv.conf; use only V4 servers for fallback
aboch 9 年之前
父節點
當前提交
f9a0bbebee

+ 1 - 1
libnetwork/libnetwork_test.go

@@ -1706,7 +1706,7 @@ func TestEnableIPv6(t *testing.T) {
 	}
 
 	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
-	expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n")
+	expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n")
 	//take a copy of resolv.conf for restoring after test completes
 	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
 	if err != nil {

+ 7 - 0
libnetwork/netutils/utils.go

@@ -14,6 +14,13 @@ import (
 	"github.com/docker/libnetwork/types"
 )
 
+// constants for the IP address type
+const (
+	IP = iota // IPv4 and IPv6
+	IPv4
+	IPv6
+)
+
 var (
 	// ErrNetworkOverlapsWithNameservers preformatted error
 	ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")

+ 14 - 4
libnetwork/resolvconf/resolvconf.go

@@ -10,6 +10,7 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/resolvconf/dns"
 )
 
@@ -29,6 +30,8 @@ var (
 	localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`)
 	nsIPv6Regexp      = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
 	nsRegexp          = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
+	nsIPv6Regexpmatch = regexp.MustCompile(`^\s*nameserver\s*((` + ipv6Address + `))\s*$`)
+	nsIPv4Regexpmatch = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `))\s*$`)
 	searchRegexp      = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
 	optionsRegexp     = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`)
 )
@@ -119,7 +122,7 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) {
 	}
 	// if the resulting resolvConf has no more nameservers defined, add appropriate
 	// default DNS servers for IPv4 and (optionally) IPv6
-	if len(GetNameservers(cleanedResolvConf)) == 0 {
+	if len(GetNameservers(cleanedResolvConf, netutils.IP)) == 0 {
 		logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers : %v", defaultIPv4Dns)
 		dns := defaultIPv4Dns
 		if ipv6Enabled {
@@ -151,10 +154,17 @@ func getLines(input []byte, commentMarker []byte) [][]byte {
 }
 
 // GetNameservers returns nameservers (if any) listed in /etc/resolv.conf
-func GetNameservers(resolvConf []byte) []string {
+func GetNameservers(resolvConf []byte, kind int) []string {
 	nameservers := []string{}
 	for _, line := range getLines(resolvConf, []byte("#")) {
-		var ns = nsRegexp.FindSubmatch(line)
+		var ns [][]byte
+		if kind == netutils.IP {
+			ns = nsRegexp.FindSubmatch(line)
+		} else if kind == netutils.IPv4 {
+			ns = nsIPv4Regexpmatch.FindSubmatch(line)
+		} else if kind == netutils.IPv6 {
+			ns = nsIPv6Regexpmatch.FindSubmatch(line)
+		}
 		if len(ns) > 0 {
 			nameservers = append(nameservers, string(ns[1]))
 		}
@@ -167,7 +177,7 @@ func GetNameservers(resolvConf []byte) []string {
 // This function's output is intended for net.ParseCIDR
 func GetNameserversAsCIDR(resolvConf []byte) []string {
 	nameservers := []string{}
-	for _, nameserver := range GetNameservers(resolvConf) {
+	for _, nameserver := range GetNameservers(resolvConf, netutils.IP) {
 		nameservers = append(nameservers, nameserver+"/32")
 	}
 	return nameservers

+ 2 - 1
libnetwork/resolvconf/resolvconf_test.go

@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/libnetwork/netutils"
 	_ "github.com/docker/libnetwork/testutils"
 )
 
@@ -48,7 +49,7 @@ nameserver 1.2.3.4
 		`search example.com
 nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4"},
 	} {
-		test := GetNameservers([]byte(resolv))
+		test := GetNameservers([]byte(resolv), netutils.IP)
 		if !strSlicesEqual(test, result) {
 			t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv)
 		}

+ 16 - 6
libnetwork/resolver.go

@@ -36,6 +36,7 @@ const (
 	ptrIPv4domain = ".in-addr.arpa."
 	ptrIPv6domain = ".ip6.arpa."
 	respTTL       = 1800
+	maxExtDNS     = 3 //max number of external servers to try
 )
 
 // resolver implements the Resolver interface
@@ -188,15 +189,24 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 		if len(r.extDNS) == 0 {
 			return
 		}
-		log.Debugf("Querying ext dns %s for %s[%d]", r.extDNS[0], name, query.Question[0].Qtype)
 
-		c := &dns.Client{Net: "udp"}
-		addr := fmt.Sprintf("%s:%d", r.extDNS[0], 53)
+		num := maxExtDNS
+		if len(r.extDNS) < maxExtDNS {
+			num = len(r.extDNS)
+		}
+		for i := 0; i < num; i++ {
+			log.Debugf("Querying ext dns %s for %s[%d]", r.extDNS[i], name, query.Question[0].Qtype)
 
-		// TODO: iterate over avilable servers in case of error
-		resp, _, err = c.Exchange(query, addr)
-		if err != nil {
+			c := &dns.Client{Net: "udp"}
+			addr := fmt.Sprintf("%s:%d", r.extDNS[i], 53)
+
+			resp, _, err = c.Exchange(query, addr)
+			if err == nil {
+				break
+			}
 			log.Errorf("external resolution failed, %s", err)
+		}
+		if resp == nil {
 			return
 		}
 	}

+ 7 - 2
libnetwork/sandbox.go

@@ -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"
@@ -827,7 +828,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)
 		)
@@ -935,7 +936,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()}
@@ -943,6 +945,9 @@ 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()...)