CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-dnspython

DNS toolkit for Python supporting almost all record types with high-level and low-level DNS operations

85

1.37x
Overview
Eval results
Files

dns-zones.mddocs/

DNS Zones

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.

Capabilities

Zone Creation

Create DNS zones from text files, zone transfers, or programmatically.

def from_text(text, origin=None, rdclass='IN', relativize=True, zone_factory=None,
              filename=None, allow_include=False, check_origin=True):
    """
    Parse a DNS zone from text format.
    
    Args:
        text (str): Zone file text content
        origin (str or dns.name.Name): Zone origin (default from SOA)
        rdclass (str or int): Record class (default 'IN')
        relativize (bool): Make names relative to origin
        zone_factory (class): Zone class to instantiate
        filename (str): Filename for error reporting
        allow_include (bool): Allow $INCLUDE directives
        check_origin (bool): Verify zone has proper SOA and NS records
        
    Returns:
        dns.zone.Zone: Parsed DNS zone
    """

def from_file(f, origin=None, rdclass='IN', relativize=True, zone_factory=None,
              filename=None, allow_include=True, check_origin=True):
    """
    Parse a DNS zone from a file.
    
    Args:
        f (file-like): File object to read from
        origin (str or dns.name.Name): Zone origin
        rdclass (str or int): Record class
        relativize (bool): Make names relative to origin
        zone_factory (class): Zone class to instantiate
        filename (str): Filename for error reporting
        allow_include (bool): Allow $INCLUDE directives
        check_origin (bool): Verify zone structure
        
    Returns:
        dns.zone.Zone: Parsed DNS zone
    """

def from_xfr(xfr, zone_factory=None, relativize=True, check_origin=True):
    """
    Create a DNS zone from a zone transfer.
    
    Args:
        xfr (generator): Zone transfer message generator
        zone_factory (class): Zone class to instantiate
        relativize (bool): Make names relative to origin
        check_origin (bool): Verify zone structure
        
    Returns:
        dns.zone.Zone: Zone created from transfer
    """

Zone Class

DNS zone represented as a mapping from names to nodes containing resource record sets.

class Zone:
    """
    A DNS zone as a mapping from names to nodes.
    
    A zone is a collection of DNS resource records with a common origin.
    The zone is represented as a mapping from names to nodes, where each
    node contains the resource record sets for that name.
    
    Attributes:
        nodes (dict): Mapping from names to nodes
        origin (dns.name.Name): Zone origin name
        rdclass (int): Zone record class
    """
    
    def __init__(self, origin, rdclass='IN', relativize=True):
        """
        Initialize a DNS zone.
        
        Args:
            origin (str or dns.name.Name): Zone origin
            rdclass (str or int): Record class
            relativize (bool): Store names relative to origin
        """
    
    def __repr__(self):
        """Return string representation of zone."""
    
    def __eq__(self, other):
        """Test zone equality."""
    
    def __ne__(self, other):
        """Test zone inequality."""
    
    def __iter__(self):
        """Iterate over names in zone."""
    
    def keys(self):
        """Return iterator over zone names."""
    
    def values(self):
        """Return iterator over zone nodes."""
    
    def items(self):
        """Return iterator over (name, node) pairs."""
    
    def __len__(self):
        """Return number of names in zone."""
    
    def __getitem__(self, key):
        """Get node by name."""
    
    def __setitem__(self, key, value):
        """Set node for name."""
    
    def __delitem__(self, key):
        """Delete node by name."""
    
    def __contains__(self, key):
        """Test if name exists in zone."""

Node Operations

Find, create, and manipulate nodes within the zone.

def find_node(name, create=False):
    """
    Find a node in the zone.
    
    Args:
        name (str or dns.name.Name): Node name
        create (bool): Create node if it doesn't exist
        
    Returns:
        dns.node.Node: Zone node
        
    Raises:
        KeyError: If name not found and create=False
    """

def get_node(name, create=False):
    """
    Get a node from the zone.
    
    Args:
        name (str or dns.name.Name): Node name
        create (bool): Create node if it doesn't exist
        
    Returns:
        dns.node.Node or None: Zone node or None if not found
    """

def delete_node(name):
    """
    Delete a node from the zone.
    
    Args:
        name (str or dns.name.Name): Node name to delete
        
    Raises:
        KeyError: If name not found
    """

RRset Operations

Find, get, and manipulate resource record sets within the zone.

