checker-ns-restrictions/checker/rule.go

80 lines
2.3 KiB
Go

package checker
import (
"context"
"fmt"
sdk "git.happydns.org/checker-sdk-go/checker"
)
// Rules returns one CheckRule per individual NS security concern. Every rule
// reads the same shared observation produced by Collect and only looks at
// its own facet of the raw probe data, so a single network round trip feeds
// every rule.
func Rules() []sdk.CheckRule {
return []sdk.CheckRule{
&resolutionRule{},
&axfrRule{},
&ixfrRule{},
&noRecursionRule{},
&anyRFC8482Rule{},
&authoritativeRule{},
}
}
// loadReport fetches the shared NS observation. On error it returns a
// CheckState the caller should emit verbatim to short-circuit its rule.
func loadReport(ctx context.Context, obs sdk.ObservationGetter, errCode string) (*NSRestrictionsReport, *sdk.CheckState) {
var report NSRestrictionsReport
if err := obs.Get(ctx, ObservationKeyNSRestrictions, &report); err != nil {
return nil, &sdk.CheckState{
Status: sdk.StatusError,
Message: fmt.Sprintf("Failed to get NS restrictions data: %v", err),
Code: errCode,
}
}
return &report, nil
}
// serverLabel returns a human-friendly subject for a given server result.
func serverLabel(srv NSServerResult) string {
if srv.Address == "" {
return srv.Name
}
return fmt.Sprintf("%s (%s)", srv.Name, srv.Address)
}
// serverMeta returns the per-server meta blob attached to every state a
// rule produces.
func serverMeta(srv NSServerResult) map[string]any {
return map[string]any{
"name": srv.Name,
"address": srv.Address,
}
}
// probedServers returns only the servers that were actually probed
// (i.e. DNS-resolved and not skipped). Rules that need to iterate over
// probe results should call this helper to transparently skip the
// resolution-error and address-skipped rows, which are the concern of
// the dedicated resolutionRule.
func probedServers(report *NSRestrictionsReport) []NSServerResult {
out := make([]NSServerResult, 0, len(report.Servers))
for _, s := range report.Servers {
if s.ResolutionError != "" || s.AddressSkipped {
continue
}
out = append(out, s)
}
return out
}
// noProbesState returns the default state emitted when a rule has nothing to
// evaluate (no server was successfully probed).
func noProbesState(code string) sdk.CheckState {
return sdk.CheckState{
Status: sdk.StatusUnknown,
Message: "no nameserver could be probed",
Code: code,
}
}