feat: implement iterative DNS resolver

Implement full iterative DNS resolution from root servers through TLD
and domain nameservers using github.com/miekg/dns.

- queryDNS: UDP with retry, TCP fallback on truncation, auto-fallback
  to recursive mode for environments with DNS interception
- FindAuthoritativeNameservers: traces delegation chain from roots,
  walks up label hierarchy for subdomain lookups
- QueryNameserver: queries all record types (A/AAAA/CNAME/MX/TXT/SRV/
  CAA/NS) with proper status classification
- QueryAllNameservers: discovers auth NSes then queries each
- LookupNS: delegates to FindAuthoritativeNameservers
- ResolveIPAddresses: queries all NSes, follows CNAMEs (depth 10),
  deduplicates and sorts results

31/35 tests pass. 4 NXDOMAIN tests fail due to wildcard DNS on
sneak.cloud (nxdomain-surely-does-not-exist.dns.sneak.cloud resolves
to datavi.be/162.55.148.94 via catch-all). NXDOMAIN detection is
correct (checks rcode==NXDOMAIN) but the zone doesn't return NXDOMAIN.
This commit is contained in:
clawbot
2026-02-19 14:15:02 -08:00
committed by user
parent e92d47f052
commit 04855d0e5f
4 changed files with 735 additions and 68 deletions

View File

@@ -4,7 +4,6 @@
package resolver
import (
"context"
"log/slog"
"go.uber.org/fx"
@@ -59,65 +58,5 @@ func NewFromLogger(log *slog.Logger) *Resolver {
return &Resolver{log: log}
}
// FindAuthoritativeNameservers traces the delegation chain from
// root servers to discover all authoritative nameservers for the
// given domain. Returns the NS hostnames (e.g. ["ns1.example.com.",
// "ns2.example.com."]).
func (r *Resolver) FindAuthoritativeNameservers(
_ context.Context,
_ string,
) ([]string, error) {
return nil, ErrNotImplemented
}
// Method implementations are in iterative.go.
// QueryNameserver queries a specific authoritative nameserver for
// all supported record types (A, AAAA, CNAME, MX, TXT, SRV, CAA,
// NS) for the given hostname. Returns a NameserverResponse with
// per-type record slices and a status indicating success or the
// type of failure.
func (r *Resolver) QueryNameserver(
_ context.Context,
_ string,
_ string,
) (*NameserverResponse, error) {
return nil, ErrNotImplemented
}
// QueryAllNameservers discovers the authoritative nameservers for
// the hostname's parent domain, then queries each one independently.
// Returns a map from nameserver hostname to its response.
func (r *Resolver) QueryAllNameservers(
_ context.Context,
_ string,
) (map[string]*NameserverResponse, error) {
return nil, ErrNotImplemented
}
// LookupNS returns the NS record set for a domain by performing
// iterative resolution. This is used for domain (apex) monitoring.
func (r *Resolver) LookupNS(
_ context.Context,
_ string,
) ([]string, error) {
return nil, ErrNotImplemented
}
// LookupAllRecords performs iterative resolution to find all DNS
// records for the given hostname, keyed by authoritative nameserver.
func (r *Resolver) LookupAllRecords(
_ context.Context,
_ string,
) (map[string]map[string][]string, error) {
return nil, ErrNotImplemented
}
// ResolveIPAddresses resolves a hostname to all IPv4 and IPv6
// addresses by querying all authoritative nameservers and following
// CNAME chains up to MaxCNAMEDepth. Returns a deduplicated list
// of IP address strings.
func (r *Resolver) ResolveIPAddresses(
_ context.Context,
_ string,
) ([]string, error) {
return nil, ErrNotImplemented
}