nadzoring.dns_lookup.trace module

DNS trace routing functionality for tracking resolution paths.

nadzoring.dns_lookup.trace.create_hop(nameserver: str) dict[str, Any][source]

Create a new hop dictionary for DNS trace tracking.

Initializes a hop structure to store information about a single step in the DNS resolution path.

Parameters:

nameserver – IP address of the nameserver for this hop.

Returns:

Hop dictionary with the following structure:
  • nameserver: IP address of the queried nameserver

  • records: List of record strings obtained from this hop

  • response_time: Response time in milliseconds (None if not yet measured)

  • next: Next nameserver IP or status string (None if unknown)

  • error: Error message if this hop failed (None otherwise)

Return type:

Dict[str, Any]

Example

>>> hop = create_hop("198.41.0.4")
>>> hop["records"].append("A record response")
>>> hop["response_time"] = 45.67
nadzoring.dns_lookup.trace.get_delegation_info(current_domain: Name, current_ns: str, hop: dict[str, Any]) str | None[source]

Get delegation information from a nameserver for the next hop.

Queries a nameserver for NS records of the current domain to find delegation information, then resolves the nameserver IP for the next hop.

Parameters:
  • current_domain – Domain name as dns.name.Name object to query for NS records.

  • current_ns – IP address of the current nameserver to query.

  • hop – Hop dictionary to update with delegation records and errors. Modified in-place to add delegation information.

Returns:

IP address of the next nameserver to query, or None if

delegation information cannot be obtained or resolved.

Return type:

Optional[str]

Notes

  • Uses UDP query for NS records with 5 second timeout

  • Attempts to resolve nameserver hostnames to IP addresses

  • Falls back to socket.gethostbyname() if dns.resolver fails

  • Logs exceptions but continues execution

nadzoring.dns_lookup.trace.query_nameserver(domain: str, nameserver: str) tuple[Answer | None, float | None, str | None][source]

Query a specific nameserver for A records of a domain.

Performs a DNS A record lookup against a specified nameserver, measuring response time and handling various error conditions gracefully.

Parameters:
  • domain – Domain name to query (e.g., “example.com”).

  • nameserver – IP address of the nameserver to query.

Returns:

A tuple containing:
  • answers: DNS Answer object if successful, None otherwise.

  • response_time: Response time in milliseconds rounded to 2 decimals,

    None if timeout occurred.

  • error: Error message string if resolution failed, None if successful.

Return type:

Tuple[Optional[Answer], Optional[float], Optional[str]]

Examples

>>> answers, rt, error = query_nameserver("example.com", "8.8.8.8")
>>> if answers:
...     print(f"Resolved in {rt}ms: {answers[0]}")
>>> elif error:
...     print(f"Failed: {error}")

Notes

  • Timeout is set to 3 seconds per query with 5 seconds total lifetime

  • Response time is None only for timeout errors

  • For other errors, response time is still recorded

nadzoring.dns_lookup.trace.trace_dns(domain: str, nameserver: str | None = None) dict[str, Any][source]

Trace the complete DNS resolution path for a domain.

Performs a DNS trace following the delegation chain from root servers to authoritative nameservers, similar to dig +trace functionality.

Parameters:
  • domain – Domain name to trace (e.g., “example.com”).

  • nameserver – Optional starting nameserver IP. If None, starts from root server (198.41.0.4 - a.root-servers.net).

Returns:

Trace result containing:
  • domain: The domain that was traced

  • hops: List of hop dictionaries, each representing a nameserver

    queried along the path

  • final_answer: The hop dictionary containing the final answer

    (None if resolution failed)

Return type:

Dict[str, Any]

Example

>>> result = trace_dns("example.com")
>>> for i, hop in enumerate(result["hops"]):
...     print(f"Hop {i + 1}: {hop['nameserver']} ({hop['response_time']}ms)")
>>> if result["final_answer"]:
...     print(f"Final answer: {result['final_answer']['records']}")

Notes

  • Maximum hops limited to 30 to prevent infinite loops

  • Detects and reports loops in delegation chain

  • Tracks visited nameservers to avoid repetition

  • Gracefully handles delegation failures and errors