0
# DNS Queries
1
2
Low-level DNS query functions that provide direct control over DNS message exchange with nameservers. These functions handle UDP and TCP communication, zone transfers, and provide fine-grained control over query parameters.
3
4
## Capabilities
5
6
### UDP Queries
7
8
Send DNS queries using UDP protocol with full control over query parameters and response handling.
9
10
```python { .api }
11
def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
12
ignore_unexpected=False, one_rr_per_rrset=False, ignore_trailing=False):
13
"""
14
Send a DNS query via UDP.
15
16
Args:
17
q (dns.message.Message): DNS query message
18
where (str): Nameserver IP address
19
timeout (float): Query timeout in seconds
20
port (int): Destination port (default 53)
21
af (int): Address family (socket.AF_INET or socket.AF_INET6)
22
source (str): Source IP address
23
source_port (int): Source port number
24
ignore_unexpected (bool): Ignore responses from unexpected sources
25
one_rr_per_rrset (bool): Put each RR in its own RRset
26
ignore_trailing (bool): Ignore trailing junk in packets
27
28
Returns:
29
dns.message.Message: DNS response message
30
"""
31
32
def send_udp(sock, what, destination, expiration=None):
33
"""
34
Send a DNS message to the specified UDP socket destination.
35
36
Args:
37
sock (socket): UDP socket
38
what (dns.message.Message or bytes): Message to send
39
destination (tuple): (address, port) tuple
40
expiration (float): Absolute expiration time
41
"""
42
43
def receive_udp(sock, destination, expiration=None, ignore_unexpected=False,
44
one_rr_per_rrset=False, keyring=None, request_mac=b'',
45
ignore_trailing=False):
46
"""
47
Read a DNS message from a UDP socket.
48
49
Args:
50
sock (socket): UDP socket
51
destination (tuple): Expected source (address, port)
52
expiration (float): Absolute expiration time
53
ignore_unexpected (bool): Ignore responses from unexpected sources
54
one_rr_per_rrset (bool): Put each RR in its own RRset
55
keyring (dict): TSIG keyring for validation
56
request_mac (bytes): TSIG MAC from request
57
ignore_trailing (bool): Ignore trailing junk in packets
58
59
Returns:
60
dns.message.Message: DNS response message
61
"""
62
```
63
64
### TCP Queries
65
66
Send DNS queries using TCP protocol for reliable delivery and large responses.
67
68
```python { .api }
69
def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
70
one_rr_per_rrset=False, ignore_trailing=False):
71
"""
72
Send a DNS query via TCP.
73
74
Args:
75
q (dns.message.Message): DNS query message
76
where (str): Nameserver IP address
77
timeout (float): Query timeout in seconds
78
port (int): Destination port (default 53)
79
af (int): Address family (socket.AF_INET or socket.AF_INET6)
80
source (str): Source IP address
81
source_port (int): Source port number
82
one_rr_per_rrset (bool): Put each RR in its own RRset
83
ignore_trailing (bool): Ignore trailing junk in packets
84
85
Returns:
86
dns.message.Message: DNS response message
87
"""
88
89
def send_tcp(sock, what, expiration=None):
90
"""
91
Send a DNS message to the specified TCP socket.
92
93
Args:
94
sock (socket): TCP socket
95
what (dns.message.Message or bytes): Message to send
96
expiration (float): Absolute expiration time
97
"""
98
99
def receive_tcp(sock, expiration=None, one_rr_per_rrset=False, keyring=None,
100
request_mac=b'', ignore_trailing=False):
101
"""
102
Read a DNS message from a TCP socket.
103
104
Args:
105
sock (socket): TCP socket
106
expiration (float): Absolute expiration time
107
one_rr_per_rrset (bool): Put each RR in its own RRset
108
keyring (dict): TSIG keyring for validation
109
request_mac (bytes): TSIG MAC from request
110
ignore_trailing (bool): Ignore trailing junk in packets
111
112
Returns:
113
dns.message.Message: DNS response message
114
"""
115
```
116
117
### Zone Transfers
118
119
Perform zone transfers (AXFR/IXFR) to retrieve complete zone data from authoritative servers.
120
121
```python { .api }
122
def xfr(where, zone, rdtype='AXFR', rdclass='IN', timeout=None, port=53,
123
keyring=None, keyname=None, relativize=True, af=None, lifetime=None,
124
source=None, source_port=0, serial=0, use_udp=False,
125
keyalgorithm='HMAC-MD5.SIG-ALG.REG.INT'):
126
"""
127
Perform a zone transfer and return a generator yielding messages.
128
129
Args:
130
where (str): Nameserver IP address
131
zone (str or dns.name.Name): Zone name
132
rdtype (str or int): Transfer type ('AXFR' or 'IXFR')
133
rdclass (str or int): Record class (default 'IN')
134
timeout (float): Query timeout in seconds
135
port (int): Destination port (default 53)
136
keyring (dict): TSIG keyring for authentication
137
keyname (str or dns.name.Name): TSIG key name
138
relativize (bool): Relativize names to zone origin
139
af (int): Address family
140
lifetime (float): Total transfer lifetime
141
source (str): Source IP address
142
source_port (int): Source port number
143
serial (int): Serial number for IXFR
144
use_udp (bool): Use UDP for IXFR
145
keyalgorithm (str): TSIG algorithm name
146
147
Yields:
148
dns.message.Message: Transfer response messages
149
"""
150
```
151
152
### Helper Functions
153
154
Utility functions for working with sockets and query timing.
155
156
```python { .api }
157
def _compute_expiration(timeout):
158
"""
159
Compute absolute expiration time from timeout.
160
161
Args:
162
timeout (float): Timeout in seconds
163
164
Returns:
165
float: Absolute expiration time
166
"""
167
168
def _matches_destination(af, address, destination, ignore_unexpected):
169
"""
170
Check if address matches expected destination.
171
172
Args:
173
af (int): Address family
174
address (tuple): Actual source address
175
destination (tuple): Expected destination
176
ignore_unexpected (bool): Ignore unexpected sources
177
178
Returns:
179
bool: True if addresses match or should be ignored
180
"""
181
```
182
183
## Usage Examples
184
185
### Basic UDP Query
186
187
```python
188
import dns.message
189
import dns.query
190
import dns.name
191
import dns.rdatatype
192
193
# Create a query message
194
qname = dns.name.from_text('example.com')
195
q = dns.message.make_query(qname, dns.rdatatype.A)
196
197
# Send UDP query
198
response = dns.query.udp(q, '8.8.8.8', timeout=10)
199
200
# Process response
201
for rrset in response.answer:
202
for rdata in rrset:
203
if rrset.rdtype == dns.rdatatype.A:
204
print(f"IP address: {rdata.address}")
205
```
206
207
### TCP Query with Custom Options
208
209
```python
210
import dns.message
211
import dns.query
212
import dns.name
213
import dns.rdatatype
214
215
# Create query with EDNS
216
qname = dns.name.from_text('large-response.example.com')
217
q = dns.message.make_query(qname, dns.rdatatype.TXT, use_edns=0, payload=4096)
218
219
# Send TCP query with custom source
220
response = dns.query.tcp(q, '8.8.8.8', timeout=30, source='192.168.1.100',
221
source_port=12345)
222
223
# Check response
224
print(f"Response code: {response.rcode()}")
225
print(f"Answer count: {len(response.answer)}")
226
```
227
228
### Zone Transfer
229
230
```python
231
import dns.query
232
import dns.zone
233
import dns.name
234
235
# Perform AXFR zone transfer
236
zone_name = dns.name.from_text('example.com')
237
zone_messages = dns.query.xfr('ns1.example.com', zone_name,
238
timeout=300, lifetime=600)
239
240
# Build zone from transfer
241
zone = dns.zone.from_xfr(zone_messages)
242
243
# Iterate through zone records
244
for name, node in zone.nodes.items():
245
for rdataset in node.rdatasets:
246
print(f"{name} {rdataset.ttl} {rdataset.rdclass} {rdataset.rdtype}")
247
for rdata in rdataset:
248
print(f" {rdata}")
249
```
250
251
### Authenticated Query with TSIG
252
253
```python
254
import dns.message
255
import dns.query
256
import dns.tsigkeyring
257
import dns.name
258
259
# Create TSIG keyring
260
keyring = dns.tsigkeyring.from_text({
261
'key-name': 'base64-encoded-key'
262
})
263
264
# Create authenticated query
265
qname = dns.name.from_text('secure.example.com')
266
q = dns.message.make_query(qname, dns.rdatatype.A)
267
q.use_tsig(keyring, 'key-name')
268
269
# Send authenticated query
270
response = dns.query.udp(q, '192.168.1.1', timeout=10)
271
272
# Verify response authentication
273
if response.tsig_error() == 0:
274
print("Response verified successfully")
275
else:
276
print(f"TSIG verification failed: {response.tsig_error()}")
277
```
278
279
## Exceptions
280
281
```python { .api }
282
class UnexpectedSource(DNSException):
283
"""A DNS query response came from an unexpected address or port."""
284
285
class BadResponse(DNSException):
286
"""A DNS query response does not respond to the question asked."""
287
288
class TransferError(DNSException):
289
"""A zone transfer response had a non-zero rcode."""
290
```