dany

package module
v1.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 14 Imported by: 0

README

Overview

dany is a commandline DNS client that simulates (unreliable/semi-deprecated) dns ANY queries by doing individual typed DNS queries and aggregating the results. Queries are done concurrently for best performance.

Usage

dany [<types>] <hostname>

where <types> is a comma-separated list of DNS record types to query. If unspecified, the default types list is: A,AAAA,HTTPS,MX,NS,SOA,TXT.

In the output, fields are separated by tabs, so you can use cut (with no delimiter) to extract individual fields.

Examples:

$ dany cisco.com
A               72.163.4.185
AAAA            2001:420:1101:1::185
MX      10      alln-mx-01.cisco.com.
MX      20      rcdn-mx-01.cisco.com.
MX      30      aer-mx-01.cisco.com.
NS              ns1.cisco.com.
NS              ns2.cisco.com.
NS              ns3.cisco.com.
SOA             ns1.cisco.com.      postmaster.cisco.com.
TXT             926723159-3188410
TXT             MS=ms35724259
TXT             docusign=5e18de8e-36d0-4a8e-8e88-b7803423fa2f
TXT             docusign=95052c5f-a421-4594-9227-02ad2d86dfbe
TXT             facebook-domain-verification=qr2nigspzrpa96j1nd9criovuuwino
TXT             google-site-verification=K2w--6oeqrFjHfYtTsYyd2tFw7OQd6g5HJDC9UAI8Jk
TXT             google-site-verification=PdOwpBvoBbr90361WK-DzUDRAwNMWd2f4jqgvGKlpWg
TXT             google-site-verification=lW5eqPMJI4VrLc28YW-JBkqA-FDNVnhFCXQVDvFqZTo
TXT             v=spf1 redirect=spfa._spf.cisco.com
TXT             zpSH7Ye/seyY61hH8+Rq5Kb+ZJ9hDa+qeFBaD/6sPAAg+2POkGdP0byHb1pFVK9uZgYF2AIosUSZq4MB17oydQ==

$ dany mx,txt google.com
MX      10      aspmx.l.google.com.
MX      20      alt1.aspmx.l.google.com.
MX      30      alt2.aspmx.l.google.com.
MX      40      alt3.aspmx.l.google.com.
MX      50      alt4.aspmx.l.google.com.
TXT             docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e
TXT             facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95
TXT             globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8=
TXT             v=spf1 include:_spf.google.com ~all

