
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Mon, 06 Apr 2026 10:22:26 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Defending QUIC from acknowledgement-based DDoS attacks]]></title>
            <link>https://blog.cloudflare.com/defending-quic-from-acknowledgement-based-ddos-attacks/</link>
            <pubDate>Wed, 29 Oct 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ We identified and patched two DDoS vulnerabilities in our QUIC implementation related to packet acknowledgements. Cloudflare customers were not affected. We examine the "Optimistic ACK" attack vector and our solution, which dynamically skips packet numbers to validate client behavior.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>On April 10th, 2025 12:10 UTC, a security researcher notified Cloudflare of two vulnerabilities (<a href="https://www.cve.org/CVERecord?id=CVE-2025-4820"><u>CVE-2025-4820</u></a> and <a href="https://www.cve.org/CVERecord?id=CVE-2025-4821"><u>CVE-2025-4821</u></a>) related to QUIC packet acknowledgement (ACK) handling, through our <a href="https://hackerone.com/cloudflare?type=team"><u>Public Bug Bounty</u></a> program. These were DDoS vulnerabilities in the <a href="https://github.com/cloudflare/quiche"><u>quiche</u></a> library, and Cloudflare services that use it. quiche is Cloudflare's open-source implementation of QUIC protocol, which is the transport protocol behind <a href="https://blog.cloudflare.com/http3-the-past-present-and-future/"><u>HTTP/3</u></a>.</p><p>Upon notification, Cloudflare engineers patched the affected infrastructure, and the researcher confirmed that the DDoS vector was mitigated. <b>Cloudflare’s investigation revealed no evidence that the vulnerabilities were being exploited or that any customers were affected.</b> quiche versions prior to 0.24.4 were affected.</p><p>Here, we’ll explain why ACKs are important to Internet protocol design and how they help ensure fair network usage. Finally, we will explain the vulnerabilities and discuss our mitigation for the Optimistic ACK attack: a dynamic CWND-aware skip frequency that scales with a connection’s send rate.</p>
    <div>
      <h3>Internet Protocols and Attack Vectors</h3>
      <a href="#internet-protocols-and-attack-vectors">
        
      </a>
    </div>
    <p>QUIC is an Internet transport protocol that offers equivalent features to <a href="https://www.cloudflare.com/learning/ddos/glossary/tcp-ip/"><u>TCP</u></a> (Transmission Control Protocol) and <a href="https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/"><u>TLS</u></a> (Transport Layer Security). QUIC runs over <a href="https://www.cloudflare.com/en-gb/learning/ddos/glossary/user-datagram-protocol-udp/"><u>UDP</u></a> (User Datagram Protocol), is encrypted by default and offers a few benefits over the prior set of protocols (including smaller handshake time, connection migration, and preventing <a href="https://en.wikipedia.org/wiki/Head-of-line_blocking"><u>head-of-line blocking</u></a> that can manifest in TCP). Similar to TCP, QUIC relies on packet acknowledgements to make general progress. For example, ACKs are used for liveliness checks, validation, loss recovery signals, and congestion algorithm signals.</p><p>ACKs are an important source of signals for Internet protocols, which necessitates validation to ensure a malicious peer is not subverting these signals. Cloudflare's QUIC implementation, quiche, lacked ACK range validation, which meant a peer could send an ACK range for packets never sent by the endpoint; this was patched in <a href="https://www.cve.org/CVERecord?id=CVE-2025-4821"><u>CVE-2025-4821</u></a>. Additionally, a sophisticated attacker could  mount an attack by predicting and preemptively sending ACKs (a technique called Optimistic ACK); this was patched in <a href="https://www.cve.org/CVERecord?id=CVE-2025-4820"><u>CVE-2025-4820</u></a>. By exploiting the lack of ACK validation, an attacker can cause an endpoint to artificially expand its send rate; thereby gaining an unfair advantage over other connections. In the extreme case this can be a DDoS attack vector caused by higher server CPU utilization and an amplification of network traffic.</p>
    <div>
      <h3>Fairness and Congestion control</h3>
      <a href="#fairness-and-congestion-control">
        
      </a>
    </div>
    <p>A typical CDN setup includes hundreds of server processes, serving thousands of concurrent connections. Each connection has its own recovery and congestion control algorithm that is responsible for determining its fair share of the network. The Internet is a shared resource that relies on well-behaved transport protocols correctly implementing congestion control to ensure fairness.</p><p>To illustrate the point, let’s consider a shared network where the first connection (blue) is operating at capacity. When a new connection (green) joins and probes for capacity, it will trigger packet loss, thereby signaling the blue connection to reduce its send rate. The probing can be highly dynamic and although convergence might take time, the hope is that both connections end up sharing equal capacity on the network.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/44jjkcx22rpD7VdnZKsnPD/4d514e73c885a729bd973b3efb2564bf/image4.jpg" />
          </figure><p><sup>New connection joining the shared network. Existing flows make room for the new flow.</sup></p><p>In order to ensure fairness and performance, each endpoint uses a <a href="http://blog.cloudflare.com/cubic-and-hystart-support-in-quiche/"><u>Congestion Control</u></a> algorithm. There are various algorithms but for our purposes let's consider <a href="https://www.rfc-editor.org/rfc/rfc9438.html"><u>Cubic</u></a>, a loss-based algorithm. Cubic, when in steady state, periodically explores higher sending rates. As the peer ACKs new packets, Cubic unlocks additional sending capacity (congestion window) to explore even higher send rates. Cubic continues to increase its send rate until it detects congestion signals (e.g., packet loss), indicating that the network is potentially at capacity and the connection should lower its sending rate.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5FvyfLs39CrWnHv8JjiJkd/d44cc31229e4dafa062d607c4214cba0/image6.png" />
          </figure><p><sup>Cubic congestion control responding to loss on the network.</sup></p>
    <div>
      <h3>The role of ACKs</h3>
      <a href="#the-role-of-acks">
        
      </a>
    </div>
    <p>ACKs are a feedback mechanism that Internet protocols use to make progress. A server serving a large file download will send that data across multiple packets to the client. Since networks are lossy, the client is responsible for ACKing when it has received a packet from the server, thus confirming delivery and progress. Lack of an ACK indicates that the packet has been lost and that the data might require retransmission. This feedback allows the server to confirm when the client has received all the data that it requested.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1LMkCz6BB4aUav8pVhM1Mb/30f94cdaa857a08af3b8c0b9bb24de91/Screenshot_2025-10-28_at_15.23.05.png" />
          </figure><p><sup>The server delivers packets and the client responds with ACKs.</sup></p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Sa33xjYHj52KZZTL4ITWv/d0347affc68318b36da988331c55fd6c/Screenshot_2025-10-28_at_15.23.38.png" />
          </figure><p><sup>The server delivers packets, but packet [2] is lost. The client responds with ACKs only for packets [1, 3], thereby signalling that packet [2] was lost.</sup></p><p>In QUIC, packet numbers don't have to be sequential; that means skipping packet numbers is natively supported. Additionally, a <a href="https://www.rfc-editor.org/rfc/rfc9000.html#name-ack-frames"><u>QUIC ACK Frame</u></a> can contain gaps and multiple ACK ranges. As we will see, the built-in support for skipping packet numbers is a unique feature of QUIC (over TCP) that will help us enforce ACK validation.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2azePr06Z0kGVQwdEaaqbx/5ab6844b4d515444393ab0b8ca33bf1d/Screenshot_2025-10-28_at_15.25.05.png" />
          </figure><p><sup>The server delivering packets, but skipping packet [4]. The client responds with ACKs only for packets it received, and not sending an ACK for packet [4].</sup></p><p>ACKs also provide signals that control an endpoint's send rate and help provide fairness and performance. Delay between ACKs, variations in the delay, and lack of ACKs provide valuable signals, which suggest a change in the network and are important inputs to a congestion control algorithm.</p>
    <div>
      <h3>Skipping packets to avoid ACK delay</h3>
      <a href="#skipping-packets-to-avoid-ack-delay">
        
      </a>
    </div>
    <p>QUIC allows endpoints to encode the ACK delay: the time by which the ACK for packet number 'X' was intentionally delayed from when the endpoint received packet number 'X.' This delay can result from normal packet processing or be an implementation-specific optimization. For example, since ACKs processing can be expensive (both for CPU and network), delaying ACKs can allow for batching and reducing the associated overhead.</p><blockquote><p>If the sender wants to elicit a faster acknowledgement on PTO, it can skip a packet number to eliminate the acknowledgement delay. -- <a href="https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.4">https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.4</a></p></blockquote><p>However, since a delay in ACK signal also delays peer feedback, this can be detrimental for loss recovery. QUIC endpoints can therefore signal the peer to avoid delaying an ACK packet by skipping a packet number. This detail will become important as we will see later in the post.</p>
    <div>
      <h3>Validating ACK range</h3>
      <a href="#validating-ack-range">
        
      </a>
    </div>
    <p>It is expected that a well-behaved client should only send ACKs for packets that it has received. A lack of validation meant that it was possible for the client to send a very large ACK range for packets never sent by the server. For example, assuming the server has sent packets 0-5, a client was able to send an ACK Frame with the range 0-100.</p><p>By itself this is not actually a huge deal since quiche is smart enough to drop larger ACKs and only process ACKs for packets it has sent. However, as we will see in the next section, this made the Optimistic ACK vulnerability easier to exploit.</p><p>The fix was to enforce ACK range validation based on the largest packets sent by the server and close the connection on violation. This matches the RFC recommendation.</p><blockquote><p>An endpoint SHOULD treat receipt of an acknowledgment for a packet it did not send as a connection error of type PROTOCOL_VIOLATION, if it is able to detect the condition. -- <a href="https://www.rfc-editor.org/rfc/rfc9000#section-13.1">https://www.rfc-editor.org/rfc/rfc9000#section-13.1</a></p></blockquote>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/aPajmSD1NWaWvFv2aXAhs/480054b6514f3a1ddad219e4e81388f5/Screenshot_2025-10-28_at_15.26.15.png" />
          </figure><p><sup>The server validating ACKs: the client sending ACK for packets [4..5] not sent by the server. The server closes the connection since ACK validation fails.</sup></p>
    <div>
      <h3>Optimistic ACK attack</h3>
      <a href="#optimistic-ack-attack">
        
      </a>
    </div>
    <p>In the following scenario, let’s assume the client is trying to mount an Optimistic ACK attack against the server. The goal of a client mounting the attack is to cause the server to send at a high rate. To achieve a high send rate, the client needs to deliver ACKs quickly back to the server, thereby providing an artificially low <a href="https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/"><u>RTT</u></a> / high bandwidth signal. Since packet numbers are typically monotonically increasing, a clever client can predict the next packet number and preemptively send ACKs (artificial ACK).</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2xCY6yXFysB3yPxfa4TjOb/962a74feaf95e520abf037bd12e19db7/Screenshot_2025-10-28_at_15.28.39.png" />
          </figure><p><sup>Optimistic ACK attack: the client predicting packets sent by the server and preemptively sending ACKs. ACK validation does not help here.</sup></p><p>If the server has proper ACK validation, an invalid ACK for packets not yet sent by the server should trigger a connection close (without ACK range validation, the attack is trivial to execute). Therefore, a malicious client needs to be clever about pacing the artificial ACKs so they arrive just as the server has sent the packet. If the attack is done correctly, the server will see a very low RTT, and result in an inflated send rate.</p><blockquote><p>An endpoint that acknowledges packets it has not received might cause a congestion controller to permit sending at rates beyond what the network supports. An endpoint MAY skip packet numbers when sending packets to detect this behavior. An endpoint can then immediately close the connection with a connection error of type PROTOCOL_VIOLATION -- <a href="https://www.rfc-editor.org/rfc/rfc9000#section-21.4">https://www.rfc-editor.org/rfc/rfc9000#section-21.4</a></p></blockquote>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2fppvXzvdTOugNzCtxgiH5/897da7f980f1de95bdafa1aee423dcf2/Screenshot_2025-10-28_at_15.40.37.png" />
          </figure><p><sup>Preventing an Optimistic ACK attack: the client predicting packets sent by the server and preemptively sending ACKs. Since the server skipped packet [4], it is able to detect the invalid ACK and close the connection.</sup></p><p>The <a href="https://www.rfc-editor.org/rfc/rfc9000#section-21.4"><u>QUIC RFC</u></a> mentions the Optimistic ACK attack and suggests skipping packets to detect this attack. By skipping packets, the client is unable to easily predict the next packet number and risks connection close if the server implements invalid ACK range validation. Implementation details – like how many packet numbers to skip and how often – are missing, however.</p><p>The [malicious] client transmission pattern does not indicate any malicious behavior.</p><blockquote><p>As such, the bit rate towards the server follows normal behavior. Considering that QUIC packets are end-to-end encrypted, a middlebox cannot identify the attack by analyzing the client’s traffic. -- <a href="https://louisna.github.io/files/2025-anrw-oack.pdf">MAY is not enough! QUIC servers SHOULD skip packet numbers</a></p></blockquote><p>Ideally, the client would like to use as few resources as possible, while simultaneously causing the server to use as many as possible. In fact, as the security researchers confirmed in their paper: it is difficult to detect a malicious QUIC client using external traffic analysis, and it’s therefore necessary for QUIC implementations to mitigate the Optimistic ACK attack by skipping packets.</p><p>The Optimistic ACK vulnerability is not unique to QUIC. In fact the vulnerability was first discovered against TCP. However, since TCP does not natively support skipping packet numbers, an Optimistic ACK attack in TCP is harder to mitigate and can require additional DDoS analysis. By allowing for packet skipping, QUIC is able to prevent this type of attack at the protocol layer and more effectively ensure correctness and fairness over untrusted networks.</p>
    <div>
      <h3>How often to skip packet numbers</h3>
      <a href="#how-often-to-skip-packet-numbers">
        
      </a>
    </div>
    <p>According to the QUIC RFC, skipping packet numbers currently has two purposes. The first is to elicit a faster acknowledgement for loss recovery and the second is to mitigate an Optimistic ACK attack. A QUIC implementation skipping packets for Optimistic ACK attack therefore needs to skip frequently enough to mitigate the attack, while considering the effects on eliminating ACK delay.</p><p>Since packet skipping needs to be unpredictable, a simple implementation could be to skip packet numbers based on a random number from a static range. However, since the number of packets increases as the send rate increases, this has the downside of not adapting to the send rate. At smaller send rates, a static range will be too frequent, while at higher send rates it won't be frequent enough and therefore be less effective. It's also arguably most important to validate the send rate when there are higher send rates. It therefore seems necessary to adapt the skip frequency based on the send rate.</p><p>Congestion window (CWND) is a parameter used by congestion control algorithms to determine the amount of bytes that can be sent per round. Since the send rate increases based on the amount of bytes ACKed (capped by bytes sent), we claim that CWND makes a great proxy for dynamically adjusting the skip frequency. This CWND-aware skip frequency allows all connections, regardless of current send rate, to effectively mitigate the Optimistic ACK attack.</p>
            <pre><code>// c: the current packet number
// s: range of random packet number to skip from
//
// curr_pn
//  |
//  v                 |--- (upper - lower) ---|
// [c x x x x x x x x s s s s s s s s s s s s s x x]
//    |--min_skip---| |------skip_range-------|

const DEFAULT_INITIAL_CONGESTION_WINDOW_PACKETS: usize = 10;
const MIN_SKIP_COUNTER_VALUE: u64 = DEFAULT_INITIAL_CONGESTION_WINDOW_PACKETS * 2;

let packets_per_cwnd = (cwnd / max_datagram_size) as u64;
let lower = packets_per_cwnd / 2;
let upper = packets_per_cwnd * 2;

let skip_range = upper - lower;
let rand_skip_value = rand(skip_range);

let skip_pn = MIN_SKIP_COUNTER_VALUE + lower + rand_skip_value;</code></pre>
            <p><sup>Skip frequency calculation in quiche.</sup></p>
    <div>
      <h3>Timeline</h3>
      <a href="#timeline">
        
      </a>
    </div>
    <p>All timestamps are in UTC.</p><ul><li><p>2025–04-10 12:10 - Cloudflare is notified of an ACK validation and Optimistic ACK vulnerability via the Bug Bounty Program.</p></li><li><p>2025-04-19 00:20 – Cloudflare confirms both vulnerabilities are reproducible and begins working on fix.</p></li><li><p>2025-05-02 20:12 - Security patch is complete and infrastructure patching starts.</p></li><li><p>2025–05-16 04:52 - Cloudflare infrastructure patching is complete.</p></li><li><p>New quiche version released.</p></li></ul>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>We would like to sincerely thank <a href="https://louisna.github.io/"><u>Louis Navarre</u></a> and <a href="https://perso.uclouvain.be/olivier.bonaventure/blog/html/pages/bio.html"><u>Olivier Bonaventure</u></a> from <a href="https://www.uclouvain.be/en"><u>UCLouvain</u></a>, who responsibly disclosed this issue via our <a href="https://www.cloudflare.com/en-gb/disclosure/"><u>Cloudflare Bug Bounty Program</u></a>, allowing us to identify and mitigate the vulnerability. They also published a <a href="https://louisna.github.io/publication/2025-anrw-oack"><u>paper</u></a> with their findings, notifying 10 other QUIC implementations that also suffered from the Optimistic ACK vulnerability. </p><p>We welcome further <a href="https://www.cloudflare.com/en-gb/disclosure/"><u>submissions</u></a> from our community of researchers to continually improve the security of all of our products and open source projects.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Protocols]]></category>
            <category><![CDATA[Vulnerabilities]]></category>
            <category><![CDATA[Security]]></category>
            <guid isPermaLink="false">1vU4Xmgau85ysMJVxTEx09</guid>
            <dc:creator>Apoorv Kothari</dc:creator>
            <dc:creator>Louis Navarre (Guest author)</dc:creator>
        </item>
        <item>
            <title><![CDATA[MoQ: Refactoring the Internet's real-time media stack]]></title>
            <link>https://blog.cloudflare.com/moq/</link>
            <pubDate>Fri, 22 Aug 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ Media over QUIC (MoQ) is a new IETF standard that resolves this conflict, creating a single foundation for sub-second, interactive streaming at a global scale.
 ]]></description>
            <content:encoded><![CDATA[ <p>For over two decades, we've built real-time communication on the Internet using a patchwork of specialized tools. RTMP gave us ingest. <a href="https://www.cloudflare.com/learning/video/what-is-http-live-streaming/"><u>HLS</u></a> and <a href="https://www.mpeg.org/standards/MPEG-DASH/"><u>DASH</u></a> gave us scale. WebRTC gave us interactivity. Each solved a specific problem for its time, and together they power the global streaming ecosystem we rely on today.</p><p>But using them together in 2025 feels like building a modern application with tools from different eras. The seams are starting to show—in complexity, in latency, and in the flexibility needed for the next generation of applications, from sub-second live auctions to massive interactive events. We're often forced to make painful trade-offs between latency, scale, and operational complexity.</p><p>Today Cloudflare is launching the first Media over QUIC (MoQ) relay network, running on every Cloudflare server in datacenters in 330+ cities. MoQ is an open protocol being developed at the <a href="https://www.ietf.org/"><u>IETF</u></a> by engineers from across the industry—not a proprietary Cloudflare technology. MoQ combines the low-latency interactivity of WebRTC, the scalability of HLS/DASH, and the simplicity of a single architecture, all built on a modern transport layer. We're joining Meta, Google, Cisco, and others in building implementations that work seamlessly together, creating a shared foundation for the next generation of real-time applications on the Internet.</p>
    <div>
      <h3><b>An evolutionary ladder of compromise</b></h3>
      <a href="#an-evolutionary-ladder-of-compromise">
        
      </a>
    </div>
    <p>To understand the promise of MoQ, we first have to appreciate the history that led us here—a journey defined by a series of architectural compromises where solving one problem inevitably created another.</p><p><b>The RTMP era: Conquering latency, compromising on scale</b></p><p>In the early 2000s, <b>RTMP (Real-Time Messaging Protocol)</b> was a breakthrough. It solved the frustrating "download and wait" experience of early video playback on the web by creating a persistent, stateful TCP connection between a <a href="https://en.wikipedia.org/wiki/Adobe_Flash"><u>Flash</u></a> client and a server. This enabled low-latency streaming (2-5 seconds), powering the first wave of live platforms like <a href="http://justin.tv"><u>Justin.tv</u></a> (which later became Twitch).</p><p>But its strength was its weakness. That stateful connection, which had to be maintained for every viewer, was architecturally hostile to scale. It required expensive, specialized media servers and couldn't use the commodity HTTP-based <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/"><u>Content Delivery Networks (CDNs)</u></a> that were beginning to power the rest of the web. Its reliance on TCP also meant that a single lost packet could freeze the entire stream—a phenomenon known as <a href="https://blog.cloudflare.com/the-road-to-quic/#head-of-line-blocking"><u>head-of-line blocking</u></a>—creating jarring latency spikes. The industry retained RTMP for the "first mile" from the camera to servers (ingest), but a new solution was needed for the "last mile" from servers to your screen (delivery).</p><p><b>The HLS &amp; DASH era: Solving for scale, compromising on latency</b></p><p>The catalyst for the next era was the iPhone's rejection of Flash. In response, Apple created <a href="https://www.cloudflare.com/learning/video/what-is-http-live-streaming/"><b><u>HLS (HTTP Live Streaming)</u></b></a>. HLS, and its open-standard counterpart <b>MPEG-DASH</b> abandoned stateful connections and treated video as a sequence of small, static files delivered over standard HTTP.</p><p>This enabled much greater scalability. By moving to the interoperable open standard of HTTP for the underlying transport, video could now be distributed by any web server and cached by global CDNs, allowing platforms to reach millions of viewers reliably and relatively inexpensively. The compromise? A <i>significant</i> trade-off in latency. To ensure smooth playback, players needed to buffer at least three video segments before starting. With segment durations of 6-10 seconds, this baked 15-30 seconds of latency directly into the architecture.</p><p>While extensions like <a href="https://developer.apple.com/documentation/http-live-streaming/enabling-low-latency-http-live-streaming-hls"><u>Low-Latency HLS (LL-HLS)</u></a> have more recently emerged to achieve latencies in the 3-second range, they remain complex patches<a href="https://blog.cloudflare.com/the-road-to-quic/#head-of-line-blocking"><u> fighting against the protocol's fundamental design</u></a>. These extensions introduce a layer of stateful, real-time communication—using clever workarounds like holding playlist requests open—that ultimately strain the stateless request-response model central to HTTP's scalability and composability.</p><p><b>The WebRTC Era: Conquering conversational latency, compromising on architecture</b></p><p>In parallel, <b>WebRTC (Web Real-Time Communication)</b> emerged to solve a different problem: plugin-free, two-way conversational video with sub-500ms latency within a browser. It worked by creating direct peer-to-peer (P2P) media paths, removing central servers from the equation.</p><p>But this P2P model is fundamentally at odds with broadcast scale. <a href="https://blog.cloudflare.com/cloudflare-calls-anycast-webrtc/#webrtc-growing-pains"><u>In a mesh network, the number of connections grows quadratically with each new participant</u></a> (the "N-squared problem"). For more than a handful of users, the model collapses under the weight of its own complexity. To work around this, the industry developed server-based topologies like the Selective Forwarding Unit (SFU) and Multipoint Control Unit (MCU). These are effective but require building what is essentially a <a href="https://blog.cloudflare.com/cloudflare-calls-anycast-webrtc/#is-cloudflare-calls-a-real-sfu"><u>private, stateful, real-time CDN</u></a>—a complex and expensive undertaking that is not standardized across infrastructure providers.</p><p>This journey has left us with a fragmented landscape of specialized, non-interoperable silos, forcing developers to stitch together multiple protocols and accept a painful three-way tension between <b>latency, scale, and complexity</b>.</p>
    <div>
      <h3><b>Introducing MoQ</b></h3>
      <a href="#introducing-moq">
        
      </a>
    </div>
    <p>This is the context into which Media over QUIC (MoQ) emerges. It's not just another protocol; it's a new design philosophy built from the ground up to resolve this historical trilemma. Born out of an open, community-driven effort at the IETF, <u>MoQ aims to be a foundational Internet technology, not a proprietary product</u>.</p><p>Its promise is to unify the disparate worlds of streaming by delivering:</p><ol><li><p><b>Sub-second latency at broadcast scale:</b> Combining the latency of WebRTC with the scale of HLS/DASH and the simplicity of RTMP.</p></li><li><p><b>Architectural simplicity:</b> Creating a single, flexible protocol for ingest, distribution, and interactive use cases, eliminating the need to transcode between different technologies.</p></li><li><p><b>Transport efficiency:</b> Building on <a href="https://blog.cloudflare.com/the-road-to-quic/"><u>QUIC</u></a>, a <a href="https://www.cloudflare.com/learning/ddos/glossary/user-datagram-protocol-udp/"><u>UDP</u></a> based protocol to eliminate bottlenecks like TCP<a href="https://blog.cloudflare.com/the-road-to-quic/#head-of-line-blocking"><u> head-of-line blocking</u></a>.</p></li></ol><p>The initial focus was "Media" over QUIC, but the core concepts—named tracks of timed, ordered, but independent data—are so flexible that the working group is now simply calling the protocol "MoQ." The name reflects the power of the abstraction: it's a generic transport for any real-time data that needs to be delivered efficiently and at scale.</p><p>MoQ is now generic enough that it’s a data fanout or pub/sub system, for everything from audio/video (high bandwidth data) to sports score updates (low bandwidth data).</p>
    <div>
      <h3><b>A deep dive into the MoQ protocol stack</b></h3>
      <a href="#a-deep-dive-into-the-moq-protocol-stack">
        
      </a>
    </div>
    <p>MoQ's elegance comes from solving the right problem at the right layer. Let's build up from the foundation to see how it achieves sub-second latency at scale.</p><p>The choice of QUIC as MoQ's foundation isn't arbitrary—it addresses issues that have plagued streaming protocols for decades.</p><p>By building on <b>QUIC</b> (the transport protocol that also powers <a href="https://www.cloudflare.com/learning/performance/what-is-http3/"><u>HTTP/3</u></a>), MoQ solves some key streaming problems:</p><ul><li><p><b>No head-of-line blocking:</b> Unlike TCP where one lost packet blocks everything behind it, QUIC streams are independent. A lost packet on one stream (e.g., an audio track) doesn't block another (e.g., the main video track). This alone eliminates the stuttering that plagued RTMP.</p></li><li><p><b>Connection migration:</b> When your device switches from Wi-Fi to cellular mid-stream, the connection seamlessly migrates without interruption—no rebuffering, no reconnection.</p></li><li><p><b>Fast connection establishment:</b> QUIC's <a href="https://blog.cloudflare.com/even-faster-connection-establishment-with-quic-0-rtt-resumption/"><u>0-RTT resumption</u></a> means returning viewers can start playing instantly.</p></li><li><p><b>Baked-in, mandatory encryption:</b> All QUIC connections are encrypted by default with <a href="https://blog.cloudflare.com/rfc-8446-aka-tls-1-3/"><u>TLS 1.3</u></a>.</p></li></ul>
    <div>
      <h4>The core innovation: Publish/subscribe for media</h4>
      <a href="#the-core-innovation-publish-subscribe-for-media">
        
      </a>
    </div>
    <p>With QUIC solving transport issues, MoQ introduces its key innovation: treating media as subscribable tracks in a publish/subscribe system. But unlike traditional pub/sub, this is designed specifically for real-time media at CDN scale.</p><p>Instead of complex session management (WebRTC) or file-based chunking (HLS), <b>MoQ lets publishers announce named tracks of media that subscribers can request</b>. A relay network handles the distribution without needing to understand the media itself.</p>
    <div>
      <h4>How MoQ organizes media: The data model</h4>
      <a href="#how-moq-organizes-media-the-data-model">
        
      </a>
    </div>
    <p>Before we see how media flows through the network, let's understand how MoQ structures it. MoQ organizes data in a hierarchy:</p><ul><li><p><b>Tracks</b>: Named streams of media, like "video-1080p" or "audio-english". Subscribers request specific tracks by name.</p></li><li><p><b>Groups</b>: Independently decodable chunks of a track. For video, this typically means a GOP (Group of Pictures) starting with a keyframe. New subscribers can join at any Group boundary.</p></li><li><p><b>Objects</b>: The actual packets sent on the wire. Each Object belongs to a Track and has a position within a Group.</p></li></ul><p>This simple hierarchy enables two capabilities:</p><ol><li><p>Subscribers can start playback at <b>Group</b> boundaries without waiting for the next keyframe</p></li><li><p>Relays can forward <b>Objects</b> without parsing or understanding the media format</p></li></ol>
    <div>
      <h5>The network architecture: From publisher to subscriber</h5>
      <a href="#the-network-architecture-from-publisher-to-subscriber">
        
      </a>
    </div>
    <p>MoQ’s network components are also simple:</p><ul><li><p><b>Publishers</b>: Announce track namespaces and send Objects</p></li><li><p><b>Subscribers</b>: Request specific tracks by name</p></li><li><p><b>Relays</b>: Connect publishers to subscribers by forwarding immutable Objects without parsing or <a href="https://www.cloudflare.com/learning/video/video-encoding-formats/"><u>transcoding</u></a> the media</p></li></ul><p>A Relay acts as a subscriber to receive tracks from upstream (like the original publisher) and simultaneously acts as a publisher to forward those same tracks downstream. This model is the key to MoQ's scalability: one upstream subscription can fan out to serve thousands of downstream viewers.</p>
    <div>
      <h5>The MoQ Stack</h5>
      <a href="#the-moq-stack">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4g2MroH24otkzH3LQsFWZe/84ca43ad6c1c933ac395bf4ac767c584/image1.png" />
          </figure><p>MoQ's architecture can be understood as three distinct layers, each with a clear job:</p><ol><li><p><b>The Transport Foundation (QUIC or WebTransport):</b> This is the modern foundation upon which everything is built. MoQT can run directly over raw <b>QUIC</b>, which is ideal for native applications, or over <b>WebTransport</b>, which is required for use in a web browser. Crucially, the<a href="https://www.ietf.org/archive/id/draft-ietf-webtrans-http3-02.html"> <u>WebTransport protocol</u></a> and its corresponding<a href="https://w3c.github.io/webtransport/"> <u>W3C browser API</u></a> make QUIC's multiplexed reliable streams and unreliable datagrams directly accessible to browser applications. This is a game-changer. Protocols like <a href="https://blog.cloudflare.com/stream-now-supports-srt-as-a-drop-in-replacement-for-rtmp/"><u>SRT</u></a> may be efficient, but their lack of native browser support relegates them to ingest-only roles. WebTransport gives MoQ first-class citizenship on the web, making it suitable for both ingest and massive-scale distribution directly to clients.</p></li><li><p><b>The MoQT Layer:</b> Sitting on top of QUIC (or WebTransport), the MoQT layer provides the signaling and structure for a publish-subscribe system. This is the primary focus of the IETF working group. It defines the core control messages—like ANNOUNCE, and SUBSCRIBE—and the basic data model we just covered. MoQT itself is intentionally spartan; it doesn't know or care if the data it's moving is <a href="https://www.cloudflare.com/learning/video/what-is-h264-avc/"><u>H.264</u></a> video, Opus audio, or game state updates.</p></li><li><p><b>The Streaming Format Layer:</b> This is where media-specific logic lives. A streaming format defines things like manifests, codec metadata, and packaging rules.
 <a href="https://datatracker.ietf.org/doc/draft-ietf-moq-warp/"><b><u>WARP</u></b></a> is one such format being developed alongside MoQT at the IETF, but it isn't the only one. Another standards body, like DASH-IF, could define a <a href="https://www.iso.org/standard/85623.html"><u>CMAF</u></a>-based streaming format over MoQT. A company that controls both original publisher and end subscriber can develop its own proprietary streaming format to experiment with new codecs or delivery mechanisms without being constrained by the transport protocol.</p></li></ol><p>This separation of layers is why different organizations can build interoperable implementations while still innovating at the streaming format layer.</p>
    <div>
      <h4>End-to-End Data Flow</h4>
      <a href="#end-to-end-data-flow">
        
      </a>
    </div>
    <p>Now that we understand the architecture and the data model, let's walk through how these pieces come together to deliver a stream. The protocol is flexible, but a typical broadcast flow relies on the <code>ANNOUNCE</code> and <code>SUBSCRIBE </code>messages to establish a data path from a publisher to a subscriber through the relay network.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2iRTJFdtCjIOcyg7ezoYgJ/e303ea8d1eb438328b60fdb28be47e84/image2.png" />
          </figure><p>Here is a step-by-step breakdown of what happens in this flow:</p><ol><li><p><b>Initiating Connections:</b> The process begins when the endpoints, acting as clients, connect to the relay network. The Original Publisher initiates a connection with its nearest relay (we'll call it Relay A). Separately, an End Subscriber initiates a connection with its own local relay (Relay B). These endpoints perform a <code>SETUP</code> handshake with their respective relays to establish a MoQ session and declare supported parameters.</p></li><li><p><b>Announcing a Namespace:</b> To make its content discoverable, the Publisher sends an <code>ANNOUNCE</code> message to Relay A. This message declares that the publisher is the authoritative source for a given <b>track namespace</b>. Relay A receives this and registers in a shared control plane (a conceptual database) that it is now a source for this namespace within the network.</p></li><li><p><b>Subscribing to a Track:</b> When the End Subscriber wants to receive media, it sends a <code>SUBSCRIBE</code> message to its relay, Relay B. This message is a request for a specific <b>track name</b> within a specific <b>track namespace</b>.</p></li><li><p><b>Connecting the Relays:</b> Relay B receives the <code>SUBSCRIBE</code> request and queries the control plane. It looks up the requested namespace and discovers that Relay A is the source. Relay B then initiates a session with Relay A (if it doesn't already have one) and forwards the <code>SUBSCRIBE</code> request upstream.</p></li><li><p><b>Completing the Path and Forwarding Objects:</b> Relay A, having received the subscription request from Relay B, forwards it to the Original Publisher. With the full path now established, the Publisher begins sending the <code>Objects</code> for the requested track. The Objects flow from the Publisher to Relay A, which forwards them to Relay B, which in turn forwards them to the End Subscriber. If another subscriber connects to Relay B and requests the same track, Relay B can immediately start sending them the Objects without needing to create a new upstream subscription.</p></li></ol>
    <div>
      <h5>An Alternative Flow: The <code>PUBLISH</code> Model</h5>
      <a href="#an-alternative-flow-the-publish-model">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6KJYU1eWNyuSZEHNYonDDn/3898003d5a7f5904787c7ef009b22fe0/image3.png" />
          </figure><p>More recent drafts of the MoQ specification have introduced an alternative, push-based model using a <code>PUBLISH</code> message. In this flow, a publisher can effectively ask for permission to send a track's objects to a relay <i>without</i> waiting for a <code>SUBSCRIBE </code>request. The publisher sends a <code>PUBLISH</code> message, and the relay's <code>PUBLISH_OK</code> response indicates whether it will accept the objects. This is particularly useful for ingest scenarios, where a publisher wants to send its stream to an entry point in the network immediately, ensuring the media is available the instant the first subscriber connects.</p>
    <div>
      <h4>Advanced capabilities: Prioritization and congestion control</h4>
      <a href="#advanced-capabilities-prioritization-and-congestion-control">
        
      </a>
    </div>
    <p>MoQ’s benefits really shine when networks get congested. MoQ includes mechanisms for handling the reality of network traffic. One such mechanism is Subgroups.</p><p><b>Subgroups</b> are subdivisions within a Group that effectively map directly to the underlying QUIC streams. All Objects within the same Subgroup are generally sent on the same QUIC stream, guaranteeing their delivery order. Subgroup numbering also presents an opportunity to encode prioritization: within a Group, lower-numbered Subgroups are considered higher priority. </p><p>This enables intelligent quality degradation, especially with layered codecs (e.g. SVC):</p><ul><li><p><b>Subgroup 0</b>: Base video layer (360p) - must deliver</p></li><li><p><b>Subgroup 1</b>: Enhancement to 720p - deliver if bandwidth allows</p></li><li><p><b>Subgroup 2</b>: Enhancement to 1080p - first to drop under congestion</p></li></ul><p>When a relay detects congestion, it can drop Objects from higher-numbered Subgroups, preserving the base layer. Viewers see reduced quality instead of buffering.</p><p>The MoQ specification defines a scheduling algorithm that determines the order for all objects that are "ready to send." When a relay has multiple objects ready, it prioritizes them first by <b>group order</b> (ascending or descending) and then, within a group, by <b>subgroup id</b>. Our implementation supports the <b>group order</b> preference, which can be useful for low-latency broadcasts. If a viewer falls behind and its subscription uses descending group order, the relay prioritizes sending Objects from the newest "live" Group, potentially canceling unsent Objects from older Groups. This can help viewers catch up to the live edge quickly, a highly desirable feature for many interactive streaming use cases. The optimal strategies for using these features to improve QoE for specific use cases are still an open research question. We invite developers and researchers to use our network to experiment and help find the answers.</p>
    <div>
      <h3><b>Implementation: building the Cloudflare MoQ relay</b></h3>
      <a href="#implementation-building-the-cloudflare-moq-relay">
        
      </a>
    </div>
    <p>Theory is one thing; implementation is another. To validate the protocol and understand its real-world challenges, we've been building one of the first global MoQ relay networks. Cloudflare's network, which places compute and logic at the edge, is very well suited for this.</p><p>Our architecture connects the abstract concepts of MoQ to the Cloudflare stack. In our deep dive, we mentioned that when a publisher <code>ANNOUNCE</code>s a namespace, relays need to register this availability in a "shared control plane" so that <code>SUBSCRIBE</code> requests can be routed correctly. For this critical piece of state management, we use <a href="https://developers.cloudflare.com/durable-objects/"><u>Durable Objects</u></a>.</p><p>When a publisher announces a new namespace to a relay in, say, London, that relay uses a Durable Object—our strongly consistent, single-threaded storage solution—to record that this namespace is now available at that specific location. When a subscriber in Paris wants a track from that namespace, the network can query this distributed state to find the nearest source and route the <code>SUBSCRIBE</code> request accordingly. This architecture builds upon the technology we developed for Cloudflare's real-time services and provides a solution to the challenge of state management at a global scale.</p>
    <div>
      <h4>An Evolving Specification</h4>
      <a href="#an-evolving-specification">
        
      </a>
    </div>
    <p>Building on a new protocol in the open means implementing against a moving target. To get MoQ into the hands of the community, we made a deliberate trade-off: our current relay implementation is based on a <b>subset of the features defined in </b><a href="https://www.ietf.org/archive/id/draft-ietf-moq-transport-07.html"><b><u>draft-ietf-moq-transport-07</u></b></a>. This version became a de facto target for interoperability among several open-source projects and pausing there allowed us to put effort towards other aspects of deploying our relay network<b>.</b></p><p>This draft of the protocol makes a distinction between accessing "past" and "future" content. <code><b>SUBSCRIBE</b></code> is used to receive <b>future</b> objects for a track as they arrive—like tuning into a live broadcast to get everything from that moment forward. In contrast, <code><b>FETCH</b></code> provides a mechanism for accessing <b>past</b> content that a relay may already have in its cache—like asking for a recording of a song that just played.</p><p>Both are part of the same specification, but for the most pressing low-latency use cases, a performant implementation of <code>SUBSCRIBE</code> is what matters most. For that reason, we have focused our initial efforts there and have not yet implemented <code>FETCH</code>.</p><p>This is where our roadmap is flexible and where the community can have a direct impact. Do you need <code>FETCH</code> to build on-demand or catch-up functionality? Or is more complete support for the prioritization features within <code>SUBSCRIBE</code> more critical for your use case? The feedback we receive from early developers will help us decide what to build next.</p><p>As always, we will announce our updates and changes to our implementation as we continue with development on our <a href="https://developers.cloudflare.com/moq"><u>developer docs pages</u></a>.</p>
    <div>
      <h3>Kick the tires on the future</h3>
      <a href="#kick-the-tires-on-the-future">
        
      </a>
    </div>
    <p>We believe in building in the open and interoperability in the community. MoQ is not a Cloudflare technology but a foundational Internet technology. To that end, the first demo client we’re presenting is an open source, community example.</p><p><b>You can access the demo here: </b><a href="https://moq.dev/publish/"><b><u>https://moq.dev/publish/</u></b></a></p><p>Even though this is a preview release, we are running MoQ relays at Cloudflare’s full scale, like we do every production service. This means every server that is part of the Cloudflare network in more than 330 cities is now a MoQ relay.</p><p>We invite you to experience the "wow" moment of near-instant, sub-second streaming latency that MoQ enables. How would you use a protocol that offers the speed of a video call with the scale of a global broadcast?</p>
    <div>
      <h3><b>Interoperability</b></h3>
      <a href="#interoperability">
        
      </a>
    </div>
    <p>We’ve been working with others in the IETF WG community and beyond on interoperability of publishers, players and other parts of the MoQ ecosystem. So far, we’ve tested with:</p><ul><li><p>Luke Curley’s <a href="https://moq.dev"><u>moq.dev</u></a></p></li><li><p>Lorenzo Miniero’s <a href="https://github.com/meetecho/imquic"><u>imquic</u></a></p></li><li><p>Meta’s <a href="https://github.com/facebookexperimental/moxygen"><u>Moxygen</u></a> </p></li><li><p><a href="https://github.com/englishm/moq-rs"><u>moq-rs</u></a></p></li><li><p><a href="https://github.com/englishm/moq-js"><u>moq-js</u></a></p></li><li><p><a href="https://norsk.video/"><u>Norsk</u></a></p></li><li><p><a href="https://vindral.com/"><u>Vindral</u></a></p></li></ul>
    <div>
      <h3>The Road Ahead</h3>
      <a href="#the-road-ahead">
        
      </a>
    </div>
    <p>The Internet's media stack is being refactored. For two decades, we've been forced to choose between latency, scale, and complexity. The compromises we made solved some problems, but also led to a fragmented ecosystem.</p><p>MoQ represents a promising new foundation—a chance to unify the silos and build the next generation of real-time applications on a scalable protocol. We're committed to helping build this foundation in the open, and we're just getting started.</p><p>MoQ is a realistic way forward, built on QUIC for future proofing, easier to understand than WebRTC, compatible with browsers unlike RTMP.</p><p>The protocol is evolving, the implementations are maturing, and the community is growing. Whether you're building the next generation of live streaming, exploring real-time collaboration, or pushing the boundaries of interactive media, consider whether MoQ may provide the foundation you need.</p>
    <div>
      <h3>Availability and pricing</h3>
      <a href="#availability-and-pricing">
        
      </a>
    </div>
    <p>We want developers to start building with MoQ today. To make that possible MoQ at Cloudflare is in tech preview - this means it's available free of charge for testing (at any scale). Visit our <a href="https://developers.cloudflare.com/moq/"><u>developer homepage </u></a>for updates and potential breaking changes.</p><p>Indie developers and large enterprises alike ask about pricing early in their adoption of new technologies. We will be transparent and clear about MoQ pricing. In general availability, self-serve customers should expect to pay 5 cents/GB outbound with no cost for traffic sent towards Cloudflare. </p><p>Enterprise customers can expect usual pricing in line with regular media delivery pricing, competitive with incumbent protocols. This means if you’re already using Cloudflare for media delivery, you should not be wary of adopting new technologies because of cost. We will support you.</p><p>If you’re interested in partnering with Cloudflare in adopting the protocol early or contributing to its development, please reach out to us at <a><u>moq@cloudflare.com</u></a>! Engineers excited about the future of the Internet are standing by.</p>
    <div>
      <h3>Get involved:</h3>
      <a href="#get-involved">
        
      </a>
    </div>
    <ul><li><p><b>Try the demo:</b> <a href="https://moq.dev/publish/"><u>https://moq.dev/publish/</u></a></p></li><li><p><b>Read the Internet draft:</b> <a href="https://datatracker.ietf.org/doc/draft-ietf-moq-transport/"><u>https://datatracker.ietf.org/doc/draft-ietf-moq-transport/</u></a></p></li><li><p><b>Contribute</b> to the protocol’s development: <a href="https://datatracker.ietf.org/group/moq/documents/"><u>https://datatracker.ietf.org/group/moq/documents/</u></a></p></li><li><p><b>Visit </b>our developer homepage: <a href="https://developers.cloudflare.com/moq/"><u>https://developers.cloudflare.com/moq/</u></a></p></li></ul><p></p> ]]></content:encoded>
            <category><![CDATA[Video]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Live Streaming]]></category>
            <category><![CDATA[WebRTC]]></category>
            <category><![CDATA[IETF]]></category>
            <category><![CDATA[Standards]]></category>
            <guid isPermaLink="false">2XgF5NjmAy3cqybLPkpMFu</guid>
            <dc:creator>Mike English</dc:creator>
            <dc:creator>Renan Dincer</dc:creator>
        </item>
        <item>
            <title><![CDATA[Open sourcing h3i: a command line tool and library for low-level HTTP/3 testing and debugging]]></title>
            <link>https://blog.cloudflare.com/h3i/</link>
            <pubDate>Mon, 30 Dec 2024 14:00:00 GMT</pubDate>
            <description><![CDATA[ h3i is a command line tool and Rust library designed for low-level testing and debugging of HTTP/3, which runs over QUIC. ]]></description>
            <content:encoded><![CDATA[ <p>Have you ever built a piece of IKEA furniture, or put together a LEGO set, by following the instructions closely and only at the end realized at some point you didn't <i>quite</i> follow them correctly? The final result might be close to what was intended, but there's a nagging thought that maybe, just maybe, it's not as rock steady or functional as it could have been.</p><p>Internet protocol specifications are instructions designed for engineers to build things. Protocol designers take great care to ensure the documents they produce are clear. The standardization process gathers consensus and review from experts in the field, to further ensure document quality. Any reasonably skilled engineer should be able to take a specification and produce a performant, reliable, and secure implementation. The Internet is central to everyone's lives, and we depend on these implementations. Any deviations from the specification can put us at risk. For example, mishandling of malformed requests can allow attacks such as <a href="https://en.wikipedia.org/wiki/HTTP_request_smuggling"><u>request smuggling</u></a>.</p><p>h3i is a binary command line tool and Rust library designed for low-level testing and debugging of HTTP/3, which runs over QUIC. <a href="https://crates.io/crates/h3i"><u>h3i</u></a> is free and open source as part of Cloudflare's <a href="https://github.com/cloudflare/quiche"><u>quiche</u></a> project. In this post we'll explain the motivation behind developing h3i, how we use it to help develop robust and safe standards-compliant software and production systems, and how you can similarly use it to test your own software or services. If you just want to jump into how to use h3i, go to the <a href="#the-h3i-command-line-tool"><u>h3i command line tool</u></a> section.</p>
    <div>
      <h2>A recap of QUIC and HTTP/3</h2>
      <a href="#a-recap-of-quic-and-http-3">
        
      </a>
    </div>
    <p><a href="https://blog.cloudflare.com/http3-the-past-present-and-future/"><u>QUIC</u></a> is a secure-by-default transport protocol that provides performance advantages compared to TCP and TLS via a more efficient handshake, along with stream multiplexing that provides <a href="https://en.wikipedia.org/wiki/Head-of-line_blocking"><u>head-of-line blocking</u></a> avoidance. <a href="https://www.cloudflare.com/en-gb/learning/performance/what-is-http3/"><u>HTTP/3</u></a> is an application protocol that maps HTTP semantics to QUIC, such as defining how HTTP requests and responses are assigned to individual QUIC streams.</p><p>Cloudflare has supported QUIC on our global network in some shape or form <a href="https://blog.cloudflare.com/http3-the-past-present-and-future/"><u>since 2018</u></a>. We started while the <a href="https://ietf.org/"><u>Internet Engineering Task Force (IETF)</u></a> was earnestly standardizing the protocol, working through early iterations and using interoperability testing and experience to help provide feedback for the standards process. We <a href="https://blog.cloudflare.com/quic-version-1-is-live-on-cloudflare/"><u>launched support</u></a> for QUIC version 1 and HTTP/3 as soon as <a href="https://datatracker.ietf.org/doc/html/rfc9000"><u>RFC 9000</u></a> (and its accompanying specifications) were published in 2021.</p><p>We work on the Protocols team, who own the ingress proxy into the Cloudflare network. This is essentially Cloudflare’s “front door” — HTTP requests that come to Cloudflare from the Internet pass through us first. The majority of requests are passed onwards to things like rulesets, workers, caches, or a customer origin. However, you might be surprised that many requests don't ever make it that far because they are, in some way, invalid or malformed. Servers listening on the Internet have to be robust to traffic that is not RFC compliant, whether caused by accident or malicious intent.</p><p>The Protocols team actively participates in IETF standardization work and has also helped build and maintain other Cloudflare services that leverage quiche for QUIC and HTTP/3, from the proxies that help <a href="https://blog.cloudflare.com/icloud-private-relay/"><u>iCloud Private Relay</u></a> via <a href="https://blog.cloudflare.com/unlocking-quic-proxying-potential/"><u>MASQUE proxying</u></a>, to replacing <a href="https://blog.cloudflare.com/zero-trust-warp-with-a-masque/"><u>WARP's use of Wireguard with MASQUE</u></a>, and beyond.</p><p>Throughout all of these different use cases, it is important for us to extensively test all aspects of the protocols. A deep dive into protocol details is a blog post (or three) in its own right. So let's take a thin slice across HTTP to help illustrate the concepts.</p><p><a href="https://www.rfc-editor.org/rfc/rfc9110.html"><u>HTTP Semantics</u></a> are common to all versions of HTTP — the overall architecture, terminology, and protocol aspects such as request and response messages, methods, status codes, header and trailer fields, message content, and much more. Each individual HTTP version defines how semantics are transformed into a "wire format" for exchange over the Internet. You can read more about HTTP/1.1 and HTTP/2 in some of our previous <a href="https://blog.cloudflare.com/a-primer-on-proxies/"><u>blog</u></a> <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>posts</u></a>.</p><p>With HTTP/3, HTTP request and response messages are split into a series of binary frames. <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-7.2.2"><u>HEADERS</u></a> frames carry a representation of HTTP metadata (method, path, status code, field lines). The payload of the frame is the encoded <a href="https://datatracker.ietf.org/doc/html/rfc9204"><u>QPACK</u></a> compression output. <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-7.2.1"><u>DATA</u></a> frames carry <a href="https://datatracker.ietf.org/doc/html/rfc9110#section-6.4.1"><u>HTTP content</u></a> (aka "message body"). In order to exchange these frames, HTTP/3 relies on QUIC <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-2"><u>streams</u></a>. These provide an ordered and reliable byte stream and each have an identifier (ID) that is unique within the scope of a connection. There are <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-2.1"><u>four different stream types</u></a>, denominated by the two least significant bits of the ID.</p><p>As a simple example, assuming a QUIC connection has already been established, a client can make a GET request and receive a 200 OK response with an HTML body using the follow sequence:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7vVfQ5CYaaVPVmGloRUnkI/88bd727c3526e540bd493bc15fbe904a/unnamed.png" />
          </figure><ol><li><p>Client allocates the first available client-initiated bidirectional QUIC stream. (The IDs start at 0, then 4, 8, 12 and so on)</p></li><li><p>Client sends the request HEADERS frame on the stream and sets the stream's <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-19.8"><u>FIN bit</u></a> to mark the end of stream.</p></li><li><p>Server receives the request HEADERS frame and validates it against <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2"><u>RFC 9114 rules</u></a>. If accepted, it processes the request and prepares the response.</p></li><li><p>Server sends the response HEADERS frame on the same stream.</p></li><li><p>Server sends the response DATA frame on the same stream and sets the FIN bit.</p></li><li><p>Client receives the response frames and validates them. If accepted, the content is presented to the user.</p></li></ol><p>At the QUIC layer, stream data is split into STREAM frames, which are sent in QUIC packets over UDP. QUIC deals with any loss detection and recovery, helping to ensure stream data is reliable. The layer cake diagram below provides a handy comparison of how HTTP/1.1, HTTP/2 and HTTP/3 use TCP, UDP and IP.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4049UpKGn4BJcYcEXSFgWz/32143a5ba3672786639908ad96851225/image2.png" />
          </figure>
    <div>
      <h2>Background on testing QUIC and HTTP/3 at Cloudflare</h2>
      <a href="#background-on-testing-quic-and-http-3-at-cloudflare">
        
      </a>
    </div>
    <p>The Protocols team has a diverse set of automated test tools that exercise our ingress proxy software in order to ensure it can stand up to the deluge that the Internet can throw at it. Just like a bouncer at a nightclub front door, we need to prevent as much bad traffic as possible before it gets inside and potentially causes damage.</p><p>HTTP/2 and HTTP/3 share several concepts. When we started developing early HTTP/3 support, we'd already learned a lot from production experience with HTTP/2. While HTTP/2 addressed many issues with HTTP/1.1 (especially problems like <a href="https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf"><u>request smuggling</u></a>, caused by its ASCII-based message delineation), HTTP/2 also added complexity and new avenues for attack. Security is an ongoing process, and the Protocols team continually hardens our software and systems to threats. For example, mitigating the range of <a href="https://blog.cloudflare.com/on-the-recent-http-2-dos-attacks/"><u>denial-of-service attacks</u></a> identified by Netflix in 2019, or the <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>HTTP/2 Rapid Reset</u></a> attacks of 2023.</p><p>For testing HTTP/2, we rely on the Python <a href="https://pypi.org/project/requests/"><u>Requests</u></a> library for testing conventional HTTP exchanges. However, that mostly only exercises HEADERS and DATA frames. There are eight other frame types and a plethora of ways that they can interact (hence the new attack vectors mentioned above). In order to get full testing coverage, we have to break down into the lower layer <a href="https://pypi.org/project/h2/"><u>h2</u></a> library, which allows exact frame-by-frame control. However, even that is not always enough. Libraries tend to want to follow the RFC rules and prevent their users from doing "the wrong thing". This is entirely logical for most purposes. For our needs though, we need to take off the safety guards just like any potential attackers might do. We have a few cases where the best way to exercise certain traffic patterns is to handcraft HTTP/2 frames in a hex editor, store that as binary, and replay it with a tool such as <a href="https://docs.openssl.org/1.0.2/man1/s_client/"><u>OpenSSL s_client</u></a>.</p><p>We knew we'd need similar testing approaches for HTTP/3. However, when we started in 2018, there weren't many other suitable client implementations. The rate of iteration on the specifications also meant it was hard to always keep in sync. So we built tests on quiche, using a mix of our <a href="https://github.com/cloudflare/quiche/blob/master/apps/src/client.rs"><u>quiche-client</u></a> and <a href="https://github.com/cloudflare/quiche/tree/master/tools/http3_test"><u>http3_test</u></a>. Over time, the python library <a href="https://github.com/aiortc/aioquic"><u>aioquic</u></a> has matured, and we have used it to add a range of lower-layer tests that break or bend HTTP/3 rules, in order to prove our proxies are robust.</p><p>Finally, we would be remiss not to mention that all the tests in our ingress proxy are <b>in addition to </b>the suite of over 500 integration tests that run on the quiche project itself.</p>
    <div>
      <h2>Making HTTP/3 testing more accessible and maintainable with h3i</h2>
      <a href="#making-http-3-testing-more-accessible-and-maintainable-with-h3i">
        
      </a>
    </div>
    <p>While we are happy with the coverage of our current tests, the smorgasbord of test tools makes it hard to know what to reach for when adding new tests. For example, we've had cases where aioquic's safety guards prevent us from doing something, and it has needed a patch or workaround. This sort of thing requires a time investment just to debug/develop the tests.</p><p>We believe it shouldn't take a protocol or code expert to develop what are often very simple to describe tests. While it is important to provide guide rails for the majority of conventional use cases, it is also important to provide accessible methods for taking them off.</p><p>Let's consider a simple example. In HTTP/3 there is something called the control stream. It's used to exchange frames such as SETTINGS, which affect the HTTP/3 connection. RFC 9114 <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-6.2.1"><u>Section 6.2.1</u></a> states:</p><blockquote><p><i>Each side MUST initiate a single control stream at the beginning of the connection and send its SETTINGS frame as the first frame on this stream. If the first frame of the control stream is any other frame type, this MUST be treated as a connection error of type H3_MISSING_SETTINGS. Only one control stream per peer is permitted; receipt of a second stream claiming to be a control stream MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR. The sender MUST NOT close the control stream, and the receiver MUST NOT request that the sender close the control stream. If either control stream is closed at any point, this MUST be treated as a connection error of type H3_CLOSED_CRITICAL_STREAM. Connection errors are described in Section 8.</i></p></blockquote><p>There are many tests we can conjure up just from that paragraph:</p><ol><li><p>Send a non-SETTINGS frame as the first frame on the control stream.</p></li><li><p>Open two control streams.</p></li><li><p>Open a control stream and then close it with a FIN bit.</p></li><li><p>Open a control stream and then reset it with a RESET_STREAM QUIC frame.</p></li><li><p>Wait for the peer to open a control stream and then ask for it to be reset with a STOP_SENDING QUIC frame.</p></li></ol><p>All of the above actions should cause a remote peer that has implemented the RFC properly to close the connection. Therefore, it is not in the interest of the local client or server applications to ever do these actions.</p><p>Many QUIC and HTTP/3 implementations are developed as libraries that are integrated into client or server applications. There may be an extensive set of unit or integration tests of the library checking RFC rules. However, it is also important to run the same tests on the integrated assembly of library and application, since it's all too common that an unhandled/mishandled library error can cascade to cause issues in upper layers. For instance, the HTTP/2 Rapid Reset attacks affected Cloudflare due to their <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/#impact-on-customers"><u>impact on how one service spoke to another</u></a>.</p><p>We've developed h3i, a command line tool and library, to make testing more accessible and maintainable for all. We started with a client that can exercise servers, since that's what our focus has been. Future developments could support the opposite, a server that behaves in unusual ways in order to exercise clients.</p><p><b>Note: </b>h3i is <i>not</i> intended to be a production client! Its flexibility may cause issues that are not observed in other production-oriented clients. It is also not intended to be used for any type of performance testing and measurement.</p>
    <div>
      <h2>The h3i command line tool</h2>
      <a href="#the-h3i-command-line-tool">
        
      </a>
    </div>
    <p>The primary purpose of the h3i command line tool is quick low-level debugging and exploratory testing. Rather than worrying about writing code or a test script, users can quickly run an ad-hoc client test against a target, guided by interactive prompts.</p><p>In the simplest case, you can think of h3i a bit like <a href="https://curl.se/"><u>curl</u></a> but with access to some extra HTTP/3 parameters. In the example below, we issue a request to <a href="https://cloudflare-quic.com"><u>https://cloudflare-quic.com</u></a>/ and receive a response.</p><div>
  
</div><p>Walking through a simple GET with h3i step-by-step:</p><ol><li><p>Grab a copy of the h3i binary either by running <code>cargo install h3i</code> or cloning the quiche source repo at <a href="https://github.com/cloudflare/quiche/"><u>https://github.com/cloudflare/quiche/</u></a>. Both methods assume you have some familiarity with Rust and Cargo. See the cargo <a href="https://doc.rust-lang.org/book/ch14-04-installing-binaries.html"><u>documentation</u></a> for more information.</p><ol><li><p><code>cargo install</code> will place the binary on your path, so you can then just run it by executing <code>h3i</code>.</p></li><li><p>If running from source, navigate to the quiche/h3i directory and then use <code>cargo run</code>.</p></li></ol></li><li><p>Run the binary and provide the name and port of the target server. If the port is omitted, the default value 443 is assumed. E.g, <code>cargo run cloudflare-quic.com</code></p></li><li><p>h3i then enters the action prompting phase. A series of one or more HTTP/3 actions can be queued up, such as sending frames, opening or terminating streams, or waiting on data from the server. The full set of options is documented in the <a href="https://github.com/cloudflare/quiche/blob/master/h3i/README.md#command-line-tool"><u>readme</u></a>.</p><ol><li><p>The prompting interface adapts to keyboard inputs and supports tab completion.</p></li><li><p>In the example above, the <code>headers</code> action is selected, which walks through populating the fields in a HEADERS frame. It includes <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.3.1"><u>mandatory fields</u></a> from RFC 9114 for convenience. If a test requires omitting these, the <code>headers_no_pseudo</code> can be used instead.</p></li></ol></li><li><p>The <code>commit</code> prompt choice finalizes the action list and moves to the connection phase. h3i initiates a QUIC connection to the server identified in step 2. Once connected, actions are executed in order.</p></li><li><p>By default, h3i reports some limited information about the frames the server sent. To get more detailed information, the <code>RUST_LOG</code> environment can be set with either <code>debug</code> or <code>trace</code> levels.</p></li></ol>
    <div>
      <h2>Instant record and replay, powered by qlog</h2>
      <a href="#instant-record-and-replay-powered-by-qlog">
        
      </a>
    </div>
    <p>It can be fun to play around with the h3i command line tool to see how different servers respond to different combinations or sequences of actions. Occasionally, you'll find a certain set that you want to run over and over again, or share with a friend or colleague. Having to manually enter the prompts repeatedly, or share screenshots of the h3i input can turn tedious. Fortunately, h3i records all the actions in a log file by default — the file path is printed immediately after h3i starts. The format of this file is based on <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema"><u>qlog</u></a>, an in-progress standard in development at the IETF for network protocol logging. It’s a perfect fit for our low-level needs.</p><p>Here's an example h3i qlog file:</p>
            <pre><code>{"qlog_version":"0.3","qlog_format":"JSON-SEQ","title":"h3i","description":"h3i","trace":{"vantage_point":{"type":"client"},"title":"h3i","description":"h3i","configuration":{"time_offset":0.0}}}
{
  "time": 0.172783,
  "name": "http:frame_created",
  "data": {
    "stream_id": 0,
    "frame": {
      "frame_type": "headers",
      "headers": [
        {
          "name": ":method",
          "value": "GET"
        },
        {
          "name": ":authority",
          "value": "cloudflare-quic.com"
        },
        {
          "name": ":path",
          "value": "/"
        },
        {
          "name": ":scheme",
          "value": "https"
        },
        {
          "name": "user-agent",
          "value": "h3i"
        }
      ]
    }
  },
  "fin_stream": true
}</code></pre>
            <p>h3i logs can be replayed using the <code>--qlog-input</code> option. You can change the target server host and port, and keep all the same actions. However, most servers will validate the :authority pseudo-header or Host header contained in a HEADERS frame. The --replay-host-override option allows changing these fields without needing to modify the file by hand.</p><p>And yes, qlog files are human-readable text in the JSON-SEQ format. So you can also just write these by hand in the first place if you like! However, if you're going to start writing things, maybe Rust is your preferred option…</p>
    <div>
      <h2>Using the h3i library to send a malformed request with Rust</h2>
      <a href="#using-the-h3i-library-to-send-a-malformed-request-with-rust">
        
      </a>
    </div>
    <p>In our previous example, we just sent a valid request so there wasn't anything interesting to observe. Where h3i really shines is in generating traffic that isn't RFC compliant, such as malformed HTTP messages, invalid frame sequences, or other actions on streams. This helps determine if a server is acting robustly and defensively.</p><p>Let's explore this more with an example of HTTP content-length mismatch. RFC 9114 <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2"><u>section 4.1.2</u></a> specifies:</p><blockquote><p><i>A request or response that is defined as having content when it contains a Content-Length header field (Section 8.6 of [HTTP]) is malformed if the value of the Content-Length header field does not equal the sum of the DATA frame lengths received. A response that is defined as never having content, even when a Content-Length is present, can have a non-zero Content-Length header field even though no content is included in DATA frames.</i></p><p><i>Intermediaries that process HTTP requests or responses (i.e., any intermediary not acting as a tunnel) MUST NOT forward a malformed request or response. Malformed requests or responses that are detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.</i></p><p><i>For malformed requests, a server MAY send an HTTP response indicating the error prior to closing or resetting the stream.</i></p></blockquote><p>There are good reasons that the RFC is so strict about handling mismatched content lengths. They can be a vector for <a href="https://portswigger.net/research/http2"><u>desynchronization attacks</u></a> (similar to request smuggling), especially when a proxy is converting inbound HTTP/3 to outbound HTTP/1.1.</p><p>We've provided an <a href="https://github.com/cloudflare/quiche/blob/master/h3i/examples/content_length_mismatch.rs"><u>example</u></a> of how to use the h3i Rust library to write a tailor-made test client that sends a mismatched content length request. It sends a Content-Length header of 5, but its body payload is “test”, which is only 4 bytes. It then waits for the server to respond, after which it explicitly closes the connection by sending a QUIC CONNECTION_CLOSE frame.</p><p>When running low-level tests, it can be interesting to also take a packet capture (<a href="https://en.wikipedia.org/wiki/Pcap"><u>pcap</u></a>) and observe what is happening on the wire. Since QUIC is an encrypted transport, we'll need to use the SSLKEYLOG environment variable to capture the session keys so that tools like Wireshark can <a href="https://wiki.wireshark.org/TLS#using-the-pre-master-secret"><u>decrypt and dissect</u></a>.</p><p>To follow along at home, clone a copy of the quiche repository, start a packet capture on the appropriate network interface and then run:</p>
            <pre><code>cd quiche/h3i
SSLKEYLOGFILE="h3i-example.keys" cargo run --example content_length_mismatch</code></pre>
            <p>In our decrypted capture, we see the expected sequence of handshake, request, response, and then closure.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Qkdd3h0x826tH95S61u92/5de829e018b9d3ef409a2452362fa81e/image1.png" />
          </figure>
    <div>
      <h2>Surveying the example code</h2>
      <a href="#surveying-the-example-code">
        
      </a>
    </div>
    <p>The <a href="https://github.com/cloudflare/quiche/blob/master/h3i/examples/content_length_mismatch.rs"><u>example</u></a> is a simple binary app with a <code>main()</code> entry point. Let's survey the key elements.</p><p>First, we set up an h3i configuration to a target server:</p>
            <pre><code>let config = Config::new()
        .with_host_port("cloudflare-quic.com".to_string())
        .with_idle_timeout(2000)
        .build()
        .unwrap();</code></pre>
            <p>The idle timeout is a QUIC concept which tells each endpoint when it should close the connection if the connection has been idle. This prevents endpoints from spinning idly if the peer hasn’t closed the connection. h3i’s default is 30 seconds, which can be too long for tests, so we set ours to 2 seconds here.</p><p>Next, we define a set of request headers and encode them with QPACK compression, ready to put in a HEADERS frame. Note that h3i does provide a <a href="https://docs.rs/h3i/latest/h3i/actions/h3/fn.send_headers_frame.html"><u>send_headers_frame</u></a> helper method which does this for you, but the example does it manually for clarity:</p>
            <pre><code>let headers = vec![
        Header::new(b":method", b"POST"),
        Header::new(b":scheme", b"https"),
        Header::new(b":authority", b"cloudflare-quic.com"),
        Header::new(b":path", b"/"),
        // We say that we're going to send a body with 5 bytes...
        Header::new(b"content-length", b"5"),
    ];

    let header_block = encode_header_block(&amp;headers).unwrap();</code></pre>
            <p>Then, we define the set of h3i actions that we want to execute in order: send HEADERS, send a too-short DATA frame, wait for the server's HEADERS, then close the connection.</p>
            <pre><code>let actions = vec![
        Action::SendHeadersFrame {
            stream_id: STREAM_ID,
            fin_stream: false,
            headers,
            frame: Frame::Headers { header_block },
        },
        Action::SendFrame {
            stream_id: STREAM_ID,
            fin_stream: true,
            frame: Frame::Data {
                // ...but, in actuality, we only send 4 bytes. This should yield a
                // 400 Bad Request response from an RFC-compliant
                // server: https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2-3
                payload: b"test".to_vec(),
            },
        },
        Action::Wait {
            wait_type: WaitType::StreamEvent(StreamEvent {
                stream_id: STREAM_ID,
                event_type: StreamEventType::Headers,
            }),
        },
        Action::ConnectionClose {
            error: quiche::ConnectionError {
                is_app: true,
                error_code: quiche::h3::WireErrorCode::NoError as u64,
                reason: vec![],
            },
        },
    ];</code></pre>
            <p>Finally, we'll set things in motion with <code>connect()</code>, which sets up the QUIC connection, executes the actions list and collects the summary.</p>
            <pre><code>let summary =
        sync_client::connect(config, &amp;actions).expect("connection failed");

    println!(
        "=== received connection summary! ===\n\n{}",
        serde_json::to_string_pretty(&amp;summary).unwrap_or_else(|e| e.to_string())
    );</code></pre>
            <p><a href="https://docs.rs/h3i/latest/h3i/client/connection_summary/struct.ConnectionSummary.html"><u>ConnectionSummary</u></a>  provides data about the connection, including the frames h3i received, details about why the connection closed, and connection statistics. The example prints the summary out. However, you can programmatically check it. We do this to write our own internal automation tests.</p><p>If you're running the example, it should print something like the following:</p>
            <pre><code>=== received connection summary! ===

{
  "stream_map": {
    "0": [
      {
        "UNKNOWN": {
          "raw_type": 2471591231244749708,
          "payload": ""
        }
      },
      {
        "UNKNOWN": {
          "raw_type": 2031803309763646295,
          "payload": "4752454153452069732074686520776f7264"
        }
      },
      {
        "enriched_headers": {
          "header_block_len": 75,
          "headers": [
            {
              "name": ":status",
              "value": "400"
            },
            {
              "name": "server",
              "value": "cloudflare"
            },
            {
              "name": "date",
              "value": "Sat, 07 Dec 2024 00:34:12 GMT"
            },
            {
              "name": "content-type",
              "value": "text/html"
            },
            {
              "name": "content-length",
              "value": "155"
            },
            {
              "name": "cf-ray",
              "value": "8ee06dbe2923fa17-ORD"
            }
          ]
        }
      },
      {
        "DATA": {
          "payload_len": 104
        }
      },
      {
        "DATA": {
          "payload_len": 51
        }
      }
    ]
  },
  "stats": {
    "recv": 10,
    "sent": 5,
    "lost": 0,
    "retrans": 0,
    "sent_bytes": 1712,
    "recv_bytes": 4178,
    "lost_bytes": 0,
    "stream_retrans_bytes": 0,
    "paths_count": 1,
    "reset_stream_count_local": 0,
    "stopped_stream_count_local": 0,
    "reset_stream_count_remote": 0,
    "stopped_stream_count_remote": 0,
    "path_challenge_rx_count": 0
  },
  "path_stats": [
    {
      "local_addr": "0.0.0.0:64418",
      "peer_addr": "104.18.29.7:443",
      "active": true,
      "recv": 10,
      "sent": 5,
      "lost": 0,
      "retrans": 0,
      "rtt": 0.008140072,
      "min_rtt": 0.004645536,
      "rttvar": 0.004238173,
      "cwnd": 13500,
      "sent_bytes": 1712,
      "recv_bytes": 4178,
      "lost_bytes": 0,
      "stream_retrans_bytes": 0,
      "pmtu": 1350,
      "delivery_rate": 247720
    }
  ],
  "error": {
    "local_error": {
      "is_app": true,
      "error_code": 256,
      "reason": ""
    },
    "timed_out": false
  }
}
</code></pre>
            <p>Let’s walk through the output. Up first is the <a href="https://docs.rs/h3i/latest/h3i/client/connection_summary/struct.StreamMap.html"><u>StreamMap</u></a>, which is a record of all frames received on each stream. We can see that we received 5 frames on stream 0: 2 UNKNOWNs, one <a href="https://docs.rs/h3i/latest/h3i/frame/struct.EnrichedHeaders.html"><u>EnrichedHeaders</u></a> frame, and two DATA frames.</p><p>The UNKNOWN frames are extension frames that are unknown to h3i; the server under test is sending what are known as <a href="https://datatracker.ietf.org/doc/draft-edm-protocol-greasing/"><u>GREASE</u></a> frames to help exercise the protocol and ensure clients are not erroring when they receive something unexpected per <a href="https://datatracker.ietf.org/doc/html/rfc9114#extensions"><u>RFC 9114 requirements</u></a>.</p><p>The EnrichedHeaders frame is essentially an HTTP/3 HEADERS frame, but with some small helpers, like one to get the response status code. The server under test sent a 400 as expected.</p><p>The DATA frames carry response body bytes. In this case, the body is the HTML required to render the Cloudflare Bad Request page (you can peek at the HTML yourself in Wireshark). We chose to omit the raw bytes from the ConnectionSummary since they may not be representable safely as text. A future improvement could be to encode the bytes in base64 or hex, in order to support tests that need to check response content.</p>
    <div>
      <h2>h3i for test automation</h2>
      <a href="#h3i-for-test-automation">
        
      </a>
    </div>
    <p>We believe h3i is a great library for building automated tests on. You can take the above example and modify it to fit within various types of (continuous) integration tests.</p><p>We outlined earlier how the Protocols team HTTP/3 testing has organically grown to use three different frameworks. Even within those, we still didn't have much flexibility and ease of use. Over the last year we've been building h3i itself and reimplementing our suite of ingress proxy test cases using the Rust library. This has helped us improve test coverage with a range of new tests not previously possible. It also surprisingly identified some problems with the old tests, particularly for some edge cases where it wasn't clear how the old test code implementation was running under the hood.</p>
    <div>
      <h2>Bake offs, interop, and wider testing of HTTP</h2>
      <a href="#bake-offs-interop-and-wider-testing-of-http">
        
      </a>
    </div>
    <p><a href="https://datatracker.ietf.org/doc/html/rfc1025"><u>RFC 1025</u></a> was published in 1987. Authored by <a href="https://icannwiki.org/Jon_Postel"><u>Jon Postel</u></a>, it discusses bake offs:</p><blockquote><p><i>In the early days of the development of TCP and IP, when there were very few implementations and the specifications were still evolving, the only way to determine if an implementation was "correct" was to test it against other implementations and argue that the results showed your own implementation to have done the right thing.  These tests and discussions could, in those early days, as likely change the specification as change the implementation.</i></p><p><i>There were a few times when this testing was focused, bringing together all known implementations and running through a set of tests in hopes of demonstrating the N squared connectivity and correct implementation of the various tricky cases.  These events were called "Bake Offs".</i></p></blockquote><p>While nearly 4 decades old, the concept of exercising Internet protocol implementations and seeing how they compare to the specification still holds true. The QUIC WG made heavy use of interoperability testing through its standardization process. We started off sitting in a room and running tests manually by hand (or with some help from scripts). Then <a href="https://seemann.io/"><u>Marten Seemann</u></a> developed the <a href="https://interop.seemann.io/"><u>QUIC Interop Runner</u></a>, which runs regular automated testing and collects and renders all the results. This has proven to be incredibly useful.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OGnVUbatoX8Ya2IO5RdCl/754316e004a8e658ac089e10e70b72ca/image6.png" />
          </figure><p>The state of HTTP/3 interoperability testing is not quite as mature. Although there are tools such as <a href="https://kazu-yamamoto.hatenablog.jp/"><u>Kazu Yamamoto's</u></a> excellent <a href="https://github.com/kazu-yamamoto/h3spec"><u>h3spec</u></a> (in Haskell) for testing conformance, there isn't a similar continuous integration process of collection and rendering of results. While h3i shares similarities with h3spec, we felt it important to focus on the framework capabilities rather than creating a corpus of tests and assertions. Cloudflare is a big fan of Rust and as several teams move to Rust-based proxies, having a consistent ecosystem provides advantages (such as developer velocity).</p><p>We certainly feel there is a great opportunity for continued collaboration and cross-pollination between projects in the QUIC and HTTP space. For example, h3i might provide a suitable basis to build another tool (or set of scripts) to run bake offs or interop tests. Perhaps it even makes sense to have a common collection of test cases owned by the community, that can be specialized to the most appropriate or preferred tooling. This topic was recently presented at the <a href="https://github.com/HTTPWorkshop/workshop2024/blob/main/talks/5.%20Testing/testing.pdf"><u>HTTP Workshop 2024</u></a> by Mohammed Al-Sahaf, and it excites us to see <a href="https://www.caffeinatedwonders.com/2024/12/18/towards-validated-http-implementation/"><u>new potential directions</u></a> of testing improvements.</p><p>When using any tools or methods for protocol testing, we encourage responsible handling of security-related matters. If you believe you may have identified a vulnerability in an IETF Internet protocol itself, please follow the IETF's <a href="https://www.ietf.org/standards/rfcs/vulnerabilities/"><u>reporting guidance</u></a>. If you believe you may have discovered an implementation vulnerability in a product, open source project, or service using QUIC or HTTP, then you should report these directly to the responsible party. Implementers or operators often provide their own publicly-available guidance and contact details to send reports. For example, the Cloudflare quiche <a href="https://github.com/cloudflare/quiche/security/policy"><u>security policy</u></a> is available in the Security tab of the GitHub repository.</p>
    <div>
      <h2>Summary and outlook</h2>
      <a href="#summary-and-outlook">
        
      </a>
    </div>
    <p>Cloudflare takes testing very seriously. While h3i has a limited feature set as a test HTTP/3 client, we believe it provides a strong framework that can be extended to a wider range of different cases and different protocols. For example, we'd like to add support for low-level HTTP/2.</p><p>We've designed h3i to integrate into a wide range of testing methodologies, from manual ad-hoc testing, to native Rust tests, to conformance testbenches built with scripting languages. We've had great success migrating our existing zoo of test tools to a single one that is more accessible and easier to maintain.</p><p>Now that you've read about h3i's capabilities, it's left as an exercise to the reader to go back to the example of HTTP/3 control streams and consider how you could write tests to exercise a server.</p><p>We encourage the community to experiment with h3i and provide feedback, and propose ideas or contributions to the <a href="https://github.com/cloudflare/quiche"><u>GitHub repository</u></a> as issues or Pull Requests.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5rp4YDTbXm37OxK7dtjiKF/816c0eed08926b7d34842f4769808277/image4.png" />
          </figure><p></p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Testing]]></category>
            <category><![CDATA[Protocols]]></category>
            <category><![CDATA[Rust]]></category>
            <guid isPermaLink="false">2yX9ADcaKBprzyI9BaBoqN</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Evan Rittenhouse</dc:creator>
        </item>
        <item>
            <title><![CDATA[Zero Trust WARP: tunneling with a MASQUE]]></title>
            <link>https://blog.cloudflare.com/zero-trust-warp-with-a-masque/</link>
            <pubDate>Wed, 06 Mar 2024 14:00:15 GMT</pubDate>
            <description><![CDATA[ This blog discusses the introduction of MASQUE to Zero Trust WARP and how Cloudflare One customers will benefit from this modern protocol ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3gjB6Xaz5umz7Thed17Fb8/831d6d87a94f651c4f4803a6444d0f5c/image5-11.png" />
            
            </figure>
    <div>
      <h2>Slipping on the MASQUE</h2>
      <a href="#slipping-on-the-masque">
        
      </a>
    </div>
    <p>In June 2023, we <a href="/masque-building-a-new-protocol-into-cloudflare-warp/">told you</a> that we were building a new protocol, <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE</a>, into WARP. MASQUE is a fascinating protocol that extends the capabilities of <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> and leverages the unique properties of the QUIC transport protocol to efficiently proxy IP and UDP traffic without sacrificing performance or privacy</p><p>At the same time, we’ve seen a rising demand from <a href="https://www.cloudflare.com/learning/security/glossary/what-is-zero-trust/">Zero Trust</a> customers for features and solutions that only MASQUE can deliver. All customers want WARP traffic to look like HTTPS to avoid detection and blocking by firewalls, while a significant number of customers also require FIPS-compliant encryption. We have something good here, and it’s been proven elsewhere (more on that below), so we are building MASQUE into Zero Trust WARP and will be making it available to all of our Zero Trust customers — at WARP speed!</p><p>This blog post highlights some of the key benefits our Cloudflare One customers will realize with MASQUE.</p>
    <div>
      <h2>Before the MASQUE</h2>
      <a href="#before-the-masque">
        
      </a>
    </div>
    <p>Cloudflare is on a mission to help build a better Internet. And it is a journey we’ve been on with our device client and WARP for almost five years. The precursor to WARP was the 2018 launch of <a href="/announcing-1111/">1.1.1.1</a>, the Internet’s fastest, privacy-first consumer DNS service. WARP was introduced in 2019 with the <a href="/1111-warp-better-vpn/">announcement</a> of the 1.1.1.1 service with WARP, a high performance and secure consumer DNS and VPN solution. Then in 2020, we <a href="/introducing-cloudflare-for-teams">introduced</a> Cloudflare’s Zero Trust platform and the Zero Trust version of WARP to help any IT organization secure their environment, featuring a suite of tools we first built to protect our own IT systems. Zero Trust WARP with MASQUE is the next step in our journey.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1zi7uOkKEYkgp6dpBwQRo4/cb0147f0558ed92bb83a0f61a4ebbacc/image4-14.png" />
            
            </figure>
    <div>
      <h2>The current state of WireGuard</h2>
      <a href="#the-current-state-of-wireguard">
        
      </a>
    </div>
    <p><a href="https://www.wireguard.com/">WireGuard</a> was the perfect choice for the 1.1.1.1 with WARP service in 2019. WireGuard is fast, simple, and secure. It was exactly what we needed at the time to guarantee our users’ privacy, and it has met all of our expectations. If we went back in time to do it all over again, we would make the same choice.</p><p>But the other side of the simplicity coin is a certain rigidity. We find ourselves wanting to extend WireGuard to deliver more capabilities to our Zero Trust customers, but WireGuard is not easily extended. Capabilities such as better session management, advanced congestion control, or simply the ability to use FIPS-compliant cipher suites are not options within WireGuard; these capabilities would have to be added on as proprietary extensions, if it was even possible to do so.</p><p>Plus, while WireGuard is popular in VPN solutions, it is not standards-based, and therefore not treated like a first class citizen in the world of the Internet, where non-standard traffic can be blocked, sometimes intentionally, sometimes not. WireGuard uses a non-standard port, port 51820, by default. Zero Trust WARP changes this to use port 2408 for the WireGuard tunnel, but it’s still a non-standard port. For our customers who control their own firewalls, this is not an issue; they simply allow that traffic. But many of the large number of public Wi-Fi locations, or the approximately 7,000 ISPs in the world, don’t know anything about WireGuard and block these ports. We’ve also faced situations where the ISP does know what WireGuard is and blocks it intentionally.</p><p>This can play havoc for roaming Zero Trust WARP users at their local coffee shop, in hotels, on planes, or other places where there are captive portals or public Wi-Fi access, and even sometimes with their local ISP. The user is expecting reliable access with Zero Trust WARP, and is frustrated when their device is blocked from connecting to Cloudflare’s global network.</p><p>Now we have another proven technology — MASQUE — which uses and extends HTTP/3 and QUIC. Let’s do a quick review of these to better understand why Cloudflare believes MASQUE is the future.</p>
    <div>
      <h2>Unpacking the acronyms</h2>
      <a href="#unpacking-the-acronyms">
        
      </a>
    </div>
    <p>HTTP/3 and QUIC are among the most recent advancements in the evolution of the Internet, enabling faster, more reliable, and more secure connections to endpoints like websites and APIs. Cloudflare worked closely with industry peers through the <a href="https://www.ietf.org/">Internet Engineering Task Force</a> on the development of <a href="https://datatracker.ietf.org/doc/html/rfc9000">RFC 9000</a> for QUIC and <a href="https://datatracker.ietf.org/doc/html/rfc9114">RFC 9114</a> for HTTP/3. The technical background on the basic benefits of HTTP/3 and QUIC are reviewed in our 2019 blog post where we announced <a href="/http3-the-past-present-and-future/">QUIC and HTTP/3 availability</a> on Cloudflare’s global network.</p><p>Most relevant for Zero Trust WARP, QUIC delivers better performance on low-latency or high packet loss networks thanks to packet coalescing and multiplexing. QUIC packets in separate contexts during the handshake can be coalesced into the same UDP datagram, thus reducing the number of receive and system interrupts. With multiplexing, QUIC can carry multiple HTTP sessions within the same UDP connection. Zero Trust WARP also benefits from QUIC’s high level of privacy, with TLS 1.3 designed into the protocol.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ARWf5TO9CaOucOU527M2X/b53da149e40b8c28fc812552cfcaca26/image2-11.png" />
            
            </figure><p>MASQUE unlocks QUIC’s potential for proxying by providing the application layer building blocks to support efficient tunneling of TCP and UDP traffic. In Zero Trust WARP, MASQUE will be used to establish a tunnel over HTTP/3, delivering the same capability as WireGuard tunneling does today. In the future, we’ll be in position to add more value using MASQUE, leveraging Cloudflare’s ongoing participation in the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE Working Group</a>. This blog post is a good read for those interested in <a href="/unlocking-quic-proxying-potential/">digging deeper into MASQUE</a>.</p><p>OK, so Cloudflare is going to use MASQUE for WARP. What does that mean to you, the Zero Trust customer?</p>
    <div>
      <h2>Proven reliability at scale</h2>
      <a href="#proven-reliability-at-scale">
        
      </a>
    </div>
    <p>Cloudflare’s network today spans more than 310 cities in over 120 countries, and interconnects with over 13,000 networks globally. HTTP/3 and QUIC were introduced to the Cloudflare network in 2019, the HTTP/3 standard was <a href="/cloudflare-view-http3-usage/">finalized in 2022</a>, and represented about <a href="https://radar.cloudflare.com/adoption-and-usage?dateStart=2023-01-01&amp;dateEnd=2023-12-31#http-1x-vs-http-2-vs-http-3">30% of all HTTP traffic on our network in 2023</a>.</p><p>We are also using MASQUE for <a href="/icloud-private-relay/">iCloud Private Relay</a> and other Privacy Proxy partners. The services that power these partnerships, from our Rust-based <a href="/introducing-oxy/">proxy framework</a> to our open source <a href="https://github.com/cloudflare/quiche">QUIC implementation</a>, are already deployed globally in our network and have proven to be fast, resilient, and reliable.</p><p>Cloudflare is already operating MASQUE, HTTP/3, and QUIC reliably at scale. So we want you, our Zero Trust WARP users and Cloudflare One customers, to benefit from that same reliability and scale.</p>
    <div>
      <h2>Connect from anywhere</h2>
      <a href="#connect-from-anywhere">
        
      </a>
    </div>
    <p>Employees need to be able to connect from anywhere that has an Internet connection. But that can be a challenge as many security engineers will configure firewalls and other networking devices to block all ports by default, and only open the most well-known and common ports. As we pointed out earlier, this can be frustrating for the roaming Zero Trust WARP user.</p><p>We want to fix that for our users, and remove that frustration. HTTP/3 and QUIC deliver the perfect solution. QUIC is carried on top of UDP (<a href="https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml">protocol number 17</a>), while HTTP/3 uses <a href="https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml">port 443</a> for encrypted traffic. Both of these are well known, widely used, and are very unlikely to be blocked.</p><p>We want our Zero Trust WARP users to reliably connect wherever they might be.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/53RZc92rNIUWscFuLuA13w/098b18464be4ee893d51786ff74a5bc4/image1-13.png" />
            
            </figure>
    <div>
      <h2>Compliant cipher suites</h2>
      <a href="#compliant-cipher-suites">
        
      </a>
    </div>
    <p>MASQUE leverages <a href="https://datatracker.ietf.org/doc/html/rfc8446">TLS 1.3</a> with QUIC, which provides a number of cipher suite choices. WireGuard also uses standard cipher suites. But some standards are more, let’s say, standard than others.</p><p>NIST, the <a href="https://www.nist.gov/">National Institute of Standards and Technology</a> and part of the US Department of Commerce, does a tremendous amount of work across the technology landscape. Of interest to us is the NIST research into network security that results in <a href="https://csrc.nist.gov/pubs/fips/140-2/upd2/final">FIPS 140-2</a> and similar publications. NIST studies individual cipher suites and publishes lists of those they recommend for use, recommendations that become requirements for US Government entities. Many other customers, both government and commercial, use these same recommendations as requirements.</p><p>Our first MASQUE implementation for Zero Trust WARP will use <a href="https://www.cloudflare.com/learning/ssl/why-use-tls-1.3/">TLS 1.3</a> and FIPS compliant cipher suites.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/25Qc8qdJd78bngZqpH0Pv7/1541929144b5ed4d85ccca36e0787957/image3-12.png" />
            
            </figure>
    <div>
      <h2>How can I get Zero Trust WARP with MASQUE?</h2>
      <a href="#how-can-i-get-zero-trust-warp-with-masque">
        
      </a>
    </div>
    <p>Cloudflare engineers are hard at work implementing MASQUE for the mobile apps, the desktop clients, and the Cloudflare network. Progress has been good, and we will open this up for beta testing early in the second quarter of 2024 for Cloudflare One customers. Your account team will be reaching out with participation details.</p>
    <div>
      <h2>Continuing the journey with Zero Trust WARP</h2>
      <a href="#continuing-the-journey-with-zero-trust-warp">
        
      </a>
    </div>
    <p>Cloudflare launched WARP five years ago, and we’ve come a long way since. This introduction of MASQUE to Zero Trust WARP is a big step, one that will immediately deliver the benefits noted above. But there will be more — we believe MASQUE opens up new opportunities to leverage the capabilities of QUIC and HTTP/3 to build innovative <a href="https://www.cloudflare.com/zero-trust/solutions/">Zero Trust solutions</a>. And we’re also continuing to work on other new capabilities for our Zero Trust customers.Cloudflare is committed to continuing our mission to help build a better Internet, one that is more private and secure, scalable, reliable, and fast. And if you would like to join us in this exciting journey, check out our <a href="https://www.cloudflare.com/careers/jobs/">open positions</a>.</p> ]]></content:encoded>
            <category><![CDATA[Security Week]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Cloudflare Access]]></category>
            <category><![CDATA[Better Internet]]></category>
            <category><![CDATA[WARP]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[TLS 1.3]]></category>
            <category><![CDATA[Privacy]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[1.1.1.1]]></category>
            <guid isPermaLink="false">5sDoFBGGZJbT4D9pftVhXY</guid>
            <dc:creator>Dan Hall</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing HTTP/3 Prioritization]]></title>
            <link>https://blog.cloudflare.com/better-http-3-prioritization-for-a-faster-web/</link>
            <pubDate>Tue, 20 Jun 2023 13:00:46 GMT</pubDate>
            <description><![CDATA[ Today, Cloudflare is very excited to announce full support for HTTP/3 Extensible Priorities, a new standard that speeds the loading of webpages by up to 37% ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5WMquEFDro1TjSvsKvdb2X/1ebf5bacb443b2c7c611b2600cfe1352/image4-9.png" />
            
            </figure><p>Today, Cloudflare is very excited to announce full support for HTTP/3 Extensible Priorities, a new standard that speeds the loading of webpages by up to 37%. Cloudflare worked closely with standards builders to help form the specification for HTTP/3 priorities and is excited to help push the web forward. HTTP/3 Extensible Priorities is available on all plans on Cloudflare. For paid users, there is an enhanced version available that improves performance even more.</p><p>Web pages are made up of many objects that must be downloaded before they can be processed and presented to the user. Not all objects have equal importance for web performance. The role of HTTP prioritization is to load the right bytes at the most opportune time, to achieve the best results. Prioritization is most important when there are multiple objects all competing for the same constrained resource. In <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>, this resource is the QUIC connection. In most cases, bandwidth is the bottleneck from server to client. Picking what objects to dedicate bandwidth to, or share bandwidth amongst, is a critical foundation to web performance. When it goes askew, the other optimizations we build on top can suffer.</p><p>Today, we're announcing support for prioritization in HTTP/3, using the full capabilities of the HTTP Extensible Priorities (<a href="https://www.rfc-editor.org/rfc/rfc9218.html">RFC 9218)</a> standard, augmented with Cloudflare's knowledge and experience of enhanced HTTP/2 prioritization. This change is compatible with all mainstream web browsers and can improve key metrics such as <a href="https://web.dev/lcp/">Largest Contentful Paint</a> (LCP) by up to 37% in our test. Furthermore, site owners can apply server-side overrides, using Cloudflare Workers or directly from an origin, to customize behavior for their specific needs.</p>
    <div>
      <h3>Looking at a real example</h3>
      <a href="#looking-at-a-real-example">
        
      </a>
    </div>
    <p>The ultimate question when it comes to features like HTTP/3 Priorities is: how well does this work and should I turn it on? The details are interesting and we'll explain all of those shortly but first lets see some demonstrations.</p><p>In order to evaluate prioritization for HTTP/3, we have been running many simulations and tests. Each web page is unique. Loading a web page can require many TCP or QUIC connections, each of them idiosyncratic. These all affect how prioritization works and how effective it is.</p><p>To evaluate the effectiveness of priorities, we ran a set of tests measuring Largest Contentful Paint (LCP). As an example, we benchmarked blog.cloudflare.com to see how much we could improve performance:</p><div></div>
<p></p><p>As a film strip, this is what it looks like:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1nUzro5TRNUdT66D48SAX9/eea3706754ab1adcdcf2de1520b4e8b2/unnamed.png" />
            
            </figure><p>In terms of actual numbers, we see Largest Contentful Paint drop from 2.06 seconds down to 1.29 seconds. Let’s look at why that is. To analyze exactly what’s going on we have to look at a waterfall diagram of how this web page is loading. A waterfall diagram is a way of visualizing how assets are loading. Some may be loaded in parallel whilst some might be loaded sequentially. Without smart prioritization, the waterfall for loading assets for this web page looks as follows:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7GEe1xRnxvauMVfOKy5KH2/ab43c1561d3d512589a6de0b063419a1/BLOG-1879-waterfall-analysis-2.png" />
            
            </figure><p>There are several interesting things going on here so let's break it down. The LCP image at request 21 is for 1937-1.png, weighing 30.4 KB. Although it is the LCP image, the browser requests it as priority u=3,i, which informs the server to put it in the same round-robin bandwidth-sharing bucket with all of the other images. Ahead of the LCP image is index.js, a JavaScript file that is loaded with a "defer" attribute. This JavaScript is non-blocking and shouldn't affect key aspects of page layout.</p><p>What appears to be happening is that the browser gives index.js the priority u=3,i=?0, which places it ahead of the images group on the server-side. Therefore, the 217 KB of index.js is sent in preference to the LCP image. Far from ideal. Not only that, once the script is delivered, it needs to be processed and executed. This saturates the CPU and prevents the LCP image from being painted, for about 300 milliseconds, even though it was delivered already.</p><p>The waterfall with prioritization looks much better:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Y2mU3vMrf4DVgI6Cq7CSv/980f93870fee27984d40dd310ee38c8d/BLOG-1879-waterfall-analysis-1.png" />
            
            </figure><p>We used a server-side override to promote the priority of the LCP image 1937-1.png from u=3,i to u=2,i. This has the effect of making it leapfrog the "defer" JavaScript. We can see at around 1.2 seconds, transmission of index.js is halted while the image is delivered in full. And because it takes another couple of hundred milliseconds to receive the remaining JavaScript, there is no CPU competition for the LCP image paint. These factors combine together to drastically improve LCP times.</p>
    <div>
      <h3>How Extensible Priorities actually works</h3>
      <a href="#how-extensible-priorities-actually-works">
        
      </a>
    </div>
    <p>First of all, you don't need to do anything yourselves to make it work. Out of the box, browsers will send Extensible Priorities signals alongside HTTP/3 requests, which we'll feed into our priority scheduling decision making algorithms. We'll then decide the best way to send HTTP/3 response data to ensure speedy page loads.</p><p>Extensible Priorities has a similar interaction model to HTTP/2 priorities, client send priorities and servers act on them to schedule response data, we'll explain exactly how that works in a bit.</p><p>HTTP/2 priorities used a dependency tree model. While this was very powerful it turned out hard to implement and use. When the IETF came to try and port it to HTTP/3 during the standardization process, we hit major issues. If you are interested in all that background, go and read my blog post describing why we adopted a <a href="/adopting-a-new-approach-to-http-prioritization/">new approach to HTTP/3 prioritization</a>.</p><p>Extensible Priorities is a far simpler scheme. HTTP/2's dependency tree with 255 weights and dependencies (that can be mutual or exclusive) is complex, hard to use as a web developer and could not work for HTTP/3. Extensible Priorities has just two parameters: urgency and incremental, and these are capable of achieving exactly the same web performance goals.</p><p>Urgency is an integer value in the range 0-7. It indicates the importance of the requested object, with 0 being most important and 7 being the least. The default is 3. Urgency is comparable to HTTP/2 weights. However, it's simpler to reason about 8 possible urgencies rather than 255 weights. This makes developer's lives easier when trying to pick a value and predicting how it will work in practice.</p><p>Incremental is a boolean value. The default is false. A true value indicates the requested object can be processed as parts of it are received and read - commonly referred to as streaming processing. A false value indicates the object must be received in whole before it can be processed.</p><p>Let's consider some example web objects to put these parameters into perspective:</p><ul><li><p>An HTML document is the most important piece of a webpage. It can be processed as parts of it arrive. Therefore, urgency=0 and incremental=true is a good choice.</p></li><li><p>A CSS style is important for page rendering and could block visual completeness. It needs to be processed in whole. Therefore, urgency=1 and incremental=false is suitable, this would mean it doesn't interfere with the HTML.</p></li><li><p>An image file that is outside the browser viewport is not very important and it can be processed and painted as parts arrive. Therefore, urgency=3 and incremental=true is appropriate to stop it interfering with sending other objects.</p></li><li><p>An image file that is the "hero image" of the page, making it the Largest Contentful Pain element. An urgency of 1 or 2 will help it avoid being mixed in with other images. The choice of incremental value is a little subjective and either might be appropriate.</p></li></ul><p>When making an HTTP request, clients decide the Extensible Priority value composed of the urgency and incremental parameters. These are sent either as an HTTP header field in the request (meaning inside the HTTP/3 HEADERS frame on a request stream), or separately in an HTTP/3 PRIORITY_UPDATE frame on the control stream. HTTP headers are sent once at the start of a request; a client might change its mind so the PRIORITY_UPDATE frame allows it to reprioritize at any point in time.</p><p>For both the header field and PRIORITY_UPDATE, the parameters are exchanged using the Structured Fields Dictionary format (<a href="https://www.rfc-editor.org/info/rfc8941">RFC 8941</a>) and serialization rules. In order to save bytes on the wire, the parameters are shortened – urgency to 'u', and incremental to 'i'.</p><p>Here's how the HTTP header looks alongside a GET request for important HTML, using HTTP/3 style notation:</p>
            <pre><code>HEADERS:
    :method = GET
    :scheme = https
    :authority = example.com
    :path = /index.html
     priority = u=0,i</code></pre>
            <p>The PRIORITY_UPDATE frame only carries the serialized Extensible Priority value:</p>
            <pre><code>PRIORITY_UPDATE:
    u=0,i</code></pre>
            <p>Structured Fields has some other neat tricks. If you want to indicate the use of a default value, then that can be done via omission. Recall that the urgency default is 3, and incremental default is false. A client could send "u=1" alongside our important CSS request (urgency=1, incremental=false). For our lower priority image it could send just "i=?1" (urgency=3, incremental=true). There's even another trick, where boolean true dictionary parameters are sent as just "i". You should expect all of these formats to be used in practice, so it pays to be mindful about their meaning.</p><p>Extensible Priority servers need to decide how best to use the available connection bandwidth to schedule the response data bytes. When servers receive priority client signals, they get one form of input into a decision making process. RFC 9218 provides a set of <a href="https://www.rfc-editor.org/rfc/rfc9218.html#name-server-scheduling">scheduling recommendations</a> that are pretty good at meeting a board set of needs. These can be distilled down to some golden rules.</p><p>For starters, the order of requests is crucial. Clients are very careful about asking for things at the moment they want it. Serving things in request order is good. In HTTP/3, because there is no strict ordering of stream arrival, servers can use stream IDs to determine this. Assuming the order of the requests is correct, the next most important thing is urgency ordering. Serving according to urgency values is good.</p><p>Be wary of non-incremental requests, as they mean the client needs the object in full before it can be used at all. An incremental request means the client can process things as and when they arrive.</p><p>With these rules in mind, the scheduling then becomes broadly: for each urgency level, serve non-incremental requests in whole serially, then serve incremental requests in round robin fashion in parallel. What this achieves is dedicated bandwidth for very important things, and shared bandwidth for less important things that can be processed or rendered progressively.</p><p>Let's look at some examples to visualize the different ways the scheduler can work. These are generated by using <a href="https://github.com/cloudflare/quiche">quiche's</a> <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/">qlog</a> support and running it via the <a href="https://qvis.quictools.info/">qvis</a> analysis tool. These diagrams are similar to a waterfall chart; the y-dimension represents stream IDs (0 at the top, increasing as we move down) and the x-dimension shows reception of stream data.</p><p>Example 1: all streams have the same urgency and are non-incremental so get served in serial order of stream ID.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2mzTrM4iI9h7uEJXa2TOuT/40d1ba7c1d13949107d68a2e1fb5398f/u-same.png" />
            
            </figure><p>Example 2: the streams have the same urgency and are incremental so get served in round-robin fashion.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1V44aLuoHvqxR4gpETKJ2x/fdb8ddb148353333b4aaceff11858ff6/u-same-i.png" />
            
            </figure><p>Example 3: the streams have all different urgency, with later streams being more important than earlier streams. The data is received serially but in a reverse order compared to example 1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2koT4ij8bzGMc06OVNIFGZ/26572e5bffa63b588860050e005fe64e/u-reversed.png" />
            
            </figure><p>Beyond the Extensible Priority signals, a server might consider other things when scheduling, such as file size, content encoding, how the application vs content origins are configured etc.. This was true for HTTP/2 priorities but Extensible Priorities introduces a new neat trick, a priority signal can also be sent as a response header to override the client signal.</p><p>This works especially well in a proxying scenario where your HTTP/3 terminating proxy is sat in front of some backend such as Workers. The proxy can pass through the request headers to the backend, it can inspect these and if it wants something different, return response headers to the proxy. This allows powerful tuning possibilities and because we operate on a semantic request basis (rather than HTTP/2 priorities dependency basis) we don't have all the complications and dangers. Proxying isn't the only use case. Often, one form of "API" to your local server is via setting response headers e.g., via configuration. Leveraging that approach means we don't have to invent new APIs.</p><p>Let's consider an example where server overrides are useful. Imagine we have a webpage with multiple images that are referenced via  tags near the top of the HTML. The browser will process these quite early in the page load and want to issue requests. At this point, <b>it might not know enough</b> about the page structure to determine if an image is in the viewport or outside the viewport. It can guess, but that might turn out to be wrong if the page is laid out a certain way. Guessing wrong means that something is misprioritized and might be taking bandwidth away from something that is more important. While it is possible to reprioritize things mid-flight using the PRIORITY_UPDATE frame, this action is "laggy" and by the time the server realizes things, it might be too late to make much difference.</p><p>Fear not, the web developer who built the page knows exactly how it is supposed to be laid out and rendered. They can overcome client uncertainty by overriding the Extensible Priority when they serve the response. For instance, if a client guesses wrong and requests the LCP image at a low priority in a shared bandwidth bucket, the image will load slower and web performance metrics will be adversely affected. Here's how it might look and how we can fix it:</p>
            <pre><code>Request HEADERS:
    :method = GET
    :scheme = https
    :authority = example.com
    :path = /lcp-image.jpg
     priority = u=3,i</code></pre>
            
            <pre><code>Response HEADERS:
:status = 200
content-length: 10000
content-type: image/jpeg
priority = u=2</code></pre>
            <p>Priority response headers are one tool to tweak client behavior and they are complementary to other web performance techniques. Methods like efficiently ordering elements in HTML, using attributes like "async" or "defer", augmenting HTML links with Link headers, or using more descriptive link relationships like “<a href="https://html.spec.whatwg.org/multipage/links.html#link-type-preload">preload</a>” all help to improve a browser's understanding of the resources comprising a page. A website that optimizes these things provides a better chance for the browser to make the best choices for prioritizing requests.</p><p>More recently, a new attribute called “<a href="https://web.dev/fetch-priority/">fetchpriority</a>” has emerged that allows developers to tune some of the browser behavior, by boosting or dropping the priority of an element relative to other elements of the same type. The attribute can help the browser do two important things for Extensible priorities: first, the browser might send the request earlier or later, helping to satisfy our golden rule #1 - ordering. Second, the browser might pick a different urgency value, helping to satisfy rule #2. However, "fetchpriority" is a nudge mechanism and it doesn't allow for directly setting a desired priority value. The nudge can be a bit opaque. Sometimes the circumstances benefit greatly from just knowing plainly what the values are and what the server will do, and that's where the response header can help.</p>
    <div>
      <h3>Conclusions</h3>
      <a href="#conclusions">
        
      </a>
    </div>
    <p>We’re excited about bringing this new standard into the world. Working with standards bodies has always been an amazing partnership and we’re very pleased with the results. We’ve seen great results with HTTP/3 priorities, reducing Largest Contentful Paint by up to 37% in our test. We’ll be rolling this feature out over the next few weeks as part of the HTTP Priorities feature for HTTP/2 that’s already available today.</p> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[QUIC]]></category>
            <guid isPermaLink="false">3sxwiYeGEwXXvE9ltToeUB</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Achiel van der Mandele</dc:creator>
        </item>
        <item>
            <title><![CDATA[Examining HTTP/3 usage one year on]]></title>
            <link>https://blog.cloudflare.com/http3-usage-one-year-on/</link>
            <pubDate>Tue, 06 Jun 2023 13:00:20 GMT</pubDate>
            <description><![CDATA[ With the HTTP/3 RFC celebrating its 1st birthday, we examined HTTP version usage trends between May 2022 - May 2023. We found that HTTP/3 usage by browsers continued to grow, but that search engine and social media bots continued to effectively ignore the latest version of the web’s core protocol ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3fGsSPUCSxABWlwpC5HfdV/ca7cf03337e600bd768b8acc7d06de36/image11-1.png" />
            
            </figure><p>In June 2022, after the publication of a set of HTTP-related Internet standards, including the <a href="https://www.rfc-editor.org/rfc/rfc9114.html">RFC that formally defined HTTP/3</a>, we published <a href="/cloudflare-view-http3-usage/"><i>HTTP RFCs have evolved: A Cloudflare view of HTTP usage trends</i></a>. One year on, as the RFC reaches its first birthday, we thought it would be interesting to look back at how these trends have evolved over the last year.</p><p>Our previous post reviewed usage trends for <a href="https://datatracker.ietf.org/doc/html/rfc9112">HTTP/1.1</a>, <a href="https://datatracker.ietf.org/doc/html/rfc9113">HTTP/2</a>, and <a href="https://datatracker.ietf.org/doc/html/rfc9114">HTTP/3</a> observed across Cloudflare’s network between May 2021 and May 2022, broken out by version and browser family, as well as for search engine indexing and social media bots. At the time, we found that browser-driven traffic was overwhelmingly using HTTP/2, although HTTP/3 usage was showing signs of growth. Search and social bots were mixed in terms of preference for <a href="https://www.cloudflare.com/learning/performance/http2-vs-http1.1/">HTTP/1.1 vs. HTTP/2</a>, with little-to-no HTTP/3 usage seen.</p><p>Between May 2022 and May 2023, we found that HTTP/3 usage in browser-retrieved content continued to grow, but that search engine indexing and social media bots continued to effectively ignore the latest version of the web’s core protocol. (Having said that, <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">the benefits of HTTP/3</a> are very user-centric, and arguably offer minimal benefits to bots designed to asynchronously crawl and index content. This may be a key reason that we see such low adoption across these automated user agents.) In addition, HTTP/3 usage across API traffic is still low, but doubled across the year. Support for HTTP/3 is on by default for zones using Cloudflare’s free tier of service, while paid customers have the option to activate support.</p><p>HTTP/1.1 and HTTP/2 use TCP as a transport layer and add security via <a href="https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/">TLS</a>. HTTP/3 uses QUIC to provide both the transport layer and security. Due to the difference in transport layer, user agents usually require learning that an origin is accessible using HTTP/3 before they'll try it. One method of discovery is <a href="https://httpwg.org/specs/rfc7838.html">HTTP Alternative Services</a>, where servers return an Alt-Svc response header containing a list of supported <a href="https://developer.mozilla.org/en-US/docs/Glossary/ALPN">Application-Layer Protocol Negotiation Identifiers (ALPN IDs)</a>. Another method is the <a href="/speeding-up-https-and-http-3-negotiation-with-dns/">HTTPS record type</a>, where clients query the DNS to learn the supported ALPN IDs. The ALPN ID for HTTP/3 is "h3" but while the specification was in development and iteration, we added a suffix to identify the particular draft version e.g., "h3-29" identified <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-29">draft 29</a>. In order to maintain compatibility for a wide range of clients, Cloudflare advertised both "h3" and "h3-29". However, draft 29 was published close to three years ago and clients have caught up with support for the final RFC. As of late May 2023, Cloudflare no longer advertises h3-29 for zones that have HTTP/3 enabled, helping to save several bytes on each HTTP response or <a href="https://www.cloudflare.com/learning/dns/dns-records/">DNS record</a> that would have included it. Because a browser and web server typically automatically negotiate the highest HTTP version available, HTTP/3 takes precedence over HTTP/2.</p><p>In the sections below, “likely automated” and “automated” traffic based on <a href="https://developers.cloudflare.com/bots/concepts/bot-score/">Cloudflare bot score</a> has been filtered out for desktop and mobile browser analysis to restrict analysis to “likely human” traffic, but it is included for the search engine and social media bot analysis. In addition, references to HTTP requests or HTTP traffic below include requests made over both HTTP and HTTPS.</p>
    <div>
      <h3>Overall request distribution by HTTP version</h3>
      <a href="#overall-request-distribution-by-http-version">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/BD7nhUhMqEAKHE3lw7Ucs/1230d8393a90c5a431398edccac2b6c2/download-3.png" />
            
            </figure><p>Aggregating global web traffic to Cloudflare on a daily basis, we can observe usage trends for HTTP/1.1, HTTP/2, and HTTP/3 across the surveyed one year period. The share of traffic over HTTP/1.1 declined from 8% to 7% between May and the end of September, but grew rapidly to over 11% through October. It stayed elevated into the new year and through January, dropping back down to 9% by May 2023. Interestingly, the weekday/weekend traffic pattern became more pronounced after the October increase, and remained for the subsequent six months. HTTP/2 request share saw nominal change over the year, beginning around 68% in May 2022, but then starting to decline slightly in June. After that, its share didn’t see a significant amount of change, ending the period just shy of 64%. No clear weekday/weekend pattern was visible for HTTP/2. Starting with just over 23% share in May 2022, the percentage of requests over HTTP/3 grew to just over 30% by August and into September, but dropped to around 26% by November. After some nominal loss and growth, it ended the surveyed time period at 28% share. (Note that this graph begins in late May due to data retention limitations encountered when generating the graph in early June.)</p>
    <div>
      <h3>API request distribution by HTTP version</h3>
      <a href="#api-request-distribution-by-http-version">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1iKB6A5jGKVMBcaRAYckjv/47b7777093a2cad492060224a8257601/download--1--2.png" />
            
            </figure><p>Although <a href="/application-security-2023/">API traffic</a> makes up a significant amount of Cloudflare’s request volume, only a small fraction of those requests are made over HTTP/3. Approximately half of such requests are made over HTTP/1.1, with another third over HTTP/2. However, HTTP/3 usage for APIs grew from around 6% in May 2022 to over 12% by May 2023. HTTP/3’s smaller share of traffic is likely due in part to support for HTTP/3 in key tools like <a href="https://curl.se/docs/http3.html">curl</a> still being considered as “experimental”. Should this change in the future, with HTTP/3 gaining first-class support in such tools, we expect that this will accelerate growth in HTTP/3 usage, both for <a href="https://www.cloudflare.com/learning/security/api/what-is-an-api/">APIs</a> and overall as well.</p>
    <div>
      <h3>Mitigated request distribution by HTTP version</h3>
      <a href="#mitigated-request-distribution-by-http-version">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4J6wSXALudeaeZNzxvgRBo/6614895278f32528664d3f1444402350/download--2--2.png" />
            
            </figure><p>The analyses presented above consider all HTTP requests made to Cloudflare, but we also thought that it would be interesting to look at HTTP version usage by potentially malicious traffic, so we broke out just those requests that were mitigated by one of Cloudflare’s application security solutions. The graph above shows that the vast majority of mitigated requests are made over HTTP/1.1 and HTTP/2, with generally less than 5% made over HTTP/3. Mitigated requests appear to be most frequently made over HTTP/1.1, although HTTP/2 accounted for a larger share between early August and late November. These observations suggest that attackers don’t appear to be investing the effort to upgrade their tools to take advantage of the newest version of HTTP, finding the older versions of the protocol sufficient for their needs. (Note that this graph begins in late May 2022 due to data retention limitations encountered when generating the graph in early June 2023.)</p>
    <div>
      <h3>HTTP/3 use by desktop browser</h3>
      <a href="#http-3-use-by-desktop-browser">
        
      </a>
    </div>
    <p>As we noted last year, <a href="https://caniuse.com/http3">support for HTTP/3 in the stable release channels of major browsers</a> came in November 2020 for Google Chrome and Microsoft Edge, and April 2021 for Mozilla Firefox. We also noted that in Apple Safari, HTTP/3 support needed to be <a href="https://developer.apple.com/forums/thread/660516">enabled</a> in the “Experimental Features” developer menu in production releases. However, in the most recent releases of Safari, it appears that this step is no longer necessary, and that HTTP/3 is now natively supported.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/46nLEn3t41yyWfhZkznaEa/29c5b7bfa59b34f55977cc65ad67c2bf/download--3--2.png" />
            
            </figure><p>Looking at request shares by browser, Chrome started the period responsible for approximately 80% of HTTP/3 request volume, but the continued growth of Safari dropped it to around 74% by May 2023. A year ago, Safari represented less than 1% of HTTP/3 traffic on Cloudflare, but grew to nearly 7% by May 2023, likely as a result of support graduating from experimental to production.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7L26q8bA4sjcNlx7Vh0ohL/667061d148ccbaa0043cd3fd1e38a879/download--4--2.png" />
            
            </figure><p>Removing Chrome from the graph again makes trends across the other browsers more visible. As noted above, Safari experienced significant growth over the last year, while Edge saw a bump from just under 10% to just over 11% in June 2022. It stayed around that level through the new year, and then gradually dropped below 10% over the next several months. Firefox dropped slightly, from around 10% to just under 9%, while reported HTTP/3 traffic from Internet Explorer was near zero.</p><p>As we did in last year’s post, we also wanted to look at how the share of HTTP versions has changed over the last year across each of the leading browsers. The relative stability of HTTP/2 and HTTP/3 seen over the last year is in some contrast to the observations made in last year’s post, which saw some noticeable shifts during the May 2021 - May 2022 timeframe.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3bt30ch54tIJHXIcA4xzNo/ae9bf1593781da888f4c4843ac379465/download--5--1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/CRgOGynraOznE7gu7AFjM/ec94e0c8be1b4ec2fb4f9f8f0a715cb0/download--6--1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3AbRtdFXbJ43Xli6w0jVJN/ad597050da4a948d41a9b275c3752d96/download--7-.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/GgWSo7NP45FZffpsqScv1/e269f55f5b59402ad771a065196b3d59/download--8-.png" />
            
            </figure><p>In looking at request share by protocol version across the major desktop browser families, we see that across all of them, HTTP/1.1 share grows in late October. Further analysis indicates that this growth was due to significantly higher HTTP/1.1 request volume across several large customer zones, but it isn’t clear <b>why</b> this influx of traffic using an older version of HTTP occurred. It is clear that HTTP/2 remains the dominant protocol used for content requests by the major browsers, consistently accounting for 50-55% of request volume for Chrome and Edge, and ~60% for Firefox. However, for Safari, HTTP/2’s share dropped from nearly 95% in May 2022 to around 75% a year later, thanks to the growth in HTTP/3 usage.</p><p>HTTP/3 share on Safari grew from under 3% to nearly 18% over the course of the year, while its share on the other browsers was more consistent, with Chrome and Edge hovering around 40% and Firefox around 35%, and both showing pronounced weekday/weekend traffic patterns. (That pattern is arguably the most pronounced for Edge.) Such a pattern becomes more, yet still barely, evident with Safari in late 2022, although it tends to vary by less than a percent.</p>
    <div>
      <h3>HTTP/3 usage by mobile browser</h3>
      <a href="#http-3-usage-by-mobile-browser">
        
      </a>
    </div>
    <p>Mobile devices are responsible for <a href="https://radar.cloudflare.com/traffic?range=28d">over half</a> of request volume to Cloudflare, with Chrome Mobile <a href="https://radar.cloudflare.com/adoption-and-usage?range=28d">generating</a> more than 25% of all requests, and Mobile Safari more than 10%. Given this, we decided to explore HTTP/3 usage across these two key mobile platforms.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6gEIDgm3aTtDYNZj0GD5bS/3728f1ff9a6790b44f66deec6101871c/download--9-.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6a0By0cXENGpNbqV1BQB7G/5ddbdae331642235f4395c0972e8121e/download--10-.png" />
            
            </figure><p>Looking at Chrome Mobile and Chrome Mobile Webview (an embeddable version of Chrome that applications can use to display Web content), we find HTTP/1.1 usage to be minimal, topping out at under 5% of requests. HTTP/2 usage dropped from 60% to just under 55% between May and mid-September, but then bumped back up to near 60%, remaining essentially flat to slightly lower through the rest of the period. In a complementary fashion, HTTP/3 traffic increased from 37% to 45%, before falling just below 40% in mid-September, hovering there through May. The usage patterns ultimately look very similar to those seen with desktop Chrome, albeit without the latter’s clear weekday/weekend traffic pattern.</p><p>Perhaps unsurprisingly, the usage patterns for Mobile Safari and Mobile Safari Webview closely mirror those seen with desktop Safari. HTTP/1.1 share increases in October, and HTTP/3 sees strong growth, from under 3% to nearly 18%.</p>
    <div>
      <h3>Search indexing bots</h3>
      <a href="#search-indexing-bots">
        
      </a>
    </div>
    <p>Exploring usage of the various versions of HTTP by <a href="https://www.cloudflare.com/learning/bots/what-is-a-web-crawler/">search engine crawlers/bots</a>, we find that last year’s trend continues, and that there remains little-to-no usage of HTTP/3. (As mentioned above, this is somewhat expected, as HTTP/3 is optimized for browser use cases.) Graphs for Bing &amp; Baidu here are trimmed to a period ending April 1, 2023 due to anomalous data during April that is being investigated.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2zpXgMRgxrsctpJHrIShZC/ca5830878f4a328f0ee98ea5afdd883b/download--11-.png" />
            
            </figure><p>GoogleBot continues to rely primarily on HTTP/1.1, which generally comprises 55-60% of request volume. The balance is nearly all HTTP/2, although some nominal growth in HTTP/3 usage sees it peaking at just under 2% in March.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/415sWhtv1TxuyQJgW95wq4/a4340af637f9dbc42f25b3d81f61f356/download--12-.png" />
            
            </figure><p>Through January 2023, around 85% of requests from Microsoft’s BingBot were made via HTTP/2, but dropped to closer to 80% in late January. The balance of the requests were made via HTTP/1.1, as HTTP/3 usage was negligible.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2EP2wiznT1eIlRB7rwDQZB/6a2ffcda96dbc4a77f85d4866453aea0/download--13-.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7BxyzvnZnL8rWgIpIcEh9D/63cd123faeb6e9795b3766082b918b1a/download--14-.png" />
            
            </figure><p>Looking at indexing bots from search engines based outside of the United States, Russia’s YandexBot appears to use HTTP/1.1 almost exclusively, with HTTP/2 usage generally around 1%, although there was a period of increased usage between late August and mid-November. It isn’t clear what ultimately caused this increase. There was no meaningful request volume seen over HTTP/3. The indexing bot used by Chinese search engine Baidu also appears to strongly prefer HTTP/1.1, generally used for over 85% of requests. However, the percentage of requests over HTTP/2 saw a number of spikes, briefly reaching over 60% on days in July, November, and December 2022, as well as January 2023, with several additional spikes in the 30% range. Again, it isn’t clear what caused this spiky behavior. HTTP/3 usage by BaiduBot is effectively non-existent as well.</p>
    <div>
      <h3>Social media bots</h3>
      <a href="#social-media-bots">
        
      </a>
    </div>
    <p>Similar to Bing &amp; Baidu above, the graphs below are also trimmed to a period ending April 1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6JuMhjbBKR1azrJ0zgZfeM/7c765cdc40f70ddbdec16aa447585e0f/download--15-.png" />
            
            </figure><p>Facebook’s use of HTTP/3 for site crawling and indexing over the last year remained near zero, similar to what we observed over the previous year. HTTP/1.1 started the period accounting for under 60% of requests, and except for a brief peak above it in late May, usage of HTTP/1.1 steadily declined over the course of the year, dropping to around 30% by April 2023. As such, use of HTTP/2 increased from just over 40% in May 2022 to over 70% in April 2023. Meta engineers confirmed that this shift away from HTTP/1.1 usage is an expected gradual change in their infrastructure's use of HTTP, and that they are slowly working towards removing HTTP/1.1 from their infrastructure entirely.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Gq43pPPIHZuV6L8gqwHCv/1bb85f1d4eb42551a64e41e943678e7f/download--16-.png" />
            
            </figure><p>In last year’s blog post, we noted that “TwitterBot clearly has a strong and consistent preference for HTTP/2, accounting for 75-80% of its requests, with the balance over HTTP/1.1.” This preference generally remained the case through early October, at which point HTTP/2 usage began a gradual decline to just above 60% by April 2023. It isn’t clear what drove the week-long HTTP/2 drop and HTTP/1.1 spike in late May 2022. And as we noted last year, TwitterBot’s use of HTTP/3 remains non-existent.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4fb6YfpvO1LgDfHmQ9ExXh/5c999b0cf8ced8ca0c7a64b9788c3fb5/download--17-.png" />
            
            </figure><p>In contrast to Facebook’s and Twitter’s site crawling bots, HTTP/3 actually accounts for a noticeable, and growing, volume of requests made by LinkedIn’s bot, increasing from just under 1% in May 2022 to just over 10% in April 2023. We noted last year that LinkedIn’s use of HTTP/2 began to take off in March 2022, growing to approximately 5% of requests. Usage of this version gradually increased over this year’s surveyed period to 15%, although the growth was particularly erratic and spiky, as opposed to a smooth, consistent increase. HTTP/1.1 remained the dominant protocol used by LinkedIn’s bots, although its share dropped from around 95% in May 2022 to 75% in April 2023.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>On the whole, we are excited to see that usage of HTTP/3 has generally increased for browser-based consumption of traffic, and recognize that there is opportunity for significant further growth if and when it starts to be used more actively for API interactions through production support in key tools like curl. And though disappointed to see that search engine and social media bot usage of HTTP/3 remains minimal to non-existent, we also recognize that the real-time benefits of using the newest version of the web’s foundational protocol may not be completely applicable for asynchronous automated content retrieval.</p><p>You can follow these and other trends in the “Adoption and Usage” section of Cloudflare Radar at <a href="https://radar.cloudflare.com/adoption-and-usage">https://radar.cloudflare.com/adoption-and-usage</a>, as well as by following <a href="https://twitter.com/cloudflareradar">@CloudflareRadar</a> on Twitter or <a href="https://cloudflare.social/@radar">https://cloudflare.social/@radar</a> on Mastodon.</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">7Dpg4lAaYLKzXNozcyuxdv</guid>
            <dc:creator>David Belson</dc:creator>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[HTTP RFCs have evolved: A Cloudflare view of HTTP usage trends]]></title>
            <link>https://blog.cloudflare.com/cloudflare-view-http3-usage/</link>
            <pubDate>Mon, 06 Jun 2022 20:49:17 GMT</pubDate>
            <description><![CDATA[ HTTP/3 is now RFC 9114. We explore Cloudflare's view of how it is being used ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Today, a cluster of Internet standards were published that rationalize and modernize the definition of HTTP - the application protocol that underpins the web. This work includes updates to, and <a href="https://www.cloudflare.com/learning/cloud/how-to-refactor-applications/">refactoring</a> of, HTTP semantics, HTTP caching, HTTP/1.1, HTTP/2, and the brand-new <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>. Developing these specifications has been no mean feat and today marks the culmination of efforts far and wide, in the Internet Engineering Task Force (IETF) and beyond. We thought it would be interesting to celebrate the occasion by sharing some analysis of Cloudflare's view of HTTP traffic over the last 12 months.</p><p>However, before we get into the traffic data, for quick reference, here are the new RFCs that you should make a note of and start using:</p><ul><li><p>HTTP Semantics - <a href="https://www.rfc-editor.org/rfc/rfc9110.html">RFC 9110</a></p><ul><li><p>HTTP's overall architecture, common terminology and shared protocol aspects such as request and response messages, methods, status codes, header and trailer fields, message content, representation data, content codings and much more. Obsoletes RFCs <a href="https://www.rfc-editor.org/rfc/rfc2818.html">2818</a>, <a href="https://www.rfc-editor.org/rfc/rfc7231.html">7231</a>, <a href="https://www.rfc-editor.org/rfc/rfc7232.html">7232</a>, <a href="https://www.rfc-editor.org/rfc/rfc7233.html">7233</a>, <a href="https://www.rfc-editor.org/rfc/rfc7235.html">7235</a>, <a href="https://www.rfc-editor.org/rfc/rfc7538.html">7538</a>, <a href="https://www.rfc-editor.org/rfc/rfc7615.html">7615</a>, <a href="https://www.rfc-editor.org/rfc/rfc7694.html">7694</a>, and portions of <a href="https://www.rfc-editor.org/rfc/rfc7230.html">7230</a>.</p></li></ul></li><li><p>HTTP Caching - <a href="https://www.rfc-editor.org/rfc/rfc9111.html">RFC 9111</a></p><ul><li><p>HTTP caches and related header fields to control the behavior of response caching. Obsoletes RFC <a href="https://www.rfc-editor.org/rfc/rfc7234.html">7234</a>.</p></li></ul></li><li><p>HTTP/1.1 - <a href="https://www.rfc-editor.org/rfc/rfc9112.html">RFC 9112</a></p><ul><li><p>A syntax, aka "wire format", of HTTP that uses a text-based format. Typically used over TCP and TLS. Obsolete portions of RFC <a href="https://www.rfc-editor.org/rfc/rfc7230.html">7230</a>.</p></li></ul></li><li><p>HTTP/2 - RFC <a href="https://www.rfc-editor.org/rfc/rfc9113.html">9113</a></p><ul><li><p>A syntax of HTTP that uses a binary framing format, which provides streams to support concurrent requests and responses. Message fields can be compressed using HPACK. Typically used over TCP and TLS. Obsoletes RFCs <a href="https://www.rfc-editor.org/rfc/rfc7540.html">7540</a> and <a href="https://www.rfc-editor.org/rfc/rfc8740.html">8740</a>.</p></li></ul></li><li><p>HTTP/3 - RFC <a href="https://www.rfc-editor.org/rfc/rfc9114.html">9114</a></p><ul><li><p>A syntax of HTTP that uses a binary framing format optimized for the QUIC transport protocol. Message fields can be compressed using QPACK.</p></li></ul></li><li><p>QPACK - RFC <a href="https://www.rfc-editor.org/rfc/rfc9204.html">9204</a></p><ul><li><p>A variation of HPACK field compression that is optimized for the QUIC transport protocol.</p></li></ul></li></ul><p>On May 28, 2021, we <a href="/quic-version-1-is-live-on-cloudflare/">enabled</a> QUIC version 1 and HTTP/3 for all Cloudflare customers, using the final "h3" identifier that matches RFC 9114. So although today's publication is an occasion to celebrate, for us nothing much has changed, and it's business as usual.</p><p><a href="https://caniuse.com/http3">Support for HTTP/3 in the stable release channels of major browsers</a> came in November 2020 for Google Chrome and Microsoft Edge and April 2021 for Mozilla Firefox. In Apple Safari, HTTP/3 support currently needs to be <a href="https://developer.apple.com/forums/thread/660516">enabled</a> in the “Experimental Features” developer menu in production releases.</p><p>A browser and web server typically automatically negotiate the highest HTTP version available. Thus, HTTP/3 takes precedence over HTTP/2. We looked back over the last year to understand HTTP/3 usage trends across the Cloudflare network, as well as analyzing HTTP versions used by traffic from leading browser families (Google Chrome, Mozilla Firefox, Microsoft Edge, and Apple Safari), major search engine indexing bots, and bots associated with some popular social media platforms. The graphs below are based on aggregate HTTP(S) traffic seen globally by the Cloudflare network, and include requests for website and application content across the Cloudflare customer base between May 7, 2021, and May 7, 2022. We used <a href="https://developers.cloudflare.com/bots/concepts/bot-score/">Cloudflare bot scores</a> to restrict analysis to “likely human” traffic for the browsers, and to “likely automated” and “automated” for the search and social bots.</p>
    <div>
      <h3>Traffic by HTTP version</h3>
      <a href="#traffic-by-http-version">
        
      </a>
    </div>
    <p>Overall, HTTP/2 still comprises the majority of the request traffic for Cloudflare customer content, as clearly seen in the graph below. After remaining fairly consistent through 2021, HTTP/2 request volume increased by approximately 20% heading into 2022. HTTP/1.1 request traffic remained fairly flat over the year, aside from a slight drop in early December. And while HTTP/3 traffic initially trailed HTTP/1.1, it surpassed it in early July, growing steadily and  roughly doubling in twelve months.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2UKNCgWJPAocsCrvTmqKOG/6c1d9ff45b8c4430f4663f4fe8a41964/image13-1.png" />
            
            </figure>
    <div>
      <h3>HTTP/3 traffic by browser</h3>
      <a href="#http-3-traffic-by-browser">
        
      </a>
    </div>
    <p>Digging into just HTTP/3 traffic, the graph below shows the trend in daily aggregate request volume over the last year for HTTP/3 requests made by the surveyed browser families. Google Chrome (orange line) is far and away the leading browser, with request volume far outpacing the others.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6fOBxNVQis3KRP9qMJtN0h/07df569e787dcfd3b918124a9c324b30/image6-21.png" />
            
            </figure><p>Below, we remove Chrome from the graph to allow us to more clearly see the trending across other browsers. Likely because it is also based on the Chromium engine, the trend for Microsoft Edge closely mirrors Chrome. As noted above, Mozilla Firefox first enabled production support in <a href="https://hacks.mozilla.org/2021/04/quic-and-http-3-support-now-in-firefox-nightly-and-beta/">version 88</a> in April 2021, making it available by default by the end of May. The increased adoption of that updated version during the following month is clear in the graph as well, as HTTP/3 request volume from Firefox grew rapidly. HTTP/3 traffic from Apple Safari increased gradually through April, suggesting growth in the number of users enabling the experimental feature or running a Technology Preview version of the browser. However, Safari’s HTTP/3 traffic has subsequently dropped over the last couple of months. We are not aware of any specific reasons for this decline, but our most recent observations indicate HTTP/3 traffic is recovering.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7Mupv6iXQ195JfJkFLJQjX/cb0cc4153c043740e92e93fb2e041626/image2-57.png" />
            
            </figure><p>Looking at the lines in the graph for Chrome, Edge, and Firefox, a weekly cycle is clearly visible in the graph, suggesting greater usage of these browsers during the work week. This same pattern is absent from Safari usage.</p><p>Across the surveyed browsers, Chrome ultimately accounts for approximately 80% of the HTTP/3 requests seen by Cloudflare, as illustrated in the graphs below. Edge is responsible for around another 10%, with Firefox just under 10%, and Safari responsible for the balance.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Yph7V9e1W31PWkSry6pCy/6c874447bfa49392244e587dfb3d35fe/image1-64.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1zPj3TMsZuiirtoljldJYy/12f92447d2d0b3c26afd0b5754c510f1/image8-10.png" />
            
            </figure><p>We also wanted to look at how the mix of HTTP versions has changed over the last year across each of the leading browsers. Although the percentages vary between browsers, it is interesting to note that the trends are very similar across Chrome, Firefox and Edge. (After Firefox turned on default HTTP/3 support in May 2021, of course.)  These trends are largely customer-driven – that is, they are likely due to changes in Cloudflare customer configurations.</p><p>Most notably we see an increase in HTTP/3 during the last week of September, and a decrease in HTTP/1.1 at the beginning of December. For Safari, the HTTP/1.1 drop in December is also visible, but the HTTP/3 increase in September is not. We expect that over time, once Safari supports HTTP/3 by default that its trends will become more similar to those seen for the other browsers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4P1m2PJH7GBq9kBUL4vH0/fd19391109337e16a255967b54120392/image7-12.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Fj8pBr6Z5tpMV9XUTC1lJ/68b10faf3b1f840844d1cf97f8204b64/image9-6.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6iMw3Aj3IXWpjn4LyxBAsG/7b59629b937fb39d352a126a5bd178d3/image12-1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2dtxJLKq2N23CBwcZlEz8s/64bdc5275320e16bd0b8780db49e0ffc/image11-2.png" />
            
            </figure>
    <div>
      <h3>Traffic by search indexing bot</h3>
      <a href="#traffic-by-search-indexing-bot">
        
      </a>
    </div>
    <p>Back in 2014, Google <a href="https://developers.google.com/search/blog/2014/08/https-as-ranking-signal">announced</a> that it would start to consider HTTPS usage as a ranking signal as it indexed websites. However, it does not appear that Google, or any of the other major search engines, currently consider support for the latest versions of HTTP as a ranking signal. (At least not directly – the performance improvements associated with newer versions of HTTP could theoretically influence rankings.) Given that, we wanted to understand which versions of HTTP the indexing bots themselves were using.</p><p>Despite leading the charge around the development of QUIC, and integrating HTTP/3 support into the Chrome browser early on, it appears that on the indexing/crawling side, Google still has quite a long way to go. The graph below shows that requests from GoogleBot are still predominantly being made over HTTP/1.1, although use of HTTP/2 has grown over the last six months, gradually approaching HTTP/1.1 request volume. (A <a href="https://developers.google.com/search/blog/2020/09/googlebot-will-soon-speak-http2">blog post</a> from Google provides some potential insights into this shift.) Unfortunately, the volume of requests from GoogleBot over HTTP/3 has remained extremely limited over the last year.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3gTr2C26AB8SF6aK0CaiK/9b555a912b3428ad9e15572936bf4fb1/image4-32.png" />
            
            </figure><p>Microsoft’s BingBot also fails to use HTTP/3 when indexing sites, with near-zero request volume. However, in contrast to GoogleBot, BingBot prefers to use HTTP/2, with a wide margin developing in mid-May 2021 and remaining consistent across the rest of the past year.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/444sdNtnh5h0LNsGtUWmuV/b4d3a2f76ec4a5b8fc579371c9f005a2/image10-5.png" />
            
            </figure>
    <div>
      <h3>Traffic by social media bot</h3>
      <a href="#traffic-by-social-media-bot">
        
      </a>
    </div>
    <p>Major social media platforms use custom bots to retrieve metadata for shared content, <a href="https://developers.facebook.com/docs/sharing/bot/">improve language models for speech recognition technology</a>, or otherwise index website content. We also surveyed the HTTP version preferences of the bots deployed by three of the leading social media platforms.</p><p>Although <a href="https://http3check.net/?host=www.facebook.com">Facebook supports HTTP/3</a> on their main website (and presumably their mobile applications as well), their back-end FacebookBot crawler does not appear to support it. Over the last year, on the order of 60% of the requests from FacebookBot have been over HTTP/1.1, with the balance over HTTP/2. Heading into 2022, it appeared that HTTP/1.1 preference was trending lower, with request volume over the 25-year-old protocol dropping from near 80% to just under 50% during the fourth quarter. However, that trend was abruptly reversed, with HTTP/1.1 growing back to over 70% in early February. The reason for the reversal is unclear.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6upA1FtAbR6TWhexL8CkxT/87b3f1d676e1f9189ad5b7dc1d869e4a/image3-44.png" />
            
            </figure><p>Similar to FacebookBot, it appears TwitterBot’s use of HTTP/3 is, unfortunately, pretty much non-existent. However, TwitterBot clearly has a strong and consistent preference for HTTP/2, accounting for 75-80% of its requests, with the balance over HTTP/1.1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2c9sz97ViywLHaRd4vxCwE/9c981e7c39f8c894957447b4a3337c1a/image14-1.png" />
            
            </figure><p>In contrast, LinkedInBot has, over the last year, been firmly committed to making requests over HTTP/1.1, aside from the apparently brief anomalous usage of HTTP/2 last June. However, in mid-March, it appeared to tentatively start exploring the use of other HTTP versions, with around 5% of requests now being made over HTTP/2, and around 1% over HTTP/3, as seen in the upper right corner of the graph below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ozCJpCXILw6ulzIAxDyXn/70f9a1c95d76f4fd1f6f9e70e4d3e270/image5-23.png" />
            
            </figure>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>We're happy that HTTP/3 has, at long last, been published as <a href="https://www.rfc-editor.org/rfc/rfc9114.html">RFC 9114</a>. More than that, we're super pleased to see that regardless of the wait, browsers have steadily been enabling support for the protocol by default. This allows end users to seamlessly gain the advantages of HTTP/3 whenever it is available. On Cloudflare's global network, we've seen continued growth in the share of traffic speaking HTTP/3, demonstrating continued interest from customers in enabling it for their sites and services. In contrast, we are disappointed to see bots from the major search and social platforms continuing to rely on aging versions of HTTP. We'd like to build a better understanding of how these platforms chose particular HTTP versions and welcome collaboration in exploring the advantages that HTTP/3, in particular, could provide.</p><p>Current statistics on HTTP/3 and QUIC adoption at a country and autonomous system (ASN) level can be found on <a href="https://radar.cloudflare.com/">Cloudflare Radar</a>.</p><p>Running HTTP/3 and QUIC on the edge for everyone has allowed us to monitor a wide range of aspects related to interoperability and performance across the Internet. Stay tuned for future blog posts that explore some of the technical developments we've been making.</p><p>And this certainly isn't the end of protocol innovation, as HTTP/3 and QUIC provide many exciting new opportunities. The IETF and wider community are already underway building new capabilities on top, such as <a href="/unlocking-quic-proxying-potential/">MASQUE</a> and <a href="https://datatracker.ietf.org/wg/webtrans/documents/">WebTransport</a>. Meanwhile, in the last year, the QUIC Working Group has adopted new work such as <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-v2/">QUIC version 2</a>, and the <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-multipath/">Multipath Extension to QUIC</a>.</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">4Dd2QedroFWYvUMb5Ba3ha</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>David Belson</dc:creator>
        </item>
        <item>
            <title><![CDATA[Unlocking QUIC’s proxying potential with MASQUE]]></title>
            <link>https://blog.cloudflare.com/unlocking-quic-proxying-potential/</link>
            <pubDate>Sun, 20 Mar 2022 16:58:37 GMT</pubDate>
            <description><![CDATA[ We continue our technical deep dive into traditional TCP proxying over HTTP ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In the last post on <a href="/a-primer-on-proxies/">proxy TCP-based applications</a>, we discussed how HTTP CONNECT can be used to proxy TCP-based applications, including DNS-over-HTTPS and generic HTTPS traffic, between a client and target server. This provides significant benefits for those applications, but it doesn’t lend itself to non-TCP applications. And if you’re wondering whether or not we care about these, the answer is an affirmative yes!</p><p>For instance, <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> is based on QUIC, which runs on top of UDP. What if we wanted to speak HTTP/3 to a target server? That requires two things: (1) the means to encapsulate a UDP payload between client and proxy (which the proxy decapsulates and forward to the target in an actual UDP datagram), and (2) a way to instruct the proxy to open a UDP association to a target so that it knows where to forward the decapsulated payload. In this post, we’ll discuss answers to these two questions, starting with encapsulation.</p>
    <div>
      <h3>Encapsulating datagrams</h3>
      <a href="#encapsulating-datagrams">
        
      </a>
    </div>
    <p>While TCP provides a reliable and ordered byte stream for applications to use, UDP instead provides unreliable messages called datagrams. Datagrams sent or received on a connection are loosely associated, each one is independent from a transport perspective. Applications that are built on top of UDP can leverage the unreliability for good. For example, low-latency media streaming often does so to avoid lost packets getting retransmitted. This makes sense, on a live teleconference it is better to receive the most recent audio or video rather than starting to lag behind while you're waiting for stale data</p><p>QUIC is designed to run on top of an unreliable protocol such as UDP. QUIC provides its own layer of security, packet loss detection, methods of data recovery, and congestion control. If the layer underneath QUIC duplicates those features, they can cause wasted work or worse create destructive interference. For instance, QUIC <a href="https://www.rfc-editor.org/rfc/rfc9002.html#section-7">congestion control</a> defines a number of signals that provide input to sender-side algorithms. If layers underneath QUIC affect its packet flows (loss, timing, pacing, etc), they also affect the algorithm output. Input and output run in a feedback loop, so perturbation of signals can get amplified. All of this can cause congestion control algorithms to be more conservative in the data rates they use.</p><p>If we could speak HTTP/3 to a proxy, and leverage a reliable QUIC stream to carry encapsulated datagrams payload, then everything <i>can</i> work. However, the reliable stream interferes with expectations. The most likely outcome being slower end-to-end UDP throughput than we could achieve without tunneling. Stream reliability runs counter to our goals.</p><p>Fortunately, QUIC's <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/">unreliable datagram extension</a> adds a new <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram-07#section-4">DATAGRAM frame</a> that, as its name plainly says, is unreliable. It has several uses; the one we care about is that it provides a building block for performant UDP tunneling. In particular, this extension has the following properties:</p><ul><li><p>DATAGRAM frames are individual messages, unlike a long QUIC stream.</p></li><li><p>DATAGRAM frames do not contain a multiplexing identifier, unlike QUIC's stream IDs.</p></li><li><p>Like all QUIC frames, DATAGRAM frames must fit completely inside a QUIC packet.</p></li><li><p>DATAGRAM frames are subject to congestion control, helping senders to avoid overloading the network.</p></li><li><p>DATAGRAM frames are acknowledged by the receiver but, importantly, if the sender detects a loss, QUIC does not retransmit the lost data.</p></li></ul><p>The Datagram "Unreliable Datagram Extension to QUIC" specification will be published as an RFC soon. Cloudflare's <a href="https://github.com/cloudflare/quiche">quiche</a> library has supported it since October 2020.</p><p>Now that QUIC has primitives that support sending unreliable messages, we have a standard way to effectively tunnel UDP inside it. QUIC provides the STREAM and DATAGRAM transport primitives that support our proxying goals. Now it is the application layer responsibility to describe <b>how</b> to use them for proxying. Enter MASQUE.</p>
    <div>
      <h3>MASQUE: Unlocking QUIC’s potential for proxying</h3>
      <a href="#masque-unlocking-quics-potential-for-proxying">
        
      </a>
    </div>
    <p>Now that we’ve described how encapsulation works, let’s now turn our attention to the second question listed at the start of this post: How does an application initialize an end-to-end tunnel, informing a proxy server where to send UDP datagrams to, and where to receive them from? This is the focus of the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE Working Group</a>, which was formed in June 2020 and has been designing answers since. Many people across the Internet ecosystem have been contributing to the standardization activity. At Cloudflare, that includes Chris (as co-chair), Lucas (as co-editor of one WG document) and several other colleagues.</p><p>MASQUE started solving the UDP tunneling problem with a pair of specifications: a definition for how <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-h3-datagram/">QUIC datagrams are used with HTTP/3</a>, and <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-connect-udp/">a new kind of HTTP request</a> that initiates a UDP socket to a target server. These have built on the concept of extended CONNECT, which was first introduced for HTTP/2 in <a href="https://datatracker.ietf.org/doc/html/rfc8441">RFC 8441</a> and has now been <a href="https://datatracker.ietf.org/doc/draft-ietf-httpbis-h3-websockets/">ported to HTTP/3</a>. Extended CONNECT defines the :protocol pseudo-header that can be used by clients to indicate the intention of the request. The initial use case was WebSockets, but we can repurpose it for UDP and it looks like this:</p>
            <pre><code>:method = CONNECT
:protocol = connect-udp
:scheme = https
:path = /target.example.com/443/
:authority = proxy.example.com</code></pre>
            <p>A client sends an extended CONNECT request to a proxy server, which identifies a target server in the :path. If the proxy succeeds in opening a UDP socket, it responds with a 2xx (Successful) status code. After this, an end-to-end flow of unreliable messages between the client and target is possible; the client and proxy exchange QUIC DATAGRAM frames with an encapsulated payload, and the proxy and target exchange UDP datagrams bearing that payload.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3BXgtvSVPvNMa3CkKqqioK/1530306e4007e30b6d7b995c2b01f823/image3-34.png" />
            
            </figure>
    <div>
      <h3>Anatomy of Encapsulation</h3>
      <a href="#anatomy-of-encapsulation">
        
      </a>
    </div>
    <p>UDP tunneling has a constraint that TCP tunneling does not – namely, the size of messages and how that relates to path MTU (Maximum Transmission Unit; for more background see our <a href="https://www.cloudflare.com/learning/network-layer/what-is-mtu/">Learning Center article</a>). The path MTU is the maximum size that is allowed on the path between client and server. The actual maximum is the smallest maximum across all elements at every hop and at every layer, from the network up to application. All it takes is for one component with a small MTU to reduce the path MTU entirely. On the Internet, <a href="https://www.cloudflare.com/learning/network-layer/what-is-mtu/">1,500 bytes</a> is a common practical MTU. When considering tunneling using QUIC, we need to appreciate the anatomy of QUIC packets and frames in order to understand how they add bytes of overheard. This consumes bytes and subtracts from our theoretical maximum.</p><p>We've been talking in terms of HTTP/3 which normally has its own frames (HEADERS, DATA, etc) that have a common type and length overhead. However, there is no HTTP/3 framing when it comes to DATAGRAM, instead the bytes are placed directly into the QUIC frame. This frame is composed of two fields. The first field is a variable number of bytes, called the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-masque-h3-datagram-05#section-3">Quarter Stream ID</a> field, which is an encoded identifier that supports independent multiplexed DATAGRAM flows. It does so by binding each DATAGRAM to the HTTP request stream ID. In QUIC, stream IDs use two bits to encode four types of stream. Since request streams are always of one type (client-initiated bidirectional, to be exact), we can divide their ID by four to save space on the wire. Hence the name Quarter Stream ID. The second field is payload, which contains the end-to-end message payload. Here's how it might look on the wire.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7fzMrcBgH540C9SizGskfh/2107ffe432c189ec089e5663615bc814/image2-75.png" />
            
            </figure><p>If you recall our lesson from the <a href="/a-primer-on-proxies/">last post</a>, DATAGRAM frames (like all frames) must fit completely inside a QUIC packet. Moreover, since QUIC requires that <a href="https://www.rfc-editor.org/rfc/rfc9000.html#section-14-7">fragmentation is disabled</a>, QUIC packets must fit completely inside a UDP datagram. This all combines to limit the maximum size of things that we can actually send: the path MTU determines the size of the UDP datagram, then we need to subtract the overheads of the UDP datagram header, QUIC packet header, and QUIC DATAGRAM frame header. For a better understanding of QUIC's wire image and overheads, see <a href="https://www.rfc-editor.org/rfc/rfc8999.html#section-5">Section 5 of RFC 8999</a> and <a href="https://www.rfc-editor.org/rfc/rfc9000.html#section-12.4">Section 12.4 of RFC 9000</a>.</p><p>If a sender has a message that is too big to fit inside the tunnel, there are only two options: discard the message or fragment it. Neither of these are good options. Clients create the UDP tunnel and are more likely to accurately calculate the real size of encapsulated UDP datagram payload, thus avoiding the problem. However, a target server is most likely unaware that a client is behind a proxy, so it cannot accommodate the tunneling overhead. It might send a UDP datagram payload that is too big for the proxy to encapsulate. This conundrum is common to all proxy protocols! There's an art in picking the right MTU size for UDP-based traffic in the face of tunneling overheads. While approaches like path MTU discovery can help, they are <a href="/path-mtu-discovery-in-practice/">not a silver bullet</a>. Choosing conservative maximum sizes can reduce the chances of tunnel-related problems. However, this needs to be weighed against being too restrictive. Given a theoretical path MTU of 1,500, once we consider QUIC encapsulation overheads, tunneled messages with a limit between 1,200 and 1,300 bytes can be effective.This is especially important when we think about tunneling QUIC itself. <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-8.1">RFC 9000 Section 8.1</a> details how clients that initiate new QUIC connections must send UDP datagrams of at least 1,200 bytes. If a proxy can't support that, then QUIC will not work in a tunnel.</p>
    <div>
      <h3>Nested tunneling for Improved Privacy Proxying</h3>
      <a href="#nested-tunneling-for-improved-privacy-proxying">
        
      </a>
    </div>
    <p>MASQUE gives us the application layer building blocks to support efficient tunneling of TCP or UDP traffic. What's cool about this is that we can combine these blocks into different deployment architectures for different scenarios or different needs.</p><p>One example of this case is nested tunneling via multiple proxies, which can minimize the connection metadata available to each individual proxy or server (one example of this type of deployment is described in our recent post on <a href="/icloud-private-relay/">iCloud Private Relay)</a>. In this kind of setup, a client might manage at least three logical connections. First, a QUIC connection between Client and Proxy 1. Second, a QUIC connection between Client and Proxy 2, which runs via a CONNECT tunnel in the first connection. Third, an end-to-end byte stream between Client and Server, which runs via a CONNECT tunnel in the second connection. A real TCP connection only exists between Proxy 2 and Server. If additional Client to Server logical connections are needed, they can be created inside the existing pair of QUIC connections.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3zIR70pmMrWlgjGongXqkH/9409a30dfba8a603d9a917b20e8a3d3a/image4-16.png" />
            
            </figure>
    <div>
      <h3>Towards a full tunnel with IP tunneling</h3>
      <a href="#towards-a-full-tunnel-with-ip-tunneling">
        
      </a>
    </div>
    <p>Proxy support for UDP and TCP already unblocks a huge assortment of use cases, including TLS, QUIC, HTTP, DNS, and so on. But it doesn’t help protocols that use different <a href="https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml">IP protocols</a>, like <a href="https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol">ICMP</a> or IPsec <a href="https://en.wikipedia.org/wiki/IPsec#Encapsulating_Security_Payload">Encapsulating Security Payload</a> (ESP). Fortunately, the MASQUE Working Group has also been working on IP tunneling. This is a lot more complex than UDP tunneling, so they first spent some time defining a common set of <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-ip-proxy-reqs/">requirements</a>. The group has recently adopted a new specification to support <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-connect-ip/">IP proxying over HTTP</a>. This behaves similarly to the other CONNECT designs we've discussed but with a few differences. Indeed, IP proxying support using HTTP as a substrate would unlock many applications that existing protocols like IPsec and WireGuard enable.</p><p>At this point, it would be reasonable to ask: “A complete HTTP/3 stack is a bit excessive when all I need is a simple end-to-end tunnel, right?” Our answer is, it depends! CONNECT-based IP proxies use TLS and rely on well established PKIs for creating secure channels between endpoints, whereas protocols like WireGuard use a simpler cryptographic protocol for key establishment and defer authentication to the application. WireGuard does not support proxying over TCP but <a href="https://www.wireguard.com/known-limitations/">can be adapted to work over TCP</a> transports, if necessary. In contrast, CONNECT-based proxies do support TCP and UDP transports, depending on what version of HTTP is used. Despite these differences, these protocols do share similarities. In particular, the actual framing used by both protocols – be it the TLS record layer or QUIC packet protection for CONNECT-based proxies, or WireGuard encapsulation – are not interoperable but only slightly differ in wire format. Thus, from a performance perspective, there’s not really much difference.</p><p>In general, comparing these protocols is like comparing apples and oranges – they’re fit for different purposes, have different implementation requirements, and assume different ecosystem participants and threat models. At the end of the day, CONNECT-based proxies are better suited to an ecosystem and environment that is already heavily invested in TLS and the existing WebPKI, so we expect CONNECT-based solutions for IP tunnels to become the norm in the future. Nevertheless, it's early days, so be sure to watch this space if you’re interested in learning more!</p>
    <div>
      <h3>Looking ahead</h3>
      <a href="#looking-ahead">
        
      </a>
    </div>
    <p>The IETF has chartered the MASQUE Working Group to help design an HTTP-based solution for UDP and IP that complements the existing CONNECT method for TCP tunneling. Using HTTP semantics allows us to use features like request methods, response statuses, and header fields to enhance tunnel initialization. For example, allowing for reuse of existing authentication mechanisms or the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-proxy-status">Proxy-Status</a> field. By using HTTP/3, UDP and IP tunneling can benefit from QUIC's secure transport native unreliable datagram support, and other features. Through a flexible design, older versions of HTTP can also be supported, which helps widen the potential deployment scenarios. Collectively, this work brings proxy protocols to the masses.</p><p>While the design details of MASQUE specifications continue to be iterated upon, so far several implementations have been developed, some of which have been interoperability tested during IETF hackathons. This running code helps inform the continued development of the specifications. Details are likely to continue changing before the end of the process, but we should expect the overarching approach to remain similar. Join us during the MASQUE WG meeting in <a href="https://www.ietf.org/how/meetings/113/">IETF 113</a> to learn more!</p> ]]></content:encoded>
            <category><![CDATA[Proxying]]></category>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[QUIC]]></category>
            <guid isPermaLink="false">7uf0jVn0IMKFbqLxWODDNM</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Christopher Wood</dc:creator>
        </item>
        <item>
            <title><![CDATA[Making connections with TCP and Sockets for Workers]]></title>
            <link>https://blog.cloudflare.com/introducing-socket-workers/</link>
            <pubDate>Mon, 15 Nov 2021 13:59:16 GMT</pubDate>
            <description><![CDATA[ The ability to make TCP and QUIC client connections from within Workers and Durable Objects, as well as the ability to connect to Workers over TCP and QUIC without using HTTP, will be coming to Cloudflare Workers. Here’s a peek at what we’re working on. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Today we are excited to announce that we are developing <a href="https://www.cloudflare.com/learning/security/api/what-is-an-api/">APIs</a> and infrastructure to support more TCP, UDP, and QUIC-based protocols in Cloudflare Workers. Once released, these new capabilities will make it possible to use non-HTTP socket connections to and from a Worker or Durable Object as easily as one can use HTTP and WebSockets today.</p><p>Out of the box, <a href="https://workers.cloudflare.com/?&amp;_bt=521144407143&amp;_bk=&amp;_bm=b&amp;_bn=g&amp;_bg=123914288844&amp;_placement=&amp;_target=&amp;_loc=1013686&amp;_dv=c&amp;awsearchcpc=1&amp;gclid=Cj0KCQiAsqOMBhDFARIsAFBTN3eXuRcLLiS_c0CtV8uR9xVVQhymoIrK5uHE_yReRLtVkHkekfCWprUaAtoyEALw_wcB&amp;gclsrc=aw.ds">Cloudflare Workers</a> support the ability to open HTTP and WebSocket connections using the standardized <a href="https://developers.cloudflare.com/workers/runtime-apis/fetch">fetch</a> and <a href="https://developers.cloudflare.com/workers/runtime-apis/websockets">WebSocket APIs</a>. With just a few internal changes to make it operational in Workers, we’ve developed an <a href="/relational-database-connectors/">example</a> using an off-the-shelf driver (in this example, a Deno-based <a href="https://deno.land/x/postgres@v0.13.0">Postgres client driver</a>) to communicate with a remote Postgres server via WebSocket over a secure <a href="https://www.cloudflare.com/products/tunnel/">Cloudflare Tunnel</a>.</p>
            <pre><code>import { Client } from './driver/postgres/postgres'

export default {
  async fetch(request: Request, env, ctx: ExecutionContext) {
    try {
      const client = new Client({
        user: 'postgres',
        database: 'postgres',
        hostname: 'https://db.example.com',
        password: '',
        port: 5432,
      })
      await client.connect()
      const result = await client.queryArray('SELECT * FROM users WHERE uuid=1;')
      ctx.waitUntil(client.end())
      return new Response(JSON.stringify(result.rows[0]))
    } catch (e) {
      return new Response((e as Error).message)
    }
  },
}
</code></pre>
            <p>The example works by replacing the bits of the Postgres client driver that use the Deno-specific TCP socket APIs with standard fetch and WebSockets APIs. We then establish a WebSocket connection with a remote Cloudflare Tunnel daemon running adjacent to the Postgres server, establishing what is effectively TCP-over-WebSockets.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/xvjFKpdAS2plGdWFtEcSd/a522beae8d20642ea3a68f4ae25e3fdc/image1-17.png" />
            
            </figure><p>While the fact we were able to build the example and communicate effectively and efficiently with the Postgres server — without making any changes to the Cloudflare Workers runtime — is impressive, there are limitations to the approach. For one, the solution requires additional infrastructure to establish and maintain the WebSocket tunnel — in this case, the instance of the Cloudflare Tunnel daemon running adjacent to the Postgres server. While we are certainly happy to provide that daemon to customers, it would just be better if that component were not required at all. Second, tunneling TCP over WebSockets, which is itself tunneled via HTTP over TCP is a bit suboptimal. It works, but we can do better.</p>
    <div>
      <h3>Making connections from Cloudflare Workers</h3>
      <a href="#making-connections-from-cloudflare-workers">
        
      </a>
    </div>
    <p>Currently, there is no standard API for socket connections in JavaScript. We want to change that.</p><p>If you’ve used Node.js before, then you’re most likely familiar with the <a href="https://nodejs.org/dist/latest-v17.x/docs/api/net.html#class-netsocket"><code>net.Socket</code></a> and <a href="https://nodejs.org/dist/latest-v17.x/docs/api/tls.html#class-tlstlssocket"><code>net.TLSSocket</code></a> objects. If you use Deno, then you might know that they’ve recently introduced the <a href="https://doc.deno.land/builtin/stable#Deno.connect"><code>Deno.connect()</code></a> and <a href="https://doc.deno.land/builtin/stable#Deno.connectTls"><code>Deno.connectTLS()</code></a> APIs. When you look at those APIs, what should immediately be apparent is how different they are from one another despite doing the exact same thing.</p><p>When we decided that we would add the ability to open and use socket connections from within Workers, we also agreed that we really have no interest in developing yet another non-standard, platform-specific API that is unlike the APIs provided by other platforms. Therefore, we are extending an invitation to all JavaScript runtime platforms that need socket capabilities to collaborate on a new (and eventually standardized) API that just works no matter which runtime you choose to develop on.</p><p>Here’s a rough example of what we have in mind for opening and reading from a simple TCP client connection:</p>
            <pre><code>const socket = new Socket({
  remote: { address: '123.123.123.123', port: 1234 },
})
for await (const chunk of socket.readable)
  console.log(chunk)</code></pre>
            <p>Or, this example, sending a simple “hello world” packet using UDP:</p>
            <pre><code>const socket = new Socket({
  type: 'udp',
  remote: { address: '123.123.123.123', port: 1234 },
});
const enc = new TextEncoder();
const writer = socket.writable.getWriter();
await writer.write(enc.encode('hello world'));
await writer.close();</code></pre>
            <p>The API will be designed generically enough to work both client and server-side; for TCP, UDP, and QUIC; with or without TLS, and will not rely on any mechanism specific to any single JavaScript runtime. It will build on existing broadly supported Web Platform standards such as <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget">EventTarget</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream">ReadableStream</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/WritableStream">WritableStream</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal">AbortSignal</a>, and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises">promises</a>. It will be familiar to developers who are already familiar with the <code>fetch()</code> API, service workers, and promises using async/await.</p>
            <pre><code>interface Socket : EventTarget {
  constructor(object SocketInit);

  Promise&lt;undefined&gt; update(object SocketInit);

  readonly attribute ReadableStream readable;
  readonly attribute WritableStream writable;
  
  readonly attribute Promise&lt;undefined&gt; ready;
  readonly attribute Promise&lt;undefined&gt; closed;

  Promise&lt;undefined&gt; abort(optional any reason);
  readonly attribute AbortSignal signal;
 
  readonly attribute SocketStats stats;
  readonly attribute SocketInfo info;
}</code></pre>
            <p>This is just a proposal at this point and the details will very likely change from the examples above by the time the capability is delivered in Workers. It is our hope that other platforms will join us in the effort of developing and supporting this new API so that developers have a consistent foundation upon which to build regardless of where they run their code.</p>
    <div>
      <h3>Introducing Socket Workers</h3>
      <a href="#introducing-socket-workers">
        
      </a>
    </div>
    <p>The ability to open socket <i>client</i> connections is only half of the story.</p><p>When we first started talking about adding these capabilities an obvious question was asked: What about using non-HTTP protocols to connect <i>to</i> Workers? What if instead of just having the ability to connect a Worker to some other back-end database, we could implement the entire database itself on the edge, inside Workers, and have non-HTTP clients connect to it? For that matter, what if we could implement an SMTP server in Workers? Or an MQTT message queue? Or a full VoIP platform? Or implement packet filters, transformations, inspectors, or protocol transcoders?</p><p>Workers are far too powerful to limit to just HTTP and WebSockets, so we will soon introduce Socket Workers -- that is, Workers that can be connected to directly using raw TCP, UDP, or QUIC protocols without using HTTP.</p><p>What will this new Workers feature look like? Many of the details are still being worked through, but the idea is to deploy a Worker script that understands and responds to “connect” events in much the same way that “fetch” events work today. Importantly, this would build on the same common socket API being developed for client connections:</p>
            <pre><code>addEventListener('connect', (event) =&gt; {
  const enc = new TextEncoder();
  const writer = event.socket.writable.getWriter();
  writer.write(enc.encode('Hello World'));
  writer.close();
});</code></pre>
            
    <div>
      <h3>Next Steps (and a call to action)</h3>
      <a href="#next-steps-and-a-call-to-action">
        
      </a>
    </div>
    <p>The new socket API for JavaScript and Socket Workers are under active development, with focus initially on enabling better and more efficient ways for Workers to connect to databases on the backend — you can sign up <a href="https://www.cloudflare.com/database-connectors-early-access/">here</a> to join the waitlist for access to Database Connectors and Socket Workers. We are excited to work with early users, as well as our technology partners to develop, refine, and test these new capabilities.</p><p>Once released, we expect Socket Workers to blow the doors wide open on the types of intelligent distributed applications that can be deployed to the Cloudflare network edge, and we are excited to see what you build with them.</p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">7MZbwJq5IVdd2rRHZRWrUf</guid>
            <dc:creator>James M Snell</dc:creator>
        </item>
        <item>
            <title><![CDATA[Getting Cloudflare Tunnels to connect to the Cloudflare Network with QUIC]]></title>
            <link>https://blog.cloudflare.com/getting-cloudflare-tunnels-to-connect-to-the-cloudflare-network-with-quic/</link>
            <pubDate>Wed, 20 Oct 2021 13:00:53 GMT</pubDate>
            <description><![CDATA[  It is now possible to connect a Cloudflare Tunnel to the Cloudflare network with QUIC. While doing this, we ran into an interesting connectivity problem unique to UDP.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>I work on <i>Cloudflare Tunnel</i>, which lets customers quickly connect their private services and networks through the Cloudflare network without having to expose their public IPs or ports through their firewall. Tunnel is managed for users by <i>cloudflared</i>, a tool that runs on the same network as the private services. It proxies traffic for these services via Cloudflare, and users can then access these services securely through the Cloudflare network.</p><p>Recently, I was trying to get <i>Cloudflare Tunnel</i> to connect to the Cloudflare network using a UDP protocol, QUIC. While doing this, I ran into an interesting connectivity problem unique to UDP. In this post I will talk about how I went about debugging this connectivity issue beyond the land of firewalls, and how some interesting differences between UDP and TCP came into play when sending network packets.</p>
    <div>
      <h3>How does Cloudflare Tunnel work?</h3>
      <a href="#how-does-cloudflare-tunnel-work">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/NEssmu5aijDShf2V3IWjw/cfd10b15ec2b255155f13cc2899d7b69/2-17.png" />
            
            </figure><p><i>cloudflared</i> works by opening several connections to different servers on the Cloudflare edge. Currently, these are long-lived TCP-based connections proxied over HTTP/2 frames. When Cloudflare receives a request to a hostname, it is proxied through these connections to the local service behind <i>cloudflared</i>.</p><p>While our HTTP/2 protocol mode works great, we’d like to improve a few things. First, TCP traffic sent over HTTP/2 is susceptible to <a href="https://en.wikipedia.org/wiki/Head-of-line_blocking">Head of Line (HoL) blocking</a> — this affects both HTTP traffic and traffic from <a href="https://developers.cloudflare.com/cloudflare-one/tutorials/warp-to-tunnel">WARP routing</a>. Additionally, it is currently not possible to initiate communication from <i>cloudflared’s</i> HTTP/2 server in an efficient way. With the current Go implementation of HTTP/2, we could use <a href="https://en.wikipedia.org/wiki/Server-sent_events#:~:text=Server%2DSent%20Events%20(SSE),client%20connection%20has%20been%20established.">Server-Sent Events</a>, but this is not very useful in the scheme of proxying L4 traffic.</p><p>The upgrade to QUIC solves possible HoL blocking issues and opens up avenues that allow us to initiate communication from <i>cloudflared</i> to a different <i>cloudflared</i> in the future.</p><p>Naturally, QUIC required a UDP-based listener on our edge servers which <i>cloudflared</i> could connect to. We already connect to a TCP-based listener for the existing protocols, so this should be nice and easy, right?</p>
    <div>
      <h3>Failed to dial to the edge</h3>
      <a href="#failed-to-dial-to-the-edge">
        
      </a>
    </div>
    <p>Things weren’t as straightforward as they first looked. I added a QUIC listener on the edge, and the ability for <i>cloudflared</i> to connect to this new UDP-based listener. I tried to run my brand new QUIC tunnel and this happened.</p>
            <pre><code>$  cloudflared tunnel run --protocol quic my-tunnel
2021-09-17T18:44:11Z ERR Failed to create new quic connection, err: failed to dial to edge: timeout: no recent network activity</code></pre>
            <p><i>cloudflared</i> wasn’t even establishing a connection to the edge. I started looking at the obvious places first. <i>Did I add a firewall rule allowing traffic to this port?</i> Check_. Did I have iptables rules ACCEPTing or DROPping appropriate traffic for this port?_ Check_._ They seemed to be in order. So what else could I do?</p>
    <div>
      <h3>tcpdump all the packets</h3>
      <a href="#tcpdump-all-the-packets">
        
      </a>
    </div>
    <p>I started by logging for UDP traffic on the machine my server was running on to see what could be happening.</p>
            <pre><code>$  sudo tcpdump -n -i eth0 port 7844 and udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:44:27.742629 IP 173.13.13.10.50152 &gt; 198.41.200.200.7844: UDP, length 1252
14:44:27.743298 IP 203.0.113.0.7844 &gt; 173.13.13.10.50152: UDP, length 37</code></pre>
            <p>Looking at this <i>tcpdump</i> helped me understand why I had no connectivity! Not only was this port getting UDP traffic but I was also seeing traffic flow out. But there seemed to be something strange afoot. Incoming packets were being sent to 198.41.200.200:7844 while responses were being sent back from 203.0.113.0:7844 (this is an <a href="https://datatracker.ietf.org/doc/html/rfc5737">example IP</a> used for illustration purposes)  instead.</p><p>Why is this a problem? If a host (in this case, the server) chooses an address from a network unable to communicate with a public Internet host, it is likely that the return half of the communication will never arrive. But wait a minute. Why is some other IP getting prioritized over a source address my packets were already being sent to? Let’s take a deeper look at some IP addresses. (Note that I’ve deliberately oversimplified and scrambled results to minimally illustrate the problem)</p>
            <pre><code>$  ip addr list
eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1600 qdisc noqueue state UP group default qlen 1000
inet 203.0.113.0/32 scope global eth0
inet 198.41.200.200/32 scope global eth0 </code></pre>
            
            <pre><code>$ ip route show
default via 203.0.113.0 dev eth0</code></pre>
            <p>So this was clearly why the server was working fine on my machine but not on the Cloudflare edge servers. It looks like I have multiple IPs on the interface my service is bound to. The IP that is the default route is being sent back as the source address of the packet.</p>
    <div>
      <h3>Why does this work for TCP but not UDP?</h3>
      <a href="#why-does-this-work-for-tcp-but-not-udp">
        
      </a>
    </div>
    <p>Connection-oriented protocols, like TCP, initiate a connection (<a href="https://man7.org/linux/man-pages/man2/connect.2.html">connect()</a>) with a <a href="https://en.wikipedia.org/wiki/Handshaking#TCP_three-way_handshake">three-way handshake</a>. The kernel therefore maintains a state about ongoing connections and uses this to determine the source IP address at the time of a response.</p><p>Because UDP (unless SOCK_SEQPACKET is involved) is connectionless, the kernel cannot maintain state like TCP does. The <a href="https://man7.org/linux/man-pages/man3/recvfrom.3p.html"><i>recvfrom</i></a>  system call is invoked from the server side and tells who the data comes from. Unfortunately, <i>recvfrom</i>  does not tell us which IP this data is addressed for. Therefore, when the UDP server invokes the <code>[sendto](https://man7.org/linux/man-pages/man3/sendto.3p.html) system call</code> to respond to the client, we can only tell it which address to send the data to. The responsibility of determining the source-address IP then falls to the kernel. The kernel has certain <a href="http://linux-ip.net/html/routing-selection.html">heuristics</a> that it uses to determine the source address. This may or may not work, and in the <i>ip routes</i> example above, these heuristics did not work. The kernel naturally (and wrongly) picks the address of the default route to respond with.</p>
    <div>
      <h3>Telling the kernel what to do</h3>
      <a href="#telling-the-kernel-what-to-do">
        
      </a>
    </div>
    <p>I had to rely on my application to set the source address explicitly and therefore not rely on kernel heuristics.</p><p>Linux has some generic I/O system calls, namely <a href="https://man7.org/linux/man-pages/man3/recvmsg.3p.html"><i>recvmsg</i></a>  and <a href="https://man7.org/linux/man-pages/man3/sendmsg.3p.html"><i>sendmsg</i></a>. Their function signatures allow us to both read or write additional <a href="http://www.gnu.org/software/libc/manual/html_node/Out_002dof_002dBand-Data.html">out-of-band data</a> we can pass the source address to. This control information is passed via the <i>msghdr</i> struct’s <i>msg_control</i> field.</p>
            <pre><code>ssize_t sendmsg(int socket, const struct msghdr *message, int flags)
ssize_t recvmsg(int socket, struct msghdr *message, int flags);
 
struct msghdr {
     void    *   msg_name;   /* Socket name          */
     int     msg_namelen;    /* Length of name       */
     struct iovec *  msg_iov;    /* Data blocks          */
     __kernel_size_t msg_iovlen; /* Number of blocks     */
     void    *   msg_control;    /* Per protocol magic (eg BSD file descriptor passing) */
    __kernel_size_t msg_controllen; /* Length of cmsg list */
     unsigned int    msg_flags;
};</code></pre>
            <p>We can now copy the control information we’ve gotten from <i>recvmsg</i> back when calling <i>sendmsg</i>, providing the kernel with information about the source address.The library I used (<a href="https://github.com/lucas-clemente/quic-go">https://github.com/lucas-clemente/quic-go</a>) had a recent update that did exactly this! I pulled the changes into my service and gave it a spin.</p><p>But alas. It did not work! A quick <i>tcpdump</i> showed that the same source address was being sent back. It seemed clear from reading the source code that the <i>recvmsg</i> and <i>sendmsg</i> were being called with the right values. It did not make sense.</p><p>So I had to see for myself if these system calls were being made.</p>
    <div>
      <h3>strace all the system calls</h3>
      <a href="#strace-all-the-system-calls">
        
      </a>
    </div>
    <p><a href="https://man7.org/linux/man-pages/man1/strace.1.html"><i>strace</i></a> is an extremely useful tool that tracks all system calls and signals sent/received by a process. Here’s what it had to say. I've removed all the information not relevant to this specific issue.</p>
            <pre><code>17:39:09.130346 recvmsg(3, {msg_name={sa_family=AF_INET6,
sin6_port=htons(35224), inet_pton(AF_INET6, "::ffff:171.54.148.10", 
&amp;sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=112-&gt;28, msg_iov=
[{iov_base="_\5S\30\273]\275@\34\24\322\243{2\361\312|\325\n\1\314\316`\3
03\250\301X\20", iov_len=1452}], msg_iovlen=1, msg_control=[{cmsg_len=36, 
cmsg_level=SOL_IPV6, cmsg_type=0x32}, {cmsg_len=28, cmsg_level=SOL_IP, 
cmsg_type=IP_PKTINFO, cmsg_data={ipi_ifindex=if_nametoindex("eth0"),
ipi_spec_dst=inet_addr("198.41.200.200"),ipi_addr=inet_addr("198.41.200.200")}},
{cmsg_len=17, cmsg_level=SOL_IP, 
cmsg_type=IP_TOS, cmsg_data=[0]}], msg_controllen=96, msg_flags=0}, 0) = 28 &lt;0.000007&gt;</code></pre>
            
            <pre><code>17:39:09.165160 sendmsg(3, {msg_name={sa_family=AF_INET6, 
sin6_port=htons(35224), inet_pton(AF_INET6, "::ffff:171.54.148.10", 
&amp;sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=28, 
msg_iov=[{iov_base="Oe4\37:3\344 &amp;\243W\10~c\\\316\2640\255*\231 
OY\326b\26\300\264&amp;\33\""..., iov_len=1302}], msg_iovlen=1, msg_control=
[{cmsg_len=28, cmsg_level=SOL_TCP, cmsg_type=0x8}], msg_controllen=28, 
msg_flags=0}, 0) = 1302 &lt;0.000054&gt;</code></pre>
            <p>Let's start with <i>recvmsg</i> . We can clearly see that the ipi_addr for the source is being passed correctly: <i>ipi_addr=inet_addr("172.16.90.131")</i>. This part works as expected. Looking at <i>sendmsg</i>  almost instantly tells us where the problem is. The field we want, ip_spec_dst is not being set as we make this system call. So the kernel continues to make wrong guesses as to what the source address may be.</p><p>This turned out to be a <a href="https://github.com/lucas-clemente/quic-go/blob/3b46d7402c8436c38ca0d07a1ab4b4251acfd794/conn_oob.go#L249">bug</a> where the library was using <i>IPROTO_TCP</i> instead of <i>IPPROTO_IPV4</i> as the control message level while making the <i>sendmsg</i> call. Was that it? Seemed a little anticlimactic. I submitted a slightly more typesafe <a href="https://github.com/lucas-clemente/quic-go/pull/3278">fix</a> and sure enough, straces now showed me what I was expecting to see.</p>
            <pre><code>18:22:08.334755 sendmsg(3, {msg_name={sa_family=AF_INET6, 
sin6_port=htons(37783), inet_pton(AF_INET6, "::ffff:171.54.148.10", 
&amp;sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, msg_namelen=28, 
msg_iov=
[{iov_base="Ki\20NU\242\211Y\254\337\3107\224\201\233\242\2647\245}6jlE\2
70\227\3023_\353n\364"..., iov_len=33}], msg_iovlen=1, msg_control=
[{cmsg_len=28, cmsg_level=SOL_IP, cmsg_type=IP_PKTINFO, cmsg_data=
{ipi_ifindex=if_nametoindex("eth0"), 
ipi_spec_dst=inet_addr("198.41.200.200"),ipi_addr=inet_addr("0.0.0.0")}}
], msg_controllen=32, msg_flags=0}, 0) =
33 &lt;0.000049&gt;</code></pre>
            <p><i>cloudflared</i> is now able to connect with UDP (QUIC) to the Cloudflare network from anywhere in the world!</p>
            <pre><code>$  cloudflared tunnel --protocol quic run sudarsans-tunnel
2021-09-21T11:37:30Z INF Starting tunnel tunnelID=a72e9cb7-90dc-499b-b9a0-04ee70f4ed78
2021-09-21T11:37:30Z INF Version 2021.9.1
2021-09-21T11:37:30Z INF GOOS: darwin, GOVersion: go1.16.5, GoArch: amd64
2021-09-21T11:37:30Z INF Settings: map[p:quic protocol:quic]
2021-09-21T11:37:30Z INF Initial protocol quic
2021-09-21T11:37:32Z INF Connection 3ade6501-4706-433e-a960-c793bc2eecd4 registered connIndex=0 location=AMS</code></pre>
            <p>While the programmatic bug causing this issue was a trivial one, the journey into systematically discovering the issue and understanding how Linux internals worked for UDP along the way turned out to be very rewarding for me. It also reiterated my belief that <i>tcpdump</i> and <i>strace</i> are indeed invaluable tools in anybody’s arsenal when debugging network problems.</p>
    <div>
      <h3>What’s next?</h3>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>You can give this a try with the latest <i>cloudflared</i> release at <a href="https://github.com/cloudflare/cloudflared/releases/latest">https://github.com/cloudflare/cloudflared/releases/latest</a>. Just remember to set the <i>protocol</i> flag to <i>quic</i>. We plan to leverage this new mode to roll out some exciting new features for <i>Cloudflare Tunnel</i>. So upgrade away and keep watching this space for more information on how you can take advantage of this.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Tunnel]]></category>
            <category><![CDATA[Zero Trust]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[QUIC]]></category>
            <guid isPermaLink="false">1HDlvSKaYHiPl8cXFEdNV6</guid>
            <dc:creator>Sudarsan Reddy</dc:creator>
        </item>
        <item>
            <title><![CDATA[QUIC Version 1 is live on Cloudflare]]></title>
            <link>https://blog.cloudflare.com/quic-version-1-is-live-on-cloudflare/</link>
            <pubDate>Fri, 28 May 2021 21:06:55 GMT</pubDate>
            <description><![CDATA[ QUIC is a new fast and secure transport protocol. Version 1 has just been published as RFC 9000 and today Cloudflare has enabled support for all customers, come try it out.    ]]></description>
            <content:encoded><![CDATA[ <p></p><p>On May 27, 2021, the Internet Engineering Task Force published RFC 9000 - the standardized version of the QUIC transport protocol. The QUIC Working Group declared themselves done by issuing a <a href="/last-call-for-quic/">Last Call</a> 7 months ago. The i's have been dotted and the t's crossed, RFC 8999 - RFC 9002 are a suite of documents that capture years of engineering design and testing of QUIC. This marks a big occasion.</p><p>And today, one day later, we’ve made the standardized version of QUIC available to Cloudflare customers.</p><p>Transport protocols have a history of being hard to deploy on the Internet. QUIC overcomes this challenge by basing itself on top of UDP. Compared to TCP, QUIC has security by default, protecting almost all bytes from prying eyes or "helpful" middleboxes that can end up making things worse. It has designed-in features that speed up connection handshakes and mitigate the performance perils that can strike on networks that suffer loss or delays. It is pluggable, providing clear standardised extensions point that will allow smooth, iterative development and deployment of new features or performance enhancements for years to come.</p><p>The killer feature of QUIC, however, is that it is deployable in reality. We are excited to announce that QUIC version 1, <a href="https://www.rfc-editor.org/rfc/rfc9000.html">RFC 9000</a>, is available to all Cloudflare customers.  We started with a <a href="/the-quicening/">limited beta in 2018</a>, we made it <a href="/http3-the-past-present-and-future/">general availability in 2019</a>, and we've been tracking new document revisions every step of the way. In that time we've seen User-Agents like browsers join us in this merry march and prove that this thing works on the Internet.</p><p>QUIC is just a transport protocol. To make it do anything you need an application protocol to be mapped onto it. In parallel to the QUIC specification, the Working Group has defined an HTTP mapping called <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>. The design is all done, but we're waiting for a few more i's to be crossed before it too is published as an RFC. That doesn't prevent people from testing it though, and for the 3+ years that we've supported QUIC, we have supported HTTP on the top of it.</p><p>According to <a href="https://radar.cloudflare.com/">Cloudflare Radar</a>, we're seeing around 12% of Internet traffic using QUIC with HTTP/3 already. We look forward to this increasing now that RFC 9000 is out and raising awareness of the stability of things.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/44hkcMdHbgfl5XZk42hRUv/328f93d4e472216c75880da4db50b60a/image3-8.png" />
            
            </figure>
    <div>
      <h2>How do I enable QUIC and HTTP/3 for my domain?</h2>
      <a href="#how-do-i-enable-quic-and-http-3-for-my-domain">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4CC9znbBgFKJGTw6QN8YOL/094c27a60a4b9c4271d4b6cc6b610dcb/image4-12.png" />
            
            </figure><p>HTTP/3 and QUIC are controlled from the "Network" tab of your dashboard. Turn it on and start testing.</p>
    <div>
      <h2>But what does that actually do?</h2>
      <a href="#but-what-does-that-actually-do">
        
      </a>
    </div>
    <p>Cloudflare servers sit and listen for QUIC traffic on UDP port 443. Clients send an Initial QUIC packet in a UDP datagram which kicks off the handshake process. The Initial packet contains a version identifier, which the server checks and selects from. The client also provides, via the TLS Application Layer Negotiation Protocol extension, a list of application protocols it speaks. Today Cloudflare supports clients that directly connect to us and attempt to speak QUIC version 1 using the ALPN identifier "h3".</p><p>Over the years, as the draft wire format of the protocol has changed, new version and ALPN identifiers have been coined, helping to ensure the client and server pick something they can agree on. RFC 9000 coins the version 0x00000001. Since it's so new, we expect clients to continue sending some of the old ones as it takes time to support. These look like 0xff00001d, 0xff00001c, and 0xff00001b, which mark draft 29, 28, and 27 respectively. Version identifiers are 32-bits, which is conspicuous because a lot of other fields use QUICs <i>variable-length integer encoding</i> (<a href="https://www.rfc-editor.org/rfc/rfc9000.html#name-variable-length-integer-enc">see here</a>).</p><p>Before a client can even send an Initial QUIC packet however, it needs to know we're sat here listening for them! In the old days, HTTP relied on the URL to determine which TCP port to speak to. By default, it picked 80 for an http scheme, 443 for an https scheme, or used the value supplied in the authority component e.g. <a href="https://example.com:1234">https://example.com:1234</a>. Nobody wanted to change the URL schemes to support QUIC; that would have added tremendous friction to deployment.</p><p>While developing QUIC and HTTP/3, the Working Group generally relied on prior knowledge that a server would talk QUIC. And if something went wrong, we'd just ping each other directly on Slack. This kind of model obviously doesn't scale. For widespread real-world deployment we instead rely on HTTP Alternative Services (RFC 7838) to tell TCP-based clients that HTTP/3 is available. This is the method that web browsers will use to determine what protocols to use.When a client makes HTTP requests to a zone that has Cloudflare QUIC and HTTP/3 support enabled, we return an Alt-Svc header that tells it about all the QUIC versions we support. Here's an example:</p>
            <pre><code>$ curl -sI https://www.cloudflare.com/ | grep alt-svc
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400</code></pre>
            <p>The entry "h3-29" tells clients that we support HTTP/3 over QUIC draft version 29 on UDP port 443. If they support that they might just send us a QUIC Initial with the single version <b>0xff00001</b> and identifier "h3-29". Or to hedge their bets, they might send an initial with all versions that they support. Whichever type of Initial Cloudflare receives, we'll pick the highest version. They also might choose _not_ to use QUIC, for whatever reason they like, in which case they can just carry on as normal.</p><p>Previously, you needed to <a href="/how-to-test-http-3-and-quic-with-firefox-nightly/">enable experimental support</a> if you wanted to test it out in browsers. But now many of them have QUIC enabled by default and we expect them to start enabling QUIC v1 support soon. So today we've begun rolling out changes to our Alt-Svc advertisements to also include the "h3" identifier and we'll have complete world-wide support early next week. All of these protocol upgrade behaviours are done behind the scenes, hopefully your browsing experiences just appear to get magically faster. If you want to check what's happening, you can, for example, use a browser's network tools - just be sure to enable the Protocol column. Here's how it looks in Firefox:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/40t2IICcOJjpNbYclJVm3N/9b3390d0b88137917610abeb140e56da/image2-8.png" />
            
            </figure>
    <div>
      <h2>All powered by delicious Quiche!</h2>
      <a href="#all-powered-by-delicious-quiche">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4uiSku4MIBNz7VHzAR1H5B/e28eb3e55adb5be7f6d204168662db98/image5-5.png" />
            
            </figure><p>Cloudflare's QUIC and HTTP/3 support is powered by quiche, <a href="/enjoy-a-slice-of-quic-and-rust/">our own open-source implementation written in Rust</a>. You can find it on GitHub at <a href="https://github.com/cloudflare/quiche">github.com/cloudflare/quiche</a>.</p><p>Quiche is a Rust library that exposes a C API. We've designed it from day one to be easily integratable into many types of projects. Our <a href="/experiment-with-http-3-using-nginx-and-quiche/">edge servers</a> use it, <a href="https://developers.cloudflare.com/http3/curl-brew">curl uses it</a>, Mozilla uses our <a href="https://crates.io/crates/qlog">qlog</a> sub-crate in <a href="https://github.com/mozilla/neqo">neqo</a> (which powers Firefox's QUIC), <a href="https://github.com/netty/netty-incubator-codec-quic">netty uses it</a>, the list is quite long. We're excited to support this project and grow support for QUIC and HTTP/3 wherever we can. And it won't surprise you to hear that we have built some of our own tools to help us during development. quiche-client is a tool we use to get detailed information on all the nitty gritty details of QUIC connections. It also integrates into the <a href="https://interop.seemann.io/">interoperability testing matrix</a> that lets us continually assess interoperability and performance.</p><p>You can find <a href="https://developers.cloudflare.com/http3/quiche-http3-client">quiche-client</a> in the <a href="https://github.com/cloudflare/quiche/tree/master/tools">/tools folder</a> of the quiche repository. Here's an example of running it with all trace information turned on, I've highlighted the Initial version and selected ALPN. A corresponding client-{connection ID}.qlog file will be written out.</p>
            <pre><code>RUST_LOG=trace QLOG_DIR=$PWD cargo run --manifest-path tools/apps/Cargo.toml --bin quiche-client -- --wire-version 00000001  https://www.cloudflare.com

[2021-05-28T18:59:30.506616991Z INFO  quiche_apps::client] connecting to 104.16.123.96:443 from 192.168.0.50:41238 with scid 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b
[2021-05-28T18:59:30.506842369Z TRACE quiche::tls] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b write message lvl=Initial len=310
[2021-05-28T18:59:30.506891348Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b tx pkt Initial version=1 dcid=ed8de2d33a2e830279dfeaae8a7ad674 scid=5875ecd13154429e5c618eee35b6bbd9ecfe8c6b len=330 pn=0
[2021-05-28T18:59:30.506982912Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b tx frm CRYPTO off=0 len=310
[2021-05-28T18:59:30.507044916Z TRACE quiche::recovery] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b timer=998.815785ms latest_rtt=0ns srtt=None min_rtt=0ns rttvar=166.5ms loss_time=[None, None, None] loss_probes=[0, 0, 0] cwnd=13500 ssthresh=18446744073709551615 bytes_in_flight=377 app_limited=true congestion_recovery_start_time=None delivered=0 delivered_time=204.765µs recent_delivered_packet_sent_time=206.283µs app_limited_at_pkt=0  pacing_rate=0 last_packet_scheduled_time=Some(Instant { tv_sec: 620877, tv_nsec: 428024928 }) hystart=window_end=None last_round_min_rtt=None current_round_min_rtt=None rtt_sample_count=0 lss_start_time=None  
[2021-05-28T18:59:30.507160963Z TRACE quiche_apps::client] written 1200
[2021-05-28T18:59:30.537123997Z TRACE quiche_apps::client] got 1200 bytes
[2021-05-28T18:59:30.537194566Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b rx pkt Initial version=1 dcid=5875ecd13154429e5c618eee35b6bbd9ecfe8c6b scid=017022e8618952fd8c7177e863894eb0447b85f4 token= len=117 pn=0
&lt;snip&gt;
[2021-05-28T18:59:30.542581460Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b connection established: proto=Ok("h3") cipher=Some(AES128_GCM) curve=Some("X25519") sigalg=Some("ecdsa_secp256r1_sha256") resumed=false TransportParams { original_destination_connection_id: Some(ed8de2d33a2e830279dfeaae8a7ad674), max_idle_timeout: 180000, stateless_reset_token: None, max_udp_payload_size: 65527, initial_max_data: 10485760, initial_max_stream_data_bidi_local: 0, initial_max_stream_data_bidi_remote: 1048576, initial_max_stream_data_uni: 1048576, initial_max_streams_bidi: 256, initial_max_streams_uni: 3, ack_delay_exponent: 3, max_ack_delay: 25, disable_active_migration: false, active_conn_id_limit: 2, initial_source_connection_id: Some(017022e8618952fd8c7177e863894eb0447b85f4), retry_source_connection_id: None, max_datagram_frame_size: None }</code></pre>
            
    <div>
      <h2>So if QUIC is done, what's next?</h2>
      <a href="#so-if-quic-is-done-whats-next">
        
      </a>
    </div>
    <p>The road has been long, and we should celebrate the success of the community's efforts over many years to dream big and deliver something.  But as far as we're concerned, we're far from done. We've learned a lot from our early QUIC deployments - a big thank you to everyone in the wider Cloudflare team that supported the Protocols team getting here today. We'll continue to invest that back into our implementation and standardisation activities. <a href="/author/alessandro-ghedini/">Alessandro</a>, <a href="/author/junho/">Junho</a>, <a href="/author/lohith/">Lohith</a> and I will continue to participate in our respective areas of expertise in the IETF. Speaking for myself, I'll be continuing to co-chair the QUIC Working Group and help guide it through a new chapter focused on maintenance, operations, extensibility and… QUIC version 2. And I'll be moonlighting in other places like the <a href="https://datatracker.ietf.org/wg/httpbis/about/">HTTP</a> WG to push Prioritization over the line, and the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE</a> WG to help define how we can use <a href="https://datatracker.ietf.org/doc/html/draft-ietf-masque-h3-datagram-02">unreliable DATAGRAMS</a> to tunnel almost anything over QUIC and HTTP/3.</p>
    <div>
      <h2>A weekend riddle</h2>
      <a href="#a-weekend-riddle">
        
      </a>
    </div>
    <p>If you've made it this far, you are obviously very interested in QUIC. My colleague, Chris Wood, is like that too. He was very excited about the RFCs being shipped. So excited that he sent me this cryptic message:</p><p><i>"QUIC is finally here -- RFC </i><b><i>8999</i></b><i>, 9000, </i><b><i>9001</i></b><i>, and 9002. Are we and the rest of the Internet ready to turn it on? 0404d3f63f040214574904010a5735!</i></p><p>I have no clue what this means, can you help me out?</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">jMlsubMfOLintHjT8HGts</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[Moving k8s communication to gRPC]]></title>
            <link>https://blog.cloudflare.com/moving-k8s-communication-to-grpc/</link>
            <pubDate>Sat, 20 Mar 2021 14:00:00 GMT</pubDate>
            <description><![CDATA[ How we use gRPC in combination with Kubernetes to improve the performance and usability of internal APIs. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Over the past year and a half, Cloudflare has been hard at work moving our back-end services running in our non-edge locations from bare metal solutions and Mesos Marathon to a more unified approach using <a href="https://kubernetes.io/">Kubernetes(K8s)</a>. We chose Kubernetes because it allowed us to split up our monolithic application into many different microservices with granular control of communication.</p><p>For example, a <a href="https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/">ReplicaSet</a> in Kubernetes can provide high availability by ensuring that the correct number of pods are always available. A <a href="https://kubernetes.io/docs/concepts/workloads/pods/">Pod</a> in Kubernetes is similar to a container in <a href="https://www.docker.com/">Docker</a>. Both are responsible for running the actual application. These pods can then be exposed through a Kubernetes <a href="https://kubernetes.io/docs/concepts/services-networking/service/">Service</a> to abstract away the number of replicas by providing a single endpoint that load balances to the pods behind it. The services can then be exposed to the Internet via an <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/">Ingress</a>. Lastly, a network policy can protect against unwanted communication by ensuring the correct policies are applied to the application. These policies can include L3 or L4 rules.</p><p>The diagram below shows a simple example of this setup.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/33zWCqFZw2iuXfhllsHgdk/e290742e17a975a98a195bccc283297f/2-3.png" />
            
            </figure><p>Though Kubernetes does an excellent job at providing the tools for communication and traffic management, it does not help the developer decide the best way to communicate between the applications running on the pods. Throughout this blog we will look at some of the decisions we made and why we made them to discuss the pros and cons of two commonly used API architectures, REST and gRPC.</p>
    <div>
      <h3>Out with the old, in with the new</h3>
      <a href="#out-with-the-old-in-with-the-new">
        
      </a>
    </div>
    <p>When the DNS team first moved to Kubernetes, all of our pod-to-pod communication was done through REST APIs and in many cases also included Kafka. The general communication flow was as follows:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3GQIkngkqEYcBJNFzv1xNU/fe13bc8911a11a9c26dc5925b4fe6a19/1-5.png" />
            
            </figure><p>We use Kafka because it allows us to handle large spikes in volume without losing information. For example, during a Secondary DNS Zone zone transfer, Service A tells Service B that the zone is ready to be published to the edge. Service B then calls Service A’s REST API, generates the zone, and pushes it to the edge. If you want more information about how this works, I wrote an entire blog post about the <a href="/secondary-dns-deep-dive/">Secondary DNS pipeline</a> at Cloudflare.</p><p>HTTP worked well for most communication between these two services. However, as we scaled up and added new endpoints, we realized that as long as we control both ends of the communication, we could improve the usability and performance of our communication. In addition, sending large DNS zones over the network using HTTP often caused issues with sizing constraints and compression.</p><p>In contrast, gRPC can easily stream data between client and server and is commonly used in microservice architecture. These qualities made gRPC the obvious replacement for our REST APIs.</p>
    <div>
      <h3>gRPC Usability</h3>
      <a href="#grpc-usability">
        
      </a>
    </div>
    <p>Often overlooked from a developer’s perspective, HTTP client libraries are clunky and require code that defines paths, handles parameters, and deals with responses in bytes. gRPC abstracts all of this away and makes network calls feel like any other function calls defined for a struct.</p><p>The example below shows a very basic schema to set up a GRPC client/server system. As a result of gRPC using <a href="https://developers.google.com/protocol-buffers">protobuf</a> for serialization, it is largely language agnostic. Once a schema is defined, the <i>protoc</i> command can be used to generate code for <a href="https://grpc.io/docs/languages/">many languages</a>.</p><p>Protocol Buffer data is structured as <i>messages,</i> with each <i>message</i> containing information stored in the form of fields. The fields are strongly typed, providing type safety unlike JSON or XML. Two messages have been defined, <i>Hello</i> and <i>HelloResponse</i>. Next we define a service called <i>HelloWorldHandler</i> which contains one RPC function called <i>SayHello</i> that must be implemented if any object wants to call themselves a <i>HelloWorldHandler</i>.</p><p>Simple Proto:</p>
            <pre><code>message Hello{
   string Name = 1;
}

message HelloResponse{}

service HelloWorldHandler {
   rpc SayHello(Hello) returns (HelloResponse){}
}</code></pre>
            <p>Once we run our <i>protoc</i> command, we are ready to write the server-side code. In order to implement the <i>HelloWorldHandler</i>, we must define a struct that implements all of the RPC functions specified in the protobuf schema above_._ In this case, the struct <i>Server</i> defines a function <i>SayHello</i> that takes in two parameters, context and <i>*pb.Hello</i>. <i>*pb.Hello</i> was previously specified in the schema and contains one field, <i>Name. SayHello</i> must also return the <i>*pbHelloResponse</i> which has been defined without fields for simplicity.</p><p>Inside the main function, we create a TCP listener, create a new gRPC server, and then register our handler as a <i>HelloWorldHandlerServer</i>. After calling <i>Serve</i> on our gRPC server, clients will be able to communicate with the server through the function <i>SayHello</i>.</p><p>Simple Server:</p>
            <pre><code>type Server struct{}

func (s *Server) SayHello(ctx context.Context, in *pb.Hello) (*pb.HelloResponse, error) {
    fmt.Println("%s says hello\n", in.Name)
    return &amp;pb.HelloResponse{}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":8080")
    if err != nil {
        panic(err)
    }
    gRPCServer := gRPC.NewServer()
    handler := Server{}
    pb.RegisterHelloWorldHandlerServer(gRPCServer, &amp;handler)
    if err := gRPCServer.Serve(lis); err != nil {
        panic(err)
    }
}</code></pre>
            <p>Finally, we need to implement the gRPC Client. First, we establish a TCP connection with the server. Then, we create a new <i>pb.HandlerClient</i>. The client is able to call the server's <i>SayHello</i> function by passing in a *<i>pb.Hello</i> object.</p><p>Simple Client:</p>
            <pre><code>conn, err := gRPC.Dial("127.0.0.1:8080", gRPC.WithInsecure())
if err != nil {
    panic(err)
}
client := pb.NewHelloWorldHandlerClient(conn)
client.SayHello(context.Background(), &amp;pb.Hello{Name: "alex"})</code></pre>
            <p>Though I have removed some code for simplicity, these <i>services</i> and <i>messages</i> can become quite complex if needed. The most important thing to understand is that when a server attempts to announce itself as a <i>HelloWorldHandlerServer</i>, it is required to implement the RPC functions as specified within the protobuf schema. This agreement between the client and server makes cross-language network calls feel like regular function calls.</p><p>In addition to the basic Unary server described above, gRPC lets you decide between four types of service methods:</p><ul><li><p><b>Unary</b> (example above): client sends a single request to the server and gets a single response back, just like a normal function call.</p></li><li><p><b>Server Streaming:</b> server returns a stream of messages in response to a client's request.</p></li><li><p><b>Client Streaming:</b> client sends a stream of messages to the server and the server replies in a single message, usually once the client has finished streaming.</p></li><li><p><b>Bi-directional Streaming:</b> the client and server can both send streams of messages to each other asynchronously.</p></li></ul>
    <div>
      <h3>gRPC Performance</h3>
      <a href="#grpc-performance">
        
      </a>
    </div>
    <p>Not all HTTP connections are created equal. Though Golang natively supports HTTP/2, the HTTP/2 transport must be set by the client and the server must also support HTTP/2. Before moving to gRPC, we were still using HTTP/1.1 for client connections. We could have switched to HTTP/2 for performance gains, but we would have lost some of the benefits of native protobuf compression and usability changes.</p><p>The best option available in HTTP/1.1 is pipelining. Pipelining means that although requests can share a connection, they must queue up one after the other until the request in front completes. HTTP/2 improved pipelining by using connection multiplexing. Multiplexing allows for multiple requests to be sent on the same connection and at the same time.</p><p>HTTP REST APIs generally use JSON for their request and response format. Protobuf is the native request/response format of gRPC because it has a standard schema agreed upon by the client and server during registration. In addition, protobuf is known to be significantly faster than JSON due to its serialization speeds. I’ve run some benchmarks on my laptop, source code can be found <a href="https://github.com/Fattouche/protobuf-benchmark">here</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/23TkQ80Iruo8IYflqIuobN/f7323dd5817ca47f9b203b8b63a3a980/image1-26.png" />
            
            </figure><p>As you can see, protobuf performs better in small, medium, and large data sizes. It is faster per operation, smaller after marshalling, and scales well with input size. This becomes even more noticeable when unmarshaling very large data sets. Protobuf takes 96.4ns/op but JSON takes 22647ns/op, a 235X reduction in time! For large DNS zones, this efficiency makes a massive difference in the time it takes us to go from record change in our API to serving it at the edge.</p><p>Combining the benefits of HTTP/2 and protobuf showed almost no performance change from our application’s point of view. This is likely due to the fact that our pods were already so close together that our connection times were already very low. In addition, most of our gRPC calls are done with small amounts of data where the difference is negligible. One thing that we did notice <b>—</b> likely related to the multiplexing of HTTP/2 <b>—</b> was greater efficiency when writing newly created/edited/deleted records to the edge. Our latency spikes dropped in both amplitude and frequency.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6PDR6bZkh8zzVVv2j6tmE5/9ce516e00daa832135964246eaf7b95c/image2-19.png" />
            
            </figure>
    <div>
      <h3>gRPC Security</h3>
      <a href="#grpc-security">
        
      </a>
    </div>
    <p>One of the best features in Kubernetes is the NetworkPolicy. This allows developers to control what goes in and what goes out.</p>
            <pre><code>apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978</code></pre>
            <p>In this example, taken from the <a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">Kubernetes docs</a>, we can see that this will create a network policy called test-network-policy. This policy controls both ingress and egress communication to or from any pod that matches the role <i>db</i> and enforces the following rules:</p><p>Ingress connections allowed:</p><ul><li><p>Any pod in default namespace with label “role=frontend”</p></li><li><p>Any pod in any namespace that has a label “project=myproject”</p></li><li><p>Any source IP address in 172.17.0.0/16 except for 172.17.1.0/24</p></li></ul><p>Egress connections allowed:</p><ul><li><p>Any dest IP address in 10.0.0.0/24</p></li></ul><p>NetworkPolicies do a fantastic job of protecting APIs at the network level, however, they do nothing to protect APIs at the application level. If you wanted to control which endpoints can be accessed within the API, you would need k8s to be able to not only distinguish between pods, but also endpoints within those pods. These concerns led us to <a href="https://grpc.io/docs/guides/auth/">per RPC credentials</a>. Per RPC credentials are easy to set up on top of the pre-existing gRPC code. All you need to do is add interceptors to both your stream and unary handlers.</p>
            <pre><code>func (s *Server) UnaryAuthInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    // Get the targeted function
    functionInfo := strings.Split(info.FullMethod, "/")
    function := functionInfo[len(functionInfo)-1]
    md, _ := metadata.FromIncomingContext(ctx)

    // Authenticate
    err := authenticateClient(md.Get("username")[0], md.Get("password")[0], function)
    // Blocked
    if err != nil {
        return nil, err
    }
    // Verified
    return handler(ctx, req)
}</code></pre>
            <p>In this example code snippet, we are grabbing the username, password, and requested function from the info object. We then authenticate against the client to make sure that it has correct rights to call that function. This interceptor will run before any of the other functions get called, which means one implementation protects all functions. The client would initialize its secure connection and send credentials like so:</p>
            <pre><code>transportCreds, err := credentials.NewClientTLSFromFile(certFile, "")
if err != nil {
    return nil, err
}
perRPCCreds := Creds{Password: grpcPassword, User: user}
conn, err := grpc.Dial(endpoint, grpc.WithTransportCredentials(transportCreds), grpc.WithPerRPCCredentials(perRPCCreds))
if err != nil {
    return nil, err
}
client:= pb.NewRecordHandlerClient(conn)
// Can now start using the client</code></pre>
            <p>Here the client first verifies that the server matches with the certFile. This step ensures that the client does not accidentally send its password to a bad actor. Next, the client initializes the <i>perRPCCreds</i> struct with its username and password and dials the server with that information. Any time the client makes a call to an rpc defined function, its credentials will be verified by the server.</p>
    <div>
      <h3>Next Steps</h3>
      <a href="#next-steps">
        
      </a>
    </div>
    <p>Our next step is to remove the need for many applications to access the database and ultimately DRY up our codebase by pulling all DNS-related code into a single API, accessed from one gRPC interface. This removes the potential for mistakes in individual applications and makes updating our database schema easier. It also gives us more granular control over which functions can be accessed rather than which tables can be accessed.</p><p>So far, the DNS team is very happy with the results of our gRPC migration. However, we still have a long way to go before we can move entirely away from REST. We are also patiently waiting for <a href="https://github.com/grpc/grpc/issues/19126">HTTP/3 support</a> for gRPC so that we can take advantage of those super <a href="https://en.wikipedia.org/wiki/QUIC">quic</a> speeds!</p> ]]></content:encoded>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[gRPC]]></category>
            <category><![CDATA[Kubernetes]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[QUIC]]></category>
            <guid isPermaLink="false">6oeh7RRYqhqnS7vtJ2BpwP</guid>
            <dc:creator>Alex Fattouche</dc:creator>
        </item>
        <item>
            <title><![CDATA[A Last Call for QUIC, a giant leap for the Internet]]></title>
            <link>https://blog.cloudflare.com/last-call-for-quic/</link>
            <pubDate>Thu, 22 Oct 2020 14:08:51 GMT</pubDate>
            <description><![CDATA[ QUIC and HTTP/3 are open standards that have been under development in the IETF for almost exactly 4 years. On October 21, 2020, following two rounds of Working Group Last Call, draft 32 of the family of documents that describe QUIC and HTTP/3 were put into IETF Last Call. ]]></description>
            <content:encoded><![CDATA[ <p>QUIC is a new Internet transport protocol for secure, reliable and multiplexed communications. <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> builds on top of QUIC, leveraging the new features to fix performance problems such as Head-of-Line blocking. This enables web pages to load faster, especially over troublesome networks.</p><p>QUIC and HTTP/3 are open standards that have been under development in the IETF <a href="/http-3-from-root-to-tip">for almost exactly 4 years</a>. On October 21, 2020, following two rounds of Working Group Last Call, draft 32 of the family of documents that describe QUIC and HTTP/3 were put into <a href="https://mailarchive.ietf.org/arch/msg/quic/ye1LeRl7oEz898RxjE6D3koWhn0/">IETF Last Call</a>. This is an important milestone for the group. We are now telling the entire IETF community that we think we're almost done and that we'd welcome their final review.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78vaeSkXoriOtIbPyOU5rw/8ce2942b6542d94b5d0d42fc9e91d7b7/image2-24.png" />
            
            </figure><p>Speaking personally, I've been involved with QUIC in some shape or form for many years now. Earlier this year I was honoured to be asked to help co-chair the Working Group. I'm pleased to help shepherd the documents through this important phase, and grateful for the efforts of everyone involved in getting us there, especially the editors. I'm also excited about future opportunities to evolve on top of QUIC v1 to help build a better Internet.</p><p>There are two aspects to protocol development. One aspect involves writing and iterating upon the documents that describe the protocols themselves. Then, there's implementing, deploying and testing libraries, clients and/or servers. These aspects operate hand in hand, helping the Working Group move towards satisfying the goals listed in its charter. IETF Last Call marks the point that the group and their responsible Area Director (in this case Magnus Westerlund) believe the job is almost done. Now is the time to solicit feedback from the wider IETF community for review. At the end of the Last Call period, the stakeholders will take stock, address feedback as needed and, fingers crossed, go onto the next step of requesting the documents be published as RFCs on the Standards Track.</p><p>Although specification and implementation work hand in hand, they often progress at different rates, and that is totally fine. The QUIC specification has been mature and deployable for a long time now. HTTP/3 has been <a href="/http3-the-past-present-and-future/">generally available</a> on the Cloudflare edge since September 2019, and we've been delighted to see support roll out in user agents such as Chrome, Firefox, Safari, curl and so on. Although draft 32 is the latest specification, the community has for the time being settled on draft 29 as a solid basis for interoperability. This shouldn't be surprising, as foundational aspects crystallize the scope of changes between iterations decreases. For the average person in the street, there's not really much difference between 29 and 32.</p><p>So today, if you visit a website with HTTP/3 enabled—such as <a href="https://cloudflare-quic.com">https://cloudflare-quic.com</a>—you’ll probably see response headers that contain Alt-Svc: h3-29="… . And in a while, once Last Call completes and the RFCs ship, you'll start to see websites simply offer Alt-Svc: h3="… (note, no draft version!).</p>
    <div>
      <h3>Need a deep dive?</h3>
      <a href="#need-a-deep-dive">
        
      </a>
    </div>
    <p>We've collected a bunch of resource links at <a href="https://cloudflare-quic.com">https://cloudflare-quic.com</a>. If you're more of an interactive visual learner, you might be pleased to hear that I've also been hosting a series on <a href="https://cloudflare.tv/live">Cloudflare TV</a> called "Levelling up Web Performance with HTTP/3". There are over 12 hours of content including the basics of QUIC, ways to measure and debug the protocol in action using tools like Wireshark, and several deep dives into specific topics. I've also been lucky to have some guest experts join me along the way. The table below gives an overview of the episodes that are available on demand.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/41Oavd19lBk474V1BOr1ZQ/3b6d0466c42b3940e6329c754c63863d/image1-36.png" />
            
            </figure><p>Episode</p><p>Description</p><p><a href="https://cloudflare.tv/event/6jJjzbBoFwvARsoaNiUt9i">1</a></p><p>Introduction to QUIC.</p><p><a href="https://cloudflare.tv/event/5rcGVibHCKs9l9xUUMdJqg">2</a></p><p>Introduction to HTTP/3.</p><p><a href="https://cloudflare.tv/event/3OM7upT7p3vpAdzphFdhnx">3</a></p><p>QUIC &amp; HTTP/3 logging and analysis using qlog and qvis. Featuring Robin Marx.</p><p><a href="https://cloudflare.tv/event/45tQd4UPkZGULg59BZPl1p">4</a></p><p>QUIC &amp; HTTP/3 packet capture and analysis using Wireshark. Featuring Peter Wu.</p><p><a href="https://cloudflare.tv/event/4YgvMrif2yma7pM6Srv6wi">5</a></p><p>The roles of Server Push and Prioritization in HTTP/2 and HTTP/3. Featuring Yoav Weiss.</p><p><a href="https://cloudflare.tv/event/7ufIyfjZfn2aQ2K635EH3t">6</a></p><p>"After dinner chat" about curl and QUIC. Featuring Daniel Stenberg.</p><p><a href="https://cloudflare.tv/event/6vMyFU2jyx2iKXZVp7YjHW">7</a></p><p>Qlog vs. Wireshark. Featuring Robin Marx and Peter Wu.</p><p><a href="https://cloudflare.tv/event/3miIPtXnktpzjslJlnkD9c">8</a></p><p>Understanding protocol performance using WebPageTest. Featuring Pat Meenan and Andy Davies.</p><p><a href="https://cloudflare.tv/event/6Qv7zmY2oi6j28M5HZNZmV">9</a></p><p>Handshake deep dive.</p><p><a href="https://cloudflare.tv/event/3gqUUBcl40LvThxO7UQH0T">10</a></p><p>Getting to grips with quiche, Cloudflare's QUIC and HTTP/3 library.</p><p><a href="https://cloudflare.tv/event/3Mrq6DHoA9fy4ATT3Wigrv">11</a></p><p>A review of SIGCOMM's EPIQ workshop on evolving QUIC.</p><p><a href="https://cloudflare.tv/event/CHrSpig5nqKeFGFA3fzLq">12</a></p><p>Understanding the role of congestion control in QUIC. Featuring Junho Choi.</p><p></p>
    <div>
      <h3>Whither QUIC?</h3>
      <a href="#whither-quic">
        
      </a>
    </div>
    <p>So does Last Call mean QUIC is "done"? Not by a long shot. The new protocol is a giant leap for the Internet, because it enables new opportunities and innovation. QUIC v1 is basically the set of documents that have gone into Last Call. We'll continue to see people gain experience deploying and testing this, and no doubt cool blog posts about tweaking parameters for efficiency and performance are on the radar. But QUIC and HTTP/3 are extensible, so we'll see people interested in trying new things like multipath, different congestion control approaches, or new ways to carry data unreliably such as the <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/">DATAGRAM frame</a>.</p><p>We're also seeing people interested in using QUIC for other use cases. Mapping other application protocols like DNS to QUIC is a rapid way to get its improvements. We're seeing people that want to use QUIC as a substrate for carrying other transport protocols, hence the formation of the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE Working Group</a>. There's folks that want to use QUIC and HTTP/3 as a "supercharged WebSocket", hence the formation of the <a href="https://datatracker.ietf.org/wg/webtrans/documents/">WebTransport Working Group</a>.</p><p>Whatever the future holds for QUIC, we're just getting started, and I'm excited.</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Speed]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">4kkjRctgxi0uvF46ddKnp6</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[How to test HTTP/3 and QUIC with Firefox Nightly]]></title>
            <link>https://blog.cloudflare.com/how-to-test-http-3-and-quic-with-firefox-nightly/</link>
            <pubDate>Tue, 30 Jun 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ Now that Firefox Nightly supports HTTP/3 we thought we'd share some instructions to help you enable and test it yourselves. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6LFuqXEde60ewdAIKCGpBU/bf9372291e6c9ed483d3df9b8d1c2018/HTTP3-partnership-nightly-_3x-1.png" />
            
            </figure><p><a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> is the third major version of the Hypertext Transfer Protocol, which takes the bold step of moving away from TCP to the new transport protocol QUIC in order to provide performance and security improvements.</p><p>During Cloudflare's Birthday Week 2019, we were <a href="/http3-the-past-present-and-future/">delighted to announce</a> that we had enabled QUIC and HTTP/3 support on the Cloudflare edge network. This was joined by support from Google Chrome and Mozilla Firefox, two of the leading browser vendors and partners in our effort to make the web faster and more reliable for all. A big part of developing new standards is interoperability, which typically means different people analysing, implementing and testing a written specification in order to prove that it is precise, unambiguous, and actually implementable.</p><p>At the time of our announcement, Chrome Canary had experimental HTTP/3 support and we were eagerly awaiting a release of Firefox Nightly. Now that Firefox supports HTTP/3 we thought we'd share some instructions to help you enable and test it yourselves.</p>
    <div>
      <h3>How do I enable HTTP/3 for my domain?</h3>
      <a href="#how-do-i-enable-http-3-for-my-domain">
        
      </a>
    </div>
    <p>Simply go to the Cloudflare dashboard and flip the switch from the "Network" tab manually:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/zkM5pyAf9MD0HhWqueVP3/e4d9d2d8ae7a37b5da5c0bda7e9447e5/http3-toggle-1.png" />
            
            </figure>
    <div>
      <h3>Using Firefox Nightly as an HTTP/3 client</h3>
      <a href="#using-firefox-nightly-as-an-http-3-client">
        
      </a>
    </div>
    <p>Firefox Nightly has experimental support for HTTP/3. In our experience things are pretty good but be aware that you might experience some teething issues, so bear that in mind if you decide to enable and experiment with HTTP/3. If you're happy with that responsibility, you'll first need to download and install the <a href="https://www.mozilla.org/firefox/channel/desktop/">latest Firefox Nightly build</a>. Then open Firefox and enable HTTP/3 by visiting "about:config" and setting "network.http.http3.enabled" to true. There are some other parameters that can be tweaked but the defaults should suffice.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4UGnSGsahi5Qm5bqtL5qho/dfa340c0825d974ae1164bc1e6eaedda/firefox-h3-about-config.png" />
            
            </figure><p>about:config can be filtered by using a search term like "http3".</p><p>Once HTTP/3 is enabled, you can visit your site to test it out. A straightforward way to check if HTTP/3 was negotiated is to check the Developer Tools "Protocol" column in the "Network" tab (on Windows and Linux the Developer Tools keyboard shortcut is Ctrl+Shift+I, on macOS it's Command+Option+I). This "Protocol" column might not be visible at first, so to enable it right-click one of the column headers and check "Protocol" as shown below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/61omvb6CpN2nUSd6mFvqiB/c0a23a5a0551f5583efa1a5d76f7a94f/firefox-h3-protocol-column.png" />
            
            </figure><p>Then reload the page and you should see that "HTTP/3" is reported.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Q8evveLC4cyU0PGHISWmJ/58930682b8a9751208a2a6c3845db588/firefox-h3-success.png" />
            
            </figure><p>The aforementioned teething issues might cause HTTP/3 not to show up initially. When you enable HTTP/3 on a zone, we add a header field such as <code><i>alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400</i></code> to all responses for that zone. Clients see this as an advertisement to try HTTP/3 out and will take up the offer on the <b>next</b> request. So to make this happen you can reload the page but make sure that you bypass the local browser cache (via the "Disable Cache" checkbox, or use the Shift-F5 key combo) or else you'll just see the protocol used to fetch the resource the first time around. Finally, Firefox provides the "about:networking" page which provides a list of visited zones and the HTTP version that was used to load them; for example, this very blog.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/72pladWtRSe3QS38rhRR0F/59b97837d711a7f5bad8cf94f1d9cb43/firefox-h3-about-networking.png" />
            
            </figure><p>about:networking contains a table of all visited zones and the connection properties.</p><p>Sometimes browsers can get sticky to an existing HTTP connection and will refuse to start an HTTP/3 connection, this is hard to detect by humans, so sometimes the best option is to close the app completely and reopen it. Finally, we've also seen some interactions with Service Workers that make it appear that a resource was fetched from the network using HTTP/1.1, when in fact it was fetched from the local Service Worker cache. In such cases if you're keen to see HTTP/3 in action then you'll need to deregister the Service Worker. If you're in doubt about what is happening on the network it is often useful to verify things independently, for example capturing a packet trace and dissecting it with Wireshark.</p>
    <div>
      <h2>What’s next?</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>The QUIC Working Group recently <a href="https://mailarchive.ietf.org/arch/msg/quic/F7wvKGnA1FJasmaE35XIxsc2Tno/">announced a "Working Group Last Call"</a>, which marks an important milestone in the continued maturity of the standards. From the announcement:</p><blockquote><p><i>After more than three and a half years and substantial discussion, all 845 of the design issues raised against the QUIC protocol drafts have gained consensus or have a proposed resolution. In that time the protocol has been considerably transformed; it has become more secure, much more widely implemented, and has been shown to be interoperable. Both the Chairs and the Editors feel that it is ready to proceed in standardisation.</i></p></blockquote><p>The coming months will see the specifications settle and we anticipate that implementations will continue to improve their QUIC and HTTP/3 support, eventually enabling it in their stable channels. We're pleased to continue working with <a href="https://www.cloudflare.com/case-studies/mozilla/">industry partners such as Mozilla</a> to help build a better Internet together.</p><p>In the meantime, you might want to <a href="https://developers.cloudflare.com/http3/intro">check out our guides</a> to testing with other implementations such as Chrome Canary or curl. As compatibility becomes proven, implementations will shift towards optimizing their performance; you can read about Cloudflare's efforts on <a href="/http-3-vs-http-2/">comparing HTTP/3 to HTTP/2</a> and the work we've done to improve performance by <a href="/cubic-and-hystart-support-in-quiche/">adding support for CUBIC and HyStart++</a> to our congestion control module.</p> ]]></content:encoded>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[HTTP3]]></category>
            <guid isPermaLink="false">3vxyDdvWdI550GPFsqj0D5</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[CUBIC and HyStart++ Support in quiche]]></title>
            <link>https://blog.cloudflare.com/cubic-and-hystart-support-in-quiche/</link>
            <pubDate>Fri, 08 May 2020 12:46:12 GMT</pubDate>
            <description><![CDATA[ Congestion control and loss recovery play a big role in the QUIC transport protocol performance. We recently added support for CUBIC and HyStart++ to quiche, the library powering Cloudflare's QUIC, and lab-based testing shows promising results for performance in lossy network conditions. ]]></description>
            <content:encoded><![CDATA[ <p><a href="https://github.com/cloudflare/quiche">quiche</a>, Cloudflare's IETF QUIC implementation has been running <a href="https://tools.ietf.org/html/rfc8312">CUBIC congestion control</a> for a while in our production environment as mentioned in <a href="/http-3-vs-http-2/">Comparing HTTP/3 vs. HTTP/2 Performance</a>. Recently we also added <a href="https://tools.ietf.org/html/draft-balasubramanian-tcpm-hystartplusplus-03">HyStart++</a>  to the congestion control module for further improvements.</p><p>In this post, we will talk about QUIC congestion control and loss recovery briefly and CUBIC and HyStart++ in the quiche congestion control module. We will also discuss lab test results and how to visualize those using <a href="https://tools.ietf.org/html/draft-marx-qlog-event-definitions-quic-h3-01">qlog</a> which was recently added to the quiche library as well.</p>
    <div>
      <h3>QUIC Congestion Control and Loss Recovery</h3>
      <a href="#quic-congestion-control-and-loss-recovery">
        
      </a>
    </div>
    <p>In the network transport area, congestion control is how to decide how much data the connection can send into the network. It has an important role in networking so as not to overrun the link but also at the same time it needs to play nice with other connections in the same network to ensure that the overall network, the Internet, doesn’t collapse. Basically congestion control is trying to detect the current capacity of the link and tune itself in real time and it’s one of the core algorithms for running the Internet.</p><p>QUIC congestion control has been written based on many years of TCP experience, so it is little surprise that the two have mechanisms that bear resemblance. It’s based on the CWND (congestion window, the limit of how many bytes you can send to the network) and the SSTHRESH (slow start threshold, sets a limit when slow start will stop). Congestion control mechanisms can have complicated edge cases and can be hard to tune. Since QUIC is a new transport protocol that people are implementing from scratch, the current draft recommends Reno as a relatively simple mechanism to get people started. However, it has known limitations and so QUIC is designed to have pluggable congestion control; it’s up to implementers to adopt any more advanced ones of their choosing.</p><p>Since Reno became the standard for TCP congestion control, many congestion control algorithms have been proposed by academia and industry. Largely there are two categories: loss-based congestion control such as Reno and CUBIC, where the congestion control responds to a packet loss event, and delay-based congestion control, such as <a href="https://www.cs.princeton.edu/courses/archive/fall06/cos561/papers/vegas.pdf">Vegas</a> and <a href="https://queue.acm.org/detail.cfm?id=3022184">BBR</a> , which the algorithm tries to find a balance between the bandwidth and <a href="https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/">RTT</a> increase and tune the packet send rate.</p><p>You can port TCP based congestion control algorithms to QUIC without much change by implementing a few hooks. quiche provides a modular API to add a new congestion control module easily.</p><p>Loss detection is how to detect packet loss at the sender side. It’s usually separated from the congestion control algorithm but helps the congestion control to quickly respond to the congestion. Packet loss can be a result of the congestion on the link, but the link layer may also drop a packet without congestion due to the characteristics of the physical layer, such as on a WiFi or mobile network.</p><p>Traditionally TCP uses 3 DUP ACKs for ACK based detection, but delay-based loss detection such as <a href="https://tools.ietf.org/html/draft-ietf-tcpm-rack-08">RACK</a>  has also been used over the years. QUIC combines the lesson from TCP into <a href="https://tools.ietf.org/html/draft-ietf-quic-recovery-27#section-5">two categories</a> . One is based on the packet threshold (similar to 3 DUP ACK detection) and the other is based on a time threshold (similar to RACK). QUIC also has <a href="https://tools.ietf.org/html/draft-ietf-quic-recovery-27#section-3.1.5">ACK Ranges</a> similar to TCP SACK to provide a status of the received packets but ACK Ranges can keep a longer list of received packets in the ACK frame than TCP SACK. This simplifies the implementation overall and helps provide quick recovery when there is multiple loss.</p>
    <div>
      <h3>Reno</h3>
      <a href="#reno">
        
      </a>
    </div>
    <p>Reno (often referred as NewReno) is a standard <a href="https://tools.ietf.org/html/rfc5681">congestion control for TCP</a> and <a href="https://tools.ietf.org/id/draft-ietf-quic-recovery-27.html#section-6">QUIC</a> .</p><p>Reno is easy to understand and doesn't need additional memory to store the state so can be implemented in low spec hardware too. However, its slow start can be very aggressive because it keeps increasing the CWND quickly until it sees congestion. In other words, it doesn’t stop until it sees the packet loss.</p><p>Note that there are multiple states for Reno; Reno starts from "slow start" mode which increases the CWND very aggressively, roughly 2x for every RTT until the congestion is detected or CWND &gt; SSTHRESH. When packet loss is detected, it enters into the “recovery” mode until packet loss is recovered.</p><p>When it exits from recovery (no lost ranges) and CWND &gt; SSTHRESH, it enters into the "congestion avoidance" mode where the CWND grows slowly (roughly a full packet per RTT) and tries to converge on a stable CWND. As a result you will see a “sawtooth” pattern when you make a graph of the CWND over time.</p><p>Here is an example of Reno congestion control CWND graph. See the “Congestion Window” line.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7oTUuWLimS5jC3imLTcZY1/c7008deac0b62ac774735f2dda0a0324/reno-nohs.png" />
            
            </figure>
    <div>
      <h3>CUBIC</h3>
      <a href="#cubic">
        
      </a>
    </div>
    <p>CUBIC was announced in 2008 and became the default congestion control in the Linux kernel. Currently it's defined in <a href="https://tools.ietf.org/html/rfc8312">RFC8312</a>  and implemented in many OS including Linux, BSD and Windows. quiche's CUBIC implementation follows RFC8312 with a fix made by <a href="https://github.com/torvalds/linux/commit/30927520dbae297182990bb21d08762bcc35ce1d">Google in the Linux kernel</a> .</p><p>What makes the difference from Reno is during congestion avoidance  its CWND growth is based on a cubic function as follows:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1KI70rYLDzS02VWarowfyi/981f066dfbf86f11c0a2cc5c697d8d84/1J22foaznVbLs-waPSxKZusUf88svZfepM2QeTeDGe3kvjnkYKN73L861cTQu2eaxLBNtQhW-WEvmlqv3YWf_tRdfTLFXMcWDmUuNzSFanrz53N-9c4insL5kXnj.png" />
            
            </figure><p>(from the CUBIC paper: <a href="https://www.cs.princeton.edu/courses/archive/fall16/cos561/papers/Cubic08.pdf">https://www.cs.princeton.edu/courses/archive/fall16/cos561/papers/Cubic08.pdf</a>)</p><p><i>Wmax</i> is the value of CWND when the congestion is detected. Then it will reduce the CWND by 30% and then the CWND starts to grow again using a cubic function as in the graph, approaching <i>Wmax</i> aggressively in the beginning in the first half but slowly converging to <i>Wmax</i> later. This makes sure that CWND growth approaches the previous point carefully and once we pass <i>Wmax</i>, it starts to grow aggressively again after some time to find a new CWND (this is called "Max Probing").</p><p>Also it has a "TCP-friendly" (actually a Reno-friendly) mode to make sure CWND growth is always bigger than Reno. When the congestion event happens, CUBIC reduces its CWND by 30%, where Reno cuts down CWND by 50%. This makes CUBIC a little more aggressive on packet loss.</p><p>Note that the original CUBIC only defines how to update the CWND during congestion avoidance. Slow start mode is exactly the same as Reno.</p>
    <div>
      <h3>HyStart++</h3>
      <a href="#hystart">
        
      </a>
    </div>
    <p>The authors of CUBIC made a separate effort to improve slow start because CUBIC only changed the way the CWND grows during congestion avoidance. They came up with the idea of <a href="https://www.sciencedirect.com/science/article/abs/pii/S1389128611000363">HyStart</a> .</p><p>HyStart is based on two ideas and basically changes how the CWND is updated during slow start:</p><ul><li><p>RTT delay samples: when the RTT is increased during slow start and over the threshold, it exits slow start early and enters into congestion avoidance.</p></li><li><p>ACK train: When ACK inter-arrival time gets higher and over the threshold, it exits slow start early and enters into congestion avoidance.</p></li></ul><p>However in the real world, ACK train may not be very useful because of ACK compression (merging multiple ACKs into one). Also RTT delay may not work well when the network is unstable.</p><p>To improve such situations there is a new IETF draft proposed by Microsoft engineers named <a href="https://tools.ietf.org/html/draft-balasubramanian-tcpm-hystartplusplus-03">HyStart++</a> . HyStart++ is included in the Windows 10 TCP stack with CUBIC.</p><p>It's a little different from original HyStart:</p><ul><li><p>No ACK Train, only RTT sampling.</p></li><li><p>Add a LSS (Limited Slow Start) phase after exiting slow start. LSS grows the CWND faster than congestion avoidance but slower than Reno slow start. Instead of going into congestion avoidance directly, slow start exits to LSS and LSS exits to congestion avoidance when packet loss happens.</p></li><li><p>Simpler implementation.</p></li></ul><p>In quiche, HyStart++ is turned on by default for both Reno and CUBIC congestion control and can be configured via API.</p>
    <div>
      <h3>Lab Test</h3>
      <a href="#lab-test">
        
      </a>
    </div>
    <p>Here is a test result using <a href="/a-cost-effective-and-extensible-testbed-for-transport-protocol-development/">the test lab</a> . The test condition is as follows:</p><ul><li><p>5Mbps bandwidth, 60ms RTT with a different packet loss from 0% to 8%</p></li><li><p>Measure download time of 8MB file</p></li><li><p>NGINX 1.16.1 server with the <a href="https://github.com/cloudflare/quiche/tree/master/extras/nginx">HTTP3 patch</a></p></li><li><p>TCP: CUBIC in Linux kernel 4.14</p></li><li><p>QUIC: Cloudflare quiche</p></li><li><p>Download 20 times and take a median download time</p></li></ul><p>I run the test with the following combination:</p><ul><li><p>TCP CUBIC (TCP-CUBIC)</p></li><li><p>QUIC Reno (QUIC-RENO)</p></li><li><p>QUIC Reno with Hystart++ (QUIC-RENO-HS)</p></li><li><p>QUIC CUBIC (QUIC-CUBIC)</p></li><li><p>QUIC CUBIC with Hystart++ (QUIC-CUBIC-HS)</p></li></ul>
    <div>
      <h3>Overall Test Result</h3>
      <a href="#overall-test-result">
        
      </a>
    </div>
    <p>Here is a chart of overall test results:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/9p0dppTGft9jL6vBZrpI7/edf89c790e406e83b0df0c556b3c45fb/image6-2.png" />
            
            </figure><p>In these tests, TCP-CUBIC (blue bars) is the baseline to which we compare the performance of QUIC congestion control variants. We include QUIC-RENO (red and yellow bars) because that is the default QUIC baseline. Reno is simpler so we expect it to perform worse than TCP-CUBIC. QUIC-CUBIC (green and orange bars) should perform the same or better than TCP-CUBIC.</p><p>You can see with 0% packet loss TCP and QUIC are almost doing the same (but QUIC is slightly slower). As  packet loss increases QUIC CUBIC performs better than TCP CUBIC. QUIC loss recovery looks to work well, which is great news for real-world networks that do encounter loss.</p><p>With HyStart++, overall performance doesn’t change but that is to be expected, because the main goal of HyStart++ is to prevent overshooting the network. We will see that in the next section.</p>
    <div>
      <h3>The impact of HyStart++</h3>
      <a href="#the-impact-of-hystart">
        
      </a>
    </div>
    <p>HyStart++ may not improve the download time but it will reduce packet loss while maintaining the same performance without it. Since slow start will exit to congestion avoidance when packet loss is detected, we focus on 0% packet loss where only network congestion creates packet loss.</p>
    <div>
      <h3>Packet Loss</h3>
      <a href="#packet-loss">
        
      </a>
    </div>
    <p>For each test, the number of detected packets lost (not the retransmit count) is shown in the following chart. The lost packets number is the average of 20 runs for each test.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3IMpVqPBHkCvQhDQnrJE81/b23f89e3a15cb314700532b371898a46/lost_pkt_hs.png" />
            
            </figure><p>As shown above, you can see that HyStart++ reduces a lot of packet loss.</p><p>Note that compared with Reno, CUBIC can create more packet loss in general. This is because the CUBIC CWND can grow faster than Reno during congestion avoidance and also reduces the CWND less (30%) than Reno (50%) at the congestion event.</p>
    <div>
      <h3>Visualization using qlog and qvis</h3>
      <a href="#visualization-using-qlog-and-qvis">
        
      </a>
    </div>
    <p><a href="https://qvis.edm.uhasselt.be">qvis</a>  is a visualization tool based on <a href="https://tools.ietf.org/html/draft-marx-qlog-event-definitions-quic-h3-01">qlog</a> . Since quiche has implemented <a href="https://github.com/cloudflare/quiche/pull/379">qlog support</a> , we can take qlogs from a QUIC connection and use the qvis tool to visualize connection stats. This is a very useful tool for protocol development. We already used qvis for the Reno graph but let’s see a few more examples to understand how HyStart++ works.</p>
    <div>
      <h3>CUBIC without HyStart++</h3>
      <a href="#cubic-without-hystart">
        
      </a>
    </div>
    <p>Here is a qvis congestion chart for a 16MB transfer in the same lab test conditions, with 0% packet loss. You can see a high peak of CWND in the beginning due to slow start. After some time, it starts to show the CUBIC window growth pattern (concave function).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/147wv6vAfFBfVunzmgqi4Z/037337856e3edf6983e7d88f27f21d76/cubic-nohs.png" />
            
            </figure><p>When we zoom into the slow start section (the first 0.7 seconds), we can see there is a linear increase of CWND during slow start. This continues until we see a packet lost around 500ms and enters into congestion avoidance after recovery, as you can see in the following chart:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2N7Oiud9tfiQq8JQ1ReRxV/a656abfba8f9dc62778600274861d83b/cubic-nohs-zoom-legend.png" />
            
            </figure>
    <div>
      <h3>CUBIC with HyStart++</h3>
      <a href="#cubic-with-hystart">
        
      </a>
    </div>
    <p>Let’s see the same graph when HyStart++ is enabled. You can see the slow start peak is smaller than without HyStart++, which will lead to less overshooting and packet loss:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3g0T9fYiwD4biGawOh7LTS/ed5f2dfe915751e0fbad12ffd532624c/cubic-hs.png" />
            
            </figure><p>When we zoom in the slow start part again, now we can see that the slow start exits to Limited Slow Start (LSS) around 390ms and exit to congestion avoidance at the congestion event around 500ms.</p><p>As a result you can see the slope is less steep until congestion is detected. It will lead to less packet loss due to less overshooting the network and faster convergence to a stable CWND.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/49le5NmySGIuvRcZETrR8Z/67236043dd84b2932e23d0ea5db3d95d/cubic-hs-zoom-legend.png" />
            
            </figure>
    <div>
      <h3>Conclusions and Future Tasks</h3>
      <a href="#conclusions-and-future-tasks">
        
      </a>
    </div>
    <p>The QUIC draft spec already has integrated a lot of experience from TCP congestion control and loss recovery. It recommends the simple Reno mechanism as a means to get people started implementing the protocol but is under no illusion that there are better performing ones out there. So QUIC is designed to be pluggable in order for it to adopt mechanisms that are being deployed in state-of-the-art TCP implementations.</p><p>CUBIC and HyStart++ are known implementations in the TCP world and give better performance (faster download and less packet loss) than Reno. We've made quiche pluggable and have added CUBIC and HyStart++ support. Our lab testing shows that QUIC is a clear performance winner in lossy network conditions, which is the very thing it is designed for.</p><p>In the future, we also plan to work on advanced features in quiche, such as packet pacing, advanced recovery and BBR congestion control for better QUIC performance. Using quiche you can switch among multiple congestion control algorithms using the config API at the connection level, so you can play with it and choose the best one depending on your need. qlog endpoint logging can be visualized to provide high accuracy insight into how QUIC is behaving, greatly helping understanding and development.</p><p>CUBIC and HyStart++ code is available in the <a href="https://github.com/cloudflare/quiche">quiche primary branch today</a>. Please try it!</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Performance]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">525vEcQ9ys8D8JIFjgvliO</guid>
            <dc:creator>Junho Choi</dc:creator>
        </item>
        <item>
            <title><![CDATA[Comparing HTTP/3 vs. HTTP/2 Performance]]></title>
            <link>https://blog.cloudflare.com/http-3-vs-http-2/</link>
            <pubDate>Tue, 14 Apr 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ We announced support for HTTP/3, the successor to HTTP/2, during Cloudflare’s birthday week last year. Our goal is and has always been to help build a better Internet. Even though HTTP/3 is still in draft status, we've seen a lot of interest from our users. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>We announced <a href="/http3-the-past-present-and-future/">support for HTTP/3</a>, the successor to HTTP/2 during Cloudflare’s <a href="/birthday-week-2019/">birthday week</a> last year. Our goal is and has always been to help build a better Internet. Collaborating on standards is a big part of that, and we're very fortunate to do that here.</p><p>Even though <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> is still in draft status, we've seen a lot of interest from our users. So far, over 113,000 zones have activated HTTP/3 and, if you are using an experimental browser those zones can be accessed using the new protocol! It's been great seeing so many people enable HTTP/3: having real websites accessible through HTTP/3 means browsers have more diverse properties to test against.</p><p>When we <a href="/http3-the-past-present-and-future/">launched support</a> for HTTP/3, we did so in partnership with Google, who simultaneously launched experimental support in Google Chrome. Since then, we've seen more browsers add experimental support: Firefox to their nightly <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1581637">builds</a>, other Chromium-based browsers such as Opera and Microsoft Edge through the underlying Chrome browser engine, and Safari via their <a href="https://developer.apple.com/safari/technology-preview/release-notes/">technology preview</a>. We closely follow these developments and partner wherever we can help; having a large network with many sites that have HTTP/3 enabled gives browser implementers an excellent testbed against which to try out code.</p>
    <div>
      <h3>So, what's the status and where are we now?</h3>
      <a href="#so-whats-the-status-and-where-are-we-now">
        
      </a>
    </div>
    <p>The IETF standardization process develops protocols as a series of document draft versions with the ultimate aim of producing a final draft version that is ready to be marked as an RFC. The members of the QUIC Working Group collaborate on analyzing, implementing and interoperating the specification in order to find things that don't work quite right. We launched with support for <a href="https://tools.ietf.org/html/draft-ietf-quic-http-23">Draft-23 for HTTP/3</a> and have since kept up with each new draft, with <a href="https://tools.ietf.org/html/draft-ietf-quic-http-27">27</a> being the latest at time of writing. With each draft the group improves the quality of the QUIC definition and gets closer to "rough consensus" about how it behaves. In order to avoid a perpetual state of analysis paralysis and endless tweaking, the bar for proposing changes to the specification has been increasing with each new draft. This means that changes between versions are smaller, and that a final RFC should closely match the protocol that we've been running in production.</p>
    <div>
      <h3>Benefits</h3>
      <a href="#benefits">
        
      </a>
    </div>
    <p>One of the main touted advantages of HTTP/3 is increased performance, specifically around fetching multiple objects simultaneously. With HTTP/2, any interruption (packet loss) in the TCP connection blocks all streams (Head of line blocking). Because HTTP/3 is UDP-based, if a packet gets dropped that only interrupts that one stream, not all of them.</p><p>In addition, HTTP/3 offers <a href="/even-faster-connection-establishment-with-quic-0-rtt-resumption/">0-RTT</a> support, which means that subsequent connections can start up much faster by eliminating the TLS acknowledgement from the server when setting up the connection. This means the client can start requesting data much faster than with a full TLS negotiation, meaning the website starts loading earlier.</p><p>The following illustrates the packet loss and its impact: HTTP/2 multiplexing two requests . A request comes over HTTP/2 from the client to the server requesting two resources (we’ve colored the requests and their associated responses green and yellow). The responses are broken up into multiple packets and, alas, a packet is lost so both requests are held up.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5MQCKq4WKwM4fCqDGYJ8Ui/1f9306b608618fe78e3e57a1392a9b11/image1-1.gif" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6DSF88gTgVSsmiVExIa3Ry/5e26b2b32f6bd00dda851caa4c9c46e6/image4-1.gif" />
            
            </figure><p>The above shows HTTP/3 multiplexing 2 requests. A packet is lost that affects the yellow response but the green one proceeds just fine.</p><p>Improvements in session startup mean that ‘connections’ to servers start much faster, which means the browser starts to see data more quickly. We were curious to see how much of an improvement, so we ran some tests. To measure the improvement resulting from 0-RTT support, we ran some benchmarks measuring <i>time to first byte</i> (TTFB). On average, with HTTP/3 we see the first byte appearing after 176ms. With HTTP/2 we see 201ms, meaning HTTP/3 is already performing 12.4% better!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5slXFJulfUbmW5NsZqm8r/f7087c07f55ab903735524e70dd04bb0/image5-6.png" />
            
            </figure><p>Interestingly, not every aspect of the protocol is governed by the drafts or RFC. Implementation choices can affect performance, such as efficient <a href="/accelerating-udp-packet-transmission-for-quic/">packet transmission</a> and choice of congestion control algorithm. Congestion control is a technique your computer and server use to adapt to overloaded networks: by dropping packets, transmission is subsequently throttled. Because QUIC is a new protocol, getting the congestion control design and implementation right requires experimentation and tuning.</p><p>In order to provide a safe and simple starting point, the Loss Detection and Congestion Control specification recommends the <a href="https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_Tahoe_and_Reno">Reno</a> algorithm but allows endpoints to choose any algorithm they might like.  We started with <a href="https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_New_Reno">New Reno</a> but we know from experience that we can get better performance with something else. We have recently moved to <a href="https://en.wikipedia.org/wiki/CUBIC_TCP">CUBIC</a> and on our network with larger size transfers and packet loss, CUBIC shows improvement over New Reno. Stay tuned for more details in future.</p><p>For our existing HTTP/2 stack, we currently support <a href="https://github.com/google/bbr">BBR v1</a> (TCP). This means that in our tests, we’re not performing an exact apples-to-apples comparison as these congestion control algorithms will behave differently for smaller vs larger transfers. That being said, we can already see a speedup in smaller websites using HTTP/3 when compared to HTTP/2. With larger zones, the improved congestion control of our tuned HTTP/2 stack shines in performance.</p><p>For a small test page of 15KB, HTTP/3 takes an average of 443ms to load compared to 458ms for HTTP/2. However, once we increase the page size to 1MB that advantage disappears: HTTP/3 is just slightly slower than HTTP/2 on our network today, taking 2.33s to load versus 2.30s.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2UrCQVwplKQxT7aSzqwMl6/4ff62d1bdb67e54c29b553d260f11aa8/image2-11.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KPuZxBl9m6TOyvrGZfMFw/5d22e954c62325af32c99c5783f62560/image6-4.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/JDw2bdaT0Vcmd4Jyg7Yhl/af2af92b3bdc2dd1891062844027fe70/image3-11.png" />
            
            </figure><p>Synthetic benchmarks are interesting, but we wanted to know how HTTP/3 would perform in the real world.</p><p>To measure, we wanted a third party that could load websites on our network, mimicking a browser. WebPageTest is a common framework that is used to measure the page load time, with nice waterfall charts. For analyzing the backend, we used our in-house <a href="https://support.cloudflare.com/hc/en-us/articles/360033929991-Cloudflare-Browser-Insights">Browser Insights</a>, to capture timings as our edge sees it. We then tied both pieces together with bits of automation.</p><p>As a test case we decided to use <a href="/">this very blog</a> for our <a href="https://www.cloudflare.com/application-services/solutions/app-performance-monitoring/">performance monitoring</a>. We configured our own instances of WebPageTest spread over the world to load these sites over both HTTP/2 and HTTP/3. We also enabled HTTP/3 and Browser Insights. So, every time our test scripts kickoff a webpage test with an HTTP/3 supported browser loading the page, browser analytics report the data back. Rinse and repeat for HTTP/2 to be able to compare.</p><p>The following graph shows the page load time for a real world page -- <a href="/">blog.cloudflare.com</a>, to compare the performance of HTTP/3 and HTTP/2. We have these performance measurements running from different geographical locations.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Xwp5YGAE5hCP7m0TQeGeE/52a42c9ad4a53be01e22fba4888c27de/image7-5.png" />
            
            </figure><p>As you can see, HTTP/3 performance still trails HTTP/2 performance, by about 1-4% on average in North America and similar results are seen in Europe, Asia and South America. We suspect this could be due to the difference in congestion algorithms: HTTP/2 on BBR v1 vs. HTTP/3 on CUBIC. In the future, we’ll work to support the same congestion algorithm on both to get a more accurate apples-to-apples comparison.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Overall, we’re very excited to be allowed to help push this standard forward. Our implementation is holding up well, offering better performance in some cases and at worst similar to HTTP/2. As the standard finalizes, we’re looking forward to seeing browsers add support for HTTP/3 in mainstream versions. As for us, we continue to support the latest drafts while at the same time looking for more ways to leverage HTTP/3 to get even better performance, be it congestion tuning, <a href="/adopting-a-new-approach-to-http-prioritization/">prioritization</a> or system capacity (CPU and raw network throughput).</p><p>In the meantime, if you’d like to try it out, just enable HTTP/3 on our dashboard and download a nightly version of one of the major browsers. Instructions on how to enable HTTP/3 can be found on our <a href="https://developers.cloudflare.com/http3/intro/">developer documentation</a>.</p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Better Internet]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Performance]]></category>
            <guid isPermaLink="false">7uJaKjNWQi13PNs4O9ylJB</guid>
            <dc:creator>Sreeni Tellakula</dc:creator>
        </item>
        <item>
            <title><![CDATA[A cost-effective and extensible testbed for transport protocol development]]></title>
            <link>https://blog.cloudflare.com/a-cost-effective-and-extensible-testbed-for-transport-protocol-development/</link>
            <pubDate>Tue, 14 Jan 2020 16:07:15 GMT</pubDate>
            <description><![CDATA[ At Cloudflare, we develop protocols at multiple layers of the network stack. In the past, we focused on HTTP/1.1, HTTP/2, and TLS 1.3. Now, we are working on QUIC and HTTP/3, which are still in IETF draft, but gaining a lot of interest. ]]></description>
            <content:encoded><![CDATA[ <p><i>This was originally published on </i><a href="https://calendar.perfplanet.com/2019/how-to-develop-a-practical-transport-protocol/"><i>Perf Planet's 2019 Web Performance Calendar</i></a><i>.</i></p><p>At Cloudflare, we develop protocols at multiple layers of the network stack. In the past, we focused on HTTP/1.1, HTTP/2, and TLS 1.3. Now, we are working on <a href="/http3-the-past-present-and-future/">QUIC and HTTP/3</a>, which are still in IETF draft, but gaining a lot of interest.</p><p>QUIC is a secure and multiplexed transport protocol that aims to perform better than TCP under some network conditions. It is specified in a family of documents: a transport layer which specifies packet format and basic state machine, recovery and congestion control, security based on TLS 1.3, and an HTTP application layer mapping, which is now called <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>.</p><p>Let’s focus on the transport and recovery layer first. This layer provides a basis for what is sent on the wire (the packet binary format) and how we send it reliably. It includes how to open the connection, how to handshake a new secure session with the help of TLS, how to send data reliably and how to react when there is packet loss or reordering of packets. Also it includes flow control and congestion control to interact well with other transport protocols in the same network. With confidence in the basic transport and recovery layer,  we can take a look at higher application layers such as HTTP/3.</p><p>To develop such a transport protocol, we need multiple stages of the development environment. Since this is a network protocol, it’s best to test in an actual physical network to see how works on the wire. We may start the development using localhost, but after some time we may want to send and receive packets with other hosts. We can build a lab with a couple of virtual machines, using Virtualbox, VMWare or even with Docker. We also have a local testing environment with a Linux VM. But sometimes these have a limited network (localhost only) or are noisy due to other processes in the same host or virtual machines.</p><p>Next step is to have a test lab, typically an isolated network focused on protocol analysis only consisting of dedicated x86 hosts. Lab configuration is particularly important for testing various cases - there is no one-size-fits-all scenario for protocol testing. For example, EDGE is still running in production mobile networks but LTE is dominant and 5G deployment is in early stages. WiFi is very common these days. We want to test our protocol in all those environments. Of course, we can't buy every type of machine or have a very expensive network simulator for every type of environment, so using cheap hardware and an open source OS where we can configure similar environments is ideal.</p>
    <div>
      <h2>The QUIC Protocol Testing lab</h2>
      <a href="#the-quic-protocol-testing-lab">
        
      </a>
    </div>
    <p>The goal of the QUIC testing lab is to aid transport layer protocol development. To develop a transport protocol we need to have a way to control our network environment and a way to get as many different types of debugging data as possible. Also we need to get metrics for comparison with other protocols in production.</p><p>The QUIC Testing Lab has the following goals:</p><ul><li><p><b><i>Help with multiple transport protocol development</i></b>: Developing a new transport layer requires many iterations, from building and validating packets as per protocol spec, to making sure everything works fine under moderate load, to very harsh conditions such as low bandwidth and high packet loss. We need a way to run tests with various network conditions reproducibly in order to catch unexpected issues.</p></li><li><p><b><i>Debugging multiple transport protocol development</i></b>: Recording as much debugging info as we can is important for fixing bugs. Looking into packet captures definitely helps but we also need a detailed debugging log of the server and client to understand the what and why for each packet. For example, when a packet is sent, we want to know why. Is this because there is an application which wants to send some data? Or is this a retransmit of data previously known as lost? Or is this a loss probe which is not an actual packet loss but sent to see if the network is lossy?</p></li><li><p><b><i>Performance comparison between each protocol</i></b>: We want to understand the performance of a new protocol by comparison with existing protocols such as TCP, or with a previous version of the protocol under development. Also we want to test with varying parameters such as changing the congestion control mechanism, changing various timeouts, or changing the buffer sizes at various levels of the stack.</p></li><li><p><b><i>Finding a bottleneck or errors easily</i></b>: Running tests we may see an unexpected error - a transfer that timed out, or ended with an error, or a transfer was corrupted at the client side - each test needs to make sure every test is run correctly, by using a checksum of the original file to compare with what is actually downloaded, or by checking various error codes at the protocol of API level.</p></li></ul><p>When we have a test lab with separate hardware, we have benefits, as follows:</p><ul><li><p>Can configure the testing lab without public Internet access - safe and quiet.</p></li><li><p>Handy access to hardware and its console for maintenance purpose, or for adding or updating hardware.</p></li><li><p>Try other CPU architectures. For clients we use the Raspberry Pi for regular testing because this is ARM architecture (32bit or 64bit), similar to modern smartphones. So testing with ARM architecture helps for compatibility testing before going into a smartphone OS.</p></li><li><p>We can add a real smartphone for testing, such as Android or iPhone. We can test with WiFi but these devices also support Ethernet, so we can test them with a wired network for better consistency.</p></li></ul>
    <div>
      <h2>Lab Configuration</h2>
      <a href="#lab-configuration">
        
      </a>
    </div>
    <p>Here is a diagram of our QUIC Protocol Testing Lab:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1O1CdD682XoQE9Q68bPVkh/a63bd6b8a1bafa516719cfcf0a82c033/Screenshot-2019-07-01-00.35.06.png" />
            
            </figure><p>This is a conceptual diagram and we need to configure a switch for connecting each machine. Currently, we have Raspberry Pis (2 and 3) as an Origin and a Client. And small Intel x86 boxes for the Traffic Shaper and Edge server plus Ethernet switches for interconnectivity.</p><ul><li><p>Origin is simply serving HTTP and HTTPS test objects using a web server. Client may download a file from Origin directly to simulate a download direct from a customer's origin server.</p></li><li><p>Client will download a test object from Origin or Edge, using a different protocol. In typical a configuration Client connects to Edge instead of Origin, so this is to simulate an edge server in the real world. For TCP/HTTP we are using the curl command line client and for QUIC, <a href="https://github.com/cloudflare/quiche">quiche’s</a> http3_client with some modification.</p></li><li><p>Edge is running Cloudflare's web server to serve HTTP/HTTPS via TCP and also the QUIC protocol using quiche. Edge server is installed with the same Linux kernel used on Cloudflare's production machines in order to have the same low level network stack.</p></li><li><p>Traffic Shaper is sitting between Client and Edge (and Origin), controlling network conditions. Currently we are using FreeBSD and ipfw + dummynet. Traffic shaping can also be done using Linux' netem which provides additional network simulation features.</p></li></ul><p>The goal is to run tests with various network conditions, such as bandwidth, latency and packet loss upstream and downstream. The lab is able to run a plaintext HTTP test but currently our focus of testing is HTTPS over TCP and HTTP/3 over QUIC. Since QUIC is running over UDP, both TCP and UDP traffic need to be controlled.</p>
    <div>
      <h2>Test Automation and Visualization</h2>
      <a href="#test-automation-and-visualization">
        
      </a>
    </div>
    <p>In the lab, we have a script installed in Client, which can run a batch of testing with various configuration parameters - for each test combination, we can define a test configuration, including:</p><ul><li><p>Network Condition - Bandwidth, Latency, Packet Loss (upstream and downstream)</p></li></ul><p>For example using netem traffic shaper we can simulate LTE network as below,(<a href="https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/">RTT</a>=50ms, BW=22Mbps upstream and downstream, with BDP queue size)</p>
            <pre><code>$ tc qdisc add dev eth0 root handle 1:0 netem delay 25ms
$ tc qdisc add dev eth0 parent 1:1 handle 10: tbf rate 22mbit buffer 68750 limit 70000</code></pre>
            <ul><li><p>Test Object sizes - 1KB, 8KB, … 32MB</p></li><li><p>Test Protocols: HTTPS (TCP) and QUIC (UDP)</p></li><li><p>Number of runs and number of requests in a single connection</p></li></ul><p>The test script outputs a CSV file of results for importing into other tools for data processing and visualization - such as Google Sheets, Excel or even a jupyter notebook. Also it’s able to post the result to a database (Clickhouse in our case), so we can query and visualize the results.</p><p>Sometimes a whole test combination takes a long time - the current standard test set with simulated 2G, 3G, LTE, WiFi and various object sizes repeated 10 times for each request may take several hours to run. Large object testing on a slow network takes most of the time, so sometimes we also need to run a limited test (e.g. testing LTE-like conditions only for a smoke test) for quick debugging.</p>
    <div>
      <h3>Chart using Google Sheets:</h3>
      <a href="#chart-using-google-sheets">
        
      </a>
    </div>
    <p>The following comparison chart shows the total transfer time in msec for TCP vs QUIC for different network conditions. The QUIC protocol used here is a development version one.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2umJkG3YBHNnxyD2tJRHQA/c96ef4601d8d20c9760b45ad321e6135/Screen-Shot-2020-01-13-at-3.09.41-PM.png" />
            
            </figure>
    <div>
      <h2>Debugging and performance analysis using of a smartphone</h2>
      <a href="#debugging-and-performance-analysis-using-of-a-smartphone">
        
      </a>
    </div>
    <p>Mobile devices have become a crucial part of our day to day life, so testing the new transport protocol on mobile devices is critically important for mobile app performance. To facilitate that, we need to have a mobile test app which will proxy data over the new transport protocol under development. With this we have the ability to analyze protocol functionality and performance in mobile devices with different network conditions.</p><p>Adding a smartphone to the testbed mentioned above gives an advantage in terms of understanding real performance issues. The major smartphone operating systems, iOS and Android, have quite different networking stack. Adding a smartphone to testbed gives the ability to understand these operating system network stacks in depth which aides new protocol designs.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/RLA6wO7vjRol9o6nlzj34/7c1a7904a379b1e8079853c35597173c/Screen-Shot-2020-01-13-at-3.52.03-PM.png" />
            
            </figure><p>The above figure shows the network block diagram of another similar lab testbed used for protocol testing where a smartphone is connected both wired and wirelessly. A Linux netem based traffic shaper sits in-between the client and server shaping the traffic. Various networking profiles are fed to the traffic shaper to mimic real world scenarios. The client can be either an Android or iOS based smartphone, the server is a vanilla web server serving static files. Client, server and traffic shaper are all connected to the Internet along with the private lab network for management purposes.</p><p>The above lab has mobile devices for both Android or iOS  installed with a test app built with a proprietary client proxy software for proxying data over the new transport protocol under development. The test app also has the ability to make HTTP requests over TCP for comparison purposes.</p><p>The Android or iOS test app can be used to issue multiple HTTPS requests of different object sizes sequentially and concurrently using TCP and QUIC as underlying transport protocol. Later, TTOTAL (total transfer time) of each HTTPS request is used to compare TCP and QUIC performance over different network conditions. One such comparison is shown below,</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Eh2Kl4C9RI40oKf8Z3CJY/a318afd23e177895137ff481bba2dfe1/Screen-Shot-2020-01-13-at-4.08.23-PM.png" />
            
            </figure><p>The table above shows the total transfer time taken for TCP and QUIC requests over an LTE network profile fetching different objects with different concurrency levels using the test app. Here TCP goes over native OS network stack and QUIC goes over Cloudflare QUIC stack.</p><p>Debugging network performance issues is hard when it comes to mobile devices. By adding an actual smartphone into the testbed itself we have the ability to take packet captures at different layers. These are very critical in analyzing and understanding protocol performance.</p><p>It's easy and straightforward to capture packets and analyze them using the tcpdump tool on x86 boxes, but it's a challenge to capture packets on iOS and Android devices. On iOS device ‘rvictl’ lets us capture packets on an external interface. But ‘rvictl’ has some drawbacks such as timestamps being inaccurate. Since we are dealing with millisecond level events, timestamps need to be accurate to analyze the root cause of a problem.</p><p>We can capture packets on internal loopback interfaces on jailbroken iPhones and rooted Android devices. Jailbreaking a recent iOS device is nontrivial. We also need to make sure that autoupdate of any sort is disabled on such a phone otherwise it would disable the jailbreak and you have to start the whole process again. With a jailbroken phone we have root access to the device which lets us take packet captures as needed using tcpdump.</p><p>Packet captures taken using jailbroken iOS devices or rooted Android devices connected to the lab testbed help us analyze  performance bottlenecks and improve protocol performance.</p><p>iOS and Android devices different network stacks in their core operating systems. These packet captures also help us understand the network stack of these mobile devices, for example in iOS devices packets punted through loopback interface had a mysterious delay of 5 to 7ms.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Cloudflare is actively involved in helping to drive forward the QUIC and HTTP/3 standards by testing and optimizing these new protocols in simulated real world environments. By simulating a wide variety of networks we are working on our mission of Helping Build a Better Internet. For everyone, everywhere.</p><p><i>Would like to thank SangJo Lee, Hiren Panchasara, Lucas Pardue and Sreeni Tellakula for their contributions.</i></p> ]]></content:encoded>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[TLS 1.3]]></category>
            <category><![CDATA[TCP]]></category>
            <guid isPermaLink="false">58abpUfUPAE7n3X9TDOpyt</guid>
            <dc:creator>Lohith Bellad</dc:creator>
            <dc:creator>Junho Choi</dc:creator>
        </item>
        <item>
            <title><![CDATA[Accelerating UDP packet transmission for QUIC]]></title>
            <link>https://blog.cloudflare.com/accelerating-udp-packet-transmission-for-quic/</link>
            <pubDate>Wed, 08 Jan 2020 17:08:00 GMT</pubDate>
            <description><![CDATA[ Significant work has gone into optimizing TCP, UDP hasn't received as much attention, putting QUIC at a disadvantage. Let's explore a few tricks that help mitigate this. ]]></description>
            <content:encoded><![CDATA[ <p><i>This was originally published on </i><a href="https://calendar.perfplanet.com/2019/accelerating-udp-packet-transmission-for-quic/"><i>Perf Planet's 2019 Web Performance Calendar</i></a><i>.</i></p><p><a href="/the-road-to-quic/">QUIC</a>, the new Internet transport protocol designed to accelerate HTTP traffic, is delivered on top of <a href="https://www.cloudflare.com/learning/ddos/glossary/user-datagram-protocol-udp/">UDP datagrams</a>, to ease deployment and avoid interference from network appliances that drop packets from unknown protocols. This also allows QUIC implementations to live in user-space, so that, for example, browsers will be able to implement new protocol features and ship them to their users without having to wait for operating systems updates.</p><p>But while a lot of work has gone into optimizing TCP implementations as much as possible over the years, including building offloading capabilities in both software (like in operating systems) and hardware (like in network interfaces), UDP hasn't received quite as much attention as TCP, which puts QUIC at a disadvantage. In this post we'll look at a few tricks that help mitigate this disadvantage for UDP, and by association QUIC.</p><p>For the purpose of this blog post we will only be concentrating on measuring throughput of QUIC connections, which, while necessary, is not enough to paint an accurate overall picture of the performance of the QUIC protocol (or its implementations) as a whole.</p>
    <div>
      <h3>Test Environment</h3>
      <a href="#test-environment">
        
      </a>
    </div>
    <p>The client used in the measurements is h2load, <a href="https://github.com/nghttp2/nghttp2/tree/quic">built with QUIC and HTTP/3 support</a>, while the server is NGINX, built with <a href="/experiment-with-http-3-using-nginx-and-quiche/">the open-source QUIC and HTTP/3 module provided by Cloudflare</a> which is based on quiche (<a href="https://github.com/cloudflare/quiche">github.com/cloudflare/quiche</a>), Cloudflare's own <a href="/enjoy-a-slice-of-quic-and-rust/">open-source implementation of QUIC and HTTP/3</a>.</p><p>The client and server are run on the same host (my laptop) running Linux 5.3, so the numbers don’t necessarily reflect what one would see in a production environment over a real network, but it should still be interesting to see how much of an impact each of the techniques have.</p>
    <div>
      <h3>Baseline</h3>
      <a href="#baseline">
        
      </a>
    </div>
    <p>Currently the code that implements QUIC in NGINX uses the <code>sendmsg()</code> system call to send a single UDP packet at a time.</p>
            <pre><code>ssize_t sendmsg(int sockfd, const struct msghdr *msg,
    int flags);</code></pre>
            <p>The <code>struct msghdr</code> carries a <code>struct iovec</code> which can in turn carry multiple buffers. However, all of the buffers within a single iovec will be merged together into a single UDP datagram during transmission. The kernel will then take care of encapsulating the buffer in a UDP packet and sending it over the wire.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/774r0FpU47qMQ5bbxIOPL5/3560c09b55949e3c406ad958498e7fd4/sendmsg.png" />
            
            </figure><p>The throughput of this particular implementation tops out at around 80-90 MB/s, as measured by h2load when performing 10 sequential requests for a 100 MB resource.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4V8JtNxw1ogFryQ7xBVcgk/74bf3551df4837143a4cb2dbc53e3f84/sendmsg-chart.png" />
            
            </figure>
    <div>
      <h3>sendmmsg()</h3>
      <a href="#sendmmsg">
        
      </a>
    </div>
    <p>Due to the fact that <code>sendmsg()</code> only sends a single UDP packet at a time, it needs to be invoked quite a lot in order to transmit all of the QUIC packets required to deliver the requested resources, as illustrated by the following bpftrace command:</p>
            <pre><code>% sudo bpftrace -p $(pgrep nginx) -e 'tracepoint:syscalls:sys_enter_sendm* { @[probe] = count(); }'
Attaching 2 probes...
 
 
@[tracepoint:syscalls:sys_enter_sendmsg]: 904539</code></pre>
            <p>Each of those system calls causes an expensive context switch between the application and the kernel, thus impacting throughput.</p><p>But while <code>sendmsg()</code> only transmits a single UDP packet at a time for each invocation, its close cousin <code>sendmmsg()</code> (note the additional “m” in the name) is able to batch multiple packets per system call:</p>
            <pre><code>int sendmmsg(int sockfd, struct mmsghdr *msgvec,
    unsigned int vlen, int flags);</code></pre>
            <p>Multiple <code>struct mmsghdr</code> structures can be passed to the kernel as an array, each in turn carrying a single <code>struct msghdr</code> with its own <code>struct iovec</code> , with each element in the <code>msgvec</code> array representing a single UDP datagram.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5QO4EdUwmU9MJhSCY2wwC1/ac6bc505e3b1f3b4d571910f13905131/sendmmsg.png" />
            
            </figure><p>Let's see what happens when NGINX is updated to use <code>sendmmsg()</code> to send QUIC packets:</p>
            <pre><code>% sudo bpftrace -p $(pgrep nginx) -e 'tracepoint:syscalls:sys_enter_sendm* { @[probe] = count(); }'
Attaching 2 probes...
 
 
@[tracepoint:syscalls:sys_enter_sendmsg]: 2437
@[tracepoint:syscalls:sys_enter_sendmmsg]: 15676</code></pre>
            <p>The number of system calls went down dramatically, which translates into an increase in throughput, though not quite as big as the decrease in syscalls:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6fv3ZaxYLZmteczFchjfiO/e0056c40dacea0422ed53edaf8158869/sendmmsg-chart.png" />
            
            </figure>
    <div>
      <h3>UDP segmentation offload</h3>
      <a href="#udp-segmentation-offload">
        
      </a>
    </div>
    <p>With <code>sendmsg()</code> as well as <code>sendmmsg()</code>, the application is responsible for separating each QUIC packet into its own buffer in order for the kernel to be able to transmit it. While the implementation in NGINX uses static buffers to implement this, so there is no overhead in allocating them, all of these buffers need to be traversed by the kernel during transmission, which can add significant overhead.</p><p>Linux supports a feature, Generic Segmentation Offload (GSO), which allows the application to pass a single "super buffer" to the kernel, which will then take care of segmenting it into smaller packets. The kernel will try to postpone the segmentation as much as possible to reduce the overhead of traversing outgoing buffers (some NICs even support hardware segmentation, but it was not tested in this experiment due to lack of capable hardware). Originally GSO was only supported for TCP, but support for UDP GSO was recently added as well, in Linux 4.18.</p><p>This feature can be controlled using the <code>UDP_SEGMENT</code> socket option:</p>
            <pre><code>setsockopt(fd, SOL_UDP, UDP_SEGMENT, &amp;gso_size, sizeof(gso_size)))</code></pre>
            <p>As well as via ancillary data, to control segmentation for each <code>sendmsg()</code> call:</p>
            <pre><code>cm = CMSG_FIRSTHDR(&amp;msg);
cm-&gt;cmsg_level = SOL_UDP;
cm-&gt;cmsg_type = UDP_SEGMENT;
cm-&gt;cmsg_len = CMSG_LEN(sizeof(uint16_t));
*((uint16_t *) CMSG_DATA(cm)) = gso_size;</code></pre>
            <p>Where <code>gso_size</code> is the size of each segment that form the "super buffer" passed to the kernel from the application. Once configured, the application can provide one contiguous large buffer containing a number of packets of <code>gso_size</code> length (as well as a final smaller packet), that will then be segmented by the kernel (or the NIC if hardware segmentation offloading is supported and enabled).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3vQo11I0RupCQ4msUqj0Ve/dcec6ac6c0bea7c737aa9fa822e69d0a/sendmsg-gso.png" />
            
            </figure><p><a href="https://github.com/torvalds/linux/blob/80a0c2e511a97e11d82e0ec11564e2c3fe624b0d/include/linux/udp.h#L94">Up to 64 segments</a> can be batched with the <code>UDP_SEGMENT</code> option.</p><p>GSO with plain <code>sendmsg()</code> already delivers a significant improvement:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4q2OxEsgZcsw2JXc8JcAfk/a64c9b48cad41378122e7d7c5a88e67a/gso-chart.png" />
            
            </figure><p>And indeed the number of syscalls also went down significantly, compared to plain <code>sendmsg()</code> :</p>
            <pre><code>% sudo bpftrace -p $(pgrep nginx) -e 'tracepoint:syscalls:sys_enter_sendm* { @[probe] = count(); }'
Attaching 2 probes...
 
 
@[tracepoint:syscalls:sys_enter_sendmsg]: 18824</code></pre>
            <p>GSO can also be combined with <code>sendmmsg()</code> to deliver an even bigger improvement. The idea being that each <code>struct msghdr</code> can be segmented in the kernel by setting the <code>UDP_SEGMENT</code> option using ancillary data, allowing an application to pass multiple “super buffers”, each carrying up to 64 segments, to the kernel in a single system call.</p><p>The improvement is again fairly significant:</p>
    <div>
      <h3>Evolving from AFAP</h3>
      <a href="#evolving-from-afap">
        
      </a>
    </div>
    <p>Transmitting packets as fast as possible is easy to reason about, and there's much fun to be had in optimizing applications for that, but in practice this is not always the best strategy when optimizing protocols for the Internet</p><p>Bursty traffic is more likely to cause or be affected by congestion on any given network path, which will inevitably defeat any optimization implemented to increase transmission rates.</p><p>Packet pacing is an effective technique to squeeze out more performance from a network flow. The idea being that adding a short delay between each outgoing packet will smooth out bursty traffic and reduce the chance of congestion, and packet loss. For TCP this was originally implemented in Linux via the fq packet scheduler, and later by the BBR congestion control algorithm implementation, which implements its own pacer.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1PkaZcKDkzzjUDhFLRT1jw/a4247010827f1763bd7560894e30938e/afap.png" />
            
            </figure><p>Due to the nature of current QUIC implementations, which reside entirely in user-space, pacing of QUIC packets conflicts with any of the techniques explored in this post, because pacing each packet separately during transmission will prevent any batching on the application side, and in turn batching will prevent pacing, as batched packets will be transmitted as fast as possible once received by the kernel.</p><p>However Linux provides some facilities to offload the pacing to the kernel and give back some control to the application:</p><ul><li><p><b>SO_MAX_PACING_RATE</b>: an application can define this socket option to instruct the fq packet scheduler to pace outgoing packets up to the given rate. This works for UDP sockets as well, but it is yet to be seen how this can be integrated with QUIC, as a single UDP socket can be used for multiple QUIC connections (unlike TCP, where each connection has its own socket). In addition, this is not very flexible, and might not be ideal when implementing the BBR pacer.</p></li><li><p><b>SO_TXTIME / SCM_TXTIME</b>: an application can use these options to schedule transmission of specific packets at specific times, essentially instructing fq to delay packets until the provided timestamp is reached. This gives the application a lot more control, and can be easily integrated into sendmsg() as well as sendmmsg(). But it does not yet support specifying different times for each packet when GSO is used, as there is no way to define multiple timestamps for packets that need to be segmented (each segmented packet essentially ends up being sent at the same time anyway).</p></li></ul><p>While the performance gains achieved by using the techniques illustrated here are fairly significant, there are still open questions around how any of this will work with pacing, so more experimentation is required.</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[UDP]]></category>
            <category><![CDATA[TCP]]></category>
            <category><![CDATA[HTTP3]]></category>
            <guid isPermaLink="false">3pwKBhG2s8cT4COiXLHTyT</guid>
            <dc:creator>Alessandro Ghedini</dc:creator>
        </item>
        <item>
            <title><![CDATA[Even faster connection establishment with QUIC 0-RTT resumption]]></title>
            <link>https://blog.cloudflare.com/even-faster-connection-establishment-with-quic-0-rtt-resumption/</link>
            <pubDate>Wed, 20 Nov 2019 16:30:00 GMT</pubDate>
            <description><![CDATA[ One of the more interesting features introduced by TLS 1.3, the latest revision of the TLS protocol, was the so called “zero roundtrip time connection resumption”, a mode of operation that allows a client to start sending application data, such as HTTP requests ]]></description>
            <content:encoded><![CDATA[ <p>One of the more interesting features introduced by <a href="/rfc-8446-aka-tls-1-3/">TLS 1.3</a>, the latest revision of the TLS protocol, was the so called “zero <a href="https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/">roundtrip time</a> connection resumption”, a mode of operation that allows a client to start sending application data, such as HTTP requests, without having to wait for the TLS handshake to complete, thus reducing the latency penalty incurred in establishing a new connection.</p><p>The basic idea behind 0-RTT connection resumption is that if the client and server had previously established a TLS connection between each other, they can use information cached from that session to establish a new one without having to negotiate the connection’s parameters from scratch. Notably this allows the client to compute the private encryption keys required to protect application data before even talking to the server.</p><p>However, in the case of TLS, “zero roundtrip” only refers to the TLS handshake itself: the client and server are still required to first establish a TCP connection in order to be able to exchange TLS data.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7ni3h0ZnlDFEvNicARvJmV/061a4032d80cbf5c030feeecf890fcf9/HTTP-request-over-TCP-_3x.png" />
            
            </figure>
    <div>
      <h3>Zero means zero</h3>
      <a href="#zero-means-zero">
        
      </a>
    </div>
    <p><a href="/the-road-to-quic/">QUIC</a> goes a step further, and allows clients to send application data in the very first roundtrip of the connection, without requiring any other handshake to be completed beforehand.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5DCnCIKcCkYFvfHbx66Sxg/c620d9e4586b0a3d461ba4f9cf294e66/request-over-quic-0-RTT_3x.png" />
            
            </figure><p>After all, QUIC already <a href="/the-road-to-quic/#builtinsecurityandperformance">shaved a full round-trip off of a typical connection’s handshake</a> by merging the transport and cryptographic handshakes into one. By reducing the handshake by an additional roundtrip, QUIC achieves real 0-RTT connection establishment.</p><p>It literally can’t get any faster!</p>
    <div>
      <h3>Attack of the clones</h3>
      <a href="#attack-of-the-clones">
        
      </a>
    </div>
    <p>Unfortunately, 0-RTT connection resumption is not all smooth sailing, and it comes with caveats and risks, which is why <b>Cloudflare does not enable 0-RTT connection resumption by default</b>. Users should consider the risks involved and decide whether to use this feature or not.</p><p>For starters, 0-RTT connection resumption does not provide forward secrecy, meaning that a compromise of the secret parameters of a connection will trivially allow compromising the application data sent during the 0-RTT phase of new connections resumed from it. Data sent after the 0-RTT phase, meaning after the handshake has been completed, would still be safe though, as TLS 1.3 (and QUIC) will still perform the normal key exchange algorithm (which is forward secret) for data sent after the handshake completion.</p><p>More worryingly, application data sent during 0-RTT can be captured by an on-path attacker and then replayed multiple times to the same server. In many cases this is not a problem, as the attacker wouldn’t be able to decrypt the data, which is why 0-RTT connection resumption is useful, but in some cases this can be dangerous.</p><p>For example, imagine a bank that allows an authenticated user (e.g. using HTTP cookies, or other HTTP authentication mechanisms) to send money from their account to another user by making an HTTP request to a specific API endpoint. If an attacker was able to capture that request when 0-RTT connection resumption was used, they wouldn’t be able to see the plaintext and get the user’s credentials, because they wouldn’t know the secret key used to encrypt the data; however they could still potentially drain that user’s bank account by replaying the same request over and over:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5z9QMHK9VzFVOtVATVvE7B/b63202a2de73e6517ad493639b7d0ed2/Bank-API-replay-attack-_3x.png" />
            
            </figure><p>Of course this problem is not specific to banking APIs: any non-<a href="https://en.wikipedia.org/wiki/Idempotence">idempotent</a> request has the potential to cause undesired side effects, ranging from slight malfunctions to serious security breaches.</p><p>In order to help mitigate this risk, Cloudflare will always reject 0-RTT requests that are obviously not idempotent (like POST or PUT requests), but in the end it’s up to the application sitting behind Cloudflare to decide which requests can and cannot be allowed with 0-RTT connection resumption, as even innocuous-looking ones can have side effects on the origin server.</p><p>To help origins detect and potentially disallow specific requests, Cloudflare also follows the techniques described in <a href="https://tools.ietf.org/html/rfc8470">RFC8470</a>. Notably, Cloudflare will add the <code>Early-Data: 1</code> HTTP header to requests received during 0-RTT resumption that are forwarded to origins.</p><p>Origins able to understand this header can then decide to answer the request with the <a href="https://tools.ietf.org/html/rfc8470#section-5.2">425 (Too Early)</a> HTTP status code, which will instruct the client that originated the request to retry sending the same request but only after the TLS or QUIC handshake have fully completed, at which point there is no longer any risk of replay attacks. This could even be implemented as part of a <a href="https://workers.cloudflare.com/">Cloudflare Worker</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5HFpNn8buQqXN5RiCVMgfD/5b6adf72a5d14f3a7772b4ae197e6950/425-too-early-_3x.png" />
            
            </figure><p>This makes it possible for origins to allow 0-RTT requests for endpoints that are safe, such as a website’s index page which is where 0-RTT is most useful, as that is typically the first request a browser makes after establishing a connection, while still protecting other endpoints such as APIs and form submissions. But if an origin does not provide any of those non-idempotent endpoints, no action is required.</p>
    <div>
      <h3>One stop shop for all your 0-RTT needs</h3>
      <a href="#one-stop-shop-for-all-your-0-rtt-needs">
        
      </a>
    </div>
    <p>Just like we previously did for TLS 1.3, we now support 0-RTT resumption for QUIC as well. In honor of this event, we have dusted off the user-interface controls that allow Cloudflare users to enable this feature for their websites, and introduced a dedicated toggle to control whether 0-RTT connection resumption is enabled or not, which can be found under the “Network” tab on the Cloudflare dashboard:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6sYNvqFyRCrc88Esrkm3A/971767abe13746b70754b8b17f1dad18/2019-11-07-133312_3087x508_scrot.png" />
            
            </figure><p>When TLS 1.3 and/or QUIC (via the HTTP/3 toggle) are enabled, 0-RTT connection resumption will be automatically offered to clients that support it, and the replay mitigation mentioned above will also be applied to the connections making use of this feature.</p><p>In addition, if you are a user of our <a href="/experiment-with-http-3-using-nginx-and-quiche/">open-source HTTP/3 patch for NGINX</a>, after updating the patch to the latest version, you’ll be able to enable support for 0-RTT connection resumption in your own NGINX-based <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> deployment by using the built-in <a href="https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data">“ssl_early_data” option</a>, which will work for both TLS 1.3 and QUIC+HTTP/3.</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">3ljtGm0iifxH7GrGX4FSRN</guid>
            <dc:creator>Alessandro Ghedini</dc:creator>
        </item>
        <item>
            <title><![CDATA[Experiment with HTTP/3 using NGINX and quiche]]></title>
            <link>https://blog.cloudflare.com/experiment-with-http-3-using-nginx-and-quiche/</link>
            <pubDate>Thu, 17 Oct 2019 14:00:00 GMT</pubDate>
            <description><![CDATA[ Just a few weeks ago we announced the availability on our edge network of HTTP/3, the new revision of HTTP intended to improve security and performance on the Internet. Everyone can now enable HTTP/3 on their Cloudflare zone ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Just a few weeks ago <a href="/http3-the-past-present-and-future/">we announced</a> the availability on our edge network of <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>, the new revision of HTTP intended to improve security and performance on the Internet. Everyone can now enable HTTP/3 on their Cloudflare zone and experiment with it using <a href="/http3-the-past-present-and-future/#using-google-chrome-as-an-http-3-client">Chrome Canary</a> as well as <a href="/http3-the-past-present-and-future/#using-curl">curl</a>, among other clients.</p><p>We have previously made available <a href="https://github.com/cloudflare/quiche/blob/master/examples/http3-server.rs">an example HTTP/3 server as part of the quiche project</a> to allow people to experiment with the protocol, but it’s quite limited in the functionality that it offers, and was never intended to replace other general-purpose web servers.</p><p>We are now happy to announce that <a href="/enjoy-a-slice-of-quic-and-rust/">our implementation of HTTP/3 and QUIC</a> can be integrated into your own installation of NGINX as well. This is made available <a href="https://github.com/cloudflare/quiche/tree/master/extras/nginx">as a patch</a> to NGINX, that can be applied and built directly with the upstream NGINX codebase.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/RGn7FpVUT1wQ1v5yu74c3/d6db309a2e2d99da184b3bbb123f3fb5/quiche-banner-copy_2x.png" />
            
            </figure><p>It’s important to note that <b>this is not officially supported or endorsed by the NGINX project</b>, it is just something that we, Cloudflare, want to make available to the wider community to help push adoption of QUIC and HTTP/3.</p>
    <div>
      <h3>Building</h3>
      <a href="#building">
        
      </a>
    </div>
    <p>The first step is to <a href="https://nginx.org/en/download.html">download and unpack the NGINX source code</a>. Note that the HTTP/3 and QUIC patch only works with the 1.16.x release branch (the latest stable release being 1.16.1).</p>
            <pre><code> % curl -O https://nginx.org/download/nginx-1.16.1.tar.gz
 % tar xvzf nginx-1.16.1.tar.gz</code></pre>
            <p>As well as quiche, the underlying implementation of HTTP/3 and QUIC:</p>
            <pre><code> % git clone --recursive https://github.com/cloudflare/quiche</code></pre>
            <p>Next you’ll need to apply the patch to NGINX:</p>
            <pre><code> % cd nginx-1.16.1
 % patch -p01 &lt; ../quiche/extras/nginx/nginx-1.16.patch</code></pre>
            <p>And finally build NGINX with HTTP/3 support enabled:</p>
            <pre><code> % ./configure                          	\
   	--prefix=$PWD                       	\
   	--with-http_ssl_module              	\
   	--with-http_v2_module               	\
   	--with-http_v3_module               	\
   	--with-openssl=../quiche/deps/boringssl \
   	--with-quiche=../quiche
 % make</code></pre>
            <p>The above command instructs the NGINX build system to enable the HTTP/3 support ( <code>--with-http_v3_module</code>) by using the quiche library found in the path it was previously downloaded into ( <code>--with-quiche=../quiche</code>), as well as TLS and HTTP/2. Additional build options can be added as needed.</p><p>You can check out the full instructions <a href="https://github.com/cloudflare/quiche/tree/master/extras/nginx#readme">here</a>.</p>
    <div>
      <h3>Running</h3>
      <a href="#running">
        
      </a>
    </div>
    <p>Once built, NGINX can be configured to accept incoming HTTP/3 connections by adding the <code>quic</code> and <code>reuseport</code> options to the <a href="https://nginx.org/en/docs/http/ngx_http_core_module.html#listen">listen</a> configuration directive.</p><p>Here is a minimal configuration example that you can start from:</p>
            <pre><code>events {
    worker_connections  1024;
}

http {
    server {
        # Enable QUIC and HTTP/3.
        listen 443 quic reuseport;

        # Enable HTTP/2 (optional).
        listen 443 ssl http2;

        ssl_certificate      cert.crt;
        ssl_certificate_key  cert.key;

        # Enable all TLS versions (TLSv1.3 is required for QUIC).
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        
        # Add Alt-Svc header to negotiate HTTP/3.
        add_header alt-svc 'h3-23=":443"; ma=86400';
    }
}</code></pre>
            <p>This will enable both HTTP/2 and HTTP/3 on the TCP/443 and UDP/443 ports respectively.</p><p>You can then use one of the available HTTP/3 clients (such as <a href="/http3-the-past-present-and-future/#using-google-chrome-as-an-http-3-client">Chrome Canary</a>, <a href="/http3-the-past-present-and-future/#using-curl">curl</a> or even the <a href="/http3-the-past-present-and-future/#using-quiche-s-http3-client">example HTTP/3 client provided as part of quiche</a>) to connect to your NGINX instance using HTTP/3.</p><p>We are excited to make this available for everyone to experiment and play with HTTP/3, but it’s important to note that <b>the implementation is still experimental</b> and it’s likely to have bugs as well as limitations in functionality. Feel free to submit a ticket to the <a href="https://github.com/cloudflare/quiche">quiche project</a> if you run into problems or find any bug.</p> ]]></content:encoded>
            <category><![CDATA[NGINX]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Chrome]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[HTTP3]]></category>
            <guid isPermaLink="false">2M0hyPXVNiYWjSUGQRypv2</guid>
            <dc:creator>Alessandro Ghedini</dc:creator>
        </item>
    </channel>
</rss>