Lion Cipher Lab
Build a minimal userspace TCP/IP stack over a Linux TUN device (stdlib Python, real 3-way handshake)
- Foundations
- Advanced
- ~120 min
- Free · no account required
Why it matters
Almost everyone in security can recite the TCP three-way handshake and nobody has ever emitted the bytes themselves. That gap is why packet captures feel like hieroglyphics, why 'the checksum is wrong' or 'the client sent a RST' turns into hours of flailing, and why so many people can't reason about what a firewall, a NAT, or an IDS is actually looking at. This lab closes the gap the only way that sticks: you BUILD a minimal TCP/IP stack in userspace, over a Linux TUN device, in nothing but stdlib Python, and you make a real, unmodified curl/nc complete a handshake against code you wrote.…
What you'll learn
- opening a Linux TUN device from stdlib Python via ioctl(TUNSETIFF) and understanding why TUN is layer-3 (no Ethernet header) while TAP is layer-2 (full Ethernet frame)
- assigning a /24 to the interface and routing a subnet at it so YOUR stack — not the kernel's — is what answers on that address
- reading a full IP packet off the TUN file descriptor and hand-parsing an IPv4 header using IHL*4 for the real header length (never hardcoding 20), plus version, protocol, and addresses
- hand-parsing a TCP segment from raw bytes: source/dest ports, sequence, acknowledgement, data offset, the individual flag bits (SYN/ACK/FIN/PSH/RST), and window
- computing the IPv4 header checksum AND the TCP checksum with its pseudo-header, using RFC 1071 one's-complement folding, the checksum field zeroed first, and correct big-endian byte order
- driving a real three-way handshake: receive SYN, reply SYN/ACK with a chosen ISN, receive the final ACK, and reach ESTABLISHED against an unmodified client
- TCP sequence/ack arithmetic in your own code: ack = their seq + payload length, and the fact that SYN and FIN each consume exactly one sequence number
- echoing a byte of application data back and closing the connection cleanly with FIN/ACK
- cross-checking every packet on the wire with tcpdump -i tun0 and driving traffic with curl/nc from the same host
- naming the failure modes (missing IFF_NO_PI 4-byte prefix, parsing a TAP/Ethernet header on a TUN, pseudo-header/zeroing/byte-order checksum bugs, the kernel-stack RST race) and the judgment of when a userspace stack is actually the right tool (gVisor netstack, smoltcp, mTCP/DPDK, QUIC)
Steps in this lab
- The mental model: a TUN device is a layer-3 pipe, and you are the stack behind it
- Create the TUN interface, give the subnet an address, and route it at your process
- Open the TUN from Python and read one raw packet (prove there's no Ethernet header)
- Hand-parse the IPv4 header — use IHL*4, never a hardcoded 20
- Hand-parse the TCP segment — ports, seq, ack, flags, window
- The checksums: IPv4 header AND TCP-with-a-pseudo-header (RFC 1071)
- The money shot: drive a real 3-way handshake, echo a byte, and close
- Cross-check on the wire with tcpdump, and walk the named failure modes
- The judgment: build-to-understand only — where userspace TCP is actually real