DNS Message Decoder
Paste a DNS packet as hex or DoH base64url and read it: header flags, opcode and rcode, every record, and the EDNS0 OPT options.
The message is decoded in your browser. Nothing is uploaded and no DNS query is sent.
How to use
- Paste the message. Hex with or without spaces and colons, a tcpdump -x or hexdump -C listing, base64, or a whole DoH URL with its ?dns= parameter all work.
- Check the line under the box for what was recognised, and whether the first two bytes were read as a TCP length prefix rather than as part of the header.
- Read the header row: the opcode says what kind of message this is, the rcode how it ended, and the four counts how many records each section should hold.
- Work down the sections. The Data column is the rdata in presentation format — the same text a zone file would use — and a type with no decoder appears as \# length hex.
- Open the EDNS0 panel for the UDP payload size, the DO bit and the options; an extended DNS error there often says in one line what the rcode only hints at.
About this tool
ShowHide
Reads a DNS message the way a resolver does — from the first byte forward, because nothing in a packet says where a record starts except the length of everything before it. The twelve-byte header gives the id, the opcode, the response code and the four section counts; then come the question and the answer, authority and additional sections. Compression pointers are followed, and a pointer that points forward or at itself is refused rather than chased, because that is what a hostile packet contains. Labels are printed the way a zone file writes them, with \. for a dot inside a label and \DDD for any byte that is not printable, so a name carrying arbitrary octets still reads back exactly. The response code is where most surprises live: it is twelve bits wide, not four, and the top eight sit in the OPT record’s TTL — so a message a plain four-bit read calls NOERROR is reported here as BADVERS when the OPT says so. EDNS0 is decoded in full: the requestor’s UDP payload size hiding in the class field, the version and the DO bit packed into the TTL, and the options — NSID, client subnet with its source and scope prefix lengths, cookie, padding, and the extended DNS error with its code and operator text, which usually explains a SERVFAIL in one line. Rdata is decoded for A, AAAA, NS, CNAME, PTR, MX, TXT, SOA, SRV, CAA, NAPTR, DS, DNSKEY, RRSIG, NSEC, NSEC3, TLSA, SVCB and HTTPS; anything else is printed in RFC 3597 generic form instead of guessed at. What it will not do is ask a name server anything, verify a signature, or tell you whether an answer is true: a TSIG or an RRSIG is named, never checked, because checking needs a key that does not travel in the packet. Paste hex, a tcpdump or hexdump listing, base64, or the base64url of a DoH ?dns= parameter — a two-byte TCP length prefix is recognised and stepped over.
Frequently asked questions
The header says NOERROR but the tool says BADVERS. Which is right?
Both, and that is the point. The rcode started as four bits in the header, and EDNS0 widened it to twelve by putting the upper eight in the TTL field of the OPT record. A decoder that reads only the header nibble sees the low four bits of 16 — which are zero — and reports NOERROR, so a resolver rejecting your EDNS version looks like a perfectly fine empty answer. Any message with an OPT record has to combine the two halves, which is what happens here; the extended rcode is also shown on its own in the EDNS0 panel so you can see where the extra bits came from.
What exactly is the ?dns= parameter of a DNS-over-HTTPS request?
It is the whole wire-format message — the same bytes that would go in a UDP packet — encoded with base64url and, per RFC 8484, with the padding stripped. That is why it uses - and _ instead of + and /: it has to survive being a URL query parameter. Two details trip people up. The message id should be 0 in a GET request so that identical queries produce identical URLs and can be cached by HTTP; and the answer comes back as a raw application/dns-message body, not JSON, so what you copy out of the network panel is binary that has to be turned into hex before you can read it. Paste either form here.
Why refuse a compression pointer that points forward?
A pointer names an offset in the message where the rest of a name can be found, and RFC 1035 requires it to point at a prior occurrence. Backward-only is not a style preference: it is what guarantees the chase terminates. A pointer to itself, or to any later offset, lets a two-byte crafted packet spin a naive decoder forever, and packets built exactly that way circulate as denial-of-service tests. So a forward or self-referential pointer is reported as the fault it is rather than followed, and the number of jumps is capped even for backward chains.
A TXT record shows several quoted strings. Which one is the value?
All of them, joined end to end with nothing between. TXT rdata is a sequence of character-strings, each with a one-byte length, so no single string can exceed 255 bytes; anything longer — a DKIM public key, a long SPF policy — has to be split, and the receiver concatenates. That is why a DKIM record often looks like two fragments that break mid-base64. The strings are shown separately here because the split is really in the packet, and because a record whose author meant them as separate values is a bug you can only see when they are not run together.
What do SVCB and HTTPS records show, and why does the order matter?
An HTTPS or SVCB record is a priority, a target name and a list of key/value SvcParams: alpn for the protocols the server speaks, port, ipv4hint and ipv6hint for addresses to try while the A and AAAA lookups are still in flight, ech for the encrypted client hello configuration. The wire format requires the params to be in ascending key order with no duplicates, which is what makes them cheap to parse and what a hand-built record most often gets wrong. A record whose keys are out of order is malformed, so it is shown as raw hex here rather than silently reordered into something that looks correct.
Can it validate DNSSEC, or check a TSIG signature?
No, and nothing that only reads one packet could. An RRSIG is checked against the DNSKEY of the zone, which has to be fetched and then chained up through DS records to a trust anchor you already trust; a TSIG is checked with a shared secret that by definition never travels in the message. What you do get is everything the bytes themselves say: which RRSIG covers which type, its inception and expiry as real timestamps, the key tag and signer name to compare against the DNSKEY set, and whether the AD bit was set — which records only that some resolver upstream claims it validated, not that it did.
Related tools
SVCB / HTTPS Record Builder & Decoder
Normalise, encode and check an SVCB or HTTPS record: SvcParams decoded, the wire bytes broken down, and every RFC 9460 rule it breaks named.
Network
DNS Zone File Validator
Paste a BIND zone file and see what it really says: every name fully qualified, the SOA explained, and the traps a parser alone will not report.
Network
TLSA Record Generator (DANE) & Checker
Turn a certificate into its TLSA records — every selector and matching type — and check an existing record against the certificate you are serving.
Network
DNS Record Reference
Searchable cheat sheet for DNS record types — A, AAAA, CNAME, MX, TXT, NS, SOA, PTR, SRV, CAA, DNSSEC, SVCB / HTTPS — with examples.
Network
TXT Record Splitter (255-Byte Chunks)
Split a long SPF, DKIM or DMARC TXT record into the 255-byte strings DNS requires, in BIND, generic zone-file, Cloudflare or Route 53 syntax.
Network
DKIM Record Builder & Parser
Build or parse a DKIM DNS TXT record — paste your public key, pick selector, key type, hash and flags, and get the record plus its chunked form.
Network