Skip to main content

DNS Protocol Technical Guide (RFC 1035)

This document is a detailed technical guide to RFC 1035, including message formats, resource record types, practical examples, and tool usage instructions. For official RFC chapter translations, please refer to the individual chapter documents.

Document Information

  • RFC Number: 1035
  • Title: Domain Names - Implementation and Specification
  • Published Date: November 1987
  • Author: P. Mockapetris (USC/Information Sciences Institute)
  • Status: INTERNET STANDARD (STD 13)

Abstract

This RFC defines the implementation details of DNS (Domain Name System), including message formats, resource record formats, and behavioral specifications for name servers and resolvers. This document is a companion to RFC 1034 (DNS Concepts and Facilities), where RFC 1034 defines concepts, and this document defines specific implementations.

Core Concept: RFC 1035 is the implementation specification for DNS, defining message formats, record types, and implementation details.

Relationship with RFC 1034

RFC 1034 (Concepts)          RFC 1035 (Implementation)
───────────────── ─────────────────
✓ What is DNS → ✓ Message format
✓ Domain name structure → ✓ Resource record format
✓ Name server architecture → ✓ Resolution algorithm
✓ Caching strategy → ✓ Compression mechanism
✓ Query types → ✓ Protocol details

Recommendation:
Read RFC 1034 first to understand concepts
Then read RFC 1035 to learn implementation

DNS Message Format

Message Structure

All DNS messages use the same format:

+---------------------+
| Header | 12 bytes, fixed
+---------------------+
| Question | Query section (variable length)
+---------------------+
| Answer | Answer section (variable length)
+---------------------+
| Authority | Authority section (variable length)
+---------------------+
| Additional | Additional section (variable length)
+---------------------+

Header Format

                                    1  1  1  1  1  1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Total length: 12 bytes

Field Details

ID (16 bits)

Purpose: Match queries and responses
Range: 0-65535
Usage: Client randomly generates, server returns unchanged

Example:
Query: ID = 12345
Response: ID = 12345 (same)

QR (1 bit) - Query/Response

0 = Query
1 = Response

Example:
Client sends: QR=0
Server replies: QR=1

Opcode (4 bits) - Operation Code

0 = QUERY (standard query)
1 = IQUERY (inverse query, obsolete)
2 = STATUS (server status query)
3-15 = Reserved

Common: Opcode=0 (standard query)

AA (1 bit) - Authoritative Answer

Authoritative answer flag

0 = Non-authoritative answer (from cache)
1 = Authoritative answer (from authoritative server)

Example:
Query example.com A record
→ NS for example.com returns: AA=1
→ Caching server returns: AA=0

TC (1 bit) - Truncation

Truncation flag

0 = Not truncated
1 = Truncated (message exceeds 512 bytes, UDP)

Handling:
if TC=1:
Retry query using TCP

RD (1 bit) - Recursion Desired

Recursion desired

0 = Don't recurse (query local only)
1 = Please recurse

Client setting:
Usually set to 1, requesting DNS server to recurse

RA (1 bit) - Recursion Available

Recursion available

0 = Recursion not supported
1 = Recursion supported

Server response:
if server supports recursion: RA=1
else: RA=0

Z (3 bits) - Reserved

Reserved field, must be 0

Note:
Modern extensions use part of Z bits
DNSSEC uses one bit (AD, CD)

RCODE (4 bits) - Response Code

Response code

| RCODE | Meaning | Description |
|-------|---------|------------|
| 0 | NOERROR | Success |
| 1 | FORMERR | Format error |
| 2 | SERVFAIL | Server failure |
| 3 | NXDOMAIN | Name does not exist |
| 4 | NOTIMP | Not implemented |
| 5 | REFUSED | Query refused |

Common errors:
NXDOMAIN (3) = Domain name does not exist
SERVFAIL (2) = Server temporary failure

QDCOUNT (16 bits)

Number of entries in Question section
Usually 1

ANCOUNT (16 bits)

Number of resource records in Answer section

NSCOUNT (16 bits)

Number of resource records in Authority section

ARCOUNT (16 bits)

Number of resource records in Additional section

Question Section Format

                                    1  1  1  1  1  1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ QNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QTYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QCLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

QNAME: Domain name to query (variable length)
QTYPE: Query type (16 bits)
QCLASS: Query class (16 bits, usually 1=IN)

QNAME Encoding

Domain names are encoded as a sequence of labels:

Domain name: www.example.com

Encoding:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|03| w w w |07| e x a m p l e |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|02| c o m |00|
+--+--+--+--+--+

Format:
- Each label preceded by length (1 byte)
- Label content (ASCII characters)
- Terminated with 0

Example:
"www.example.com" =
3 "www" 7 "example" 3 "com" 0

Root domain: 0 (single 0 byte)

QTYPE (Query Type)

Common types:

| Value | Type | Description |
|-------|------|-------------|
| 1 | A | IPv4 address |
| 2 | NS | Name server |
| 5 | CNAME | Canonical name (alias) |
| 6 | SOA | Start of authority |
| 12 | PTR | Pointer (reverse lookup) |
| 15 | MX | Mail exchange |
| 16 | TXT | Text record |
| 28 | AAAA | IPv6 address |
| 255 | ANY | All records (deprecated) |

Example:
Query IPv4 address for example.com:
QTYPE = 1 (A record)

QCLASS (Query Class)

| Value | Class | Description |
|-------|-------|-------------|
| 1 | IN | Internet |
| 2 | CS | CSNET (obsolete) |
| 3 | CH | CHAOS |
| 4 | HS | Hesiod |
| 255 | ANY | Any class |

Usually used: QCLASS = 1 (IN)

Answer/Authority/Additional Format

Resource Record (RR) format:

                                    1  1  1  1  1  1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ NAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| CLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TTL |
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| RDLENGTH |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
/ RDATA /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

NAME: Domain name
TYPE: Record type
CLASS: Record class (usually 1=IN)
TTL: Time to live (seconds)
RDLENGTH: RDATA length
RDATA: Record data (format depends on TYPE)

Resource Record Types Explained

A Record - IPv4 Address

TYPE = 1
RDLENGTH = 4 (bytes)
RDATA = 32-bit IPv4 address

Example:
NAME: example.com
TYPE: A (1)
CLASS: IN (1)
TTL: 3600
RDLENGTH: 4
RDATA: 93.184.216.34

Encoding (RDATA):
93.184.216.34 → 0x5DB8D822

NS Record - Name Server

TYPE = 2
RDATA = Domain name of name server

Example:
NAME: example.com
TYPE: NS (2)
TTL: 86400
RDATA: ns1.example.com

Meaning: The authoritative server for example.com is ns1.example.com

CNAME Record - Alias

TYPE = 5
RDATA = Canonical name

Example:
NAME: www.example.com
TYPE: CNAME (5)
TTL: 3600
RDATA: example.com

Meaning: www.example.com is an alias for example.com

Query flow:
Query www.example.com A
→ Returns CNAME example.com
→ Continue query example.com A
→ Returns 93.184.216.34

SOA Record - Start of Authority

TYPE = 6
RDATA format:
MNAME: Primary name server
RNAME: Responsible person's mailbox
SERIAL: Serial number
REFRESH: Refresh interval
RETRY: Retry interval
EXPIRE: Expire time
MINIMUM: Minimum TTL

Example:
NAME: example.com
TYPE: SOA (6)
TTL: 86400
RDATA:
MNAME: ns1.example.com
RNAME: admin.example.com ([email protected])
SERIAL: 2024010101
REFRESH: 3600
RETRY: 600
EXPIRE: 604800
MINIMUM: 86400

