mirror of https://github.com/status-im/consul.git
Add multiple recursor definition support
This commit is contained in:
parent
38448015e1
commit
35b006d884
|
@ -302,7 +302,7 @@ func (c *Command) setupAgent(config *Config, logOutput io.Writer, logWriter *log
|
||||||
}
|
}
|
||||||
|
|
||||||
server, err := NewDNSServer(agent, &config.DNSConfig, logOutput,
|
server, err := NewDNSServer(agent, &config.DNSConfig, logOutput,
|
||||||
config.Domain, dnsAddr.String(), config.DNSRecursor)
|
config.Domain, dnsAddr.String(), config.DNSRecursors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
agent.Shutdown()
|
agent.Shutdown()
|
||||||
c.Ui.Error(fmt.Sprintf("Error starting dns server: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error starting dns server: %s", err))
|
||||||
|
|
|
@ -97,9 +97,9 @@ type Config struct {
|
||||||
// DataDir is the directory to store our state in
|
// DataDir is the directory to store our state in
|
||||||
DataDir string `mapstructure:"data_dir"`
|
DataDir string `mapstructure:"data_dir"`
|
||||||
|
|
||||||
// DNSRecursor can be set to allow the DNS server to recursively
|
// DNSRecursors can be set to allow the DNS servers to recursively
|
||||||
// resolve non-consul domains
|
// resolve non-consul domains
|
||||||
DNSRecursor string `mapstructure:"recursor"`
|
DNSRecursors []string `mapstructure:"recursors"`
|
||||||
|
|
||||||
// DNS configuration
|
// DNS configuration
|
||||||
DNSConfig DNSConfig `mapstructure:"dns_config"`
|
DNSConfig DNSConfig `mapstructure:"dns_config"`
|
||||||
|
@ -623,9 +623,12 @@ func MergeConfig(a, b *Config) *Config {
|
||||||
if b.DataDir != "" {
|
if b.DataDir != "" {
|
||||||
result.DataDir = b.DataDir
|
result.DataDir = b.DataDir
|
||||||
}
|
}
|
||||||
if b.DNSRecursor != "" {
|
|
||||||
result.DNSRecursor = b.DNSRecursor
|
// Copy the dns recursors
|
||||||
}
|
result.DNSRecursors = make([]string, 0, len(a.DNSRecursors)+len(b.DNSRecursors))
|
||||||
|
result.DNSRecursors = append(result.DNSRecursors, a.DNSRecursors...)
|
||||||
|
result.DNSRecursors = append(result.DNSRecursors, b.DNSRecursors...)
|
||||||
|
|
||||||
if b.Domain != "" {
|
if b.Domain != "" {
|
||||||
result.Domain = b.Domain
|
result.Domain = b.Domain
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNS setup
|
// DNS setup
|
||||||
input = `{"ports": {"dns": 8500}, "recursor": "8.8.8.8", "domain": "foobar"}`
|
input = `{"ports": {"dns": 8500}, "recursor": ["8.8.8.8","8.8.4.4"], "domain": "foobar"}`
|
||||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
|
@ -119,7 +119,13 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.DNSRecursor != "8.8.8.8" {
|
if len(config.DNSRecursors) != 2 {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
|
if config.DNSRecursors[0] != "8.8.8.8" {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
|
if config.DNSRecursors[1] != "8.8.4.4" {
|
||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,7 +797,6 @@ func TestMergeConfig(t *testing.T) {
|
||||||
BootstrapExpect: 0,
|
BootstrapExpect: 0,
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
DataDir: "/tmp/foo",
|
DataDir: "/tmp/foo",
|
||||||
DNSRecursor: "127.0.0.1:1001",
|
|
||||||
Domain: "basic",
|
Domain: "basic",
|
||||||
LogLevel: "debug",
|
LogLevel: "debug",
|
||||||
NodeName: "foo",
|
NodeName: "foo",
|
||||||
|
@ -811,7 +816,7 @@ func TestMergeConfig(t *testing.T) {
|
||||||
BootstrapExpect: 3,
|
BootstrapExpect: 3,
|
||||||
Datacenter: "dc2",
|
Datacenter: "dc2",
|
||||||
DataDir: "/tmp/bar",
|
DataDir: "/tmp/bar",
|
||||||
DNSRecursor: "127.0.0.2:1001",
|
DNSRecursors: []string{"127.0.0.2:1001"},
|
||||||
DNSConfig: DNSConfig{
|
DNSConfig: DNSConfig{
|
||||||
NodeTTL: 10 * time.Second,
|
NodeTTL: 10 * time.Second,
|
||||||
ServiceTTL: map[string]time.Duration{
|
ServiceTTL: map[string]time.Duration{
|
||||||
|
|
|
@ -28,12 +28,12 @@ type DNSServer struct {
|
||||||
dnsServer *dns.Server
|
dnsServer *dns.Server
|
||||||
dnsServerTCP *dns.Server
|
dnsServerTCP *dns.Server
|
||||||
domain string
|
domain string
|
||||||
recursor string
|
recursors []string
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDNSServer starts a new DNS server to provide an agent interface
|
// NewDNSServer starts a new DNS server to provide an agent interface
|
||||||
func NewDNSServer(agent *Agent, config *DNSConfig, logOutput io.Writer, domain, bind, recursor string) (*DNSServer, error) {
|
func NewDNSServer(agent *Agent, config *DNSConfig, logOutput io.Writer, domain string, bind string, recursors []string) (*DNSServer, error) {
|
||||||
// Make sure domain is FQDN
|
// Make sure domain is FQDN
|
||||||
domain = dns.Fqdn(domain)
|
domain = dns.Fqdn(domain)
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func NewDNSServer(agent *Agent, config *DNSConfig, logOutput io.Writer, domain,
|
||||||
dnsServer: server,
|
dnsServer: server,
|
||||||
dnsServerTCP: serverTCP,
|
dnsServerTCP: serverTCP,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
recursor: recursor,
|
recursors: recursors,
|
||||||
logger: log.New(logOutput, "", log.LstdFlags),
|
logger: log.New(logOutput, "", log.LstdFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,12 +70,19 @@ func NewDNSServer(agent *Agent, config *DNSConfig, logOutput io.Writer, domain,
|
||||||
if domain != consulDomain {
|
if domain != consulDomain {
|
||||||
mux.HandleFunc(consulDomain, srv.handleTest)
|
mux.HandleFunc(consulDomain, srv.handleTest)
|
||||||
}
|
}
|
||||||
if recursor != "" {
|
if len(recursors) > 0 {
|
||||||
recursor, err := recursorAddr(recursor)
|
validatedRecursors := []string{}
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Invalid recursor address: %v", err)
|
for _, recursor := range recursors {
|
||||||
|
recursor, err := recursorAddr(recursor)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid recursor address: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
validatedRecursors = append(validatedRecursors, recursor)
|
||||||
}
|
}
|
||||||
srv.recursor = recursor
|
|
||||||
|
srv.recursors = validatedRecursors
|
||||||
mux.HandleFunc(".", srv.handleRecurse)
|
mux.HandleFunc(".", srv.handleRecurse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +185,7 @@ func (d *DNSServer) handleQuery(resp dns.ResponseWriter, req *dns.Msg) {
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetReply(req)
|
m.SetReply(req)
|
||||||
m.Authoritative = true
|
m.Authoritative = true
|
||||||
m.RecursionAvailable = (d.recursor != "")
|
m.RecursionAvailable = (len(d.recursors) > 0)
|
||||||
|
|
||||||
// Only add the SOA if requested
|
// Only add the SOA if requested
|
||||||
if req.Question[0].Qtype == dns.TypeSOA {
|
if req.Question[0].Qtype == dns.TypeSOA {
|
||||||
|
@ -587,30 +594,34 @@ func (d *DNSServer) handleRecurse(resp dns.ResponseWriter, req *dns.Msg) {
|
||||||
|
|
||||||
// Recursively resolve
|
// Recursively resolve
|
||||||
c := &dns.Client{Net: network}
|
c := &dns.Client{Net: network}
|
||||||
r, rtt, err := c.Exchange(req, d.recursor)
|
for i,recursor := range d.recursors {
|
||||||
|
r, rtt, err := c.Exchange(req, recursor)
|
||||||
|
|
||||||
// On failure, return a SERVFAIL message
|
if i < len(d.recursors) && err != nil {
|
||||||
if err != nil {
|
continue
|
||||||
d.logger.Printf("[ERR] dns: recurse failed: %v", err)
|
} else if err != nil {
|
||||||
m := &dns.Msg{}
|
// On all of failure, return a SERVFAIL message
|
||||||
m.SetReply(req)
|
d.logger.Printf("[ERR] dns: recurse failed: %v", err)
|
||||||
m.RecursionAvailable = true
|
m := &dns.Msg{}
|
||||||
m.SetRcode(req, dns.RcodeServerFailure)
|
m.SetReply(req)
|
||||||
resp.WriteMsg(m)
|
m.RecursionAvailable = true
|
||||||
return
|
m.SetRcode(req, dns.RcodeServerFailure)
|
||||||
}
|
resp.WriteMsg(m)
|
||||||
d.logger.Printf("[DEBUG] dns: recurse RTT for %v (%v)", q, rtt)
|
return
|
||||||
|
}
|
||||||
|
d.logger.Printf("[DEBUG] dns: recurse RTT for %v (%v)", q, rtt)
|
||||||
|
|
||||||
// Forward the response
|
// Forward the response
|
||||||
if err := resp.WriteMsg(r); err != nil {
|
if err := resp.WriteMsg(r); err != nil {
|
||||||
d.logger.Printf("[WARN] dns: failed to respond: %v", err)
|
d.logger.Printf("[WARN] dns: failed to respond: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveCNAME is used to recursively resolve CNAME records
|
// resolveCNAME is used to recursively resolve CNAME records
|
||||||
func (d *DNSServer) resolveCNAME(name string) []dns.RR {
|
func (d *DNSServer) resolveCNAME(name string) []dns.RR {
|
||||||
// Do nothing if we don't have a recursor
|
// Do nothing if we don't have a recursor
|
||||||
if d.recursor == "" {
|
if len(d.recursors) > 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,13 +631,20 @@ func (d *DNSServer) resolveCNAME(name string) []dns.RR {
|
||||||
|
|
||||||
// Make a DNS lookup request
|
// Make a DNS lookup request
|
||||||
c := &dns.Client{Net: "udp"}
|
c := &dns.Client{Net: "udp"}
|
||||||
r, rtt, err := c.Exchange(m, d.recursor)
|
for i,recursor := range d.recursors {
|
||||||
if err != nil {
|
r, rtt, err := c.Exchange(m, recursor)
|
||||||
d.logger.Printf("[ERR] dns: cname recurse failed: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
d.logger.Printf("[DEBUG] dns: cname recurse RTT for %v (%v)", name, rtt)
|
|
||||||
|
|
||||||
// Return all the answers
|
if i < len(d.recursors) && err != nil {
|
||||||
return r.Answer
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
d.logger.Printf("[ERR] dns: cname recurse failed: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d.logger.Printf("[DEBUG] dns: cname recurse RTT for %v (%v)", name, rtt)
|
||||||
|
|
||||||
|
// Return all the answers
|
||||||
|
return r.Answer
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ func makeDNSServerConfig(t *testing.T, config *DNSConfig) (string, *DNSServer) {
|
||||||
addr, _ := conf.ClientListener(conf.Addresses.DNS, conf.Ports.DNS)
|
addr, _ := conf.ClientListener(conf.Addresses.DNS, conf.Ports.DNS)
|
||||||
dir, agent := makeAgent(t, conf)
|
dir, agent := makeAgent(t, conf)
|
||||||
server, err := NewDNSServer(agent, config, agent.logOutput,
|
server, err := NewDNSServer(agent, config, agent.logOutput,
|
||||||
conf.Domain, addr.String(), "8.8.8.8:53")
|
conf.Domain, addr.String(), []string{"8.8.8.8:53"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,14 @@ provide the redis service, located in the "east-aws" datacenter,
|
||||||
with no failing health checks. It's that simple!
|
with no failing health checks. It's that simple!
|
||||||
|
|
||||||
There are a number of [configuration options](/docs/agent/options.html) that
|
There are a number of [configuration options](/docs/agent/options.html) that
|
||||||
are important for the DNS interface. They are `client_addr`, `ports.dns`, `recursor`,
|
are important for the DNS interface. They are `client_addr`, `ports.dns`, `recursors`,
|
||||||
`domain`, and `dns_config`. By default Consul will listen on 127.0.0.1:8600 for DNS queries
|
`domain`, and `dns_config`. By default Consul will listen on 127.0.0.1:8600 for DNS queries
|
||||||
in the "consul." domain, without support for DNS recursion. All queries are case-insensitive, a
|
in the "consul." domain, without support for DNS recursion. All queries are case-insensitive, a
|
||||||
name lookup for `PostgreSQL.node.dc1.consul` will find all nodes named `postgresql`, no matter of case.
|
name lookup for `PostgreSQL.node.dc1.consul` will find all nodes named `postgresql`, no matter of case.
|
||||||
|
|
||||||
There are a few ways to use the DNS interface. One option is to use a custom
|
There are a few ways to use the DNS interface. One option is to use a custom
|
||||||
DNS resolver library and point it at Consul. Another option is to set Consul
|
DNS resolver library and point it at Consul. Another option is to set Consul
|
||||||
as the DNS server for a node, and provide a `recursor` so that non-Consul queries
|
as the DNS server for a node, and provide `recursors` so that non-Consul queries
|
||||||
can also be resolved. The last method is to forward all queries for the "consul."
|
can also be resolved. The last method is to forward all queries for the "consul."
|
||||||
domain to a Consul agent from the existing DNS server. To play with the DNS server
|
domain to a Consul agent from the existing DNS server. To play with the DNS server
|
||||||
on the command line, dig can be used:
|
on the command line, dig can be used:
|
||||||
|
|
|
@ -333,7 +333,7 @@ It returns a JSON body like this:
|
||||||
"Server": true,
|
"Server": true,
|
||||||
"Datacenter": "dc1",
|
"Datacenter": "dc1",
|
||||||
"DataDir": "/tmp/consul",
|
"DataDir": "/tmp/consul",
|
||||||
"DNSRecursor": "",
|
"DNSRecursors": [],
|
||||||
"Domain": "consul.",
|
"Domain": "consul.",
|
||||||
"LogLevel": "INFO",
|
"LogLevel": "INFO",
|
||||||
"NodeName": "foobar",
|
"NodeName": "foobar",
|
||||||
|
|
|
@ -316,10 +316,10 @@ definitions support being updated during a reload.
|
||||||
|
|
||||||
* `protocol` - Equivalent to the `-protocol` command-line flag.
|
* `protocol` - Equivalent to the `-protocol` command-line flag.
|
||||||
|
|
||||||
* `recursor` - This flag provides an address of an upstream DNS server that is used to
|
* `recursors` - 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,
|
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,
|
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 using this server.
|
the query will be resolved upstream using their servers.
|
||||||
|
|
||||||
* `rejoin_after_leave` - Equivalent to the `-rejoin` command-line flag.
|
* `rejoin_after_leave` - Equivalent to the `-rejoin` command-line flag.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue