Move status inference out of observation layer into rules
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
The prober (collect.go) was calling inferApexDNSKEYStatus during zone parsing, effectively making a SECURE/BOGUS judgement inside the collection phase rather than the evaluation phase. The DNS-rcode fallback (z.Status = z.DNSStatus) was also applied at parse time.
This commit is contained in:
parent
5591df021b
commit
4543e9b0cf
6 changed files with 110 additions and 83 deletions
|
|
@ -59,18 +59,12 @@ func decodeZone(raw json.RawMessage) ZoneAnalysis {
|
|||
z.Status = s
|
||||
}
|
||||
}
|
||||
// Root has no parent and therefore no delegation block. dnsviz signals
|
||||
// trust-anchor validation through the RRSIG covering the apex DNSKEY
|
||||
// rrset (queries.<zone>/IN/DNSKEY.answer[*].rrsig[*].status). With
|
||||
// `dnsviz grok -t …` and a matching anchor, that RRSIG becomes VALID
|
||||
// and we lift the zone to SECURE; an INVALID/EXPIRED RRSIG drags it
|
||||
// to BOGUS. Without a trust anchor, this leaves Status empty and we
|
||||
// fall back to the DNS rcode below.
|
||||
if z.Status == "" {
|
||||
z.Status = inferApexDNSKEYStatus(m["queries"])
|
||||
}
|
||||
if z.Status == "" {
|
||||
z.Status = z.DNSStatus
|
||||
// Store raw queries so rules can infer the zone status from RRSIG
|
||||
// validation when no delegation block is present (e.g. root zone).
|
||||
// Status inference and DNS-rcode fallback are the responsibility of the
|
||||
// evaluation layer (see effectiveStatus in rule.go).
|
||||
if q, ok := m["queries"].(map[string]any); ok {
|
||||
z.Queries = q
|
||||
}
|
||||
|
||||
z.Errors, z.Warnings = collectFindings(m, "")
|
||||
|
|
@ -181,62 +175,6 @@ func makeFinding(item any, codeHint, path string) Finding {
|
|||
return f
|
||||
}
|
||||
|
||||
// inferApexDNSKEYStatus returns "SECURE", "BOGUS", or "" based on the
|
||||
// status of RRSIGs covering the zone's apex DNSKEY rrset. dnsviz attaches
|
||||
// a per-RRSIG status whenever a key reaches it (either through DS from
|
||||
// the parent or through a configured trust anchor at this zone). For
|
||||
// the root, this is the only place where trust-anchor validation
|
||||
// surfaces in the grok output.
|
||||
//
|
||||
// queries is the value at zone["queries"], a map keyed by
|
||||
// "<zone>/IN/<RRTYPE>". We pick the DNSKEY query and look at every
|
||||
// RRSIG inside its answer.
|
||||
func inferApexDNSKEYStatus(queries any) string {
|
||||
q, ok := queries.(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
var dnskeyQ map[string]any
|
||||
for k, v := range q {
|
||||
if !strings.HasSuffix(k, "/IN/DNSKEY") {
|
||||
continue
|
||||
}
|
||||
if m, ok := v.(map[string]any); ok {
|
||||
dnskeyQ = m
|
||||
break
|
||||
}
|
||||
}
|
||||
if dnskeyQ == nil {
|
||||
return ""
|
||||
}
|
||||
answers, _ := dnskeyQ["answer"].([]any)
|
||||
sawValid := false
|
||||
for _, a := range answers {
|
||||
am, _ := a.(map[string]any)
|
||||
if am == nil {
|
||||
continue
|
||||
}
|
||||
rrsigs, _ := am["rrsig"].([]any)
|
||||
for _, rs := range rrsigs {
|
||||
rm, _ := rs.(map[string]any)
|
||||
if rm == nil {
|
||||
continue
|
||||
}
|
||||
s, _ := rm["status"].(string)
|
||||
switch strings.ToUpper(s) {
|
||||
case "INVALID", "BOGUS", "EXPIRED", "PREMATURE":
|
||||
return "BOGUS"
|
||||
case "VALID", "SECURE":
|
||||
sawValid = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if sawValid {
|
||||
return "SECURE"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func labelDepth(zone string) int {
|
||||
z := strings.TrimSuffix(zone, ".")
|
||||
if z == "" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue