netsleuth/tests/test_dns_leak.py
2026-08-09 04:10:44 +03:00

125 lines
4.4 KiB
Python

from __future__ import annotations
from netcheck.probes.dns_leak import (
build_adapter_result,
build_dns_leak,
detect_ecs_leak,
parse_akahelp,
parse_myaddr,
)
def test_akahelp_txt_records_become_a_flat_mapping():
records = ['"ns" "203.0.113.9"', '"ecs" "198.51.100.0/24"', '"cip" "203.0.113.44"']
assert parse_akahelp(records) == {
"ns": "203.0.113.9",
"ecs": "198.51.100.0/24",
"cip": "203.0.113.44",
}
def test_akahelp_records_without_quotes_are_handled_too():
assert parse_akahelp(["ns 203.0.113.9"]) == {"ns": "203.0.113.9"}
def test_akahelp_ignores_records_it_cannot_split():
assert parse_akahelp(["garbage", '"ns" "1.2.3.4"']) == {"ns": "1.2.3.4"}
def test_myaddr_returns_the_echoed_resolver_address():
assert parse_myaddr(['"203.0.113.9"']) == "203.0.113.9"
assert parse_myaddr(["203.0.113.9"]) == "203.0.113.9"
def test_myaddr_of_no_answer_is_none():
assert parse_myaddr([]) is None
assert parse_myaddr(['"not an ip"']) is None
def test_ecs_leak_is_detected_when_a_client_subnet_is_echoed():
assert detect_ecs_leak({"ecs": "198.51.100.0/24"}) is True
def test_no_ecs_leak_when_the_field_is_absent_or_a_wildcard():
assert detect_ecs_leak({}) is False
assert detect_ecs_leak({"ecs": ""}) is False
assert detect_ecs_leak({"ecs": "0.0.0.0/0"}) is False
def test_adapter_result_flags_a_resolver_in_a_different_asn():
result = build_adapter_result(
adapter="Wi-Fi",
resolvers=["192.168.1.1"],
echoed_ip="203.0.113.9",
echoed_asn="AS64501",
egress_asn="AS64500",
)
assert result.matches_egress_asn is False
assert result.adapter == "Wi-Fi"
assert result.configured_resolvers == ["192.168.1.1"]
def test_adapter_result_is_clean_when_the_asns_agree():
result = build_adapter_result("wg0", ["10.7.0.1"], "203.0.113.44", "AS64500", "AS64500")
assert result.matches_egress_asn is True
def test_adapter_result_is_unknown_when_either_asn_is_missing():
assert build_adapter_result("eth0", ["1.1.1.1"], "1.1.1.1", None, "AS64500").matches_egress_asn is None
assert build_adapter_result("eth0", ["1.1.1.1"], "1.1.1.1", "AS13335", None).matches_egress_asn is None
def test_adapter_result_asn_comparison_is_case_insensitive():
assert build_adapter_result("eth0", ["1.1.1.1"], "1.1.1.1", "as64500", "AS64500").matches_egress_asn is True
def test_dns_leak_note_names_the_leaking_adapter():
leaking = build_adapter_result("Wi-Fi", ["192.168.1.1"], "203.0.113.9", "AS64501", "AS64500")
clean = build_adapter_result("wg0", ["10.7.0.1"], "203.0.113.44", "AS64500", "AS64500")
leak = build_dns_leak([clean, leaking], ecs_leaked=False)
assert leak.ecs_leaked is False
assert "Wi-Fi" in leak.note
assert "browser" in leak.note.lower()
def test_dns_leak_note_is_clean_when_every_adapter_agrees():
clean = build_adapter_result("wg0", ["10.7.0.1"], "203.0.113.44", "AS64500", "AS64500")
leak = build_dns_leak([clean], ecs_leaked=False)
assert "no adapter" in leak.note.lower()
def test_dns_leak_note_mentions_ecs_when_the_subnet_leaked():
clean = build_adapter_result("wg0", ["10.7.0.1"], "203.0.113.44", "AS64500", "AS64500")
leak = build_dns_leak([clean], ecs_leaked=True)
assert leak.ecs_leaked is True
assert "client subnet" in leak.note.lower()
_CYRILLIC = set("абвгдеёжзийклмнопрстуфхцчшщъыьэюя")
def has_cyrillic(text: str) -> bool:
return any(ch in _CYRILLIC for ch in text.lower())
def test_dns_leak_note_ru_names_the_leaking_adapter():
leaking = build_adapter_result("Wi-Fi", ["192.168.1.1"], "203.0.113.9", "AS64501", "AS64500")
clean = build_adapter_result("wg0", ["10.7.0.1"], "203.0.113.44", "AS64500", "AS64500")
leak = build_dns_leak([clean, leaking], ecs_leaked=False)
assert leak.note_ru
assert has_cyrillic(leak.note_ru)
assert "Wi-Fi" in leak.note_ru
def test_dns_leak_note_ru_is_clean_when_every_adapter_agrees():
clean = build_adapter_result("wg0", ["10.7.0.1"], "203.0.113.44", "AS64500", "AS64500")
leak = build_dns_leak([clean], ecs_leaked=False)
assert leak.note_ru
assert has_cyrillic(leak.note_ru)
def test_dns_leak_note_ru_mentions_ecs_when_the_subnet_leaked():
clean = build_adapter_result("wg0", ["10.7.0.1"], "203.0.113.44", "AS64500", "AS64500")
leak = build_dns_leak([clean], ecs_leaked=True)
assert leak.note_ru
assert has_cyrillic(leak.note_ru)