几乎每个 DNS 区域都会遇到的记录
Inside a DNS Message: Header Flags, Sections and Wire Format
Every DNS lookup, from a browser asking for an address to a resolver chasing a delegation, is a short binary message in one common format. You rarely see the bytes, but tools such as dig print the header fields as text, and knowing what they mean turns that output from noise into evidence. The format has been specified by RFC 1035 since 1987, refining RFC 883 of 1983, and has been extended since, not replaced.
The 12-byte header
Every message begins with the same 12 bytes: a 16-bit ID, a 16-bit word of flags and codes, and four 16-bit counts.
| Field | Size | Meaning |
|---|---|---|
ID | 16 bits | Chosen by the client and copied into the reply, so the client can match answers to questions |
QR | 1 bit | 0 for a query, 1 for a response |
Opcode | 4 bits | The kind of request; 0 is a standard query |
AA | 1 bit | Authoritative answer: the responding server is an authority for the name in the question |
TC | 1 bit | Truncated: the message was longer than the transport allows |
RD | 1 bit | Recursion desired: the client asks the server to do the whole lookup |
RA | 1 bit | Recursion available: the server offers that service |
Z | 3 bits | Reserved in RFC 1035; DNSSEC later took two of these bits for AD and CD (RFC 2535, restated in RFC 4035) |
RCODE | 4 bits | Response code: the outcome of the query |
QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT | 16 bits each | How many entries the question, answer, authority and additional sections hold |
After the header come the four sections, in that order. The question section echoes what was asked, the answer section holds the records that answer it, the authority section points to the nameservers responsible for the zone, and the additional section carries extra records the server expects the client to want next, such as the addresses of those nameservers.
Take AA with care. A recursive resolver answering from its cache is not an authority for that data and does not set it. In the original design, a server marks an answer authoritative when it answers from zone data it holds, as opposed to cached data (Mockapetris and Dunlap, 1988). Seeing aa in a reply from one of a zone's own nameservers is the normal case, except for a referral to a child zone, which does not carry it even from an authoritative server.
Reading dig's header line
dig prints the header on two lines. A typical response looks like this:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6891
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1opcode and status are the Opcode and RCODE fields. The flags line lists the bits that are set, here qr, rd and ra, which together mean: a response, to a query that asked for recursion, from a server that offers it. The four counts are the section sizes. The ADDITIONAL: 1 is usually the server's EDNS pseudo-record, returned because dig includes one in its query; it is not an extra address.
The status is the quickest thing to read. RFC 1035 defines six response codes.
| Code | Name | Meaning |
|---|---|---|
| 0 | NOERROR | The query was processed without error |
| 1 | FORMERR | The server could not interpret the query |
| 2 | SERVFAIL | The server failed while processing the query |
| 3 | NXDOMAIN | The name does not exist; RFC 1035 calls this a Name Error and defines it for authoritative servers |
| 4 | NOTIMP | The server does not support that kind of query |
| 5 | REFUSED | The server declines to answer for policy reasons |
One common result has no code of its own. A name that exists but has no record of the type you asked for returns NOERROR with no records of that type in the answer section (a CNAME may still appear), which RFC 2308 names NODATA. The difference matters when you are diagnosing; see NXDOMAIN explained and DNS timeout vs SERVFAIL for what to do with each.
A query, byte by byte
This is a complete query for the A record of example.com in its classic form, without EDNS, as a client would send it with recursion requested. It is 29 bytes long.
1a 2b 01 00 00 01 00 00 00 00 00 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01| Bytes | Meaning |
|---|---|
1a 2b | ID: an arbitrary value chosen by the client |
01 00 | Flags: only RD is set |
00 01 | QDCOUNT: one question |
00 00 00 00 00 00 | ANCOUNT, NSCOUNT and ARCOUNT: all zero in a query |
07 65 78 61 6d 70 6c 65 | A label of length 7, then the ASCII letters of “example” |
03 63 6f 6d | A label of length 3, then “com” |
00 | The zero-length root label, which ends the name |
00 01 | QTYPE 1: the A record |
00 01 | QCLASS 1: the Internet class |
The same bytes travel inside encrypted transports. In DNS over HTTPS (RFC 8484), for instance, the same message travels either as the raw body of an HTTP POST or, in a GET request, base64url-encoded into a dns parameter, and clients are advised to set the ID to 0; see DNS over HTTPS and DNS over TLS explained.
Names, limits and compression
A name is a sequence of labels, each preceded by its length, ending in a zero byte. RFC 1035 limits a label to 63 octets and a whole name to 255. Because a label's length byte never exceeds 63, its top two bits are always zero, and that left room for compression: when the top two bits are both one, that byte and the next form a pointer, and the remaining 14 bits give an offset from the start of the message. In a response, the answer's name is very commonly the two bytes c0 0c, a pointer to offset 12, where the question's name begins right after the header. Every DNS program must understand pointers in the messages it receives, though it may choose not to produce them.
Why 512 bytes mattered, and what replaced it
RFC 1035 restricts UDP messages to 512 bytes, not counting the IP and UDP headers. A longer message is truncated and the TC bit is set, which tells the client to retry over TCP. The original designers judged the datagram limit a success rather than a problem: performance was much better than over TCP circuits and operating-system resources were not tied up, although the choice demanded careful retransmission strategies (Mockapetris and Dunlap, 1988).
As responses grew with IPv6 and DNSSEC, the limit became tight. EDNS(0), defined in RFC 6891, lets a client advertise a larger UDP payload size in an OPT pseudo-record. The RFC suggests 4096 octets as a starting point and a fallback to a range around 1280 to 1410 bytes if that fails. Since RFC 7766 in 2016, support for TCP has been a required part of a complete DNS implementation. Larger UDP responses also have a security cost, because they make reflection attacks more profitable; DNS amplification attacks and open resolvers covers that.
核心要点
Read the header first: QR says query or response, RCODE says what happened, AA says whether the answer came from an authority, and TC says to retry over TCP.
Sources and further reading
- RFC 1035: Domain Names - Implementation and Specification (Mockapetris, 1987)
- RFC 2308: Negative Caching of DNS Queries (DNS NCACHE) (Andrews, 1998)
- RFC 2535: Domain Name System Security Extensions (Eastlake, 1999)
- RFC 4035: Protocol Modifications for the DNS Security Extensions (Arends et al., 2005)
- RFC 6891: Extension Mechanisms for DNS (EDNS(0)) (Damas, Graff and Vixie, 2013)
- RFC 7766: DNS Transport over TCP - Implementation Requirements (Dickinson et al., 2016)
- Paul V. Mockapetris and Kevin J. Dunlap, Development of the Domain Name System, Proceedings of SIGCOMM '88, Computer Communication Review 18(4), 1988, pp. 123-133
- Paul Albitz and Cricket Liu, DNS and BIND, 5th edition (O'Reilly, 2006)
- Kevin R. Fall and W. Richard Stevens, TCP/IP Illustrated, Volume 1: The Protocols, 2nd edition (Addison-Wesley, 2011)
需要查看某个域名的公网 DNS 地址?使用 Domain IP Lookup 工具。
常见问题
相关阅读
一次递归 DNS 查询,逐跳详解
浏览器
想访问 example.com
解析器
运营商 / 1.1.1.1
根 + TLD
谁负责 .com?
权威服务器
真正的答案
这条链路上的每一跳本身都是一次 DNS 查询,之后都会被缓存
DNS 如何工作:从域名到 IP 地址
互联网的电话簿,从头到尾追踪一遍:从输入域名,到第一个数据包抵达服务器,这短短几毫秒里究竟发生了什么。
四种结果,四种不同的后续处理
DNS 超时与 SERVFAIL 有何区别
二者看上去都是查询失败,但超时和 SERVFAIL 指向的是不同的问题,应对的下一步也不一样。本文帮您分清并正确处理。
几乎每个 DNS 区域都会遇到的记录
DNS 记录类型详解:完整参考
每一种值得了解的记录类型:它的作用、长什么样,以及人们常犯的错误,全部浓缩在一页参考中。