DNS server: allow returning _multiple_ AAAA records

Previously the DNS server only returned the first AAAA record of a
customized domain; now it will return all the AAAA records.
This commit is contained in:
Brian Cunnie
2020-12-17 07:54:08 -08:00
parent ef868f7fdb
commit 1251afa774
2 changed files with 55 additions and 25 deletions

View File

@@ -204,13 +204,10 @@ func processQuestion(q dnsmessage.Question, b *dnsmessage.Builder) (logMessage s
}
case dnsmessage.TypeAAAA:
{
var nameToAAAA *dnsmessage.AAAAResource
nameToAAAA, err = NameToAAAA(q.Name.String())
var nameToAAAAs []dnsmessage.AAAAResource
nameToAAAAs, err = NameToAAAA(q.Name.String())
if err != nil {
// There's only one possible error this can be: ErrNotFound. note that
// this could be written more efficiently; however, I wrote it to
// accommodate 'if err != nil' convention. My first version was 'if
// err == nil', and it flummoxed me.
// There's only one possible error this can be: ErrNotFound
err = noAnswersOnlyAuthorities(q, b, &logMessage)
return
} else {
@@ -218,18 +215,22 @@ func processQuestion(q dnsmessage.Question, b *dnsmessage.Builder) (logMessage s
if err != nil {
return
}
err = b.AAAAResource(dnsmessage.ResourceHeader{
Name: q.Name,
Type: dnsmessage.TypeAAAA,
Class: dnsmessage.ClassINET,
TTL: 604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
Length: 0,
}, *nameToAAAA)
if err != nil {
return
var logMessages []string
for _, nameToAAAA := range nameToAAAAs {
err = b.AAAAResource(dnsmessage.ResourceHeader{
Name: q.Name,
Type: dnsmessage.TypeAAAA,
Class: dnsmessage.ClassINET,
TTL: 604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
Length: 0,
}, nameToAAAA)
if err != nil {
return
}
ip := net.IP(nameToAAAA.AAAA[:])
logMessages = append(logMessages, ip.String())
}
ip := net.IP(nameToAAAA.AAAA[:])
logMessage += ip.String()
logMessage += strings.Join(logMessages, ", ")
}
}
case dnsmessage.TypeALL:
@@ -383,14 +384,14 @@ func NameToA(fqdnString string) (*dnsmessage.AResource, error) {
// NameToAAAA NameToA returns either an AAAAResource that matched the hostname
// or ErrNotFound
func NameToAAAA(fqdnString string) (*dnsmessage.AAAAResource, error) {
func NameToAAAA(fqdnString string) ([]dnsmessage.AAAAResource, error) {
fqdn := []byte(fqdnString)
// is it a customized AAAA record? If so, return early
if domain, ok := Customizations[fqdnString]; ok && len(domain.AAAA) > 0 {
return &domain.AAAA[0], nil // TODO: handle multiple AAAA records
return domain.AAAA, nil
}
if !ipv6RE.Match(fqdn) {
return &dnsmessage.AAAAResource{}, ErrNotFound
return nil, ErrNotFound
}
ipv6RE.Longest()
@@ -402,7 +403,7 @@ func NameToAAAA(fqdnString string) (*dnsmessage.AAAAResource, error) {
for i := range ipv16address {
AAAAR.AAAA[i] = ipv16address[i]
}
return &AAAAR, nil
return []dnsmessage.AAAAResource{AAAAR}, nil
}
func NSResources() map[string]dnsmessage.NSResource {

View File

@@ -406,9 +406,10 @@ var _ = Describe("Xip", func() {
Describe("NameToAAAA()", func() {
DescribeTable("when it succeeds",
func(fqdn string, expectedAAAA dnsmessage.AAAAResource) {
ipv6Answer, err := xip.NameToAAAA(fqdn)
ipv6Answers, err := xip.NameToAAAA(fqdn)
Expect(err).ToNot(HaveOccurred())
Expect(*ipv6Answer).To(Equal(expectedAAAA))
Expect(len(ipv6Answers)).To(Equal(1))
Expect(ipv6Answers[0]).To(Equal(expectedAAAA))
},
// sslip.io website
Entry("sslip.io", "sslip.io.", xip.Customizations["sslip.io."].AAAA[0]),
@@ -439,12 +440,30 @@ var _ = Describe("Xip", func() {
It("should succeed every time", func() {
for i := 0; i < 1000; i++ {
addr := randomIPv6Address()
ipv6Answer, err := xip.NameToAAAA(strings.ReplaceAll(addr.String(), ":", "-"))
ipv6Answers, err := xip.NameToAAAA(strings.ReplaceAll(addr.String(), ":", "-"))
Expect(err).ToNot(HaveOccurred())
Expect(ipv6Answer.AAAA[:]).To(Equal([]uint8(addr)))
Expect(ipv6Answers[0].AAAA[:]).To(Equal([]uint8(addr)))
}
})
})
When("There is more than one AAAA record", func() {
It("returns them all", func() {
fqdn := random8ByteString()
xip.Customizations[fqdn] = xip.DomainCustomization{
//copy(xip.Customizations[fqdn].AAAA, dnsmessage.AAAAResource)
AAAA: []dnsmessage.AAAAResource{
{AAAA: [16]byte{1}},
{AAAA: [16]byte{2}},
},
}
ipv6Addrs, err := xip.NameToAAAA(fqdn)
Expect(err).ToNot(HaveOccurred())
Expect(len(ipv6Addrs)).To(Equal(2))
Expect(ipv6Addrs[0].AAAA).To(Equal([16]byte{1}))
Expect(ipv6Addrs[1].AAAA).To(Equal([16]byte{2}))
delete(xip.Customizations, fqdn)
})
})
})
})
@@ -465,3 +484,13 @@ func randomIPv6Address() net.IP {
}
return ipv6
}
// random8ByteString() returns an 8-char string consisting solely of the letters a-z.
func random8ByteString() string {
var randomString []byte
for i := 0; i < 8; i++ {
// 97 == ascii 'a', and there are 26 letters in the alphabet
randomString = append(randomString, byte(97+rand.Intn(26)))
}
return string(randomString)
}