Initial commit
This commit is contained in:
commit
e6eb2e081e
15 changed files with 2058 additions and 0 deletions
176
checker/types.go
Normal file
176
checker/types.go
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
package checker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ObservationKeyDelegation is the observation key for delegation data.
|
||||
const ObservationKeyDelegation = "delegation"
|
||||
|
||||
// DelegationData is the raw, judgment-free observation produced by Collect.
|
||||
// Every field records what was observed (or the error string returned by
|
||||
// the probe) but never classifies severity. Rules consume this data and
|
||||
// emit CheckStates.
|
||||
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"`
|
||||
|
||||
// DeclaredNS lists the NS hostnames declared by the service definition,
|
||||
// lowercased and FQDN-normalized.
|
||||
DeclaredNS []string `json:"declared_ns,omitempty"`
|
||||
|
||||
// DeclaredDS lists the DS records declared by the service definition.
|
||||
DeclaredDS []DSRecord `json:"declared_ds,omitempty"`
|
||||
|
||||
// ParentDiscoveryError captures why the parent zone's authoritative
|
||||
// servers could not be resolved, when that step failed outright.
|
||||
ParentDiscoveryError string `json:"parent_discovery_error,omitempty"`
|
||||
|
||||
// ParentNS lists the parent zone's authoritative server addresses that
|
||||
// were queried (host:port entries).
|
||||
ParentNS []string `json:"parent_ns,omitempty"`
|
||||
|
||||
// ParentViews holds one entry per queried parent server describing
|
||||
// what it returned for the delegation of DelegatedFQDN.
|
||||
ParentViews []ParentView `json:"parent_views,omitempty"`
|
||||
|
||||
// Children holds one entry per NS name learned from the first
|
||||
// successful parent view, with the per-address probes performed
|
||||
// against that NS.
|
||||
Children []ChildNSView `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
// ParentView captures everything one specific parent server returned
|
||||
// while being probed for the delegation.
|
||||
type ParentView struct {
|
||||
Server string `json:"server"`
|
||||
UDPNSError string `json:"udp_ns_error,omitempty"`
|
||||
TCPNSError string `json:"tcp_ns_error,omitempty"`
|
||||
NS []string `json:"ns,omitempty"`
|
||||
Glue map[string][]string `json:"glue,omitempty"`
|
||||
DSQueryError string `json:"ds_query_error,omitempty"`
|
||||
DS []DSRecord `json:"ds,omitempty"`
|
||||
DSRRSIGs []DSRRSIGObservation `json:"ds_rrsigs,omitempty"`
|
||||
}
|
||||
|
||||
// ChildNSView holds the observations for a single delegated NS hostname,
|
||||
// possibly probed across several addresses.
|
||||
type ChildNSView struct {
|
||||
NSName string `json:"ns_name"`
|
||||
ResolveError string `json:"resolve_error,omitempty"`
|
||||
Addresses []ChildAddressView `json:"addresses,omitempty"`
|
||||
}
|
||||
|
||||
// ChildAddressView captures the probes performed against a single
|
||||
// (NS, IP address) pair.
|
||||
type ChildAddressView struct {
|
||||
Address string `json:"address"`
|
||||
Server string `json:"server"`
|
||||
UDPError string `json:"udp_error,omitempty"`
|
||||
Authoritative bool `json:"authoritative"`
|
||||
SOASerial uint32 `json:"soa_serial,omitempty"`
|
||||
SOASerialKnown bool `json:"soa_serial_known,omitempty"`
|
||||
TCPError string `json:"tcp_error,omitempty"`
|
||||
ChildNS []string `json:"child_ns,omitempty"`
|
||||
ChildNSError string `json:"child_ns_error,omitempty"`
|
||||
ChildGlueAddrs []string `json:"child_glue_addrs,omitempty"`
|
||||
DNSKEYError string `json:"dnskey_error,omitempty"`
|
||||
DNSKEYs []DNSKEYRecord `json:"dnskeys,omitempty"`
|
||||
}
|
||||
|
||||
// DSRecord mirrors a DS RR in a form that is both human-readable (Text)
|
||||
// and directly comparable (the structured fields).
|
||||
type DSRecord struct {
|
||||
Text string `json:"text"`
|
||||
KeyTag uint16 `json:"keytag"`
|
||||
Algorithm uint8 `json:"algorithm"`
|
||||
DigestType uint8 `json:"digest_type"`
|
||||
Digest string `json:"digest"`
|
||||
}
|
||||
|
||||
// ToMiekg rebuilds a *dns.DS from the stored fields.
|
||||
func (d DSRecord) ToMiekg() *dns.DS {
|
||||
return &dns.DS{
|
||||
KeyTag: d.KeyTag,
|
||||
Algorithm: d.Algorithm,
|
||||
DigestType: d.DigestType,
|
||||
Digest: d.Digest,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDSRecord converts a miekg *dns.DS into the wire-friendly DSRecord.
|
||||
func NewDSRecord(d *dns.DS) DSRecord {
|
||||
return DSRecord{
|
||||
Text: d.String(),
|
||||
KeyTag: d.KeyTag,
|
||||
Algorithm: d.Algorithm,
|
||||
DigestType: d.DigestType,
|
||||
Digest: d.Digest,
|
||||
}
|
||||
}
|
||||
|
||||
// DNSKEYRecord preserves the fields needed to recompute DS digests.
|
||||
type DNSKEYRecord struct {
|
||||
Name string `json:"name"`
|
||||
Flags uint16 `json:"flags"`
|
||||
Protocol uint8 `json:"protocol"`
|
||||
Algorithm uint8 `json:"algorithm"`
|
||||
PublicKey string `json:"public_key"`
|
||||
}
|
||||
|
||||
// ToMiekg rebuilds a *dns.DNSKEY from the stored fields so the rule can
|
||||
// call k.ToDS(digestType).
|
||||
func (k DNSKEYRecord) ToMiekg() *dns.DNSKEY {
|
||||
name := k.Name
|
||||
if name == "" {
|
||||
name = "."
|
||||
}
|
||||
return &dns.DNSKEY{
|
||||
Hdr: dns.RR_Header{Name: dns.Fqdn(name), Rrtype: dns.TypeDNSKEY, Class: dns.ClassINET},
|
||||
Flags: k.Flags,
|
||||
Protocol: k.Protocol,
|
||||
Algorithm: k.Algorithm,
|
||||
PublicKey: k.PublicKey,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDNSKEYRecord converts a miekg *dns.DNSKEY into the wire-friendly form.
|
||||
func NewDNSKEYRecord(k *dns.DNSKEY) DNSKEYRecord {
|
||||
return DNSKEYRecord{
|
||||
Name: k.Hdr.Name,
|
||||
Flags: k.Flags,
|
||||
Protocol: k.Protocol,
|
||||
Algorithm: k.Algorithm,
|
||||
PublicKey: k.PublicKey,
|
||||
}
|
||||
}
|
||||
|
||||
// DSRRSIGObservation records an RRSIG covering a DS RRset; rules decide
|
||||
// whether the current clock falls inside the validity window.
|
||||
type DSRRSIGObservation struct {
|
||||
Inception uint32 `json:"inception"`
|
||||
Expiration uint32 `json:"expiration"`
|
||||
}
|
||||
|
||||
// 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.
|
||||
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"`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue