Merge pull request #3600 from hashicorp/support-go-sockaddr-for-dns-recursors

DNS recursors can be added through go-sockaddr templates. Entries
are deduplicated while the order is maintained.

Originally proposed by @taylorchu

See #2932
pull/3607/merge
Frank Schroeder 2017-10-23 10:45:36 +02:00
commit 81917ee675
No known key found for this signature in database
GPG Key ID: 4D65C6EAEC87DECD
3 changed files with 58 additions and 12 deletions

View File

@ -387,6 +387,26 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
}
}
// expand dns recursors
uniq := map[string]bool{}
dnsRecursors := []string{}
for _, r := range c.DNSRecursors {
x, err := template.Parse(r)
if err != nil {
return RuntimeConfig{}, fmt.Errorf("Invalid DNS recursor template %q: %s", r, err)
}
for _, addr := range strings.Fields(x) {
if strings.HasPrefix(addr, "unix://") {
return RuntimeConfig{}, fmt.Errorf("DNS Recursors cannot be unix sockets: %s", addr)
}
if uniq[addr] {
continue
}
uniq[addr] = true
dnsRecursors = append(dnsRecursors, addr)
}
}
// Create the default set of tagged addresses.
if c.TaggedAddresses == nil {
c.TaggedAddresses = make(map[string]string)
@ -525,7 +545,7 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
DNSOnlyPassing: b.boolVal(c.DNS.OnlyPassing),
DNSPort: dnsPort,
DNSRecursorTimeout: b.durationVal("recursor_timeout", c.DNS.RecursorTimeout),
DNSRecursors: c.DNSRecursors,
DNSRecursors: dnsRecursors,
DNSServiceTTL: dnsServiceTTL,
DNSUDPAnswerLimit: b.intVal(c.DNS.UDPAnswerLimit),
@ -706,6 +726,11 @@ func (b *Builder) Validate(rt RuntimeConfig) error {
return fmt.Errorf("DNS address cannot be a unix socket")
}
}
for _, a := range rt.DNSRecursors {
if ipaddr.IsAny(a) {
return fmt.Errorf("DNS recursor address cannot be 0.0.0.0, :: or [::]")
}
}
if rt.Bootstrap && !rt.ServerMode {
return fmt.Errorf("'bootstrap = true' requires 'server = true'")
}

View File

