Derive probed record types from the working zone
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

Stop blindly probing a fixed list (which always included CAA): read the
auto-filled zone and only probe the RR types each owner actually has,
keeping SOA/NS at the apex. The recordTypes option still works as an
explicit override; missing zone falls back to the legacy default.
This commit is contained in:
nemunaire 2026-05-25 18:22:09 +08:00
commit 7d23348098
5 changed files with 367 additions and 15 deletions

View file

@ -34,7 +34,7 @@ func (p *resolverPropagationProvider) Collect(ctx context.Context, opts sdk.Chec
includeFiltered := sdk.GetBoolOption(opts, "includeFiltered", false)
region := getStringOpt(opts, "region", "all")
transportsOpt := getStringOpt(opts, "transports", "udp")
recordTypesOpt := getStringOpt(opts, "recordTypes", "SOA,NS,A,AAAA,MX,TXT,CAA")
recordTypesOpt := getStringOpt(opts, "recordTypes", "")
subdomainsOpt := getStringOpt(opts, "subdomains", "")
runTimeoutS := sdk.GetIntOption(opts, "runTimeoutSeconds", 30)
allowlistOpt := getStringOpt(opts, "resolverAllowlist", "")
@ -44,15 +44,12 @@ func (p *resolverPropagationProvider) Collect(ctx context.Context, opts sdk.Chec
if len(transports) == 0 {
transports = []string{string(TransportUDP)}
}
qtypes := parseQTypes(recordTypesOpt)
if len(qtypes) == 0 {
return nil, fmt.Errorf("no valid record types in %q", recordTypesOpt)
}
extraNames := parseCSV(subdomainsOpt)
allowlist := parseCSV(allowlistOpt)
// Build the list of owner names to probe.
names := []string{dns.Fqdn(zone)}
apex := dns.Fqdn(zone)
names := []string{apex}
seenName := map[string]bool{names[0]: true}
for _, sd := range extraNames {
full := joinSubdomain(sd, zone)
@ -62,12 +59,20 @@ func (p *resolverPropagationProvider) Collect(ctx context.Context, opts sdk.Chec
}
}
// Pick the RR types to probe at each owner. An explicit recordTypes
// option overrides everything; otherwise we derive the per-owner type
// set from the working zone (when the host auto-filled it).
ownerQTypes, typeUnion, err := resolveQTypes(opts, recordTypesOpt, apex, names)
if err != nil {
return nil, err
}
resolvers := selectedResolvers(includeFiltered, region, allowlist)
data := &ResolverPropagationData{
Zone: dns.Fqdn(zone),
Names: names,
Types: qtypeNames(qtypes),
Types: qtypeNames(typeUnion),
Resolvers: map[string]*ResolverView{},
RRsets: map[string]*RRsetView{},
}
@ -88,10 +93,10 @@ func (p *resolverPropagationProvider) Collect(ctx context.Context, opts sdk.Chec
started := time.Now()
// Ground truth from the zone's own authoritative servers.
expected := collectExpected(runCtx, zone, svc, names, qtypes)
expected := collectExpectedPerOwner(runCtx, zone, svc, ownerQTypes)
for _, n := range names {
for _, qt := range qtypes {
for _, qt := range ownerQTypes[n] {
key := rrsetKey(n, dns.TypeToString[qt])
v := &RRsetView{
Name: strings.ToLower(dns.Fqdn(n)),
@ -158,7 +163,7 @@ func (p *resolverPropagationProvider) Collect(ctx context.Context, opts sdk.Chec
}
for _, n := range names {
for _, qt := range qtypes {
for _, qt := range ownerQTypes[n] {
probe := runProbe(runCtx, job.r, job.tr, n, qt)
key := rrsetKey(n, dns.TypeToString[qt])
view.Probes[key] = probe
@ -207,7 +212,7 @@ type expectedEntry struct {
records []string
}
func collectExpected(ctx context.Context, zone string, svc *originService, names []string, qtypes []uint16) map[string]*expectedEntry {
func collectExpectedPerOwner(ctx context.Context, zone string, svc *originService, ownerQTypes map[string][]uint16) map[string]*expectedEntry {
out := map[string]*expectedEntry{}
var nsHosts []string
@ -244,7 +249,7 @@ func collectExpected(ctx context.Context, zone string, svc *originService, names
return out
}
for _, n := range names {
for n, qtypes := range ownerQTypes {
for _, qt := range qtypes {
key := rrsetKey(n, dns.TypeToString[qt])
if e := queryAuthoritative(ctx, authAddrs, n, qt); e != nil {