- Exponential backoff retry logic (100ms, 200ms, 400ms... capped at 2s) replacing fixed 100ms delay between retries - Explicit REFUSED and NOTIMP response types (RespREFUSED, RespNOTIMPL) surfaced as terminal results with user-visible messages - CNAME loop detection: walking the ancestor referral chain before following a CNAME prevents infinite recursion; produces RespCNAMELoop - DNAME record support: synthesize CNAME target from DNAME mapping when the server omits the RFC 6672 synthesized CNAME record - ErrorMessage field on Response for surfacing error details to users - Fix resolveGlueViaSystem timeout bug: deadline.Sub(deadline) was always 0; replaced with time.Until(deadline) - DNAME records excluded from hasFinalAnswer so DNAME-only responses are correctly classified as RespCNAMEFollow - Text and JSON output updated with labels for all new response types - Tests: CNAME loop (2-step and direct), REFUSED, NOTIMP, graceful degradation (partial and total server failure), DNAME synthesis, IsNameInChain, backoffDelay, ResponseClassification strings 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
76f5010a5e
commit
368f200d23
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hits/ExploreDNS/internal/dns"
|
||||
miekgdns "github.com/miekg/dns"
|
||||
@@ -141,7 +142,19 @@ func (t *Traverser) Traverse(ctx context.Context, name string) ([]TraversalResul
|
||||
if resp.Type == RespCNAMEFollow {
|
||||
follow := resp.CNAMEFollowReferral()
|
||||
if follow != nil {
|
||||
if !stack.Push(follow) {
|
||||
// Detect CNAME loop: target name already appears in the ancestor chain.
|
||||
if follow.Parent != nil && follow.Parent.IsNameInChain(follow.Name) {
|
||||
mu.Lock()
|
||||
results = append(results, TraversalResult{
|
||||
Referral: follow,
|
||||
Response: &Response{
|
||||
Referral: follow,
|
||||
Type: RespCNAMELoop,
|
||||
ErrorMessage: fmt.Sprintf("CNAME loop detected: %s already in traversal chain", follow.Name),
|
||||
},
|
||||
})
|
||||
mu.Unlock()
|
||||
} else if !stack.Push(follow) {
|
||||
mu.Lock()
|
||||
results = append(results, TraversalResult{
|
||||
Referral: follow,
|
||||
@@ -412,12 +425,16 @@ func (t *Traverser) resolveGlueViaSystem(ctx context.Context, name string, cache
|
||||
|
||||
c := &miekgdns.Client{
|
||||
Net: "udp",
|
||||
ReadTimeout: 5,
|
||||
WriteTimeout: 5,
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
}
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
c.ReadTimeout = deadline.Sub(deadline)
|
||||
c.WriteTimeout = deadline.Sub(deadline)
|
||||
remaining := time.Until(deadline)
|
||||
if remaining <= 0 {
|
||||
return nil
|
||||
}
|
||||
c.ReadTimeout = remaining
|
||||
c.WriteTimeout = remaining
|
||||
}
|
||||
|
||||
fqdn := miekgdns.Fqdn(name)
|
||||
|
||||
Reference in New Issue
Block a user