Advertisement
Open Source Projects by Phil Schwartz

Building a Python DNS cache comparison tool for poisoning risks

A DNS cache comparison tool can help administrators spot suspicious answers before they become an operational incident. Rather than trusting one recursive resolver, the utility queries several independent sources, compares their responses, and highlights differences in address records, aliases, time-to-live values and DNSSEC status.

The project suits a practical Python portfolio because it combines networking, parsing, asynchronous programming and security analysis. It can run as a command-line utility on Linux, a scheduled monitoring job, or a small service that records resolver behaviour over time.

DNS cache poisoning occurs when false DNS data is accepted and stored by a recursive resolver. A user may then be sent to an imitation website, an unwanted mail server or an infrastructure endpoint controlled by an attacker. One inconsistent response does not prove an attack, though. DNS changes, geo-routing and stale caches can create legitimate variation.

For Australian operators, the results need local context. A resolver in Sydney may return a different CDN address from one in Perth, while an NBN connection in a regional town may use an ISP resolver with different caching behaviour. The tool should distinguish ordinary internet conditions from signals that deserve investigation.

Define the comparison model

The first design decision is what constitutes a reference answer. A public resolver such as Google Public DNS, Cloudflare or Quad9 can provide comparison data, but those services may have their own policies and cached records. A stronger approach queries the target resolver alongside one or more authoritative name servers, following delegation from the domain’s parent zone when practical.

The program should compare complete DNS responses rather than only the first IPv4 address. Useful fields include A and AAAA records, CNAME chains, MX records, NS records, response codes, DNSSEC-related flags and TTL values. Record order should be normalised because recursive servers may rotate addresses without changing the underlying answer.

A comparison result should have clear categories: matching, legitimately different, incomplete, or suspicious. For example, an NXDOMAIN response from one resolver and a valid answer from another may reflect negative caching or a recent registration. The tool should report the discrepancy and supporting evidence, rather than declaring poisoning automatically.

Build reliable Python queries

The dnspython package provides a practical foundation for DNS packet creation and response parsing. Its resolver APIs are convenient for initial prototypes, while lower-level message handling gives more control over flags, transport and DNSSEC data. Python’s asyncio can issue queries concurrently, reducing the effect of network latency when several resolvers are tested.

Each query needs a deadline, retry policy and transport record. UDP is the normal first choice, with TCP fallback when the truncated flag is set. Optional DNS-over-TLS and DNS-over-HTTPS checks can show whether an intermediary is altering conventional DNS traffic, although encrypted transport does not make an untrusted resolver authoritative.

Use time.monotonic() for elapsed-time measurements and retain the raw response during development. A stable measurement record might include the resolver address, query name, record type, timestamp in UTC, transport, response code, answer set, authority section, TTL and DNSSEC flags. Avoid logging sensitive client details unless they are required for the investigation.

Detect patterns that deserve attention

A poisoning risk indicator is stronger when several observations agree. An unexpected address from one resolver, a long TTL, a missing DNSSEC validation signal and a different CNAME chain form a more concerning pattern than a minor TTL mismatch. The tool can assign a severity score, but the scoring rules should remain visible and easy to audit.

DNSSEC deserves special treatment. A validating resolver should generally reject forged signed data when the zone is correctly configured, returning a validation failure rather than silently serving an altered answer. The utility should inspect the AD flag where appropriate, request DNSSEC records when needed, and clearly state when a domain is unsigned, broken or simply not tested deeply enough.

Timing and geography can create false positives. Australian websites commonly use global content delivery networks, so a resolver in Melbourne may receive a different address from one in Brisbane. A domain hosted on AWS Sydney infrastructure may also provide a regional answer that looks unusual from an overseas reference point. Repeated polling from the same network helps separate normal rotation from sudden divergence.

Record evidence for Australian networks

A useful command-line interface could accept a domain, record type, resolver list and sampling count. Operators might run it against an ISP-provided resolver, a home router, a corporate forwarder and public services. This is relevant for households and small businesses using Telstra, Optus or TPG connections, where the nominated resolver can vary between plans and modem configurations.

Regional connectivity matters as well. A monitoring job hosted in Sydney cannot fully represent users on a regional NBN service, a Perth office or a remote mining operation using satellite or private links. Store the vantage point with every result, and use Australian Eastern, Central and Western time zones correctly when presenting reports.

Evidence worth storing

Signals worth reviewing

Keep raw packets or redacted response data for a limited retention period. Hashing the query name is unsuitable if investigators later need to reproduce a finding, so access controls and sensible retention are better safeguards. For a public open-source project, document exactly what is collected and how users can disable persistence.

Test, package and operate the utility

Testing should cover normal records, aliases, IPv6 answers, wildcard zones, DNSSEC-signed domains, expired signatures and deliberately inconsistent mock resolvers. A local test harness can return controlled responses, allowing the comparison logic to be checked without relying on changing public DNS. Property-based tests are useful for record ordering, duplicate records and unusual names.

Network tests should include packet loss, truncated UDP replies, SERVFAIL responses and slow resolvers. The program must never treat a timeout as proof of poisoning. It should label the observation as unavailable and preserve enough diagnostic detail to explain the decision.

A concise output format makes the tool useful in scripts. JSON can feed dashboards or incident systems, while a human-readable report can group mismatches by domain and severity. Exit codes should distinguish a clean comparison, an operational failure and a potentially unsafe discrepancy.

Package the project with a clear licence, documentation and reproducible installation instructions. A small Python command-line application can be distributed through a source repository or PyPI, with examples for Linux cron and systemd timers. For Australian teams, include guidance on rate limits, privacy, UTC storage and contacting an ISP before escalating an anomaly as a suspected cache-poisoning event.