The -w/--www flag additionally probes the www.<hostname> label. By default only A and AAAA are queried for the www label; if -t/--types (or -a/--all) is given explicitly, that set is used for the www probe too. With -T/--tag, apex and www results are emitted on separate lines tagged with their hostname; without it, they share the same output and identical rows are collapsed (so a www that resolves to the same IP as the apex won't appear twice).

$ dany -w -T google.com
google.com              A               172.217.25.110
google.com              AAAA            2404:6800:4006:80d::200e
google.com              MX      10      smtp.google.com.
google.com              NS              ns1.google.com.
google.com              NS              ns2.google.com.
google.com              NS              ns3.google.com.
google.com              NS              ns4.google.com.
google.com              SOA             ns1.google.com. dns-admin.google.com.
google.com              TXT             v=spf1 include:_spf.google.com ~all
www.google.com          A               142.251.150.119
www.google.com          AAAA            2404:6800:4006:80d::2004

The -f/--fmt flag selects the output format: text (default, the tab-separated form shown above), json, or yaml (yml as a convenience alias). In json and yaml modes:

  • Each record carries both rdata (the canonical DNS presentation form, always a string) and data (a typed per-RR-type payload — address for A/AAAA, preference+exchange for MX, full RFC field set for SOA, strings array for TXT, etc.).
  • A schema_version: 1 envelope wraps the per-hostname output. Multi- hostname runs emit NDJSON (one object per line) in json mode and multi-document YAML (----separated) in yaml mode.
  • Errors fold into the envelope's errors field with a stable machine- readable code (NXDOMAIN, SERVFAIL, EXCHANGE_ERROR, …) — nothing goes to stderr.
  • PTR records (when -p/--ptr is set) appear as standalone entries with the source IP carried in data.ip for easy joining (text mode folds them into the matching A/AAAA row instead).
$ dany -f json -t a,mx example.com
{"schema_version":1,"query":{"hostname":"example.com","types":["a","mx"],
"server":"8.8.8.8:53","options":{"www":false,"usd":false,"ptr":false}},
"answers":[{"type":"A","name":"example.com.","ttl":86400,"class":"IN",
"rdata":"96.7.128.198","data":{"address":"96.7.128.198"}}],"errors":[]}

$ dany -f yaml -t mx example.com
---
schema_version: 1
query:
  hostname: example.com
  types:
    - mx
  server: 8.8.8.8:53
  options:
    www: false
    usd: false
    ptr: false
answers:
  - type: MX
    name: example.com.
    ttl: 86400
    class: IN
    rdata: 10 mx.example.com.
    data:
      preference: 10
      exchange: mx.example.com.
errors: []

dnx

dnx is a companion CLI that reads one or more hostnames (as arguments or on stdin) and reports those that return NXDOMAIN. For safety it probes multiple record types concurrently (MX,NS,SOA by default) and only reports a hostname as NXDOMAIN if every type returns NXDOMAIN — a host that answers any one type is not reported.

dnx <hostname> [<hostname> ...]
dnx < hostnames.txt

Examples:

# Report which of these domains don't exist
$ dnx example.com does-not-exist.example nxdomain.test
does-not-exist.example
nxdomain.test

# Feed a list on stdin
$ cat domains.txt | dnx
...

# -c/--count: report every hostname with its count of non-NXDOMAIN responses
$ dnx -c example.com does-not-exist.example
example.com,3
does-not-exist.example,0

# -V/--invert: report the hostnames that DO resolve (not NXDOMAIN)
$ dnx -V example.com does-not-exist.example
example.com

Useful flags:

  • -s/--server <ip> — use a single resolver IP (overrides the system resolvers).
  • -r/--resolv <file> — load resolver IPs from a file (one per line); queries rotate round-robin across them.
  • -t/--types <list> — override the NX-probe types (default MX,NS,SOA).
  • -C/--concurrency <n> — hostnames queried concurrently per resolver (default 3; the effective cap is n × number-of-resolvers).
  • -c/--count, -V/--invert — as shown above.
  • --version — print version and exit.

Using dany as a library

Both CLIs are thin wrappers over the dany package, which you can import directly:

go get github.com/gavincarr/dany
package main

import (
	"fmt"

	"github.com/gavincarr/dany"
)

func main() {
	// Build a resolver set (round-robins across all of them per query).
	resolvers, err := dany.NewResolversFromStrings([]string{"1.1.1.1", "8.8.8.8"})
	if err != nil {
		panic(err)
	}

	q := &dany.Query{
		Hostname:  "example.com",
		Types:     dany.DefaultRRTypes, // or e.g. []string{"A", "MX", "TXT"}
		Resolvers: resolvers,
	}

	answers, errs := dany.RunQuery(q)
	for _, e := range errs {
		fmt.Println("error:", e) // *dany.QueryError; errors.Is(e, dany.ErrNXDomain) works
	}

	fmt.Print(dany.Render(answers, false)) // canonical tab-separated text
	// ...or structured, sharing one typed envelope:
	//   dany.RenderJSON(answers, q, errs)
	//   dany.RenderYAML(answers, q, errs)
}

Key API surface:

  • Query functions. RunQuery(q *Query) ([]Answer, []error) does the typed-ANY aggregation; RunNXQuery(q *Query) int powers dnx (returns the number of non-NXDOMAIN responses, so 0 means every probe type was NXDOMAIN).
  • Renderers. Render(answers, tagHostname) produces the tab-separated text; RenderJSON / RenderYAML produce the structured formats. All three consume the same []Answer — the query path does no formatting and the renderers do no I/O, so you can also consume []Answer directly and skip them.
  • Resolvers. NewResolvers(ips ...net.IP) builds a round-robin set from one or more parsed IPs (panics if given none); NewResolversFromStrings([]string) parses and validates IP strings, returning an error instead; LoadResolvers(file) reads them from a file. Append more with (*Resolvers).Append.
  • Errors are structured. Each is a *QueryError carrying a stable Code (NXDOMAIN, SERVFAIL, EXCHANGE_ERROR, UNSUPPORTED_TYPE, …) and supports errors.Is against ErrNXDomain / ErrServFail.
  • Type constants. DefaultRRTypes, SupportedRRTypes, DNSSECRRTypes, DNSSECBundle, NXTypes, and SupportedUSDs expose the same type sets the CLIs use.

Note that Answer.RR is a github.com/miekg/dns RR, so inspecting records directly couples you to that package (going through the renderers does not).

Author

Gavin Carr gavin@openfusion.net

Licence

MIT. See LICENCE.

Documentation

Index

Constants

View Source
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

View Source
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).

View Source
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).

View Source
var DefaultRRTypes = []string{"A", "AAAA", "HTTPS", "MX", "NS", "SOA", "TXT"}
View Source
var ErrNXDomain = errors.New("NXDOMAIN")
View Source
var ErrServFail = errors.New("SERVFAIL")
View Source
var NXTypes = []string{
	"MX", "NS", "SOA",
}
View Source
var SupportedRRTypes = []string{
	"A", "AAAA", "CAA", "CNAME", "DNSKEY", "DS", "HTTPS", "MX", "NS", "SOA", "SRV", "SVCB", "TXT",
}
View Source
var SupportedUSDs = []string{

	"_dmarc", "_domainkey", "_mta-sts", "_smtp._tls", "default._bimi",

	"_atproto",
}

Functions

func Render

func Render(answers []Answer, tagHostname bool) string

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

func RenderJSON(answers []Answer, q *Query, errs []error) string

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

func RenderYAML(answers []Answer, q *Query, errs []error) string

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

func RunNXQuery(q *Query) int

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 AAAAData

type AAAAData struct {
	Address string `json:"address" yaml:"address"`
}

type AData

type AData struct {
	Address string `json:"address" yaml:"address"`
}

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

func RunQuery(q *Query) ([]Answer, []error)

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 CAAData

type CAAData struct {
	Flag  uint8  `json:"flag"  yaml:"flag"`
	Tag   string `json:"tag"   yaml:"tag"`
	Value string `json:"value" yaml:"value"`
}

type CNAMEData

type CNAMEData struct {
	Target string `json:"target" yaml:"target"`
}

type DNSKEYData

type DNSKEYData struct {
	Flags     uint16 `json:"flags"      yaml:"flags"`
	Protocol  uint8  `json:"protocol"   yaml:"protocol"`
	Algorithm uint8  `json:"algorithm"  yaml:"algorithm"`
	PublicKey string `json:"public_key" yaml:"public_key"`
}

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 MXData

type MXData struct {
	Preference uint16 `json:"preference" yaml:"preference"`
	Exchange   string `json:"exchange"   yaml:"exchange"`
}

type NSData

type NSData struct {
	Target string `json:"target" yaml:"target"`
}

type NSECData

type NSECData struct {
	NextDomain string   `json:"next_domain" yaml:"next_domain"`
	Types      []string `json:"types"       yaml:"types"`
}

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

func BuildOutput(answers []Answer, q *Query, errs []error) *Output

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 OutputOptions struct {
	Www bool `json:"www" yaml:"www"`
	Usd bool `json:"usd" yaml:"usd"`
	Ptr bool `json:"ptr" yaml:"ptr"`
}

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

type QueryError struct {
	Type     string
	Hostname string
	Code     string
	Err      error
}

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 and "UNSUPPORTED_TYPE" for unknown RR types) 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 LoadResolvers(filename string) (*Resolvers, error)

func NewResolvers

func NewResolvers(ips ...net.IP) *Resolvers

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

func NewResolversFromStrings(ips []string) (*Resolvers, error)

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) Append

func (r *Resolvers) Append(ip net.IP)

func (*Resolvers) Next

func (r *Resolvers) Next() net.IP

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 SRVData

type SRVData struct {
	Priority uint16 `json:"priority" yaml:"priority"`
	Weight   uint16 `json:"weight"   yaml:"weight"`
	Port     uint16 `json:"port"     yaml:"port"`
	Target   string `json:"target"   yaml:"target"`
}

type SVCBData added in v1.6.0

type SVCBData struct {
	Priority uint16      `json:"priority" yaml:"priority"`
	Target   string      `json:"target"   yaml:"target"`
	Params   []SVCBParam `json:"params"   yaml:"params"`
}

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.

type TXTData

type TXTData struct {
	Strings []string `json:"strings" yaml:"strings"`
}

TXTData exposes the raw multi-string form (TXT can legitimately carry multiple character-strings). Consumers wanting the concatenated text can join them; Rdata also carries the presentation form.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL