Writing Criteria
Every guide in this repo is written to the same standard. If you're adding or editing a guide — human or AI — hold it to these.
- Plain words, real ideas. Simple language, never dumbed-down concepts. Explain jargon on first use; collect terms in the glossary.
- No hype. No marketing adjectives, no "revolutionary," no promises about what something will do for the reader.
- Honest about limits. Say what the thing can't do. State uncertainty instead of smoothing it over. Validation notes include what remains unverified.
- No invented numbers. Benchmarks, defaults, and specs are either measured or qualified with "depends on your setup." If it wasn't tested, say so.
- Checkable. Commands are meant to be run, with "Check:" blocks showing what success looks like. Sources are linked, not asserted.
- Respect the reader's setup. Call out Windows/Mac/Linux differences. Don't assume a GPU, a budget, or prior experience.
- Safety isn't skipped. Real risks get stated plainly, not buried.
- Scoped. Each guide says what it covers and points elsewhere for the rest. No guide pretends to be the whole subject.
- Structure over prose. Tables, before/after examples, symptom → fix. Scannable beats essay.
Verification notes for this guide
Standard 3 and 4 applied to this guide,
specifically. The build machine ran Ubuntu
24.04 as root, with tcpdump 4.99.4 and
libpcap 1.10.4 (with TPACKET_V3) installed
fresh for the build (apt-get install
tcpdump; OpenSSL 3.0.13 underlies both).
Every quoted output in the chapters is a
capture from that tcpdump, watching the
shipped lab. Working transcripts are kept
with the build (tcpdump-lab/transcripts/,
twenty files).
The lab. examples/lab_server.py binds
127.0.0.1 only and stands up a specimen web
server on tcp/45080 (Server:
PacketLab/1.0, one invented page) and a UDP
echo on udp/45053 that answers every datagram
prefixed with echo:. Two specimens are
deliberate absences: nothing binds tcp/45999
or udp/45998. examples/lab_tls_server.py
serves the same page over TLS on tcp/45443
with a self-signed certificate made during
the build (CN=lab.test, SAN DNS:lab.test;
the openssl receipts are chapter 8's).
Drivers are curl, ping, netcat, and getent.
examples/specimen.pcap is the capture of
chapter 7, shipped so the reading lessons
work before the reader captures anything.
Capture hygiene, declared. Captures were
bounded by -c or by a harness timeout
standing in for Ctrl-C; driver commands ran
in a second "terminal" (a backgrounded shell)
and are noted in each transcript as such.
Two cosmetic interventions, neither touching
a byte of capture output: in
08b-read-pcap.txt the echoed pipeline's
shell-escaped quotes were un-escaped for
readability, and the chapter quotes trim
driver parentheticals in two places. One
capture was retaken for consistency: the
first TLS capture attempt returned zero
packets because the driver's request had
silently gone to the build shell's egress
proxy (the name lab.test is not in its
no-proxy list); the retaken capture drives
curl with --noproxy "*", and chapter 8
says so in place. One fixture defect was
found and fixed during the build: the UDP
echo's first reply path died on this
sandbox's refusal of unconnected UDP sends
(see the invisible-send entry below); the
shipped fixture answers each datagram from
a connected socket, which the same sandbox
permits, and the fixture in examples/ is
the fixed one.
Live-captured (every command run for real on the build box):
- The identity and doorway listings:
tcpdump --version,tcpdump -D(eight devices),ip -brief address show(loopback plus the one external interface,host0). - The full planted web conversation on
loopback, repeatedly: three-way
handshake, request, two-push response,
acknowledgements, two-FIN close — at
default verbosity,
-v,-vv,-A,-X, and-e, and end to end in the shipped specimen.pcap. Packet counts for identical fetches varied between runs (12 and 13) exactly as chapter 9 describes; the chapters quote one run whole and say so. - The filter language against one mixed
burst (ping + curl + UDP echo):
unfiltered (18 packets), then
icmp(4),icmp or udp port 45053(6), and the SYN testtcp[tcpflags] & tcp-syn != 0(2: the SYN and SYN-ACK alone). The malformed filter (tpc port 45080) and its exact error. Primitives exercised live: tcp, udp, icmp, port, or, the flag byte-test. - Payload captures: the HTTP request
line, headers, and page body under
-A; the UDP echo's datagrams in both directions; hex under-X; the link-layer line under-e(loopback's all-zero hardware addresses, as printed). - A DNS conversation on the external interface: AAAA and A queries to the machine's resolver and their answers, decoded by tcpdump itself. The answers are the sandbox resolver's synthetic ones (198.18.x), disclosed in chapter 6; the query names, order, and timing are genuine.
- Capture files:
-wwriting specimen.pcap (16 packets, 1,908 bytes, identified byfileas pcap 2.4),-rreading it back whole, read-time filtering (icmp→ 4 lines),-ttttdates, and the awk/sort/uniq talkers pipeline. The-wruns use-Z root: without it this sandbox refuses tcpdump's savefile ownership change and the run fails — that failure is itself captured (error verbatim, exit 1, 24-byte header-only file) and taught in chapters 7 and 9. - Rotation:
-G 2 -W 3writing three time-named files and stopping at the cap ("Maximum file limit reached: 3", 13 of 16 packets filed). - Snaplen:
-s 100truncating the payload view while headers report true lengths — the page text present twice in the full capture is absent (grep count 0) in the truncated one. - Refusals, both shapes: a TCP SYN to
the closed specimen answered by
[R.](curl's exit 7 recorded), and a UDP datagram to the closed specimen answered by an ICMP port-unreachable. - The errors chapter, verbatim:
capture attempted as user
nobody(permission refused),-i nosuch0(no such device), the filter syntax error above. - The invisible send: a probe whose
unconnected UDP
sendtothis sandbox refuses with EPERM was run under a matching capture, which reported 0 packets captured / 0 received / 0 dropped — the absence is the evidence, quoted as captured. - TLS: the self-signed certificate's
creation and inspection; the full
HTTPS fetch captured under
-A— the SNI namelab.testand ALPN list legible in the ClientHello dump, andgrep -c "GET /"on the capture returning 0. TLS 1.3 was negotiated, as the driver's own verbose output confirmed.
Documented-only (not run), and why:
- Wireshark and tshark. Neither is
installed on the build machine
(
tsharkverified absent). They are named and placed — Wireshark as the GUI reader of the pcap files chapter 7 makes, tshark in one honest paragraph in chapter 1 — and nothing about their behaviour is demonstrated. - TLS decryption via a key log (SSLKEYLOGFILE plus Wireshark): named in chapter 8 as a cooperative- endpoint arrangement that exists; not installed, not run, not taught.
- Third-party / promiscuous capture of other hosts' traffic. The build machine's only external link is point-to-point, so every capture in this guide contains this machine's own traffic and nothing else's to show. Chapter 8 describes what promiscuous mode can and cannot reach on modern switched networks as description, and no capture pretends otherwise. Wi-Fi monitor mode is likewise described only: no usable wireless capture device exists here.
- Filter primitives taught from the
table but not separately captured:
host,net,portrange,src/dst,not. Their grammar is thepcap-filtermanual page's; the exercised primitives are listed in the live ledger above. - Fragmentation, ECH, and saturated- link drop behaviour: named where a reader will meet them (fragment fields in chapter 3, ECH closing SNI in chapter 8, drops argued from the footer counters) — described, not staged. Every footer in the lab honestly reports zero drops; the guide does not manufacture a busier network than it has.
Specimen discipline, for the record: every capture targets the build machine's own interfaces; every fixture binds 127.0.0.1; the only external traffic captured is the machine's own DNS, driven by the author. No output was completed, corrected, or invented: where a capture surprised the draft — the footer's loopback doubling, the 24-byte savefile, the proxy that swallowed the first TLS run — the chapters were written to the capture.