Documentation
¶
Index ¶
- Constants
- Variables
- func Render(answers []Answer, tagHostname bool) string
- func RenderJSON(answers []Answer, q *Query, errs []error) string
- func RenderYAML(answers []Answer, q *Query, errs []error) string
- func RunNXQuery(q *Query) int
- type AAAAData
- type AData
- type Answer
- type CAAData
- type CNAMEData
- type DNSKEYData
- type DSData
- type MXData
- type NSData
- type NSECData
- type Output
- type OutputAnswer
- type OutputError
- type OutputOptions
- type OutputQuery
- type PTRData
- type Query
- type QueryError
- type RRSIGData
- type Resolvers
- type SOAData
- type SRVData
- type SVCBData
- type SVCBParam
- type TXTData
Constants ¶
const SchemaVersion = 1
SchemaVersion is the JSON output schema version, bumped only for backwards-incompatible changes. Additive changes (new optional fields, new RR types, new error codes) do not bump it.
Variables ¶
var DNSSECBundle = []string{"DNSKEY", "DS", "NSEC"}
DNSSECBundle is the subset added by the --dnssec convenience flag. It deliberately excludes RRSIG: a bare QTYPE=RRSIG query almost always SERVFAILs on a recursive resolver (an RRSIG is a signature over another RRset and isn't independently validatable, so validating resolvers refuse the meta-query), which would add a near-guaranteed error line to every --dnssec run. RRSIG stays reachable via an explicit -t RRSIG (e.g. against an authoritative server, which can answer it).
var DNSSECRRTypes = []string{"DNSKEY", "DS", "NSEC", "RRSIG"}
DNSSECRRTypes is the full set of DNSSEC records dany can render, and thus the set accepted for an explicit -t. DNSKEY and DS are also in SupportedRRTypes (the --all trust-chain summary); NSEC and RRSIG are the opaque, high-churn signing records that --all intentionally omits (they violate the low-frequency/non-opaque selection rule).
var DefaultRRTypes = []string{"A", "AAAA", "HTTPS", "MX", "NS", "SOA", "TXT"}
var ErrNXDomain = errors.New("NXDOMAIN")
var ErrServFail = errors.New("SERVFAIL")
var NXTypes = []string{
"MX", "NS", "SOA",
}
var SupportedRRTypes = []string{
"A", "AAAA", "CAA", "CNAME", "DNSKEY", "DS", "HTTPS", "MX", "NS", "SOA", "SRV", "SVCB", "TXT",
}
var SupportedUSDs = []string{
"_dmarc", "_domainkey", "_mta-sts", "_smtp._tls", "default._bimi",
"_atproto",
}
Functions ¶
func Render ¶
Render turns a slice of Answers into the canonical dany text output: one tab-separated `\n`-terminated line per non-PTR Answer, with PTR records folded into their corresponding A/AAAA lines, sorted globally. Exact-duplicate lines are collapsed (relevant when --www queries surface IPs the apex already returned). If tagHostname is true each line is prefixed with the queried hostname and a tab — useful when caller is multiplexing multiple hostnames. Render does no I/O.
func RenderJSON ¶
RenderJSON serializes BuildOutput as a single JSON object terminated by a newline — i.e. ready to concatenate into NDJSON across multiple hostname invocations.
func RenderYAML ¶
RenderYAML serializes BuildOutput as one YAML document prefixed with `---\n`. Concatenating multiple RenderYAML outputs across hostnames yields a well-formed multi-document YAML stream.
Output shape is the same Output envelope used by RenderJSON; the yaml struct tags on the *Data types are kept in lockstep with the json tags (snake_case, same field names) so consumers can swap formats without schema surprises.
func RunNXQuery ¶
RunNXQuery probes q.Hostname across multiple RR types and returns the count of probes that did NOT return NXDOMAIN — i.e. len(types) - nxcount, where types is q.Types if non-empty else NXTypes.
Interpretation:
- 0 — every probe returned NXDOMAIN; hostname is fully NX.
- len(types) — no probe returned NXDOMAIN (either real answers, other errors, or timeouts; we can't distinguish these here).
- in between — partial NXDOMAIN; treated as not-NX by callers (dnx).
Probes that time out or error with anything other than ErrNXDomain are counted as non-NX, so transient failures bias toward "not NX" rather than false-positive NXDOMAIN reports.
NX probes intentionally stay on UDP regardless of q.Udp — responses are tiny and there is no benefit to TCP for this codepath.
Types ¶
type Answer ¶
type Answer struct {
Type string
Hostname string
RR dns.RR
Empty bool // present-empty (NODATA); RR is nil when true
}
Answer is a single DNS resource record returned from a typed query. Type is the queried RR type, uppercase ("A", "MX", "TXT", ...) — plus "PTR" for reverse-lookups synthesised when q.Ptr is set. Hostname is the queried hostname (e.g. "example.com", or "_dmarc.example.com" for USD probes; for PTR Answers it is the IP whose PTR was looked up, in dotted/colon form). RR is the raw record from miekg/dns.
func RunQuery ¶
RunQuery fans out concurrent typed DNS lookups for q.Hostname across q.Types (plus USD TXT probes if q.Usd is set, plus A/AAAA probes against www.<q.Hostname> if q.Www is set, plus PTR follow-ups for A/AAAA if q.Ptr is set) and returns the collected Answers and per-query errors. The returned slice is unsorted; pass it through Render for the canonical tab-separated text representation.
On wall-clock timeout (timeoutSeconds), in-flight goroutines' results are silently dropped — they appear as neither Answers nor errors.
type DNSKEYData ¶
type DSData ¶ added in v1.6.0
type DSData struct {
KeyTag uint16 `json:"key_tag" yaml:"key_tag"`
Algorithm uint8 `json:"algorithm" yaml:"algorithm"`
DigestType uint8 `json:"digest_type" yaml:"digest_type"`
Digest string `json:"digest" yaml:"digest"`
}
DSData is the Delegation Signer — the parent-side link in the DNSSEC chain of trust. Digest is hex; small and stable, so it (with DNSKEY) is part of the --all trust-chain summary. The signing records below (NSEC/RRSIG) are surfaced only under --dnssec.
type Output ¶
type Output struct {
SchemaVersion int `json:"schema_version" yaml:"schema_version"`
Query OutputQuery `json:"query" yaml:"query"`
Answers []OutputAnswer `json:"answers" yaml:"answers"`
Errors []OutputError `json:"errors" yaml:"errors"`
}
Output is the top-level envelope returned per hostname. Used as the data model for every renderer (JSON, YAML, ...) — see render_json.go / render_yaml.go for the format-specific wrappers around BuildOutput. Stable shape; new fields may be added but existing fields must not be renamed or removed without bumping SchemaVersion.
func BuildOutput ¶
BuildOutput assembles the typed Output envelope from a RunQuery result. Answers and Errors are sorted into a stable total order (see below) so consecutive runs render identically despite RunQuery's nondeterministic concurrent arrival order. The marshaling step (json/yaml/...) is the caller's concern — see RenderJSON for the canonical NDJSON wrapper.
type OutputAnswer ¶
type OutputAnswer struct {
Type string `json:"type" yaml:"type"`
Name string `json:"name" yaml:"name"`
TTL uint32 `json:"ttl" yaml:"ttl"`
Class string `json:"class" yaml:"class"`
Rdata string `json:"rdata" yaml:"rdata"`
Data interface{} `json:"data" yaml:"data"`
PresentEmpty bool `json:"present_empty,omitempty" yaml:"present_empty,omitempty"`
}
OutputAnswer is one DNS resource record. Rdata is the canonical DNS presentation form (always present); Data is the typed per-RR payload — see the per-type *Data structs for shapes.
func (*OutputAnswer) UnmarshalJSON ¶ added in v1.8.0
func (oa *OutputAnswer) UnmarshalJSON(b []byte) error
UnmarshalJSON decodes an OutputAnswer, restoring the typed per-RR-type Data payload that a plain interface{} decode would otherwise flatten into a map[string]interface{} (with numbers as float64). The record's own "type" field is the discriminator: after decoding the envelope fields, the raw "data" object is re-decoded into the concrete *Data struct newData picks.
Marshal keeps its natural interface{} path (encoding/json reflects the concrete Data value it holds), so no MarshalJSON counterpart is needed and Marshal->Unmarshal is symmetric: a value that went out as MXData comes back as MXData, not a map.
func (*OutputAnswer) UnmarshalYAML ¶ added in v1.8.0
func (oa *OutputAnswer) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML mirrors UnmarshalJSON for the yaml.v3 decoder: it restores the typed Data payload keyed off the "type" discriminator. Without it yaml.v3 decodes the interface{} Data field into a map[string]interface{}, the same way encoding/json does. Marshalling stays on the default reflection path, so there is no MarshalYAML counterpart.
type OutputError ¶
type OutputError struct {
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Hostname string `json:"hostname,omitempty" yaml:"hostname,omitempty"`
Code string `json:"code" yaml:"code"`
Message string `json:"message" yaml:"message"`
}
OutputError mirrors QueryError for the envelope. Code is a stable machine-readable identifier (e.g. "NXDOMAIN", "SERVFAIL", "EXCHANGE_ERROR", "UNSUPPORTED_TYPE", or "UNKNOWN" for errors lacking a QueryError wrapper). Message preserves the human-readable text.
type OutputOptions ¶
type OutputQuery ¶
type OutputQuery struct {
Hostname string `json:"hostname" yaml:"hostname"`
Types []string `json:"types" yaml:"types"`
Server string `json:"server" yaml:"server"`
Options OutputOptions `json:"options" yaml:"options"`
}
type PTRData ¶
type PTRData struct {
Target string `json:"target" yaml:"target"`
IP string `json:"ip,omitempty" yaml:"ip,omitempty"`
}
PTRData carries Target (the resolved hostname) and IP (the original IP the PTR was queried for, recovered from the in-addr.arpa/ip6.arpa name). IP is empty for PTR records that aren't reverse lookups of an IP.
type Query ¶
type Query struct {
Hostname string
Types []string
Resolvers *Resolvers
Server string
IgnoreErrors bool
Udp bool
Ptr bool
Usd bool
Www bool
// WwwTypes, when non-empty, overrides the default www-probe type set
// (A, AAAA). Only consulted when Www is true. Callers that want the
// www. probe to mirror the user's explicit -t/--types selection set
// this; callers that want the address-only default leave it nil.
WwwTypes []string
Tag bool
}
dany Query - lookup Types for Hostname using Server
type QueryError ¶
QueryError is the structured error type emitted by RunQuery / RunNXQuery goroutines. It carries the RR type and hostname that were being queried plus a stable string Code (DNS rcode names like "NXDOMAIN"/"SERVFAIL", plus "EXCHANGE_ERROR" for transport-level failures, "UNSUPPORTED_TYPE" for unknown RR types, and "INVALID_NAME" for a hostname IDNA rejects) so structured consumers — notably the JSON renderer — can act on errors without parsing the message.
Error() preserves the historical `Error on <type> lookup for "<host>": <…>` format so legacy text consumers and existing substring-based tests keep working. Unwrap exposes the underlying error so errors.Is(err, ErrNXDomain) / ErrServFail continue to match.
func (*QueryError) Error ¶
func (e *QueryError) Error() string
func (*QueryError) Unwrap ¶
func (e *QueryError) Unwrap() error
type RRSIGData ¶
type RRSIGData struct {
TypeCovered string `json:"type_covered" yaml:"type_covered"`
Algorithm uint8 `json:"algorithm" yaml:"algorithm"`
Labels uint8 `json:"labels" yaml:"labels"`
OriginalTTL uint32 `json:"original_ttl" yaml:"original_ttl"`
Expiration string `json:"expiration" yaml:"expiration"`
Inception string `json:"inception" yaml:"inception"`
KeyTag uint16 `json:"key_tag" yaml:"key_tag"`
SignerName string `json:"signer_name" yaml:"signer_name"`
Signature string `json:"signature" yaml:"signature"`
}
type Resolvers ¶
type Resolvers struct {
List []net.IP
Length int
Index int
// contains filtered or unexported fields
}
List of Resolver ips
func LoadResolvers ¶
func NewResolvers ¶
NewResolvers builds a Resolvers set from one or more IPs, which Next() then rotates through round-robin. Called with a single IP it behaves as before; pass several (or spread a slice with ips...) to load-balance queries across resolvers. It panics if called with no IPs, since an empty set has no resolver for Next() to return.
func NewResolversFromStrings ¶ added in v1.7.0
NewResolversFromStrings builds a Resolvers set by parsing each string as an IP address. Unlike NewResolvers it returns an error rather than panicking, since it typically parses dynamic input (config/flags/env): it errors on the first unparseable entry, or if ips is empty.
func (*Resolvers) Next ¶
Next returns the next resolver IP round-robin. It is safe to call concurrently from multiple goroutines sharing one *Resolvers (dnx does, and RunQuery does via resolveServer): the Index read-modify-write is guarded by a mutex. The single-resolver fast path stays lock-free — Length and List[0] are fixed after construction.
type SOAData ¶
type SOAData struct {
MName string `json:"mname" yaml:"mname"`
RName string `json:"rname" yaml:"rname"`
Serial uint32 `json:"serial" yaml:"serial"`
Refresh uint32 `json:"refresh" yaml:"refresh"`
Retry uint32 `json:"retry" yaml:"retry"`
Expire uint32 `json:"expire" yaml:"expire"`
Minimum uint32 `json:"minimum" yaml:"minimum"`
}
type SVCBParam ¶ added in v1.6.0
type SVCBParam struct {
Key string `json:"key" yaml:"key"`
Value string `json:"value" yaml:"value"`
}
SVCBData is the shared payload for SVCB and its HTTPS alias (RFC 9460). Params is an ordered slice (not a map) to preserve the record's canonical ascending-key wire order and keep output deterministic. Values are the presentation form of each SvcParamValue (e.g. alpn -> "h2,h3"); the ech param carries an opaque base64 ECHConfig, surfaced verbatim.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
dany
command
|
|
|
dnx
command
|
|
|
internal
|
|
|
testdns
Package testdns is a tiny in-process DNS server for tests.
|
Package testdns is a tiny in-process DNS server for tests. |
|
version
Package version exposes the current dany release version, embedded from VERSION at compile time.
|
Package version exposes the current dany release version, embedded from VERSION at compile time. |