<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>cadlag dot org</title>
    <link>https://cadlag.org/</link>
    <description>Recent content on cadlag dot org</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>
    <managingEditor>erik&#43;blog@cadlag.org (Erik Davis)</managingEditor>
    <webMaster>erik&#43;blog@cadlag.org (Erik Davis)</webMaster>
    <copyright>Erik Davis (CC BY 4.0)</copyright>
    <lastBuildDate>Fri, 14 Mar 2025 14:03:13 -0700</lastBuildDate>
    <atom:link href="https://cadlag.org/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>One-time pad and perfect secrecy</title>
      <link>https://cadlag.org/posts/one-time-pad-perfect-secrecy/</link>
      <pubDate>Fri, 14 Mar 2025 14:03:13 -0700</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/one-time-pad-perfect-secrecy/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://en.wikipedia.org/wiki/One-time_pad&#34;&gt;one-time pad&lt;/a&gt; is one&#xA;of the simplest and well known secure encryption schemes. Suppose we&#xA;have a message \(m\), which is a sequence of \(L\) bits. The idea of the one-time pad is to take an additional \(L\) bits selected at random, called the key, and then create the ciphertext \(c\) by xor&amp;rsquo;ing the key and message together:&lt;/p&gt;&#xA;&lt;p&gt;$$ c = k \oplus m. $$&lt;/p&gt;&#xA;&lt;p&gt;To decrypt this ciphertext, we simply apply the key again:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The <a href="https://en.wikipedia.org/wiki/One-time_pad">one-time pad</a> is one
of the simplest and well known secure encryption schemes. Suppose we
have a message \(m\), which is a sequence of \(L\) bits. The idea of the one-time pad is to take an additional \(L\) bits selected at random, called the key, and then create the ciphertext \(c\) by xor&rsquo;ing the key and message together:</p>
<p>$$ c = k \oplus m. $$</p>
<p>To decrypt this ciphertext, we simply apply the key again:</p>
<p>$$ m = k \oplus m. $$</p>
<p>To understand why this is secure, we need to think like an attacker. Suppose we had access to \(c\). What can we say about \(m\)? We might try a few possible keys and see whether we recover anything interesting, but the a problem is immediate: with a length \(L\) message, there are \(2^L\) keys. And since the key is selected at random, we have no reason to suspect one more than other. This is like finding a needle in the haystack.</p>
<p>Intuitively we know there is no way we can expect to glean any information about the message from the ciphertext. But how can we formalize this? <a href="https://en.wikipedia.org/wiki/Claude_Shannon">Claude Shannon</a> captured this idea with the notion of <em>perfect secrecy</em>. An attacker might start with some initial impressions of what messages are likely or unlikely. Perfect secrecy demands that they have no reason to change these impressions based on intercepting a ciphertext alone. Mathematically, we might write this like</p>
<p>$$ P(m) = P(m \mid c), $$</p>
<p>where \(P(m)\) is the prior probability of a given message, and \(P(m \mid c)\) is the conditional probability of a message given the ciphertext.</p>
<p>We can use <a href="https://en.wikipedia.org/wiki/Bayes%27_theorem">Bayes&rsquo; theorem</a> to find an equivalent reformulation. Recall that this tells us that</p>
<p>$$ P(m \mid c) = \frac{P(c \mid m) P(m)}{P(c)}. $$</p>
<p>Combining the two equations we see that perfect secrecy is equivalent to</p>
<p>$$ P(c) = P(c \mid m), $$</p>
<p>or in English: the ciphertext must be <a href="https://en.wikipedia.org/wiki/Independence_%28probability_theory%29">independent</a> of the message.</p>
<p>It&rsquo;s easy to verify this for the one-time pad. Recalling that we choose the key at random, we have</p>
<p>$$ P(c \mid m) = P( c = m \oplus k) = \frac{1}{2^L}. $$</p>
<p>Here we see that we have more than independence: the conditional probability is uniform. Thus, we&rsquo;ve shown that the one-time pad has perfect secrecy.</p>
<p>If you look at a book like <a href="https://toc.cryptobook.us/">Boneh and Shoup</a> you&rsquo;ll see this idea of perfect secrecy formulated in a slightly more general context. Here they say a <em>Shannon cipher</em> involves a key space \(\mathcal{K}\), a message space \(\mathcal{M}\), and a cihpertext space \(\mathcal{C}\), together with an encoder \(E : \mathcal{K} \times \mathcal{M} \to \mathcal{C}\) and decoder \(D : \mathcal{K} \times C \to \mathcal{M}\). To say that decoding &ldquo;works&rdquo;, mathematically, is to say that for all \(k \in \mathcal{K}, m \in \mathcal{M}\), we have</p>
<p>$$ D(k, E(k, m)) = m. $$</p>
<p>In this context, the requirement of perfect security demands that, for all \(m_0, m_1 \in \mathcal{M}\) and \(c \in \mathcal{C}\), if \(k\) is uniformly distributed over \(\mathcal{K}\), then</p>
<p>$$ P[ E(k, m_0) = c] = P[ E(k, m_1) = c]. $$</p>
<p>This is just a generalization of what we saw with the one-time pad!</p>
<p>Perfect secrecy is a lot to ask for. Although the one-time pad has
this property, it comes at a significant cost: we need a key that is
as large as our messages. This is typically not tractable, but the
scheme is still important as a conceptual &ldquo;gold standard&rdquo;.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Avoiding loops with BGP</title>
      <link>https://cadlag.org/posts/avoiding-loops-with-bgp/</link>
      <pubDate>Sat, 08 Mar 2025 15:52:40 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/avoiding-loops-with-bgp/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://cadlag.org/posts/why-bgp/&#34;&gt;Last time&lt;/a&gt; I motivated BGP in the context&#xA;of inter-domain routing. This time, I&amp;rsquo;d like to describe a bit about&#xA;how BGP operates.&lt;/p&gt;&#xA;&lt;p&gt;A basic requirement of any routing protocol is that it cope with&#xA;&lt;em&gt;routing loops&lt;/em&gt;. Recall that under the model of destination-based&#xA;forwarding, each router forwards a packet based on the packet&amp;rsquo;s&#xA;destination IP address. The sequence of routers a packet visits as it&#xA;is forwarded through the network defines a path. If at any point this&#xA;packet returns to a router it has previously visited, this path has a&#xA;loop. Loops are dangerous because a packet will never escape,&#xA;ultimately exhausting the IP TTL. Note that a routing loop is not the&#xA;same as a loop in the network. Many network topologies have loops for&#xA;the sake of redundancy; a network loop is necessary for there to be&#xA;more than one path between hosts. But it&amp;rsquo;s the routing protocol&amp;rsquo;s job&#xA;to ensure that packets are forwarded in a loop-free fashion.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="/posts/why-bgp/">Last time</a> I motivated BGP in the context
of inter-domain routing. This time, I&rsquo;d like to describe a bit about
how BGP operates.</p>
<p>A basic requirement of any routing protocol is that it cope with
<em>routing loops</em>. Recall that under the model of destination-based
forwarding, each router forwards a packet based on the packet&rsquo;s
destination IP address. The sequence of routers a packet visits as it
is forwarded through the network defines a path. If at any point this
packet returns to a router it has previously visited, this path has a
loop. Loops are dangerous because a packet will never escape,
ultimately exhausting the IP TTL. Note that a routing loop is not the
same as a loop in the network. Many network topologies have loops for
the sake of redundancy; a network loop is necessary for there to be
more than one path between hosts. But it&rsquo;s the routing protocol&rsquo;s job
to ensure that packets are forwarded in a loop-free fashion.</p>
<p>A naive distance-vector protocol will eventually converge to a
loop-free state, given enough time. But this convergence takes time,
and you see what is known as <a href="https://en.wikipedia.org/wiki/Distance-vector_routing_protocol#Count_to_infinity_problem">&ldquo;counting to
infinity&rdquo;</a>,
where loops are only evicted after computed distances increase
step-by-step until reaching a large enough value that they are
effectively infinite. While there are various tricks to mitigate this,
BGP takes a simpler approach.</p>
<p>Routers running BGP (also known as BGP &ldquo;speakers&rdquo;) are connected in
peering relationships. Here it&rsquo;s useful to distinguish between
connections within a single autonomous system (iBGP connections) and
connections across autonomous systems (eBGP connections). Both eBGP
and iBGP connections run the same protocol &ndash; BGP &ndash; but they are
configured slightly differently.</p>
<p>Whereas routers running a naive distance-vector algorithm will
advertise distance information, BGP speakers advertise routes. In the
context of BGP, a route pairs a set of destinations with several
attributes of a path between those destinations. There are several
path attributes, but I will mention two of the mandatory ones.</p>
<ol>
<li>The <code>AS_PATH</code> attribute is a sequence of AS-path segments. In its
simplest form this is a list of AS numbers, like <code>[1,6,7]</code>, though
the actual specification allows for unordered sets as well.</li>
<li>The <code>NEXT_HOP</code> is the IP address of the router that should be used
as the next hop to the destination.</li>
</ol>
<p>When a route is advertised on an eBGP connection, the sender adds its
AS number to the <code>AS_PATH</code>. Thus, as information propagates from one
AS to another, the route carries information about its history. This
makes it straightforward to detect possible inter-AS routing
loops. I&rsquo;ll quote from <a href="https://datatracker.ietf.org/doc/html/rfc4271">the
spec</a>:</p>
<blockquote>
<p>If the <code>AS_PATH</code> attribute of a BGP route contains an AS loop, the BGP route should be excluded from the Phase 2 decision function.  AS loop detection is done by scanning the full AS path (as specified in the <code>AS_PATH</code> attribute), and checking that the autonomous system number of the local system does not appear in the AS path.  Operations of a BGP speaker that is configured to accept routes with its own autonomous system number in the AS path are outside the scope of this document.</p>
</blockquote>
<p>Note that this &ldquo;Phase 2 decision function&rdquo; is just jargon for the rule
that determines what advertised information actually makes it into the
local forwarding table of a BGP speaker (and hence could be
subsequently advertised to peers).</p>
<p>The <code>AS_PATH</code> information is enough to prevent AS loops. But what
happens within a single AS?</p>
<p>Consider an AS with three routers  A, B, and C, as shown below.</p>





<pre tabindex="0"><code>                   +-------+        +-------+
             eBGP  |       |  iBGP  |       |
            -------|   A   |--------|   B   |
                   |       |        |       |
                   +-------+        +-------+
                         \            /
                     iBGP \          / iBGP
                           \        /
                            +-------+
                            |       |
                            |  C    |
                            |       |
                            +-------+</code></pre><p>Suppose A advertises a route to B, and B advertises this to C, and
then C advertises this to A. The <code>AS_PATH</code> of this route does not
reveal the loop, <em>because it is internal to the current AS</em>. If A
accepted this advertisement, it would be a problem.</p>
<p>The BGP answer to this issue of intra-AS loops is another simple
mechanism: speakers should not re-advertise routes received via
iBGP. In our above example, this means A will advertise to B and C
directly, and neither B nor C will send anything back to A. No loops
are possible with this restriction.</p>
<p>While this solution is straightforward, it introduces a scalability
problem. Since routes learned via iBGP are not re-advertised, we need
to have iBGP connections between every pair of routers running BGP
(this is sometimes called &ldquo;full mesh&rdquo; connectivity). In the above
diagram that&rsquo;s OK, because there are only three routers. But for N
routers, there are N*(N-1)/2 pairs, and the amount of BGP updates
flowing around the network and stored within the various
routing-information bases can quickly get out of hand.</p>
<p>Fortunately, there is a BGP extension in <a href="https://datatracker.ietf.org/doc/html/rfc4456">RFC
4456</a> allowing a BGP
speaker to be designated as a &ldquo;route reflector&rdquo;. Route reflectors can
advertise iBGP learned routes to configured iBGP peers. Here&rsquo;s a
diagram from RFC 4456:</p>





<pre tabindex="0"><code>                 / - - - - - - - - - - - - -  -
                 |           Cluster           |
                   +-------+        +-------+
                 | |       |        |       |  |
                   | RTR-A |        | RTR-B |
                 | |Client |        |Client |  |
                   +-------+        +-------+
                 |       \           /         |
                    IBGP  \         / IBGP
                 |         \       /           |
                           +-------+
                 |         |       |           |
                           | RTR-C |
                 |         |  RR   |           |
                           +-------+
                 |           /   \             |
                  - - - - - /- - -\- - - - - - /
                     IBGP  /       \ IBGP
                  +-------+         +-------+
                  | RTR-D |  IBGP   | RTR-E |
                  |  Non- |---------|  Non- |
                  |Client |         |Client |
                  +-------+         +-------+</code></pre><p>The idea of route reflection is to subdivide the routers into
