Initial commit
This commit is contained in:
commit
30caf67389
18 changed files with 2098 additions and 0 deletions
147
checker/types.go
Normal file
147
checker/types.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Package checker implements the happyDomain "dangling records"
|
||||
// checker: it walks the working zone, identifies every pointer record
|
||||
// (CNAME / MX / SRV / NS) whose target lives outside the zone, performs
|
||||
// a light DNS resolution to detect immediate breakage (NXDOMAIN), and
|
||||
// publishes DiscoveryEntry records so a companion checker (typically
|
||||
// the host's domain_expiry) can verify each external registrable domain
|
||||
// via RDAP/WHOIS. The rule layer joins both signals to surface
|
||||
// subdomains at risk of takeover (the "dangling CNAME" attack class
|
||||
// publicised by Ars Technica in 2017).
|
||||
package checker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
const ObservationKeyDangling = "dangling_records"
|
||||
|
||||
// DanglingData is the raw observation payload. It carries one Pointer
|
||||
// entry per (owner, rrtype, target) triple found in the zone, including
|
||||
// targets resolved to their DNS verdict. Aggregation by owner happens
|
||||
// in the rule layer.
|
||||
type DanglingData struct {
|
||||
// Zone is the zone apex, without trailing dot. Empty when the host
|
||||
// did not provide a domain_name option.
|
||||
Zone string `json:"zone,omitempty"`
|
||||
|
||||
// ServicesScanned counts every service inspected (matches the same
|
||||
// field in checker-legacy-records, anchoring the report).
|
||||
ServicesScanned int `json:"services_scanned"`
|
||||
|
||||
// Pointers lists every pointer record encountered. One entry per
|
||||
// distinct (owner, rrtype, target). External pointers carry a
|
||||
// non-empty Registrable; in-zone pointers leave it empty so the
|
||||
// rule does not request RDAP on the user's own apex.
|
||||
Pointers []Pointer `json:"pointers,omitempty"`
|
||||
|
||||
// CollectErrors records non-fatal problems encountered during the
|
||||
// zone walk, surfaced in the report so silent skips do not
|
||||
// masquerade as a clean pass.
|
||||
CollectErrors []string `json:"collect_errors,omitempty"`
|
||||
}
|
||||
|
||||
// Pointer is the unit of observation: one (owner, rrtype, target) seen
|
||||
// in the zone, plus the result of the local DNS resolution.
|
||||
type Pointer struct {
|
||||
// Owner is the FQDN that carries the pointer record (CNAME owner,
|
||||
// MX/SRV owner, NS apex, …). No trailing dot.
|
||||
Owner string `json:"owner"`
|
||||
|
||||
// Subdomain is Owner relative to the zone apex. "" means apex
|
||||
// (rendered as "@" in the report).
|
||||
Subdomain string `json:"subdomain"`
|
||||
|
||||
// Rrtype is the textual record type ("CNAME", "MX", "SRV", "NS").
|
||||
Rrtype string `json:"rrtype"`
|
||||
|
||||
// Target is the FQDN the record points at. No trailing dot.
|
||||
Target string `json:"target"`
|
||||
|
||||
// External is true when Target's registrable domain differs from
|
||||
// the zone's registrable domain (the takeover-risk case).
|
||||
External bool `json:"external"`
|
||||
|
||||
// Registrable is the eTLD+1 of Target. Empty when External is false
|
||||
// or when public-suffix lookup failed.
|
||||
Registrable string `json:"registrable,omitempty"`
|
||||
|
||||
// ServiceType is the happyDomain service that exposed the record
|
||||
// ("svcs.CNAME", "svcs.MXs", …). Useful for navigating users back
|
||||
// to the right edit screen in the report.
|
||||
ServiceType string `json:"service_type,omitempty"`
|
||||
|
||||
// Resolution is the verdict of the local DNS lookup of Target:
|
||||
// "ok", "nxdomain", "no_answer", "servfail", "timeout", "skipped".
|
||||
// "skipped" is used when the collector chose not to resolve (for
|
||||
// example, because lookups are disabled at runtime).
|
||||
Resolution string `json:"resolution"`
|
||||
|
||||
// ResolutionDetail is a free-form sentence describing the
|
||||
// resolution outcome (e.g. the underlying error string). Optional.
|
||||
ResolutionDetail string `json:"resolution_detail,omitempty"`
|
||||
}
|
||||
|
||||
// rawZone is the minimal slice of happyDomain's *Zone JSON we consume.
|
||||
// Like checker-legacy-records, we redeclare just the fields we need so
|
||||
// this checker compiles without depending on the happyDomain module.
|
||||
type rawZone struct {
|
||||
DomainName string `json:"domain_name,omitempty"`
|
||||
Services map[string][]rawService `json:"services"`
|
||||
}
|
||||
|
||||
type rawService struct {
|
||||
Type string `json:"_svctype"`
|
||||
Domain string `json:"_domain"`
|
||||
Service json.RawMessage `json:"Service"`
|
||||
}
|
||||
|
||||
// Below: minimal JSON shapes for each service body we extract pointers
|
||||
// from. We only need fields that point at a host name, so the
|
||||
// definitions are deliberately partial.
|
||||
|
||||
type cnameBody struct {
|
||||
Record struct {
|
||||
Hdr struct {
|
||||
Name string `json:"Name"`
|
||||
} `json:"Hdr"`
|
||||
Target string `json:"Target"`
|
||||
} `json:"cname"`
|
||||
}
|
||||
|
||||
type mxRecord struct {
|
||||
Hdr struct {
|
||||
Name string `json:"Name"`
|
||||
} `json:"Hdr"`
|
||||
Mx string `json:"Mx"`
|
||||
}
|
||||
|
||||
type mxsBody struct {
|
||||
MXs []mxRecord `json:"mx"`
|
||||
}
|
||||
|
||||
type srvRecord struct {
|
||||
Hdr struct {
|
||||
Name string `json:"Name"`
|
||||
} `json:"Hdr"`
|
||||
Target string `json:"Target"`
|
||||
}
|
||||
|
||||
type srvsBody struct {
|
||||
Records []srvRecord `json:"srv"`
|
||||
}
|
||||
|
||||
// orphanRecord covers the body shape used by svcs.Orphan when the
|
||||
// embedded RR is a CNAME, NS, MX, or SRV. We sniff Hdr.Rrtype before
|
||||
// committing to a specific decoder.
|
||||
type orphanRecord struct {
|
||||
Record struct {
|
||||
Hdr struct {
|
||||
Name string `json:"Name"`
|
||||
Rrtype uint16 `json:"Rrtype"`
|
||||
} `json:"Hdr"`
|
||||
// Optional fields, populated for the relevant rrtype.
|
||||
Target string `json:"Target,omitempty"`
|
||||
Mx string `json:"Mx,omitempty"`
|
||||
Ns string `json:"Ns,omitempty"`
|
||||
} `json:"record"`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue