Files
DECNET/tests/test_sniffer_p0f.py
anti dae3687089 test: add fingerprinting and TCP analysis tests
- test_sniffer_p0f.py: p0f passive OS fingerprinting tests
- test_sniffer_tcp_fingerprint.py: TCP fingerprinting accuracy tests
- test_sniffer_retransmit.py: retransmission detection and analysis
2026-04-15 12:51:35 -04:00

118 lines
3.9 KiB
Python

"""
Unit tests for the passive p0f-lite OS fingerprint lookup.
Covers:
- initial_ttl() TTL → bucket rounding
- hop_distance() upper-bound clamping
- guess_os() signature matching for Linux, Windows, macOS, nmap,
embedded, and the unknown fallback
"""
from __future__ import annotations
from decnet.sniffer.p0f import guess_os, hop_distance, initial_ttl
# ─── initial_ttl ────────────────────────────────────────────────────────────
class TestInitialTtl:
def test_linux_bsd(self):
assert initial_ttl(64) == 64
assert initial_ttl(59) == 64
assert initial_ttl(33) == 64
def test_windows(self):
assert initial_ttl(128) == 128
assert initial_ttl(120) == 128
assert initial_ttl(65) == 128
def test_embedded(self):
assert initial_ttl(255) == 255
assert initial_ttl(254) == 255
assert initial_ttl(200) == 255
def test_very_short(self):
# anything <= 32 rounds to 32
assert initial_ttl(32) == 32
assert initial_ttl(1) == 32
def test_out_of_range(self):
# Packets with TTL > 255 (should never happen) still bucket.
assert initial_ttl(300) == 255
# ─── hop_distance ───────────────────────────────────────────────────────────
class TestHopDistance:
def test_zero_when_local(self):
assert hop_distance(64) == 0
assert hop_distance(128) == 0
assert hop_distance(255) == 0
def test_typical(self):
assert hop_distance(60) == 4 # 4 hops from Linux
assert hop_distance(120) == 8 # 8 hops from Windows
def test_negative_or_weird_still_bucketed(self):
# TTL=0 is anomalous but we still return a non-negative distance.
# TTL 0 bucket is 32 → distance = 32 - 0 = 32.
assert hop_distance(0) == 32
# ─── guess_os ───────────────────────────────────────────────────────────────
class TestGuessOs:
def test_linux_default(self):
# Modern Linux: TTL 64, window 29200+, WScale 7, full options
result = guess_os(
ttl=64, window=29200, mss=1460, wscale=7,
options_sig="M,S,T,N,W",
)
assert result == "linux"
def test_windows_default(self):
# Windows 10: TTL 128, window 64240, WScale 8, MSS 1460
result = guess_os(
ttl=128, window=64240, mss=1460, wscale=8,
options_sig="M,N,W,N,N,T,S",
)
assert result == "windows"
def test_macos_ios(self):
# macOS default: TTL 64, window 65535, WScale 6, ends with EOL
result = guess_os(
ttl=64, window=65535, mss=1460, wscale=6,
options_sig="M,N,W,N,N,T,S,E",
)
assert result == "macos_ios"
def test_nmap_sYn(self):
# nmap -sS uses tiny/distinctive windows like 1024 or 4096
result = guess_os(
ttl=64, window=1024, mss=1460, wscale=10,
options_sig="M,W,T,S,S",
)
assert result == "nmap"
def test_nmap_alt_window(self):
result = guess_os(
ttl=64, window=31337, mss=1460, wscale=10,
options_sig="M,W,T,S,S",
)
assert result == "nmap"
def test_embedded_ttl255(self):
# Any TTL bucket 255 → embedded
result = guess_os(
ttl=250, window=4128, mss=536, wscale=None,
options_sig="M",
)
assert result == "embedded"
def test_unknown(self):
# Bizarre combo nothing matches
result = guess_os(
ttl=50, window=100, mss=0, wscale=None, options_sig="",
)
assert result == "unknown"