CI / test (pull_request) Failing after 2m40s
Add core traversal engine with iterative resolution from root servers: - referral.go: Referral struct with name, type, bailiwick, addresses, state - cache.go: Chained InfoCache with parent inheritance for NS and glue records - stack.go: LIFO stack with configurable max depth enforcement - response.go: Response classifier (referral, answer, CNAME follow, NODATA, NXDOMAIN, SERVFAIL) with child referral generation and probability splitting - traverser.go: Traverser orchestrates full traversal from root to leaf, following all referral branches, handling CNAME chains, and respecting max depth limits Add IterativeQuery/IterativeQueryWithExchange to dns package (RD=false queries). 57 new tests covering all acceptance criteria: traversal from root to leaf, comprehensive branch following, max depth enforcement, probability distribution, chained cache behavior, CNAME following, NXDOMAIN/SERVFAIL handling, context cancellation, and concurrent access. Co-authored-by: multica-agent <github@multica.ai>
79 lines
1.4 KiB
Go
79 lines
1.4 KiB
Go
package traverse
|
|
|
|
import (
|
|
"net"
|
|
"strings"
|
|
|
|
miekgdns "github.com/miekg/dns"
|
|
)
|
|
|
|
type ResolutionState int
|
|
|
|
const (
|
|
StateUnresolved ResolutionState = iota
|
|
StateResolving
|
|
StateResolved
|
|
)
|
|
|
|
func (s ResolutionState) String() string {
|
|
switch s {
|
|
case StateUnresolved:
|
|
return "unresolved"
|
|
case StateResolving:
|
|
return "resolving"
|
|
case StateResolved:
|
|
return "resolved"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
type Referral struct {
|
|
Name string
|
|
Qtype uint16
|
|
Qclass uint16
|
|
Bailiwick string
|
|
|
|
Addresses []net.IP
|
|
State ResolutionState
|
|
|
|
NSName string
|
|
Parent *Referral
|
|
Depth int
|
|
Prob float64
|
|
}
|
|
|
|
func NewReferral(name string, qtype uint16, bailiwick string, depth int, prob float64, parent *Referral) *Referral {
|
|
return &Referral{
|
|
Name: miekgdns.Fqdn(strings.ToLower(name)),
|
|
Qtype: qtype,
|
|
Qclass: miekgdns.ClassINET,
|
|
Bailiwick: miekgdns.Fqdn(strings.ToLower(bailiwick)),
|
|
Depth: depth,
|
|
Prob: prob,
|
|
Parent: parent,
|
|
State: StateUnresolved,
|
|
}
|
|
}
|
|
|
|
func (r *Referral) InBailiwick(name string) bool {
|
|
if r.Bailiwick == "" || r.Bailiwick == "." {
|
|
return true
|
|
}
|
|
fqdn := miekgdns.Fqdn(strings.ToLower(name))
|
|
return miekgdns.IsSubDomain(r.Bailiwick, fqdn)
|
|
}
|
|
|
|
func (r *Referral) HasAddresses() bool {
|
|
return len(r.Addresses) > 0
|
|
}
|
|
|
|
func (r *Referral) SetAddresses(addrs []net.IP) {
|
|
r.Addresses = addrs
|
|
if len(addrs) > 0 {
|
|
r.State = StateResolved
|
|
} else {
|
|
r.State = StateUnresolved
|
|
}
|
|
}
|