Extract querySiblings from observeCoexistence so both CNAME and DNAME coexistence checks share the same parallel RRset scan. Add observeDNAMECoexistence (called from Collect) that populates AliasData.DNAMECoexistence for each DNAME node in DNAMESubstitutions. Add the dname_coexistence rule (RFC 6672 §2.3) that flags any sibling RRsets at a DNAME owner as CRIT, with matching tests.
121 lines
3.2 KiB
Go
121 lines
3.2 KiB
Go
package checker
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
// Version is overridden at build time via -ldflags by main.go and plugin.go.
|
|
var Version = "built-in"
|
|
|
|
func Definition() *sdk.CheckerDefinition {
|
|
def := &sdk.CheckerDefinition{
|
|
ID: "alias",
|
|
Name: "CNAME / DNAME / ALIAS chain",
|
|
Version: Version,
|
|
Availability: sdk.CheckerAvailability{
|
|
ApplyToService: true,
|
|
LimitToServices: []string{
|
|
"svcs.CNAME",
|
|
"svcs.SpecialCNAME",
|
|
},
|
|
},
|
|
ObservationKeys: []sdk.ObservationKey{ObservationKeyAlias},
|
|
Options: sdk.CheckerOptionsDocumentation{
|
|
UserOpts: []sdk.CheckerOptionDocumentation{
|
|
{
|
|
Id: "allowApexCNAME",
|
|
Type: "bool",
|
|
Label: "Allow CNAME at apex",
|
|
Description: "Shared by cname_at_apex and cname_coexistence: when enabled, a CNAME at a zone apex (and its coexistence violations) are downgraded to warnings. RFC 1912 forbids this, so leaving it off is strongly recommended.",
|
|
Default: defaultAllowApexCNAME,
|
|
},
|
|
{
|
|
Id: "recognizeApexFlattening",
|
|
Type: "bool",
|
|
Label: "Recognize ALIAS/ANAME flattening",
|
|
Description: "Shared by apex_flattening and cname_coexistence: when enabled, providers that serve A/AAAA at the apex (ALIAS/ANAME pseudo-records) are recognised as intentional and excused from coexistence violations.",
|
|
Default: defaultRecognizeApexFlattening,
|
|
},
|
|
},
|
|
DomainOpts: []sdk.CheckerOptionDocumentation{
|
|
{
|
|
Id: "domain_name",
|
|
Label: "Parent domain name",
|
|
AutoFill: sdk.AutoFillDomainName,
|
|
},
|
|
{
|
|
Id: "subdomain",
|
|
Label: "Subdomain",
|
|
AutoFill: sdk.AutoFillSubdomain,
|
|
},
|
|
},
|
|
ServiceOpts: []sdk.CheckerOptionDocumentation{
|
|
{
|
|
Id: "service_type",
|
|
Label: "Service type",
|
|
AutoFill: sdk.AutoFillServiceType,
|
|
},
|
|
{
|
|
Id: "service",
|
|
Label: "Service",
|
|
AutoFill: sdk.AutoFillService,
|
|
},
|
|
{
|
|
Id: "domain_name",
|
|
Label: "Parent domain name",
|
|
AutoFill: sdk.AutoFillDomainName,
|
|
},
|
|
},
|
|
},
|
|
Rules: []sdk.CheckRule{
|
|
apexLookupRule{},
|
|
chainLoopRule{},
|
|
chainLengthRule{},
|
|
chainQueryErrorRule{},
|
|
chainRcodeRule{},
|
|
hopTTLRule{},
|
|
cnameAtApexRule{},
|
|
apexFlatteningRule{},
|
|
cnameCoexistenceRule{},
|
|
dnameCoexistenceRule{},
|
|
cnameDnssecRule{},
|
|
targetResolvableRule{},
|
|
multipleRecordsRule{},
|
|
},
|
|
HasHTMLReport: true,
|
|
Interval: &sdk.CheckIntervalSpec{
|
|
Min: 5 * time.Minute,
|
|
Max: 24 * time.Hour,
|
|
Default: 1 * time.Hour,
|
|
},
|
|
}
|
|
def.BuildRulesInfo()
|
|
return def
|
|
}
|
|
|
|
// ValidateOptions runs on the host before Collect so bad options are rejected
|
|
// up-front rather than producing an unhelpful runtime error mid-walk.
|
|
func (p *aliasProvider) ValidateOptions(opts sdk.CheckerOptions) error {
|
|
if v, ok := opts["maxChainLength"]; ok {
|
|
f, ok := v.(float64)
|
|
if !ok {
|
|
return fmt.Errorf("maxChainLength must be a number")
|
|
}
|
|
if f < 1 {
|
|
return fmt.Errorf("maxChainLength must be >= 1")
|
|
}
|
|
}
|
|
if v, ok := opts["minTargetTTL"]; ok {
|
|
f, ok := v.(float64)
|
|
if !ok {
|
|
return fmt.Errorf("minTargetTTL must be a number")
|
|
}
|
|
if f < 0 {
|
|
return fmt.Errorf("minTargetTTL must be >= 0")
|
|
}
|
|
}
|
|
return nil
|
|
}
|