- Zig 94.7%
- Python 3.1%
- Nix 2.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
zon2nix no longer depends on the zig-overlay, so the overlay leaves flake.lock entirely. The regenerated expression drops the comment saying nixpkgs lacks Zig 0.17, builds the package farm with runCommand so it can be substituted from a cache, and tolerates an empty dependency set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HUmrsokV13zXmHVrDJaBSc |
||
| .forgejo/workflows | ||
| LICENSES | ||
| src | ||
| tests | ||
| tools | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| build.zig.zon.nix | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
| REUSE.toml | ||
zig-dns
DNS messages for Zig 0.17, decoded and encoded, and nothing else.
This library turns bytes into a message you can read and a message you describe into bytes. It opens no sockets, reads no files, starts no threads, consults no configuration and holds no cache — and it never allocates. What you do with a message is somewhere else, which is the point: the hard parts of this format are the same whether the bytes came from a socket, from a packet capture, or from a fuzzer.
The API documentation is generated from the doc comments, which are most of the explanation of why DNS is the shape it is.
Where this lives
The repository lives in three places that carry the same history. The Forgejo instance at https://git.jcollie.dev/jeff/zig-dns is the web-visible one:
$ git clone https://git.jcollie.dev/jeff/zig-dns.git
it is mirrored on Tangled at https://tangled.org/jcollie.dev/zig-dns, and it is also on the Radicle network, where the repository's identifier is
rad:z2zFuqA4NbWoKuX8FoSnwGZ1n2XU3
and rad clone rad:z2zFuqA4NbWoKuX8FoSnwGZ1n2XU3 fetches it from any node that
seeds it. Any of the three is the whole project.
Adding it to a project
$ zig fetch --save git+https://git.jcollie.dev/jeff/zig-dns.git
and then, in build.zig:
const dns = b.dependency("dns", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("dns", dns.module("dns"));
main needs Zig 0.17.0. For Zig 0.16.0, use the v0.1.0 tag, the last
release of zig-dns to build with it:
$ zig fetch --save git+https://git.jcollie.dev/jeff/zig-dns.git#v0.1.0
$ git clone -b v0.1.0 https://git.jcollie.dev/jeff/zig-dns.git
The zig-0.16 branch points at the same commit. It is kept for 0.16 users
rather than developed; new work lands on main only.
Quick start
Reading:
const dns = @import("dns");
const message = try dns.Message.parse(bytes);
std.debug.print("{f}\n", .{message}); // prints it the way dig does
var it = message.answers();
while (try it.next()) |record| {
switch (try record.data()) {
.a => |address| std.debug.print("{f}\n", .{address}),
.cname => |name| std.debug.print("{f}\n", .{name}),
else => {},
}
}
Writing:
var buf: [512]u8 = undefined;
var builder = try dns.Builder.init(&buf, .{
.id = 0x1234,
.recursion_desired = true,
}, .{});
try builder.question(.{
.name = dns.Name.literal("example.com"),
.type = .a,
});
try builder.opt(.{}); // EDNS(0), without which almost nothing works
const query = builder.finish();
Name.literal encodes and validates the name at compile time, so a typo is a
compile error and it needs no buffer. For a name that is not known until run
time there is Name.fromText, which writes into a Name.Buffer you supply:
var names: dns.Name.Buffer = undefined;
const name = try dns.Name.fromText(&names, whatever_the_user_typed);
What is in it
Message |
the four sections, with each one's offset found in a single validating pass |
Header |
the twelve bytes, and every flag, readable on their own when the rest cannot be trusted |
Name |
labels, compression pointers, case-insensitive comparison and hashing, canonical order, the presentation escaping, and reading one back — absolute, or relative to an origin |
Record |
an owner, a type, a TTL, and data that is only decoded when asked for |
rdata |
seventy-seven record types, and RFC 3597 opaque data for everything else |
edns |
the opt pseudo-record: payload size, extended response codes, cookies, client subnet, extended errors |
Builder |
encoding, with name compression and an atomic record that rolls back rather than half-filling a buffer |
serial |
RFC 1982 arithmetic: comparing two numbers that wrap, which an soa serial does and < gets wrong at the one moment it matters |
tsig |
the bytes a TSIG signature covers, written into a writer — which fields, in which order, unsigned again and with the identifier put back. The keyed hash that consumes them is somebody else's |
sig0 |
the same for SIG(0): the record data with the signature omitted, then the message before the signature was added. The public key operation that consumes them is somebody else's too |
update |
the nine shapes a dynamic update takes — which class, which TTL and which empty rdata says "delete this RRset" rather than "add a record with nothing in it" — as two unions with one variant per subsection of §2.4 and §2.5 |
Seventy-seven record types have a parser of their own — every type dnspython parses, less the five that are only ever questions:
| addresses and names | A AAAA NS CNAME DNAME PTR SOA MX SRV NAPTR NSAP-PTR MD MF MB MG MR |
| text | TXT SPF HINFO RP MINFO NINFO AVC RESINFO WALLET X25 ISDN GPOS |
| service and policy | SVCB HTTPS CAA URI KX LP AFSDB RT PX |
| DNSSEC | DS CDS DLV TA DNSKEY CDNSKEY KEY RRSIG SIG NSEC NSEC3 NSEC3PARAM NXT |
| keys published for elsewhere | SSHFP TLSA SMIMEA CERT IPSECKEY OPENPGPKEY DHCID HIP AMTRELAY |
| zone maintenance | CSYNC ZONEMD DSYNC |
| pseudo-records | OPT TSIG TKEY |
| identifiers and locators | NID L32 L64 EUI48 EUI64 APL LOC WKS A6 NSAP NULL UNSPEC |
Anything else decodes as unknown and re-encodes byte for byte, because RFC
3597 requires that a resolver carry a type nobody has told it about. The five
QTYPEs — ANY, AXFR, IXFR, MAILA, MAILB — are refused instead: they
name a question and there is no such record, so data says so rather than
handing back bytes that cannot mean anything.
What it will not do
No cryptography, and neither tsig nor sig0 is an exception. RFC 8945
§4.3 and RFC 2931 §3.1 say which bytes a signature covers, in which order, with
the message unsigned again first — and that is serialisation, which is what
this library is for. So both write those bytes into an Io.Writer and stop: point the writer at an
HMAC and you have a signer, point it at Writer.fixed and you have the digest
input in your hand, which is the only way a signature bug is ever found. What
the writer does with them is not a message library's business.
rdata.dnssec decodes every DNSSEC record type and
Dnskey.keyTag does the arithmetic that links a signature to the key that
made it, but nothing here verifies one, and Tsig is decoded without its MAC
ever being checked. Builder refuses to compress names in anything signed so
that what a validator is handed is what was signed.
No zone files. Everything has a format that writes the presentation
form, because a decoded message that cannot be printed is hard to trust, and
nothing here reads one back — with one exception, which is names.
Name.fromText and Name.fromTextRelative exist because a name is what a
program has the moment somebody types one, long before any zone file is
involved: a resolver needs it for its search list and a zone file reader needs
it for $ORIGIN, and neither should have to write the escape rules again. The
rest of the presentation format — the record types, the directives, the
grammar — is zig-dns-zone, which
is built on this.
No I/O, and no resolver. No retry, no truncation-and-retry-over-TCP, no cache, no root hints, no happy eyeballs. Those need a policy and a clock and this needs neither.
Three things worth knowing
Everything borrows. A decoded Message is a view over the buffer it was
read from, and so is every Name and every record in it. A name can be
compressed, meaning its labels are not where it appears to be but somewhere
earlier in the message — which is why a Name holds the whole message and an
offset, and why Name.clone exists for when one has to outlive the buffer.
Running out of room is normal. A DNS server does not decide how big its
answer will be, it discovers it. So Builder.record is atomic: on
error.NoSpace the builder is exactly as it was, with no half-written record
and no compression pointer aimed at bytes that were rolled back. Filling a
response is a loop and a catch:
for (answers) |rr| builder.record(.answer, rr) catch |err| switch (err) {
error.NoSpace => {
builder.setTruncated();
break;
},
else => return err,
};
Where the format is under-specified, you get a say. RFC 1035 says a
compression pointer names "a prior occurrence of the same name" and leaves two
readings of "prior" in use. By default a pointer need only point below itself;
.{ .names = .{ .pointers = .descending } } requires it to point below every
offset already followed, which is what dnspython asks and makes termination
obvious rather than argued:
const message = try dns.Message.parseWithOptions(bytes, .{
.names = .{ .pointers = .descending },
});
Both refuse every loop, and no compressor can tell them apart — one that only points at what it has already written makes the targets descend on its own — so the difference is reachable only by a message nothing generated. Which is exactly the kind a decoder needs an answer for.
Decoding is strict about framing and lenient about meaning. A message
whose sections do not add up, a name that points forwards, a record whose
length disagrees with its type — all refused. A record type nobody knows, a
response code nobody has defined, a class that is not IN — all carried
through unchanged, because a library that cannot hold what it does not
understand cannot be a forwarder, a proxy, or a debugging tool.
Building
zig build test runs everything; zig build check compiles the parts no test
runs. IPv4 and IPv6 addresses are parsed and formatted by
z46, which is the only dependency.
$ zig build test --summary all
$ zig build docs && zig build docs-serve # http://127.0.0.1:8000/
Under Nix, nix develop -c zig build test uses the toolchain in flake.nix
rather than whatever is on the path.
Testing
Beyond the unit tests beside each file, tests/messages.zig holds messages
captured verbatim from a real resolver — a signed DNSKEY set, an HTTPS
record with four parameters, a denial of existence — and checks both that they
decode and that they survive being built again. A round trip through code that
agrees with itself proves nothing about whether it agrees with the rest of the
internet.
Checking it against something else
Every test above is this library agreeing with itself, which cannot catch the
decoder and the encoder being wrong the same way. zig build differential
puts a few hundred thousand mutations of the captured messages to this library
and to dnspython, and compares whether each
accepted the message and what it found in it:
$ nix develop -c zig build differential
200000 messages from seed 1: both accept 33445, both refuse 165839, disagree 742
...
Every disagreement is one that is written down.
The disagreements that remain are strictness choices rather than defects, and
each is recorded in tests/differential.py with the reason — this library
refusing a record whose length does not match its type where dnspython keeps
the bytes as opaque data; dnspython refusing record types this library carries
through as unknown; the two of them reading RFC 1035's "prior occurrence"
differently when a compression pointer is involved. A kind of disagreement
that is not written down fails the run, so a change to what is accepted has
to be looked at rather than absorbed.
nix flake check runs the same comparison as a build, under both pointer
rules and with the Zig dependency coming from build.zig.zon.nix rather than
from the network, so it needs nothing on the path. Regenerate that file with
nix develop -c zon2nix --17 --nix=build.zig.zon.nix build.zig.zon whenever a
dependency moves.
Fuzzing
tests/fuzz.zig holds the properties that must survive any input at all: that
decoding terminates, stays inside its buffer, and round-trips whatever it
claims to have understood. Zig's own fuzzer runs them with coverage feedback:
$ zig build fuzz --fuzz # until interrupted
$ zig build fuzz --fuzz=1M # a bounded run
$ zig build fuzz --fuzz -Dfuzz-filter=names # one target
zig build fuzz-run is a loop of our own over the same targets, with a corpus
in place of coverage feedback. It does a fixed amount of work from a seed that
can be given again, which is what CI runs, and replays a single input:
$ zig build fuzz-run # a minute of each target
$ zig build fuzz-run -- --seconds 300 --target names
$ zig build fuzz-run -- --input fuzz-findings/x.bin --target names
License
MIT. The project follows the REUSE standard; reuse lint checks it.
References cited
The documents this library is written against, in the RFC citation format so
that a reference here matches one anywhere else. Each entry says what the
document is and what in src/ is written from it. All of them are also filed
in a Zotero collection called zig-dns, with the canonical text of each RFC
attached, so a citation can be taken from there rather than composed.
- [RFC822] Crocker, D., "STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT
MESSAGES", STD 11, RFC 822, August 1982,
https://www.rfc-editor.org/info/rfc822. The mail address form that one
half of a
pxrecord maps to an X.400 one. - [RFC973] Mockapetris, P., "Domain system changes and observations",
RFC 973, January 1986, https://www.rfc-editor.org/info/rfc973. What made
mdandmfobsolete in favor ofmx. Both still decode, as the domain name they always were. - [RFC1035] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987, https://www.rfc-editor.org/info/rfc1035. The format itself: the header, the four sections, labels and compression pointers (§4.1.4), the character-string (§3.3), the 512-byte UDP limit and the two-byte TCP length prefix (§4.2), and the presentation escaping (§5.1). Its "a prior occurrence of the same name" is the sentence both pointer rules read differently.
- [RFC1183] Everhart, C., Mamakos, L., Ullmann, R., and P. Mockapetris,
Ed., "New DNS RR Definitions", RFC 1183, October 1990,
https://www.rfc-editor.org/info/rfc1183.
AFSDB,RP,X25,ISDNandRT. - [RFC1712] Farrell, C., Schulze, M., Pleitner, S., and D. Baldoni, "DNS
Encoding of Geographical Location", RFC 1712, November 1994,
https://www.rfc-editor.org/info/rfc1712.
GPOS, three decimal strings, whichLOCreplaced with something a machine can compare. - [RFC1876] Davis, C., Vixie, P., Goodwin, T., and I. Dickinson, "A Means
for Expressing Location Information in the Domain Name System", RFC 1876,
January 1996, https://www.rfc-editor.org/info/rfc1876.
LOC, its base-and-exponent sizes, and §2's instruction to treat a version this does not know as data of unknown meaning. - [RFC1982] Elz, R. and R. Bush, "Serial Number Arithmetic", RFC 1982,
August 1996, https://www.rfc-editor.org/info/rfc1982. How an
soaserial is compared, which is not how a number is:serialis §3.2's comparison, including the pair of serials half the space apart that §3.2 leaves deliberately unordered and that this reports asnullrather than deciding. - [RFC1996] Vixie, P., "A Mechanism for Prompt Notification of Zone Changes
(DNS NOTIFY)", RFC 1996, August 1996,
https://www.rfc-editor.org/info/rfc1996. The
notifyopcode. - [RFC2136] Vixie, P., Ed., Thomson, S., Rekhter, Y., and J. Bound,
"Dynamic Updates in the Domain Name System (DNS UPDATE)", RFC 2136,
April 1997, https://www.rfc-editor.org/info/rfc2136. The
updateopcode, which renames the four sections rather than changing them, andupdateentire: §2.4 and §2.5's nine shapes, which are encodings rather than ideas — the class, the TTL and the emptiness of the rdata are what tell a deletion from an addition — and §3.4.1's prescan, which a requestor can run on its own changes before spending a round trip learningnotzone. Decoding one stays the caller's: a message library that reinterpreted the sections by opcode would be deciding something, which is one of the recorded disagreements with dnspython. - [RFC2163] Allocchio, C., "Using the Internet DNS to Distribute MIXER
Conformant Global Address Mapping (MCGAM)", RFC 2163, January 1998,
https://www.rfc-editor.org/info/rfc2163.
PX. - [RFC2181] Elz, R. and R. Bush, "Clarifications to the DNS
Specification", RFC 2181, July 1997,
https://www.rfc-editor.org/info/rfc2181. §5.2, that records in one RRset
whose TTLs differ are not thereby different records, which is why
Recordcompares as it does. - [RFC2308] Andrews, M., "Negative Caching of DNS Queries (DNS NCACHE)",
RFC 2308, March 1998, https://www.rfc-editor.org/info/rfc2308. What the
last field of an
soahas meant since: how long a denial may be cached, rather than a default TTL. - [RFC2535] Eastlake 3rd, D., "Domain Name System Security Extensions",
RFC 2535, March 1999, https://www.rfc-editor.org/info/rfc2535.
KEY,SIGandNXT— the DNSSEC that came before RFC 4034's, all three of which still decode here. - [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for
specifying the location of services (DNS SRV)", RFC 2782, February 2000,
https://www.rfc-editor.org/info/rfc2782.
SRV, and its "name compression is not to be used for this field". - [RFC2874] Crawford, M. and C. Huitema, "DNS Extensions to Support IPv6
Address Aggregation and Renumbering", RFC 2874, July 2000,
https://www.rfc-editor.org/info/rfc2874.
A6, an address with its prefix somewhere else. - [RFC2930] Eastlake 3rd, D., "Secret Key Establishment for DNS (TKEY
RR)", RFC 2930, September 2000,
https://www.rfc-editor.org/info/rfc2930.
TKEY, the other half ofTSIG. - [RFC2931] Eastlake 3rd, D., "DNS Request and Transaction Signatures
( SIG(0)s )", RFC 2931, September 2000,
https://www.rfc-editor.org/info/rfc2931.
sig0: §3's constants — type covered zero, the root as the owner, classany— and §3.1's two-part data, the record's own rdata with the signature omitted rather than zeroed, followed by the message as it stood before the signature was added to it. - [RFC3007] Wellington, B., "Secure Domain Name System (DNS) Dynamic
Update", RFC 3007, November 2000,
https://www.rfc-editor.org/info/rfc3007. What ties
updatetotsigandsig0: an update is authenticated by a signature on the request rather than by anything inside it, which is why none of the three knows about the other two. - [RFC3123] Koch, P., "A DNS RR Type for Lists of Address Prefixes (APL
RR)", RFC 3123, June 2001, https://www.rfc-editor.org/info/rfc3123.
APL. - [RFC3403] Mealling, M., "Dynamic Delegation Discovery System (DDDS) Part
Three: The Domain Name System (DNS) Database", RFC 3403, October 2002,
https://www.rfc-editor.org/info/rfc3403.
NAPTR, whose replacement field §4.1 says is not compressed. - [RFC3425] Lawrence, D., "Obsoleting IQUERY", RFC 3425, November 2002, https://www.rfc-editor.org/info/rfc3425. Why opcode 1 is named and has no meaning.
- [RFC3597] Gustafsson, A., "Handling of Unknown DNS Resource Record (RR)
Types", RFC 3597, September 2003,
https://www.rfc-editor.org/info/rfc3597. Why
unknownis not a failure case: an unrecognized type is carried byte for byte. §4 forbids compressing a name in anything defined after RFC 1035, which is whatBuilderobeys and what makes a signed record safe to re-encode; §5 is the\# length hexpresentation form and theTYPE1234andCLASS42spellings. - [RFC4025] Richardson, M., "A Method for Storing IPsec Keying Material in
DNS", RFC 4025, March 2005, https://www.rfc-editor.org/info/rfc4025.
IPSECKEY. - [RFC4034] Arends, R., Austein, R., Larson, M., Massey, D., and S. Rose,
"Resource Records for the DNS Security Extensions", RFC 4034, March 2005,
https://www.rfc-editor.org/info/rfc4034.
DS,DNSKEY,RRSIGandNSEC: the key tag arithmetic of Appendix B, the type bitmap of §4.1.2, the serial comparison of an expiry time in §3.1.5, and the canonical name order of §6.1 thatName.orderimplements. - [RFC4343] Eastlake 3rd, D., "Domain Name System (DNS) Case Insensitivity
Clarification", RFC 4343, January 2006,
https://www.rfc-editor.org/info/rfc4343. Why
Name.eqlandName.hashignore case, and over which bytes. - [RFC4398] Josefsson, S., "Storing Certificates in the Domain Name System
(DNS)", RFC 4398, March 2006, https://www.rfc-editor.org/info/rfc4398.
CERT. - [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, October 2006, https://www.rfc-editor.org/info/rfc4648. The alphabets the presentation forms are written in, §7's extended hex one among them.
- [RFC5001] Austein, R., "DNS Name Server Identifier (NSID) Option",
RFC 5001, August 2007, https://www.rfc-editor.org/info/rfc5001. The
nsidoption, which says which node answered. - [RFC5155] Laurie, B., Sisson, G., Arends, R., and D. Blacka, "DNS
Security (DNSSEC) Hashed Authenticated Denial of Existence", RFC 5155,
March 2008, https://www.rfc-editor.org/info/rfc5155.
NSEC3andNSEC3PARAM, and the unpadded base32hex their hashes are printed in. - [RFC6563] Jiang, S., Conrad, D., and B. Carpenter, "Moving A6 to
Historic Status", RFC 6563, March 2012,
https://www.rfc-editor.org/info/rfc6563. Why
A6is decoded but nothing should send one. - [RFC6672] Rose, S. and W. Wijngaards, "DNAME Redirection in the DNS",
RFC 6672, June 2012, https://www.rfc-editor.org/info/rfc6672.
DNAME, whose target is not compressed even though it looks like aCNAME's. - [RFC6742] Atkinson, RJ, Bhatti, SN, and S. Rose, "DNS Resource Records
for the Identifier-Locator Network Protocol (ILNP)", RFC 6742,
November 2012, https://www.rfc-editor.org/info/rfc6742.
NID,L32,L64andLP. - [RFC6840] Weiler, S., Ed. and D. Blacka, Ed., "Clarifications and
Implementation Notes for DNS Security (DNSSEC)", RFC 6840, February 2013,
https://www.rfc-editor.org/info/rfc6840. §5.7, what the
DObit means in a query rather than a response. - [RFC6891] Damas, J., Graff, M., and P. Vixie, "Extension Mechanisms for
DNS (EDNS(0))", STD 75, RFC 6891, April 2013,
https://www.rfc-editor.org/info/rfc6891. The
optpseudo-record, which is where a message keeps everything the twelve-byte header had no room for: exactly one of them (§6.1.1), owned by the root (§6.1.2), carrying the payload size, the upper bits of the response code, and the option list. - [RFC6975] Crocker, S. and S. Rose, "Signaling Cryptographic Algorithm
Understanding in DNS Security Extensions (DNSSEC)", RFC 6975, July 2013,
https://www.rfc-editor.org/info/rfc6975. The
dau,dhuandn3uoptions. - [RFC7208] Kitterman, S., "Sender Policy Framework (SPF) for Authorizing
Use of Domains in Email, Version 1", RFC 7208, April 2014,
https://www.rfc-editor.org/info/rfc7208. Why the
SPFtype is decoded and deprecated: the policy went back to living in aTXT. - [RFC7314] Andrews, M., "Extension Mechanisms for DNS (EDNS) EXPIRE
Option", RFC 7314, July 2014,
https://www.rfc-editor.org/info/rfc7314. The
expireoption. - [RFC7477] Hardaker, W., "Child-to-Parent Synchronization in DNS",
RFC 7477, March 2015, https://www.rfc-editor.org/info/rfc7477.
CSYNC. - [RFC7553] Faltstrom, P. and O. Kolkman, "The Uniform Resource Identifier
(URI) DNS Resource Record", RFC 7553, June 2015,
https://www.rfc-editor.org/info/rfc7553.
URI, whose target §4.5 says must not be empty — one of the length-versus-type checks this library makes and dnspython does not. - [RFC7828] Wouters, P., Abley, J., Dickinson, S., and R. Bellis, "The
edns-tcp-keepalive EDNS0 Option", RFC 7828, April 2016,
https://www.rfc-editor.org/info/rfc7828. The
tcp_keepaliveoption. - [RFC7830] Mayrhofer, A., "The EDNS(0) Padding Option", RFC 7830,
May 2016, https://www.rfc-editor.org/info/rfc7830. The
paddingoption, which carries nothing and is the point. - [RFC7858] Hu, Z., Zhu, L., Heidemann, J., Mankin, A., Wessels, D., and P. Hoffman, "Specification for DNS over Transport Layer Security (TLS)", RFC 7858, May 2016, https://www.rfc-editor.org/info/rfc7858. Port 853, which is the whole of what this library takes from it.
- [RFC7871] Contavalli, C., van der Gaast, W., Lawrence, D., and
W. Kumari, "Client Subnet in DNS Queries", RFC 7871, May 2016,
https://www.rfc-editor.org/info/rfc7871. The
client_subnetoption, and §6's rule that only the significant bits of the address are sent. - [RFC7873] Eastlake 3rd, D. and M. Andrews, "Domain Name System (DNS)
Cookies", RFC 7873, May 2016,
https://www.rfc-editor.org/info/rfc7873. The
cookieoption and thebadcookieresponse code. - [RFC7901] Wouters, P., "CHAIN Query Requests in DNS", RFC 7901,
June 2016, https://www.rfc-editor.org/info/rfc7901. The
chainoption. - [RFC8005] Laganier, J., "Host Identity Protocol (HIP) Domain Name System
(DNS) Extension", RFC 8005, October 2016,
https://www.rfc-editor.org/info/rfc8005.
HIP. - [RFC8145] Wessels, D., Kumari, W., and P. Hoffman, "Signaling Trust
Anchor Knowledge in DNS Security Extensions (DNSSEC)", RFC 8145, April 2017,
https://www.rfc-editor.org/info/rfc8145. The
key_tagoption. - [RFC8490] Bellis, R., Cheshire, S., Dickinson, J., Dickinson, S.,
Lemon, T., and T. Pusateri, "DNS Stateful Operations", RFC 8490, March 2019,
https://www.rfc-editor.org/info/rfc8490. The
dsoopcode and thedsotypeniresponse code. - [RFC8749] Mekking, W. and D. Mahoney, "Moving DNSSEC Lookaside
Validation (DLV) to Historic Status", RFC 8749, March 2020,
https://www.rfc-editor.org/info/rfc8749. Why
DLVis decoded and decommissioned. - [RFC8777] Holland, J., "DNS Reverse IP Automatic Multicast Tunneling
(AMT) Discovery", RFC 8777, April 2020,
https://www.rfc-editor.org/info/rfc8777.
AMTRELAY. - [RFC8914] Kumari, W., Hunt, E., Arends, R., Hardaker, W., and
D. Lawrence, "Extended DNS Errors", RFC 8914, October 2020,
https://www.rfc-editor.org/info/rfc8914. The
extended_erroroption: the difference between a server that cannot answer and a server that will not. - [RFC8945] Dupont, F., Morris, S., Vixie, P., Eastlake 3rd, D.,
Gudmundsson, O., and B. Wellington, "Secret Key Transaction Authentication
for DNS (TSIG)", STD 93, RFC 8945, November 2020,
https://www.rfc-editor.org/info/rfc8945.
TSIG, decoded without its MAC ever being checked, and never compressed on the way out so that a verifier sees what was signed. §4.3 is whattsigwrites: the request's MAC, the message with its signature removed and its identifier put back, and the variables — or, for the second and later messages of a transfer, §5.3.1's timers alone. §4.2's error field is its own registry, where 16 isbadsigand not thebadversthe same number means in a header, which is whyTsig.ErrorCodeexists. - [RFC8976] Wessels, D., Barber, P., Weinberg, M., Kumari, W., and
W. Hardaker, "Message Digest for DNS Zones", RFC 8976, February 2021,
https://www.rfc-editor.org/info/rfc8976.
ZONEMD. - [RFC9276] Hardaker, W. and V. Dukhovni, "Guidance for NSEC3 Parameter
Settings", BCP 236, RFC 9276, August 2022,
https://www.rfc-editor.org/info/rfc9276. Why zero iterations and an empty
salt are what an
NSEC3PARAMshould say. - [RFC9460] Schwartz, B., Bishop, M., and E. Nygren, "Service Binding and
Parameter Specification via the DNS (SVCB and HTTPS Resource Records)",
RFC 9460, November 2023, https://www.rfc-editor.org/info/rfc9460.
SVCBandHTTPS: the strictly increasing key order of §2.2, themandatorycheck of §8, alias mode and the parameters §2.4.2 says to ignore there, and thekeyNNNNNspelling of §2.1. - [RFC9461] Schwartz, B., "Service Binding Mapping for DNS Servers",
RFC 9461, November 2023, https://www.rfc-editor.org/info/rfc9461. The
dohpathservice parameter. - [RFC9540] Pauly, T. and T. Reddy.K, "Discovery of Oblivious Services via
Service Binding Records", RFC 9540, February 2024,
https://www.rfc-editor.org/info/rfc9540. The
ohttpservice parameter. - [RFC9567] Arends, R. and M. Larson, "DNS Error Reporting", RFC 9567,
April 2024, https://www.rfc-editor.org/info/rfc9567. The
report_channeloption. - [RFC9606] Reddy.K, T. and M. Boucadair, "DNS Resolver Information",
RFC 9606, June 2024, https://www.rfc-editor.org/info/rfc9606.
RESINFO. - [RFC9660] Salgado, H., Vergara, M., and D. Wessels, "The DNS Zone Version
(ZONEVERSION) Option", RFC 9660, October 2024,
https://www.rfc-editor.org/info/rfc9660. The
zoneversionoption. - [RFC9715] Fujiwara, K. and P. Vixie, "IP Fragmentation Avoidance in DNS over UDP", RFC 9715, January 2025, https://www.rfc-editor.org/info/rfc9715. Why the payload size to advertise is 1232 rather than as much as possible.
- [RFC9859] Stenstam, J., Thomassen, P., and J. Levine, "Generalized DNS
Notifications", RFC 9859, September 2025,
https://www.rfc-editor.org/info/rfc9859.
DSYNC, and the generalized notify that has a parent re-check aCDSorCSYNCwithout waiting for a scan. - [Z46] Ollie, J., "z46 — IPv4 and IPv6 addresses, networks and endpoints
for Zig", 2026, https://git.jcollie.dev/jeff/z46. The only dependency:
every address this library hands back — in an
a, anaaaa, awks, anapl, anipseckey, an SVCB address hint or a client subnet option — is one of its types, parsed and formatted by it. - [DNSPYTHON] Halley, B. and the dnspython contributors, "dnspython", version 2.8.0, https://www.dnspython.org/. The second decoder the differential test compares against, message by message, and the source of the stricter of the two compression pointer rules.