// Package checker detects dangling pointer records (CNAME/MX/SRV/NS) whose external targets // may have expired or been re-registered, enabling subdomain takeover. package checker import ( "encoding/json" ) const ObservationKeyDangling = "dangling_records" // DanglingData is the raw observation payload; one Pointer per (owner, rrtype, target) triple. type DanglingData struct { Zone string `json:"zone,omitempty"` ServicesScanned int `json:"services_scanned"` Pointers []Pointer `json:"pointers,omitempty"` // CollectErrors surfaces non-fatal scan problems so silent skips don't masquerade as a clean pass. CollectErrors []string `json:"collect_errors,omitempty"` } // Pointer is one (owner, rrtype, target) triple from the zone, with its DNS resolution verdict. type Pointer struct { Owner string `json:"owner"` Subdomain string `json:"subdomain"` Rrtype string `json:"rrtype"` Target string `json:"target"` // External flags takeover risk: Target's registrable domain differs from the zone's. External bool `json:"external"` Registrable string `json:"registrable,omitempty"` // ServiceType identifies the happyDomain service for linking back to the edit screen. ServiceType string `json:"service_type,omitempty"` Resolution string `json:"resolution"` ResolutionDetail string `json:"resolution_detail,omitempty"` } // rawZone is a partial Zone type redeclared here to avoid importing 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"` } 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 wraps an svcs.Orphan body; Hdr.Rrtype is sniffed to pick the right field. 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"` }