checker-delegation/checker/types.go

110 lines
4.1 KiB
Go

// This file is part of the happyDomain (R) project.
// Copyright (c) 2026 happyDomain
// Authors: Pierre-Olivier Mercier, et al.
//
// This program is offered under a commercial and under the AGPL license.
// For commercial licensing, contact us at <contact@happydomain.org>.
//
// For AGPL licensing:
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package checker
import (
"encoding/json"
"github.com/miekg/dns"
)
// ObservationKeyDelegation is the observation key for delegation data.
const ObservationKeyDelegation = "delegation"
// Severity classifies a finding emitted by the delegation checker.
type Severity string
const (
SeverityInfo Severity = "info"
SeverityWarn Severity = "warn"
SeverityCrit Severity = "crit"
)
// DelegationFinding describes a single observation produced while running
// the delegation testsuite.
type DelegationFinding struct {
// Code is a stable machine-readable identifier (e.g. "delegation_ns_mismatch").
Code string `json:"code"`
// Severity grades the finding.
Severity Severity `json:"severity"`
// Message is a human-readable explanation.
Message string `json:"message"`
// Server is the DNS server that exhibited the finding (parent or child),
// when applicable. Empty for findings tied to the service definition itself.
Server string `json:"server,omitempty"`
}
// DelegationData is the observation payload stored by the checker. It carries
// every finding emitted by the testsuite plus the raw observed state from the
// parent and from each delegated server.
type DelegationData struct {
// DelegatedFQDN is the FQDN of the delegated zone (subdomain + parent).
DelegatedFQDN string `json:"delegated_fqdn"`
// ParentZone is the FQDN of the parent zone that delegates DelegatedFQDN.
ParentZone string `json:"parent_zone"`
// ParentNS lists the parent zone's authoritative servers that were
// queried (FQDNs of NS records).
ParentNS []string `json:"parent_ns,omitempty"`
// AdvertisedNS holds the NS RRset returned by the parent for the
// delegated FQDN, normalized as lowercase FQDNs.
AdvertisedNS []string `json:"advertised_ns,omitempty"`
// AdvertisedGlue maps an in-bailiwick NS hostname to the glue addresses
// returned by the parent for that name.
AdvertisedGlue map[string][]string `json:"advertised_glue,omitempty"`
// ParentDS lists the DS records returned by the parent for the
// delegated FQDN, in their textual presentation form.
ParentDS []string `json:"parent_ds,omitempty"`
// ChildSerials maps an NS hostname to the SOA serial it returns for
// the delegated FQDN.
ChildSerials map[string]uint32 `json:"child_serials,omitempty"`
// Findings is the list of issues / observations produced by the run.
Findings []DelegationFinding `json:"findings"`
}
// delegationService is the minimal local mirror of happyDomain's
// `services/abstract.Delegation` type. It is duplicated on purpose so that
// this checker does not have to import the (heavy) happyDomain server module
// just to decode the service payload. github.com/miekg/dns marshals
// dns.NS / dns.DS to JSON in the same shape happyDomain uses.
type delegationService struct {
NameServers []*dns.NS `json:"ns"`
DS []*dns.DS `json:"ds"`
}
// serviceMessage is the minimal local mirror of happyDomain's ServiceMessage
// envelope. We only need the embedded service JSON; the rest of the meta
// fields are ignored.
type serviceMessage struct {
Type string `json:"_svctype"`
Domain string `json:"_domain"`
Service json.RawMessage `json:"Service"`
}