Initial commit
This commit is contained in:
commit
5a632a3b30
24 changed files with 2901 additions and 0 deletions
188
checker/rules_enumeration_test.go
Normal file
188
checker/rules_enumeration_test.go
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
package checker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
// fakeObs round-trips through JSON like the production read path so tests
|
||||
// catch any tag drift between DNSSECData fields and rule expectations.
|
||||
type fakeObs struct{ data *DNSSECData }
|
||||
|
||||
func (f fakeObs) Get(_ context.Context, _ sdk.ObservationKey, dest any) error {
|
||||
if f.data == nil {
|
||||
return nil
|
||||
}
|
||||
raw, err := json.Marshal(f.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(raw, dest)
|
||||
}
|
||||
|
||||
func (fakeObs) GetRelated(_ context.Context, _ sdk.ObservationKey) ([]sdk.RelatedObservation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func run(r sdk.CheckRule, data *DNSSECData, opts sdk.CheckerOptions) []sdk.CheckState {
|
||||
return r.Evaluate(context.Background(), fakeObs{data: data}, opts)
|
||||
}
|
||||
|
||||
func signedZone(denial DenialKind, p *NSEC3ParamObservation) *DNSSECData {
|
||||
return &DNSSECData{
|
||||
Domain: "example.com",
|
||||
Servers: map[string]PerServerView{
|
||||
"ns1.example.com.:53": {
|
||||
Server: "ns1.example.com.:53",
|
||||
DNSKEYs: []DNSKEYRecord{{Flags: 257, Algorithm: 13, KeyTag: 12345, IsKSK: true}},
|
||||
NSEC3PARAM: p,
|
||||
DenialKind: denial,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func wantStatus(t *testing.T, states []sdk.CheckState, want sdk.Status) {
|
||||
t.Helper()
|
||||
if len(states) == 0 {
|
||||
t.Fatalf("no states returned")
|
||||
}
|
||||
if states[0].Status != want {
|
||||
t.Fatalf("status = %v, want %v: %+v", states[0].Status, want, states[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDenialUsesNSEC3(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
data *DNSSECData
|
||||
want sdk.Status
|
||||
}{
|
||||
{
|
||||
name: "NSEC zone is walkable -> WARN",
|
||||
data: signedZone(DenialNSEC, nil),
|
||||
want: sdk.StatusWarn,
|
||||
},
|
||||
{
|
||||
name: "NSEC3 zone -> OK",
|
||||
data: signedZone(DenialNSEC3, &NSEC3ParamObservation{Iterations: 0}),
|
||||
want: sdk.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "OPT-OUT zone -> OK",
|
||||
data: signedZone(DenialOptOut, &NSEC3ParamObservation{Iterations: 0, Flags: 1}),
|
||||
want: sdk.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "Unsigned zone -> INFO",
|
||||
data: &DNSSECData{Domain: "x", Servers: map[string]PerServerView{
|
||||
"ns1:53": {Server: "ns1:53", DenialKind: DenialNone},
|
||||
}},
|
||||
want: sdk.StatusInfo,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
wantStatus(t, run(denialUsesNSEC3Rule{}, tc.data, nil), tc.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNSEC3Iterations(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
iter uint16
|
||||
opts sdk.CheckerOptions
|
||||
want sdk.Status
|
||||
}{
|
||||
{"iter=0 -> OK", 0, nil, sdk.StatusOK},
|
||||
{"iter=1 default ceiling 0 -> WARN", 1, nil, sdk.StatusWarn},
|
||||
{"iter=10 default ceiling 0 -> WARN", 10, nil, sdk.StatusWarn},
|
||||
{"iter=10 ceiling 100 -> OK", 10, sdk.CheckerOptions{"nsec3IterationsMax": float64(100)}, sdk.StatusOK},
|
||||
{"iter=10 severity=crit -> CRIT", 10, sdk.CheckerOptions{"nsec3IterationsSeverity": "crit"}, sdk.StatusCrit},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
data := signedZone(DenialNSEC3, &NSEC3ParamObservation{Iterations: tc.iter})
|
||||
wantStatus(t, run(nsec3IterationsRule{}, data, tc.opts), tc.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNSEC3SaltEmpty(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
saltLength uint8
|
||||
want sdk.Status
|
||||
}{
|
||||
{"empty salt -> OK", 0, sdk.StatusOK},
|
||||
{"non-empty salt -> WARN", 8, sdk.StatusWarn},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
data := signedZone(DenialNSEC3, &NSEC3ParamObservation{
|
||||
Iterations: 0, SaltLength: tc.saltLength, Salt: strings.Repeat("ab", int(tc.saltLength)),
|
||||
})
|
||||
wantStatus(t, run(nsec3SaltEmptyRule{}, data, nil), tc.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNSEC3OptOut(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
flags uint8
|
||||
want sdk.Status
|
||||
}{
|
||||
{"OPT-OUT off -> OK", 0, sdk.StatusOK},
|
||||
{"OPT-OUT on -> INFO", 1, sdk.StatusInfo},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
data := signedZone(DenialNSEC3, &NSEC3ParamObservation{Iterations: 0, Flags: tc.flags})
|
||||
wantStatus(t, run(nsec3OptOutRule{}, data, nil), tc.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDenialConsistent(t *testing.T) {
|
||||
consistent := &DNSSECData{
|
||||
Domain: "x",
|
||||
Servers: map[string]PerServerView{
|
||||
"ns1:53": {Server: "ns1:53", DenialKind: DenialNSEC3},
|
||||
"ns2:53": {Server: "ns2:53", DenialKind: DenialNSEC3},
|
||||
},
|
||||
}
|
||||
wantStatus(t, run(denialConsistentRule{}, consistent, nil), sdk.StatusOK)
|
||||
|
||||
drifting := &DNSSECData{
|
||||
Domain: "x",
|
||||
Servers: map[string]PerServerView{
|
||||
"ns1:53": {Server: "ns1:53", DenialKind: DenialNSEC},
|
||||
"ns2:53": {Server: "ns2:53", DenialKind: DenialNSEC3},
|
||||
},
|
||||
}
|
||||
wantStatus(t, run(denialConsistentRule{}, drifting, nil), sdk.StatusWarn)
|
||||
}
|
||||
|
||||
func TestRoundTripJSON(t *testing.T) {
|
||||
d := signedZone(DenialNSEC3, &NSEC3ParamObservation{Iterations: 0, SaltLength: 0})
|
||||
raw, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var back DNSSECData
|
||||
if err := json.Unmarshal(raw, &back); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if back.Domain != d.Domain {
|
||||
t.Fatalf("domain round-trip lost: %q vs %q", back.Domain, d.Domain)
|
||||
}
|
||||
if got := back.Servers["ns1.example.com.:53"].DenialKind; got != DenialNSEC3 {
|
||||
t.Fatalf("denial round-trip lost: %v", got)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue