nadzoring.dns_lookup.poisoning module¶
DNS poisoning detection and analysis functionality.
This module detects DNS cache poisoning, censorship, and manipulation by comparing responses from multiple resolvers across different geographic locations and providers.
- nadzoring.dns_lookup.poisoning.CDN_NETWORKS: dict[str, list[str]] = {'Akamai': ['23.32.0.0/11', '23.64.0.0/14', '23.72.0.0/13', '23.192.0.0/11', '23.224.0.0/13', '23.248.0.0/14', '2.16.0.0/13', '2.20.0.0/14', '2.22.0.0/15', '2.23.0.0/16', '69.192.0.0/16', '95.100.0.0/15', '96.6.0.0/15', '104.64.0.0/10'], 'Amazon AWS': ['13.32.0.0/15', '13.224.0.0/14', '52.84.0.0/15', '54.182.0.0/16', '54.192.0.0/16', '54.230.0.0/16', '54.239.128.0/18', '99.84.0.0/15', '143.204.0.0/16', '144.220.0.0/16', '13.248.0.0/14', '15.248.0.0/16', '18.64.0.0/14', '52.124.0.0/14', '52.222.0.0/15'], 'Azure CDN': ['13.73.0.0/16', '13.80.0.0/15', '13.88.0.0/16', '13.104.0.0/14', '13.107.128.0/22', '40.90.0.0/15', '40.126.0.0/18', '52.168.0.0/14', '52.224.0.0/14', '52.239.0.0/15'], 'CloudFront': ['13.32.0.0/15', '13.224.0.0/14', '13.249.0.0/16', '18.64.0.0/14', '18.154.0.0/15', '52.84.0.0/15', '54.182.0.0/16', '54.192.0.0/16', '54.230.0.0/16', '54.239.128.0/18', '99.84.0.0/15', '143.204.0.0/16', '144.220.0.0/16', '146.254.0.0/16'], 'Cloudflare': ['1.1.1.0/24', '1.0.0.0/24', '104.16.0.0/12', '172.64.0.0/13', '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20', '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22'], 'Facebook': ['31.13.24.0/21', '31.13.64.0/18', '45.64.40.0/22', '66.220.144.0/20', '69.63.176.0/20', '69.171.224.0/19', '74.119.76.0/22', '102.132.96.0/20', '103.4.96.0/22', '129.134.0.0/17', '157.240.0.0/17', '173.252.64.0/18', '179.60.192.0/22', '185.60.216.0/22', '204.15.20.0/22'], 'Fastly': ['23.235.32.0/20', '104.156.80.0/20', '151.101.0.0/16', '157.52.64.0/18', '172.111.64.0/18', '185.31.16.0/22', '199.27.72.0/21', '199.232.0.0/16'], 'Google': ['8.8.8.0/24', '8.8.4.0/24', '64.233.160.0/19', '66.102.0.0/20', '66.249.64.0/19', '72.14.192.0/18', '74.125.0.0/16', '108.177.8.0/21', '142.250.0.0/15', '172.217.0.0/16', '173.194.0.0/16', '207.126.144.0/20', '209.85.128.0/17', '216.58.192.0/19', '216.239.32.0/19'], 'Mail.ru': ['94.100.176.0/20', '95.163.0.0/16', '185.5.128.0/22', '185.30.176.0/22', '185.86.176.0/22', '217.69.128.0/20'], 'Microsoft': ['13.64.0.0/11', '13.96.0.0/13', '13.104.0.0/14', '20.0.0.0/8', '40.64.0.0/10', '52.96.0.0/14', '52.112.0.0/14', '52.120.0.0/14', '104.40.0.0/13', '104.208.0.0/13'], 'Netflix': ['3.160.0.0/12', '23.192.0.0/11', '34.192.0.0/10', '52.48.0.0/12', '54.144.0.0/12', '108.128.0.0/12', '184.72.0.0/14', '185.2.220.0/22', '185.48.244.0/22'], 'Twitter': ['104.244.40.0/21', '199.16.156.0/22', '199.59.148.0/22', '192.133.76.0/22', '209.237.192.0/19', '69.195.160.0/19'], 'Yandex': ['5.45.192.0/18', '37.9.64.0/18', '77.88.0.0/18', '84.252.128.0/17', '87.250.224.0/19', '93.158.128.0/18', '95.108.128.0/17', '141.8.128.0/18', '199.21.96.0/22', '213.180.192.0/19']}¶
Known CDN and cloud provider network ranges for IP ownership detection.
- class nadzoring.dns_lookup.poisoning.IPAnalysisResult[source]¶
Bases:
TypedDictResult of IP address pattern analysis.
- count¶
Total number of IP addresses analysed.
- Type:
int
- unique¶
Number of unique IP addresses.
- Type:
int
- ipv4¶
Count of IPv4 addresses.
- Type:
int
- ipv6¶
Count of IPv6 addresses.
- Type:
int
- private¶
Count of private (RFC 1918) addresses.
- Type:
int
- reserved¶
Count of reserved addresses.
- Type:
int
- owners¶
Inferred provider name for each IP.
- Type:
list[str]
- countries¶
Inferred country for each IP (simplified heuristic).
- Type:
list[str]
- count: int¶
- countries: list[str]¶
- ipv4: int¶
- ipv6: int¶
- owners: list[str]¶
- private: int¶
- reserved: int¶
- unique: int¶
- class nadzoring.dns_lookup.poisoning.InconsistencyDetail[source]¶
Bases:
TypedDictDetailed information about a DNS response inconsistency.
- server¶
IP of the DNS server that returned inconsistent results.
- Type:
str
- server_name¶
Provider name from
SERVER_NAMES.- Type:
str
- server_country¶
Country code from
SERVER_COUNTRIES.- Type:
str
- type¶
Inconsistency class —
"error_mismatch","record_mismatch","cdn_variation", or"ttl_mismatch".- Type:
Literal[‘error_mismatch’, ‘record_mismatch’, ‘cdn_variation’, ‘ttl_mismatch’]
- severity¶
Impact level —
"high","medium","low", or"info".- Type:
Literal[‘high’, ‘medium’, ‘low’, ‘info’]
- control_error¶
Error from the control server, if any.
- Type:
str | None
- test_error¶
Error from the test server, if any.
- Type:
str | None
- control_records¶
Records returned by the control server.
- Type:
list[str]
- test_records¶
Records returned by the test server.
- Type:
list[str]
- control_ttl¶
TTL from the control server.
- Type:
int | None
- test_ttl¶
TTL from the test server.
- Type:
int | None
- diff¶
Description or numeric magnitude of the difference.
- Type:
str | int | None
- common_records¶
Records present in both responses.
- Type:
list[str] | None
- control_analysis¶
IP analysis for the control records.
- test_analysis¶
IP analysis for the test records.
- owner¶
Shared owner when both sides belong to the same network.
- Type:
str | None
- control_owner¶
Inferred owner of the control records.
- Type:
str | None
- test_owner¶
Inferred owner of the test records.
- Type:
str | None
- common_records: list[str] | None¶
- control_analysis: IPAnalysisResult¶
- control_error: str | None¶
- control_owner: str | None¶
- control_records: list[str]¶
- control_ttl: int | None¶
- diff: str | int | None¶
- owner: str | None¶
- server: str¶
- server_country: str¶
- server_name: str¶
- severity: Literal['high', 'medium', 'low', 'info']¶
- test_analysis: IPAnalysisResult¶
- test_error: str | None¶
- test_owner: str | None¶
- test_records: list[str]¶
- test_ttl: int | None¶
- type: Literal['error_mismatch', 'record_mismatch', 'cdn_variation', 'ttl_mismatch']¶
- class nadzoring.dns_lookup.poisoning.MetricsResult[source]¶
Bases:
TypedDictAggregated metrics from a DNS poisoning test run.
- total_tested¶
Number of test servers queried.
- Type:
int
- poisoned¶
Whether poisoning indicators exceed the threshold.
- Type:
bool
- confidence¶
Confidence score (0-100).
- Type:
float
- mismatches¶
Count of record mismatches.
- Type:
int
- cdn_variations¶
Count of CDN-related IP variations.
- Type:
int
- cdn_detected¶
Whether CDN usage was identified.
- Type:
bool
- cdn_owner¶
Name of the detected CDN provider.
- Type:
str
- cdn_percentage¶
Percentage of IPs belonging to the CDN.
- Type:
float
- unique_ips_seen¶
Unique IPs across all test results.
- Type:
int
- ip_diversity¶
IPs not present in the control result.
- Type:
int
- control_ip_count¶
IPs returned by the control server.
- Type:
int
- consensus_top¶
Top-3 most common IPs with counts.
- Type:
list[tuple[str, int]]
- consensus_rate¶
Percentage of servers returning the most common IP.
- Type:
float
- geo_diversity¶
Unique countries among test servers.
- Type:
int
- anycast_likely¶
Whether anycast routing is probable.
- Type:
bool
- cdn_likely¶
Whether CDN usage is probable.
- Type:
bool
- poisoning_likely¶
Whether deliberate poisoning is probable.
- Type:
bool
- anycast_likely: bool¶
- cdn_detected: bool¶
- cdn_likely: bool¶
- cdn_owner: str¶
- cdn_percentage: float¶
- cdn_variations: int¶
- confidence: float¶
- consensus_rate: float¶
- consensus_top: list[tuple[str, int]]¶
- control_ip_count: int¶
- geo_diversity: int¶
- ip_diversity: int¶
- mismatches: int¶
- poisoned: bool¶
- poisoning_likely: bool¶
- total_tested: int¶
- unique_ips_seen: int¶
- nadzoring.dns_lookup.poisoning.SERVER_COUNTRIES: dict[str, str] = {'1.0.0.1': 'AU', '1.1.1.1': 'AU', '149.112.112.112': 'CH', '185.228.168.9': 'CA', '185.228.169.9': 'CA', '208.67.220.220': 'US', '208.67.222.222': 'US', '64.6.64.6': 'US', '64.6.65.6': 'US', '76.76.19.19': 'CA', '8.8.4.4': 'US', '8.8.8.8': 'US', '9.9.9.9': 'CH', '94.140.14.14': 'CY', '94.140.15.15': 'CY'}¶
Mapping of public DNS server IPs to their country codes.
- nadzoring.dns_lookup.poisoning.SERVER_NAMES: dict[str, str] = {'1.0.0.1': 'Cloudflare', '1.1.1.1': 'Cloudflare', '149.112.112.112': 'Quad9', '185.228.168.9': 'CleanBrowsing', '185.228.169.9': 'CleanBrowsing', '208.67.220.220': 'OpenDNS', '208.67.222.222': 'OpenDNS', '64.6.64.6': 'Verisign', '64.6.65.6': 'Verisign', '76.76.19.19': 'ControlD', '8.8.4.4': 'Google', '8.8.8.8': 'Google', '9.9.9.9': 'Quad9', '94.140.14.14': 'AdGuard', '94.140.15.15': 'AdGuard'}¶
Mapping of public DNS server IPs to their provider names.
- nadzoring.dns_lookup.poisoning._analyze_ip_patterns(records: list[str]) IPAnalysisResult[source]¶
Analyse IP address patterns for characteristics and ownership.
- Parameters:
records – IP address strings to analyse.
- Returns:
IPAnalysisResultdict, or an empty dict for empty input.
- nadzoring.dns_lookup.poisoning._build_result(domain: str, record_type: str, control_server: str, control_result: DNSResult, test_results: dict[str, DNSResult], additional_results: dict[str, DNSResult] | None, inconsistencies: list[InconsistencyDetail], mismatches: int, cdn_variations: int, metrics: MetricsResult, poisoning_level: str) PoisoningCheckResult[source]¶
Assemble the final
PoisoningCheckResultfrom collected data.- Parameters:
domain – Tested domain name.
record_type – DNS record type queried.
control_server – Control server IP.
control_result – DNS result from the control server.
test_results – Dict of test server results.
additional_results – Optional supplementary record results.
inconsistencies – Detected inconsistencies.
mismatches – Count of record mismatches.
cdn_variations – Count of CDN variations.
metrics – Aggregated metrics from
_calculate_metrics().poisoning_level – Poisoning severity label.
- Returns:
Complete
PoisoningCheckResult.
- nadzoring.dns_lookup.poisoning._calculate_metrics(test_results: dict[str, DNSResult], control_result: DNSResult, mismatches: int, cdn_variations: int) MetricsResult[source]¶
Compute poisoning-detection metrics from test results.
- Parameters:
test_results – Dict mapping server IPs to DNS results.
control_result – Control server DNS result.
mismatches – Count of record mismatches.
cdn_variations – Count of CDN-related variations.
- Returns:
MetricsResultwith confidence, diversity, and detection flags.
- nadzoring.dns_lookup.poisoning._compare_results(control: DNSResult, test: DNSResult, server: str) InconsistencyDetail | None[source]¶
Compare control and test DNS results and return an inconsistency if found.
Detects
error_mismatch,record_mismatch,cdn_variation, andttl_mismatch(> 1 hour) types.- Parameters:
control – DNS result from the trusted control resolver.
test – DNS result from the test resolver.
server – IP address of the test server.
- Returns:
InconsistencyDetailwhen a discrepancy is found,Nonewhen results are consistent.
- nadzoring.dns_lookup.poisoning._count_severities(inconsistencies: list[InconsistencyDetail]) dict[str, int][source]¶
Aggregate inconsistency counts by severity level.
- Parameters:
inconsistencies – List of inconsistency detail dicts.
- Returns:
Dict with
"high","medium","low", and"info"keys.
- nadzoring.dns_lookup.poisoning._determine_poisoning_level(confidence: float, *, poisoned: bool, cdn_detected: bool) str[source]¶
Map confidence and detection flags to a poisoning severity label.
- Parameters:
confidence – Confidence score (0-100).
poisoned – Whether poisoning indicators exceed the threshold.
cdn_detected – Whether CDN usage was identified.
- Returns:
One of
"NONE","LOW","MEDIUM","HIGH","CRITICAL", or"SUSPICIOUS".
- nadzoring.dns_lookup.poisoning._get_additional_records(domain: str, additional_types: list[str] | None, control_server: str) dict[str, DNSResult] | None[source]¶
Retrieve supplementary DNS record types from the control server.
- Parameters:
domain – Domain name to query.
additional_types – Record types to query, or
Noneto skip.control_server – Control server IP address.
- Returns:
Dict mapping record types to results, or
Nonewhen additional_types is empty/None.
- nadzoring.dns_lookup.poisoning._test_dns_servers(domain: str, record_type: RecordType, test_servers: list[str], control_result: DNSResult, control_server: str) tuple[dict[str, DNSResult], list[InconsistencyDetail], int, int][source]¶
Query all test servers and collect comparison results.
The control server itself is skipped if it appears in test_servers.
- Parameters:
domain – Domain to query.
record_type – DNS record type to query.
test_servers – Test server IP addresses.
control_result – Result from the control server for comparison.
control_server – Control server IP (skipped when encountered in list).
- Returns:
Four-tuple of
(test_results, inconsistencies, mismatches, cdn_variations).
- nadzoring.dns_lookup.poisoning.check_dns_poisoning(domain: str, control_server: str = '8.8.8.8', test_servers: list[str] | None = None, record_type: str = 'A', additional_types: list[str] | None = None) PoisoningCheckResult[source]¶
Check for DNS poisoning, censorship, or manipulation.
Queries the trusted control_server and compares its response against multiple test servers. CDN and anycast patterns are classified separately from true poisoning.
- Parameters:
domain – Domain to test (e.g.
"example.com").control_server – Trusted DNS server IP used as the baseline. Defaults to
"8.8.8.8"(Google DNS).test_servers – Test server IPs.
Noneusesget_public_dns_servers().record_type – Record type to query. Defaults to
"A".additional_types – Extra record types to query on the control server for additional context.
- Returns:
PoisoningCheckResultwith comprehensive analysis fields.
Examples
>>> result = check_dns_poisoning("example.com") >>> if result["poisoned"]: ... print(f"Confidence: {result['confidence']}%")
>>> result = check_dns_poisoning( ... "example.com", test_servers=["1.1.1.1", "9.9.9.9"] ... )
- nadzoring.dns_lookup.poisoning.get_ip_owner(ip: str) str[source]¶
Determine the CDN/cloud provider for an IP address.
Only IPv4 addresses are matched against
CDN_NETWORKS; IPv6 always returns"Unknown".- Parameters:
ip – IP address string to check.
- Returns:
Provider name if a match is found, otherwise
"Unknown".
Examples
>>> get_ip_owner("8.8.8.8") 'Google' >>> get_ip_owner("192.168.1.1") 'Unknown'
- nadzoring.dns_lookup.poisoning.is_likely_cdn(ips: list[str]) tuple[bool, str, float][source]¶
Determine whether a set of IP addresses likely belongs to a CDN.
More than 50 % of IPs belonging to the same known provider is treated as CDN usage.
- Parameters:
ips – IP address strings to analyse.
- Returns:
Three-tuple of
(is_cdn, owner_name, percentage). Returns(False, "Unknown", 0.0)for empty input.
Examples
>>> is_likely_cdn(["1.1.1.1", "1.0.0.1", "8.8.8.8"]) (True, 'Cloudflare', 66.7)