output: distinguish nameserver resolution failures from domain errors
When an in-bailiwick nameserver cannot be resolved (no glue records and iterative resolution fails), the traversal previously returned a generic RespError. This made the Results section show many identical '6.7% resulted in an error' lines and the Summary show '100% resulted in an error' — even though the domain itself may be perfectly reachable in practice via glue held by the registry. Add a new RespNSResolutionFailed response type (string: ns_error) for this specific case. Changes: - traverse/response.go: add RespNSResolutionFailed, include it in IsTerminal() and String() - traverse/traverser.go: use RespNSResolutionFailed with a descriptive ErrorMessage when ResolveNS fails in processReferral - output/stats.go: map ns_error to nameserver lookup failed in summaryTypeLabel - output/text.go: handle RespNSResolutionFailed in formatResultLine Before: Results: 6.7% resulted in an error (x15) Summary: 100% resulted in an error After: Results: 6.7% nameserver ns-a.hansenits.com.au could not be resolved (x15) Summary: 100% nameserver lookup failed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Copilot
multica-agent
parent
d6063eb636
commit
beefaf44e0
@@ -20,6 +20,11 @@ const (
|
||||
RespNOTIMPL
|
||||
RespCNAMELoop
|
||||
RespError
|
||||
// RespNSResolutionFailed indicates that the traversal could not resolve the
|
||||
// IP address of an in-bailiwick nameserver. The domain may still be
|
||||
// reachable in practice (e.g. via glue records held by the registry), but
|
||||
// the iterative traversal could not complete that path.
|
||||
RespNSResolutionFailed
|
||||
)
|
||||
|
||||
func (rt ResponseType) String() string {
|
||||
@@ -44,6 +49,8 @@ func (rt ResponseType) String() string {
|
||||
return "cname_loop"
|
||||
case RespError:
|
||||
return "error"
|
||||
case RespNSResolutionFailed:
|
||||
return "ns_error"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
@@ -231,7 +238,7 @@ func (r *Response) resolveGlue(child *Referral) {
|
||||
|
||||
func (r *Response) IsTerminal() bool {
|
||||
switch r.Type {
|
||||
case RespAnswer, RespNODATA, RespNXDOMAIN, RespSERVFAIL, RespREFUSED, RespNOTIMPL, RespCNAMELoop, RespError:
|
||||
case RespAnswer, RespNODATA, RespNXDOMAIN, RespSERVFAIL, RespREFUSED, RespNOTIMPL, RespCNAMELoop, RespError, RespNSResolutionFailed:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
||||
@@ -246,6 +246,7 @@ func TestResponseIsTerminal(t *testing.T) {
|
||||
{RespNXDOMAIN, true},
|
||||
{RespSERVFAIL, true},
|
||||
{RespError, true},
|
||||
{RespNSResolutionFailed, true},
|
||||
{RespReferral, false},
|
||||
{RespCNAMEFollow, false},
|
||||
}
|
||||
@@ -272,6 +273,7 @@ func TestResponseTypeString(t *testing.T) {
|
||||
{RespNXDOMAIN, "nxdomain"},
|
||||
{RespSERVFAIL, "servfail"},
|
||||
{RespError, "error"},
|
||||
{RespNSResolutionFailed, "ns_error"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -232,18 +233,28 @@ func (t *Traverser) processReferral(ctx context.Context, ref *Referral, cache *I
|
||||
} else {
|
||||
addrs, err := t.ResolveNS(ctx, ref.Name, cache, visitedCopy, t.depth)
|
||||
if err != nil {
|
||||
nsName := strings.TrimSuffix(ref.Bailiwick, ".")
|
||||
if nsName == "" || nsName == "." {
|
||||
nsName = strings.TrimSuffix(ref.Name, ".")
|
||||
}
|
||||
return &Response{
|
||||
Referral: ref,
|
||||
Type: RespError,
|
||||
Referral: ref,
|
||||
Type: RespNSResolutionFailed,
|
||||
ErrorMessage: fmt.Sprintf("nameserver %s could not be resolved", nsName),
|
||||
}
|
||||
}
|
||||
if len(addrs) > 0 {
|
||||
ref.Addresses = addrs
|
||||
ref.State = StateResolved
|
||||
} else {
|
||||
nsName := strings.TrimSuffix(ref.Bailiwick, ".")
|
||||
if nsName == "" || nsName == "." {
|
||||
nsName = strings.TrimSuffix(ref.Name, ".")
|
||||
}
|
||||
return &Response{
|
||||
Referral: ref,
|
||||
Type: RespError,
|
||||
Referral: ref,
|
||||
Type: RespNSResolutionFailed,
|
||||
ErrorMessage: fmt.Sprintf("nameserver %s could not be resolved", nsName),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user