### Install dnspython from source on Windows Source: https://github.com/rthalley/dnspython/blob/main/doc/installation.md Install dnspython by building from source on Windows systems. ```default python setup.py install ``` -------------------------------- ### Install dnspython from source on UNIX-like systems Source: https://github.com/rthalley/dnspython/blob/main/doc/installation.md Install dnspython by building from source on UNIX-like systems using sudo. ```default sudo python setup.py install ``` -------------------------------- ### Install dnspython from source Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython from its source code. This involves upgrading pip and build, building the wheel, and then installing the wheel file. ```bash pip install --upgrade pip build python -m build pip install dist/*.whl ``` -------------------------------- ### Install dnspython with experimental DoQ support Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython with the optional dependency for experimental DNS-over-QUIC (DoQ) functionality. ```bash pip install dnspython[doq] ``` -------------------------------- ### Install dnspython with Trio support Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython with the optional dependency for integration with the Trio asynchronous I/O package. ```bash pip install dnspython[trio] ``` -------------------------------- ### Install dnspython using pip Source: https://github.com/rthalley/dnspython/blob/main/doc/installation.md Use this command to install dnspython via pip, the standard Python package installer. ```default pip install dnspython ``` -------------------------------- ### Install dnspython with DNSSEC support Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython with the optional dependency for DNSSEC functionality. ```bash pip install dnspython[dnssec] ``` -------------------------------- ### Install dnspython with multiple optional features Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython with a combination of optional features, such as DoH, DNSSEC, and IDNA. ```bash pip install dnspython[doh,dnssec,idna] ``` -------------------------------- ### Install dnspython with IDNA support Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython with the optional dependency for internationalized domain names (IDNA) functionality. ```bash pip install dnspython[idna] ``` -------------------------------- ### Install dnspython using pip Source: https://github.com/rthalley/dnspython/blob/main/README.md Install the dnspython package using pip. This is the standard method for installing Python packages. ```bash pip install dnspython ``` -------------------------------- ### Install latest dnspython from GitHub Source: https://github.com/rthalley/dnspython/blob/main/README.md Install the latest development version of dnspython directly from its GitHub repository using pip. ```bash pip install git+https://github.com/rthalley/dnspython.git ``` -------------------------------- ### Install dnspython with DNS-over-HTTPS support Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython with the optional dependency for DNS-over-HTTPS (DoH) functionality. ```bash pip install dnspython[doh] ``` -------------------------------- ### Install dnspython with WMI support on Windows Source: https://github.com/rthalley/dnspython/blob/main/README.md Install dnspython with the optional dependency for using WMI on Windows to determine active DNS settings. ```bash pip install dnspython[wmi] ``` -------------------------------- ### Asynchronous DNS Resolution Source: https://context7.com/rthalley/dnspython/llms.txt Provides examples of asynchronous DNS resolution using dns.asyncresolver, supporting asyncio and Trio. Covers high-level resolution, custom nameservers, reverse lookups, and low-level queries. ```python import asyncio import dns.asyncresolver import dns.asyncquery import dns.message async def main(): # High-level async resolution answer = await dns.asyncresolver.resolve("example.com", "A") for rdata in answer: print(f"A: {rdata.address}") # Async resolver with custom nameservers resolver = dns.asyncresolver.Resolver(configure=False) resolver.nameservers = ["8.8.8.8"] # Async reverse lookup answer = await resolver.resolve_address("8.8.8.8") for rdata in answer: print(f"PTR: {rdata.target}") # resolve_name: A + AAAA in parallel answers = await resolver.resolve_name("example.com") for addr in answers.addresses(): print(addr) # zone_for_name: find authoritative zone zone = await dns.asyncresolver.zone_for_name("www.example.com") print(f"Authoritative zone: {zone}") # Async resolve at a specific server (convenience function) answer = await dns.asyncresolver.resolve_at("8.8.8.8", "google.com", "NS") for rdata in answer: print(rdata.target) # DDR upgrade in async context await resolver.try_ddr() print(resolver.nameservers) # Low-level async queries q = dns.message.make_query("example.com.", "AAAA") r = await dns.asyncquery.udp(q, "8.8.8.8") r2 = await dns.asyncquery.tcp(q, "8.8.8.8") r3 = await dns.asyncquery.tls(q, "1.1.1.1") asyncio.run(main()) ``` -------------------------------- ### DNS Rdata Ordering Example Source: https://github.com/rthalley/dnspython/blob/main/doc/rdata-class.md Illustrates the difference in sorting behavior between relative and absolute domain names in Rdata objects. Comparing relative and absolute rdata is deprecated. ```dns $ORIGIN example. name 300 IN NS a ; 1 NS a. ; 2 ``` -------------------------------- ### Validate DNSSEC signatures and create DS records Source: https://context7.com/rthalley/dnspython/llms.txt Demonstrates DNSSEC signature validation and creating DS records. Requires `dnspython[dnssec]` to be installed. Fetch RRset, RRSIG, and DNSKEY to perform validation. ```python import dns.dnssec import dns.name import dns.rdataset import dns.resolver import dns.query import dns.rdatatype # Validate an RRset signature # (Fetch the RRset, RRSIG, and DNSKEY from a resolver) name = dns.name.from_text("example.com.") request = dns.message.make_query(name, dns.rdatatype.A, want_dnssec=True) response = dns.query.udp(request, "8.8.8.8") answer_rrset = None rrsig_rrset = None for rrset in response.answer: if rrset.rdtype == dns.rdatatype.A: answer_rrset = rrset elif rrset.rdtype == dns.rdatatype.RRSIG: rrsig_rrset = rrset # Get the zone's DNSKEY dnskey_answer = dns.resolver.resolve(name, "DNSKEY") try: dns.dnssec.validate( answer_rrset, rrsig_rrset, {name: dnskey_answer.rrset}, ) print("Signature valid!") except dns.dnssec.ValidationFailure as e: print(f"Validation failed: {e}") # Make a DS record from a DNSKEY ds_rrset = dns.dnssec.make_ds( name, dnskey_answer.rrset[0], algorithm="SHA256", ) print(ds_rrset) ``` -------------------------------- ### TSIG-Authenticated Resolver Configuration Source: https://context7.com/rthalley/dnspython/llms.txt Demonstrates how to configure a dns.resolver.Resolver to sign every query with a TSIG key for authenticated communication with nameservers. ```python import dns.resolver import dns.tsig import dns.tsigkeyring # Example usage would involve creating a TSIG key and configuring the resolver: # keyring = dns.tsigkeyring.from_text({ # "mykey": "mysecretkey" # }) # resolver = dns.resolver.Resolver() # resolver.use_tsig(keyring, "mykey") ``` -------------------------------- ### Configure DNS Resolver Cache Source: https://context7.com/rthalley/dnspython/llms.txt Demonstrates setting up a time-expiring cache with a cleaning interval and an LRU cache with a maximum size. ```python import dns.resolver # Simple time-expiring cache resolver = dns.resolver.Resolver() resolver.cache = dns.resolver.Cache(cleaning_interval=300.0) resolver.resolve("example.com", "A") resolver.resolve("example.com", "A") # served from cache stats = resolver.cache.get_statistics_snapshot() print(f"Hits: {stats.hits}, Misses: {stats.misses}") # Hits: 1, Misses: 1 # LRU cache with max 10000 entries resolver2 = dns.resolver.Resolver() resolver2.cache = dns.resolver.LRUCache(max_size=10000) resolver2.resolve("google.com", "A") # Check per-key hits key = (dns.name.from_text("google.com"), dns.rdatatype.A, dns.rdataclass.IN) print(resolver2.cache.get_hits_for_key(key)) # 0 (just stored, not re-hit yet) # Flush a specific entry resolver2.cache.flush(key) # Flush entire cache resolver.cache.flush() ``` -------------------------------- ### Configuring TSIG Authentication Source: https://context7.com/rthalley/dnspython/llms.txt Demonstrates how to configure TSIG authentication for a DNS resolver using either a dns.tsig.Key object or a keyring dictionary. ```APIDOC ## Method 1: using a dns.tsig.Key object resolver = dns.resolver.Resolver(configure=False) resolver.nameservers = ["10.0.0.1"] key = dns.tsig.Key("mykey.", "c2VjcmV0a2V5MTIzNDU2Nzg=", algorithm=dns.tsig.HMAC_SHA256) resolver.use_tsig(keyring=key) answer = resolver.resolve("internal.corp.", "A") ## Method 2: using a keyring dict (compatible with tsigkeyring) keyring = dns.tsigkeyring.from_text({ "transfer-key.": "NjHwPsMKjdN++dOfE5iAiQ==" }) resolver2 = dns.resolver.Resolver(configure=False) resolver2.nameservers = ["10.0.0.1"] resolver2.use_tsig(keyring, keyname="transfer-key.") answer = resolver2.resolve("example.corp.", "SOA") ``` -------------------------------- ### Load DNS Zones from Text and File Source: https://context7.com/rthalley/dnspython/llms.txt Shows how to parse DNS zone data from a string or a file into a dns.zone.Zone object. Includes iterating records, looking up nodes, and writing zones back to text. ```python import io import dns.zone import dns.rdatatype ZONE_TEXT = """ $ORIGIN example.com. $TTL 3600 @ IN SOA ns1 admin 2024010101 3600 900 604800 300 @ IN NS ns1.example.com. @ IN A 93.184.216.34 ns1 IN A 93.184.216.35 www IN A 93.184.216.36 mail IN MX 10 mail.example.com. mail IN A 93.184.216.37 """ # Load from string zone = dns.zone.from_text(ZONE_TEXT, origin="example.com.") # Iterate all A records for name, ttl, rdata in zone.iterate_rdatas("A"): print(f"{name}.example.com. {ttl} A {rdata.address}") # Lookup a specific node node = zone["www"] rdataset = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.A) for rdata in rdataset: print(rdata.address) # 93.184.216.36 # Load from file (zone name taken from filename) # zone2 = dns.zone.from_file("/etc/bind/zones/example.com", # origin="example.com.", relativize=False) # Write zone to text print(zone.to_text()) ``` -------------------------------- ### dns.dnssec — DNSSEC validation and signing Source: https://context7.com/rthalley/dnspython/llms.txt Provides DNSSEC signature validation and zone signing. Requires `pip install dnspython[dnssec]` (installs the `cryptography` package). ```APIDOC ## dns.dnssec — DNSSEC validation and signing Provides DNSSEC signature validation and zone signing. Requires `pip install dnspython[dnssec]` (installs the `cryptography` package). ```python import dns.dnssec import dns.name import dns.rdataset import dns.resolver # Validate an RRset signature # (Fetch the RRset, RRSIG, and DNSKEY from a resolver) name = dns.name.from_text("example.com.") request = dns.message.make_query(name, dns.rdatatype.A, want_dnssec=True) response = dns.query.udp(request, "8.8.8.8") answer_rrset = None rrsig_rrset = None for rrset in response.answer: if rrset.rdtype == dns.rdatatype.A: answer_rrset = rrset elif rrset.rdtype == dns.rdatatype.RRSIG: rrsig_rrset = rrset # Get the zone's DNSKEY dnskey_answer = dns.resolver.resolve(name, "DNSKEY") try: dns.dnssec.validate( answer_rrset, rrsig_rrset, {name: dnskey_answer.rrset}, ) print("Signature valid!") except dns.dnssec.ValidationFailure as e: print(f"Validation failed: {e}") # Make a DS record from a DNSKEY ds_rrset = dns.dnssec.make_ds( name, dnskey_answer.rrset[0], algorithm="SHA256", ) print(ds_rrset) ``` ``` -------------------------------- ### Rdata Class and Type Constants Source: https://github.com/rthalley/dnspython/blob/main/doc/rdata-types.md Examples of constants for rdata classes and types. These are used to specify the class and type of an rdata. ```python dns.rdataclass.IN dns.rdatatype.AAAA ``` -------------------------------- ### Configure TSIG authentication for DNS queries Source: https://context7.com/rthalley/dnspython/llms.txt Demonstrates two methods for configuring TSIG authentication: using a dns.tsig.Key object or a keyring dictionary. Ensure the key secret is correctly base64 encoded. ```python import dns.resolver import dns.tsig import dns.tsigkeyring # Method 1: using a dns.tsig.Key object resolver = dns.resolver.Resolver(configure=False) resolver.nameservers = ["10.0.0.1"] key = dns.tsig.Key("mykey.", "c2VjcmV0a2V5MTIzNDU2Nzg=", algorithm=dns.tsig.HMAC_SHA256) resolver.use_tsig(keyring=key) answer = resolver.resolve("internal.corp.", "A") # Method 2: using a keyring dict (compatible with tsigkeyring) keyring = dns.tsigkeyring.from_text({ "transfer-key.": "NjHwPsMKjdN++dOfE5iAiQ==" }) resolver2 = dns.resolver.Resolver(configure=False) resolver2.nameservers = ["10.0.0.1"] resolver2.use_tsig(keyring, keyname="transfer-key.") answer = resolver2.resolve("example.corp.", "SOA") ``` -------------------------------- ### Read Relativized RRsets with Unforced Rdclass Source: https://github.com/rthalley/dnspython/blob/main/doc/zonefile.md This example demonstrates reading relativized RRsets where the rdclass is not forced but must match the default_rdclass. It uses `origin` and `relativize=True` for name processing. ```python input = ''' name1 20 MX 10 a.example. name2 30 IN MX 20 b ''' rrsets = dns.zonefile.read_rrsets(input, origin='example', relativize=True, rdclass=None) ``` -------------------------------- ### Send DNS Query via DNS-over-HTTPS (DoH) Source: https://context7.com/rthalley/dnspython/llms.txt Sends a DNS query using the RFC 8484 DNS-over-HTTPS protocol. Requires `pip install dnspython[doh]`. Supports HTTP/1, HTTP/2, and HTTP/3. ```python import httpx import dns.message import dns.query import dns.rdatatype from dns.query import HTTPVersion q = dns.message.make_query("example.com.", dns.rdatatype.A) # Single shot with Google's DoH response = dns.query.https(q, "https://dns.google/dns-query", timeout=10.0) for rrset in response.answer: print(rrset) # Reuse an httpx session for multiple queries (more efficient) with httpx.Client() as session: q1 = dns.message.make_query("example.com.", "A") r1 = dns.query.https(q1, "https://dns.google/dns-query", session=session) q2 = dns.message.make_query("example.com.", "MX") r2 = dns.query.https(q2, "https://dns.google/dns-query", session=session) # Force HTTP/2 response = dns.query.https(q, "https://cloudflare-dns.com/dns-query", http_version=HTTPVersion.H2) # Use GET instead of POST response = dns.query.https(q, "https://dns.google/dns-query", post=False) ``` -------------------------------- ### Construct reverse DNS names for IP addresses Source: https://context7.com/rthalley/dnspython/llms.txt Provides utilities for constructing reverse DNS names (in-addr.arpa and ip6.arpa) for PTR lookups. Includes conversion to and from IP addresses, and a convenience method for PTR lookups. ```python import dns.reversename import dns.resolver # IPv4 reverse name rev4 = dns.reversename.from_address("93.184.216.34") print(rev4) # 34.216.184.93.in-addr.arpa. # IPv6 reverse name rev6 = dns.reversename.from_address("2001:db8::1") print(rev6) # 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. # Convert back to address addr = dns.reversename.to_address(rev4) print(addr) # 93.184.216.34 # PTR lookup via resolver convenience method answer = dns.resolver.resolve_address("8.8.8.8") for rdata in answer: print(rdata.target) # dns.google. ``` -------------------------------- ### dns.asyncresolver Source: https://context7.com/rthalley/dnspython/llms.txt Asynchronous DNS resolution library supporting asyncio and Trio. All resolver methods are coroutines and auto-detect the running event loop. ```APIDOC ## dns.asyncresolver — Asynchronous DNS resolution `dns.asyncresolver` is the async counterpart to `dns.resolver`, supporting asyncio and Trio. All resolver methods are coroutines. Auto-detects the running event loop via sniffio when available. ```python import asyncio import dns.asyncresolver import dns.asyncquery import dns.message async def main(): # High-level async resolution answer = await dns.asyncresolver.resolve("example.com", "A") for rdata in answer: print(f"A: {rdata.address}") # Async resolver with custom nameservers resolver = dns.asyncresolver.Resolver(configure=False) resolver.nameservers = ["8.8.8.8"] # Async reverse lookup answer = await resolver.resolve_address("8.8.8.8") for rdata in answer: print(f"PTR: {rdata.target}") # resolve_name: A + AAAA in parallel answers = await resolver.resolve_name("example.com") for addr in answers.addresses(): print(addr) # zone_for_name: find authoritative zone zone = await dns.asyncresolver.zone_for_name("www.example.com") print(f"Authoritative zone: {zone}") # Async resolve at a specific server (convenience function) answer = await dns.asyncresolver.resolve_at("8.8.8.8", "google.com", "NS") for rdata in answer: print(rdata.target) # DDR upgrade in async context await resolver.try_ddr() print(resolver.nameservers) # Low-level async queries q = dns.message.make_query("example.com.", "AAAA") r = await dns.asyncquery.udp(q, "8.8.8.8") r2 = await dns.asyncquery.tcp(q, "8.8.8.8") r3 = await dns.asyncquery.tls(q, "1.1.1.1") asyncio.run(main()) ``` ``` -------------------------------- ### dns.query.https Source: https://context7.com/rthalley/dnspython/llms.txt Sends a DNS query using the RFC 8484 DNS-over-HTTPS (DoH) protocol. This requires the `dnspython[doh]` extra to be installed, which includes `httpx` and `h2`. It supports HTTP/1, HTTP/2, and HTTP/3, and allows for reusing `httpx` sessions for efficiency. ```APIDOC ## dns.query.https — Send DNS query via DNS-over-HTTPS (DoH) Sends a DNS query using the RFC 8484 DNS-over-HTTPS protocol. Requires `pip install dnspython[doh]` (installs `httpx` and `h2`). Supports HTTP/1, HTTP/2, and HTTP/3. ### Method ```python import httpx import dns.message import dns.query import dns.rdatatype from dns.query import HTTPVersion q = dns.message.make_query("example.com.", dns.rdatatype.A) # Single shot with Google's DoH response = dns.query.https(q, "https://dns.google/dns-query", timeout=10.0) for rrset in response.answer: print(rrset) # Reuse an httpx session for multiple queries (more efficient) with httpx.Client() as session: q1 = dns.message.make_query("example.com.", "A") r1 = dns.query.https(q1, "https://dns.google/dns-query", session=session) q2 = dns.message.make_query("example.com.", "MX") r2 = dns.query.https(q2, "https://dns.google/dns-query", session=session) # Force HTTP/2 response = dns.query.https(q, "https://cloudflare-dns.com/dns-query", http_version=HTTPVersion.H2) # Use GET instead of POST response = dns.query.https(q, "https://dns.google/dns-query", post=False) ``` ``` -------------------------------- ### DNS Name Manipulation Source: https://context7.com/rthalley/dnspython/llms.txt Demonstrates creating and manipulating DNS names using dns.name.Name objects. Supports absolute/relative names and hierarchy checks. ```python import dns.name # Create names from text root = dns.name.root # dns.name.Name([b'']) empty = dns.name.empty # dns.name.Name([]) fqdn = dns.name.from_text("www.example.com.") rel = dns.name.from_text("www", origin=None) # relative name print(fqdn.labels) # (b'www', b'example', b'com', b'') print(fqdn.is_absolute()) # True print(rel.is_absolute()) # False # Hierarchy checks example = dns.name.from_text("example.com.") sub = dns.name.from_text("www.example.com.") print(sub.is_subdomain(example)) # True print(example.is_superdomain(sub)) # True ``` -------------------------------- ### dns.resolver.Resolver.use_tsig Source: https://context7.com/rthalley/dnspython/llms.txt Configures the resolver to sign every query with a TSIG key for authenticated communication with nameservers. ```APIDOC ## dns.resolver.Resolver.use_tsig — TSIG-authenticated resolver Configures the resolver to sign every query with a TSIG key, enabling authenticated communication with nameservers that require it. ```python import dns.resolver import dns.tsig import dns.tsigkeyring ``` ``` -------------------------------- ### Configurable Stub Resolver with dns.resolver.Resolver Source: https://context7.com/rthalley/dnspython/llms.txt The `dns.resolver.Resolver` class offers a configurable stub resolver. It can be initialized with custom nameservers, timeouts, and caching mechanisms. Supports various protocols including DoH and DoT, and DDR for automatic transport upgrades. ```python import socket import dns.resolver # Custom resolver with explicit nameservers r = dns.resolver.Resolver(configure=False) r.nameservers = ["8.8.8.8", "8.8.4.4"] r.lifetime = 10.0 # total resolution lifetime in seconds r.timeout = 2.0 # per-attempt timeout in seconds # Resolve with the custom resolver answer = r.resolve("example.com", "A") print(f"Answered by: {answer.nameserver}:{answer.port}") ``` ```python # Use an LRU cache for repeated queries r.cache = dns.resolver.LRUCache(max_size=500) answer1 = r.resolve("example.com", "A") # cache miss answer2 = r.resolve("example.com", "A") # cache hit print(f"Cache hits: {r.cache.hits()}") # Cache hits: 1 ``` ```python # resolve_name: get both A and AAAA records in one call answers = r.resolve_name("example.com", family=socket.AF_UNSPEC) for addr in answers.addresses(): print(addr) ``` ```python # resolve_address: reverse PTR lookup answer = r.resolve_address("93.184.216.34") for rdata in answer: print(rdata.target) # example.com. ``` ```python # Use a DoH nameserver r2 = dns.resolver.Resolver(configure=False) r2.nameservers = ["https://dns.google/dns-query"] answer = r2.resolve("example.com", "A") ``` ```python # Use DoT via Nameserver object import dns.nameserver dot_ns = dns.nameserver.DoTNameserver("1.1.1.1", port=853) r3 = dns.resolver.Resolver(configure=False) r3.nameservers = [dot_ns] answer = r3.resolve("example.com", "NS") ``` ```python # DDR: auto-upgrade to encrypted transport r4 = dns.resolver.Resolver(configure=False) r4.nameservers = ["1.1.1.1"] r4.try_ddr() # upgrades nameservers to DoH/DoT if available print(r4.nameservers) # now contains DoH/DoT server objects ``` -------------------------------- ### dns.message.make_query Source: https://context7.com/rthalley/dnspython/llms.txt Constructs a DNS query message that is ready to be sent. It supports EDNS options, TSIG signing, and custom flags. The constructed message can be serialized into wire format using the `to_wire()` method. ```APIDOC ## dns.message.make_query — Construct a DNS query message Creates a `QueryMessage` ready to be sent. Supports EDNS options, TSIG signing, and custom flags. The message can be serialized to wire format with `to_wire()`. ### Parameters - **qname** (`dns.name.Name` or str) - The name for which the query is made. - **rdtype** (`dns.rdatatype.Rdatatype` or int or str) - The type of record being queried. - **rdclass** (`dns.rdataclass.Rdataclass` or int or str, optional) - The query class. Defaults to `dns.rdataclass.IN`. - **use_edns** (int or None, optional) - EDNS version to use. Defaults to `None`. - **options** (list of `dns.edns.Option`, optional) - EDNS options to include. - **flags** (int, optional) - DNS flags to set. - **tsig_keyring** (`dns.tsig.Key` or `dns.tsigkeyring.Keyring`, optional) - TSIG key or keyring for authentication. ### Request Example ```python import dns.message import dns.rdatatype import dns.edns import dns.tsig # Simple A query q = dns.message.make_query("example.com.", "A") # Query with EDNS0 and client subnet option (ECS) ecs = dns.edns.ECSOption("203.0.113.0", 24) q = dns.message.make_query("www.google.com.", "A", use_edns=0, options=[ecs]) # Query with TSIG authentication key = dns.tsig.Key("keyname.", "bnp6+y85UcBfsieuB/Uhx3EUsjc8wAFyyCSS5rhScb0=", algorithm=dns.tsig.HMAC_SHA256) q = dns.message.make_query("example.", "SOA") q.use_tsig(keyring=key) response = dns.query.udp(q, "127.0.0.1") soa_rrset = response.find_rrset(response.answer, "example", "IN", "SOA") print(soa_rrset) # Inspect message attributes print(f"Message ID: {q.id}") print(f"Flags: {dns.flags.to_text(q.flags)}") print(f"Wire bytes: {q.to_wire().hex()}") # Parse a message from wire format wire = q.to_wire() parsed = dns.message.from_wire(wire) print(parsed.to_text()) ``` ``` -------------------------------- ### Basic DNS Resolution with dns.resolver.resolve Source: https://context7.com/rthalley/dnspython/llms.txt Use `dns.resolver.resolve` for high-level DNS queries. It handles recursive lookups using the system's default resolver and returns structured answer sets. Handles common exceptions like `NXDOMAIN`, `NoAnswer`, and `LifetimeTimeout`. ```python import dns.resolver # Basic A record lookup try: answer = dns.resolver.resolve("example.com", "A") for rdata in answer: print(f"IPv4: {rdata.address}") # IPv4: 93.184.216.34 except dns.resolver.NXDOMAIN: print("Name does not exist") except dns.resolver.NoAnswer: print("No records of that type") except dns.resolver.LifetimeTimeout as e: print(f"Timeout: {e}") ``` ```python # MX record lookup answers = dns.resolver.resolve("gmail.com", "MX") for rdata in sorted(answers, key=lambda r: r.preference): print(f"Priority {rdata.preference}: {rdata.exchange}") # Priority 5: gmail-smtp-in.l.google.com. # Priority 10: alt1.gmail-smtp-in.l.google.com. ``` ```python # TXT record lookup (e.g., SPF) answers = dns.resolver.resolve("example.com", "TXT") for rdata in answers: print(b"".join(rdata.strings).decode()) ``` ```python # With explicit lifetime timeout (seconds) answer = dns.resolver.resolve("example.com", "AAAA", lifetime=3.0) for rdata in answer: print(f"IPv6: {rdata.address}") ``` -------------------------------- ### Construct DNS Response Message Source: https://context7.com/rthalley/dnspython/llms.txt Creates a response message from a query, copying the question section and setting the QR flag. Useful for custom DNS servers or test harnesses. ```python import dns.message import dns.flags import dns.rcode # Make a response to a received query received_query = dns.message.make_query("example.com.", "A") response = dns.message.make_response(received_query) response.flags |= dns.flags.AA # set Authoritative Answer # Add an A record answer rrset = response.find_rrset( response.answer, dns.name.from_text("example.com."), dns.rdataclass.IN, dns.rdatatype.A, create=True, ) rset.add(dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, "93.184.216.34"), ttl=300) wire = response.to_wire() print(f"Response size: {len(wire)} bytes") print(response.to_text()) ``` -------------------------------- ### Clone dnspython repository Source: https://github.com/rthalley/dnspython/blob/main/doc/installation.md Clone the dnspython source code repository from GitHub to build it locally. ```default git clone https://github.com/rthalley/dnspython.git ``` -------------------------------- ### dns.message.make_response Source: https://context7.com/rthalley/dnspython/llms.txt Creates a DNS response message from an existing query message. It copies the question section and sets the QR flag, making it useful for building custom DNS servers or test harnesses. ```APIDOC ## dns.message.make_response — Construct a DNS response message Creates a response message from an existing query message, copying the question section and setting the QR flag. Useful when building custom DNS servers or test harnesses. ### Parameters - **query** (`dns.message.QueryMessage`) - The query message to respond to. - **flags** (int, optional) - Flags to set on the response. Defaults to `dns.flags.QR`. - **rcode** (`dns.rcode.Rcode` or int, optional) - The response code. Defaults to `dns.rcode.NOERROR`. ### Request Example ```python import dns.message import dns.flags import dns.rcode # Make a response to a received query received_query = dns.message.make_query("example.com.", "A") response = dns.message.make_response(received_query) response.flags |= dns.flags.AA # set Authoritative Answer # Add an A record answer rrset = response.find_rrset( response.answer, dns.name.from_text("example.com."), dns.rdataclass.IN, dns.rdatatype.A, create=True, ) rset.add(dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, "93.184.216.34"), ttl=300) wire = response.to_wire() print(f"Response size: {len(wire)} bytes") print(response.to_text()) ``` ```