@ -445,12 +445,12 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
{
desc: "-recursor",
flags: []string{
`-recursor=a`,
`-recursor=b`,
`-recursor=1.2.3.4`,
`-recursor=5.6.7.8`,
`-data-dir=` + dataDir,
},
patch: func(rt *RuntimeConfig) {
rt.DNSRecursors = []string{"a", "b"}
rt.DNSRecursors = []string{"1.2.3.4", "5.6.7.8"}
rt.DataDir = dataDir
},
},
@ -988,6 +988,16 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
rt.DataDir = dataDir
},
},
{
desc: "dns recursor templates with deduplication",
flags: []string{`-data-dir=` + dataDir},
json: []string{`{ "recursors": [ "{{ printf \"5.6.7.8:9999\" }}", "{{ printf \"1.2.3.4\" }}", "{{ printf \"5.6.7.8:9999\" }}" ] }`},
hcl: []string{`recursors = [ "{{ printf \"5.6.7.8:9999\" }}", "{{ printf \"1.2.3.4\" }}", "{{ printf \"5.6.7.8:9999\" }}" ] `},
patch: func(rt *RuntimeConfig) {
rt.DNSRecursors = []string{"5.6.7.8:9999", "1.2.3.4"}
rt.DataDir = dataDir
},
},
// ------------------------------------------------------------
// precedence rules
@ -1047,7 +1057,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
"bootstrap_expect": 3,
"datacenter":"a",
"node_meta": {"a":"b"},
"recursors":["a", "b"],
"recursors":["1.2.3.5", "5.6.7.9"],
"serf_lan": "a",
"serf_wan": "a",
"start_join":["a", "b"]
@ -1061,7 +1071,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
bootstrap_expect = 3
datacenter = "a"
node_meta = { "a" = "b" }
recursors = ["a", "b"]
recursors = ["1.2.3.5", "5.6.7.9"]
serf_lan = "a"
serf_wan = "a"
start_join = ["a", "b"]
@ -1076,7 +1086,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
`-data-dir=` + dataDir,
`-join`, `c`, `-join=d`,
`-node-meta=c:d`,
`-recursor`, `c`, `-recursor=d`,
`-recursor`, `1.2.3.6`, `-recursor=5.6.7.10`,
`-serf-lan-bind=3.3.3.3`,
`-serf-wan-bind=4.4.4.4`,
},
@ -1087,7 +1097,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
rt.SerfAdvertiseAddrLAN = tcpAddr("1.1.1.1:8301")
rt.SerfAdvertiseAddrWAN = tcpAddr("2.2.2.2:8302")
rt.Datacenter = "b"
rt.DNSRecursors = []string{"c", "d", "a", "b"}
rt.DNSRecursors = []string{"1.2.3.6", "5.6.7.10", "1.2.3.5", "5.6.7.9"}
rt.NodeMeta = map[string]string{"c": "d"}
rt.SerfBindAddrLAN = tcpAddr("3.3.3.3:8301")
rt.SerfBindAddrWAN = tcpAddr("4.4.4.4:8302")
@ -1453,6 +1463,15 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
hcl: []string{`advertise_addr_wan = "::"`},
err: "Advertise WAN address cannot be 0.0.0.0, :: or [::]",
},
{
desc: "recursors any",
flags: []string{
`-data-dir=` + dataDir,
},
json: []string{`{ "recursors": ["::"] }`},
hcl: []string{`recursors = ["::"]`},
err: "DNS recursor address cannot be 0.0.0.0, :: or [::]",
},
{
desc: "dns_config.udp_answer_limit invalid",
flags: []string{
@ -2175,7 +2194,7 @@ func TestFullConfig(t *testing.T) {
"raft_protocol": 19016,
"reconnect_timeout": "23739s",
"reconnect_timeout_wan": "26694s",
"recursors": [ "FtFhoUHl", "UYkwck1k" ],
"recursors": [ "63.38.39.58", "92.49.18.18" ],
"rejoin_after_leave": true,
"retry_interval": "8067s",
"retry_interval_wan": "28866s",
@ -2609,7 +2628,7 @@ func TestFullConfig(t *testing.T) {
raft_protocol = 19016
reconnect_timeout = "23739s"
reconnect_timeout_wan = "26694s"
recursors = [ "FtFhoUHl", "UYkwck1k" ]
recursors = [ "63.38.39.58", "92.49.18.18" ]
rejoin_after_leave = true
retry_interval = "8067s"
retry_interval_wan = "28866s"
@ -3122,7 +3141,7 @@ func TestFullConfig(t *testing.T) {
DNSOnlyPassing: true,
DNSPort: 7001,
DNSRecursorTimeout: 4427 * time.Second,
DNSRecursors: []string{"FtFhoUHl", "UYkwck1k"},
DNSRecursors: []string{"63.38.39.58", "92.49.18.18"},
DNSServiceTTL: map[string]time.Duration{"*": 32030 * time.Second},
DNSUDPAnswerLimit: 29909,
DataDir: dataDir,

View File

@ -1036,7 +1036,9 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
* <a name="recursors"></a><a href="#recursors">`recursors`</a> This flag provides addresses of
upstream DNS servers that are used to recursively resolve queries if they are not inside the service
domain for Consul. For example, a node can use Consul directly as a DNS server, and if the record is
outside of the "consul." domain, the query will be resolved upstream.
outside of the "consul." domain, the query will be resolved upstream. As of Consul 1.0.1 recursors
can be provided as ip addresses or as go-sockaddr templates. IP addresses are resolved in order,
and duplicates are ignored.
* <a name="rejoin_after_leave"></a><a href="#rejoin_after_leave">`rejoin_after_leave`</a> Equivalent
to the [`-rejoin` command-line flag](#_rejoin).