100 lines
3.5 KiB
Go
100 lines
3.5 KiB
Go
package checker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
type nsDeclaredRule struct{}
|
|
|
|
func (r *nsDeclaredRule) Name() string { return "authoritative_consistency.ns_declared" }
|
|
func (r *nsDeclaredRule) Description() string {
|
|
return "Verifies the service declares at least the recommended number of name servers and that at least one name server could be discovered."
|
|
}
|
|
|
|
func (r *nsDeclaredRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
data, errSt := loadObservation(ctx, obs)
|
|
if errSt != nil {
|
|
return []sdk.CheckState{*errSt}
|
|
}
|
|
minNS := sdk.GetIntOption(opts, "minNameServers", 2)
|
|
useParentNS := sdk.GetBoolOption(opts, "useParentNS", true)
|
|
|
|
var findings []Finding
|
|
|
|
if len(data.DeclaredNS) == 0 && !useParentNS {
|
|
findings = append(findings, Finding{
|
|
Code: CodeNoNS,
|
|
Severity: SeverityCrit,
|
|
Message: "no name servers declared in the service and parent cross-check is disabled",
|
|
})
|
|
}
|
|
if len(data.Probed) == 0 {
|
|
findings = append(findings, Finding{
|
|
Code: CodeNoNS,
|
|
Severity: SeverityCrit,
|
|
Message: "no authoritative name servers could be discovered (declared list empty and parent query empty)",
|
|
})
|
|
}
|
|
if len(data.DeclaredNS) > 0 && len(data.DeclaredNS) < minNS {
|
|
findings = append(findings, Finding{
|
|
Code: CodeTooFewNS,
|
|
Severity: SeverityWarn,
|
|
Message: fmt.Sprintf("only %d name server(s) declared, RFC 1034 recommends at least %d", len(data.DeclaredNS), minNS),
|
|
})
|
|
}
|
|
|
|
if len(findings) == 0 {
|
|
return []sdk.CheckState{passState("authoritative_consistency.ns_declared.ok", fmt.Sprintf("%d name server(s) declared", len(data.DeclaredNS)))}
|
|
}
|
|
return findingsToStates(findings)
|
|
}
|
|
|
|
type parentDelegationRule struct{}
|
|
|
|
func (r *parentDelegationRule) Name() string { return "authoritative_consistency.parent_delegation" }
|
|
func (r *parentDelegationRule) Description() string {
|
|
return "Cross-checks the NS RRset returned by the parent zone's referral with the NS declared in the service."
|
|
}
|
|
|
|
func (r *parentDelegationRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
useParentNS := sdk.GetBoolOption(opts, "useParentNS", true)
|
|
if !useParentNS {
|
|
return []sdk.CheckState{notTestedState("authoritative_consistency.parent_delegation.skipped", "Parent delegation cross-check disabled by option.")}
|
|
}
|
|
data, errSt := loadObservation(ctx, obs)
|
|
if errSt != nil {
|
|
return []sdk.CheckState{*errSt}
|
|
}
|
|
|
|
var findings []Finding
|
|
if data.ParentQueryError != "" {
|
|
findings = append(findings, Finding{
|
|
Code: CodeParentQueryFailed,
|
|
Severity: SeverityWarn,
|
|
Message: fmt.Sprintf("parent delegation query failed: %s", data.ParentQueryError),
|
|
})
|
|
} else if len(data.DeclaredNS) > 0 && len(data.ParentNS) > 0 {
|
|
missing, extra := diffStringSets(data.DeclaredNS, data.ParentNS)
|
|
if len(missing) > 0 || len(extra) > 0 {
|
|
findings = append(findings, Finding{
|
|
Code: CodeParentDrift,
|
|
Severity: SeverityWarn,
|
|
Message: fmt.Sprintf(
|
|
"NS RRset at parent does not match declared service: missing=%v extra=%v",
|
|
missing, extra,
|
|
),
|
|
})
|
|
}
|
|
}
|
|
|
|
if len(findings) == 0 {
|
|
if len(data.ParentNS) == 0 {
|
|
return []sdk.CheckState{notTestedState("authoritative_consistency.parent_delegation.skipped", "No parent delegation observed.")}
|
|
}
|
|
return []sdk.CheckState{passState("authoritative_consistency.parent_delegation.ok", "Parent delegation matches the declared NS list.")}
|
|
}
|
|
return findingsToStates(findings)
|
|
}
|