Retain V6 DNS server in resolv.conf; use only V4 servers for fallback

Signed-off-by: Santhosh Manohar <santhosh@docker.com>
This commit is contained in:
Santhosh Manohar 2016-01-18 04:07:19 -08:00
parent a02c73c352
commit 30ef9bcf4a
6 changed files with 47 additions and 14 deletions

View file

@ -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 {

View file

@ -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")

View file

@ -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

View file

@ -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)
}

View file

@ -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)
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)
c := &dns.Client{Net: "udp"}
addr := fmt.Sprintf("%s:%d", r.extDNS[0], 53)
addr := fmt.Sprintf("%s:%d", r.extDNS[i], 53)
// TODO: iterate over avilable servers in case of error
resp, _, err = c.Exchange(query, addr)
if err != nil {
if err == nil {
break
}
log.Errorf("external resolution failed, %s", err)
}
if resp == nil {
return
}
}

View file

@ -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()...)