Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop handling a domain if all nameservers don't provide sufficient glue records when they should #417

Merged
merged 6 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/zdns/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const (
StatusTimeout Status = "TIMEOUT"
StatusIterTimeout Status = "ITERATIVE_TIMEOUT"
StatusNoAuth Status = "NOAUTH"
StatusNoNeededGlue Status = "NONEEDEDGLUE" // When a nameserver is authoritative for itself and the parent nameserver doesn't provide the glue to look it up
)

var RootServersV4 = []string{
Expand Down
15 changes: 11 additions & 4 deletions src/zdns/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,6 @@ func (r *Resolver) iterateOnAuthorities(ctx context.Context, q Question, depth i
if nsStatus != StatusNoError {
var err error
newStatus, err := handleStatus(nsStatus, err)
// default case we continue
if err == nil {
if i+1 == len(result.Authorities) {
r.verboseLog((depth + 2), "--> Auth find Failed. Unknown error. No more authorities to try, terminating: ", nsStatus)
Expand All @@ -608,8 +607,11 @@ func (r *Resolver) iterateOnAuthorities(ctx context.Context, q Question, depth i
}
}
iterateResult, newTrace, status, err := r.iterativeLookup(ctx, q, ns, depth+1, newLayer, newTrace)
if isStatusAnswer(status) {
r.verboseLog((depth + 1), "--> Auth Resolution success: ", status)
if status == StatusNoNeededGlue {
r.verboseLog((depth + 2), "--> Auth resolution of ", ns, " was unsuccessful. No glue to follow", status)
return iterateResult, newTrace, status, err
} else if isStatusAnswer(status) {
r.verboseLog((depth + 1), "--> Auth Resolution of ", ns, " success: ", status)
return iterateResult, newTrace, status, err
} else if i+1 < len(result.Authorities) {
r.verboseLog((depth + 2), "--> Auth resolution of ", ns, " Failed: ", status, ". Will try next authority")
Expand Down Expand Up @@ -643,6 +645,11 @@ func (r *Resolver) extractAuthority(ctx context.Context, authority interface{},
// that would normally be cache poison. Because it's "ok" and quite common
res, status := checkGlue(server, *result, r.ipVersionMode, r.iterationIPPreference)
if status != StatusNoError {
if ok, _ = nameIsBeneath(server, layer); ok {
// The domain we're searching for is beneath us but no glue was returned. We cannot proceed without this Glue.
// Terminating
return "", StatusNoNeededGlue, "", trace
}
// Fall through to normal query
var q Question
q.Name = server
Expand All @@ -654,7 +661,7 @@ func (r *Resolver) extractAuthority(ctx context.Context, authority interface{},
}
res, trace, status, _ = r.iterativeLookup(ctx, q, r.randomRootNameServer(), depth+1, ".", trace)
}
if status == StatusIterTimeout {
if status == StatusIterTimeout || status == StatusNoNeededGlue {
return "", status, "", trace
}
if status == StatusNoError {
Expand Down
8 changes: 6 additions & 2 deletions src/zdns/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ func checkGlueHelper(server, ansType string, result SingleQueryResult) (SingleQu
if !ok {
continue
}
if ans.Type == ansType && strings.TrimSuffix(ans.Name, ".") == server {
// sanitize case and trailing dot
// RFC 4343 - states DNS names are case-insensitive
if ans.Type == ansType && strings.EqualFold(strings.TrimSuffix(ans.Name, "."), server) {
var retv SingleQueryResult
retv.Authorities = make([]interface{}, 0)
retv.Answers = make([]interface{}, 0, 1)
Expand Down Expand Up @@ -150,11 +152,13 @@ func TranslateDNSErrorCode(err int) Status {
}

// handleStatus is a helper function to deal with a status and error. Error is only returned if the status is an
// Iterative Timeout
// Iterative Timeout or NoNeededGlueRecord
func handleStatus(status Status, err error) (Status, error) {
switch status {
case StatusIterTimeout:
return status, err
case StatusNoNeededGlue:
return status, err
case StatusNXDomain:
return status, nil
case StatusServFail:
Expand Down
4 changes: 2 additions & 2 deletions testing/ipv6_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ def test_ipv6_unreachable(self):
c = "A --iterative --6=true --4=false"
name = "esrg.stanford.edu"
cmd, res = self.run_zdns(c, name)
# esrg.stanford.edu is hosted on NS's that do not have an IPv6 address. Therefore, this will fail.
self.assertServFail(res, cmd)
# esrg.stanford.edu is hosted on NS's that do not have an IPv6 address. Therefore, the lookup won't get sufficient glue records to resolve the query.
self.assertEqual(res["status"], "NONEEDEDGLUE", cmd)

def test_ipv6_external_lookup_unreachable_nameserver(self):
c = "A --6=true --4=false --name-servers=1.1.1.1"
Expand Down