78 lines
2.6 KiB
Go
78 lines
2.6 KiB
Go
package checker
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
// DNS-level rules: lookup outcome, record presence, service/DNS parity,
|
|
// DNSSEC authentication, and owner-name hash correctness. These apply
|
|
// to both OPENPGPKEY and SMIMEA records.
|
|
|
|
func checkDNSQueryFailed(d *EmailKeyData, _ sdk.CheckerOptions) []issue {
|
|
if d.DNSQueryError == "" {
|
|
return nil
|
|
}
|
|
return []issue{{
|
|
Severity: sdk.StatusCrit,
|
|
Message: d.DNSQueryError,
|
|
Hint: "Check that the zone is published at an authoritative server reachable from this checker.",
|
|
}}
|
|
}
|
|
|
|
func checkDNSNoRecord(d *EmailKeyData, _ sdk.CheckerOptions) []issue {
|
|
if d.DNSAnswerPresent == nil || *d.DNSAnswerPresent {
|
|
return nil
|
|
}
|
|
kind := "OPENPGPKEY"
|
|
if d.Kind == KindSMIMEA {
|
|
kind = "SMIMEA"
|
|
}
|
|
return []issue{{
|
|
Severity: sdk.StatusCrit,
|
|
Message: fmt.Sprintf("Authoritative DNS returned no %s record at %s.", kind, d.QueriedOwner),
|
|
Hint: "Ensure the record is present in the zone and that the zone has been loaded by the authoritative servers.",
|
|
}}
|
|
}
|
|
|
|
func checkDNSRecordMismatch(d *EmailKeyData, _ sdk.CheckerOptions) []issue {
|
|
if d.DNSRecordMatchesService == nil || *d.DNSRecordMatchesService {
|
|
return nil
|
|
}
|
|
return []issue{{
|
|
Severity: sdk.StatusWarn,
|
|
Message: "The record returned by DNS does not match the one declared in the service. The zone may not have been re-published since the last edit.",
|
|
Hint: "Propagate the zone to the authoritative servers, then wait for TTL/negative-cache expiry.",
|
|
}}
|
|
}
|
|
|
|
func checkDNSSECNotValidated(d *EmailKeyData, opts sdk.CheckerOptions) []issue {
|
|
if d.DNSSECSecure == nil || *d.DNSSECSecure {
|
|
return nil
|
|
}
|
|
sev := sdk.StatusWarn
|
|
if sdk.GetBoolOption(opts, OptionRequireDNSSEC, true) {
|
|
sev = sdk.StatusCrit
|
|
}
|
|
return []issue{{
|
|
Severity: sev,
|
|
Message: "The validating resolver did not set the AD flag: the record is not DNSSEC-authenticated, which defeats the whole DANE trust model.",
|
|
Hint: "Sign the zone with DNSSEC and publish the DS record at the parent so RFC 7929/8162 consumers can authenticate the key.",
|
|
}}
|
|
}
|
|
|
|
func checkOwnerHashMismatch(d *EmailKeyData, _ sdk.CheckerOptions) []issue {
|
|
if d.ExpectedOwnerPrefix == "" || d.ObservedOwnerPrefix == "" {
|
|
return nil
|
|
}
|
|
if strings.EqualFold(d.ObservedOwnerPrefix, d.ExpectedOwnerPrefix) {
|
|
return nil
|
|
}
|
|
return []issue{{
|
|
Severity: sdk.StatusCrit,
|
|
Message: fmt.Sprintf("Owner name prefix %q does not match SHA-256(%q)[:28]=%q.", d.ObservedOwnerPrefix, d.Username, d.ExpectedOwnerPrefix),
|
|
Hint: "Republish the record at the hash-derived name for the intended user, or update the Username field to match the record's owner name.",
|
|
}}
|
|
}
|