0
# DNS Zones
1
2
DNS zone parsing, creation, and manipulation functionality. Provides complete zone file support including zone transfers, zone validation, and comprehensive zone data operations for authoritative DNS server implementations.
3
4
## Capabilities
5
6
### Zone Creation
7
8
Create DNS zones from text files, zone transfers, or programmatically.
9
10
```python { .api }
11
def from_text(text, origin=None, rdclass='IN', relativize=True, zone_factory=None,
12
filename=None, allow_include=False, check_origin=True):
13
"""
14
Parse a DNS zone from text format.
15
16
Args:
17
text (str): Zone file text content
18
origin (str or dns.name.Name): Zone origin (default from SOA)
19
rdclass (str or int): Record class (default 'IN')
20
relativize (bool): Make names relative to origin
21
zone_factory (class): Zone class to instantiate
22
filename (str): Filename for error reporting
23
allow_include (bool): Allow $INCLUDE directives
24
check_origin (bool): Verify zone has proper SOA and NS records
25
26
Returns:
27
dns.zone.Zone: Parsed DNS zone
28
"""
29
30
def from_file(f, origin=None, rdclass='IN', relativize=True, zone_factory=None,
31
filename=None, allow_include=True, check_origin=True):
32
"""
33
Parse a DNS zone from a file.
34
35
Args:
36
f (file-like): File object to read from
37
origin (str or dns.name.Name): Zone origin
38
rdclass (str or int): Record class
39
relativize (bool): Make names relative to origin
40
zone_factory (class): Zone class to instantiate
41
filename (str): Filename for error reporting
42
allow_include (bool): Allow $INCLUDE directives
43
check_origin (bool): Verify zone structure
44
45
Returns:
46
dns.zone.Zone: Parsed DNS zone
47
"""
48
49
def from_xfr(xfr, zone_factory=None, relativize=True, check_origin=True):
50
"""
51
Create a DNS zone from a zone transfer.
52
53
Args:
54
xfr (generator): Zone transfer message generator
55
zone_factory (class): Zone class to instantiate
56
relativize (bool): Make names relative to origin
57
check_origin (bool): Verify zone structure
58
59
Returns:
60
dns.zone.Zone: Zone created from transfer
61
"""
62
```
63
64
### Zone Class
65
66
DNS zone represented as a mapping from names to nodes containing resource record sets.
67
68
```python { .api }
69
class Zone:
70
"""
71
A DNS zone as a mapping from names to nodes.
72
73
A zone is a collection of DNS resource records with a common origin.
74
The zone is represented as a mapping from names to nodes, where each
75
node contains the resource record sets for that name.
76
77
Attributes:
78
nodes (dict): Mapping from names to nodes
79
origin (dns.name.Name): Zone origin name
80
rdclass (int): Zone record class
81
"""
82
83
def __init__(self, origin, rdclass='IN', relativize=True):
84
"""
85
Initialize a DNS zone.
86
87
Args:
88
origin (str or dns.name.Name): Zone origin
89
rdclass (str or int): Record class
90
relativize (bool): Store names relative to origin
91
"""
92
93
def __repr__(self):
94
"""Return string representation of zone."""
95
96
def __eq__(self, other):
97
"""Test zone equality."""
98
99
def __ne__(self, other):
100
"""Test zone inequality."""
101
102
def __iter__(self):
103
"""Iterate over names in zone."""
104
105
def keys(self):
106
"""Return iterator over zone names."""
107
108
def values(self):
109
"""Return iterator over zone nodes."""
110
111
def items(self):
112
"""Return iterator over (name, node) pairs."""
113
114
def __len__(self):
115
"""Return number of names in zone."""
116
117
def __getitem__(self, key):
118
"""Get node by name."""
119
120
def __setitem__(self, key, value):
121
"""Set node for name."""
122
123
def __delitem__(self, key):
124
"""Delete node by name."""
125
126
def __contains__(self, key):
127
"""Test if name exists in zone."""
128
```
129
130
### Node Operations
131
132
Find, create, and manipulate nodes within the zone.
133
134
```python { .api }
135
def find_node(name, create=False):
136
"""
137
Find a node in the zone.
138
139
Args:
140
name (str or dns.name.Name): Node name
141
create (bool): Create node if it doesn't exist
142
143
Returns:
144
dns.node.Node: Zone node
145
146
Raises:
147
KeyError: If name not found and create=False
148
"""
149
150
def get_node(name, create=False):
151
"""
152
Get a node from the zone.
153
154
Args:
155
name (str or dns.name.Name): Node name
156
create (bool): Create node if it doesn't exist
157
158
Returns:
159
dns.node.Node or None: Zone node or None if not found
160
"""
161
162
def delete_node(name):
163
"""
164
Delete a node from the zone.
165
166
Args:
167
name (str or dns.name.Name): Node name to delete
168
169
Raises:
170
KeyError: If name not found
171
"""
172
```
173
174
### RRset Operations
175
176
Find, get, and manipulate resource record sets within the zone.
177
178
```python { .api }
179
def find_rdataset(name, rdtype, covers='NONE', create=False):
180
"""
181
Find an rdataset in the zone.
182
183
Args:
184
name (str or dns.name.Name): Record name
185
rdtype (str or int): Record type
186
covers (str or int): Covered type for RRSIG records
187
create (bool): Create rdataset if not found
188
189
Returns:
190
dns.rdataset.Rdataset: Resource record set
191
"""
192
193
def get_rdataset(name, rdtype, covers='NONE', create=False):
194
"""
195
Get an rdataset from the zone.
196
197
Args:
198
name (str or dns.name.Name): Record name
199
rdtype (str or int): Record type
200
covers (str or int): Covered type for RRSIG records
201
create (bool): Create rdataset if not found
202
203
Returns:
204
dns.rdataset.Rdataset or None: Rdataset or None if not found
205
"""
206
207
def delete_rdataset(name, rdtype, covers='NONE'):
208
"""
209
Delete an rdataset from the zone.
210
211
Args:
212
name (str or dns.name.Name): Record name
213
rdtype (str or int): Record type
214
covers (str or int): Covered type for RRSIG records
215
"""
216
217
def replace_rdataset(name, replacement):
218
"""
219
Replace an rdataset in the zone.
220
221
Args:
222
name (str or dns.name.Name): Record name
223
replacement (dns.rdataset.Rdataset): Replacement rdataset
224
"""
225
```
226
227
### RRset Operations
228
229
Work with complete resource record sets including name and TTL information.
230
231
```python { .api }
232
def find_rrset(name, rdtype, covers='NONE'):
233
"""
234
Find an RRset in the zone.
235
236
Args:
237
name (str or dns.name.Name): Record name
238
rdtype (str or int): Record type
239
covers (str or int): Covered type for RRSIG records
240
241
Returns:
242
dns.rrset.RRset: Resource record set
243
"""
244
245
def get_rrset(name, rdtype, covers='NONE'):
246
"""
247
Get an RRset from the zone.
248
249
Args:
250
name (str or dns.name.Name): Record name
251
rdtype (str or int): Record type
252
covers (str or int): Covered type for RRSIG records
253
254
Returns:
255
dns.rrset.RRset or None: RRset or None if not found
256
"""
257
```
258
259
### Zone Iteration
260
261
Iterate over zone contents with filtering and processing options.
262
263
```python { .api }
264
def iterate_rdatasets(rdtype='ANY', covers='NONE'):
265
"""
266
Generate all rdatasets in the zone.
267
268
Args:
269
rdtype (str or int): Filter by record type ('ANY' for all)
270
covers (str or int): Filter by covered type for RRSIG
271
272
Yields:
273
tuple: (name, rdataset) pairs
274
"""
275
276
def iterate_rdatas(rdtype='ANY', covers='NONE'):
277
"""
278
Generate all resource records in the zone.
279
280
Args:
281
rdtype (str or int): Filter by record type ('ANY' for all)
282
covers (str or int): Filter by covered type for RRSIG
283
284
Yields:
285
tuple: (name, ttl, rdata) tuples
286
"""
287
```
288
289
### Zone Output
290
291
Convert zones to text format or write to files.
292
293
```python { .api }
294
def to_file(f, sorted=True, relativize=True, nl=None):
295
"""
296
Write zone to a file.
297
298
Args:
299
f (file-like): File to write to
300
sorted (bool): Sort records by name
301
relativize (bool): Make names relative to origin
302
nl (bytes): Line ending (default system)
303
"""
304
305
def to_text(sorted=True, relativize=True, nl=None):
306
"""
307
Convert zone to text format.
308
309
Args:
310
sorted (bool): Sort records by name
311
relativize (bool): Make names relative to origin
312
nl (str): Line ending (default system)
313
314
Returns:
315
str: Zone in text format
316
"""
317
```
318
319
### Zone Validation
320
321
Validate zone structure and check for required records.
322
323
```python { .api }
324
def check_origin():
325
"""
326
Check that the zone is properly structured.
327
328
Validates that:
329
- Zone has SOA record at origin
330
- Zone has NS records at origin
331
- SOA serial number is reasonable
332
333
Raises:
334
dns.zone.NoSOA: If no SOA at origin
335
dns.zone.NoNS: If no NS at origin
336
dns.zone.BadZone: If other structural problems
337
"""
338
```
339
340
## Usage Examples
341
342
### Loading Zone Files
343
344
```python
345
import dns.zone
346
import dns.name
347
348
# Load zone from file
349
zone = dns.zone.from_file('example.com.zone', origin='example.com.')
350
351
print(f"Zone origin: {zone.origin}")
352
print(f"Zone class: {zone.rdclass}")
353
print(f"Number of names: {len(zone)}")
354
355
# Load zone from text
356
zone_text = '''
357
$ORIGIN example.com.
358
$TTL 3600
359
@ IN SOA ns1.example.com. admin.example.com. (
360
2023010101 ; serial
361
10800 ; refresh
362
3600 ; retry
363
604800 ; expire
364
86400 ) ; minimum
365
366
IN NS ns1.example.com.
367
IN NS ns2.example.com.
368
369
www IN A 192.0.2.1
370
IN AAAA 2001:db8::1
371
mail IN A 192.0.2.2
372
'''
373
374
zone = dns.zone.from_text(zone_text)
375
```
376
377
### Zone from Transfer
378
379
```python
380
import dns.zone
381
import dns.query
382
import dns.name
383
384
# Perform zone transfer and create zone
385
zone_name = dns.name.from_text('example.com.')
386
xfr_messages = dns.query.xfr('ns1.example.com', zone_name)
387
zone = dns.zone.from_xfr(xfr_messages)
388
389
print(f"Transferred zone: {zone.origin}")
390
print(f"Zone records: {len(zone)}")
391
```
392
393
### Zone Manipulation
394
395
```python
396
import dns.zone
397
import dns.name
398
import dns.rdataset
399
import dns.rdatatype
400
import dns.rdataclass
401
import dns.rdata
402
403
# Create new zone
404
origin = dns.name.from_text('test.example.')
405
zone = dns.zone.Zone(origin)
406
407
# Add SOA record
408
soa_rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
409
'ns1.test.example. admin.test.example. 1 3600 1800 1209600 300')
410
soa_rdataset = dns.rdataset.from_rdata(300, soa_rdata)
411
zone.replace_rdataset('@', soa_rdataset)
412
413
# Add NS records
414
ns_rdata1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns1.test.example.')
415
ns_rdata2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns2.test.example.')
416
ns_rdataset = dns.rdataset.from_rdata_list(300, [ns_rdata1, ns_rdata2])
417
zone.replace_rdataset('@', ns_rdataset)
418
419
# Add A record
420
www_name = dns.name.from_text('www', origin)
421
a_rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.10')
422
a_rdataset = dns.rdataset.from_rdata(300, a_rdata)
423
zone.replace_rdataset(www_name, a_rdataset)
424
```
425
426
### Zone Querying and Iteration
427
428
```python
429
import dns.zone
430
import dns.rdatatype
431
432
zone = dns.zone.from_file('example.com.zone')
433
434
# Find specific records
435
try:
436
www_a = zone.find_rdataset('www', dns.rdatatype.A)
437
print(f"www A records: {list(www_a)}")
438
except KeyError:
439
print("www A record not found")
440
441
# Get records safely
442
mx_records = zone.get_rdataset('@', dns.rdatatype.MX)
443
if mx_records:
444
print(f"MX records: {list(mx_records)}")
445
446
# Iterate over all records
447
print("All zone records:")
448
for name, rdataset in zone.iterate_rdatasets():
449
print(f"{name} {rdataset.ttl} {rdataset.rdclass} {rdataset.rdtype}")
450
for rdata in rdataset:
451
print(f" {rdata}")
452
453
# Filter by record type
454
print("Only A records:")
455
for name, rdataset in zone.iterate_rdatasets(rdtype=dns.rdatatype.A):
456
for rdata in rdataset:
457
print(f"{name} A {rdata.address}")
458
```
459
460
### Zone Validation and Output
461
462
```python
463
import dns.zone
464
465
zone = dns.zone.from_file('example.com.zone')
466
467
# Validate zone structure
468
try:
469
zone.check_origin()
470
print("Zone validation passed")
471
except dns.zone.NoSOA:
472
print("Zone missing SOA record")
473
except dns.zone.NoNS:
474
print("Zone missing NS records")
475
except dns.zone.BadZone as e:
476
print(f"Zone validation failed: {e}")
477
478
# Output zone
479
print("Zone as text:")
480
print(zone.to_text())
481
482
# Write to file
483
with open('output.zone', 'w') as f:
484
zone.to_file(f, sorted=True)
485
```
486
487
## Node Class
488
489
```python { .api }
490
class Node:
491
"""
492
A DNS node containing resource record sets.
493
494
A node represents all the resource records at a particular name
495
in a DNS zone. It contains a mapping from (rdtype, covers) tuples
496
to rdatasets.
497
"""
498
499
def __init__(self):
500
"""Initialize empty node."""
501
502
def find_rdataset(self, rdclass, rdtype, covers='NONE', create=False):
503
"""Find rdataset in node."""
504
505
def get_rdataset(self, rdclass, rdtype, covers='NONE', create=False):
506
"""Get rdataset from node."""
507
508
def delete_rdataset(self, rdclass, rdtype, covers='NONE'):
509
"""Delete rdataset from node."""
510
511
def replace_rdataset(self, replacement):
512
"""Replace rdataset in node."""
513
```
514
515
## Exceptions
516
517
```python { .api }
518
class BadZone(DNSException):
519
"""The zone is malformed."""
520
521
class NoSOA(BadZone):
522
"""The zone has no SOA RR at its origin."""
523
524
class NoNS(BadZone):
525
"""The zone has no NS RRset at its origin."""
526
527
class UnknownOrigin(DNSException):
528
"""The zone's origin is unknown."""
529
```