reimplement-recursive-resolver #6
|
@ -70,11 +70,12 @@ func (h *DnsHandler) recursiveResolve(domain string, qtype uint16, maxDepth int)
|
||||||
answers = append(answers, cname)
|
answers = append(answers, cname)
|
||||||
|
|
||||||
cnameRecursive, cnameAuth, err := h.resolveDNS(record.Content, qtype, maxDepth-1)
|
cnameRecursive, cnameAuth, err := h.resolveDNS(record.Content, qtype, maxDepth-1)
|
||||||
|
authoritative = authoritative && cnameAuth
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return nil, authoritative, err
|
return nil, authoritative, err
|
||||||
}
|
}
|
||||||
authoritative = authoritative && cnameAuth
|
|
||||||
answers = append(answers, cnameRecursive...)
|
answers = append(answers, cnameRecursive...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,14 +127,16 @@ func (h *DnsHandler) resolveDNS(domain string, qtype uint16, maxDepth int) ([]dn
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
cnameAnswers, _, err := h.resolveDNS(cname.Target, qtype, maxDepth-1)
|
cnameAnswers, cnameAuth, err := h.resolveDNS(cname.Target, qtype, maxDepth-1)
|
||||||
|
authoritative = authoritative && cnameAuth
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
answers = append(answers, cnameAnswers...)
|
answers = append(answers, cnameAnswers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return answers, false, nil
|
authoritative = authoritative && len(externalAnswers) == 0
|
||||||
|
return answers, authoritative, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *DnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
func (h *DnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
|
|
@ -58,83 +58,6 @@ func setup(arguments *args.Arguments) (*sql.DB, *dns.Server, string, func()) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWhenExternalDomain(t *testing.T) {
|
|
||||||
externalDb, _, externalAddr, externalCleanup := setup(nil)
|
|
||||||
internalDb, _, internalAddr, internalCleanup := setup(&args.Arguments{
|
|
||||||
DnsPort: randomPort(),
|
|
||||||
DnsResolvers: []string{externalAddr},
|
|
||||||
})
|
|
||||||
defer internalCleanup()
|
|
||||||
defer externalCleanup()
|
|
||||||
|
|
||||||
authoritativeRecords := []database.DNSRecord{
|
|
||||||
{
|
|
||||||
ID: "1",
|
|
||||||
UserID: "test",
|
|
||||||
Name: "external.example.com.",
|
|
||||||
Type: "CNAME",
|
|
||||||
Content: "external.internal.example.com.",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
internalRecords := []database.DNSRecord{
|
|
||||||
{
|
|
||||||
ID: "1",
|
|
||||||
UserID: "test",
|
|
||||||
Name: "external.internal.example.com.",
|
|
||||||
Type: "A",
|
|
||||||
Content: "127.0.0.1",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "2",
|
|
||||||
UserID: "test",
|
|
||||||
Name: "test.internal.example.com.",
|
|
||||||
Type: "CNAME",
|
|
||||||
Content: "external.example.com.",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, record := range authoritativeRecords {
|
|
||||||
database.SaveDNSRecord(externalDb, &record)
|
|
||||||
}
|
|
||||||
for _, record := range internalRecords {
|
|
||||||
database.SaveDNSRecord(internalDb, &record)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure that if the record doesn't exist in the internal database, it will
|
|
||||||
// go and query the external dns resolvers, then loop back to the internal
|
|
||||||
|
|
||||||
qtype := dns.TypeA
|
|
||||||
domain := dns.Fqdn("test.internal.example.com.")
|
|
||||||
client := &dns.Client{}
|
|
||||||
message := &dns.Msg{}
|
|
||||||
message.SetQuestion(domain, qtype)
|
|
||||||
|
|
||||||
in, _, err := client.Exchange(message, internalAddr)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(in.Answer) != 3 {
|
|
||||||
t.Fatalf("expected 3 answers, got %d", len(in.Answer))
|
|
||||||
}
|
|
||||||
|
|
||||||
aRecord := in.Answer[2]
|
|
||||||
if aRecord.Header().Name != internalRecords[0].Name {
|
|
||||||
t.Fatalf("expected %s, got %s", domain, aRecord.Header().Name)
|
|
||||||
}
|
|
||||||
if aRecord.Header().Rrtype != dns.TypeA {
|
|
||||||
t.Fatalf("expected %s, got %s", dns.TypeToString[aRecord.Header().Rrtype], internalRecords[1].Type)
|
|
||||||
}
|
|
||||||
if aRecord.(*dns.A).A.String() != internalRecords[0].Content {
|
|
||||||
t.Fatalf("expected %s, got %s", internalRecords[0].Content, aRecord.(*dns.A).A.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.Authoritative {
|
|
||||||
t.Fatalf("expected non-authoritative response")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWhenCNAMEIsResolved(t *testing.T) {
|
func TestWhenCNAMEIsResolved(t *testing.T) {
|
||||||
testDb, _, addr, cleanup := setup(nil)
|
testDb, _, addr, cleanup := setup(nil)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
@ -322,3 +245,86 @@ func TestWhenUnresolvingCNAMEWithMaxDepth(t *testing.T) {
|
||||||
t.Fatalf("expected SERVFAIL, got %d", in.Rcode)
|
t.Fatalf("expected SERVFAIL, got %d", in.Rcode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWhenExternalDomain(t *testing.T) {
|
||||||
|
externalDb, _, externalAddr, externalCleanup := setup(nil)
|
||||||
|
internalDb, _, internalAddr, internalCleanup := setup(&args.Arguments{
|
||||||
|
DnsPort: randomPort(),
|
||||||
|
DnsResolvers: []string{externalAddr},
|
||||||
|
})
|
||||||
|
defer internalCleanup()
|
||||||
|
defer externalCleanup()
|
||||||
|
|
||||||
|
authoritativeRecords := []database.DNSRecord{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
UserID: "test",
|
||||||
|
Name: "external.example.com.",
|
||||||
|
Type: "CNAME",
|
||||||
|
Content: "external.internal.example.com.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
UserID: "test",
|
||||||
|
Name: "final.example.com.",
|
||||||
|
Type: "A",
|
||||||
|
Content: "127.0.0.1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
internalRecords := []database.DNSRecord{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
UserID: "test",
|
||||||
|
Name: "external.internal.example.com.",
|
||||||
|
Type: "CNAME",
|
||||||
|
Content: "final.example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
UserID: "test",
|
||||||
|
Name: "test.internal.example.com.",
|
||||||
|
Type: "CNAME",
|
||||||
|
Content: "external.example.com.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, record := range authoritativeRecords {
|
||||||
|
database.SaveDNSRecord(externalDb, &record)
|
||||||
|
}
|
||||||
|
for _, record := range internalRecords {
|
||||||
|
database.SaveDNSRecord(internalDb, &record)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that if the record doesn't exist in the internal database, it will
|
||||||
|
// go and query the external dns resolvers, then loop back to the internal
|
||||||
|
|
||||||
|
qtype := dns.TypeA
|
||||||
|
domain := dns.Fqdn("test.internal.example.com.")
|
||||||
|
client := &dns.Client{}
|
||||||
|
message := &dns.Msg{}
|
||||||
|
message.SetQuestion(domain, qtype)
|
||||||
|
|
||||||
|
in, _, err := client.Exchange(message, internalAddr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(in.Answer) != 4 {
|
||||||
|
t.Fatalf("expected 4 answers, got %d", len(in.Answer))
|
||||||
|
}
|
||||||
|
|
||||||
|
aRecord := in.Answer[3]
|
||||||
|
if aRecord.Header().Name != authoritativeRecords[1].Name {
|
||||||
|
t.Fatalf("expected %s, got %s", domain, aRecord.Header().Name)
|
||||||
|
}
|
||||||
|
if aRecord.Header().Rrtype != dns.TypeA {
|
||||||
|
t.Fatalf("expected %s, got %s", dns.TypeToString[aRecord.Header().Rrtype], internalRecords[1].Type)
|
||||||
|
}
|
||||||
|
if aRecord.(*dns.A).A.String() != authoritativeRecords[1].Content {
|
||||||
|
t.Fatalf("expected %s, got %s", authoritativeRecords[1].Content, aRecord.(*dns.A).A.String())
|
||||||
|
}
|
||||||
|
if in.Authoritative {
|
||||||
|
t.Fatalf("expected non-authoritative response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue