PathVector Blog
Hands-on networking and protocol engineering notes from PathVector Studio.
-
2026-08-05
Which router wins the segment? Read the election, not the docs
OSPF's DR/BDR election on a broadcast segment is a filter, a max(), and a tie-break — read it as three lines of Python instead of a bullet list.
-
2026-08-04
A Hello does not make a neighbor Full — the code says so in two stages
OSPF's neighbor state machine reads as two separate gates in code: Hello-phase booleans decide Init/2-Way/ExStart, and database-exchange inputs decide Loading/Full.
-
2026-08-03
An OSPF Hello has to match before it can mean anything
Reading OSPF's Hello check as code: the five fields that must match before a neighbor relationship can even begin, and why seeing your own router ID changes everything.
-
2026-08-02
A BGP speaker is just state plus three event handlers
Fourteen sessions of BGP logic collapse into one small Python object: six pieces of state, three methods, and one three-line rhythm repeated in each of them.
-
2026-08-01
One prefix stops being one route: reading BGP's decision set as code
Best-path selection alone breaks down once validation and policy exist. Reading a toy BGP decision process shows why one prefix has to become a set of peer-specific candidates first.
-
2026-07-31
Announce, withdraw, and peer down are three different code paths
Reading a BGP event dispatcher as code: why announce gates the peer, withdraw skips the gate, and peer-down is the only branch that can touch many prefixes at once.
-
2026-07-30
When Loc-RIB changes, every peer needs a different answer
Reading BGP export refresh as code: how one Loc-RIB change turns into an advertise for one peer, a withdraw for another, and silence for a third.
-
2026-07-29
Established is not a status label — it's a write permission
In BGP, whether a route reaches Adj-RIB-In comes down to the placement of a single if. Read the session-state gate as code.
-
2026-07-28
One route, one function chain: reading a BGP pipeline as code
Trace a single received BGP route end to end through validation, import policy, best-path, and export — and watch nine sessions of isolated snippets turn into one small control plane.
-
2026-07-28
When a BGP peer disappears, one session loss becomes many route decisions
Reading BGP peer loss as code: why a single session going down triggers a set of withdrawals plus a per-prefix best-path recomputation, and why some prefixes survive while others vanish.
-
2026-07-27
Export policy decides what leaves: reading BGP outbound state as code
The route you install locally and the route you advertise to a peer are different objects. A 25-line Python function shows exactly where they diverge.
-
2026-07-26
Import policy rewrites the route before best-path ever sees it
Reading BGP import policy as code: the candidate that enters best-path selection is not always the one the peer sent.
-
2026-07-25
Where a route lives: the three RIBs, as code
A BGP router keeps the same route in three different stores. Reading ribs.py shows why received, selected, and advertised state are deliberately kept apart.
-
2026-07-24
Validation State Doesn't Act By Itself
RPKI tells you a route is invalid — it does not tell the router to drop it. Read the BGP policy layer as code and see why validation and policy are separate.
-
2026-07-23
Origin validation is a separate decision from best path
BGP picking a best path doesn't mean the origin AS is authorized — read RPKI origin validation as code and see why valid, invalid, and not_found are three distinct answers.
-
2026-07-22
BGP best path selection is just a chain of if statements
Reading BGP best path selection as ordered branches: the first differing field decides the winner, and everything after it never runs.
-
2026-07-21
How a BGP UPDATE Changes State: Reading Withdrawal and Announcement as Code
A BGP UPDATE can remove routes and add routes in one message — reading the Python shows why withdrawal is a different mutation from a dead session.
-
2026-07-20
What a BGP Neighbor Needs — Reading Session Setup as Code
A BGP session isn't a config line — it's a state machine that stops at a different place depending on which input is missing. We read that machine in Python.
-
2026-07-12
A Network Protocol Learning Roadmap: 42 Hands-On Labs and 151 Code-Reading Sessions, Mapped
Two free courses — hands-on labs and code-reading sessions — organized into genre maps and goal-based routes, so you know exactly where to start and what to read next.
-
2026-07-10
L4 Load Balancing with IPVS: One VIP, Three Backends, and a Perfect 10/10/10 Split
Put a Linux IPVS director in front of three backends, hit one virtual IP thirty times, and watch round-robin NAT split the connections exactly 10/10/10 — while the client never sees a backend address.
-
2026-07-10
Multicast and IGMP: How One UDP Stream Reaches Many Receivers Without a Single Extra Copy
Join two receivers to group 239.1.1.1 with IGMP, send one UDP stream, and watch both receive it in full — then find the IGMP reports and the 01:00:5e multicast MAC in a packet capture.
-
2026-07-10
TCP MSS Clamping: Fixing Path MTU Black Holes by Rewriting the SYN
When a narrow link hides deep in the path and ICMP is filtered, PMTUD black-holes your TCP connections. Watch a router rewrite the SYN's MSS from 1460 to 1360 so every segment fits — no PMTUD required.
-
2026-07-10
Path MTU Discovery: Why Blocking ICMP Makes Big Pages Hang
Build a path with a 1400-byte bottleneck link, send a 1500-byte Don't-Fragment packet into it, and watch ICMP fragmentation-needed teach the sender the Path MTU — the mechanism that silently breaks when firewalls drop ICMP.
-
2026-07-10
NAT Explained: How a Whole Private Network Hides Behind One Public IP
Build a masquerading NAT in a container lab, watch the server see only the NAT's public address, and inspect the conntrack table that routes replies back to the right private host.
-
2026-07-10
IPv6 Killed ARP: Watching Neighbor Discovery Resolve a MAC Address, Packet by Packet
Clear the neighbor cache, ping an IPv6 neighbor, and capture the Neighbor Solicitation / Advertisement exchange that replaces ARP — multicast instead of broadcast, ICMPv6 instead of a dedicated protocol.
-
2026-07-10
OSPF Explained: Flood the Map, Run Dijkstra, and Reroute in Seconds
Build a three-router OSPF triangle, watch every router flood the same link-state map, see SPF pick the cheapest path by cost, then kill the best link and watch it reconverge automatically.
-
2026-07-10
Policy Routing: When the Source Address Picks the Path, Not the Destination
Two hosts send to the same destination IP, yet one exits via up1 and the other via up2 — add a single ip rule and watch Linux route by source, not destination.
-
2026-07-10
Traffic Shaping with a Token Bucket: Cap a 56 Gbit/s Link at 10 Mbit/s Using tc
Attach a tbf token-bucket qdisc to a container's egress and watch iperf3 drop from tens of Gbit/s to exactly the rate you configured — plus why a too-small burst throttles you almost to zero.
-
2026-07-10
HTTP/2 Streams and the Jump to QUIC: Why HTTP/3 Ditched TCP
Multiplex three requests over one TCP connection with HTTP/2, read the Alt-Svc header that advertises HTTP/3, and see why QUIC moves streams onto UDP to kill head-of-line blocking.
-
2026-07-10
Reverse Path Filtering: How Linux Drops Spoofed Packets at the Door
Spoof a source address from the wrong network, watch strict rp_filter drop it at ingress while real traffic sails through, then switch it off and see the forgery get forwarded — BCP 38 anti-spoofing, hands-on.
-
2026-07-10
RPKI Origin Validation: Watch BGP Routes Turn Valid, Invalid, and Not Found
Connect FRRouting to a local RPKI-to-Router cache, announce the same prefix from an authorized and an unauthorized AS, and watch origin validation label each route valid, invalid, or not found.
-
2026-07-10
One TCP Connection, From SYN to FIN: Capture the Whole Lifecycle in tcpdump
Open a single TCP connection in a two-node container lab and annotate its entire life in one packet capture: the three-way handshake, one data exchange, and the four-way teardown.
-
2026-07-10
Break the Link on Purpose: Watching TCP Retransmit, Shrink Its Window, and Still Deliver Every Byte
Add 25ms of delay and 15% packet loss with tc netem, push 3 MB through, and watch TCP detect the loss, retransmit, shrink its congestion window — and still complete the transfer.
-
2026-07-10
TLS 1.3 on the Wire: What an Eavesdropper Can Still See Before Encryption Kicks In
Open one TLS 1.3 connection, capture the handshake, and pinpoint the exact boundary where cleartext ends: SNI and the ALPN offer are visible, but the certificate is not.
-
2026-07-10
Mutual TLS Explained: Making the Client Prove Its Identity Too
Run a tiny lab CA, sign a server cert and a client cert, then watch a -Verify server accept the client that presents a certificate and reject the one that doesn't — with a 'certificate required' TLS alert.
-
2026-07-10
How traceroute Really Works: TTL, ICMP Time-Exceeded, and Mapping a Path Hop by Hop
Build a real client → r1 → r2 → server path in containers, run traceroute, and capture the ICMP time-exceeded messages that turn a simple loop-prevention field into a hop-by-hop map.
-
2026-07-10
VLANs Explained: Two Separate Networks on One Wire with 802.1Q Tags
Put two VLANs on a single physical link, ping across each, and watch 802.1Q tags keep them completely isolated — one wire, two broadcast domains.
-
2026-07-10
VXLAN Explained: An Overlay You Can Read on the Wire
Build a point-to-point VXLAN overlay, ping across it, then capture the underlay and watch the inner ICMP appear in plain text — proof that encapsulation and encryption are two different jobs.
-
2026-07-10
WireGuard, Seen From Both Sides: The Same Ping as Ciphertext and Cleartext
Build a WireGuard tunnel between two containers, then capture the same ping twice — encrypted UDP on the real link, cleartext ICMP inside wg0 — to see exactly where a VPN's encryption applies.
-
2026-07-10
ARP Explained: How IPv4 Turns an IP Address into a MAC by Shouting at Everyone
Clear the ARP cache, ping a neighbor, and capture the broadcast 'who has 10.0.0.2?' request and unicast 'is-at' reply that make IPv4 delivery on a link actually work.
-
2026-07-10
BFD Explained: Catching a Silent Network Failure in Under a Second
When a link stays up but forwarding silently dies, OSPF alone waits 40 seconds to notice. Add BFD and the same failure is detected in ~900 ms — here's a hands-on lab that proves it.
-
2026-07-10
BGP From Scratch: Announce One Prefix and Explain Every Field of the Route
Build a two-router eBGP lab with containerlab and FRRouting, announce a single prefix, and learn to read NLRI, AS_PATH, NEXT_HOP, and ORIGIN straight out of RFC 4271 — packet capture included.
-
2026-07-10
BGP UPDATE in Action: Watch a Route Appear, Disappear, and Come Back
Announce a prefix over eBGP, withdraw it, and re-announce it — then confirm in FRRouting output and a packet capture that one UPDATE message does both the advertising and the withdrawing.
-
2026-07-10
Competing Origins: When Two ASes Announce the Same Prefix, Who Do You Believe?
Make two different ASNs originate the same prefix, watch an upstream router receive both competing paths, and learn why the BGP table alone can never tell you which origin is legitimate.
-
2026-07-10
CUBIC vs BBR: How Your Congestion Control Choice Changes Throughput 7x on a Lossy Path
Impair one path with 100 ms RTT and 2% random loss, run iperf3 with CUBIC and then BBR, and watch the same link deliver 12 Mbit/s or 88 Mbit/s depending only on the algorithm.
-
2026-07-10
DANE Explained: When DNS Vouches for the Certificate — No CA Required
Pin a self-signed certificate with a DNSSEC-signed TLSA record, watch openssl accept it with Verify return code 0, then throw an impostor cert at the same pin and watch DANE reject it.
-
2026-07-10
DHCP Explained: How a Machine With No IP Address Gets One in Four Messages
Boot a client with no IP address at all, run a DHCP client against a tiny server, and capture the full Discover-Offer-Request-Ack (DORA) exchange on the wire.
-
2026-07-10
DNAT Explained: Publishing an Internal Service Through One Public Address and Port
Hit a public address:port and get nothing, add one DNAT rule, and the same request lands on a hidden internal server — then read the conntrack table to see how the reply gets un-NATed.
-
2026-07-10
How DNS Really Resolves a Name: Build Your Own Root, TLD, and Authoritative Servers and Trace Every Step
Build a tiny private DNS hierarchy — root, TLD, and authoritative — then watch a recursive resolver walk the delegation chain with dig +trace and see caching kick in on the second query.
-
2026-07-10
DNS Caching Explained: Watch TTLs Count Down and NXDOMAIN Get Cached Too
Query the same name twice and watch the TTL shrink, compare short and long TTLs, then ask for a name that doesn't exist and see why NXDOMAIN comes back with an SOA — and gets cached anyway.
-
2026-07-10
DNSSEC in a Container Lab: Sign a Zone, Tamper With It, and Watch the Resolver Say No
Sign a DNS zone, validate it with a trust anchor and watch the AD flag appear — then flip one byte of the data and see the resolver reject the answer with SERVFAIL.
-
2026-07-10
Encrypted DNS in Practice: Resolve the Same Name over Do53, DoT, and DoH — Then Sniff the Wire
Query the same name over classic port-53 DNS, DNS over TLS, and DNS over HTTPS, capture all three on the wire, and see exactly what an on-path observer can and cannot read.
-
2026-07-10
Split-Horizon DNS: One Name, Two Answers, and the Server Decides by Who's Asking
Serve the same zone through two BIND views, ask from an internal and an external client, and watch one name resolve to a private address for insiders and a public one for everyone else.
-
2026-07-10
DNS Round-Robin: The Cheapest Load Balancer Is Three A Records and a Rotating Answer
Give one name three A records, let BIND rotate the order on every response, and watch clients spread across backends — the simplest load distribution there is, and the coarsest.
-
2026-07-10
One Web Request, End to End: Watch curl Cross DNS, TCP, TLS, and HTTP in Order
Run a single curl command in a container lab and watch it traverse every layer in sequence — DNS resolution, the TCP handshake, TLS 1.3 with SNI and ALPN, and an HTTP/2 200 — captured on the wire.
-
2026-07-10
ECMP Explained: Two Equal Paths, and the Kernel Hashes Flows Across Them
Install a two-next-hop BGP route with maximum-paths, blast 16 TCP flows across two parallel links, then flip Linux's hash policy and watch one link do all the work — the classic ECMP gotcha.
-
2026-07-10
Stateful Firewalls Explained: Judge the Connection, Not the Packet
Set FORWARD to default-DROP, allow only ESTABLISHED/RELATED flows and NEW connections from the inside, then watch conntrack let replies through automatically while blocking unsolicited traffic.
-
2026-07-10
GRE Explained: The Layer-3 Tunnel That Wraps Everything and Encrypts Nothing
Build a point-to-point GRE tunnel, ping across the overlay, and capture the underlay to watch IP protocol 47 carry your inner packets in the clear — completing the WireGuard/VXLAN/GRE tunnel trilogy.
-
2026-07-10
HTTP/1.1 in the Clear: Read One Request and Response Line by Line, Then Watch 304 Save the Day
Send four cleartext HTTP/1.1 requests — 200 with cache headers, HEAD, a conditional GET that returns 304, and a 404 — and learn to name every line in the exchange.
-
2026-07-10
Redirects and Cookies: How Stateless HTTP Fakes Having a Memory
Drive a 302 redirect and a Set-Cookie/Cookie round trip with curl in a container lab, and see exactly how stateless HTTP pretends to remember you.
-
2026-07-09
Anycast Explained: One IP Address, Many Servers, and BGP Picks the Winner
Announce the same IP from two servers, let BGP choose the best path, then kill the winner and watch traffic fail over automatically — no client changes needed.