Files
dnswatcher/internal/resolver/export_test.go
T
sneak a771f51b0b
check / check (push) Successful in 1m20s
resolver, watcher: a domain's nameservers are only its own delegation (closes #222)
When a domain's parent zone's servers answer NXDOMAIN, LookupNS returns
ErrNXDomain. The watcher then saves the domain with no nameservers and
nxdomain set, shown on the dashboard and in /api/v1/status, asks for none
of its records and removes those saved, so its old nameservers go in one
NS Change. A domain with no delegation of its own gets an empty set and
its records are still asked at the zone it is in.
FindAuthoritativeNameservers moves to a parent name only on one of those
two answers; when the servers do not answer, it returns the error. After
an upgrade, a domain without its own delegation that was saved with its
parent zone's nameservers gets one NS Change; the README says so.

Model: opus-5-5
2026-10-02 10:24:40 +00:00

147 lines
3.6 KiB
Go

package resolver
import (
"context"
"log/slog"
"time"
"github.com/miekg/dns"
)
// NewWithFailingTCP returns a Resolver whose TCP client gives up before
// it can connect, so the retry over TCP of every truncated reply fails.
func NewWithFailingTCP(log *slog.Logger) *Resolver {
r := NewFromLogger(log)
r.tcp = &tcpClient{timeout: time.Nanosecond}
return r
}
// NewWithQueryTimeout returns a Resolver whose queries over UDP give up
// after timeout, so a test that asks an address where nothing answers
// does not wait out the usual timeout.
func NewWithQueryTimeout(log *slog.Logger, timeout time.Duration) *Resolver {
r := NewFromLogger(log)
r.client = &udpClient{timeout: timeout}
return r
}
// FollowDelegation exports followDelegation for testing.
func (r *Resolver) FollowDelegation(
ctx context.Context,
domain string,
servers []string,
) ([]string, error) {
return r.followDelegation(ctx, domain, servers)
}
// FindAuthoritativeNameserversFrom exports findAuthoritativeNameservers
// for testing.
func (r *Resolver) FindAuthoritativeNameserversFrom(
ctx context.Context,
domain string,
servers []string,
) ([]string, error) {
return r.findAuthoritativeNameservers(ctx, domain, servers)
}
// ResolveNSIterative exports resolveNSIterative for testing.
func (r *Resolver) ResolveNSIterative(
ctx context.Context,
domain string,
) ([]string, error) {
return r.resolveNSIterative(ctx, domain)
}
// ExtractRecordValue exports extractRecordValue for testing.
func ExtractRecordValue(rr dns.RR) string {
return extractRecordValue(rr)
}
// CollectAnswerRecords exports collectAnswerRecords for testing.
func CollectAnswerRecords(msg *dns.Msg, resp *NameserverResponse) {
var state queryState
collectAnswerRecords(msg, resp, &state)
}
// UsableReply exports usableReply for testing.
func UsableReply(resp *dns.Msg, zone string, name string) bool {
return usableReply(resp, zone, name)
}
// NSSetFrom exports nsSetFrom for testing.
func NSSetFrom(resp *dns.Msg, domain string) []string {
return nsSetFrom(resp, domain)
}
// CollectIPs exports collectIPs for testing.
func CollectIPs(
results map[string]*NameserverResponse,
) ([]string, string, error) {
return collectIPs(results)
}
// QueryServers exports queryServers for testing.
func (r *Resolver) QueryServers(
ctx context.Context,
servers []string,
zone string,
name string,
qtype uint16,
) (*dns.Msg, error) {
return r.queryServers(ctx, servers, zone, name, qtype)
}
// QueryEachNS exports queryEachNS for testing.
func (r *Resolver) QueryEachNS(
ctx context.Context,
nameservers []string,
hostname string,
) (map[string]*NameserverResponse, error) {
return r.queryEachNS(ctx, nameservers, hostname, recordTypes())
}
// ResolveNSIPs exports resolveNSIPs for testing, looking each name up
// as a lookup that no other lookup started.
func (r *Resolver) ResolveNSIPs(
ctx context.Context,
nsNames []string,
) []string {
ips, _ := r.resolveNSIPs(ctx, nsNames, 1)
return ips
}
// MaxLookupDepth exports maxLookupDepth for testing.
const MaxLookupDepth = maxLookupDepth
// QueryZone exports queryZone for testing.
func (r *Resolver) QueryZone(
ctx context.Context,
given []string,
withoutAddresses []string,
zone string,
name string,
qtype uint16,
depth int,
) (*dns.Msg, error) {
return r.queryZone(
ctx, given, withoutAddresses, zone, name, qtype, depth,
)
}
// RootServerList exports rootServerList for testing.
func RootServerList() []string {
return rootServerList()
}
// Shuffled exports shuffled for testing.
func Shuffled(
servers []string,
shuffle func(n int, swap func(i, j int)),
) []string {
return shuffled(servers, shuffle)
}