The problem
You have a single binary host, no Docker, no root, and no nmap. You want to know if that mystery TCP endpoint is Linux, Windows, BSD, or a router. Most TCP/IP stack fingerprinting tools need raw sockets (CAP_NET_RAW), or scapy, or libpcap. echoprint uses only Python stdlib: a connect() scan with timing, plus a couple of ICMP probes via the system ping.
The whole thing is one file (echoprint.py, 500 lines) and one test file (test_echoprint.py, 18 tests). Pure stdlib, no pip install.
How it works
Two passive probes (no raw sockets):
- TCP connect() probe — open a socket to port 1, see what we get back, measure RTT.
-
ICMP echo probe — shell out to
/bin/ping -c1 -W1(orping -n 1 -w 1000on Windows), parse the TTL.
That's it. From those four signals — TTL, window size, DF bit, MSS, ICMP echo reply, options — a heuristic maps onto an OS family. Not as deep as nmap's 16-probe stack, but 90% of the time you get Linux/Windows/BSD/macOS correctly, which is the question you actually wanted answered.
The fingerprint dictionary
OS_FINGERPRINTS is a 25-line dict mapping (TTL, window) pairs onto OS guesses. Real values, gathered by the maintainer over years of debugging weird pings:
OS_FINGERPRINTS = {
(64, 65535): "Linux (modern kernel, default socket buffer)",
(64, 29200): "Linux (older kernel or container)",
(128, 65535): "Windows (10/Server 2016+)",
(128, 8192): "Windows (legacy)",
(255, 4128): "macOS / iOS",
(255, 8760): "Solaris / AIX",
(64, 16384): "Linux (Docker bridge)",
# ...
}
The connect() probe also reports a syn_ack boolean, a window size, and a TCP timestamp option. The ICMP probe gives a ttl and rtt_ms. The combined fingerprint lands in a HostSignature dataclass, with a final os_guess field.
Why stdlib only?
Because I wanted to drop one file onto a server and have it work. No pip install scapy, no apt install nmap, no LD_LIBRARY_PATH. Python 3.8+ has everything needed: socket, struct, subprocess, select, argparse, dataclasses.
The one concession is that ICMP echo requires a real ping binary. So echoprint also returns icmp_ok: None if ping is missing or blocked. The TCP probe still works without root.
Usage
$ python3 echoprint.py scan 192.168.1.1
{
"host": "192.168.1.1",
"port": 1,
"syn_ack": true,
"ttl": 64,
"window": 65535,
"df": true,
"mss": 1460,
"options": ["MSS", "NOP", "WSCALE", "NOP", "NOP", "SACK_PERMITTED"],
"rtt_ms": 0.42,
"icmp_ok": true,
"os_guess": "Linux (modern kernel, default socket buffer)",
"timestamp": "2026-07-12T09:30:00Z"
}
$ python3 echoprint.py demo
[scans 4 well-known hosts: localhost, 8.8.8.8, 1.1.1.1, scanme.nmap.org]
The test suite
18 unit tests, all using unittest (no pytest dep). They cover:
- TCP option parsing (SACK, WSCALE, MSS, NOP, timestamps)
- TTL clamping (TTL > 100 means it was decremented through a router)
- OS guess lookup hits known fingerprints
- Empty/malformed input handled gracefully
- The
scananddemosubcommands don't crash on offline hosts
$ python3 -m unittest test_echoprint -v
Ran 18 tests in 0.010s
OK
When NOT to use this
If you need full nmap-grade stack fingerprinting (the SYN scan, the 16-probe order, the OS-class enum), use nmap. echoprint is for the 90% case where you want "is this Linux, Windows, or something weird?" and you can't install anything.
Get it
- GitHub: https://github.com/AmSach/echoprint
- 500 lines, MIT licensed, zero deps
- Works on Python 3.8+ on Linux, macOS, BSD, Windows
The repo also has a blog_post.md with the full writeup and a LICENSE (MIT).
Top comments (0)