&ldquo;clusters&rdquo;. Within each cluster we have a designated &ldquo;route reflector&rdquo;
which is linked in a star topology to a set of &ldquo;client
routers&rdquo;. Across clusters we have a full-mesh connectivity of the
route reflectors. When a route reflector receives advertisements from
another cluster, it can advertise this to its clients. If a route
reflector receives an advertisement from a client, it can advertise
this to all other iBGP peers. If we had k clusters of size M, using
route reflectors requires O(k^2 + M) total iBGP
connections. Assuming k is more or less a small, fixed constant, you
can see that this has linear scaling (rather than the naive quadratic
scaling of iBGP).</p>
<p>It&rsquo;s worth noting that there&rsquo;s another extension, <a href="https://datatracker.ietf.org/doc/html/rfc5065">RFC
5065</a>, that allows
several ASes to be treated as a &ldquo;confederation&rdquo; that appears as a
single AS to external peers. Within each AS of the confederation one
would still need full mesh iBGP, but because eBGP is used between ASes
of the confederation the connectivity can be sparser. If your
confederation had k ASes of size M, then you would need something like
O(kM^2) total iBGP connections. In practice, it seems like route
reflectors are the more popular option, though there&rsquo;s a risk for
misconfiguration.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Why BGP?</title>
      <link>https://cadlag.org/posts/why-bgp/</link>
      <pubDate>Tue, 04 Mar 2025 10:13:40 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/why-bgp/</guid>
      <description>&lt;p&gt;The internet got its name from the fact that it is a &amp;ldquo;network of&#xA;networks&amp;rdquo;. Various businesses, universities, and government entities&#xA;developed networks but had to coordinate in order to communicate&#xA;across these. The challenges here are more than just technical; the&#xA;reality is that different organizations have different incentives.&lt;/p&gt;&#xA;&lt;p&gt;In the jargon of computer networks, such entities are called&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Autonomous_system_%28Internet%29&#34;&gt;autonomous&#xA;systems&lt;/a&gt;. They&#xA;may control routing within&#xA;their domains, but how should routing happen &lt;em&gt;across&lt;/em&gt;&#xA;domains?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The internet got its name from the fact that it is a &ldquo;network of
networks&rdquo;. Various businesses, universities, and government entities
developed networks but had to coordinate in order to communicate
across these. The challenges here are more than just technical; the
reality is that different organizations have different incentives.</p>
<p>In the jargon of computer networks, such entities are called
<a href="https://en.wikipedia.org/wiki/Autonomous_system_%28Internet%29">autonomous
systems</a>. They
may control routing within
their domains, but how should routing happen <em>across</em>
domains?</p>
<p>Some of these autonomous systems are
<a href="https://en.wikipedia.org/wiki/Stub_network">&ldquo;stubs&rdquo;</a>,
i.e. organizations that just want to provide internet access to their
own networks. Others, such as an ISP or network carrier, are in the
business of selling connectivity or transit services. Autonomous
systems can enter into various relationships with each other: a service
provider might sell access to a stub, and two service providers might
agree to transfer data between themselves (known as
<a href="https://en.wikipedia.org/wiki/Peering">&ldquo;peering&rdquo;</a>).</p>
<p>As noted, each AS has their own incentives and priorities. A transit
AS may want to forward traffic for which they get paid but not traffic
for which they don&rsquo;t. A government may want to ensure that their data
is never routed through a certain country. For the internet to even
exist, such incentives have to be aligned. From this perspective,
inter-AS (also called inter-domain) routing isn&rsquo;t just about
minimizing the number of hops or the network latency. Rather, it&rsquo;s
about providing autonomous systems with a sufficiently rich set of
policy levers that they can conduct business.</p>
<p>Within the world of routing protocols, a distinction is often made
between &ldquo;distance-vector&rdquo; and &ldquo;link-state&rdquo; protocols. A
<a href="https://en.wikipedia.org/wiki/Distance-vector_routing_protocol">distance-vector</a>
protocol computes routes by distributing the computation. Routers
publish the destinations they can reach along with the cost to reach
them (hence the name: mathematically this looks like a vector of
distances). When one router receives distance vectors from another, it
re-calculates its own costs based on this updated information. This is
a distributed form of the
<a href="https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm">Bellman-Ford</a>
algorithm, and one of the oldest approaches to routing. One of the
earliest implementations is the <a href="https://en.wikipedia.org/wiki/Routing_Information_Protocol">Routing Information Protocol
(RIP)</a>.</p>
<p>The distance-vector idea is conceptually simple, but a naive
implementation suffers from several performance issues. One notable
problem is that convergence can be slow in the face of topology
changes. Underlying this is the fact that stale information can
circulate around network loops, and routers don&rsquo;t have any way of
knowing that they are acting on this stale information.</p>
<p>Over time a new paradigm emerged, the so-called
<a href="https://en.wikipedia.org/wiki/Link-state_routing_protocol">link-state</a>
algorithms. Rather than distribute the path computation, link-state
protocols distribute knowledge of the underlying network
topology. Routers do this by advertising the links they have available
(hence the name). They also maintain a database of the advertisements
they have seen. Shortest paths through the network can be computed on
a router directly (e.g. using Dijkstra&rsquo;s algorithm). The internet
standard here is the <a href="https://en.wikipedia.org/wiki/Open_Shortest_Path_First">Open Shortest Path
First</a>
protocol.</p>
<p>Link-state protocols typically have better convergence properties than
distance-vector protocols, but they are not well suited for routing
across autonomous systems. This goes back to issues of policy and
incentive. Suppose an autonomous system is only willing to route
traffic when they get paid to. This kind of constraint cannot be
enforced in the network topology or from clever ways of assigning link
costs. Nonetheless, evaluating whether a proposed route
adheres to this constraint is straightforward.</p>
<p>This is where the internet&rsquo;s <a href="https://en.wikipedia.org/wiki/Border_Gateway_Protocol">Border Gateway
Protocol</a> (BGP)
comes in. BGP takes the distance-vector paradigm but turns it on its
head. What distance-vector gets right, from the perspective of
inter-domain routing, is that it is centered on sharing reachability
information rather than link information. But the emphasis on
distances or costs as the bottom line is too narrow-minded. Instead,
routers running BGP advertise paths and metadata about these
paths. Administrators have control over what paths their AS
advertises. They also control how their AS uses path information
shared by domains.</p>
<p>BGP was first proposed in 1989 in <a href="https://datatracker.ietf.org/doc/html/rfc1105">RFC
1105</a>. The initial RFC
is surprisingly short. I was amused to learn that the original idea
was developed in an IETF cafeteria as the authors scribbled their
thoughts on a pair of napkins, leading BGP to be known as the
<a href="https://computerhistory.org/blog/the-two-napkin-protocol/">&ldquo;two-knapkin
protocol&rdquo;</a>. BGP
was not created in a vacuum. The problem of inter-domain routing had
already been considered in <a href="https://datatracker.ietf.org/doc/html/rfc827">RFC
827</a> but was showing its
limits as the internet grew. So BGP was an attempt at a next-generation inter-domain routing protocol.</p>
<p>The latest version, BGP-4, takes <a href="https://datatracker.ietf.org/doc/html/rfc4271">100
pages</a> to specify in
the core standard. Today, inter-domain routing runs on BGP-4. What the
protocol has lost in elegance or brevity, it&rsquo;s made up for by
successfully scaling the internet.</p>
]]></content:encoded>
    </item>
    <item>
      <title>RFC 1180: A TCP/IP Tutorial</title>
      <link>https://cadlag.org/posts/rfc-1180-tcp-ip-tutorial/</link>
      <pubDate>Sat, 01 Mar 2025 09:16:30 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/rfc-1180-tcp-ip-tutorial/</guid>
      <description>&lt;p&gt;There are several types of &lt;a href=&#34;https://www.ietf.org/process/rfcs/&#34;&gt;IETF&#xA;RFCs&lt;/a&gt;, including strict standards,&#xA;looser &amp;ldquo;best common practices&amp;rdquo;, as well as purely informational&#xA;documents. Today we&amp;rsquo;ll look at &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc1180&#34;&gt;RFC&#xA;1180&lt;/a&gt;, a tutorial on&#xA;how TCP/IP typically worked as of 1991 (when this document was&#xA;written). This RFC is more than 30 years old, so I&amp;rsquo;ll mention a few&#xA;possible updates that come to mind as I read it. This is probably&#xA;going to feel a bit abrupt in places—think of it more as a set of&#xA;notes than a fully synthesized RFC revision.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>There are several types of <a href="https://www.ietf.org/process/rfcs/">IETF
RFCs</a>, including strict standards,
looser &ldquo;best common practices&rdquo;, as well as purely informational
documents. Today we&rsquo;ll look at <a href="https://datatracker.ietf.org/doc/html/rfc1180">RFC
1180</a>, a tutorial on
how TCP/IP typically worked as of 1991 (when this document was
written). This RFC is more than 30 years old, so I&rsquo;ll mention a few
possible updates that come to mind as I read it. This is probably
going to feel a bit abrupt in places—think of it more as a set of
notes than a fully synthesized RFC revision.</p>
<h3 id="sections-1--2-introduction-and-tcpip-overview">Sections 1 &amp; 2 (Introduction and TCP/IP Overview)</h3>
<p>RFC 1180 starts with a discussion of the basic structure of
TCP/IP. This has not fundamentally changed, but there are some recent
competitors to TCP, such as
<a href="https://en.wikipedia.org/wiki/QUIC">QUIC</a>, that should be
noted. Likewise, while Ethernet is still in widespread use, many
people rely on wireless link layer protocols.</p>
<h3 id="section-3-ethernet">Section 3 (Ethernet)</h3>
<p>Ethernet started as a shared-bus protocol and relied heavily on
<a href="https://en.wikipedia.org/wiki/Carrier-sense_multiple_access">carrier-sense multiple
access</a>
to manage communication on broadcast channels. These days it&rsquo;s mostly
used with point-to-point full duplex links, connected via switches, so
the emphasis has moved from medium access control techniques to packet
switching.</p>
<h3 id="section-4-arp">Section 4 (ARP)</h3>
<p>ARP solves the problem of determining link-layer MAC addresses given
an IP address. RFC 1180 describes a &ldquo;typical scenario&rdquo; in which the
destination IP address is used to directly look up the destination MAC
address, so that an Ethernet frame can be constructed. There are two
extensions of this discussion that I&rsquo;d consider:</p>
<ol>
<li>A typical case not mentioned is when an IP packet is destined for
an address outside of the current subnet. In this case the IP
packet needs to be sent to the next-hop router, and so it is this
next-hop router&rsquo;s MAC address that is needed. While this can be
inferred from the discussion in the next section (on IP), I think
it would have been worth an explicit call-out here.</li>
<li>By now, we recognize some of ARP&rsquo;s weaknesses, such as ARP spoofing.</li>
<li>Although ARP is still used for IPv4, it is not used for
IPv6. Instead, see <a href="https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol">Neighbor Discovery
Protocol</a>.</li>
</ol>
<h3 id="section-5-internet-protocol">Section 5 (Internet Protocol)</h3>
<p>Overall this section was clear, and I found the distinction between
Direct Routing (where IP adds little beyond Ethernet) and Indirect
Routing (where IP is used to connect multiple Ethernet networks) well
motivated. The extended discussion is dated in a few ways:</p>
<ol>
<li>This section predates
<a href="https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing">CIDR</a>. So
the discussion on addressing, as well as the routing examples, are
&ldquo;classful&rdquo;.</li>
<li>There&rsquo;s also no mention of
<a href="https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol">DHCP</a>,
since it didn&rsquo;t exist at the time.</li>
<li>RFC 1180 discusses the role of <code>hosts</code> files in associating names
to IP addresses. While these are still used today,
<a href="https://en.wikipedia.org/wiki/Domain_Name_System">DNS</a> is the main
mechanism for managing this association.</li>
<li>There&rsquo;s no discussion of IPv6.</li>
</ol>
<h3 id="section-6--7-udp-and-tcp">Section 6 &amp; 7 (UDP and TCP)</h3>
<p>As far as I can tell, UDP hasn&rsquo;t really changed since 1991. Maybe the
only thing I would add here is some additional context around which
contemporary application protocols use UDP.</p>
<p>TCP, on the other hand, has seen a lot of development, even if the
basic protocol has not changed. Just a few examples:</p>
<ol>
<li>There has been a fair amount of work on TCP congestion
control. This has ramifications at lower levels of the stack
(e.g. router bufferbloat), and is probably worth mentioning if only
briefly.</li>
<li>This tutorial is notably light on security. I think it should include
a discussion of
<a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">TLS</a>.</li>
</ol>
<h3 id="section-8-network-applications">Section 8 (Network Applications)</h3>
<p>In terms of philosophy, this section is still well motivated. But the
particular examples (TELNET, FTP, rsh, NFS, SNMP, X-Windows) could be
revised. Here are a few protocols I&rsquo;d mention:</p>
<ol>
<li>HTTP and HTTPS are ubiquitous examples that must be mentioned.</li>
<li>ssh as a modern and widespread replacement for rsh.</li>
<li>A mail or messaging protocol, like SMTP.</li>
<li>Some RPC protocol like gRPC.</li>
<li>Perhaps a reference to an overlay protocol like <a href="https://en.wikipedia.org/wiki/Tor_%28network%29">Tor</a>.</li>
</ol>
<h3 id="concluding-thoughts">Concluding Thoughts</h3>
<p>When writing a tutorial there&rsquo;s a tension between what to include and
what to leave out. On the whole I think the authors of <a href="https://datatracker.ietf.org/doc/html/rfc1180">RFC
1180</a> did an admirable
job. These days, this kind of &ldquo;overview&rdquo; can be found in any
networking textbook, but in 1991 such information was undoubtedly
harder to come by. I imagine this RFC helped orient a generation of
system administrators, software developers, and network operators to
the organization and function of the TCP/IP stack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A few factoids about IPv6 datagrams</title>
      <link>https://cadlag.org/posts/ipv6-datagram-factoids/</link>
      <pubDate>Tue, 25 Feb 2025 11:01:32 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/ipv6-datagram-factoids/</guid>
      <description>&lt;p&gt;A few weeks ago I went through &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc791&#34;&gt;RFC&#xA;791&lt;/a&gt;, which was the&#xA;original IPv4 specification. I thought it could be interesting to&#xA;follow up on this by looking at &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc8200&#34;&gt;RFC&#xA;8200&lt;/a&gt; which is the&#xA;latest specification for IPv6.&lt;/p&gt;&#xA;&lt;p&gt;The primary rationale for IPv6 is to go beyond the limits of IPv4&amp;rsquo;s&#xA;address space. As you recall, IPv4 addresses are 32 bits, limiting the&#xA;protocol to roughly 4 billion addresses. Over the past decade or so,&#xA;various entities responsible for managing IPv4 addresses have&#xA;allocated their final blocks. The &lt;a href=&#34;https://www.iana.org/&#34;&gt;IANA&lt;/a&gt;&#xA;declared the &amp;rsquo;top-level&amp;rsquo; allocation exhausted in 2011, followed by&#xA;various regional registries in subsequent years. Wikipedia has a more&#xA;detailed discussion of this&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/IPv4_address_exhaustion&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A few weeks ago I went through <a href="https://datatracker.ietf.org/doc/html/rfc791">RFC
791</a>, which was the
original IPv4 specification. I thought it could be interesting to
follow up on this by looking at <a href="https://datatracker.ietf.org/doc/html/rfc8200">RFC
8200</a> which is the
latest specification for IPv6.</p>
<p>The primary rationale for IPv6 is to go beyond the limits of IPv4&rsquo;s
address space. As you recall, IPv4 addresses are 32 bits, limiting the
protocol to roughly 4 billion addresses. Over the past decade or so,
various entities responsible for managing IPv4 addresses have
allocated their final blocks. The <a href="https://www.iana.org/">IANA</a>
declared the &rsquo;top-level&rsquo; allocation exhausted in 2011, followed by
various regional registries in subsequent years. Wikipedia has a more
detailed discussion of this
<a href="https://en.wikipedia.org/wiki/IPv4_address_exhaustion">here</a>.</p>
<p>IPv6 introduces a 128-bit address space. Many of the fundamentals of
IPv4 are still here: datagrams, &ldquo;best-effort delivery&rdquo;, and so on. But
in some ways IPv6 also smooths some of the rough edges of IPv4.</p>
<p>You can see this by looking at the IPv6 header:</p>





<pre tabindex="0"><code>   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version| Traffic Class |           Flow Label                  |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Payload Length        |  Next Header  |   Hop Limit   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                                                               +
   |                                                               |
   +                         Source Address                        +
   |                                                               |
   +                                                               +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                                                               +
   |                                                               |
   +                      Destination Address                      +
   |                                                               |
   +                                                               +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</code></pre><p>Let&rsquo;s take a look at the fields in more detail:</p>
<ul>
<li>The <code>Version</code> field is a hardcoded <code>6</code> for IPv6.</li>
<li>The <code>Traffic Class</code> field can be used for <a href="https://datatracker.ietf.org/doc/html/rfc2474">differentiated
services</a> and
<a href="https://datatracker.ietf.org/doc/html/rfc3168">explicit congestion
notification</a>. This
basically lets IPv6 routers do things like traffic shaping or signal
congestion to transport-level protocols like TCP.</li>
<li>The <code>Payload Length</code> specifies the size of the data following the header.</li>
<li>The <code>Next Header</code> field indicates the type of header immediately
following this one (e.g. ICMP, UDP, TCP). You can see the current
values
<a href="https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers">here</a>.</li>
<li>The <code>Hop Limit</code> is equivalent to the IPv4 time-to-live (TTL) field.</li>
<li>The <code>Source Address</code> and <code>Destination Address</code> are as you would expect.</li>
</ul>
<p>Compared to the IPv4 header (see
<a href="https://datatracker.ietf.org/doc/html/rfc791#section-3.1">here</a>) this
is remarkably streamlined. In particular, forwarding an IPv6 packet is
simplified because the header has a fixed size (whereas IPv4 has
&ldquo;options&rdquo;) and there is no checksum that has to be recomputed when the
hop limit / TTL gets decremented.</p>
<p>IPv6 eliminates the IPv4 variable-length &ldquo;Options&rdquo; field in a simple
and elegant way: it defers options to various &ldquo;Extension Headers&rdquo;
that sit between the IPv6 header and transport-layer data. Each of
these extension headers has a &ldquo;Next Header&rdquo; field, allowing them to be
chained together. About a third of RFC 8200 is defining these
extension headers, but a virtue of this approach is that the basic
mechanism of datagram forwarding can be accomplished without needing
any of these.</p>
<p>IPv6 also eliminates IPv4&rsquo;s fragment offset field. The spec requires
that any implementor have a minimum transmission unit (MTU) of 1280
bytes, and suggests using <a href="https://datatracker.ietf.org/doc/html/rfc8201">Path MTU
Discovery</a>.</p>
<p>There&rsquo;s much more that could be said about IPv6 &ndash; I only briefly
touched on the extension headers, and didn&rsquo;t discuss IPv6 addressing
in any detail. But I have been wondering: how many people actually use
IPv6? The original specification is almost 30 years old, but adoption
of IPv6 has been slowed by the ubiquity of IPv4 and the use of things
such as <a href="https://en.wikipedia.org/wiki/Network_address_translation">network address
translation</a>
to cope with the limited address space. Google has a running <a href="https://www.google.com/intl/en/ipv6/statistics.html">chart of
IPv6 traffic</a> to
their services. At the time of writing this article, total IPv6 usage
only accounts for 47% or so of Google&rsquo;s requests. There&rsquo;s still a long
way to go!</p>
]]></content:encoded>
    </item>
    <item>
      <title>ncat as an alternative ping</title>
      <link>https://cadlag.org/posts/ncat-as-an-alternative-ping/</link>
      <pubDate>Sat, 22 Feb 2025 09:56:50 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/ncat-as-an-alternative-ping/</guid>
      <description>&lt;p&gt;Whether it is used for diagnosing connectivity issues or measuring&#xA;network latency, &lt;code&gt;ping&lt;/code&gt; is an essential tool in any software&#xA;engineer&amp;rsquo;s toolkit. Under the hood, &lt;code&gt;ping&lt;/code&gt; relies on&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol&#34;&gt;ICMP&lt;/a&gt;&#xA;echo messages. &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;But many network administrators disable ICMP, or at least certain&#xA;types of ICMP traffic. This is sometimes for security reasons, as ICMP&#xA;can be used to map out a network, or as part of a denial-of-service&#xA;attack. So what if you need to &lt;code&gt;ping&lt;/code&gt; a host but can&amp;rsquo;t?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Whether it is used for diagnosing connectivity issues or measuring
network latency, <code>ping</code> is an essential tool in any software
engineer&rsquo;s toolkit. Under the hood, <code>ping</code> relies on
<a href="https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol">ICMP</a>
echo messages. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>But many network administrators disable ICMP, or at least certain
types of ICMP traffic. This is sometimes for security reasons, as ICMP
can be used to map out a network, or as part of a denial-of-service
attack. So what if you need to <code>ping</code> a host but can&rsquo;t?</p>
<p>If this host accepts TCP requests, one option is to try to open a TCP
connection. A convenient tool for this is <code>ncat</code>, a part of the
<a href="https://nmap.org/">nmap</a> suite. On macOS, installing this
is as simple as <code>brew install nmap</code>.</p>
<p>Let&rsquo;s do a quick comparison between <code>ncat</code> and <code>ping</code>. To open a TCP connection and immediately close it, we can run <code>ncat -zv google.com 80</code>. The <code>-z</code> is for &ldquo;zero I/O&rdquo; mode, and we want <code>-v</code> to see some output. I&rsquo;m asking for port 80, since I know <code>google.com</code> is serving HTTP requests there. I see the following output:</p>





<pre tabindex="0"><code>Ncat: Version 7.95 ( https://nmap.org/ncat )
Ncat: Connected to 142.251.40.46:80.
Ncat: 0 bytes sent, 0 bytes received in 0.09 seconds.</code></pre><p>On the other hand, running <code>ping 142.251.40.46</code> I get</p>





<pre tabindex="0"><code>PING 142.251.40.46 (142.251.40.46): 56 data bytes
64 bytes from 142.251.40.46: icmp_seq=0 ttl=116 time=16.572 ms
64 bytes from 142.251.40.46: icmp_seq=1 ttl=116 time=16.137 ms
64 bytes from 142.251.40.46: icmp_seq=2 ttl=116 time=16.583 ms
^C
--- 142.251.40.46 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss</code></pre><p>A key difference is that <code>ncat</code> reports significantly higher latency than <code>ping</code>. How can we explain this?</p>
<p>When I ran the above, I also captured the network traffic with Wireshark. Below is what I see for the <code>ncat</code> call:</p>
<p><img src="/posts/ncat-as-an-alternative-ping/ncat_packets.png" alt="ncat packets"></p>
<p>There are a few things to note here:</p>
<ol>
<li>The initial <code>SYN</code> + <code>SYN/ACK</code> round trip (the first part of establishing the TCP connection) has a latency of about 16ms, which is consistent with what we see from <code>ping</code>.</li>
<li><code>ncat</code> sets up and immediately closes the connection, so there are two round trips here.</li>
<li>Network latency doesn&rsquo;t fully account for the duration that <code>ncat</code> reports.</li>
</ol>
<p>I&rsquo;m not quite sure how to make sense of this 90ms duration when the
TCP connection establishment and teardown was less than 40ms. It&rsquo;s
likely that the <code>ncat</code> duration is computed across a few calls to a
system timer, and also includes the user/kernel transitions for the
underlying socket processing &ndash; so some additional latency beyond the
network time-of-flight is expected. With that said, I re-ran the same
command a few times and saw durations as low as 50ms and as high as
170ms. <code>¯\_(ツ)_/¯</code></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I have also written about this <a href="/posts/internet-control-messaging-protocol/">here</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Forwarding IP packets</title>
      <link>https://cadlag.org/posts/forwarding-ip-packets/</link>
      <pubDate>Thu, 20 Feb 2025 06:48:54 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/forwarding-ip-packets/</guid>
      <description>&lt;p&gt;A network router forwards IP packets from one network to another. In&#xA;&lt;em&gt;destination-based forwarding&lt;/em&gt;, the output port for a packet depends&#xA;entirely on the destination IP address. To enable this, routers manage&#xA;a &lt;em&gt;forwarding table&lt;/em&gt; (also known as a &lt;a href=&#34;https://en.wikipedia.org/wiki/Forwarding_information_base&#34;&gt;forwarding information&#xA;base&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Because there are a huge number of possible IP addresses, routers&#xA;typically work with ranges of addresses, as in&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing&#34;&gt;CIDR&lt;/a&gt;. In&#xA;this convention, and assuming IPv4, a range is denoted &lt;code&gt;a.b.c.d/x&lt;/code&gt;&#xA;where &lt;code&gt;x&lt;/code&gt; indicates the number of bits associated with the&#xA;network. This leaves &lt;code&gt;32-x&lt;/code&gt; bits for hosts. So for example,&#xA;&lt;code&gt;0.0.0.0/0&lt;/code&gt; is a range that covers all IP addresses, whereas&#xA;&lt;code&gt;192.168.1.0/24&lt;/code&gt; covers just those addresses of the form&#xA;&lt;code&gt;192.168.1.*&lt;/code&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A network router forwards IP packets from one network to another. In
<em>destination-based forwarding</em>, the output port for a packet depends
entirely on the destination IP address. To enable this, routers manage
a <em>forwarding table</em> (also known as a <a href="https://en.wikipedia.org/wiki/Forwarding_information_base">forwarding information
base</a>).</p>
<p>Because there are a huge number of possible IP addresses, routers
typically work with ranges of addresses, as in
<a href="https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing">CIDR</a>. In
this convention, and assuming IPv4, a range is denoted <code>a.b.c.d/x</code>
where <code>x</code> indicates the number of bits associated with the
network. This leaves <code>32-x</code> bits for hosts. So for example,
<code>0.0.0.0/0</code> is a range that covers all IP addresses, whereas
<code>192.168.1.0/24</code> covers just those addresses of the form
<code>192.168.1.*</code>.</p>
<p>Rather than require that the ranges in the forwarding table be
disjoint, the convention is that ranges may overlap. Both <code>0.0.0.0/0</code>
(a &lsquo;default&rsquo; route) and <code>192.168.1.0/24</code> (a more specific override)
could appear in a forwarding table. When resolving the output port for
a given IP packet, it&rsquo;s not enough to find an entry in the forwarding
table that matches. Instead, we are interested in the <a href="https://en.wikipedia.org/wiki/Longest_prefix_match">longest prefix
match</a>.</p>
<p>It&rsquo;s useful to distinguish between the <a href="https://en.wikipedia.org/wiki/Data_plane">&ldquo;data
plane&rdquo;</a> and <a href="https://en.wikipedia.org/wiki/Control_plane">&ldquo;control
plane&rdquo;</a> of a router. The
data plane is the part of the router that actually forwards
packets. The control plane is the part that manages the forwarding
table and coordinates with other routers as part of a routing
algorithm.</p>
<p>The data plane has stringent performance requirements and typically
involves custom hardware. Here Kurose &amp; Ross suggest considering a
simplified picture with three components:</p>
<ol>
<li>An <em>input port</em> receives incoming data. This is where the physical
and link (e.g. Ethernet) layers end, and the IP processing
begins. Each input port can separately resolve the output port
based on a lookup to the forwarding table.</li>
<li>After the output port is resolved, a packet is sent through a
<em>switching fabric</em>. This is basically a piece of digital logic
(e.g. a bus or interconnection network) that physically implements
the forwarding.</li>
<li>An <em>output port</em> receives packets from the switching fabric and
does the necessary link and physical layer operations to send these
out.</li>
</ol>
<p>Each of these components has its own complexities. For example, while
&ldquo;forwarding table lookup&rdquo; sounds innocent enough, the implementation
can be highly nontrivial. <a href="https://community.juniper.net/blogs/sharada-yeluri/2023/01/02/longest-prefix-matching-in-networking-chips">This
article</a>
goes into a few details, noting that forwarding tables in high-end
routers can contain millions of entries and may exceed the capacity of
on-chip SRAM. Meanwhile, the router&rsquo;s line rate may require that a
longest-prefix match lookup happens in as little as a single clock
cycle. Routers may use (seemingly) esoteric elements such as <a href="https://en.wikipedia.org/wiki/Content-addressable_memory">&ldquo;ternary
content-addressable
memories&rdquo;</a>
to efficiently implement forwarding calculations.</p>
<p>Another issue is that an output port may not be able to keep up with
all of the inbound packets (for example, if they are arriving from
multiple inputs simultaneously). Routers typically have memory buffers
that can hold a short backlog of packets, smoothing out a burst of
activity by making some packets wait around. But ultimately, excess
packets are dropped, and packets which are delayed too long may
be considered failures by the transport or application
layers. Determining the optimal size of these buffers, and an
efficient policy for managing them, can be highly nontrivial.</p>
<p>While we won&rsquo;t go into any further details here, I hope this gives some
appreciation for some of what goes into a router. It&rsquo;s not the sort of
knowledge I find myself needing for typical software work, but it is
still nice to have some perspective on this essential pillar of
networking.</p>
]]></content:encoded>
    </item>
    <item>
      <title>HTTP/2: The view from Wireshark</title>
      <link>https://cadlag.org/posts/http-2-the-view-from-wireshark/</link>
      <pubDate>Tue, 18 Feb 2025 20:00:11 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/http-2-the-view-from-wireshark/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://cadlag.org/posts/http2-header-compression-with-hpack/&#34;&gt;Last time&lt;/a&gt; we talked about&#xA;HTTP/2 header compression. Today we&amp;rsquo;ll actually look at HTTP/2 in&#xA;action, using &lt;a href=&#34;https://wiki.wireshark.org/&#34;&gt;Wireshark&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For what follows, we&amp;rsquo;ll assume a simple client &amp;amp; server interaction&#xA;where the client makes two &lt;code&gt;GET&lt;/code&gt; requests over a single, persistent&#xA;HTTP/2 connection. At first I tried to do this in Python using&#xA;&lt;a href=&#34;https://github.com/python-hyper/h2&#34;&gt;hyper-h2&lt;/a&gt; but after fussing&#xA;around a bit I just gave up and switched to Go. The Go&#xA;&lt;a href=&#34;https://pkg.go.dev/net/http&#34;&gt;net/http&lt;/a&gt; package supports HTTP/2 and it&#xA;was pretty easy to have ChatGPT write a simple&#xA;&lt;a href=&#34;https://gist.github.com/braised-babbage/374890bfd28edfb9a69ac2a3a07b8d6a&#34;&gt;client&lt;/a&gt;&#xA;and&#xA;&lt;a href=&#34;https://gist.github.com/braised-babbage/84c443bf2aa9c98c0b3f2b42e4583fa9&#34;&gt;server&lt;/a&gt;&#xA;for me. The client makes two &lt;code&gt;GET /&lt;/code&gt; requests, and the server responds&#xA;with &lt;code&gt;&amp;quot;hello world&amp;quot;&lt;/code&gt; to each. The only thing I had to tweak was the&#xA;&lt;code&gt;http.Transport&lt;/code&gt; settings used by the client, to force HTTP/2 over a&#xA;single connection.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="/posts/http2-header-compression-with-hpack/">Last time</a> we talked about
