93 lines
3 KiB
Go
93 lines
3 KiB
Go
package checker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
type apexLookupRule struct{}
|
|
|
|
func (apexLookupRule) Name() string { return "apex_lookup" }
|
|
func (apexLookupRule) Description() string {
|
|
return "Verifies the zone apex (SOA) of the checked name can be located."
|
|
}
|
|
|
|
func (apexLookupRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, _ sdk.CheckerOptions) []sdk.CheckState {
|
|
data, errState := loadAlias(ctx, obs)
|
|
if errState != nil {
|
|
return errState
|
|
}
|
|
if data.Apex != "" {
|
|
return okState(data.Apex, fmt.Sprintf("apex %s located", data.Apex))
|
|
}
|
|
return []sdk.CheckState{withHint(sdk.CheckState{
|
|
Status: sdk.StatusCrit,
|
|
Subject: data.Owner,
|
|
Message: fmt.Sprintf("could not locate zone apex: %s", data.ApexLookupError),
|
|
}, "Check that the parent delegation exists and that the zone is published.")}
|
|
}
|
|
|
|
type cnameAtApexRule struct{}
|
|
|
|
func (cnameAtApexRule) Name() string { return "cname_at_apex" }
|
|
func (cnameAtApexRule) Description() string {
|
|
return "Flags a CNAME at the zone apex, which conflicts with the SOA/NS records the apex must carry (RFC 1912 §2.4). Honours the shared allowApexCNAME option."
|
|
}
|
|
|
|
func (cnameAtApexRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
data, errState := loadAlias(ctx, obs)
|
|
if errState != nil {
|
|
return errState
|
|
}
|
|
if !apexKnown(data) {
|
|
return skipped("apex lookup failed")
|
|
}
|
|
if !data.OwnerIsApex {
|
|
return skipped("owner is not the zone apex")
|
|
}
|
|
if !data.ApexHasCNAME {
|
|
return okState(data.Apex, "no CNAME at apex")
|
|
}
|
|
status := sdk.StatusCrit
|
|
if allowApexCNAME(opts) {
|
|
status = sdk.StatusWarn
|
|
}
|
|
return []sdk.CheckState{withHint(sdk.CheckState{
|
|
Status: status,
|
|
Subject: data.Apex,
|
|
Message: fmt.Sprintf("CNAME at apex %s conflicts with SOA/NS (RFC 1912 §2.4)", data.Apex),
|
|
}, "Use the provider's ALIAS/ANAME flattening, an HTTP redirect, or move content to a sub-label such as www.")}
|
|
}
|
|
|
|
type apexFlatteningRule struct{}
|
|
|
|
func (apexFlatteningRule) Name() string { return "apex_flattening" }
|
|
func (apexFlatteningRule) Description() string {
|
|
return "Notes ALIAS/ANAME provider-side flattening (A/AAAA served at apex alongside SOA/NS)."
|
|
}
|
|
|
|
func (apexFlatteningRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
data, errState := loadAlias(ctx, obs)
|
|
if errState != nil {
|
|
return errState
|
|
}
|
|
if !apexKnown(data) {
|
|
return skipped("apex lookup failed")
|
|
}
|
|
if !data.OwnerIsApex {
|
|
return skipped("owner is not the zone apex")
|
|
}
|
|
if !data.ApexFlattening {
|
|
return okState(data.Apex, "no ALIAS/ANAME flattening detected")
|
|
}
|
|
if !recognizeApexFlattening(opts) {
|
|
return skipped("recognizeApexFlattening disabled")
|
|
}
|
|
return []sdk.CheckState{withHint(sdk.CheckState{
|
|
Status: sdk.StatusInfo,
|
|
Subject: data.Apex,
|
|
Message: fmt.Sprintf("apex %s serves A/AAAA directly (provider-side ALIAS/ANAME flattening)", data.Apex),
|
|
}, "Keep the upstream target's TTL in mind: apex A/AAAA will only update as fast as the provider re-flattens.")}
|
|
}
|