mirror of https://github.com/status-im/consul.git
Merge pull request #11348 from kbabuadze/fix-answers-alt-domain
Fix answers for alt domain
This commit is contained in:
commit
0854e1d684
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
dns: Fixed an issue where on DNS requests made with .alt_domain response was returned as .domain
|
||||||
|
```
|
50
agent/dns.go
50
agent/dns.go
|
@ -348,6 +348,20 @@ func serviceIngressDNSName(service, datacenter, domain string, entMeta *structs.
|
||||||
return serviceCanonicalDNSName(service, "ingress", datacenter, domain, entMeta)
|
return serviceCanonicalDNSName(service, "ingress", datacenter, domain, entMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getResponseDomain returns alt-domain if it is configured and request is made with alt-domain,
|
||||||
|
// respects DNS case insensitivity
|
||||||
|
func (d *DNSServer) getResponseDomain(questionName string) string {
|
||||||
|
labels := dns.SplitDomainName(questionName)
|
||||||
|
domain := d.domain
|
||||||
|
for i := len(labels) - 1; i >= 0; i-- {
|
||||||
|
currentSuffix := strings.Join(labels[i:], ".") + "."
|
||||||
|
if strings.EqualFold(currentSuffix, d.domain) || strings.EqualFold(currentSuffix, d.altDomain) {
|
||||||
|
domain = currentSuffix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domain
|
||||||
|
}
|
||||||
|
|
||||||
// handlePtr is used to handle "reverse" DNS queries
|
// handlePtr is used to handle "reverse" DNS queries
|
||||||
func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) {
|
func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) {
|
||||||
q := req.Question[0]
|
q := req.Question[0]
|
||||||
|
@ -485,14 +499,14 @@ func (d *DNSServer) handleQuery(resp dns.ResponseWriter, req *dns.Msg) {
|
||||||
|
|
||||||
switch req.Question[0].Qtype {
|
switch req.Question[0].Qtype {
|
||||||
case dns.TypeSOA:
|
case dns.TypeSOA:
|
||||||
ns, glue := d.nameservers(cfg, maxRecursionLevelDefault)
|
ns, glue := d.nameservers(req.Question[0].Name, cfg, maxRecursionLevelDefault)
|
||||||
m.Answer = append(m.Answer, d.soa(cfg, q.Name))
|
m.Answer = append(m.Answer, d.soa(cfg, q.Name))
|
||||||
m.Ns = append(m.Ns, ns...)
|
m.Ns = append(m.Ns, ns...)
|
||||||
m.Extra = append(m.Extra, glue...)
|
m.Extra = append(m.Extra, glue...)
|
||||||
m.SetRcode(req, dns.RcodeSuccess)
|
m.SetRcode(req, dns.RcodeSuccess)
|
||||||
|
|
||||||
case dns.TypeNS:
|
case dns.TypeNS:
|
||||||
ns, glue := d.nameservers(cfg, maxRecursionLevelDefault)
|
ns, glue := d.nameservers(req.Question[0].Name, cfg, maxRecursionLevelDefault)
|
||||||
m.Answer = ns
|
m.Answer = ns
|
||||||
m.Extra = glue
|
m.Extra = glue
|
||||||
m.SetRcode(req, dns.RcodeSuccess)
|
m.SetRcode(req, dns.RcodeSuccess)
|
||||||
|
@ -550,7 +564,7 @@ func (d *DNSServer) addSOA(cfg *dnsConfig, msg *dns.Msg, questionName string) {
|
||||||
// nameservers returns the names and ip addresses of up to three random servers
|
// nameservers returns the names and ip addresses of up to three random servers
|
||||||
// in the current cluster which serve as authoritative name servers for zone.
|
// in the current cluster which serve as authoritative name servers for zone.
|
||||||
|
|
||||||
func (d *DNSServer) nameservers(cfg *dnsConfig, maxRecursionLevel int) (ns []dns.RR, extra []dns.RR) {
|
func (d *DNSServer) nameservers(questionName string, cfg *dnsConfig, maxRecursionLevel int) (ns []dns.RR, extra []dns.RR) {
|
||||||
out, err := d.lookupServiceNodes(cfg, serviceLookup{
|
out, err := d.lookupServiceNodes(cfg, serviceLookup{
|
||||||
Datacenter: d.agent.config.Datacenter,
|
Datacenter: d.agent.config.Datacenter,
|
||||||
Service: structs.ConsulServiceName,
|
Service: structs.ConsulServiceName,
|
||||||
|
@ -578,14 +592,14 @@ func (d *DNSServer) nameservers(cfg *dnsConfig, maxRecursionLevel int) (ns []dns
|
||||||
d.logger.Warn("Skipping invalid node for NS records", "node", name)
|
d.logger.Warn("Skipping invalid node for NS records", "node", name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
respDomain := d.getResponseDomain(questionName)
|
||||||
fqdn := name + ".node." + dc + "." + d.domain
|
fqdn := name + ".node." + dc + "." + respDomain
|
||||||
fqdn = dns.Fqdn(strings.ToLower(fqdn))
|
fqdn = dns.Fqdn(strings.ToLower(fqdn))
|
||||||
|
|
||||||
// NS record
|
// NS record
|
||||||
nsrr := &dns.NS{
|
nsrr := &dns.NS{
|
||||||
Hdr: dns.RR_Header{
|
Hdr: dns.RR_Header{
|
||||||
Name: d.domain,
|
Name: respDomain,
|
||||||
Rrtype: dns.TypeNS,
|
Rrtype: dns.TypeNS,
|
||||||
Class: dns.ClassINET,
|
Class: dns.ClassINET,
|
||||||
Ttl: uint32(cfg.NodeTTL / time.Second),
|
Ttl: uint32(cfg.NodeTTL / time.Second),
|
||||||
|
@ -662,6 +676,9 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi
|
||||||
// have to deref to clone it so we don't modify (start from the agent's defaults)
|
// have to deref to clone it so we don't modify (start from the agent's defaults)
|
||||||
var entMeta = d.defaultEnterpriseMeta
|
var entMeta = d.defaultEnterpriseMeta
|
||||||
|
|
||||||
|
// Choose correct response domain
|
||||||
|
respDomain := d.getResponseDomain(req.Question[0].Name)
|
||||||
|
|
||||||
// Get the QName without the domain suffix
|
// Get the QName without the domain suffix
|
||||||
qName := strings.ToLower(dns.Fqdn(req.Question[0].Name))
|
qName := strings.ToLower(dns.Fqdn(req.Question[0].Name))
|
||||||
qName = d.trimDomain(qName)
|
qName = d.trimDomain(qName)
|
||||||
|
@ -833,7 +850,7 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi
|
||||||
//check if the query type is A for IPv4 or ANY
|
//check if the query type is A for IPv4 or ANY
|
||||||
aRecord := &dns.A{
|
aRecord := &dns.A{
|
||||||
Hdr: dns.RR_Header{
|
Hdr: dns.RR_Header{
|
||||||
Name: qName + d.domain,
|
Name: qName + respDomain,
|
||||||
Rrtype: dns.TypeA,
|
Rrtype: dns.TypeA,
|
||||||
Class: dns.ClassINET,
|
Class: dns.ClassINET,
|
||||||
Ttl: uint32(cfg.NodeTTL / time.Second),
|
Ttl: uint32(cfg.NodeTTL / time.Second),
|
||||||
|
@ -854,7 +871,7 @@ func (d *DNSServer) dispatch(remoteAddr net.Addr, req, resp *dns.Msg, maxRecursi
|
||||||
//check if the query type is AAAA for IPv6 or ANY
|
//check if the query type is AAAA for IPv6 or ANY
|
||||||
aaaaRecord := &dns.AAAA{
|
aaaaRecord := &dns.AAAA{
|
||||||
Hdr: dns.RR_Header{
|
Hdr: dns.RR_Header{
|
||||||
Name: qName + d.domain,
|
Name: qName + respDomain,
|
||||||
Rrtype: dns.TypeAAAA,
|
Rrtype: dns.TypeAAAA,
|
||||||
Class: dns.ClassINET,
|
Class: dns.ClassINET,
|
||||||
Ttl: uint32(cfg.NodeTTL / time.Second),
|
Ttl: uint32(cfg.NodeTTL / time.Second),
|
||||||
|
@ -1535,13 +1552,14 @@ func findWeight(node structs.CheckServiceNode) int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSServer) encodeIPAsFqdn(dc string, ip net.IP) string {
|
func (d *DNSServer) encodeIPAsFqdn(questionName string, dc string, ip net.IP) string {
|
||||||
ipv4 := ip.To4()
|
ipv4 := ip.To4()
|
||||||
|
respDomain := d.getResponseDomain(questionName)
|
||||||
if ipv4 != nil {
|
if ipv4 != nil {
|
||||||
ipStr := hex.EncodeToString(ip)
|
ipStr := hex.EncodeToString(ip)
|
||||||
return fmt.Sprintf("%s.addr.%s.%s", ipStr[len(ipStr)-(net.IPv4len*2):], dc, d.domain)
|
return fmt.Sprintf("%s.addr.%s.%s", ipStr[len(ipStr)-(net.IPv4len*2):], dc, respDomain)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%s.addr.%s.%s", hex.EncodeToString(ip), dc, d.domain)
|
return fmt.Sprintf("%s.addr.%s.%s", hex.EncodeToString(ip), dc, respDomain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1623,13 +1641,14 @@ func (d *DNSServer) makeRecordFromNode(node *structs.Node, qType uint16, qName s
|
||||||
// Otherwise it will return a IN A record
|
// Otherwise it will return a IN A record
|
||||||
func (d *DNSServer) makeRecordFromServiceNode(dc string, serviceNode structs.CheckServiceNode, addr net.IP, req *dns.Msg, ttl time.Duration) ([]dns.RR, []dns.RR) {
|
func (d *DNSServer) makeRecordFromServiceNode(dc string, serviceNode structs.CheckServiceNode, addr net.IP, req *dns.Msg, ttl time.Duration) ([]dns.RR, []dns.RR) {
|
||||||
q := req.Question[0]
|
q := req.Question[0]
|
||||||
|
respDomain := d.getResponseDomain(q.Name)
|
||||||
|
|
||||||
ipRecord := makeARecord(q.Qtype, addr, ttl)
|
ipRecord := makeARecord(q.Qtype, addr, ttl)
|
||||||
if ipRecord == nil {
|
if ipRecord == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.Qtype == dns.TypeSRV {
|
if q.Qtype == dns.TypeSRV {
|
||||||
nodeFQDN := fmt.Sprintf("%s.node.%s.%s", serviceNode.Node.Node, dc, d.domain)
|
nodeFQDN := fmt.Sprintf("%s.node.%s.%s", serviceNode.Node.Node, dc, respDomain)
|
||||||
answers := []dns.RR{
|
answers := []dns.RR{
|
||||||
&dns.SRV{
|
&dns.SRV{
|
||||||
Hdr: dns.RR_Header{
|
Hdr: dns.RR_Header{
|
||||||
|
@ -1664,7 +1683,7 @@ func (d *DNSServer) makeRecordFromIP(dc string, addr net.IP, serviceNode structs
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.Qtype == dns.TypeSRV {
|
if q.Qtype == dns.TypeSRV {
|
||||||
ipFQDN := d.encodeIPAsFqdn(dc, addr)
|
ipFQDN := d.encodeIPAsFqdn(q.Name, dc, addr)
|
||||||
answers := []dns.RR{
|
answers := []dns.RR{
|
||||||
&dns.SRV{
|
&dns.SRV{
|
||||||
Hdr: dns.RR_Header{
|
Hdr: dns.RR_Header{
|
||||||
|
@ -1833,11 +1852,12 @@ func (d *DNSServer) serviceSRVRecords(cfg *dnsConfig, dc string, nodes structs.C
|
||||||
|
|
||||||
answers, extra := d.nodeServiceRecords(dc, node, req, ttl, cfg, maxRecursionLevel)
|
answers, extra := d.nodeServiceRecords(dc, node, req, ttl, cfg, maxRecursionLevel)
|
||||||
|
|
||||||
|
respDomain := d.getResponseDomain(req.Question[0].Name)
|
||||||
resp.Answer = append(resp.Answer, answers...)
|
resp.Answer = append(resp.Answer, answers...)
|
||||||
resp.Extra = append(resp.Extra, extra...)
|
resp.Extra = append(resp.Extra, extra...)
|
||||||
|
|
||||||
if cfg.NodeMetaTXT {
|
if cfg.NodeMetaTXT {
|
||||||
resp.Extra = append(resp.Extra, d.generateMeta(fmt.Sprintf("%s.node.%s.%s", node.Node.Node, dc, d.domain), node.Node, ttl)...)
|
resp.Extra = append(resp.Extra, d.generateMeta(fmt.Sprintf("%s.node.%s.%s", node.Node.Node, dc, respDomain), node.Node, ttl)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2128,6 +2128,58 @@ func TestDNS_NSRecords(t *testing.T) {
|
||||||
require.Equal(t, wantExtra, in.Extra, "extra")
|
require.Equal(t, wantExtra, in.Extra, "extra")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDNS_AltDomain_NSRecords(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
a := NewTestAgent(t, `
|
||||||
|
domain = "CONSUL."
|
||||||
|
node_name = "server1"
|
||||||
|
alt_domain = "test-domain."
|
||||||
|
`)
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
questions := []struct {
|
||||||
|
ask string
|
||||||
|
domain string
|
||||||
|
wantDomain string
|
||||||
|
}{
|
||||||
|
{"something.node.consul.", "consul.", "server1.node.dc1.consul."},
|
||||||
|
{"something.node.test-domain.", "test-domain.", "server1.node.dc1.test-domain."},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, question := range questions {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion(question.ask, dns.TypeNS)
|
||||||
|
|
||||||
|
c := new(dns.Client)
|
||||||
|
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wantAnswer := []dns.RR{
|
||||||
|
&dns.NS{
|
||||||
|
Hdr: dns.RR_Header{Name: question.domain, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 0, Rdlength: 0x13},
|
||||||
|
Ns: question.wantDomain,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, wantAnswer, in.Answer, "answer")
|
||||||
|
wantExtra := []dns.RR{
|
||||||
|
&dns.A{
|
||||||
|
Hdr: dns.RR_Header{Name: question.wantDomain, Rrtype: dns.TypeA, Class: dns.ClassINET, Rdlength: 0x4, Ttl: 0},
|
||||||
|
A: net.ParseIP("127.0.0.1").To4(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, wantExtra, in.Extra, "extra")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNS_NSRecords_IPV6(t *testing.T) {
|
func TestDNS_NSRecords_IPV6(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
|
@ -2169,6 +2221,59 @@ func TestDNS_NSRecords_IPV6(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDNS_AltDomain_NSRecords_IPV6(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
a := NewTestAgent(t, `
|
||||||
|
domain = "CONSUL."
|
||||||
|
node_name = "server1"
|
||||||
|
advertise_addr = "::1"
|
||||||
|
alt_domain = "test-domain."
|
||||||
|
`)
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
questions := []struct {
|
||||||
|
ask string
|
||||||
|
domain string
|
||||||
|
wantDomain string
|
||||||
|
}{
|
||||||
|
{"server1.node.dc1.consul.", "consul.", "server1.node.dc1.consul."},
|
||||||
|
{"server1.node.dc1.test-domain.", "test-domain.", "server1.node.dc1.test-domain."},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, question := range questions {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion(question.ask, dns.TypeNS)
|
||||||
|
|
||||||
|
c := new(dns.Client)
|
||||||
|
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wantAnswer := []dns.RR{
|
||||||
|
&dns.NS{
|
||||||
|
Hdr: dns.RR_Header{Name: question.domain, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 0, Rdlength: 0x2},
|
||||||
|
Ns: question.wantDomain,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, wantAnswer, in.Answer, "answer")
|
||||||
|
wantExtra := []dns.RR{
|
||||||
|
&dns.AAAA{
|
||||||
|
Hdr: dns.RR_Header{Name: question.wantDomain, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Rdlength: 0x10, Ttl: 0},
|
||||||
|
AAAA: net.ParseIP("::1"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, wantExtra, in.Extra, "extra")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNS_ExternalServiceToConsulCNAMENestedLookup(t *testing.T) {
|
func TestDNS_ExternalServiceToConsulCNAMENestedLookup(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
|
@ -2397,6 +2502,110 @@ func TestDNS_ServiceLookup_ServiceAddress_A(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDNS_AltDomain_ServiceLookup_ServiceAddress_A(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
a := NewTestAgent(t, `
|
||||||
|
alt_domain = "test-domain"
|
||||||
|
`)
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
// Register a node with a service.
|
||||||
|
{
|
||||||
|
args := &structs.RegisterRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Node: "foo",
|
||||||
|
Address: "127.0.0.1",
|
||||||
|
Service: &structs.NodeService{
|
||||||
|
Service: "db",
|
||||||
|
Tags: []string{"primary"},
|
||||||
|
Address: "127.0.0.2",
|
||||||
|
Port: 12345,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var out struct{}
|
||||||
|
if err := a.RPC("Catalog.Register", args, &out); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register an equivalent prepared query.
|
||||||
|
var id string
|
||||||
|
{
|
||||||
|
args := &structs.PreparedQueryRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Op: structs.PreparedQueryCreate,
|
||||||
|
Query: &structs.PreparedQuery{
|
||||||
|
Name: "test",
|
||||||
|
Service: structs.ServiceQuery{
|
||||||
|
Service: "db",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := a.RPC("PreparedQuery.Apply", args, &id); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up the service directly and via prepared query.
|
||||||
|
questions := []struct {
|
||||||
|
ask string
|
||||||
|
wantDomain string
|
||||||
|
}{
|
||||||
|
{"db.service.consul.", "consul."},
|
||||||
|
{id + ".query.consul.", "consul."},
|
||||||
|
{"db.service.test-domain.", "test-domain."},
|
||||||
|
{id + ".query.test-domain.", "test-domain."},
|
||||||
|
}
|
||||||
|
for _, question := range questions {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion(question.ask, dns.TypeSRV)
|
||||||
|
|
||||||
|
c := new(dns.Client)
|
||||||
|
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(in.Answer) != 1 {
|
||||||
|
t.Fatalf("Bad: %#v", in)
|
||||||
|
}
|
||||||
|
|
||||||
|
srvRec, ok := in.Answer[0].(*dns.SRV)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
|
if srvRec.Port != 12345 {
|
||||||
|
t.Fatalf("Bad: %#v", srvRec)
|
||||||
|
}
|
||||||
|
if srvRec.Target != "7f000002.addr.dc1."+question.wantDomain {
|
||||||
|
t.Fatalf("Bad: %#v", srvRec)
|
||||||
|
}
|
||||||
|
if srvRec.Hdr.Ttl != 0 {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
aRec, ok := in.Extra[0].(*dns.A)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
if aRec.Hdr.Name != "7f000002.addr.dc1."+question.wantDomain {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
if aRec.A.String() != "127.0.0.2" {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
if aRec.Hdr.Ttl != 0 {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNS_ServiceLookup_ServiceAddress_SRV(t *testing.T) {
|
func TestDNS_ServiceLookup_ServiceAddress_SRV(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
|
@ -2605,6 +2814,110 @@ func TestDNS_ServiceLookup_ServiceAddressIPV6(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDNS_AltDomain_ServiceLookup_ServiceAddressIPV6(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
a := NewTestAgent(t, `
|
||||||
|
alt_domain = "test-domain"
|
||||||
|
`)
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
// Register a node with a service.
|
||||||
|
{
|
||||||
|
args := &structs.RegisterRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Node: "foo",
|
||||||
|
Address: "127.0.0.1",
|
||||||
|
Service: &structs.NodeService{
|
||||||
|
Service: "db",
|
||||||
|
Tags: []string{"primary"},
|
||||||
|
Address: "2607:20:4005:808::200e",
|
||||||
|
Port: 12345,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var out struct{}
|
||||||
|
if err := a.RPC("Catalog.Register", args, &out); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register an equivalent prepared query.
|
||||||
|
var id string
|
||||||
|
{
|
||||||
|
args := &structs.PreparedQueryRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Op: structs.PreparedQueryCreate,
|
||||||
|
Query: &structs.PreparedQuery{
|
||||||
|
Name: "test",
|
||||||
|
Service: structs.ServiceQuery{
|
||||||
|
Service: "db",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := a.RPC("PreparedQuery.Apply", args, &id); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up the service directly and via prepared query.
|
||||||
|
questions := []struct {
|
||||||
|
ask string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"db.service.consul.", "2607002040050808000000000000200e.addr.dc1.consul."},
|
||||||
|
{"db.service.test-domain.", "2607002040050808000000000000200e.addr.dc1.test-domain."},
|
||||||
|
{id + ".query.consul.", "2607002040050808000000000000200e.addr.dc1.consul."},
|
||||||
|
{id + ".query.test-domain.", "2607002040050808000000000000200e.addr.dc1.test-domain."},
|
||||||
|
}
|
||||||
|
for _, question := range questions {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion(question.ask, dns.TypeSRV)
|
||||||
|
|
||||||
|
c := new(dns.Client)
|
||||||
|
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(in.Answer) != 1 {
|
||||||
|
t.Fatalf("Bad: %#v", in)
|
||||||
|
}
|
||||||
|
|
||||||
|
srvRec, ok := in.Answer[0].(*dns.SRV)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
|
if srvRec.Port != 12345 {
|
||||||
|
t.Fatalf("Bad: %#v", srvRec)
|
||||||
|
}
|
||||||
|
if srvRec.Target != question.want {
|
||||||
|
t.Fatalf("Bad: %#v", srvRec)
|
||||||
|
}
|
||||||
|
if srvRec.Hdr.Ttl != 0 {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
aRec, ok := in.Extra[0].(*dns.AAAA)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
if aRec.Hdr.Name != question.want {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
if aRec.AAAA.String() != "2607:20:4005:808::200e" {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
if aRec.Hdr.Ttl != 0 {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNS_ServiceLookup_WanTranslation(t *testing.T) {
|
func TestDNS_ServiceLookup_WanTranslation(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
|
@ -6462,6 +6775,9 @@ func TestDNS_AltDomains_Service(t *testing.T) {
|
||||||
Tags: []string{"primary"},
|
Tags: []string{"primary"},
|
||||||
Port: 12345,
|
Port: 12345,
|
||||||
},
|
},
|
||||||
|
NodeMeta: map[string]string{
|
||||||
|
"key": "value",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var out struct{}
|
var out struct{}
|
||||||
|
@ -6470,16 +6786,19 @@ func TestDNS_AltDomains_Service(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
questions := []string{
|
questions := []struct {
|
||||||
"db.service.consul.",
|
ask string
|
||||||
"db.service.test-domain.",
|
wantDomain string
|
||||||
"db.service.dc1.consul.",
|
}{
|
||||||
"db.service.dc1.test-domain.",
|
{"db.service.consul.", "test-node.node.dc1.consul."},
|
||||||
|
{"db.service.test-domain.", "test-node.node.dc1.test-domain."},
|
||||||
|
{"db.service.dc1.consul.", "test-node.node.dc1.consul."},
|
||||||
|
{"db.service.dc1.test-domain.", "test-node.node.dc1.test-domain."},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, question := range questions {
|
for _, question := range questions {
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetQuestion(question, dns.TypeSRV)
|
m.SetQuestion(question.ask, dns.TypeSRV)
|
||||||
|
|
||||||
c := new(dns.Client)
|
c := new(dns.Client)
|
||||||
in, _, err := c.Exchange(m, a.DNSAddr())
|
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||||
|
@ -6498,20 +6817,33 @@ func TestDNS_AltDomains_Service(t *testing.T) {
|
||||||
if srvRec.Port != 12345 {
|
if srvRec.Port != 12345 {
|
||||||
t.Fatalf("Bad: %#v", srvRec)
|
t.Fatalf("Bad: %#v", srvRec)
|
||||||
}
|
}
|
||||||
if srvRec.Target != "test-node.node.dc1.consul." {
|
if got, want := srvRec.Target, question.wantDomain; got != want {
|
||||||
t.Fatalf("Bad: %#v", srvRec)
|
t.Fatalf("SRV target invalid, got %v want %v", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
aRec, ok := in.Extra[0].(*dns.A)
|
aRec, ok := in.Extra[0].(*dns.A)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("Bad: %#v", in.Extra[0])
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
}
|
}
|
||||||
if aRec.Hdr.Name != "test-node.node.dc1.consul." {
|
|
||||||
t.Fatalf("Bad: %#v", in.Extra[0])
|
if got, want := aRec.Hdr.Name, question.wantDomain; got != want {
|
||||||
|
t.Fatalf("A record header invalid, got %v want %v", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
if aRec.A.String() != "127.0.0.1" {
|
if aRec.A.String() != "127.0.0.1" {
|
||||||
t.Fatalf("Bad: %#v", in.Extra[0])
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txtRec, ok := in.Extra[1].(*dns.TXT)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[1])
|
||||||
|
}
|
||||||
|
if got, want := txtRec.Hdr.Name, question.wantDomain; got != want {
|
||||||
|
t.Fatalf("TXT record header invalid, got %v want %v", got, want)
|
||||||
|
}
|
||||||
|
if txtRec.Txt[0] != "key=value" {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[1])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,6 +213,9 @@ The options below are all specified on the command-line.
|
||||||
DNS queries in an alternate domain, in addition to the primary domain. If unset,
|
DNS queries in an alternate domain, in addition to the primary domain. If unset,
|
||||||
no alternate domain is used.
|
no alternate domain is used.
|
||||||
|
|
||||||
|
In Consul 1.10.4 and later, Consul DNS responses will use the same domain as in the query (`-domain` or `-alt-domain`) where applicable.
|
||||||
|
PTR query responses will always use `-domain`, since the desired domain cannot be included in the query.
|
||||||
|
|
||||||
- `-enable-script-checks` ((#\_enable_script_checks)) This controls whether
|
- `-enable-script-checks` ((#\_enable_script_checks)) This controls whether
|
||||||
[health checks that execute scripts](/docs/agent/checks) are enabled on this
|
[health checks that execute scripts](/docs/agent/checks) are enabled on this
|
||||||
agent, and defaults to `false` so operators must opt-in to allowing these. This
|
agent, and defaults to `false` so operators must opt-in to allowing these. This
|
||||||
|
@ -824,6 +827,8 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'."
|
||||||
removed from the cluster. This may only be set on client agents and if unset then other nodes will use the main
|
removed from the cluster. This may only be set on client agents and if unset then other nodes will use the main
|
||||||
`reconnect_timeout` setting when determining when this node may be removed from the cluster.
|
`reconnect_timeout` setting when determining when this node may be removed from the cluster.
|
||||||
|
|
||||||
|
- `alt_domain` Equivalent to the [`-alt-domain` command-line flag](#_alt_domain)
|
||||||
|
|
||||||
- `serf_lan` ((#serf_lan_bind)) Equivalent to the [`-serf-lan-bind` command-line flag](#_serf_lan_bind).
|
- `serf_lan` ((#serf_lan_bind)) Equivalent to the [`-serf-lan-bind` command-line flag](#_serf_lan_bind).
|
||||||
This is an IP address, not to be confused with [`ports.serf_lan`](#serf_lan_port).
|
This is an IP address, not to be confused with [`ports.serf_lan`](#serf_lan_port).
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ are located in the `us-east-1` datacenter, and have no failing health checks.
|
||||||
It's that simple!
|
It's that simple!
|
||||||
|
|
||||||
There are a number of configuration options that are important for the DNS interface,
|
There are a number of configuration options that are important for the DNS interface,
|
||||||
specifically [`client_addr`](/docs/agent/options#client_addr),
|
specifically [`client_addr`](/docs/agent/options#client_addr),[`ports.dns`](/docs/agent/options#dns_port),
|
||||||
[`ports.dns`](/docs/agent/options#dns_port), [`recursors`](/docs/agent/options#recursors),
|
[`recursors`](/docs/agent/options#recursors),[`domain`](/docs/agent/options#domain),
|
||||||
[`domain`](/docs/agent/options#domain), and [`dns_config`](/docs/agent/options#dns_config).
|
[`alt_domain`](/docs/agent/options#alt_domain), and [`dns_config`](/docs/agent/options#dns_config).
|
||||||
By default, Consul will listen on 127.0.0.1:8600 for DNS queries in the `consul.`
|
By default, Consul will listen on 127.0.0.1:8600 for DNS queries in the `consul.`
|
||||||
domain, without support for further DNS recursion. Please consult the
|
domain, without support for further DNS recursion. Please consult the
|
||||||
[documentation on configuration options](/docs/agent/options),
|
[documentation on configuration options](/docs/agent/options),
|
||||||
|
|
Loading…
Reference in New Issue