HTTP/2 header compression. Today we&rsquo;ll actually look at HTTP/2 in
action, using <a href="https://wiki.wireshark.org/">Wireshark</a>.</p>
<p>For what follows, we&rsquo;ll assume a simple client &amp; server interaction
where the client makes two <code>GET</code> requests over a single, persistent
HTTP/2 connection. At first I tried to do this in Python using
<a href="https://github.com/python-hyper/h2">hyper-h2</a> but after fussing
around a bit I just gave up and switched to Go. The Go
<a href="https://pkg.go.dev/net/http">net/http</a> package supports HTTP/2 and it
was pretty easy to have ChatGPT write a simple
<a href="https://gist.github.com/braised-babbage/374890bfd28edfb9a69ac2a3a07b8d6a">client</a>
and
<a href="https://gist.github.com/braised-babbage/84c443bf2aa9c98c0b3f2b42e4583fa9">server</a>
for me. The client makes two <code>GET /</code> requests, and the server responds
with <code>&quot;hello world&quot;</code> to each. The only thing I had to tweak was the
<code>http.Transport</code> settings used by the client, to force HTTP/2 over a
single connection.</p>
<p>When I ran this, the resulting Wireshark capture looked like this:</p>
<p><img src="/posts/http-2-the-view-from-wireshark/full_trace.png" alt="Full Trace"></p>
<p>To start with, we see the same sort of TLS negotiation that we
discussed <a href="/posts/https-with-tls-1-3/">previously</a>. After this we see the HTTP/2
messages.</p>
<p>The first few of these, indicated below, come before the actual <code>GET</code> request.</p>
<p><img src="/posts/http-2-the-view-from-wireshark/settings_and_more.png" alt="Settings and More"></p>
<p>Since this was run on a loopback interface, distinguishing the source
and destination of the packets can be tricky. The easiest way to
identify these is to note that there is a TCP ACK (in the opposite
direction) immediately following each. With that in mind, here&rsquo;s what
we see:</p>
<ol>
<li>The server (running on port 8443) sends the client a segment with a
single <code>SETTINGS</code> frame. The HTTP/2 spec requires that the server
send this to confirm that the protocol is in use and establish
initial settings for the HTTP/2 connection (this is known as the
<a href="https://datatracker.ietf.org/doc/html/rfc9113#preface">connection
preface</a>).</li>
<li>The client (running on port 54081) sends a segment that appears
to have three frames: <code>Magic</code>, <code>SETTINGS</code>, and <code>WINDOW_UPDATE</code>.
<code>Magic</code> indicates the string <code>&quot;PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n&quot;</code>
which starts the client&rsquo;s connection preface (this was chosen so
that HTTP/1.1 intermediaries would not attempt to process further
frames). Following this is a <code>SETTINGS</code> frame. The <code>WINDOW_UPDATE</code>
frame is used for flow control.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></li>
<li>Following this, both the client and the server respond with a
<code>SETTINGS</code> frame to acknowledge that the previous settings have
been received.</li>
</ol>
<p>After this exchange, the connection is ready for the actual requests &amp; responses. I indicate these below:</p>
<p><img src="/posts/http-2-the-view-from-wireshark/http_headers_and_data.png" alt="Headers and Data"></p>
<p>This looks like what we expect:</p>
<ol>
<li>The first <code>GET</code> request is carried by a <code>HEADERS</code> frame from the
client to the server.</li>
<li>The server responds. The response has two parts: a <code>HEADERS</code> frame
(e.g. carrying the <code>200 OK</code> code) and a <code>DATA</code> frame with the
actual body of the response.</li>
<li>Since our script makes two responses back-to-back, we see another
pair of <code>HEADERS</code> (from the client) followed by <code>HEADERS</code>+<code>DATA</code>
from the server.</li>
</ol>
<p>Looking closely, we can see HPACK in action. The size of the
first <code>HEADERS</code> packet from the client is 145 bytes. But the second
time around this is only 113 bytes. The actual header is the same, but
the second time around the client can reference previously sent
values, reducing the transmitted data size.</p>
<p>HTTP/2 is undoubtedly harder to work with than HTTP/1.1, but much of
the friction will ease up as tooling matures. With first-class support
for HTTP/2, Wireshark makes debugging and understanding the protocol a
breeze.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>See also <a href="https://stackoverflow.com/questions/57064556/is-this-wireshark-capture-of-http-2-showing-three-frames">this StackOverflow discussion</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>HTTP/2: Header Compression With HPACK</title>
      <link>https://cadlag.org/posts/http2-header-compression-with-hpack/</link>
      <pubDate>Mon, 17 Feb 2025 07:13:40 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/http2-header-compression-with-hpack/</guid>
      <description>&lt;p&gt;HTTP/1.1 requests and response typically carry a&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/List_of_HTTP_header_fields&#34;&gt;header&lt;/a&gt;&#xA;which carries metadata about the HTTP message. The header contains&#xA;key-value pairs that appear right after the start line of the&#xA;message, but before the actual data. For example, the following&#xA;message (from the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages&#34;&gt;MDN&#xA;docs&lt;/a&gt;) has&#xA;a header with three entries:&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;POST /users HTTP/1.1&#xA;Host: example.com&#xA;Content-Type: application/x-www-form-urlencoded&#xA;Content-Length: 50&#xA;&#xA;name=FirstName%20LastName&amp;amp;email=bsmth%40example.com&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the above example, the header is larger than the actual body of the&#xA;request. Worse still, HTTP is stateless, so session metadata&#xA;(e.g. cookies) must be replicated for every request.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>HTTP/1.1 requests and response typically carry a
<a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields">header</a>
which carries metadata about the HTTP message. The header contains
key-value pairs that appear right after the start line of the
message, but before the actual data. For example, the following
message (from the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages">MDN
docs</a>) has
a header with three entries:</p>





<pre tabindex="0"><code>POST /users HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 50

name=FirstName%20LastName&amp;email=bsmth%40example.com</code></pre><p>In the above example, the header is larger than the actual body of the
request. Worse still, HTTP is stateless, so session metadata
(e.g. cookies) must be replicated for every request.</p>
<p>HTTP/2 improves upon this situation by introducing a header
compression format known as HPACK. Introduced in <a href="https://datatracker.ietf.org/doc/html/rfc7541">RFC
7541</a>, HPACK manages
key-value pairs through a shared table which can be updated during
the lifespan of a persistent HTTP/2 connection. A client can mark that
a key-value pair should be added to the table, and subsequently refer
to either the key or the key &amp; value by their index into this table.</p>
<p>HPACK provides a mechanism but leaves the compression strategy up to
the implementation (several flavors of <a href="https://en.wikipedia.org/wiki/Dictionary_coder">dictionary
coding</a> are
possible). The sender has full control over when and how the table is
managed; a receiver simply decodes messages according to the usage of
the sender.</p>
<p>To illustrate HPACK in action, we can step through an example given in
the
<a href="https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.3">appendix</a>
of RFC 7541. We&rsquo;ll skip some of the bitwise minutiae, instead just
following the high-level logic.</p>
<p>Suppose a client makes an initial request with the following headers:</p>





<pre tabindex="0"><code>:method: GET
:scheme: http
:path: /
:authority: www.example.com</code></pre><p>The first three key-value pairs are so common that rather than require
the client to introduce them explicitly, they correspond to entries
<code>2</code>, <code>6</code>, and <code>4</code> in a pre-defined <a href="https://datatracker.ietf.org/doc/html/rfc7541#appendix-A">static
table</a>. On
the wire they only require three bytes: <code>0x82</code> (<code>0x80</code> + offset <code>2</code>) for the first, <code>0x86</code>
for the second, and <code>0x84</code> for the third.</p>
<p>Things get interesting with the next pair, <code>:authority: www.example.com</code>. Here we have a very common header key that appears
in the static table (<code>:authority:</code> shows up with index 1), but the
value (<code>www.example.com</code>) is new to this connection. In such cases,
HPACK lets you refer to the key as a standalone entity and then
provide the value directly. On the wire this looks like <code>0x41</code> (&ldquo;just
the key with index 1&rdquo;), followed by <code>0x0f</code> (indicating the value is a
15 byte literal), followed by the byte values for <code>www.example.com</code>.</p>
<p>Taken together, the header for this first message takes 20 bytes to
represent with HPACK. Considering that the first <code>:method: GET</code>,
followed by a carriage return and line feed, is 14 bytes under
HTTP/1.1, I&rsquo;d say HPACK is pretty effective in this example.</p>
<p>The real power of HPACK comes from the fact that it provides for a
dynamic key-value table which persists across the lifetime of the HTTP
connection. Initially this table is empty, and after this first
request the dynamic table would have a single entry:</p>
<table>
  <thead>
      <tr>
          <th>Index</th>
          <th>Key</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>62</td>
          <td><code>:authority:</code></td>
          <td><code>www.example.com</code></td>
      </tr>
  </tbody>
</table>
<p>Note that the static table uses indices 1-61, so the dynamic table
starts at 62.</p>
<p>Suppose now the client makes a second request with the following header:</p>





<pre tabindex="0"><code>:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache</code></pre><p>As before, the first three entries are compressed as <code>0x82 86 84</code> due
to their presence in the static table. But now the <code>:authority www.example.com</code> pair is present with index 62, so the client can
refer to it with <code>0xbe</code> (this is <code>0x80 + 62</code>).</p>
<p>The last line, <code>cache-control: no-cache</code>, has a key that appears in
the static table (index 24) but a value that does not. So it is
represented as <code>0x58</code> (for the key) followed by <code>0x08</code> (designating an
eight character string literal) and then the actual encoding of the
string <code>no-cache</code>.</p>
<p>As we see, this entire header is represented in just 14 bytes under
HPACK. After it is sent the dynamic table has a new entry for
<code>cache-control: no-cache</code>. By convention, new entries are inserted at
the head of this table (shifting the other entries by 1):</p>
<table>
  <thead>
      <tr>
          <th>Index</th>
          <th>Key</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>62</td>
          <td><code>cache-control:</code></td>
          <td><code>no-cache</code></td>
      </tr>
      <tr>
          <td>63</td>
          <td><code>:authority:</code></td>
          <td><code>www.example.com</code></td>
      </tr>
  </tbody>
</table>
<p>The specification requires that the entire static+dynamic table have a
fixed size, to make decoding inexpensive. This is controllable via an
HTTP/2 parameter <code>SETTINGS_HEADER_TABLE_SIZE</code> which defaults
to 256. Concretely, this means that inserting new entries to the table
can cause old ones to roll off.</p>
<p>As you can see, HPACK provides a simple but effective mechanism for
header compression. A session cookie would only need to be sent once,
after which it would occupy a single entry in the dynamic table and
could be referred to by index. This keeps headers small, so that
network resources may be more efficiently be used by application data.</p>
]]></content:encoded>
    </item>
    <item>
      <title>HTTP with TLS 1.3</title>
      <link>https://cadlag.org/posts/https-with-tls-1-3/</link>
      <pubDate>Wed, 12 Feb 2025 20:55:09 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/https-with-tls-1-3/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://cadlag.org/posts/looking-at-an-http-1-1-session/&#34;&gt;Last time&lt;/a&gt; we looked&#xA;at a HTTP/1.1 request and response using Wireshark. Over the next few&#xA;posts I&amp;rsquo;m building towards a better understanding of&#xA;&lt;a href=&#34;https://grpc.io/&#34;&gt;gRPC&lt;/a&gt;. gRPC uses HTTP/2, which departs from&#xA;HTTP/1.1 in several ways. Before getting into those changes, let&amp;rsquo;s&#xA;look at how HTTP can be used for secure communication.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Transport_Layer_Security&#34;&gt;Transport Layer&#xA;Security&lt;/a&gt;, or&#xA;TLS for short, is an approach to security which sits just above TCP&#xA;(hence the name). At a high level, the protocol describes a way to&#xA;open an encrypted channel on top of an underlying TCP stream. An&#xA;initial handshake settles cryptographic conventions and identities,&#xA;after which encrypted application data is sent over ordinary TCP&#xA;segments.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="/posts/looking-at-an-http-1-1-session/">Last time</a> we looked
at a HTTP/1.1 request and response using Wireshark. Over the next few
posts I&rsquo;m building towards a better understanding of
<a href="https://grpc.io/">gRPC</a>. gRPC uses HTTP/2, which departs from
HTTP/1.1 in several ways. Before getting into those changes, let&rsquo;s
look at how HTTP can be used for secure communication.</p>
<p><a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">Transport Layer
Security</a>, or
TLS for short, is an approach to security which sits just above TCP
(hence the name). At a high level, the protocol describes a way to
open an encrypted channel on top of an underlying TCP stream. An
initial handshake settles cryptographic conventions and identities,
after which encrypted application data is sent over ordinary TCP
segments.</p>
<p>There are a lot of cryptographic details that can obscure the
high level structure of the protocol. To get a feel for how TLS works,
we can instead just try it out with an HTTP request (so-called
<a href="https://en.wikipedia.org/wiki/HTTPS">HTTPS</a>) and look at some of the
captured packets.</p>
<p>Last time, we used <code>cURL</code> to generate an HTTP request. Today, we&rsquo;ll use
Python. In the following code we use the <code>ssl</code> package to wrap an
ordinary TCP socket with TLS:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">socket</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">ssl</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">host</span> <span class="o">=</span> <span class="s1">&#39;google.com&#39;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">port</span> <span class="o">=</span> <span class="mi">443</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">context</span> <span class="o">=</span> <span class="n">ssl</span><span class="o">.</span><span class="n">create_default_context</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># Log TLS key information for use with Wireshark</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">context</span><span class="o">.</span><span class="n">keylog_filename</span> <span class="o">=</span>  <span class="s2">&#34;sslkeylog.log&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">with</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span> <span class="k">as</span> <span class="n">sock</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="k">with</span> <span class="n">context</span><span class="o">.</span><span class="n">wrap_socket</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">server_hostname</span><span class="o">=</span><span class="n">host</span><span class="p">)</span> <span class="k">as</span> <span class="n">ssock</span><span class="p">:</span>    
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="n">request</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="s2">&#34;GET / HTTP/1.1</span><span class="se">\r\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="sa">f</span><span class="s2">&#34;Host: </span><span class="si">{</span><span class="n">host</span><span class="si">}</span><span class="se">\r\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="s2">&#34;Connection: close</span><span class="se">\r\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="s2">&#34;</span><span class="se">\r\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="n">ssock</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;ascii&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="n">response_parts</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">            <span class="n">data</span> <span class="o">=</span> <span class="n">ssock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">4096</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">            <span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">                <span class="k">break</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">            <span class="n">response_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">            
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="n">ssock</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="n">response</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">response_parts</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s1">&#39;replace&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div><p>Note that in Python, we need an <code>SSLContext</code> in order to wrap a
socket. In the above code we explicitly indicate that the context
should save the session&rsquo;s TLS keys. We&rsquo;ll need these
to decrypt the packet contents in Wireshark.</p>
<p>After running the above and catching the packets, we see the following:</p>
<p><img src="/posts/https-with-tls-1-3/https_orig.png" alt="HTTPS Encrypted"></p>
<p>Although we can&rsquo;t follow every detail in this, we can at least
understand the shape of the interaction:</p>
<ol>
<li>There&rsquo;s an ordinary TCP connection establishment.</li>
<li>Then, some back and forth between the client and server to set up
the TLS session. Wireshark labels many of these packets with <code>TLSv1.3</code> as the protocol, and in some cases gives suggestive names like &ldquo;Server Hello, Change Cipher Spec&rdquo;.</li>
<li>There are a number of <code>TLSv1.3</code> segments that just get labeled &ldquo;Application Data&rdquo;. These are encrypted but presumably include the HTTP <code>GET</code> and response.</li>
<li>Finally, the TCP connection closes.</li>
</ol>
<p>To further inspect these packets we need the keys we recorded during our request. These are <a href="https://security.stackexchange.com/questions/222119/potential-risks-of-publicly-uploading-a-wireshark-trace-with-tls-related-informa">ephemeral to the session</a> so it&rsquo;s safe to share the contents of <code>sslkeylog.log </code>:</p>





<pre tabindex="0"><code># TLS secrets log file, generated by OpenSSL / Python
SERVER_HANDSHAKE_TRAFFIC_SECRET bb058323a16b445da4c69a211dd9fb3718a5574fef4a13e59a00c94eb46b5731 f431df302f018369fe4540bf3d148ea62faedeff5b518db06e6077267ca2807241c7934238702e288641759d473caaab
EXPORTER_SECRET bb058323a16b445da4c69a211dd9fb3718a5574fef4a13e59a00c94eb46b5731 b24fc91dddbe4c1fd5cd308d1cdd0db3c0dacfc3756ac9661d7c5a20d04a10c0759c55fcc3b8a38fa2793e191d7b8992
SERVER_TRAFFIC_SECRET_0 bb058323a16b445da4c69a211dd9fb3718a5574fef4a13e59a00c94eb46b5731 d8a62b42acffc95f5730618010de5cbdeec02c8d0e26a85d53da989e806cd6f0b297772b9c082bae2d2c86b6276848a6
CLIENT_HANDSHAKE_TRAFFIC_SECRET bb058323a16b445da4c69a211dd9fb3718a5574fef4a13e59a00c94eb46b5731 f58ff4ceb0cd5ff5dd668c7f6217896e17eb5a1b3a00a2af0a8a6118d0ab3bc57f9de4cf67a432285db4dcee7b43a1b9
CLIENT_TRAFFIC_SECRET_0 bb058323a16b445da4c69a211dd9fb3718a5574fef4a13e59a00c94eb46b5731 5312948edcc68e012acd1622c0f2191bb36b2ed1b26a4d76a7b6dd8df2a807239fcdae09da5e5581a5198bed25e4588e</code></pre><p>In Wireshark you can provide this file (<code>Preference -&gt; Protocols -&gt; TLS -&gt; (Pre)-Master-Secret log filename</code>) and then see something like this:</p>
<p><img src="/posts/https-with-tls-1-3/https_decrypted.png" alt="HTTPS Decrypted"></p>
<p>Here we see a few more details that weren&rsquo;t visible before:</p>
<ol>
<li>The HTTP request and response, as expected.</li>
<li>A <code>TLSv1.3</code> message to provide a &ldquo;New Session Ticket&rdquo;. This allows a client to resume this session in a future connection (e.g. reducing the cost of a handshake).</li>
</ol>
<p>This was just a quick &ldquo;anatomical exercise&rdquo;. I won&rsquo;t dwell too much on
TLS, but it&rsquo;s ubiquitous and so worth getting familiar
with. For a more detailed dive into how TLS drives the underlying TCP
connection, see <a href="https://tls13.xargs.org/">The Illustrated TLS 1.3
Connection</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Looking at an HTTP/1.1 Session</title>
      <link>https://cadlag.org/posts/looking-at-an-http-1-1-session/</link>
      <pubDate>Tue, 11 Feb 2025 17:33:30 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/looking-at-an-http-1-1-session/</guid>
      <description>&lt;p&gt;Our recent foray into TCP/IP led us to look at HTTP as a prime example&#xA;of an application layer protocol. Today I thought it would be fun to&#xA;look at an HTTP request/response interaction with&#xA;&lt;a href=&#34;https://www.wireshark.org/&#34;&gt;Wireshark&lt;/a&gt;. Let&amp;rsquo;s break it down step by&#xA;step and see exactly how HTTP/1.1 plays out over TCP.&lt;/p&gt;&#xA;&lt;p&gt;When I run:&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;curl -v http://google.com -H &lt;span class=&#34;s2&#34;&gt;&amp;#34;Connection: close&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I see the following:&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;* Host google.com:80 was resolved.&#xA;* IPv6: (none)&#xA;* IPv4: 142.250.72.174&#xA;*   Trying 142.250.72.174:80...&#xA;* Connected to google.com (142.250.72.174) port 80&#xA;&amp;gt; GET / HTTP/1.1&#xA;&amp;gt; Host: google.com&#xA;&amp;gt; User-Agent: curl/8.7.1&#xA;&amp;gt; Accept: */*&#xA;&amp;gt; Connection: close&#xA;&amp;gt; &#xA;* Request completely sent off&#xA;&amp;lt; HTTP/1.1 301 Moved Permanently&#xA;&amp;lt; Location: http://www.google.com/&#xA;&amp;lt; Content-Type: text/html; charset=UTF-8&#xA;&amp;lt; Content-Security-Policy-Report-Only: object-src &amp;#39;none&amp;#39;;base-uri &amp;#39;self&amp;#39;;script-src &amp;#39;nonce-EB7GxjMVJsa5Mr_7PWB0yA&amp;#39; &amp;#39;strict-dynamic&amp;#39; &amp;#39;report-sample&amp;#39; &amp;#39;unsafe-eval&amp;#39; &amp;#39;unsafe-inline&amp;#39; https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp&#xA;&amp;lt; Date: Wed, 12 Feb 2025 01:43:25 GMT&#xA;&amp;lt; Expires: Fri, 14 Mar 2025 01:43:25 GMT&#xA;&amp;lt; Cache-Control: public, max-age=2592000&#xA;&amp;lt; Server: gws&#xA;&amp;lt; Content-Length: 219&#xA;&amp;lt; X-XSS-Protection: 0&#xA;&amp;lt; X-Frame-Options: SAMEORIGIN&#xA;&amp;lt; Connection: close&#xA;&amp;lt; &#xA;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta http-equiv=&amp;#34;content-type&amp;#34; content=&amp;#34;text/html;charset=utf-8&amp;#34;&amp;gt;&#xA;&amp;lt;TITLE&amp;gt;301 Moved&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;&#xA;&amp;lt;H1&amp;gt;301 Moved&amp;lt;/H1&amp;gt;&#xA;The document has moved&#xA;&amp;lt;A HREF=&amp;#34;http://www.google.com/&amp;#34;&amp;gt;here&amp;lt;/A&amp;gt;.&#xA;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;&#xA;* Closing connection&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Looking at Wireshark, I see the following capture:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Our recent foray into TCP/IP led us to look at HTTP as a prime example
of an application layer protocol. Today I thought it would be fun to
look at an HTTP request/response interaction with
<a href="https://www.wireshark.org/">Wireshark</a>. Let&rsquo;s break it down step by
step and see exactly how HTTP/1.1 plays out over TCP.</p>
<p>When I run:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">curl -v http://google.com -H <span class="s2">&#34;Connection: close&#34;</span></span></span></code></pre></div><p>I see the following:</p>