Usage:
- Identify zone authoritative information
- Control zone transfers
- Set caching policy

MX Record - Mail Exchange

TYPE = 15
RDATA format:
PREFERENCE: Priority (16 bits)
EXCHANGE: Mail server domain name

Example:
NAME: example.com
TYPE: MX (15)
TTL: 3600
RDATA:
PREFERENCE: 10
EXCHANGE: mail1.example.com

Multiple MX records:
example.com MX 10 mail1.example.com
example.com MX 20 mail2.example.com
example.com MX 30 mail3.example.com

Processing:
- Prefer lower values
- Random selection for same priority
- Try next on failure

TXT Record - Text

TYPE = 16
RDATA = Arbitrary text string

Example:
NAME: example.com
TYPE: TXT (16)
TTL: 3600
RDATA: "v=spf1 include:_spf.google.com ~all"

Usage:
- SPF (Sender Policy Framework)
- DKIM (DomainKeys Identified Mail)
- Domain verification
- Arbitrary metadata

Multiple strings:
RDATA can contain multiple <length><string> pairs

AAAA Record - IPv6 Address

TYPE = 28
RDLENGTH = 16 (bytes)
RDATA = 128-bit IPv6 address

Example:
NAME: example.com
TYPE: AAAA (28)
TTL: 3600
RDLENGTH: 16
RDATA: 2606:2800:220:1:248:1893:25c8:1946

Encoding:
IPv6 addresses stored as 16 bytes in network byte order

PTR Record - Reverse Lookup

TYPE = 12
RDATA = Domain name

Usage: Reverse IP address to domain name lookup

Example:
Query: Domain name for 93.184.216.34
NAME: 34.216.184.93.in-addr.arpa
TYPE: PTR (12)
RDATA: example.com

IPv6 reverse:
2606:2800:220:1::1
→ 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.0.2.2.0.0.0.8.2.6.0.6.2.ip6.arpa

DNS Message Compression

To reduce message size, DNS uses pointer compression to eliminate duplicate domain names:

Compression format:

Domain name label length:
- 00-3F: Normal label length (0-63)
- C0-FF: Pointer (11xxxxxx xxxxxxxx)

Pointer format:
11 <14-bit offset>

Example:
Original message:
Offset 12: 3 "www" 7 "example" 3 "com" 0
Offset 30: 7 "example" 3 "com" 0

Compressed:
Offset 12: 3 "www" 7 "example" 3 "com" 0
Offset 30: C0 0x11 (points to offset 12+4="example")

Savings:
30: "example.com" (12 bytes)
Compressed to: C0 0x11 (2 bytes)
Saved: 10 bytes

Compression Example:

Query: www.example.com, A record for example.com

Uncompressed:
Question:
12: 3"www"7"example"3"com"0 (17 bytes)
Answer:
29: 3"www"7"example"3"com"0 (17 bytes)
46: 7"example"3"com"0 (13 bytes)

Compressed:
Question:
12: 3"www"7"example"3"com"0 (17 bytes)
Answer:
29: C0 0C (2 bytes, points to offset 12)
31: C0 10 (2 bytes, points to offset 16="example.com")

Total saved: (17-2) + (13-2) = 26 bytes

DNS Query Examples

Complete DNS Query/Response

# Python DNS query example

import socket
import struct

def build_dns_query(domain, qtype=1):
"""Build DNS query message"""

# Header
transaction_id = 0x1234
flags = 0x0100 # Standard query, recursion desired
qdcount = 1
ancount = 0
nscount = 0
arcount = 0

header = struct.pack('!HHHHHH',
transaction_id,
flags,
qdcount, ancount, nscount, arcount)

# Question
qname = b''
for part in domain.split('.'):
qname += struct.pack('B', len(part)) + part.encode()
qname += b'\x00' # End marker

question = qname + struct.pack('!HH', qtype, 1) # TYPE, CLASS

return header + question

