Phase 4.1: Error handling, edge cases, and robustness (#11)
CI / test (push) Failing after 2m36s
CI / test (push) Failing after 2m36s
This commit was merged in pull request #11.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hits/ExploreDNS/internal/dns"
|
||||
miekgdns "github.com/miekg/dns"
|
||||
@@ -17,6 +18,12 @@ type TraverserConfig struct {
|
||||
QueryConfig *dns.QueryConfig
|
||||
RootAddrs []net.IP
|
||||
Hooks *TraverserHooks
|
||||
// Fast controls cache sharing across branches. When true (default), child
|
||||
// branches inherit glue discovered by earlier branches via the shared root
|
||||
// cache, trading accuracy for speed. When false, each branch gets a
|
||||
// completely independent cache — slower but results are not contaminated by
|
||||
// sibling branch observations.
|
||||
Fast bool
|
||||
}
|
||||
|
||||
func DefaultTraverserConfig() *TraverserConfig {
|
||||
@@ -26,6 +33,7 @@ func DefaultTraverserConfig() *TraverserConfig {
|
||||
RootConfig: nil,
|
||||
QueryConfig: nil,
|
||||
RootAddrs: nil,
|
||||
Fast: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,9 +105,19 @@ func (t *Traverser) Traverse(ctx context.Context, name string) ([]TraversalResul
|
||||
break
|
||||
}
|
||||
|
||||
cache := rootCache
|
||||
if ref.Parent != nil {
|
||||
cache = rootCache.Child()
|
||||
var cache *InfoCache
|
||||
if t.config.Fast {
|
||||
// Fast mode: inherit glue from the shared root cache so earlier
|
||||
// branch discoveries are visible to later branches.
|
||||
cache = rootCache
|
||||
if ref.Parent != nil {
|
||||
cache = rootCache.Child()
|
||||
}
|
||||
} else {
|
||||
// Non-fast mode: every referral gets its own independent cache so
|
||||
// no cross-branch glue is reused, ensuring each path is resolved
|
||||
// from scratch.
|
||||
cache = NewInfoCache(nil)
|
||||
}
|
||||
|
||||
if t.config.Hooks != nil {
|
||||
@@ -141,7 +159,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 +442,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