Frontend Labs
⋯

0.8 The Go labs: build the network tools yourself

Reading about a protocol teaches you its shape. Writing a program that speaks it shows you the details: the bytes, the timeouts, the error codes, the states. From Part 3 onwards, many chapters end with a "Build it in Go" section: a small, complete program (usually 50–200 lines) that turns the chapter into something you can run, break, and extend.

Why Go

Go's standard library contains a complete network stack API (net, net/netip, crypto/tls, net/http) with no extra dependencies. Its goroutines make "one connection per goroutine" natural. And it's the language much of today's network infrastructure is written in: Kubernetes, Docker, Caddy, Traefik, CoreDNS, Consul, Prometheus, and most Envoy control planes. You don't need to know Go well to start. Each lab explains what's specific to Go, and the Go guide covers the language itself.

Setup (5 minutes)

# Install Go 1.22 or newer (the labs were tested with Go 1.26):
#   macOS:  brew install go        Linux: https://go.dev/doc/install
go version

# One module holds every lab; each lab is a folder with a main.go
mkdir -p ~/netlabs && cd ~/netlabs
go mod init netlabs
mkdir dnsquery            # then save the lab's code as dnsquery/main.go
go run ./dnsquery example.com

Labs marked (Linux) use Linux-only kernel features. On macOS, run them in a container. This works even on Docker Desktop:

docker run --rm -it --cap-add NET_ADMIN -v "$PWD":/labs -w /labs golang:1.26 bash
apt-get update && apt-get install -y iproute2 tcpdump   # ss, tc, tcpdump inside the container

What Go's net package does underneath

Every lab uses a few calls. Knowing what each one asks the kernel to do connects the code to the chapters:

Go call System calls underneath (Linux) What happens on the wire / in the kernel
net.Dial("tcp", addr) socket(), non-blocking connect(), then wait in epoll SYN sent; returns after SYN-ACK + ACK (Chapter 21)
net.Listen("tcp", addr) socket(), setsockopt(SO_REUSEADDR), bind(), listen(somaxconn) Socket enters LISTEN; kernel now completes handshakes by itself
ln.Accept() accept4() Takes one finished connection off the accept queue (Chapter 52)
conn.Read(buf) read(); if no data, the goroutine parks in the netpoller (epoll/kqueue) Drains the socket's receive buffer, which opens the window (Chapter 24)
conn.Write(buf) write(); parks if the send buffer is full Copies into the send buffer; TCP sends when cwnd/rwnd allow
conn.SetDeadline(t) none (a runtime timer) Read/Write fail with a timeout error after t
conn.Close() close() FIN, or RST if unread data was still waiting
net.Dial("udp", addr) socket(), connect() Nothing is sent. Only a route and a source address are chosen

Three Go defaults that matter later: TCP connections have TCP_NODELAY on (Nagle off, Chapter 26), TCP keepalives on (every 15 s), and listeners set SO_REUSEADDR, so a restarted server can rebind its port even while old connections sit in TIME_WAIT (Chapter 23).

To see the system calls any lab makes, build it and trace it:

go build -o /tmp/lab ./dialcheck
strace -f -e trace=network /tmp/lab example.com:443     # Linux

Index of the Go labs in this guide

Lab Chapter What you build
subnet 10, 11, 61 Subnet calculator, subnet splitter, overlap checker, IPAM allocator
whoami 12 Your private vs public address: NAT made visible
dnsquery 18 A DNS client from raw bytes, with message compression
bindlab 19 Bind conflicts, loopback vs wildcard, SO_REUSEPORT
udpping 20 UDP echo + loss/reorder/jitter meter
dialcheck 21 Classifies connected / refused / timed out / DNS failure
stream 22 Proof that TCP has no message boundaries, and length-prefix framing
closewait 23 A CLOSE_WAIT leak, half-close with CloseWrite
zerowindow 24 A slow reader that drives the window to zero
nagle 26 The 40 ms Nagle + delayed-ACK stall, on demand
rawhttp 28 HTTP/1.1 by hand over TCP/TLS, decoding chunked framing
tlsinspect 29, 56 A scriptable openssl s_client with failure diagnosis
pcapread 31–32 A pcap decoder: Ethernet/SLL → IP → TCP/UDP
tcpinfo (Linux) 33 ss -ti from inside your program: rtt, cwnd, retransmits
netcheck 34 The troubleshooting ladder as one command
prober 46–47 A blackbox exporter with a Prometheus latency histogram
acceptq 52 Overflowing a listen queue on purpose
policytest 53 Firewall policy as executable tests
dnsdiff 55 Compare answers across resolvers
certreload 56 Zero-downtime certificate rotation
lbdrain 57 Health-checked load balancer + gracefully draining backends
proxyproto 57 PROXY protocol parser: the real client IP behind an L4 load balancer
bdp 59 The bandwidth-delay product, measured

Larger projects that build on these, such as an L4 load balancer, a TLS reverse proxy, a WAF, and a DDoS-resistant edge proxy, are in the Go 120-day plan, Weeks 5–17. The individual chapters link to them.

Generated from real-life-guide-v1.md · 8 Oct 2026 16:36