def find_rdataset(name, rdtype, covers='NONE', create=False):
    """
    Find an rdataset in the zone.
    
    Args:
        name (str or dns.name.Name): Record name
        rdtype (str or int): Record type  
        covers (str or int): Covered type for RRSIG records
        create (bool): Create rdataset if not found
        
    Returns:
        dns.rdataset.Rdataset: Resource record set
    """

def get_rdataset(name, rdtype, covers='NONE', create=False):
    """
    Get an rdataset from the zone.
    
    Args:
        name (str or dns.name.Name): Record name
        rdtype (str or int): Record type
        covers (str or int): Covered type for RRSIG records  
        create (bool): Create rdataset if not found
        
    Returns:
        dns.rdataset.Rdataset or None: Rdataset or None if not found
    """

def delete_rdataset(name, rdtype, covers='NONE'):
    """
    Delete an rdataset from the zone.
    
    Args:
        name (str or dns.name.Name): Record name
        rdtype (str or int): Record type
        covers (str or int): Covered type for RRSIG records
    """

def replace_rdataset(name, replacement):
    """
    Replace an rdataset in the zone.
    
    Args:
        name (str or dns.name.Name): Record name
        replacement (dns.rdataset.Rdataset): Replacement rdataset
    """

RRset Operations

Work with complete resource record sets including name and TTL information.

def find_rrset(name, rdtype, covers='NONE'):
    """
    Find an RRset in the zone.
    
    Args:
        name (str or dns.name.Name): Record name
        rdtype (str or int): Record type
        covers (str or int): Covered type for RRSIG records
        
    Returns:
        dns.rrset.RRset: Resource record set
    """

def get_rrset(name, rdtype, covers='NONE'):
    """
    Get an RRset from the zone.
    
    Args:
        name (str or dns.name.Name): Record name
        rdtype (str or int): Record type  
        covers (str or int): Covered type for RRSIG records
        
    Returns:
        dns.rrset.RRset or None: RRset or None if not found
    """

Zone Iteration

Iterate over zone contents with filtering and processing options.

def iterate_rdatasets(rdtype='ANY', covers='NONE'):
    """
    Generate all rdatasets in the zone.
    
    Args:
        rdtype (str or int): Filter by record type ('ANY' for all)
        covers (str or int): Filter by covered type for RRSIG
        
    Yields:
        tuple: (name, rdataset) pairs
    """

def iterate_rdatas(rdtype='ANY', covers='NONE'):
    """
    Generate all resource records in the zone.
    
    Args:
        rdtype (str or int): Filter by record type ('ANY' for all)
        covers (str or int): Filter by covered type for RRSIG
        
    Yields:
        tuple: (name, ttl, rdata) tuples
    """

Zone Output

Convert zones to text format or write to files.

def to_file(f, sorted=True, relativize=True, nl=None):
    """
    Write zone to a file.
    
    Args:
        f (file-like): File to write to
        sorted (bool): Sort records by name
        relativize (bool): Make names relative to origin
        nl (bytes): Line ending (default system)
    """

def to_text(sorted=True, relativize=True, nl=None):
    """
    Convert zone to text format.
    
    Args:
        sorted (bool): Sort records by name
        relativize (bool): Make names relative to origin  
        nl (str): Line ending (default system)
        
    Returns:
        str: Zone in text format
    """

Zone Validation

Validate zone structure and check for required records.

def check_origin():
    """
    Check that the zone is properly structured.
    
    Validates that:
    - Zone has SOA record at origin
    - Zone has NS records at origin
    - SOA serial number is reasonable
    
    Raises:
        dns.zone.NoSOA: If no SOA at origin
        dns.zone.NoNS: If no NS at origin
        dns.zone.BadZone: If other structural problems
    """

Usage Examples

Loading Zone Files

import dns.zone
import dns.name

# Load zone from file
zone = dns.zone.from_file('example.com.zone', origin='example.com.')

print(f"Zone origin: {zone.origin}")
print(f"Zone class: {zone.rdclass}")
print(f"Number of names: {len(zone)}")

# Load zone from text
zone_text = '''
$ORIGIN example.com.
$TTL 3600
@   IN  SOA ns1.example.com. admin.example.com. (
            2023010101  ; serial
            10800       ; refresh
            3600        ; retry
            604800      ; expire
            86400 )     ; minimum

    IN  NS  ns1.example.com.
    IN  NS  ns2.example.com.
    
www IN  A   192.0.2.1
    IN  AAAA 2001:db8::1
mail IN A   192.0.2.2
'''

zone = dns.zone.from_text(zone_text)

Zone from Transfer

import dns.zone
import dns.query
import dns.name

# Perform zone transfer and create zone
zone_name = dns.name.from_text('example.com.')
xfr_messages = dns.query.xfr('ns1.example.com', zone_name)
zone = dns.zone.from_xfr(xfr_messages)

print(f"Transferred zone: {zone.origin}")
print(f"Zone records: {len(zone)}")

Zone Manipulation

import dns.zone
import dns.name
import dns.rdataset
import dns.rdatatype
import dns.rdataclass
import dns.rdata

# Create new zone
origin = dns.name.from_text('test.example.')
zone = dns.zone.Zone(origin)

# Add SOA record
soa_rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA,
    'ns1.test.example. admin.test.example. 1 3600 1800 1209600 300')
soa_rdataset = dns.rdataset.from_rdata(300, soa_rdata)
zone.replace_rdataset('@', soa_rdataset)

# Add NS records
ns_rdata1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns1.test.example.')
ns_rdata2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns2.test.example.')
ns_rdataset = dns.rdataset.from_rdata_list(300, [ns_rdata1, ns_rdata2])
zone.replace_rdataset('@', ns_rdataset)

# Add A record
www_name = dns.name.from_text('www', origin)
a_rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.10')
a_rdataset = dns.rdataset.from_rdata(300, a_rdata)
zone.replace_rdataset(www_name, a_rdataset)

Zone Querying and Iteration

import dns.zone
import dns.rdatatype

zone = dns.zone.from_file('example.com.zone')

# Find specific records
try:
    www_a = zone.find_rdataset('www', dns.rdatatype.A)
    print(f"www A records: {list(www_a)}")
except KeyError:
    print("www A record not found")

# Get records safely
mx_records = zone.get_rdataset('@', dns.rdatatype.MX)
if mx_records:
    print(f"MX records: {list(mx_records)}")

# Iterate over all records
print("All zone records:")
for name, rdataset in zone.iterate_rdatasets():
    print(f"{name} {rdataset.ttl} {rdataset.rdclass} {rdataset.rdtype}")
    for rdata in rdataset:
        print(f"  {rdata}")

# Filter by record type
print("Only A records:")
for name, rdataset in zone.iterate_rdatasets(rdtype=dns.rdatatype.A):
    for rdata in rdataset:
        print(f"{name} A {rdata.address}")

Zone Validation and Output

import dns.zone

zone = dns.zone.from_file('example.com.zone')

# Validate zone structure
try:
    zone.check_origin()
    print("Zone validation passed")
except dns.zone.NoSOA:
    print("Zone missing SOA record")
except dns.zone.NoNS:
    print("Zone missing NS records")
except dns.zone.BadZone as e:
    print(f"Zone validation failed: {e}")

# Output zone
print("Zone as text:")
print(zone.to_text())

# Write to file
with open('output.zone', 'w') as f:
    zone.to_file(f, sorted=True)

Node Class

class Node:
    """
    A DNS node containing resource record sets.
    
    A node represents all the resource records at a particular name
    in a DNS zone. It contains a mapping from (rdtype, covers) tuples
    to rdatasets.
    """
    
    def __init__(self):
        """Initialize empty node."""
    
    def find_rdataset(self, rdclass, rdtype, covers='NONE', create=False):
        """Find rdataset in node."""
    
    def get_rdataset(self, rdclass, rdtype, covers='NONE', create=False):
        """Get rdataset from node."""
    
    def delete_rdataset(self, rdclass, rdtype, covers='NONE'):
        """Delete rdataset from node."""
    
    def replace_rdataset(self, replacement):
        """Replace rdataset in node."""

Exceptions

class BadZone(DNSException):
    """The zone is malformed."""

class NoSOA(BadZone):
    """The zone has no SOA RR at its origin."""

class NoNS(BadZone):
    """The zone has no NS RRset at its origin."""

class UnknownOrigin(DNSException):
    """The zone's origin is unknown."""

Install with Tessl CLI

npx tessl i tessl/pypi-dnspython

docs

dns-constants.md

dns-exceptions.md

dns-messages.md

dns-names.md

dns-queries.md

dns-records.md

dns-resolution.md

dns-updates.md

dns-utilities.md

dns-zones.md

dnssec.md

index.md

tsig.md

tile.json