mirror of https://github.com/hashicorp/consul
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
629 lines
15 KiB
629 lines
15 KiB
9 months ago
|
// Copyright (c) HashiCorp, Inc.
|
||
|
// SPDX-License-Identifier: BUSL-1.1
|
||
|
|
||
|
package dns
|
||
|
|
||
|
import (
|
||
|
"net"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/miekg/dns"
|
||
|
"github.com/stretchr/testify/mock"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/hashicorp/consul/agent/config"
|
||
|
"github.com/hashicorp/consul/agent/discovery"
|
||
|
"github.com/hashicorp/consul/internal/resource"
|
||
|
)
|
||
|
|
||
|
func Test_HandleRequest_V2Services(t *testing.T) {
|
||
|
testCases := []HandleTestCase{
|
||
|
{
|
||
|
name: "A/AAAA Query a service and return multiple A records",
|
||
|
request: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
},
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeA,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
configureDataFetcher: func(fetcher discovery.CatalogDataFetcher) {
|
||
|
results := []*discovery.Result{
|
||
|
{
|
||
|
Node: &discovery.Location{Name: "foo-1", Address: "10.0.0.1"},
|
||
|
Type: discovery.ResultTypeWorkload,
|
||
|
Tenancy: discovery.ResultTenancy{
|
||
|
Namespace: resource.DefaultNamespaceName,
|
||
|
Partition: resource.DefaultPartitionName,
|
||
|
},
|
||
|
Ports: []discovery.Port{
|
||
|
{
|
||
|
Name: "api",
|
||
|
Number: 5678,
|
||
|
},
|
||
|
// Intentionally not in the mesh
|
||
|
},
|
||
|
DNS: discovery.DNSConfig{
|
||
|
Weight: 2,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Node: &discovery.Location{Name: "foo-2", Address: "10.0.0.2"},
|
||
|
Type: discovery.ResultTypeWorkload,
|
||
|
Tenancy: discovery.ResultTenancy{
|
||
|
Namespace: resource.DefaultNamespaceName,
|
||
|
Partition: resource.DefaultPartitionName,
|
||
|
},
|
||
|
Ports: []discovery.Port{
|
||
|
{
|
||
|
Name: "api",
|
||
|
Number: 5678,
|
||
|
},
|
||
|
{
|
||
|
Name: "mesh",
|
||
|
Number: 21000,
|
||
|
},
|
||
|
},
|
||
|
DNS: discovery.DNSConfig{
|
||
|
Weight: 3,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
fetcher.(*discovery.MockCatalogDataFetcher).
|
||
|
On("FetchEndpoints", mock.Anything, mock.Anything, mock.Anything).
|
||
|
Return(results, nil).
|
||
|
Run(func(args mock.Arguments) {
|
||
|
req := args.Get(1).(*discovery.QueryPayload)
|
||
|
reqType := args.Get(2).(discovery.LookupType)
|
||
|
|
||
|
require.Equal(t, "foo", req.Name)
|
||
|
require.Empty(t, req.PortName)
|
||
|
require.Equal(t, discovery.LookupTypeService, reqType)
|
||
|
})
|
||
|
},
|
||
|
validateAndNormalizeExpected: true,
|
||
|
response: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
Response: true,
|
||
|
Authoritative: true,
|
||
|
},
|
||
|
Compress: true,
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeA,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
Answer: []dns.RR{
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("10.0.0.1"),
|
||
|
},
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("10.0.0.2"),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "SRV Query with a multi-port service return multiple SRV records",
|
||
|
request: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
},
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
configureDataFetcher: func(fetcher discovery.CatalogDataFetcher) {
|
||
|
results := []*discovery.Result{
|
||
|
{
|
||
|
Node: &discovery.Location{Name: "foo-1", Address: "10.0.0.1"},
|
||
|
Type: discovery.ResultTypeWorkload,
|
||
|
Tenancy: discovery.ResultTenancy{
|
||
|
Namespace: resource.DefaultNamespaceName,
|
||
|
Partition: resource.DefaultPartitionName,
|
||
|
},
|
||
|
Ports: []discovery.Port{
|
||
|
{
|
||
|
Name: "api",
|
||
|
Number: 5678,
|
||
|
},
|
||
|
// Intentionally not in the mesh
|
||
|
},
|
||
|
DNS: discovery.DNSConfig{
|
||
|
Weight: 2,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Node: &discovery.Location{Name: "foo-2", Address: "10.0.0.2"},
|
||
|
Type: discovery.ResultTypeWorkload,
|
||
|
Tenancy: discovery.ResultTenancy{
|
||
|
Namespace: resource.DefaultNamespaceName,
|
||
|
Partition: resource.DefaultPartitionName,
|
||
|
},
|
||
|
Ports: []discovery.Port{
|
||
|
{
|
||
|
Name: "api",
|
||
|
Number: 5678,
|
||
|
},
|
||
|
{
|
||
|
Name: "mesh",
|
||
|
Number: 21000,
|
||
|
},
|
||
|
},
|
||
|
DNS: discovery.DNSConfig{
|
||
|
Weight: 3,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
fetcher.(*discovery.MockCatalogDataFetcher).
|
||
|
On("FetchEndpoints", mock.Anything, mock.Anything, mock.Anything).
|
||
|
Return(results, nil).
|
||
|
Run(func(args mock.Arguments) {
|
||
|
req := args.Get(1).(*discovery.QueryPayload)
|
||
|
reqType := args.Get(2).(discovery.LookupType)
|
||
|
|
||
|
require.Equal(t, "foo", req.Name)
|
||
|
require.Empty(t, req.PortName)
|
||
|
require.Equal(t, discovery.LookupTypeService, reqType)
|
||
|
})
|
||
|
},
|
||
|
validateAndNormalizeExpected: true,
|
||
|
response: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
Response: true,
|
||
|
Authoritative: true,
|
||
|
},
|
||
|
Compress: true,
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
Answer: []dns.RR{
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 2,
|
||
|
Priority: 1,
|
||
|
Port: 5678,
|
||
|
Target: "api.port.foo-1.workload.default.ns.default.ap.consul.",
|
||
|
},
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 3,
|
||
|
Priority: 1,
|
||
|
Port: 5678,
|
||
|
Target: "api.port.foo-2.workload.default.ns.default.ap.consul.",
|
||
|
},
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 3,
|
||
|
Priority: 1,
|
||
|
Port: 21000,
|
||
|
Target: "mesh.port.foo-2.workload.default.ns.default.ap.consul.",
|
||
|
},
|
||
|
},
|
||
|
Extra: []dns.RR{
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "api.port.foo-1.workload.default.ns.default.ap.consul.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("10.0.0.1"),
|
||
|
},
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "api.port.foo-2.workload.default.ns.default.ap.consul.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("10.0.0.2"),
|
||
|
},
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "mesh.port.foo-2.workload.default.ns.default.ap.consul.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("10.0.0.2"),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "SRV Query with a multi-port service where the client requests a specific port, returns SRV and A records",
|
||
|
request: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
},
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "mesh.port.foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
configureDataFetcher: func(fetcher discovery.CatalogDataFetcher) {
|
||
|
results := []*discovery.Result{
|
||
|
{
|
||
|
Node: &discovery.Location{Name: "foo-2", Address: "10.0.0.2"},
|
||
|
Type: discovery.ResultTypeWorkload,
|
||
|
Tenancy: discovery.ResultTenancy{
|
||
|
Namespace: resource.DefaultNamespaceName,
|
||
|
Partition: resource.DefaultPartitionName,
|
||
|
},
|
||
|
Ports: []discovery.Port{
|
||
|
{
|
||
|
Name: "mesh",
|
||
|
Number: 21000,
|
||
|
},
|
||
|
},
|
||
|
DNS: discovery.DNSConfig{
|
||
|
Weight: 3,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
fetcher.(*discovery.MockCatalogDataFetcher).
|
||
|
On("FetchEndpoints", mock.Anything, mock.Anything, mock.Anything).
|
||
|
Return(results, nil).
|
||
|
Run(func(args mock.Arguments) {
|
||
|
req := args.Get(1).(*discovery.QueryPayload)
|
||
|
reqType := args.Get(2).(discovery.LookupType)
|
||
|
|
||
|
require.Equal(t, "foo", req.Name)
|
||
|
require.Equal(t, "mesh", req.PortName)
|
||
|
require.Equal(t, discovery.LookupTypeService, reqType)
|
||
|
})
|
||
|
},
|
||
|
validateAndNormalizeExpected: true,
|
||
|
response: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
Response: true,
|
||
|
Authoritative: true,
|
||
|
},
|
||
|
Compress: true,
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "mesh.port.foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
Answer: []dns.RR{
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "mesh.port.foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 3,
|
||
|
Priority: 1,
|
||
|
Port: 21000,
|
||
|
Target: "mesh.port.foo-2.workload.default.ns.default.ap.consul.",
|
||
|
},
|
||
|
},
|
||
|
Extra: []dns.RR{
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "mesh.port.foo-2.workload.default.ns.default.ap.consul.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("10.0.0.2"),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "SRV Query with a multi-port service that has workloads w/ hostnames (no recursors)",
|
||
|
request: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
},
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
configureDataFetcher: func(fetcher discovery.CatalogDataFetcher) {
|
||
|
results := []*discovery.Result{
|
||
|
{
|
||
|
Node: &discovery.Location{Name: "foo-1", Address: "foo-1.example.com"},
|
||
|
Type: discovery.ResultTypeWorkload,
|
||
|
Tenancy: discovery.ResultTenancy{
|
||
|
Namespace: resource.DefaultNamespaceName,
|
||
|
Partition: resource.DefaultPartitionName,
|
||
|
},
|
||
|
Ports: []discovery.Port{
|
||
|
{
|
||
|
Name: "api",
|
||
|
Number: 5678,
|
||
|
},
|
||
|
{
|
||
|
Name: "web",
|
||
|
Number: 8080,
|
||
|
},
|
||
|
},
|
||
|
DNS: discovery.DNSConfig{
|
||
|
Weight: 2,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
fetcher.(*discovery.MockCatalogDataFetcher).
|
||
|
On("FetchEndpoints", mock.Anything, mock.Anything, mock.Anything).
|
||
|
Return(results, nil).
|
||
|
Run(func(args mock.Arguments) {
|
||
|
req := args.Get(1).(*discovery.QueryPayload)
|
||
|
reqType := args.Get(2).(discovery.LookupType)
|
||
|
|
||
|
require.Equal(t, "foo", req.Name)
|
||
|
require.Empty(t, req.PortName)
|
||
|
require.Equal(t, discovery.LookupTypeService, reqType)
|
||
|
})
|
||
|
},
|
||
|
validateAndNormalizeExpected: true,
|
||
|
response: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
Response: true,
|
||
|
Authoritative: true,
|
||
|
},
|
||
|
Compress: true,
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
Answer: []dns.RR{
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 2,
|
||
|
Priority: 1,
|
||
|
Port: 5678,
|
||
|
Target: "foo-1.example.com.",
|
||
|
},
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 2,
|
||
|
Priority: 1,
|
||
|
Port: 8080,
|
||
|
Target: "foo-1.example.com.",
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "SRV Query with a multi-port service that has workloads w/ hostnames (no recursor)",
|
||
|
request: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
},
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
configureDataFetcher: func(fetcher discovery.CatalogDataFetcher) {
|
||
|
results := []*discovery.Result{
|
||
|
{
|
||
|
Node: &discovery.Location{Name: "foo-1", Address: "foo-1.example.com"},
|
||
|
Type: discovery.ResultTypeWorkload,
|
||
|
Tenancy: discovery.ResultTenancy{
|
||
|
Namespace: resource.DefaultNamespaceName,
|
||
|
Partition: resource.DefaultPartitionName,
|
||
|
},
|
||
|
Ports: []discovery.Port{
|
||
|
{
|
||
|
Name: "api",
|
||
|
Number: 5678,
|
||
|
},
|
||
|
{
|
||
|
Name: "web",
|
||
|
Number: 8080,
|
||
|
},
|
||
|
},
|
||
|
DNS: discovery.DNSConfig{
|
||
|
Weight: 2,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
fetcher.(*discovery.MockCatalogDataFetcher).
|
||
|
On("FetchEndpoints", mock.Anything, mock.Anything, mock.Anything).
|
||
|
Return(results, nil).
|
||
|
Run(func(args mock.Arguments) {
|
||
|
req := args.Get(1).(*discovery.QueryPayload)
|
||
|
reqType := args.Get(2).(discovery.LookupType)
|
||
|
|
||
|
require.Equal(t, "foo", req.Name)
|
||
|
require.Empty(t, req.PortName)
|
||
|
require.Equal(t, discovery.LookupTypeService, reqType)
|
||
|
})
|
||
|
},
|
||
|
agentConfig: &config.RuntimeConfig{
|
||
|
DNSRecursors: []string{"8.8.8.8"},
|
||
|
DNSDomain: "consul",
|
||
|
DNSNodeTTL: 123 * time.Second,
|
||
|
DNSSOA: config.RuntimeSOAConfig{
|
||
|
Refresh: 1,
|
||
|
Retry: 2,
|
||
|
Expire: 3,
|
||
|
Minttl: 4,
|
||
|
},
|
||
|
DNSUDPAnswerLimit: maxUDPAnswerLimit,
|
||
|
},
|
||
|
configureRecursor: func(recursor dnsRecursor) {
|
||
|
resp := &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
Response: true,
|
||
|
Authoritative: true,
|
||
|
Rcode: dns.RcodeSuccess,
|
||
|
},
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo-1.example.com.",
|
||
|
Qtype: dns.TypeA,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
Answer: []dns.RR{
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo-1.example.com.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
},
|
||
|
A: net.ParseIP("1.2.3.4"),
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
recursor.(*mockDnsRecursor).On("handle",
|
||
|
mock.Anything, mock.Anything, mock.Anything).Return(resp, nil)
|
||
|
},
|
||
|
validateAndNormalizeExpected: true,
|
||
|
response: &dns.Msg{
|
||
|
MsgHdr: dns.MsgHdr{
|
||
|
Opcode: dns.OpcodeQuery,
|
||
|
Response: true,
|
||
|
Authoritative: true,
|
||
|
RecursionAvailable: true,
|
||
|
},
|
||
|
Compress: true,
|
||
|
Question: []dns.Question{
|
||
|
{
|
||
|
Name: "foo.service.consul.",
|
||
|
Qtype: dns.TypeSRV,
|
||
|
Qclass: dns.ClassINET,
|
||
|
},
|
||
|
},
|
||
|
Answer: []dns.RR{
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 2,
|
||
|
Priority: 1,
|
||
|
Port: 5678,
|
||
|
Target: "foo-1.example.com.",
|
||
|
},
|
||
|
&dns.SRV{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo.service.consul.",
|
||
|
Rrtype: dns.TypeSRV,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
Weight: 2,
|
||
|
Priority: 1,
|
||
|
Port: 8080,
|
||
|
Target: "foo-1.example.com.",
|
||
|
},
|
||
|
},
|
||
|
Extra: []dns.RR{
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo-1.example.com.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("1.2.3.4"),
|
||
|
},
|
||
|
// TODO (v2-dns): This needs to be de-duplicated (NET-8064)
|
||
|
&dns.A{
|
||
|
Hdr: dns.RR_Header{
|
||
|
Name: "foo-1.example.com.",
|
||
|
Rrtype: dns.TypeA,
|
||
|
Class: dns.ClassINET,
|
||
|
Ttl: uint32(123),
|
||
|
},
|
||
|
A: net.ParseIP("1.2.3.4"),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tc := range testCases {
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
runHandleTestCases(t, tc)
|
||
|
})
|
||
|
}
|
||
|
}
|