<pre tabindex="0"><code>* Host google.com:80 was resolved.
* IPv6: (none)
* IPv4: 142.250.72.174
*   Trying 142.250.72.174:80...
* Connected to google.com (142.250.72.174) port 80
&gt; GET / HTTP/1.1
&gt; Host: google.com
&gt; User-Agent: curl/8.7.1
&gt; Accept: */*
&gt; Connection: close
&gt; 
* Request completely sent off
&lt; HTTP/1.1 301 Moved Permanently
&lt; Location: http://www.google.com/
&lt; Content-Type: text/html; charset=UTF-8
&lt; Content-Security-Policy-Report-Only: object-src &#39;none&#39;;base-uri &#39;self&#39;;script-src &#39;nonce-EB7GxjMVJsa5Mr_7PWB0yA&#39; &#39;strict-dynamic&#39; &#39;report-sample&#39; &#39;unsafe-eval&#39; &#39;unsafe-inline&#39; https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
&lt; Date: Wed, 12 Feb 2025 01:43:25 GMT
&lt; Expires: Fri, 14 Mar 2025 01:43:25 GMT
&lt; Cache-Control: public, max-age=2592000
&lt; Server: gws
&lt; Content-Length: 219
&lt; X-XSS-Protection: 0
&lt; X-Frame-Options: SAMEORIGIN
&lt; Connection: close
&lt; 
&lt;HTML&gt;&lt;HEAD&gt;&lt;meta http-equiv=&#34;content-type&#34; content=&#34;text/html;charset=utf-8&#34;&gt;
&lt;TITLE&gt;301 Moved&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY&gt;
&lt;H1&gt;301 Moved&lt;/H1&gt;
The document has moved
&lt;A HREF=&#34;http://www.google.com/&#34;&gt;here&lt;/A&gt;.
&lt;/BODY&gt;&lt;/HTML&gt;
* Closing connection</code></pre><p>Looking at Wireshark, I see the following capture:</p>
<p><img src="/posts/looking-at-an-http-1-1-session/wireshark_trace.png" alt="Wireshark Trace"></p>
<p>The first few segments set up the TCP connection. You can see the
&ldquo;three-way handshake&rdquo; in action:</p>
<p><img src="/posts/looking-at-an-http-1-1-session/tcp_connection.png" alt="TCP Connection Establishment"></p>
<p>With the TCP connection established we make the HTTP <code>GET</code>
request. The server acknowledges this <em>before</em> sending the response:</p>
<p><img src="/posts/looking-at-an-http-1-1-session/get_and_tcp_ack.png" alt="HTTP Get"></p>
<p>In principle, the server could bundle the above <code>ACK</code> with the actual
HTTP response, but doing so would introduce a delay if the response
isn&rsquo;t ready immediately. So it plays it safe: first, it sends an
<code>ACK</code>, then it responds to the request.</p>
<p>The next segment has the actual HTTP response, which we acknowledge:</p>
<p><img src="/posts/looking-at-an-http-1-1-session/http_response_and_ack.png" alt="HTTP Response"></p>
<p>Finally, the TCP connection is torn down. I ran this experiment twice,
and the next screenshot is from the second run, but the behavior and
relative sequence numbers are the same. I was expecting to see a
three-way handshake, but there are four segments here:</p>
<p><img src="/posts/looking-at-an-http-1-1-session/tcp_teardown.png" alt="TCP Teardown"></p>
<p>Recall that I asked curl to use the <code>Connection: close</code> header in my
request. This tells Google that it is free to close the connection
once it has served a response. What we see in the above screenshot is
that both sides of the TCP connection initiate a close
simultaneously. Because of this, each <code>FIN</code> is sent before receiving
the other&rsquo;s. Since a <code>FIN</code> gets its own sequence number, it requires a
separate <code>ACK</code>. So we need an extra acknowledgment to fully close
this connection.</p>
<p>The takeaway here is that we can see HTTP riding on TCP just by
sniffing packets. This gives a solid sanity check for what we have
already learned about these protocols.</p>
]]></content:encoded>
    </item>
    <item>
      <title>HTTP/0.9 and the World Wide Web</title>
      <link>https://cadlag.org/posts/http-and-the-world-wide-web/</link>
      <pubDate>Sun, 09 Feb 2025 12:04:50 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/http-and-the-world-wide-web/</guid>
      <description>&lt;p&gt;In the past few posts we have been looking at the syntax and semantics&#xA;of TCP. There is still much more to be said on the subject&#xA;(e.g. congestion control), but to really understand TCP in action we&#xA;need to also consider an application level protocol. Perhaps the most&#xA;widely used of these is the &lt;a href=&#34;https://en.wikipedia.org/wiki/HTTP&#34;&gt;Hypertext Transfer&#xA;Protocol&lt;/a&gt;, which was developed&#xA;alongside the &lt;a href=&#34;https://en.wikipedia.org/wiki/World_Wide_Web&#34;&gt;World Wide&#xA;Web&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The WWW was developed by Tim Berners-Lee and others at&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/CERN&#34;&gt;CERN&lt;/a&gt;. Tim describes the&#xA;motivation in a 1991 &lt;a href=&#34;https://www.w3.org/People/Berners-Lee/1991/08/art-6484.txt&#34;&gt;newsgroup announcement&lt;/a&gt;:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In the past few posts we have been looking at the syntax and semantics
of TCP. There is still much more to be said on the subject
(e.g. congestion control), but to really understand TCP in action we
need to also consider an application level protocol. Perhaps the most
widely used of these is the <a href="https://en.wikipedia.org/wiki/HTTP">Hypertext Transfer
Protocol</a>, which was developed
alongside the <a href="https://en.wikipedia.org/wiki/World_Wide_Web">World Wide
Web</a>.</p>
<p>The WWW was developed by Tim Berners-Lee and others at
<a href="https://en.wikipedia.org/wiki/CERN">CERN</a>. Tim describes the
motivation in a 1991 <a href="https://www.w3.org/People/Berners-Lee/1991/08/art-6484.txt">newsgroup announcement</a>:</p>
<blockquote>
<p>The WWW project was started to allow high energy physicists to share
data, news, and documentation.</p>
</blockquote>
<p>To turn the dream of the WWW into a reality, Berners-Lee had to develop
some key technologies:</p>
<ol>
<li>A textual format, HTML, for <em>hypertext documents</em>. These documents
include typesetting information as well as links to others.</li>
<li>A protocol, HTTP, to request and receive hypertext documents.</li>
<li>A server, which can host HTML files (or generate them on-the-fly).</li>
<li>A client, the earliest web browser, which can request and display
HTML.</li>
</ol>
<p>The earliest public version of HTTP is <a href="https://www.w3.org/Protocols/HTTP/AsImplemented.html">version
0.9</a>. This is an
extremely simple application protocol running on top of TCP. It
defines a single type of request made by a client: get an HTML
document at a given address. The server responds with the contents of
the HTML document, and then closes the connection. If there is an
error it is reported as a human-readable HTML message.</p>
<p>Even without a web browser, a person could manually issue a <code>GET</code>
request directly in ASCII text using a <code>telnet</code> client. No doubt this
ease of use helped drive early adoption. Over the next few years, HTTP
incorporated additional features, including new request types and
headers for communicating additional metadata. In 1996, the HTTP/1.0
specification was proposed in <a href="https://datatracker.ietf.org/doc/html/rfc1945">RFC
1945</a>. If you&rsquo;re
curious about the evolution of HTTP, I highly recommend <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Evolution_of_HTTP">this
article</a>
from the Mozilla developer documentation.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A look at the TCP segment format</title>
      <link>https://cadlag.org/posts/tcp-segment-format/</link>
      <pubDate>Sat, 08 Feb 2025 10:45:32 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/tcp-segment-format/</guid>
      <description>&lt;p&gt;TCP provides a reliable stream abstraction on top of the underlying IP&#xA;layer. Although an application &lt;a href=&#34;https://cadlag.org/posts/sockets-and-tcp-connections/&#34;&gt;interacts with&lt;/a&gt; TCP as if it were a stream&#xA;of individual bytes, a TCP implementation packages a sequence of bytes&#xA;together into what is known as a &lt;em&gt;TCP segment&lt;/em&gt;. A segment has a TCP&#xA;header, for the protocol to operate, and data, from the driving&#xA;application. Like those &lt;a href=&#34;https://en.wikipedia.org/wiki/Matryoshka_doll&#34;&gt;Russian&#xA;dolls&lt;/a&gt;, TCP segments&#xA;are then used as the &lt;em&gt;data&lt;/em&gt; of an IP packet, so that segments can be&#xA;routed from the source to destination.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>TCP provides a reliable stream abstraction on top of the underlying IP
layer. Although an application <a href="/posts/sockets-and-tcp-connections/">interacts with</a> TCP as if it were a stream
of individual bytes, a TCP implementation packages a sequence of bytes
together into what is known as a <em>TCP segment</em>. A segment has a TCP
header, for the protocol to operate, and data, from the driving
application. Like those <a href="https://en.wikipedia.org/wiki/Matryoshka_doll">Russian
dolls</a>, TCP segments
are then used as the <em>data</em> of an IP packet, so that segments can be
routed from the source to destination.</p>
<p><a href="https://datatracker.ietf.org/doc/rfc793/">RFC 793</a> provides a diagram
of the TCP segment format, which I&rsquo;ve reproduced below:</p>





<pre tabindex="0"><code>    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                            TCP Header Format

          Note that one tick mark represents one bit position.

                               Figure 3.</code></pre><p>To better understand what TCP offers, let&rsquo;s contrast it with UDP, a
much simpler protocol. <a href="https://datatracker.ietf.org/doc/rfc768/">RFC 768</a> provides an analogous
diagram for the UDP header:</p>





<pre tabindex="0"><code>                  0      7 8     15 16    23 24    31  
                 +--------+--------+--------+--------+ 
                 |     Source      |   Destination   | 
                 |      Port       |      Port       | 
                 +--------+--------+--------+--------+ 
                 |                 |                 | 
                 |     Length      |    Checksum     | 
                 +--------+--------+--------+--------+ 
                 |                                     
                 |          data octets ...            
                 +---------------- ...                 

                      User Datagram Header Format</code></pre><p>There are a few features common to both:</p>
<ul>
<li>Ports are used for multiplexing. This lets applications address specific processes rather than just hosts.</li>
<li><a href="https://en.wikipedia.org/wiki/Checksum">Checksums</a> are used to
detect corruption of individual segments/datagrams.</li>
</ul>
<p>That&rsquo;s about it! Let&rsquo;s look at a few of the differences:</p>
<ul>
<li>The TCP header has a variable length, depending on whether options are used. Because of this, it needs a <code>Data Offset</code> field to indicate where the data actually starts.</li>
<li>Unlike TCP, UDP explicitly includes a <code>Length</code> field to indicate the
total size of the datagram. TCP does not require this field because
the length can be inferred from the enclosing IP packet&rsquo;s size. One
<a href="https://stackoverflow.com/questions/41394281/why-udp-header-has-length-field">possible
reason</a>
for UDP&rsquo;s design choice is that it comes from a time when
alternatives to IP were still being considered. Additionally,
including <code>Length</code> ensures that the UDP header has 4-byte alignment.</li>
<li>TCP provides a reliable byte stream by explicitly communicating the
position in this stream for data being sent (the <code>Sequence Number</code>). Since TCP is bi-directional, a segment also indicates the
next byte expected by it sender (the <code>Acknowledgement Number</code>). The
sequence number increases as data is sent, and the acknowledgement
number increases as data is successfully received. If sent data is
not acknowledged, TCP can re-send this data.</li>
<li>To prevent scenarios where a sender is overwhelming a receiver with
more data than it can keep up with, TCP provides a notion of <a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Flow_control">flow
control</a>. This
relies on the protocol managing an interval of sequence numbers,
known as a <a href="https://en.wikipedia.org/wiki/Sliding_window_protocol">&ldquo;sliding
window&rdquo;</a>. The
window defines what sequence numbers the sender is allowed to send,
and this window advances as earlier sequence numbers get
acknowledged. Instead of using a fixed window size, the TCP
specification allows for the receiver to set the size with the
<code>Window</code> field of the header.</li>
<li>The TCP header has various flags that can be used for things like
establishing or closing a connection.</li>
<li>The <code>Urgent Pointer</code>. In principle, when the <code>Urgent</code> flag is set,
this field indicates an offset into the TCP segment&rsquo;s data where the
bytes are considered &ldquo;urgent&rdquo;. It&rsquo;s not obvious from the RFC how
this is used in practice.</li>
</ul>
<p>This comparison offers an additional perspective on TCP that
complements my previous discussion about the TCP <a href="/posts/sockets-and-tcp-connections/">state machine and
sequence diagrams</a>. While the state machine and sequence diagrams define TCP&rsquo;s
<em>semantics</em>, the segment format defines TCP&rsquo;s <em>syntax</em>. To fully
understand TCP, you need both.</p>
]]></content:encoded>
    </item>
    <item>
      <title>State Machines and Sequence Diagrams</title>
      <link>https://cadlag.org/posts/state-machines-and-sequence-diagrams/</link>
      <pubDate>Wed, 05 Feb 2025 15:53:59 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/state-machines-and-sequence-diagrams/</guid>
      <description>&lt;p&gt;While reading the TCP specification in &lt;a href=&#34;https://datatracker.ietf.org/doc/rfc793/&#34;&gt;RFC&#xA;793&lt;/a&gt;, it struck me how&#xA;important diagrammatic reasoning is in understanding such protocols.&lt;/p&gt;&#xA;&lt;p&gt;Broadly speaking, a protocol is a set of rules describing how entities&#xA;(e.g. people, machines, processes) interact in a given system. Almost&#xA;inevitably these rules depend on whether certain circumstances are&#xA;met, and typically the entire protocol can be described as a &lt;a href=&#34;https://en.wikipedia.org/wiki/Finite-state_machine&#34;&gt;state&#xA;machine&lt;/a&gt; where&#xA;transitions are triggered by events and themselves imply certain&#xA;actions (e.g. starting a timer).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>While reading the TCP specification in <a href="https://datatracker.ietf.org/doc/rfc793/">RFC
793</a>, it struck me how
important diagrammatic reasoning is in understanding such protocols.</p>
<p>Broadly speaking, a protocol is a set of rules describing how entities
(e.g. people, machines, processes) interact in a given system. Almost
inevitably these rules depend on whether certain circumstances are
met, and typically the entire protocol can be described as a <a href="https://en.wikipedia.org/wiki/Finite-state_machine">state
machine</a> where
transitions are triggered by events and themselves imply certain
actions (e.g. starting a timer).</p>
<p>There are many ways to describe such a state machine, but one of these
most legible approaches is through a graphical diagram, where states
are vertices and transitions are edges. These edges are labeled with a
precondition (which must be met for the transition to occur) and an
action (performed as part of the transition). For example, the TCP
specification describes the connection state machine and summarizes it
with a diagram. This is a full page of ASCII art &ndash; feast your eyes:</p>





<pre tabindex="0"><code>September 1981                                                          
                                           Transmission Control Protocol
                                                Functional Specification

                                    
                              +---------+ ---------\      active OPEN  
                              |  CLOSED |            \    -----------  
                              +---------+&lt;---------\   \   create TCB  
                                |     ^              \   \  snd SYN    
                   passive OPEN |     |   CLOSE        \   \           
                   ------------ |     | ----------       \   \         
                    create TCB  |     | delete TCB         \   \       
                                V     |                      \   \     
                              +---------+            CLOSE    |    \   
                              |  LISTEN |          ---------- |     |  
                              +---------+          delete TCB |     |  
                   rcv SYN      |     |     SEND              |     |  
                  -----------   |     |    -------            |     V  
 +---------+      snd SYN,ACK  /       \   snd SYN          +---------+
 |         |&lt;-----------------           ------------------&gt;|         |
 |   SYN   |                    rcv SYN                     |   SYN   |
 |   RCVD  |&lt;-----------------------------------------------|   SENT  |
 |         |                    snd ACK                     |         |
 |         |------------------           -------------------|         |
 +---------+   rcv ACK of SYN  \       /  rcv SYN,ACK       +---------+
   |           --------------   |     |   -----------                  
   |                  x         |     |     snd ACK                    
   |                            V     V                                
   |  CLOSE                   +---------+                              
   | -------                  |  ESTAB  |                              
   | snd FIN                  +---------+                              
   |                   CLOSE    |     |    rcv FIN                     
   V                  -------   |     |    -------                     
 +---------+          snd FIN  /       \   snd ACK          +---------+
 |  FIN    |&lt;-----------------           ------------------&gt;|  CLOSE  |
 | WAIT-1  |------------------                              |   WAIT  |
 +---------+          rcv FIN  \                            +---------+
   | rcv ACK of FIN   -------   |                            CLOSE  |  
   | --------------   snd ACK   |                           ------- |  
   V        x                   V                           snd FIN V  
 +---------+                  +---------+                   +---------+
 |FINWAIT-2|                  | CLOSING |                   | LAST-ACK|
 +---------+                  +---------+                   +---------+
   |                rcv ACK of FIN |                 rcv ACK of FIN |  
   |  rcv FIN       -------------- |    Timeout=2MSL -------------- |  
   |  -------              x       V    ------------        x       V  
    \ snd ACK                 +---------+delete TCB         +---------+
     ------------------------&gt;|TIME WAIT|------------------&gt;| CLOSED  |
                              +---------+                   +---------+

                      TCP Connection State Diagram
                               Figure 6.

                                                               [Page 23]</code></pre><p>For all of its complexity, this diagram gives a single page summary of
what would otherwise take many pages to describe in words. One analogy
that comes to mind is with the <a href="https://en.wikipedia.org/wiki/Configuration_space_%28physics%29">configuration
space</a> of
a physical system. The state diagram provides a complete map of
possible states: at any given moment, a TCP implementation must be in
one of these states.</p>
<p>If state diagrams summarize the structure of a system, <a href="https://en.wikipedia.org/wiki/Sequence_diagram">sequence
diagrams</a> reveal its
evolution over time. Typically these show how several actors, each
running their own version of the state machine, interact via
messages. TCP has several such diagrams in the specification. For
example, on pg. 31 there is the following diagram for the &ldquo;3-way
handshake&rdquo; used to establish a connection:</p>





<pre tabindex="0"><code>      TCP A                                                TCP B

  1.  CLOSED                                               LISTEN

  2.  SYN-SENT    --&gt; &lt;SEQ=100&gt;&lt;CTL=SYN&gt;               --&gt; SYN-RECEIVED

  3.  ESTABLISHED &lt;-- &lt;SEQ=300&gt;&lt;ACK=101&gt;&lt;CTL=SYN,ACK&gt;  &lt;-- SYN-RECEIVED

  4.  ESTABLISHED --&gt; &lt;SEQ=101&gt;&lt;ACK=301&gt;&lt;CTL=ACK&gt;       --&gt; ESTABLISHED

  5.  ESTABLISHED --&gt; &lt;SEQ=101&gt;&lt;ACK=301&gt;&lt;CTL=ACK&gt;&lt;DATA&gt; --&gt; ESTABLISHED

          Basic 3-Way Handshake for Connection Synchronization

                                Figure 7.          </code></pre><p>Here we have two hosts running TCP, and hence each in their own TCP
state. As time progresses from top to bottom, these hosts communicate
with TCP messages and advance from state to state. The first host, TCP
A, goes from <code>CLOSED</code> to <code>SYN-SENT</code> to <code>ESTABLISHED</code>, while the second
host, TCP B, goes from <code>LISTEN</code> to <code>SYN-RECEIVED</code> to
<code>ESTABLISHED</code>. Although this scenario was latent in the state diagram
itself, it&rsquo;s much more legible in a sequence diagram.</p>
<p>Whether it visually or in text, defining a protocol involves
describing a state machine and explaining the sequences it can
produce. While the above examples are presented informally, one can
imagine formalizing such diagrams to prove the mathematical
correctness of a protocol<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. But that&rsquo;s a discussion for another
time.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Here I am imagining that the protocol itself is formalized as a
state machine in some specification language. A correctness proof
would establish that certain properties hold for all sequence diagrams
generated by this state machine.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Sockets and TCP Connections</title>
      <link>https://cadlag.org/posts/sockets-and-tcp-connections/</link>
      <pubDate>Sun, 02 Feb 2025 11:13:04 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/sockets-and-tcp-connections/</guid>
      <description>&lt;p&gt;Last time I wrote about &lt;a href=&#34;https://cadlag.org/posts/user-datagram-protocol/&#34;&gt;UDP&lt;/a&gt;, a simple but unreliable&#xA;abstraction over IP. For reliable data transfer, the key protocol is&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Transmission_Control_Protocol&#34;&gt;TCP&lt;/a&gt;. However,&#xA;this reliability comes at a cost: TCP is significantly more complicated than UDP.&lt;/p&gt;&#xA;&lt;p&gt;Rather than slog through &lt;a href=&#34;https://datatracker.ietf.org/doc/rfc793/&#34;&gt;RFC&#xA;793&lt;/a&gt;, we can start by&#xA;looking at Python&amp;rsquo;s&#xA;&lt;a href=&#34;https://docs.python.org/3/library/socket.html&#34;&gt;socket&lt;/a&gt; library. This&#xA;is just a Pythonic wrapper around &lt;a href=&#34;https://en.wikipedia.org/wiki/Berkeley_sockets&#34;&gt;BSD&#xA;sockets&lt;/a&gt;. These allow&#xA;you to interact with network interfaces more-or-less as if they were&#xA;files (e.g. with &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;write&lt;/code&gt;, or their counterparts &lt;code&gt;recv&lt;/code&gt; and&#xA;&lt;code&gt;send&lt;/code&gt;).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Last time I wrote about <a href="/posts/user-datagram-protocol/">UDP</a>, a simple but unreliable
abstraction over IP. For reliable data transfer, the key protocol is
<a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol">TCP</a>. However,
this reliability comes at a cost: TCP is significantly more complicated than UDP.</p>
<p>Rather than slog through <a href="https://datatracker.ietf.org/doc/rfc793/">RFC
793</a>, we can start by
looking at Python&rsquo;s
<a href="https://docs.python.org/3/library/socket.html">socket</a> library. This
is just a Pythonic wrapper around <a href="https://en.wikipedia.org/wiki/Berkeley_sockets">BSD
sockets</a>. These allow
you to interact with network interfaces more-or-less as if they were
files (e.g. with <code>read</code> and <code>write</code>, or their counterparts <code>recv</code> and
<code>send</code>).</p>
<p>It&rsquo;s pretty easy to write a simple UDP server in Python, and since
there are many tutorials available on the web I will be brief in
description. In the following example, the server accepts messages and
then echoes them back to the sender:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">socket</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">def</span> <span class="nf">udp_server</span><span class="p">(</span><span class="n">host</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_DGRAM</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">bind</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="n">msg</span><span class="p">,</span> <span class="n">client</span> <span class="o">=</span> <span class="n">sock</span><span class="o">.</span><span class="n">recvfrom</span><span class="p">(</span><span class="mi">2048</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">        <span class="n">sock</span><span class="o">.</span><span class="n">sendto</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span></span></span></code></pre></div><p>You can tell that this is UDP because the socket type is
<code>SOCK_DGRAM</code>. A toy client might look like the following:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">udp_client</span><span class="p">(</span><span class="n">addr</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">dest</span> <span class="o">=</span> <span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_DGRAM</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">msg</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s1">&#39;Please enter a message: &#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">sendto</span><span class="p">(</span><span class="n">msg</span><span class="o">.</span><span class="n">encode</span><span class="p">(),</span> <span class="n">dest</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">response</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">sock</span><span class="o">.</span><span class="n">recvfrom</span><span class="p">(</span><span class="mi">2048</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span></span></span></code></pre></div><p>All this does is get a message from the user, send it to the server,
and then print out the response.</p>
<p>When we move to TCP, things get a bit more complicated. A similar
server (but now with type <code>SOCK_STREAM</code>) requires a bit more set-up:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">tcp_server</span><span class="p">(</span><span class="n">host</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">listener</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="n">listener</span><span class="o">.</span><span class="n">bind</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">listener</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="n">conn</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">listener</span><span class="o">.</span><span class="n">accept</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="n">msg</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">2048</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">        <span class="n">conn</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl">        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span></span></span></code></pre></div><p>Here we have a <code>listener</code> socket which is bound to the given <code>(host, port)</code> pair. It then notifies the operating system that it is ready to
<code>listen</code> for incoming connections.</p>
<p>The TCP client now has to explicitly <code>connect</code>, as shown below:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">tcp_client</span><span class="p">(</span><span class="n">addr</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">dest</span> <span class="o">=</span> <span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dest</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="n">msg</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s1">&#39;Please enter a message: &#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">msg</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">2048</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span></span></span></code></pre></div><p>On the server side, the <code>accept</code> call responds to the client&rsquo;s
<code>connect</code>. This also produces a <em>new</em> socket (<code>conn</code> above),
dedicated to that specific connection. This is a lot more
complicated than the UDP counterpart &ndash; what&rsquo;s going on here?</p>
<p>This <code>connect/accept</code> logic handles the TCP <a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment">connection
establishment</a>. The
first TCP segment (roughly, the TCP equivalent of a packet) sent from
the client to the server has a special flag in the header to indicate
that it wants a connection. This segment is sent to <code>listener</code>. Under
the hood, there is a brief back-and-forth with the client (this is the
&ldquo;three way handshake&rdquo; described in the Wikipedia article). After that,
the <code>accept</code> call on the server returns a new socket. Subsequent TCP
segments to and from the client carry normal data, and use this second
socket.</p>
<p>Notice also that in the code above, the TCP server could have multiple
connections (and so multiple sockets) associated with the same
port. What we see here is TCP multiplexing. It can be helpful to
contrast with UDP. When a UDP datagram arrives at a host, it is routed
to the appropriate socket simply by looking at the pair <code>(dest addr, dest port)</code>. This means that for a given UDP port, all incoming
packets are routed to the same socket, regardless of sender. With TCP,
each connection is uniquely identified by the tuple <code>(source addr, source port, dest addr, dest port)</code>. This allows multiple connections
on the same destination port, as long as they originate from different
sources. But because the <code>listener</code> handles the communication before
the TCP connection is established, we can only <code>bind</code> one socket to a
given <code>(dest adddr, dest port)</code> pair.</p>
<p>Anyways, this post is something of a teaser &ndash; there&rsquo;s still a lot
more to say about TCP. Next time we&rsquo;ll break down the structure of a
TCP segment and explore how sequence numbers and acknowledgements are
used to ensure reliable communication.</p>
]]></content:encoded>
    </item>
    <item>
      <title>User Datagram Protocol</title>
      <link>https://cadlag.org/posts/user-datagram-protocol/</link>
      <pubDate>Fri, 31 Jan 2025 08:26:13 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/user-datagram-protocol/</guid>
      <description>&lt;p&gt;Next stop in my whirlwind tour of various networking protocols is &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc0768&#34;&gt;UDP&#xA;(RFC 768)&lt;/a&gt;. The spec is&#xA;only two pages so this post is going to be brief.&lt;/p&gt;&#xA;&lt;p&gt;Whereas IP operates at the &amp;ldquo;network layer&amp;rdquo;, UDP sits at the &amp;ldquo;transport&#xA;layer&amp;rdquo;. Really, UDP adds just one key feature on top of the&#xA;basic IP datagram model: &lt;em&gt;ports&lt;/em&gt;. A port lets you distinguish between&#xA;multiple services behind a single network interface. This distinction&#xA;is not important for routing across the network, but it&amp;rsquo;s a practical&#xA;necessity.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Next stop in my whirlwind tour of various networking protocols is <a href="https://datatracker.ietf.org/doc/html/rfc0768">UDP
(RFC 768)</a>. The spec is
only two pages so this post is going to be brief.</p>
<p>Whereas IP operates at the &ldquo;network layer&rdquo;, UDP sits at the &ldquo;transport
layer&rdquo;. Really, UDP adds just one key feature on top of the
basic IP datagram model: <em>ports</em>. A port lets you distinguish between
multiple services behind a single network interface. This distinction
is not important for routing across the network, but it&rsquo;s a practical
necessity.</p>
<p>The <a href="https://gaia.cs.umass.edu/kurose_ross/eighth.php">Kurose and
Ross</a> analogy is
roughly this: think of hosts as households and these services as
people. IP is like the postal service, delivering letters to a
specific address. The port is the name of the intended recipient, but
it&rsquo;s up to whoever checks the mail (roughly &ldquo;the operating system&rdquo;)
to deliver this.</p>
<p>That&rsquo;s it for today. Next time, we&rsquo;ll start looking at bigger
problems that the transport layer solves.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Internet Control Messaging Protocol</title>
      <link>https://cadlag.org/posts/internet-control-messaging-protocol/</link>
      <pubDate>Thu, 30 Jan 2025 19:32:18 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/internet-control-messaging-protocol/</guid>
      <description>&lt;p&gt;Yesterday I wrote about &lt;a href=&#34;https://cadlag.org/posts/reading-the-rfc-internet-protocol/&#34;&gt;RFC 791&lt;/a&gt;, but I didn&amp;rsquo;t&#xA;mention how errors get handled or reported.&lt;/p&gt;&#xA;&lt;p&gt;Any conforming implementation of Internet Protocol must support its&#xA;companion, the Internet Control Message Protocol. Defined in &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc792&#34;&gt;RFC&#xA;792&lt;/a&gt;, ICMP provides a&#xA;very lightweight mechanism for error reporting.&lt;/p&gt;&#xA;&lt;p&gt;In essence, ICMP defines messages that are sent back to the source of&#xA;a packet that fails delivery. These messages use the standard IP header&#xA;format but contain specific data fields that define their purpose. The&#xA;spec describes a dozen or so message types, but several of these have&#xA;been deprecated. Some of the most notable types in active use are:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Yesterday I wrote about <a href="/posts/reading-the-rfc-internet-protocol/">RFC 791</a>, but I didn&rsquo;t
mention how errors get handled or reported.</p>
<p>Any conforming implementation of Internet Protocol must support its
companion, the Internet Control Message Protocol. Defined in <a href="https://datatracker.ietf.org/doc/html/rfc792">RFC
792</a>, ICMP provides a
very lightweight mechanism for error reporting.</p>
<p>In essence, ICMP defines messages that are sent back to the source of
a packet that fails delivery. These messages use the standard IP header
format but contain specific data fields that define their purpose. The
spec describes a dozen or so message types, but several of these have
been deprecated. Some of the most notable types in active use are:</p>
<ol>
<li><strong>Destination Unreachable (Type 3)</strong>: Sent when a packet cannot reach its destination.</li>
<li><strong>Echo Request (Type 8)</strong> and <strong>Echo Reply (Type 0)</strong>: Used by tools like <code>ping</code> to check network
connectivity.</li>
<li><strong>Time Exceeded (Type 11)</strong>: Indicates that the packet time-to-live (TTL)
has expired.</li>
</ol>
<p>A good example of how the Time Exceeded message can be used is
<code>traceroute</code>, which sends packets with successively increasing TTL
values in order to probe the route(s) taken to a host. For example,
when I run:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="ln">1</span><span class="cl">traceroute 8.8.8.8</span></span></code></pre></div><p>I get the following output:</p>





<pre tabindex="0"><code>traceroute to 8.8.8.8 (8.8.8.8), 64 hops max, 40 byte packets
 1  192.168.1.1 (192.168.1.1)  5.796 ms  4.522 ms  6.533 ms
 2  * * *
 3  lag-62-10.dtr02psdnca.netops.charter.com (96.34.102.37)  13.634 ms  13.846 ms  11.718 ms
 4  lag-30.crr03rvsdca.netops.charter.com (96.34.97.154)  18.296 ms  19.656 ms  26.183 ms
 5  lag-811.bbr01rvsdca.netops.charter.com (96.34.3.18)  15.703 ms  19.682 ms  16.463 ms
 6  lag-801.prr01lsanca.netops.charter.com (96.34.3.129)  16.699 ms  19.619 ms  16.894 ms
 7  sar02sghlga-eth-2-1.sghl.ga.charter.com (96.34.1.69)  18.305 ms
    72.14.219.250 (72.14.219.250)  17.759 ms  17.314 ms
 8  * * *
 9  dns.google (8.8.8.8)  20.087 ms  19.610 ms  17.278 ms</code></pre><p>Here I see various intermediate nodes from my ISP all the way to
Google&rsquo;s DNS server. The asterisks here mean that there was no
response. These nodes likely limit or disable ICMP responses.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Reading the RFC: Internet Protocol</title>
      <link>https://cadlag.org/posts/reading-the-rfc-internet-protocol/</link>
      <pubDate>Wed, 29 Jan 2025 20:19:18 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/reading-the-rfc-internet-protocol/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m going to be interviewing some network engineers in the near&#xA;future, so now is the time for me to brush up on the basics. Rather&#xA;than take the &amp;ldquo;shortest path&amp;rdquo; I decided it might be fun to read &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc791&#34;&gt;RFC&#xA;791&lt;/a&gt; &amp;ndash; and what a classic&#xA;this is.&lt;/p&gt;&#xA;&lt;p&gt;Why has IP stood the test of time? My guess is that there are a few&#xA;factors.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;As mentioned in the preface, RFC 791 is actually based on six&#xA;earlier versions of the ARPA Internet Protocol. So this is not&#xA;creation &lt;em&gt;ex nihilo&lt;/em&gt; but rather incremental refinement of some&#xA;underlying ideas.&lt;/li&gt;&#xA;&lt;li&gt;IP solves one problem and it solves it well. The authors are intentionally restrained, stating&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The internet protocol is specifically limited in scope to provide the functions necessary to deliver a package of bits (an internet datagram) from a source to a destination over an interconnected system of networks.  There are no mechanisms to augment end-to-end data reliability, flow control, sequencing, or other services commonly found in host-to-host protocols.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;m going to be interviewing some network engineers in the near
future, so now is the time for me to brush up on the basics. Rather
than take the &ldquo;shortest path&rdquo; I decided it might be fun to read <a href="https://datatracker.ietf.org/doc/html/rfc791">RFC
791</a> &ndash; and what a classic
this is.</p>
<p>Why has IP stood the test of time? My guess is that there are a few
factors.</p>
<ol>
<li>As mentioned in the preface, RFC 791 is actually based on six
earlier versions of the ARPA Internet Protocol. So this is not
creation <em>ex nihilo</em> but rather incremental refinement of some
underlying ideas.</li>
<li>IP solves one problem and it solves it well. The authors are intentionally restrained, stating</li>
</ol>
<blockquote>
<p>The internet protocol is specifically limited in scope to provide the functions necessary to deliver a package of bits (an internet datagram) from a source to a destination over an interconnected system of networks.  There are no mechanisms to augment end-to-end data reliability, flow control, sequencing, or other services commonly found in host-to-host protocols.</p>
</blockquote>
<ol start="3">
<li>The &ldquo;user interface&rdquo; (i.e. the part of this protocol that systems
programmers might interact with) is exceedingly simple. Although
the details are OS dependent, this basically amounts to a pair of
subroutines, <code>send</code> and <code>receive</code>.</li>
</ol>
<p>With that said, the protocol still has more complexity than I
expected. One challenge IP had to address is packet size differences
across networks. Although the specification allows for packets up to
65kB, it only requires implementations to support packets as small as
68 bytes (60 bytes for the header and 8 for the data). This kind of
flexibility was probably necessary, and to accommodate it IP supports
something called <em>fragmentation</em>. Basically, IP describes how to break
up or reassemble packets.</p>
<p>Fragmentation introduces significant complexity. The header has fields
indicating how a fragment relates to its original packet. When a
packet is fragmented, some fields of the original will copy to the
first fragment but not the rest. Since IP uses checksums for error
detection, fragmentation requires recomputing these. And there&rsquo;s a
whole page of the RFC detailing the complex (relative to the rest of
the document) assembly procedure to recover a packet from its
fragments.</p>
<p>In short, fragmentation is an engineering compromise to cope with
networking realities of the time. The consensus seems to be that
fragmentation is <a href="https://dl.acm.org/doi/10.1145/205447.205456">considered
harmful</a>, since if any
of the fragments get dropped then the whole packet gets dropped. These
days it looks like people try to avoid sending packets that exceed the
maximum transmission unit (MTU) along the path, cf <a href="https://datatracker.ietf.org/doc/html/rfc1191">RFC
1191</a> and <a href="https://datatracker.ietf.org/doc/html/rfc8899">RFC
8899</a>.</p>
<p>Anyways, I&rsquo;ve said enough about fragmentation. To close this entry out, here&rsquo;s something I didn&rsquo;t know: the IP header has a 16 bit
field for representation the security level of the packet, ranging
from &lsquo;Unclassified&rsquo; to &lsquo;Top Secret&rsquo;. There are eight additional levels
reserved for future use &ndash; or so they claim&hellip;.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Rebooting the Blog</title>
      <link>https://cadlag.org/posts/rebooting-the-blog/</link>
      <pubDate>Sat, 25 Jan 2025 19:01:05 -0800</pubDate><author>erik&#43;blog@cadlag.org (Erik Davis)</author>
      <guid>https://cadlag.org/posts/rebooting-the-blog/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s been a few years since my last blog post, but I find myself&#xA;wanting to write again. Despite my previous attempts at blogging, I&#xA;never settled into a regular habit. So I&amp;rsquo;ve decided to reboot this&#xA;blog, with a goal: to write more, and more often.&lt;/p&gt;&#xA;&lt;p&gt;There are really two things I hope to get out of this effort. The&#xA;first is to take seriously the idea of&#xA;&lt;a href=&#34;https://news.ycombinator.com/item?id=37118883&#34;&gt;writing-as-learning&lt;/a&gt;. In&#xA;my present stage of life, with my workdays sliced as thin as salami&#xA;and my home life focused on keeping up with a small child, I simply&#xA;don&amp;rsquo;t have as much time to think deeply about things as I used to. I&#xA;miss that. My hope is that by developing a writing habit, I can better&#xA;leverage the time I do have. Gone are the days of spending a weekend&#xA;hacking on a personal project or digesting a complex mathematical&#xA;argument. But I can find an hour here and there to write.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>It&rsquo;s been a few years since my last blog post, but I find myself
wanting to write again. Despite my previous attempts at blogging, I
never settled into a regular habit. So I&rsquo;ve decided to reboot this
blog, with a goal: to write more, and more often.</p>
<p>There are really two things I hope to get out of this effort. The
first is to take seriously the idea of
<a href="https://news.ycombinator.com/item?id=37118883">writing-as-learning</a>. In
my present stage of life, with my workdays sliced as thin as salami
and my home life focused on keeping up with a small child, I simply
don&rsquo;t have as much time to think deeply about things as I used to. I
miss that. My hope is that by developing a writing habit, I can better
leverage the time I do have. Gone are the days of spending a weekend
hacking on a personal project or digesting a complex mathematical
argument. But I can find an hour here and there to write.</p>
<p>The second thing I hope to achieve is to change how I relate to the
broader internet. When I first experienced the internet in the late
90s, it felt like such a strange and wonderful place. Part of this was
the novelty of it, but the early internet was also fundamentally open
and personal. Although the internet of today is a much larger and, in
some ways, more connected than ever, I&rsquo;ve nonetheless grown
increasingly disenchanted. These days, I mostly engage with the
internet passively &ndash; &lsquo;consuming content&rsquo; through a handful of link
aggregators or social media sites. While I don&rsquo;t expect to rekindle
the original magic of the internet, blogging feels like a meaningful
way to re-engage as an active participant.</p>
<p>I don&rsquo;t know exactly what this blog will turn into, but I&rsquo;m making a
personal commitment: over the next year, I aim to write roughly one
&rsquo;long form&rsquo; post a month. I&rsquo;ll also aim to share shorter, less
polished, posts more frequently.</p>
<p>Finally, I’ve switched from Hakyll to Hugo for this site. Hugo isn&rsquo;t
perfect, but tinkering with my old setup feels like too much
work right now. (Heck, I don’t even feel like installing Haskell on
this machine!) Hugo lets me get started quickly, and I can always
tinker later. For now, it’s time to write.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
