Files
MalinandClaude Opus 5.5 237a0f1632 feat: DNS tools API for zonemaster.es
Propagation, global resolver testing (UDP/TCP/DoH), security scan with
history tracker, infrastructure detection, DNS graph, Pi-hole/AdGuard
blocklist checks and DNSBL blacklist checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:44:45 +02:00

90 lines
3.6 KiB
Python

"""Offline tests: parsing and validation only, no network."""
import pytest
from zmtools import blocklists, dnsutil
@pytest.mark.parametrize('raw,want', [
('Example.COM', 'example.com'),
('https://www.example.com/path?q=1', 'www.example.com'),
('example.com.', 'example.com'),
('bücher.de', 'xn--bcher-kva.de'),
('example.com:8080', 'example.com'),
])
def test_normalize_ok(raw, want):
assert dnsutil.normalize_domain(raw) == want
@pytest.mark.parametrize('raw', ['', 'localhost', '1.2.3.4', 'a..b', '-bad.com', 'x' * 64 + '.com',
'exa mple.com', '<script>.com'])
def test_normalize_rejects(raw):
with pytest.raises(dnsutil.BadInput):
dnsutil.normalize_domain(raw)
@pytest.mark.parametrize('ip,ok', [
('8.8.8.8', True), ('2606:4700:4700::1111', True),
('10.20.0.11', False), ('127.0.0.1', False), ('192.168.1.1', False),
('100.95.46.79', False), ('169.254.1.1', False), ('0.0.0.0', False),
('224.0.0.1', False), ('::1', False), ('fd00::1', False), ('nonsense', False),
])
def test_public_ip(ip, ok):
assert dnsutil.is_public_ip(ip) is ok
def test_adblock_parse():
text = '\n'.join([
'! comment', '[Adblock Plus]', '||ads.example.com^', '@@||good.example.com^',
'||tracker.net^$important', '||x.com^$denyallow=y.com', '/regex/', '||*.wild.com^',
'example.org##.banner',
])
got = list(blocklists.parse('adblock', text))
assert ('ads.example.com', '||ads.example.com^', False) in got
assert ('good.example.com', '@@||good.example.com^', True) in got
assert any(d == 'tracker.net' for d, _, _ in got)
assert not any(d in ('x.com', 'wild.com') for d, _, _ in got)
assert len(got) == 3
def test_hosts_parse():
text = '127.0.0.1 localhost\n0.0.0.0 0.0.0.0\n0.0.0.0 ads.example.com # c\n# 0.0.0.0 off.com\n::1 ip6-localhost'
assert [d for d, _, _ in blocklists.parse('hosts', text)] == ['ads.example.com']
def test_parents():
assert blocklists.parents('a.b.example.com') == ['a.b.example.com', 'b.example.com', 'example.com']
def test_lookup_semantics(tmp_path, monkeypatch):
import sqlite3
db = tmp_path / 'bl.sqlite'
con = sqlite3.connect(db)
con.execute('CREATE TABLE rules (list TEXT, domain TEXT, rule TEXT, exc INTEGER)')
con.execute('CREATE TABLE lists (id TEXT PRIMARY KEY, entries INTEGER, fetched REAL, error TEXT)')
con.executemany('INSERT INTO rules VALUES (?,?,?,?)', [
('adguard_dns', 'example.com', '||example.com^', 0),
('adguard_dns', 'ok.example.com', '@@||ok.example.com^', 1),
('stevenblack', 'example.com', '0.0.0.0 example.com', 0),
])
con.commit()
con.close()
monkeypatch.setattr(blocklists, 'DB_PATH', str(db))
by = lambda d: {l['id']: l['blocked'] for l in blocklists.check_lists(d)['lists']}
assert by('example.com')['adguard_dns'] and by('example.com')['stevenblack']
sub = by('ads.example.com')
assert sub['adguard_dns'] is True # adblock: parent rule covers subdomains
assert sub['stevenblack'] is False # hosts: exact match only
assert by('ok.example.com')['adguard_dns'] is False # @@ exception wins
def test_spf_counting(monkeypatch):
from zmtools import security
zone = {'a.com': ['v=spf1 include:b.com mx -all'], 'b.com': ['v=spf1 a include:c.com ~all'],
'c.com': ['v=spf1 ip4:192.0.2.0/24 -all']}
monkeypatch.setattr(dnsutil, 'txt_values', lambda n: zone.get(n, []))
count, broken = security.spf_lookups(zone['a.com'][0])
assert count == 4 and broken == []
count, broken = security.spf_lookups('v=spf1 include:missing.com -all')
assert count == 1 and broken == ['missing.com']