def parse_dns_response(data):
"""Parse DNS response"""

# Parse Header
transaction_id, flags, qdcount, ancount, nscount, arcount = \
struct.unpack('!HHHHHH', data[:12])

print(f'Transaction ID: 0x{transaction_id:04x}')
print(f'Flags: 0x{flags:04x}')
print(f'Questions: {qdcount}')
print(f'Answers: {ancount}')

# Skip Question section
offset = 12
# (Simplified, actual parsing of QNAME needed)
while data[offset] != 0:
length = data[offset]
offset += length + 1
offset += 5 # End marker + QTYPE + QCLASS

# Parse Answer
for _ in range(ancount):
# NAME (may be pointer)
if (data[offset] & 0xC0) == 0xC0:
# Pointer
offset += 2
else:
# Full domain name
while data[offset] != 0:
length = data[offset]
offset += length + 1
offset += 1

# TYPE, CLASS, TTL, RDLENGTH
rtype, rclass, ttl, rdlength = struct.unpack('!HHIH',
data[offset:offset+10])
offset += 10

print(f'\nAnswer:')
print(f' Type: {rtype}')
print(f' TTL: {ttl}')

# RDATA
if rtype == 1: # A record
ip = '.'.join(str(b) for b in data[offset:offset+4])
print(f' IP: {ip}')

offset += rdlength

def dns_query(domain, dns_server='8.8.8.8', port=53):
"""Execute DNS query"""

# Build query
query = build_dns_query(domain)

# Send query (UDP)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(5.0)

try:
sock.sendto(query, (dns_server, port))
response, _ = sock.recvfrom(512)

print(f'Query {domain}:')
parse_dns_response(response)
finally:
sock.close()

# Usage
dns_query('example.com')

Output Example:

Query example.com:
Transaction ID: 0x1234
Flags: 0x8180
Questions: 1
Answers: 1

Answer:
Type: 1
TTL: 3600
IP: 93.184.216.34

Practical Tools

dig Command Details

# Basic query
dig example.com

# Specify record type
dig example.com A # IPv4
dig example.com AAAA # IPv6
dig example.com MX # Mail server
dig example.com NS # Name server
dig example.com TXT # Text record

# Specify DNS server
dig @8.8.8.8 example.com

# Trace query path
dig +trace example.com

# Short format output
dig +short example.com

# Reverse lookup
dig -x 93.184.216.34

# TCP query
dig +tcp example.com

# View complete response
dig +noall +answer +additional example.com

nslookup Usage

# Interactive mode
nslookup
> example.com
> set type=MX
> example.com
> exit

# Command line mode
nslookup example.com
nslookup -type=MX example.com
nslookup -type=NS example.com

host Command

# Simple query
host example.com

# Verbose output
host -v example.com

# Specify record type
host -t MX example.com
host -t NS example.com

References

Core RFCs:

  • [RFC 1034] Domain Names - Concepts and Facilities
  • [RFC 1035] Domain Names - Implementation and Specification ← This document

Extensions and Updates:

  • [RFC 2181] Clarifications to the DNS Specification
  • [RFC 2308] Negative Caching of DNS Queries (DNS NCACHE)
  • [RFC 4033] DNS Security Introduction and Requirements
  • [RFC 4034] Resource Records for the DNS Security Extensions
  • [RFC 4035] Protocol Modifications for the DNS Security Extensions
  • [RFC 6891] Extension Mechanisms for DNS (EDNS(0))

Related Protocols:

  • [RFC 8484] DNS Queries over HTTPS (DoH)
  • [RFC 7858] Specification for DNS over Transport Layer Security (TLS)

Summary: RFC 1035 defines the implementation details of DNS and is a key document for understanding how the DNS protocol works. From message formats to resource records, from query flows to compression mechanisms, this RFC provides detailed specifications for all DNS implementations. Together with RFC 1034, you will have a comprehensive understanding of the DNS system!