package checker import ( "encoding/json" "github.com/miekg/dns" ) // ObservationKeyPTR is the observation key for the PTR checker payload. const ObservationKeyPTR = "ptr" // ForwardAddress records a single A/AAAA answer collected for the PTR target. type ForwardAddress struct { Type string `json:"type"` // "A" or "AAAA" Address string `json:"address"` TTL uint32 `json:"ttl,omitempty"` } // PTRData is the raw observation payload persisted by the checker. It // contains NO judgement: severity, pass/fail and derived issues are the // responsibility of CheckRule implementations. type PTRData struct { // OwnerName is the FQDN of the PTR record as declared by the service // (the reverse-arpa name, e.g. "4.3.2.1.in-addr.arpa."). OwnerName string `json:"owner_name"` // DeclaredTarget is the hostname the service says the PTR should point // to. Always fully-qualified and lowercased. DeclaredTarget string `json:"declared_target"` // DeclaredTTL is the TTL declared by the service. DeclaredTTL uint32 `json:"declared_ttl,omitempty"` // InReverseArpa reports whether OwnerName lies under in-addr.arpa or // ip6.arpa. InReverseArpa bool `json:"in_reverse_arpa"` // IsIPv6 reports whether OwnerName is an ip6.arpa name. IsIPv6 bool `json:"is_ipv6"` // ReverseIP is the IP address reconstructed from OwnerName (if parseable). ReverseIP string `json:"reverse_ip,omitempty"` // OwnerDecodeFailed is true when OwnerName lies under *.arpa but no IP // could be decoded from it (malformed labels). OwnerDecodeFailed bool `json:"owner_decode_failed,omitempty"` // ReverseZone is the apex of the reverse zone serving OwnerName (where // the SOA lives). Empty when it could not be located. ReverseZone string `json:"reverse_zone,omitempty"` // ReverseNS are the authoritative servers of the reverse zone. ReverseNS []string `json:"reverse_ns,omitempty"` // ZoneLookupError captures the transport/NXDOMAIN-style failure // encountered while walking up to find the SOA. Empty on success. ZoneLookupError string `json:"zone_lookup_error,omitempty"` // ObservedTargets lists every PTR target observed at OwnerName. In a // healthy setup, this has exactly one entry equal to DeclaredTarget. ObservedTargets []string `json:"observed_targets,omitempty"` // ObservedTTL is the TTL of the PTR RRset as seen from authoritative // servers. ObservedTTL uint32 `json:"observed_ttl,omitempty"` // QueryError captures a transport-level failure while querying the PTR // RRset (unreachable servers, timeouts, …). Empty on success. QueryError string `json:"query_error,omitempty"` // Rcode is the textual rcode of the PTR lookup (e.g. "NOERROR", // "NXDOMAIN", "SERVFAIL"); empty when not applicable. Rcode string `json:"rcode,omitempty"` // EffectiveTarget is the hostname actually examined for hygiene and // FCrDNS (the first observed target, or the declared one when none is // observed). Empty when neither is available. EffectiveTarget string `json:"effective_target,omitempty"` // TargetSyntaxValid reports whether EffectiveTarget parses as a valid // DNS hostname. False when EffectiveTarget is empty or malformed. TargetSyntaxValid bool `json:"target_syntax_valid,omitempty"` // TargetLooksGeneric reports whether EffectiveTarget embeds the IP or // matches common ISP auto-generated patterns. TargetLooksGeneric bool `json:"target_looks_generic,omitempty"` // ForwardAddresses are the A/AAAA addresses the target resolves to // (recursive resolution from the system resolver). ForwardAddresses []ForwardAddress `json:"forward_addresses,omitempty"` // ForwardMatch is true when ReverseIP appears among ForwardAddresses // (Forward-Confirmed Reverse DNS). ForwardMatch bool `json:"forward_match,omitempty"` // TargetResolves is true when the PTR target produced at least one A or // AAAA. Distinct from ForwardMatch: a target can resolve yet point // somewhere else. TargetResolves bool `json:"target_resolves,omitempty"` } // ptrService is the minimal local mirror of happyDomain's `svcs.PTR`. It // carries a single *dns.PTR. The JSON key matches the Go struct field name // used in happyDomain (`Record`). type ptrService struct { Record *dns.PTR `json:"Record"` } // serviceMessage is the minimal local mirror of happyDomain's ServiceMessage // envelope. type serviceMessage struct { Type string `json:"_svctype"` Domain string `json:"_domain"` Service json.RawMessage `json:"Service"` }