<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
  <title>PathVector Blog</title>
  <link>https://blog.pathvector.dev/</link>
  <description>Hands-on networking and protocol engineering notes from PathVector Studio.</description>
  <language>en</language>
  <item>
    <title>Which router wins the segment? Read the election, not the docs</title>
    <link>https://blog.pathvector.dev/protocol-in-code-ospf-03/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-ospf-03/</guid>
    <description>OSPF&#x27;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.</description>
    <pubDate>Wed, 05 Aug 2026 19:02:45 +0000</pubDate>
  </item>
  <item>
    <title>A Hello does not make a neighbor Full — the code says so in two stages</title>
    <link>https://blog.pathvector.dev/protocol-in-code-ospf-02/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-ospf-02/</guid>
    <description>OSPF&#x27;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.</description>
    <pubDate>Tue, 04 Aug 2026 19:02:58 +0000</pubDate>
  </item>
  <item>
    <title>An OSPF Hello has to match before it can mean anything</title>
    <link>https://blog.pathvector.dev/protocol-in-code-ospf-01/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-ospf-01/</guid>
    <description>Reading OSPF&#x27;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.</description>
    <pubDate>Mon, 03 Aug 2026 19:02:53 +0000</pubDate>
  </item>
  <item>
    <title>A BGP speaker is just state plus three event handlers</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-15/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-15/</guid>
    <description>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.</description>
    <pubDate>Sun, 02 Aug 2026 19:02:44 +0000</pubDate>
  </item>
  <item>
    <title>One prefix stops being one route: reading BGP&#x27;s decision set as code</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-14/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-14/</guid>
    <description>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.</description>
    <pubDate>Sat, 01 Aug 2026 19:02:38 +0000</pubDate>
  </item>
  <item>
    <title>Announce, withdraw, and peer down are three different code paths</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-13/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-13/</guid>
    <description>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.</description>
    <pubDate>Fri, 31 Jul 2026 19:02:42 +0000</pubDate>
  </item>
  <item>
    <title>When Loc-RIB changes, every peer needs a different answer</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-12/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-12/</guid>
    <description>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.</description>
    <pubDate>Thu, 30 Jul 2026 19:02:36 +0000</pubDate>
  </item>
  <item>
    <title>Established is not a status label — it&#x27;s a write permission</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-11/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-11/</guid>
    <description>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.</description>
    <pubDate>Wed, 29 Jul 2026 19:02:37 +0000</pubDate>
  </item>
  <item>
    <title>One route, one function chain: reading a BGP pipeline as code</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-10/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-10/</guid>
    <description>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.</description>
    <pubDate>Tue, 28 Jul 2026 20:51:40 +0000</pubDate>
  </item>
  <item>
    <title>When a BGP peer disappears, one session loss becomes many route decisions</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-09/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-09/</guid>
    <description>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.</description>
    <pubDate>Tue, 28 Jul 2026 11:02:31 +0000</pubDate>
  </item>
  <item>
    <title>Export policy decides what leaves: reading BGP outbound state as code</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-08/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-08/</guid>
    <description>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.</description>
    <pubDate>Mon, 27 Jul 2026 11:02:40 +0000</pubDate>
  </item>
  <item>
    <title>Import policy rewrites the route before best-path ever sees it</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-07/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-07/</guid>
    <description>Reading BGP import policy as code: the candidate that enters best-path selection is not always the one the peer sent.</description>
    <pubDate>Sun, 26 Jul 2026 11:03:06 +0000</pubDate>
  </item>
  <item>
    <title>Where a route lives: the three RIBs, as code</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-06/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-06/</guid>
    <description>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.</description>
    <pubDate>Sat, 25 Jul 2026 11:02:43 +0000</pubDate>
  </item>
  <item>
    <title>Validation State Doesn&#x27;t Act By Itself</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-05/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-05/</guid>
    <description>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.</description>
    <pubDate>Fri, 24 Jul 2026 11:02:32 +0000</pubDate>
  </item>
  <item>
    <title>Origin validation is a separate decision from best path</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-04/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-04/</guid>
    <description>BGP picking a best path doesn&#x27;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.</description>
    <pubDate>Thu, 23 Jul 2026 11:03:00 +0000</pubDate>
  </item>
  <item>
    <title>BGP best path selection is just a chain of if statements</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-03/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-03/</guid>
    <description>Reading BGP best path selection as ordered branches: the first differing field decides the winner, and everything after it never runs.</description>
    <pubDate>Wed, 22 Jul 2026 11:02:41 +0000</pubDate>
  </item>
  <item>
    <title>How a BGP UPDATE Changes State: Reading Withdrawal and Announcement as Code</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-02/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-02/</guid>
    <description>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.</description>
    <pubDate>Tue, 21 Jul 2026 11:02:41 +0000</pubDate>
  </item>
  <item>
    <title>What a BGP Neighbor Needs — Reading Session Setup as Code</title>
    <link>https://blog.pathvector.dev/protocol-in-code-bgp-01/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-in-code-bgp-01/</guid>
    <description>A BGP session isn&#x27;t a config line — it&#x27;s a state machine that stops at a different place depending on which input is missing. We read that machine in Python.</description>
    <pubDate>Mon, 20 Jul 2026 21:51:20 +0000</pubDate>
  </item>
  <item>
    <title>A Network Protocol Learning Roadmap: 42 Hands-On Labs and 151 Code-Reading Sessions, Mapped</title>
    <link>https://blog.pathvector.dev/network-protocol-roadmap-2026/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/network-protocol-roadmap-2026/</guid>
    <description>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.</description>
    <pubDate>Sun, 12 Jul 2026 08:35:27 +0000</pubDate>
  </item>
  <item>
    <title>L4 Load Balancing with IPVS: One VIP, Three Backends, and a Perfect 10/10/10 Split</title>
    <link>https://blog.pathvector.dev/protocol-lab-lb-33/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-lb-33/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>Multicast and IGMP: How One UDP Stream Reaches Many Receivers Without a Single Extra Copy</title>
    <link>https://blog.pathvector.dev/protocol-lab-mcast-29/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-mcast-29/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>TCP MSS Clamping: Fixing Path MTU Black Holes by Rewriting the SYN</title>
    <link>https://blog.pathvector.dev/protocol-lab-mss-37/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-mss-37/</guid>
    <description>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&#x27;s MSS from 1460 to 1360 so every segment fits — no PMTUD required.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>Path MTU Discovery: Why Blocking ICMP Makes Big Pages Hang</title>
    <link>https://blog.pathvector.dev/protocol-lab-mtu-25/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-mtu-25/</guid>
    <description>Build a path with a 1400-byte bottleneck link, send a 1500-byte Don&#x27;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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>NAT Explained: How a Whole Private Network Hides Behind One Public IP</title>
    <link>https://blog.pathvector.dev/protocol-lab-nat-20/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-nat-20/</guid>
    <description>Build a masquerading NAT in a container lab, watch the server see only the NAT&#x27;s public address, and inspect the conntrack table that routes replies back to the right private host.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>IPv6 Killed ARP: Watching Neighbor Discovery Resolve a MAC Address, Packet by Packet</title>
    <link>https://blog.pathvector.dev/protocol-lab-ndp-23/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-ndp-23/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>OSPF Explained: Flood the Map, Run Dijkstra, and Reroute in Seconds</title>
    <link>https://blog.pathvector.dev/protocol-lab-ospf-34/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-ospf-34/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>Policy Routing: When the Source Address Picks the Path, Not the Destination</title>
    <link>https://blog.pathvector.dev/protocol-lab-pbr-38/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-pbr-38/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>Traffic Shaping with a Token Bucket: Cap a 56 Gbit/s Link at 10 Mbit/s Using tc</title>
    <link>https://blog.pathvector.dev/protocol-lab-qos-28/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-qos-28/</guid>
    <description>Attach a tbf token-bucket qdisc to a container&#x27;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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>HTTP/2 Streams and the Jump to QUIC: Why HTTP/3 Ditched TCP</title>
    <link>https://blog.pathvector.dev/protocol-lab-quic-11/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-quic-11/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>Reverse Path Filtering: How Linux Drops Spoofed Packets at the Door</title>
    <link>https://blog.pathvector.dev/protocol-lab-rpf-39/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-rpf-39/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>RPKI Origin Validation: Watch BGP Routes Turn Valid, Invalid, and Not Found</title>
    <link>https://blog.pathvector.dev/protocol-lab-rpki-04/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-rpki-04/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>One TCP Connection, From SYN to FIN: Capture the Whole Lifecycle in tcpdump</title>
    <link>https://blog.pathvector.dev/protocol-lab-tcp-07/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-tcp-07/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>Break the Link on Purpose: Watching TCP Retransmit, Shrink Its Window, and Still Deliver Every Byte</title>
    <link>https://blog.pathvector.dev/protocol-lab-tcp-08/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-tcp-08/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>TLS 1.3 on the Wire: What an Eavesdropper Can Still See Before Encryption Kicks In</title>
    <link>https://blog.pathvector.dev/protocol-lab-tls-09/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-tls-09/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>Mutual TLS Explained: Making the Client Prove Its Identity Too</title>
    <link>https://blog.pathvector.dev/protocol-lab-tls-15/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-tls-15/</guid>
    <description>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&#x27;t — with a &#x27;certificate required&#x27; TLS alert.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>How traceroute Really Works: TTL, ICMP Time-Exceeded, and Mapping a Path Hop by Hop</title>
    <link>https://blog.pathvector.dev/protocol-lab-trace-19/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-trace-19/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>VLANs Explained: Two Separate Networks on One Wire with 802.1Q Tags</title>
    <link>https://blog.pathvector.dev/protocol-lab-vlan-26/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-vlan-26/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>VXLAN Explained: An Overlay You Can Read on the Wire</title>
    <link>https://blog.pathvector.dev/protocol-lab-vxlan-18/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-vxlan-18/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>WireGuard, Seen From Both Sides: The Same Ping as Ciphertext and Cleartext</title>
    <link>https://blog.pathvector.dev/protocol-lab-wg-16/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-wg-16/</guid>
    <description>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&#x27;s encryption applies.</description>
    <pubDate>Fri, 10 Jul 2026 13:35:12 +0000</pubDate>
  </item>
  <item>
    <title>ARP Explained: How IPv4 Turns an IP Address into a MAC by Shouting at Everyone</title>
    <link>https://blog.pathvector.dev/protocol-lab-arp-24/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-arp-24/</guid>
    <description>Clear the ARP cache, ping a neighbor, and capture the broadcast &#x27;who has 10.0.0.2?&#x27; request and unicast &#x27;is-at&#x27; reply that make IPv4 delivery on a link actually work.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>BFD Explained: Catching a Silent Network Failure in Under a Second</title>
    <link>https://blog.pathvector.dev/protocol-lab-bfd-35/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-bfd-35/</guid>
    <description>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&#x27;s a hands-on lab that proves it.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>BGP From Scratch: Announce One Prefix and Explain Every Field of the Route</title>
    <link>https://blog.pathvector.dev/protocol-lab-bgp-01/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-bgp-01/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>BGP UPDATE in Action: Watch a Route Appear, Disappear, and Come Back</title>
    <link>https://blog.pathvector.dev/protocol-lab-bgp-02/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-bgp-02/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>Competing Origins: When Two ASes Announce the Same Prefix, Who Do You Believe?</title>
    <link>https://blog.pathvector.dev/protocol-lab-bgp-03/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-bgp-03/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>CUBIC vs BBR: How Your Congestion Control Choice Changes Throughput 7x on a Lossy Path</title>
    <link>https://blog.pathvector.dev/protocol-lab-cc-30/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-cc-30/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>DANE Explained: When DNS Vouches for the Certificate — No CA Required</title>
    <link>https://blog.pathvector.dev/protocol-lab-dane-17/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dane-17/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>DHCP Explained: How a Machine With No IP Address Gets One in Four Messages</title>
    <link>https://blog.pathvector.dev/protocol-lab-dhcp-22/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dhcp-22/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>DNAT Explained: Publishing an Internal Service Through One Public Address and Port</title>
    <link>https://blog.pathvector.dev/protocol-lab-dnat-40/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dnat-40/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>How DNS Really Resolves a Name: Build Your Own Root, TLD, and Authoritative Servers and Trace Every Step</title>
    <link>https://blog.pathvector.dev/protocol-lab-dns-05/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dns-05/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>DNS Caching Explained: Watch TTLs Count Down and NXDOMAIN Get Cached Too</title>
    <link>https://blog.pathvector.dev/protocol-lab-dns-06/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dns-06/</guid>
    <description>Query the same name twice and watch the TTL shrink, compare short and long TTLs, then ask for a name that doesn&#x27;t exist and see why NXDOMAIN comes back with an SOA — and gets cached anyway.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>DNSSEC in a Container Lab: Sign a Zone, Tamper With It, and Watch the Resolver Say No</title>
    <link>https://blog.pathvector.dev/protocol-lab-dns-13/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dns-13/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>Encrypted DNS in Practice: Resolve the Same Name over Do53, DoT, and DoH — Then Sniff the Wire</title>
    <link>https://blog.pathvector.dev/protocol-lab-dns-14/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dns-14/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>Split-Horizon DNS: One Name, Two Answers, and the Server Decides by Who&#x27;s Asking</title>
    <link>https://blog.pathvector.dev/protocol-lab-dns-views-42-split-horizon/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dns-views-42-split-horizon/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>DNS Round-Robin: The Cheapest Load Balancer Is Three A Records and a Rotating Answer</title>
    <link>https://blog.pathvector.dev/protocol-lab-dnsrr-41/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-dnsrr-41/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>One Web Request, End to End: Watch curl Cross DNS, TCP, TLS, and HTTP in Order</title>
    <link>https://blog.pathvector.dev/protocol-lab-e2e-12/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-e2e-12/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>ECMP Explained: Two Equal Paths, and the Kernel Hashes Flows Across Them</title>
    <link>https://blog.pathvector.dev/protocol-lab-ecmp-32/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-ecmp-32/</guid>
    <description>Install a two-next-hop BGP route with maximum-paths, blast 16 TCP flows across two parallel links, then flip Linux&#x27;s hash policy and watch one link do all the work — the classic ECMP gotcha.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>Stateful Firewalls Explained: Judge the Connection, Not the Packet</title>
    <link>https://blog.pathvector.dev/protocol-lab-fw-36/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-fw-36/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>GRE Explained: The Layer-3 Tunnel That Wraps Everything and Encrypts Nothing</title>
    <link>https://blog.pathvector.dev/protocol-lab-gre-21/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-gre-21/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>HTTP/1.1 in the Clear: Read One Request and Response Line by Line, Then Watch 304 Save the Day</title>
    <link>https://blog.pathvector.dev/protocol-lab-http-10/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-http-10/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>Redirects and Cookies: How Stateless HTTP Fakes Having a Memory</title>
    <link>https://blog.pathvector.dev/protocol-lab-http-27/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-http-27/</guid>
    <description>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.</description>
    <pubDate>Fri, 10 Jul 2026 13:28:02 +0000</pubDate>
  </item>
  <item>
    <title>Anycast Explained: One IP Address, Many Servers, and BGP Picks the Winner</title>
    <link>https://blog.pathvector.dev/protocol-lab-anycast-31/</link>
    <guid isPermaLink="true">https://blog.pathvector.dev/protocol-lab-anycast-31/</guid>
    <description>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.</description>
    <pubDate>Thu, 09 Jul 2026 21:36:49 +0000</pubDate>
  </item>
</channel>
</rss>
