
<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>Sat, 11 Apr 2026 10:11:22 GMT</lastBuildDate>
        <item>
            <title><![CDATA[DIY BYOIP: a new way to Bring Your Own IP prefixes to Cloudflare]]></title>
            <link>https://blog.cloudflare.com/diy-byoip/</link>
            <pubDate>Fri, 07 Nov 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ Announcing a new self-serve API for Bring Your Own IP (BYOIP), giving customers unprecedented control and flexibility to onboard, manage, and use their own IP prefixes with Cloudflare's services. ]]></description>
            <content:encoded><![CDATA[ <p>When a customer wants to <a href="https://blog.cloudflare.com/bringing-your-own-ips-to-cloudflare-byoip/"><u>bring IP address space to</u></a> Cloudflare, they’ve always had to reach out to their account team to put in a request. This request would then be sent to various Cloudflare engineering teams such as addressing and network engineering — and then the team responsible for the particular service they wanted to use the prefix with (e.g., CDN, Magic Transit, Spectrum, Egress). In addition, they had to work with their own legal teams and potentially another organization if they did not have primary ownership of an IP prefix in order to get a <a href="https://developers.cloudflare.com/byoip/concepts/loa/"><u>Letter of Agency (LOA)</u></a> issued through hoops of approvals. This process is complex, manual, and  time-consuming for all parties involved — sometimes taking up to 4–6 weeks depending on various approvals. </p><p>Well, no longer! Today, we are pleased to announce the launch of our self-serve BYOIP API, which enables our customers to onboard and set up their BYOIP prefixes themselves.</p><p>With self-serve, we handle the bureaucracy for you. We have automated this process using the gold standard for routing security — the Resource Public Key Infrastructure, RPKI. All the while, we continue to ensure the best quality of service by generating LOAs on our customers’ behalf, based on the security guarantees of our new ownership validation process. This ensures that customer routes continue to be accepted in every corner of the Internet.</p><p>Cloudflare takes the security and stability of the whole Internet very seriously. RPKI is a cryptographically-strong authorization mechanism and is, we believe, substantially more reliable than common practice which relies upon human review of scanned documents. However, deployment and availability of some RPKI-signed artifacts like the AS Path Authorisation (ASPA) object remains limited, and for that reason we are limiting the initial scope of self-serve onboarding to BYOIP prefixes originated from Cloudflare's autonomous system number (ASN) AS 13335. By doing this, we only need to rely on the publication of Route Origin Authorisation (ROA) objects, which are widely available. This approach has the advantage of being safe for the Internet and also meeting the needs of most of our BYOIP customers. </p><p>Today, we take a major step forward in offering customers a more comprehensive IP address management (IPAM) platform. With the recent update to <a href="https://blog.cloudflare.com/your-ips-your-rules-enabling-more-efficient-address-space-usage/"><u>enable multiple services on a single BYOIP prefix</u></a> and this latest advancement to enable self-serve onboarding via our API, we hope customers feel empowered to take control of their IPs on our network.</p>
    <div>
      <h2>An evolution of Cloudflare BYOIP</h2>
      <a href="#an-evolution-of-cloudflare-byoip">
        
      </a>
    </div>
    <p>We want Cloudflare to feel like an extension of your infrastructure, which is why we <a href="https://blog.cloudflare.com/bringing-your-own-ips-to-cloudflare-byoip/"><u>originally launched Bring-Your-Own-IP (BYOIP) back in 2020</u></a>. </p><p>A quick refresher: Bring-your-own-IP is named for exactly what it does - it allows customers to bring their own IP space to Cloudflare. Customers choose BYOIP for a number of reasons, but the main reasons are control and configurability. An IP prefix is a range or block of IP addresses. Routers create a table of reachable prefixes, known as a routing table, to ensure that packets are delivered correctly across the Internet. When a customer's Cloudflare services are configured to use the customer's own addresses, onboarded to Cloudflare as BYOIP, a packet with a corresponding destination address will be routed across the Internet to Cloudflare's global edge network, where it will be received and processed. BYOIP can be used with our Layer 7 services, Spectrum, or Magic Transit. </p>
    <div>
      <h2>A look under the hood: How it works</h2>
      <a href="#a-look-under-the-hood-how-it-works">
        
      </a>
    </div>
    
    <div>
      <h3>Today’s world of prefix validation</h3>
      <a href="#todays-world-of-prefix-validation">
        
      </a>
    </div>
    <p>Let’s take a step back and take a look at the state of the BYOIP world right now. Let’s say a customer has authority over a range of IP addresses, and they’d like to bring them to Cloudflare. We require customers to provide us with a Letter of Authorization (LOA) and have an Internet Routing Registry (IRR) record matching their prefix and ASN. Once we have this, we require manual review by a Cloudflare engineer. There are a few issues with this process:</p><ul><li><p>Insecure: The LOA is just a document—a piece of paper. The security of this method rests entirely on the diligence of the engineer reviewing the document. If the review is not able to detect that a document is fraudulent or inaccurate, it is possible for a prefix or ASN to be hijacked.</p></li><li><p>Time-consuming: Generating a single LOA is not always sufficient. If you are leasing IP space, we will ask you to provide documentation confirming that relationship as well, so that we can see a clear chain of authorisation from the original assignment or allocation of addresses to you. Getting all the paper documents to verify this chain of ownership, combined with having to wait for manual review can result in weeks of waiting to deploy a prefix!</p></li></ul>
    <div>
      <h3>Automating trust: How Cloudflare verifies your BYOIP prefix ownership in minutes</h3>
      <a href="#automating-trust-how-cloudflare-verifies-your-byoip-prefix-ownership-in-minutes">
        
      </a>
    </div>
    <p>Moving to a self-serve model allowed us to rethink the manner in which we conduct prefix ownership checks. We asked ourselves: How can we quickly, securely, and automatically prove you are authorized to use your IP prefix and intend to route it through Cloudflare?</p><p>We ended up killing two birds with one stone, thanks to our two-step process involving the creation of an RPKI ROA (verification of intent) and modification of IRR or rDNS records (verification of ownership). Self-serve unlocks the ability to not only onboard prefixes more quickly and without human intervention, but also exercises more rigorous ownership checks than a simple scanned document ever could. While not 100% foolproof, it is a significant improvement in the way we verify ownership.</p>
    <div>
      <h3>Tapping into the authorities	</h3>
      <a href="#tapping-into-the-authorities">
        
      </a>
    </div>
    <p>Regional Internet Registries (RIRs) are the organizations responsible for distributing and managing Internet number resources like IP addresses. They are composed of 5 different entities operating in different regions of the world (<a href="https://developers.cloudflare.com/byoip/get-started/#:~:text=Your%20prefix%20must%20be%20registered%20under%20one%20of%20the%20Regional%20Internet%20Registries%20(RIRs)%3A"><u>RIRs</u></a>). Originally allocated address space from the Internet Assigned Numbers Authority (IANA), they in turn assign and allocate that IP space to Local Internet Registries (LIRs) like ISPs.</p><p>This process is based on RIR policies which generally look at things like legal documentation, existing database/registry records, technical contacts, and BGP information. End-users can obtain addresses from an LIR, or in some cases through an RIR directly. As IPv4 addresses have become more scarce, brokerage services have been launched to allow addresses to be leased for fixed periods from their original assignees.</p><p>The Internet Routing Registry (IRR) is a separate system that focuses on routing rather than address assignment. Many organisations operate IRR instances and allow routing information to be published, including all five RIRs. While most IRR instances impose few barriers to the publication of routing data, those that are operated by RIRs are capable of linking the ability to publish routing information with the organisations to which the corresponding addresses have been assigned. We believe that being able to modify an IRR record protected in this way provides a good signal that a user has the rights to use a prefix.</p><p>Example of a route object containing validation token (using the documentation-only address 192.0.2.0/24):</p>
            <pre><code>% whois -h rr.arin.net 192.0.2.0/24

route:          192.0.2.0/24
origin:         AS13335
descr:          Example Company, Inc.
                cf-validation: 9477b6c3-4344-4ceb-85c4-6463e7d2453f
admin-c:        ADMIN2521-ARIN
tech-c:         ADMIN2521-ARIN
tech-c:         CLOUD146-ARIN
mnt-by:         MNT-CLOUD14
created:        2025-07-29T10:52:27Z
last-modified:  2025-07-29T10:52:27Z
source:         ARIN</code></pre>
            <p>For those that don’t want to go through the process of IRR-based validation, reverse DNS (rDNS) is provided as another secure method of verification. To manage rDNS for a prefix — whether it's creating a PTR record or a security TXT record — you must be granted permission by the entity that allocated the IP block in the first place (usually your ISP or the RIR).</p><p>This permission is demonstrated in one of two ways:</p><ul><li><p>Directly through the IP owner’s authenticated customer portal (ISP/RIR).</p></li><li><p>By the IP owner delegating authority to your third-party DNS provider via an NS record for your reverse zone.</p></li></ul><p>Example of a reverse domain lookup using dig command (using the documentation-only address 192.0.2.0/24):</p>
            <pre><code>% dig cf-validation.2.0.192.in-addr.arpa TXT

; &lt;&lt;&gt;&gt; DiG 9.10.6 &lt;&lt;&gt;&gt; cf-validation.2.0.192.in-addr.arpa TXT
;; global options: +cmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 16686
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;cf-validation.2.0.192.in-addr.arpa. IN TXT

;; ANSWER SECTION:
cf-validation.2.0.192.in-addr.arpa. 300 IN TXT "b2f8af96-d32d-4c46-a886-f97d925d7977"

;; Query time: 35 msec
;; SERVER: 127.0.2.2#53(127.0.2.2)
;; WHEN: Fri Oct 24 10:43:52 EDT 2025
;; MSG SIZE  rcvd: 150</code></pre>
            <p>So how exactly is one supposed to modify these records? That’s where the validation token comes into play. Once you choose either the IRR or Reverse DNS method, we provide a unique, single-use validation token. You must add this token to the content of the relevant record, either in the IRR or in the DNS. Our system then looks for the presence of the token as evidence that the request is being made by someone with authorization to make the requested modification. If the token is found, verification is complete and your ownership is confirmed!</p>
    <div>
      <h3>The digital passport 🛂</h3>
      <a href="#the-digital-passport">
        
      </a>
    </div>
    <p>Ownership is only half the battle; we also need to confirm your intention that you authorize Cloudflare to advertise your prefix. For this, we rely on the gold standard for routing security: the Resource Private Key Infrastructure (RPKI), and in particular Route Origin Authorization (ROA) objects.</p><p>A ROA is a cryptographically-signed document that specifies which Autonomous System Number (ASN) is authorized to originate your IP prefix. You can think of a ROA as the digital equivalent of a certified, signed, and notarised contract from the owner of the prefix.</p><p>Relying parties can validate the signatures in a ROA using the RPKI.You simply create a ROA that specifies Cloudflare's ASN (AS13335) as an authorized originator and arrange for it to be signed. Many of our customers used hosted RPKI systems available through RIR portals for this. When our systems detect this signed authorization, your routing intention is instantly confirmed. </p><p>Many other companies that support BYOIP require a complex workflow involving creating self-signed certificates and manually modifying RDAP (Registration Data Access Protocol) records—a heavy administrative lift. By embracing a choice of IRR object modification and Reverse DNS TXT records, combined with RPKI, we offer a verification process that is much more familiar and straightforward for existing network operators.</p>
    <div>
      <h3>The global reach guarantee</h3>
      <a href="#the-global-reach-guarantee">
        
      </a>
    </div>
    <p>While the new self-serve flow ditches the need for the "dinosaur relic" that is the LOA, many network operators around the world still rely on it as part of the process of accepting prefixes from other networks.</p><p>To help ensure your prefix is accepted by adjacent networks globally, Cloudflare automatically generates a document on your behalf to be distributed in place of a LOA. This document provides information about the checks that we have carried out to confirm that we are authorised to originate the customer prefix, and confirms the presence of valid ROAs to authorise our origination of it. In this way we are able to support the workflows of network operators we connect to who rely upon LOAs, without our customers having the burden of generating them.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1GimIe80gJn5PrRUGkEMpF/130d2590e45088d58ac62ab2240f4d5c/image1.png" />
          </figure>
    <div>
      <h2>Staying away from black holes</h2>
      <a href="#staying-away-from-black-holes">
        
      </a>
    </div>
    <p>One concern in designing the Self-Serve API is the trade-off between giving customers flexibility while implementing the necessary safeguards so that an IP prefix is never advertised without a matching service binding. If this were to happen, Cloudflare would be advertising a prefix with no idea on what to do with the traffic when we receive it! We call this “blackholing” traffic. To handle this, we introduced the requirement of a default service binding — i.e. a service binding that spans the entire range of the IP prefix onboarded. </p><p>A customer can later layer different service bindings on top of their default service binding via <a href="https://blog.cloudflare.com/your-ips-your-rules-enabling-more-efficient-address-space-usage/"><u>multiple service bindings</u></a>, like putting CDN on top of a default Spectrum service binding. This way, a prefix can never be advertised without a service binding and blackhole our customers’ traffic.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/20QAM5GITJ5m5kYkNlh701/82812d202ffa7b9a4e46838aa6c04937/image2.png" />
          </figure>
    <div>
      <h2>Getting started</h2>
      <a href="#getting-started">
        
      </a>
    </div>
    <p>Check out our <a href="https://developers.cloudflare.com/byoip/get-started/"><u>developer docs</u></a> on the most up-to-date documentation on how to onboard, advertise, and add services to your IP prefixes via our API. Remember that onboardings can be complex, and don’t hesitate to ask questions or reach out to our <a href="https://www.cloudflare.com/professional-services/"><u>professional services</u></a> team if you’d like us to do it for you.</p>
    <div>
      <h2>The future of network control</h2>
      <a href="#the-future-of-network-control">
        
      </a>
    </div>
    <p>The ability to script and integrate BYOIP management into existing workflows is a game-changer for modern network operations, and we’re only just getting started. In the months ahead, look for self-serve BYOIP in the dashboard, as well as self-serve BYOIP offboarding to give customers even more control.</p><p>Cloudflare's self-serve BYOIP API onboarding empowers customers with unprecedented control and flexibility over their IP assets. This move to automate onboarding empowers a stronger security posture, moving away from manually-reviewed PDFs and driving <a href="https://rpki.cloudflare.com/"><u>RPKI adoption</u></a>. By using these API calls, organizations can automate complex network tasks, streamline migrations, and build more resilient and agile network infrastructures.</p> ]]></content:encoded>
            <category><![CDATA[API]]></category>
            <category><![CDATA[Addressing]]></category>
            <category><![CDATA[BYOIP]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[Spectrum]]></category>
            <category><![CDATA[CDN]]></category>
            <category><![CDATA[Magic Transit]]></category>
            <category><![CDATA[Egress]]></category>
            <category><![CDATA[Cloudflare Gateway]]></category>
            <category><![CDATA[RPKI]]></category>
            <category><![CDATA[Aegis]]></category>
            <category><![CDATA[Smart Shield]]></category>
            <guid isPermaLink="false">4usaEaUwShJ04VKzlMV0V9</guid>
            <dc:creator>Ash Pallarito</dc:creator>
            <dc:creator>Lynsey Haynes</dc:creator>
            <dc:creator>Gokul Unnikrishnan</dc:creator>
        </item>
        <item>
            <title><![CDATA[A deep dive into BPF LPM trie performance and optimization]]></title>
            <link>https://blog.cloudflare.com/a-deep-dive-into-bpf-lpm-trie-performance-and-optimization/</link>
            <pubDate>Tue, 21 Oct 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ This post explores the performance of BPF LPM tries, a critical data structure used for IP matching.  ]]></description>
            <content:encoded><![CDATA[ <p>It started with a mysterious soft lockup message in production. A single, cryptic line that led us down a rabbit hole into the performance of one of the most fundamental data structures we use: the BPF LPM trie.</p><p>BPF trie maps (<a href="https://docs.ebpf.io/linux/map-type/BPF_MAP_TYPE_LPM_TRIE/">BPF_MAP_TYPE_LPM_TRIE</a>) are heavily used for things like IP and IP+Port matching when routing network packets, ensuring your request passes through the right services before returning a result. The performance of this data structure is critical for serving our customers, but the speed of the current implementation leaves a lot to be desired. We’ve run into several bottlenecks when storing millions of entries in BPF LPM trie maps, such as entry lookup times taking hundreds of milliseconds to complete and freeing maps locking up a CPU for over 10 seconds. For instance, BPF maps are used when evaluating Cloudflare’s <a href="https://www.cloudflare.com/network-services/products/magic-firewall/"><u>Magic Firewall</u></a> rules and these bottlenecks have even led to traffic packet loss for some customers.</p><p>This post gives a refresher of how tries and prefix matching work, benchmark results, and a list of the shortcomings of the current BPF LPM trie implementation.</p>
    <div>
      <h2>A brief recap of tries</h2>
      <a href="#a-brief-recap-of-tries">
        
      </a>
    </div>
    <p>If it’s been a while since you last looked at the trie data structure (or if you’ve never seen it before), a trie is a tree data structure (similar to a binary tree) that allows you to store and search for data for a given key and where each node stores some number of key bits.</p><p>Searches are performed by traversing a path, which essentially reconstructs the key from the traversal path, meaning nodes do not need to store their full key. This differs from a traditional binary search tree (BST) where the primary invariant is that the left child node has a key that is less than the current node and the right child has a key that is greater. BSTs require that each node store the full key so that a comparison can be made at each search step.</p><p>Here’s an example that shows how a BST might store values for the keys:</p><ul><li><p>ABC</p></li><li><p>ABCD</p></li><li><p>ABCDEFGH</p></li><li><p>DEF</p></li></ul>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1uXt5qwpyq7VzrqxXlHFLj/99677afd73a98b9ce04d30209065499f/image4.png" />
          </figure><p>In comparison, a trie for storing the same set of keys might look like this.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3TfFZmwekNAF18yWlOIVWh/58396a19e053bd1c02734a6a54eea18e/image8.png" />
          </figure><p>This way of splitting out bits is really memory-efficient when you have redundancy in your data, e.g. prefixes are common in your keys, because that shared data only requires a single set of nodes. It’s for this reason that tries are often used to efficiently store strings, e.g. dictionaries of words – storing the strings “ABC” and “ABCD” doesn’t require 3 bytes + 4 bytes (assuming ASCII), it only requires 3 bytes + 1 byte because “ABC” is shared by both (the exact number of bits required in the trie is implementation dependent).</p><p>Tries also allow more efficient searching. For instance, if you wanted to know whether the key “CAR” existed in the BST you are required to go to the right child of the root (the node with key “DEF”) and check its left child because this is where it would live if it existed. A trie is more efficient because it searches in prefix order. In this particular example, a trie knows at the root whether that key is in the trie or not.</p><p>This design makes tries perfectly suited for performing longest prefix matches and for working with IP routing using CIDR. CIDR was introduced to make more efficient use of the IP address space (no longer requiring that classes fall into 4 buckets of 8 bits) but comes with added complexity because now the network portion of an IP address can fall anywhere. Handling the CIDR scheme in IP routing tables requires matching on the longest (most specific) prefix in the table rather than performing a search for an exact match.</p><p>If searching a trie does a single-bit comparison at each node, that’s a binary trie. If searching compares more bits we call that a <b><i>multibit trie</i></b>. You can store anything you like in a trie, including IP and subnet addresses – it’s all just ones and zeroes.</p><p>Nodes in multibit tries use more memory than in binary tries, but since computers operate on multibit words anyhow, it’s more efficient from a microarchitecture perspective to use multibit tries because you can traverse through the bits faster, reducing the number of comparisons you need to make to search for your data. It’s a classic space vs time tradeoff.</p><p>There are other optimisations we can use with tries. The distribution of data that you store in a trie might not be uniform and there could be sparsely populated areas. For example, if you store the strings “A” and “BCDEFGHI” in a multibit trie, how many nodes do you expect to use? If you’re using ASCII, you could construct the binary trie with a root node and branch left for “A” or right for “B”. With 8-bit nodes, you’d need another 7 nodes to store “C”, “D”, “E”, “F”, “G”, “H", “I”.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/LO6izFC5e06dRf9ra2roC/167ba5c4128fcebacc7b7a8eab199ea5/image5.png" />
          </figure><p>Since there are no other strings in the trie, that’s pretty suboptimal. Once you hit the first level after matching on “B” you know there’s only one string in the trie with that prefix, and you can avoid creating all the other nodes by using <b><i>path compression</i></b>. Path compression replaces nodes “C”, “D”, “E” etc. with a single one such as “I”.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ADY3lNtF7NIgfUX7bX9vY/828a14e155d6530a4dc8cf3286ce8cc3/image13.png" />
          </figure><p>If you traverse the tree and hit “I”, you still need to compare the search key with the bits you skipped (“CDEFGH”) to make sure your search key matches the string. Exactly how and where you store the skipped bits is implementation dependent – BPF LPM tries simply store the entire key in the leaf node. As your data becomes denser, path compression is less effective.</p><p>What if your data distribution is dense and, say, all the first 3 levels in a trie are fully populated? In that case you can use <b><i>level compression</i></b><i> </i>and replace all the nodes in those levels with a single node that has 2**3 children. This is how Level-Compressed Tries work which are used for <a href="https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-linux">IP route lookup</a> in the Linux kernel (see <a href="https://elixir.bootlin.com/linux/v6.12.43/source/net/ipv4/fib_trie.c"><u>net/ipv4/fib_trie.c</u></a>).</p><p>There are other optimisations too, but this brief detour is sufficient for this post because the BPF LPM trie implementation in the kernel doesn’t fully use the three we just discussed.</p>
    <div>
      <h2>How fast are BPF LPM trie maps?</h2>
      <a href="#how-fast-are-bpf-lpm-trie-maps">
        
      </a>
    </div>
    <p>Here are some numbers from running <a href="https://lore.kernel.org/bpf/20250827140149.1001557-1-matt@readmodwrite.com/"><u>BPF selftests benchmark</u></a> on AMD EPYC 9684X 96-Core machines. Here the trie has 10K entries, a 32-bit prefix length, and an entry for every key in the range [0, 10K).</p><table><tr><td><p>Operation</p></td><td><p>Throughput</p></td><td><p>Stddev</p></td><td><p>Latency</p></td></tr><tr><td><p>lookup</p></td><td><p>7.423M ops/s</p></td><td><p>0.023M ops/s</p></td><td><p>134.710 ns/op</p></td></tr><tr><td><p>update</p></td><td><p>2.643M ops/s</p></td><td><p>0.015M ops/s</p></td><td><p>378.310 ns/op</p></td></tr><tr><td><p>delete</p></td><td><p>0.712M ops/s</p></td><td><p>0.008M ops/s</p></td><td><p>1405.152 ns/op</p></td></tr><tr><td><p>free</p></td><td><p>0.573K ops/s</p></td><td><p>0.574K ops/s</p></td><td><p>1.743 ms/op</p></td></tr></table><p>The time to free a BPF LPM trie with 10K entries is noticeably large. We recently ran into an issue where this took so long that it caused <a href="https://lore.kernel.org/lkml/20250616095532.47020-1-matt@readmodwrite.com/"><u>soft lockup messages</u></a> to spew in production.</p><p>This benchmark gives some idea of worst case behaviour. Since the keys are so densely populated, path compression is completely ineffective. In the next section, we explore the lookup operation to understand the bottlenecks involved.</p>
    <div>
      <h2>Why are BPF LPM tries slow?</h2>
      <a href="#why-are-bpf-lpm-tries-slow">
        
      </a>
    </div>
    <p>The LPM trie implementation in <a href="https://elixir.bootlin.com/linux/v6.12.43/source/kernel/bpf/lpm_trie.c"><u>kernel/bpf/lpm_trie.c</u></a> has a couple of the optimisations we discussed in the introduction. It is capable of multibit comparisons at leaf nodes, but since there are only two child pointers in each internal node, if your tree is densely populated with a lot of data that only differs by one bit, these multibit comparisons degrade into single bit comparisons.</p><p>Here’s an example. Suppose you store the numbers 0, 1, and 3 in a BPF LPM trie. You might hope that since these values fit in a single 32 or 64-bit machine word, you could use a single comparison to decide which next node to visit in the trie. But that’s only possible if your trie implementation has 3 child pointers in the current node (which, to be fair, most trie implementations do). In other words, you want to make a 3-way branching decision but since BPF LPM tries only have two children, you’re limited to a 2-way branch.</p><p>A diagram for this 2-child trie is given below.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ciL2t6aMyJHR2FfX41rNk/365abe47cf384729408cf9b98c65c0be/image9.png" />
          </figure><p>The leaf nodes are shown in green with the key, as a binary string, in the center. Even though a single 8-bit comparison is more than capable of figuring out which node has that key, the BPF LPM trie implementation resorts to inserting intermediate nodes (blue) to inject 2-way branching decisions into your path traversal because its parent (the orange root node in this case) only has 2 children. Once you reach a leaf node, BPF LPM tries can perform a multibit comparison to check the key. If a node supported pointers to more children, the above trie could instead look like this, allowing a 3-way branch and reducing the lookup time.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/17VoWl8OY6tzcARKDKuSjS/b9200dbeddf13f101b7085a549742f95/image3.png" />
          </figure><p>This 2-child design impacts the height of the trie. In the worst case, a completely full trie essentially becomes a binary search tree with height log2(nr_entries) and the height of the trie impacts how many comparisons are required to search for a key.</p><p>The above trie also shows how BPF LPM tries implement a form of path compression – you only need to insert an intermediate node where you have two nodes whose keys differ by a single bit. If instead of 3, you insert a key of 15 (0b1111), this won’t change the layout of the trie; you still only need a single node at the right child of the root.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2ecfKSeoqN3bfBXmC9KHw5/3be952edea34d6b2cc867ba31ce14805/image12.png" />
          </figure><p>And finally, BPF LPM tries do not implement level compression. Again, this stems from the fact that nodes in the trie can only have 2 children. IP route tables tend to have many prefixes in common and you typically see densely packed tries at the upper levels which makes level compression very effective for tries containing IP routes.</p><p>Here’s a graph showing how the lookup throughput for LPM tries (measured in million ops/sec) degrades as the number of entries increases, from 1 entry up to 100K entries.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/33I92exrEZTcUWOjxaBOqY/fb1de551b06e3272c8670d0117d738fa/image2.png" />
          </figure><p>Once you reach 1 million entries, throughput is around 1.5 million ops/sec, and continues to fall as the number of entries increases.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4OhaAaI5Y2XJCofI9V39z/567a01b3335f29ef3b46ccdd74dc27e5/image1.png" />
          </figure><p>Why is this? Initially, this is because of the L1 dcache miss rate. All of those nodes that need to be traversed in the trie are potential cache miss opportunities.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Gx4fOLKmhUKHegybQU7sl/4936239213f0061d5cbc2f5d6b63fde6/image11.png" />
          </figure><p>As you can see from the graph, L1 dcache miss rate remains relatively steady and yet the throughput continues to decline. At around 80K entries, dTLB miss rate becomes the bottleneck.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4Jy7aTN3Nyo2EsbSzw313n/d26871fa417ffe293adb47fe7f7dc56b/image7.png" />
          </figure><p>Because BPF LPM tries to dynamically allocate individual nodes from a freelist of kernel memory, these nodes can live at arbitrary addresses. Which means traversing a path through a trie almost certainly will incur cache misses and potentially dTLB misses. This gets worse as the number of entries, and height of the trie, increases.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6CB3MvSvSgH1T2eY7Xlei8/81ebe572592ca71529d79564a88993f0/image10.png" />
          </figure>
    <div>
      <h2>Where do we go from here?</h2>
      <a href="#where-do-we-go-from-here">
        
      </a>
    </div>
    <p>By understanding the current limitations of the BPF LPM trie, we can now work towards building a more performant and efficient solution for the future of the Internet.</p><p>We’ve already contributed these benchmarks to the upstream Linux kernel — but that’s only the start. We have plans to improve the performance of BPM LPM tries, particularly the lookup function which is heavily used for our workloads. This post covered a number of optimisations that are already used by the <a href="https://elixir.bootlin.com/linux/v6.12.43/source/net/ipv4/fib_trie.c"><u>net/ipv4/fib_trie.c</u></a> code, so a natural first step is to refactor that code so that a common Level Compressed trie implementation can be used. Expect future blog posts to explore this work in depth.</p><p>If you’re interested in looking at more performance numbers, <a href="https://wiki.cfdata.org/display/~jesper">Jesper Brouer</a> has recorded some here: <a href="https://github.com/xdp-project/xdp-project/blob/main/areas/bench/bench02_lpm-trie-lookup.org">https://github.com/xdp-project/xdp-project/blob/main/areas/bench/bench02_lpm-trie-lookup.org</a>.</p><h6><i>If the Linux kernel, performance, or optimising data structures excites you, </i><a href="https://www.cloudflare.com/en-gb/careers/jobs/?department=Engineering&amp;location=default"><i>our engineering teams are hiring</i></a><i>.</i></h6><p></p> ]]></content:encoded>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[eBPF]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[Linux]]></category>
            <category><![CDATA[Performance]]></category>
            <guid isPermaLink="false">2A4WHjTqyxprwUMPaZ6tfj</guid>
            <dc:creator>Matt Fleming</dc:creator>
            <dc:creator>Jesper Brouer</dc:creator>
        </item>
        <item>
            <title><![CDATA[Simplify allowlist management and lock down origin access with Cloudflare Aegis]]></title>
            <link>https://blog.cloudflare.com/aegis-deep-dive/</link>
            <pubDate>Thu, 20 Mar 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare Aegis provides dedicated egress IPs for Zero Trust origin access strategies, now supporting BYOIP and customer-facing configurability, with observability of Aegis IP utilization soon. ]]></description>
            <content:encoded><![CDATA[ <p>Today, we’re taking a deep dive into <a href="https://developers.cloudflare.com/aegis/"><u>Aegis</u></a>, Cloudflare’s origin protection product, to help you understand what the product is, how it works, and how to take full advantage of it for locking down access to your origin. We’re excited to announce the availability of <a href="https://developers.cloudflare.com/byoip/"><u>Bring Your Own IPs (BYOIP)</u></a> for Aegis, a customer-accessible Aegis API, and a gradual rollout for observability of Aegis IP utilization.</p><p>If you are new to Cloudflare Aegis, let’s take a step back and understand the product’s purpose and security benefits, process, and how it came to be. </p>
    <div>
      <h3>Origin protection then…</h3>
      <a href="#origin-protection-then">
        
      </a>
    </div>
    <p>Allowlisting a specific set of IP addresses has long existed as one of the simplest ways of restricting access to a server. This firewall mechanism is a starting state that just about every server supports. As we built Cloudflare’s network, one of the first features that customers requested was the ability to restrict access to their origin, so only Cloudflare could make requests to it. Back then, the most natural way to support this was to tell our customers which IP addresses belong to us, so they could allowlist those in their origin firewall. To that end, we have published our <a href="https://www.cloudflare.com/ips/"><u>IP address ranges</u></a>, providing an easy configuration to ensure that all traffic accessing your origin comes from Cloudflare’s network.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4I2fP03AeszxuHL78Ap9lA/bf75dcb9259b8b97b73f55831b3c019f/BLOG-2609_2.png" />
          </figure><p>However, Cloudflare’s IP ranges are used across multiple Cloudflare services and customers, so restricting access to the full list doesn’t necessarily give customers the security benefit they need. With the <a href="https://www.cloudflare.com/2024-api-security-management-report/#:~:text=Cloudflare%20serves%20over%2050%20million,billion%20cyber%20threats%20each%20day."><u>frequency</u></a> and <a href="https://blog.cloudflare.com/how-cloudflare-auto-mitigated-world-record-3-8-tbps-ddos-attack/"><u>scale</u></a> of IP-based and DDoS attacks every day, origin protection is absolutely paramount. Some customers have the need for more stringent security precautions to ensure that traffic is only coming from Cloudflare’s network and, more specifically, only coming from their zones within Cloudflare.</p>
    <div>
      <h3>Origin protection now…</h3>
      <a href="#origin-protection-now">
        
      </a>
    </div>
    <p>Cloudflare has built out additional services to lock down access to your origin, like <a href="https://developers.cloudflare.com/ssl/origin-configuration/authenticated-origin-pull/"><u>authenticated origin pulls</u></a> (mTLS) and <a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/"><u>Cloudflare Tunnels</u></a>, that no longer rely on IP addresses as an indicator of identity. These are part of a global effort towards <a href="https://www.cloudflare.com/learning/security/glossary/what-is-zero-trust/#:~:text=Zero%20Trust%20security%20means%20that,shown%20to%20prevent%20data%20breaches."><u>Zero Trust security</u></a>: whereas the Internet used to operate under a trust-but-verify model, we aim to operate as nothing is trusted, and everything is verified. </p><p>Having non-ephemeral IP addresses — upon which the firewall allowlist mechanism relies — does not quite fit the Zero Trust system. Although mTLS and similar solutions present a more modern approach to origin security, they aren’t always feasible for customers, depending on their hardware or system architecture. </p><p>We launched <a href="https://blog.cloudflare.com/cloudflare-aegis/"><u>Cloudflare Aegis</u></a> in March 2023 for customers seeking an intermediary security solution. Aegis provides a dedicated IP address, or set of addresses, from which Cloudflare sends requests, allowing you to further lock down your origin’s layer 3 firewall. Aegis also simplifies management by only requiring you to allowlist a small number of IP addresses. </p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3KmeBCAqzygLJWR7oMf7Mw/5303403c266e80d271160b9c32cbd764/BLOG-2609_3.png" />
          </figure><p>Normally, Cloudflare’s <a href="https://www.cloudflare.com/ips/"><u>publicly listed IP ranges</u></a> are used to egress from Cloudflare’s network to the customer origin. With these IP addresses distributed across Cloudflare’s network, the customer traffic can egress from many servers to the customer origin.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3RbmfIwMajVSjnHdEBN1Y/f99b2f41cb289df93f90c1960bf6a497/BLOG-2609_4.png" />
          </figure><p>With Aegis, a customer does not necessarily have an Aegis IP address on every server if they are using IPv4. That means requests must be routed through Cloudflare’s network to a server where Aegis IP addresses are present before the traffic can egress to the customer origin. </p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2TdNsZJmckJZuVCmAyCGbA/d7ed52f94c8a6fc375363bf011e40229/BLOG-2609_5.png" />
          </figure>
    <div>
      <h3>How requests are routed with Aegis</h3>
      <a href="#how-requests-are-routed-with-aegis">
        
      </a>
    </div>
    <p>A few terms, before we begin:</p><ul><li><p>Anycast: a technology where each of our data centers “announces” and can handle the same IP address ranges</p></li><li><p>Unicast: a technology where each server is given its own, unique <i>unicast</i> IP address</p></li></ul><p>Dedicated egress Aegis IPs are located in a particular set of specific data centers. This list is handpicked by the customer, in conversation with Cloudflare, to be geographically close to their origin servers for optimal security and performance in tandem. </p><p>Aegis relies on a technology called <a href="https://blog.cloudflare.com/cloudflare-servers-dont-own-ips-anymore/#soft-unicast-is-indistinguishable-from-magic"><u>soft-unicasting,</u> which allows</a> us to share a /32 egress IPv4 amongst many servers, thereby enabling us to spread a single subnet across many data centers. Then, the traffic going back from the origin servers (the return path) is routed to their closest data center. Once in Cloudflare's network, our in-house <a href="https://blog.cloudflare.com/unimog-cloudflares-edge-load-balancer/"><u>L4 XDP-based load balancer, Unimog,</u></a> ensures that the return packets make it back to the machine that connected to the origin servers at the start.</p><p>This supports fast, local, and reliable egress from Cloudflare’s network. With this configuration, we essentially use <a href="https://www.cloudflare.com/learning/cdn/glossary/anycast-network/"><u>Anycast</u></a> at the <a href="https://www.cloudflare.com/learning/security/glossary/what-is-bgp/"><u>BGP layer</u></a> before using an IP and port range to reach a specific machine in the correct data center. Across Cloudflare’s network, we use a significant range of egress IPs to cover all data centers and machines. Since Aegis customers only have a few IPv4 addresses, the range is limited to a few data centers rather than Cloudflare’s entire egress IP range.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Y2sZmlh9uy6tRAiJhCZOp/ae186c36f30ba80500b615451952dfd7/BLOG-2609_6.png" />
          </figure>
    <div>
      <h3>The capacity issue</h3>
      <a href="#the-capacity-issue">
        
      </a>
    </div>
    <p>Every IP address has <a href="https://www.cloudflare.com/learning/network-layer/what-is-a-computer-port/#:~:text=There%20are%2065%2C535%20possible%20port,File%20Transfer%20Protocol%20(FTP)."><u>65,535 ports</u></a>. A request egresses from exactly one port on the Aegis IP address to exactly one port on the origin IP address. </p><p>Each TCP request consists of a 4-way tuple that contains:</p><ol><li><p>Source IP address</p></li><li><p>Source port</p></li><li><p>Destination IP address</p></li><li><p>Destination port</p></li></ol><p>A <a href="https://blog.cloudflare.com/everything-you-ever-wanted-to-know-about-udp-sockets-but-were-afraid-to-ask-part-1/"><u>UDP request</u></a> can also consist of a 4-way tuple (if it’s connected) or a 2-way tuple (if it’s unconnected), simply including a bind IP address and port. Aegis supports both TCP and UDP traffic — in either case, the requests rely upon IP:port pairings between the source and destination. </p><p>When a request reaches the origin, it opens a <i>connection</i>, through which data can pass between the source and destination. One source port can sustain multiple connections at a time, <i>only</i> if the destination ip:ports are different. </p><p>Normally at Cloudflare, an IP address establishes connections to a variety of different destination IP ports or addresses to support high traffic volumes. With Aegis, that is no longer the case. The challenge with Aegis IP capacity is exactly that: all the traffic is egressing to the same (or a small set of) origin IP address(es) from the same (or a small set of) source IP address(es). That means Aegis IP addresses have capacity constraints associated with them.</p><p>The number of <i>concurrent connections</i> is the number of simultaneous connections for a given 4-way tuple. Between one client and one server, the volume of concurrent connections is inherently limited by the number of ports on an IP address to 65,535 — each source ip:port can only support a single outbound connection per destination IP:port. In practice, that maximum number of concurrent connections is often lower due to assignments of port ranges across many servers and imperfect load distribution. </p><p>For planning purposes, we use an estimate of ~80% of the IP capacity (the volume of concurrent connections a source IP address can support to a destination IP address) to protect against overload, in case of traffic spikes. If every port on an IP address is maintaining a concurrent connection, that address would reach and exceed capacity — it would be overloaded with port usage exhaustion. Requests may then be dropped since no new connections can be established. To build in resiliency, we only plan to support 40k concurrent connections per Aegis IP address per origin.</p>
    <div>
      <h3>Aegis with IPv6</h3>
      <a href="#aegis-with-ipv6">
        
      </a>
    </div>
    <p>Each customer who onboards with Cloudflare Aegis receives two <a href="https://www.ripe.net/about-us/press-centre/understanding-ip-addressing/#:~:text=of%20IPv6%20addresses.-,IPv6%20Relative%20Network%20Sizes,-/128"><u>/64 prefixes</u></a> to be globally allocated and announced. That means, outside of Cloudflare’s China Network, every Cloudflare data center has hundreds or even thousands of addresses reserved for egressing your traffic directly to your origin. Without Aegis, any data center in Cloudflare’s Anycast network can serve as a point of egress – so we built Aegis with IPv6 to preserve that level of resiliency and performance. The sheer scale of IPv6, with its available address space, allows us to cushion Aegis’ capacity to a point far beyond any reasonable concern. Globally allocating and announcing your Aegis IPv6 addresses maintains all of Cloudflare’s functionality as a reverse proxy without inducing additional friction.</p>
    <div>
      <h3>Aegis with IPv4</h3>
      <a href="#aegis-with-ipv4">
        
      </a>
    </div>
    <p>Although using IPv6 with Aegis facilitates the best possible speed and resiliency for your traffic, we recognize the transition from IPv4 to IPv6 can be challenging for some customers. Moreover, some customers prefer Aegis IPv4 for granular control over their traffic’s physical egress locations. Still, IPv4 space is more limited and more expensive — while all Cloudflare Aegis customers simply receive two dedicated /64s for IPv6, enabling Aegis with IPv4 requires a touch more tailoring. When you onboard to Aegis, we work with you to determine the ideal number of IPv4 addresses for your Aegis configuration to maintain optimal performance and resiliency, while also ensuring cost efficiency. </p><p>Naturally, this introduces a bottleneck — whereas every Cloudflare data center can serve as a point of egress with Aegis IPv6, only a small fraction will have that capability with Aegis IPv4. We aim to mitigate this impact by careful provisioning of the IPv4 addresses. </p><p>Now that BYOIP for Aegis is supported, you can also onboard an entire IPv4 <a href="https://www.ripe.net/about-us/press-centre/understanding-ip-addressing/#:~:text=in%20that%20%E2%80%9Cblock%E2%80%9D.-,IPv4,-The%20size%20of"><u>/24</u></a> prefix or IPv6 /64 for Aegis, allowing for a cost-effective configuration with a much higher volume of capacity.</p><p>When we launched Aegis, each IP address was allocated to one data center, requiring at least two IPv4 addresses for appropriate resiliency. To reduce the number of IP addresses necessary in your layer 3 firewall allowlist, and to manage the cost to the customer of leasing IPs, we expanded our Aegis functionality so that one address can be announced from up to four data centers. To do this, we essentially slice the available IP port range into four subsets and provision each at a unique data center. </p><p>A quick refresher: when a request travels through Cloudflare, it first hits our network via an <i>ingress data center</i>. The ingress data center is generally near the eyeball, who is sending the request. Then, the request is routed following BGP – or <a href="https://developers.cloudflare.com/argo-smart-routing/"><u>Argo Smart Routing</u></a>, when enabled – to an <i>exit, or egress, data center</i>. The exit data center will generally fall in close geographic proximity to the request’s destination, which is the customer origin. This mitigates latency induced by the final hop from Cloudflare’s network to your origin.</p><p>With Aegis, the possible exit data centers are limited to the data centers in which an Aegis IP address has been allocated. For IPv6, this is a non-issue, since every data center outside our China Network is covered. With IPv4, however, the exit data centers are limited to a much smaller number (4 x the number of Aegis IPs). Aegis IP addresses are allocated, then, to data centers in close geographic proximity to your origin(s). This maximizes the likelihood that whichever data centers would ordinarily have been selected as the egress data center are already announcing Aegis IP addresses. Theoretically, no extra hop is necessary from the optimal exit data center to an Aegis-enabled data center – they are one and the same. In practice, this cannot be guaranteed 100% of the time because optimal routes are ever-changing. We recommend IPv6 to ensure optimal performance because of this possibility of an extra hop with IPv4.</p><p>A brief comparison, to summarize:</p><table><tr><th><p>
</p></th><th><p><b>Aegis IPv4</b></p></th><th><p><b>Aegis IPv6</b></p></th></tr><tr><td><p>Physical points of egress</p></td><td><p>4 physical data center sites (1-2 cities near origin) per IP address</p></td><td><p>All 300+ Cloudflare <a href="https://www.cloudflare.com/network/"><u>locations</u></a> (excluding China network)</p></td></tr><tr><td><p>Capacity</p></td><td><p>One IPv4 address per 40,000 concurrent connections per origin</p></td><td><p>Two /64 prefixes for all Aegis customers (&gt;36 quintillion IP addresses)</p><p>~50,000x capacity of IPv4 config</p></td></tr><tr><td><p>Pricing model</p></td><td><p>Monthly fee based on IPv4 leases or BYOIP for Aegis prefix fees</p></td><td><p>Included with product purchase or BYOIP for Aegis prefix fees</p></td></tr></table><p>Now, with Aegis analytics coming soon, customers can monitor and manage their IP address usage by Cloudflare data centers in aggregate. Every Cloudflare data center will now run a service with the sole purpose of calculating and reporting Aegis usage for each origin IP:port at regular intervals. Written to an internal database, these reports will be aggregated and exposed to customers via Cloudflare’s <a href="https://developers.cloudflare.com/analytics/graphql-api/"><u>GraphQL Analytics API</u></a>. Several aggregation functions will be available, such as average usage over a period of time, or total summed usage.</p><p>This will allow customers to track their own IP address usage to further optimize the distribution of traffic and addresses across different points of presence for IPv4. Additionally, the improved observability will support customer-created notifications via RSS feeds such that you can design your own notification thresholds for port usage.</p>
    <div>
      <h3>How Aegis benefits from connection reuse &amp; coalescence</h3>
      <a href="#how-aegis-benefits-from-connection-reuse-coalescence">
        
      </a>
    </div>
    <p>As we mentioned earlier, requests egress from the source IP address to the destination IP address only when a connection has been established between the two. In early Internet protocols, requests and connections were 1:1. Now, once that connection is open, it can remain open and support hundreds or thousands of requests between that source and destination via <i>connection reuse</i> and <i>connection coalescing</i>. </p><p>Connection reuse, implemented by <a href="https://datatracker.ietf.org/doc/html/rfc2616?cf_history_state=%7B%22guid%22%3A%22C255D9FF78CD46CDA4F76812EA68C350%22%2C%22historyId%22%3A41%2C%22targetId%22%3A%223BBCDD89688CD49F2C3350ED8037BC6F%22%7D"><u>HTTP/1.1</u></a>, allows for requests with the same source ip:port and destination IP:port to pass through the same connection to the origin. A “simple” website by modern standards can send hundreds of requests just to load initially; by streamlining these into a single origin connection, connection reuse reduces the latency derived from constantly opening and closing new connections between two endpoints. Still, any request from a different domain would need to create a new, unique connection to communicate with the origin. </p><p>As of <a href="https://datatracker.ietf.org/doc/html/rfc7540"><u>HTTP/2</u></a>, connection coalescing can group requests from different domains into one connection if the requests have the same destination IP address and the server certificate is authoritative for both domains. Depending on the traffic patterns routing from the eyeball to an Aegis IP address, the volume of connection reuse &amp; coalescence can vary. One connection most likely facilitates the traffic of many requests, but each connection requires at least one request to open it in the first place. Therefore, the worst possible ratio between concurrent connections and concurrent requests is 1:1. </p><p>In practice, a 1:1 ratio between connections and requests almost <i>never</i> happens. Connection reuse and connection coalescence are very common but highly variable, due to sporadic traffic patterns. We size our Aegis IP address allocations accordingly, erring on the conservative side to minimize risk of capacity overload. With the proper number of dedicated egress IP addresses and optimal allocation to Cloudflare points of presence, we are able to lock down your origin with IPv4 addresses to block malicious layer 7 traffic and reduce overall load to your origin. </p><p>Connection reuse and coalescence pairs well with Aegis to reduce load on the origin’s side as well. Because a request can be reused if it comes from the same source IP:port and shares a destination IP:port, routing traffic from a reduced number of source IP addresses (Aegis addresses, in this case) to your origin facilitates a smaller number of total connections. Not only does this improve security by limiting open connection access, but also it reduces latency since fewer connections need to be opened. Maintaining fewer connections is also less resource intensive — more connections means more CPU and more memory handling the inbound requests. By reducing the number of connections to the origin through reuse and coalescence, HTTP/2 lowers the overall cost of operation by optimizing resource usage. </p>
    <div>
      <h3>Recap and recommendations</h3>
      <a href="#recap-and-recommendations">
        
      </a>
    </div>
    <p>Cloudflare Aegis locks down your origin by restricting access via your origin’s layer 3 firewall. By routing traffic from Cloudflare’s network to your origin through dedicated egress IP addresses, you can ensure that requests coming from Cloudflare are legitimate customer traffic. With a simple flip-switch configuration — allow listing your Aegis IP addresses in your origin’s firewall — you can block excessive noise and bad actors from access. So, to help you take full advantage of Aegis, let’s recap:</p><ul><li><p>Concurrent connections can be, at worst, a 1:1 ratio to concurrent requests.</p></li><li><p>Cloudflare bases our IP address usage recommendations on 40,000 concurrent connections to minimize risk of capacity overload.</p></li><li><p>Each Aegis IP address supports an estimated 40,000 concurrent connections per origin IP address.</p></li></ul><p>Additionally, we’re excited to now support:</p><ul><li><p><a href="https://developers.cloudflare.com/api/resources/zones/subresources/settings/methods/edit/"><u>Public Aegis API</u></a> </p></li><li><p><a href="https://developers.cloudflare.com/aegis/setup/"><u>BYOIP for Aegis</u></a> </p></li><li><p>Customer-facing Aegis observability (coming soon via gradual rollout)</p></li></ul><p>For customers leasing Cloudflare-owned Aegis IP addresses, the Aegis API will allow you to enable and disable Aegis on zones within your parent account (parent being the account which owns the IP lease). If you deploy your Aegis IP addresses across multiple accounts, you’ll still rely on Cloudflare’s account team to enable and disable Aegis on zones within those additional accounts.</p><p>For customers who leverage BYOIP for Aegis, the Aegis API will allow you to enable and disable Aegis on zones within your parent account <i>and</i> within any accounts to which you <a href="https://developers.cloudflare.com/byoip/concepts/prefix-delegations/#:~:text=BYOIP%20supports%20prefix%20delegations%2C%20which,service%20used%20with%20the%20prefix."><u>delegate prefix permissions</u></a>. We recommend BYOIP for Aegis for improved configurability and cost efficiency. </p><table><tr><th><p>
</p></th><th><p><b>BYOIP</b></p></th><th><p><b>Cloudflare-owned IPs</b></p></th></tr><tr><td><p>Enable Aegis on zones on parent account</p></td><td><p>✓</p></td><td><p>✓</p></td></tr><tr><td><p>Enable Aegis on zones beyond parent account</p></td><td><p>✓</p></td><td><p>✗</p></td></tr><tr><td><p>Disable Aegis on zones on parent account</p></td><td><p>✓</p></td><td><p>✓</p></td></tr><tr><td><p>Disable Aegis on zones beyond parent account</p></td><td><p>✓</p></td><td><p>✗</p></td></tr><tr><td><p>Access Aegis analytics via the API</p></td><td><p>✓</p></td><td><p>✓</p></td></tr></table><p>With the improved Aegis observability, all Aegis customers will be able to monitor their port usage by IP address, account, zone, and data centers in aggregate via the API. You will also be able to ingest these metrics to configure your own, customizable alerts based on certain port usage thresholds. Alongside the new configurability of Aegis, this visibility will better equip customers to manage their Aegis deployments themselves and alert <i>us</i> to any changes, rather than the other way around.</p><p>We also have a few adjacent recommendations to optimize your Aegis configuration. We generally encourage the following best practices for security hygiene for your origin and traffic as well.</p><ol><li><p><b>IPv6 Compatibility</b>: if your origin(s) support IPv6, you will experience even better resiliency, performance, and availability with your dedicated egress IP addresses at a lower overall cost.</p></li><li><p><a href="https://www.cloudflare.com/learning/performance/http2-vs-http1.1/"><b><u>HTTP/2</u></b></a><b> or </b><a href="https://www.cloudflare.com/learning/performance/what-is-http3/"><b><u>HTTP/3</u></b></a><b> adoption</b>: by supporting connection reuse and coalescence, you will reduce overall load to your origin and latency in the path of your request.</p></li><li><p><b>Multi-level origin protection</b>: while Aegis protects your origin at the application level, it pairs well with <a href="https://blog.cloudflare.com/access-aegis-cni/"><u>Access and CNI</u></a>, <a href="https://developers.cloudflare.com/ssl/origin-configuration/authenticated-origin-pull/"><u>Authenticated Origin Pulls</u></a>, and/or other Cloudflare products to holistically protect, verify, and facilitate your traffic from edge to origin.</p></li></ol><p>If you or your organization want to enhance security and lock down your origin with dedicated egress IP addresses reach out to your account team to onboard today. </p> ]]></content:encoded>
            <category><![CDATA[Security Week]]></category>
            <category><![CDATA[Aegis]]></category>
            <category><![CDATA[Egress]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <guid isPermaLink="false">LPhv5n2cp5pkZBwAC8hN0</guid>
            <dc:creator>Mia Malden</dc:creator>
            <dc:creator>Adrien Vasseur</dc:creator>
        </item>
        <item>
            <title><![CDATA[connect() - why are you so slow?]]></title>
            <link>https://blog.cloudflare.com/linux-transport-protocol-port-selection-performance/</link>
            <pubDate>Thu, 08 Feb 2024 14:00:27 GMT</pubDate>
            <description><![CDATA[ This is our story of what we learned about the connect() implementation for TCP in Linux. Both its strong and weak points. How connect() latency changes under pressure, and how to open connection so that the syscall latency is deterministic and time-bound ]]></description>
            <content:encoded><![CDATA[ <p></p><p>It is no secret that Cloudflare is encouraging companies to deprecate their use of IPv4 addresses and move to IPv6 addresses. We have a couple articles on the subject from this year:</p><ul><li><p><a href="/amazon-2bn-ipv4-tax-how-avoid-paying/">Amazon’s $2bn IPv4 tax – and how you can avoid paying it</a></p></li><li><p><a href="/ipv6-from-dns-pov/">Using DNS to estimate worldwide state of IPv6 adoption</a></p></li></ul><p>And many more in our <a href="/searchresults#q=IPv6&amp;sort=date%20descending&amp;f:@customer_facing_source=[Blog]&amp;f:@language=[English]">catalog</a>. To help with this, we spent time this last year investigating and implementing infrastructure to reduce our internal and egress use of IPv4 addresses. We prefer to re-allocate our addresses than to purchase more due to increasing costs. And in this effort we discovered that our cache service is one of our bigger consumers of IPv4 addresses. Before we remove IPv4 addresses for our cache services, we first need to understand how cache works at Cloudflare.</p>
    <div>
      <h2>How does cache work at Cloudflare?</h2>
      <a href="#how-does-cache-work-at-cloudflare">
        
      </a>
    </div>
    <p>Describing the full scope of the <a href="https://developers.cloudflare.com/reference-architecture/cdn-reference-architecture/#cloudflare-cdn-architecture-and-design">architecture</a> is out of scope of this article, however, we can provide a basic outline:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/70ULgxsqU4zuyWYVrNn6et/8c80079d6dd93083059a875bbf48059d/image1-2.png" />
            
            </figure><ol><li><p>Internet User makes a request to pull an asset</p></li><li><p>Cloudflare infrastructure routes that request to a handler</p></li><li><p>Handler machine returns cached asset, or if miss</p></li><li><p>Handler machine reaches to origin server (owned by a customer) to pull the requested asset</p></li></ol><p>The particularly interesting part is the cache miss case. When a website suddenly becomes very popular, many uncached assets may need to be fetched all at once. Hence we may make an upwards of: 50k TCP unicast connections to a single destination_._</p><p>That is a lot of connections! We have strategies in place to limit the impact of this or avoid this problem altogether. But in these rare cases when it occurs, we will then balance these connections over two source IPv4 addresses.</p><p>Our goal is to remove the load balancing and prefer one IPv4 address. To do that, we need to understand the performance impact of two IPv4 addresses vs one.</p>
    <div>
      <h2>TCP connect() performance of two source IPv4 addresses vs one IPv4 address</h2>
      <a href="#tcp-connect-performance-of-two-source-ipv4-addresses-vs-one-ipv4-address">
        
      </a>
    </div>
    <p>We leveraged a tool called <a href="https://github.com/wg/wrk">wrk</a>, and modified it to distribute connections over multiple source IP addresses. Then we ran a workload of 70k connections over 48 threads for a period of time.</p><p>During the test we measured the function <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/tcp_ipv4.c#L201">tcp_v4_connect()</a> with the BPF BCC libbpf-tool <a href="https://github.com/iovisor/bcc/blob/master/libbpf-tools/funclatency.c">funclatency</a> tool to gather latency metrics as time progresses.</p><p>Note that throughout the rest of this article, all the numbers are specific to a single machine with no production traffic. We are making the assumption that if we can improve a worse case scenario in an algorithm with a best case machine, that the results could be extrapolated to production. Lock contention was specifically taken out of the equation, but will have production implications.</p>
    <div>
      <h3>Two IPv4 addresses</h3>
      <a href="#two-ipv4-addresses">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1q7v3WNgI5X3JQg5ua0B8g/5b557ca762a08422badae379233dee76/image6.png" />
            
            </figure><p>The y-axis are buckets of nanoseconds in powers of ten. The x-axis represents the number of connections made per bucket. Therefore, more connections in a lower power of ten buckets is better.</p><p>We can see that the majority of the connections occur in the fast case with roughly ~20k in the slow case. We should expect this bimodal to increase over time due to wrk continuously closing and establishing connections.</p><p>Now let us look at the performance of one IPv4 address under the same conditions.</p>
    <div>
      <h3>One IPv4 address</h3>
      <a href="#one-ipv4-address">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6kpueuXS3SbBTIig306IDN/b27ab899656fbfc0bf3c885a44fb04a4/image8.png" />
            
            </figure><p>In this case, the bimodal distribution is even more pronounced. Over half of the total connections are in the slow case than in the fast! We may conclude that simply switching to one IPv4 address for cache egress is going to introduce significant latency on our connect() syscalls.</p><p>The next logical step is to figure out where this bottleneck is happening.</p>
    <div>
      <h2>Port selection is not what you think it is</h2>
      <a href="#port-selection-is-not-what-you-think-it-is">
        
      </a>
    </div>
    <p>To investigate this, we first took a flame graph of a production machine:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1tFwadYDdC5UVK78j4yKsv/64aca09189acba5bf3dab2e043265e0f/image7.png" />
            
            </figure><p>Flame graphs depict a run-time function call stack of a system. Y-axis depicts call-stack depth, and x-axis depicts a function name in a horizontal bar that represents the amount of times the function was sampled. Checkout this in-depth <a href="https://www.brendangregg.com/flamegraphs.html">guide</a> about flame graphs for more details.</p><p>Most of the samples are taken in the function <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/inet_hashtables.c#L1000"><code>__inet_hash_connect()</code></a>. We can see that there are also many samples for <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/inet_hashtables.c#L544"><code>__inet_check_established()</code></a> with some lock contention sampled between. We have a better picture of a potential bottleneck, but we do not have a consistent test to compare against.</p><p>Wrk introduces a bit more variability than we would like to see. Still focusing on the function <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/tcp_ipv4.c#L201"><code>tcp_v4_connect()</code></a>, we performed another synthetic test with a homegrown benchmark tool to test one IPv4 address. A tool such as <a href="https://github.com/ColinIanKing/stress-ng">stress-ng</a> may also be used, but some modification is necessary to implement the socket option <a href="https://man7.org/linux/man-pages/man7/ip.7.html"><code>IP_LOCAL_PORT_RANGE</code></a>. There is more about that socket option later.</p><p>We are now going to ensure a deterministic amount of connections, and remove lock contention from the problem. The result is something like this:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5d6tJum5BBe3jsLRqhXtFN/7952fb3d0a3da761de158fae4f925eb5/Screenshot-2024-02-07-at-15.54.29.png" />
            
            </figure><p>On the y-axis we measured the latency between the start and end of a connect() syscall. The x-axis denotes when a connect() was called. Green dots are even numbered ports, and red dots are odd numbered ports. The orange line is a linear-regression on the data.</p><p>The disparity between the average time for port allocation between even and odd ports provides us with a major clue. Connections with odd ports are found significantly slower than the even. Further, odd ports are not interleaved with earlier connections. This implies we exhaust our even ports before attempting the odd. The chart also confirms our bimodal distribution.</p>
    <div>
      <h3>__inet_hash_connect()</h3>
      <a href="#__inet_hash_connect">
        
      </a>
    </div>
    <p>At this point we wanted to understand this split a bit better. We know from the flame graph and the function <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/inet_hashtables.c#L1000"><code>__inet_hash_connect()</code></a> that this holds the algorithm for port selection. For context, this function is responsible for associating the socket to a source port in a late bind. If a port was previously provided with bind(), the algorithm just tests for a unique TCP 4-tuple (src ip, src port, dest ip, dest port) and ignores port selection.</p><p>Before we dive in, there is a little bit of setup work that happens first. Linux first generates a time-based hash that is used as the basis for the starting port, then adds randomization, and then puts that information into an offset variable. This is always set to an even integer.</p><p><a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/inet_hashtables.c#L1043">net/ipv4/inet_hashtables.c</a></p>
            <pre><code>   offset &amp;= ~1U;
    
other_parity_scan:
    port = low + offset;
    for (i = 0; i &lt; remaining; i += 2, port += 2) {
        if (unlikely(port &gt;= high))
            port -= remaining;

        inet_bind_bucket_for_each(tb, &amp;head-&gt;chain) {
            if (inet_bind_bucket_match(tb, net, port, l3mdev)) {
                if (!check_established(death_row, sk, port, &amp;tw))
                    goto ok;
                goto next_port;
            }
        }
    }

    offset++;
    if ((offset &amp; 1) &amp;&amp; remaining &gt; 1)
        goto other_parity_scan;</code></pre>
            <p>Then in a nutshell: loop through one half of ports in our range (all even or all odd ports) before looping through the other half of ports (all odd or all even ports respectively) for each connection. Specifically, this is a variation of the <a href="https://datatracker.ietf.org/doc/html/rfc6056#section-3.3.4">Double-Hash Port Selection Algorithm</a>. We will ignore the bind bucket functionality since that is not our main concern.</p><p>Depending on your port range, you either start with an even port or an odd port. In our case, our low port, 9024, is even. Then the port is picked by adding the offset to the low port:</p><p><a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/inet_hashtables.c#L1045">net/ipv4/inet_hashtables.c</a></p>
            <pre><code>port = low + offset;</code></pre>
            <p>If low was odd, we will have an odd starting port because odd + even = odd.</p><p>There is a bit too much going on in the loop to explain in text. I have an example instead:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6uVqtAUR07epRRKqQbHWkp/2a5671b1dd3c68c012e7171b8103a53e/image5.png" />
            
            </figure><p>This example is bound by 8 ports and 8 possible connections. All ports start unused. As a port is used up, the port is grayed out. Green boxes represent the next chosen port. All other colors represent open ports. Blue arrows are even port iterations of offset, and red are the odd port iterations of offset. Note that the offset is randomly picked, and once we cross over to the odd range, the offset is incremented by one.</p><p>For each selection of a port, the algorithm then makes a call to the function <code>check_established()</code> which dereferences <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/inet_hashtables.c#L544"><code>__inet_check_established()</code></a>. This function loops over sockets to verify that the TCP 4-tuple is unique. The takeaway is that the socket list in the function is usually smaller than not. This grows as more unique TCP 4-tuples are introduced to the system. Longer socket lists may slow down port selection eventually. We have a blog post on <a href="/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/">ephemeral port exhausting</a> that dives into the socket list and port uniqueness criteria.</p><p>At this point, we can summarize that the odd/even port split is what is causing our performance bottleneck. And during the investigation, it was not obvious to me (or even maybe you) why the offset was initially calculated the way it was, and why the odd/even port split was introduced. After some git-archaeology the decisions become more clear.</p>
    <div>
      <h3>Security considerations</h3>
      <a href="#security-considerations">
        
      </a>
    </div>
    <p>Port selection has been shown to be used in device <a href="https://lwn.net/Articles/910435/">fingerprinting</a> in the past. This led the authors to introduce more randomization into the initial port selection. Prior, ports were predictably picked solely based on their initial hash and a salt value which does not change often. This helps with explaining the offset, but does not explain the split.</p>
    <div>
      <h3>Why the even/odd split?</h3>
      <a href="#why-the-even-odd-split">
        
      </a>
    </div>
    <p>Prior to this <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=07f4c90062f8fc7c8c26f8f95324cbe8fa3145a5">patch</a> and that <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1580ab63fc9a03593072cc5656167a75c4f1d173">patch</a>, services may have conflicts between the connect() and bind() heavy workloads. Thus, to avoid those conflicts, the split was added. An even offset was chosen for the connect() workloads, and an odd offset for the bind() workloads. However, we can see that the split works great for connect() workloads that do not exceed one half of the allotted port range.</p><p>Now we have an explanation for the flame graph and charts. So what can we do about this?</p>
    <div>
      <h2>User space solution (kernel &lt; 6.8)</h2>
      <a href="#user-space-solution-kernel-6-8">
        
      </a>
    </div>
    <p>We have a couple of strategies that would work best for us. Infrastructure or architectural strategies are not considered due to significant development effort. Instead, we prefer to tackle the problem where it occurs.</p><h3>Select, test, repeat<p>For the “select, test, repeat” approach, you may have code that ends up looking like this:</p>
            <pre><code>sys = get_ip_local_port_range()
estab = 0
i = sys.hi
while i &gt;= 0:
    if estab &gt;= sys.hi:
        break

    random_port = random.randint(sys.lo, sys.hi)
    connection = attempt_connect(random_port)
    if connection is None:
        i += 1
        continue

    i -= 1
    estab += 1</code></pre>
            <p>The algorithm simply loops through the system port range, and randomly picks a port each iteration. Then test that the connect() worked. If not, rinse and repeat until range exhaustion.</p><p>This approach is good for up to ~70-80% port range utilization. And this may take roughly eight to twelve attempts per connection as we approach exhaustion. The major downside to this approach is the extra syscall overhead on conflict. In order to reduce this overhead, we can consider another approach that allows the kernel to still select the port for us.</p><h3>Select port by random shifting range<p>This approach leverages the <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=91d0b78c5177f3e42a4d8738af8ac19c3a90d002"><code>IP_LOCAL_PORT_RANGE</code></a> socket option. And we were able to achieve performance like this:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/Uz8whp12VuvqvKTDnE1u9/4701177d739bdffe2a2399213cf72941/Screenshot-2024-02-07-at-16.00.22.png" />
            
            </figure><p>That is much better! The chart also introduces black dots that represent errored connections. However, they have a tendency to clump at the very end of our port range as we approach exhaustion. This is not dissimilar to what we may see in “<a href="#selecttestrepeat">select, test, repeat</a>”.</p><p>The way this solution works is something like:</p>
            <pre><code>IP_BIND_ADDRESS_NO_PORT = 24
IP_LOCAL_PORT_RANGE = 51
sys = get_local_port_range()
window.lo = 0
window.hi = 1000
range = window.hi - window.lo
offset = randint(sys.lo, sys.hi - range)
window.lo = offset
window.hi = offset + range

sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, 1)
range = pack("@I", window.lo | (window.hi &lt;&lt; 16))
sk.setsockopt(IPPROTO_IP, IP_LOCAL_PORT_RANGE, range)
sk.bind((src_ip, 0))
sk.connect((dest_ip, dest_port))</code></pre>
            <p>We first fetch the system's local port range, define a custom port range, and then randomly shift the custom range within the system range. Introducing this randomization helps the kernel to start port selection randomly at an odd or even port. Then reduces the loop search space down to the range of the custom window.</p><p>We tested with a few different window sizes, and determined that a five hundred or one thousand size works fairly well for our port range:</p>
<table>
<thead>
  <tr>
    <th><span>Window size</span></th>
    <th><span>Errors</span></th>
    <th><span>Total test time</span></th>
    <th><span>Connections/second</span></th>
  </tr>
</thead>
<tbody>
  <tr>
    <td><span>500</span></td>
    <td><span>868</span></td>
    <td><span>~1.8 seconds</span></td>
    <td><span>~30,139</span></td>
  </tr>
  <tr>
    <td><span>1,000</span></td>
    <td><span>1,129</span></td>
    <td><span>~2 seconds</span></td>
    <td><span>~27,260</span></td>
  </tr>
  <tr>
    <td><span>5,000</span></td>
    <td><span>4,037</span></td>
    <td><span>~6.7 seconds</span></td>
    <td><span>~8,405</span></td>
  </tr>
  <tr>
    <td><span>10,000</span></td>
    <td><span>6,695</span></td>
    <td><span>~17.7 seconds</span></td>
    <td><span>~3,183</span></td>
  </tr>
</tbody>
</table><p>As the window size increases, the error rate increases. That is because a larger window provides less random offset opportunity. A max window size of 56,512 is no different from using the kernels default behavior. Therefore, a smaller window size works better. But you do not want it to be too small either. A window size of one is no different from “<a href="#selecttestrepeat">select, test, repeat</a>”.</p><p>In kernels &gt;= 6.8, we can do even better.</p><h2>Kernel solution (kernel &gt;= 6.8)</h2><p>A new <a href="https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=207184853dbd">patch</a> was introduced that eliminates the need for the window shifting. This solution is going to be available in the 6.8 kernel.</p><p>Instead of picking a random window offset for <code>setsockopt(IPPROTO_IP, IP_LOCAL_PORT_RANGE</code>, …), like in the previous solution, we instead just pass the full system port range to activate the solution. The code may look something like this:</p>
            <pre><code>IP_BIND_ADDRESS_NO_PORT = 24
IP_LOCAL_PORT_RANGE = 51
sys = get_local_port_range()
sk = socket(AF_INET, SOCK_STREAM)
sk.setsockopt(IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, 1)
range = pack("@I", sys.lo | (sys.hi &lt;&lt; 16))
sk.setsockopt(IPPROTO_IP, IP_LOCAL_PORT_RANGE, range)
sk.bind((src_ip, 0))
sk.connect((dest_ip, dest_port))</code></pre>
            <p>Setting <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=91d0b78c5177f3e42a4d8738af8ac19c3a90d002"><code>IP_LOCAL_PORT_RANGE</code></a> option is what tells the kernel to use a similar approach to “<a href="#random">select port by random shifting range</a>” such that the start offset is randomized to be even or odd, but then loops incrementally rather than skipping every other port. We end up with results like this:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ttWStZgNYfwftr71r8Vrt/7c333411ef01b674cc839f27ae4cbbbf/Screenshot-2024-02-07-at-16.04.24.png" />
            
            </figure><p>The performance of this approach is quite comparable to our user space implementation. Albeit, a little faster. Due in part to general improvements, and that the algorithm can always find a port given the full search space of the range. Then there are no cycles wasted on a potentially filled sub-range.</p><p>These results are great for TCP, but what about other protocols?</p>
    <div>
      <h2>Other protocols &amp; connect()</h2>
      <a href="#other-protocols-connect">
        
      </a>
    </div>
    <p>It is worth mentioning at this point that the algorithms used for the protocols are <i>mostly</i> the same for IPv4 &amp; IPv6. Typically, the key difference is how the sockets are compared to determine uniqueness and where the port search happens. We did not compare performance for all protocols. But it is worth mentioning some similarities and differences with TCP and a couple of others.</p>
    <div>
      <h3>DCCP</h3>
      <a href="#dccp">
        
      </a>
    </div>
    <p>The DCCP protocol leverages the same port selection <a href="https://elixir.bootlin.com/linux/v6.6/source/net/dccp/ipv4.c#L115">algorithm</a> as TCP. Therefore, this protocol benefits from the recent kernel changes. It is also possible the protocol could benefit from our user space solution, but that is untested. We will let the reader exercise DCCP use-cases.</p>
    <div>
      <h3>UDP &amp; UDP-Lite</h3>
      <a href="#udp-udp-lite">
        
      </a>
    </div>
    <p><a href="https://www.cloudflare.com/learning/ddos/glossary/user-datagram-protocol-udp/">UDP</a> leverages a different algorithm found in the function <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/udp.c#L239"><code>udp_lib_get_port()</code></a>. Similar to TCP, the algorithm will loop over the whole port range space incrementally. This is only the case if the port is not already supplied in the bind() call. The key difference between UDP and TCP is that a random number is generated as a step variable. Then, once a first port is identified, the algorithm loops on that port with the random number. This relies on an uint16_t overflow to eventually loop back to the chosen port. If all ports are used, increment the port by one and repeat. There is no port splitting between even and odd ports.</p><p>The best comparison to the TCP measurements is a UDP setup similar to:</p>
            <pre><code>sk = socket(AF_INET, SOCK_DGRAM)
sk.bind((src_ip, 0))
sk.connect((dest_ip, dest_port))</code></pre>
            <p>And the results should be unsurprising with one IPv4 source address:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4UM5d0RBTgqADgVLbbqMlQ/940306c90767ba4b5e3762c6467b71ed/Screenshot-2024-02-07-at-16.06.27.png" />
            
            </figure><p>UDP fundamentally behaves differently from TCP. And there is less work overall for port lookups. The outliers in the chart represent a worst-case scenario when we reach a fairly bad random number collision. In that case, we need to more-completely loop over the ephemeral range to find a port.</p><p>UDP has another problem. Given the socket option <code>SO_REUSEADDR</code>, the port you get back may conflict with another UDP socket. This is in part due to the function <a href="https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/udp.c#L141"><code>udp_lib_lport_inuse()</code></a> ignoring the UDP 2-tuple (src ip, src port) check given the socket option. When this happens you may have a new socket that overwrites a previous. Extra care is needed in that case. We wrote more in depth about these cases in a previous <a href="/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/">blog post</a>.</p>
    <div>
      <h2>In summary</h2>
      <a href="#in-summary">
        
      </a>
    </div>
    <p>Cloudflare can make a lot of unicast egress connections to origin servers with popular uncached assets. To avoid port-resource exhaustion, we balance the load over a couple of IPv4 source addresses during those peak times. Then we asked: “what is the performance impact of one IPv4 source address for our connect()-heavy workloads?”. Port selection is not only difficult to get right, but is also a performance bottleneck. This is evidenced by measuring connect() latency with a flame graph and synthetic workloads. That then led us to discovering TCP’s quirky port selection process that loops over half your ephemeral ports before the other for each connect().</p><p>We then proposed three solutions to solve the problem outside of adding more IP addresses or other architectural changes: “<a href="#selecttestrepeat">select, test, repeat</a>”, “<a href="#random">select port by random shifting range</a>”, and an <a href="https://man7.org/linux/man-pages/man7/ip.7.html"><code>IP_LOCAL_PORT_RANGE</code></a> socket option <a href="#kernel">solution</a> in newer kernels. And finally closed out with other protocol honorable mentions and their quirks.</p><p>Do not take our numbers! Please explore and measure your own systems. With a better understanding of your workloads, you can make a good decision on which strategy works best for your needs. Even better if you come up with your own strategy!</p></h3></h3> ]]></content:encoded>
            <category><![CDATA[Linux]]></category>
            <category><![CDATA[Protocols]]></category>
            <category><![CDATA[Performance]]></category>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[Network]]></category>
            <guid isPermaLink="false">1C6z0btasEsz1cmdmoug0m</guid>
            <dc:creator>Frederick Lawler</dc:creator>
        </item>
        <item>
            <title><![CDATA[Using DNS to estimate the worldwide state of IPv6 adoption]]></title>
            <link>https://blog.cloudflare.com/ipv6-from-dns-pov/</link>
            <pubDate>Thu, 14 Dec 2023 15:05:52 GMT</pubDate>
            <description><![CDATA[ In the last decade, IPv6 adoption on the client side went from under 1% to somewhere in the high 30 to low 40 percent, depending on who’s reporting, but there’s also the other end of the equation: the server side ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7lHuJcdFLT7jwhT2jjmVcF/997e67f3e714f3019d109c7c97c85ea7/image2-3.png" />
            
            </figure><p>In order for one device to talk to other devices on the Internet using the aptly named <a href="https://en.wikipedia.org/wiki/Internet_Protocol">Internet Protocol</a> (IP), it must first be assigned a unique numerical address. What this address looks like depends on the version of IP being used: <a href="https://en.wikipedia.org/wiki/Internet_Protocol_version_4">IPv4</a> or <a href="https://en.wikipedia.org/wiki/IPv6">IPv6</a>.</p><p>IPv4 was first deployed in 1983. It’s the IP version that gave birth to the modern Internet and still remains dominant today. IPv6 can be traced back to as early as 1998, but only in the last decade did it start to gain significant traction — rising from less than 1% to somewhere between 30 and 40%, depending on who’s reporting and what and how they’re measuring.</p><p>With the growth in connected devices far exceeding the number of IPv4 addresses available, <a href="/amazon-2bn-ipv4-tax-how-avoid-paying/">and its costs rising</a>, the much larger address space provided by IPv6 should have made it the dominant protocol by now. However, as we’ll see, this is not the case.</p><p>Cloudflare has been a strong advocate of IPv6 <a href="https://www.cloudflare.com/press-releases/2011/cloudflare-announces-the-automatic-ipv6-gateway/">for many years</a> and, through <a href="https://radar.cloudflare.com/">Cloudflare Radar</a>, we’ve been closely following IPv6 adoption across the Internet. At three years old, Radar is still a relatively recent platform. To go further back in time, we can briefly turn to our friends at <a href="https://stats.labs.apnic.net/ipv6/XA">APNIC</a><sup>1</sup> — one of the five Regional Internet Registries (<a href="https://en.wikipedia.org/wiki/Regional_Internet_registry">RIRs</a>). Through their data, going back to 2012, we can see that IPv6 experienced a period of seemingly exponential growth until mid-2017, after which it entered a period of linear growth that’s still ongoing:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/37xEnfcqqKABkXWhnETnXK/30e3c5afa1d14896deb307d028785913/pasted-image-0--7--2.png" />
            
            </figure><p>IPv6 adoption is slowed down by the lack of compatibility between both protocols — devices must be assigned both an IPv4 <i>and</i> an IPv6 address — along with the fact that virtually all devices on the Internet still support IPv4. Nevertheless, IPv6 is critical for the future of the Internet, and continued effort is required to increase its deployment.</p><p>Cloudflare Radar, like APNIC and most other sources today, publishes numbers that primarily reflect the extent to which Internet Service Providers (ISPs) have deployed IPv6: the <i>client side</i>. It’s a very important angle, and one that directly impacts end users, but there’s also the other end of the equation: the <i>server side</i>.</p><p>With this in mind, we invite you to follow us on a quick experiment where we aim for a glimpse of server side IPv6 adoption, and how often clients are actually (or likely) able to talk to servers over IPv6. We’ll rely on DNS for this exploration and, as they say, the results may surprise you.</p>
    <div>
      <h3>IPv6 Adoption on the Client Side (from HTTP)</h3>
      <a href="#ipv6-adoption-on-the-client-side-from-http">
        
      </a>
    </div>
    <p>By the end of October 2023, from Cloudflare’s <a href="https://radar.cloudflare.com/adoption-and-usage?dateStart=2023-08-01&amp;dateEnd=2023-10-31">perspective</a>, IPv6 adoption across the Internet was at roughly <b>36%</b> of all traffic, with slight variations depending on the time of day and day of week. When excluding bots the estimate goes up to just over 46%, while excluding humans pushes it down close to 24%. These numbers refer to the share of HTTP requests served over IPv6 <a href="https://developers.cloudflare.com/radar/glossary/#ipv6-adoption">across all IPv6-enabled content</a> (the default setting).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/VZUSDQeWI7eZ8TQheZ6lP/7ef2aac52c4fd62912f8d83f45fa6f7f/pasted-image-0-2.png" />
            
            </figure><p>For this exercise, what matters most is the number for both humans <i>and</i> bots. There are many reasons for the adoption gap between both kinds of traffic — from varying levels of IPv6 support in the plethora of client software used, to varying levels of IPv6 deployment inside the many networks where traffic comes from, to the varying size of such networks, etc. — but that’s a rabbit hole for another day. If you’re curious about the numbers for a particular country or network, you can find them on <a href="https://radar.cloudflare.com/adoption-and-usage/">Cloudflare Radar</a> and in our <a href="https://radar.cloudflare.com/year-in-review/2023#ipv6-adoption">Year in Review</a> report for 2023.</p>
    <div>
      <h3>It Takes Two to Dance</h3>
      <a href="#it-takes-two-to-dance">
        
      </a>
    </div>
    <p>You, the reader, might point out that measuring the client side of the client-server equation only tells half the story: for an IPv6-capable client to establish a connection with a server via IPv6, the server must also be IPv6-capable.</p><p>This raises two questions:</p><ol><li><p>What’s the extent of IPv6 adoption on the server side?</p></li><li><p>How well does IPv6 adoption on the client side align with adoption on the server side?</p></li></ol><p>There are several possible answers, depending on whether we’re talking about users, devices, bytes transferred, and so on. We’ll focus on <i>connections</i> (it will become clear why in a moment), and the combined question we’re asking is:</p><blockquote><p><i>How often can an IPv6-capable client use IPv6 when connecting to servers on the Internet, under typical usage patterns?</i></p></blockquote><p>Typical usage patterns include people going about their day visiting some websites more often than others or automated clients calling APIs. We’ll turn to DNS to get this perspective.</p>
    <div>
      <h3>Enter DNS</h3>
      <a href="#enter-dns">
        
      </a>
    </div>
    <p>Before a client can attempt to establish a connection with a server by name, using either the classic IPv4 protocol or the more modern IPv6, it must look up the server’s IP address in the <a href="https://en.wikipedia.org/wiki/Telephone_directory">phonebook</a> of the Internet, the <a href="https://www.cloudflare.com/learning/dns/what-is-dns/">Domain Name System (DNS)</a>.</p><p>Looking up a hostname in DNS <a href="https://www.cloudflare.com/learning/dns/what-is-dns/">is a recursive process</a>. To find the IP address of a server, the domain hierarchy (the dot-separated components of a server’s name) must be followed across several DNS authoritative servers until one of them returns the desired response<sup>2</sup>. Most clients, however, don’t do this directly and instead ask an intermediary server called a <a href="https://www.cloudflare.com/learning/dns/what-is-recursive-dns/">recursive resolver</a> to do it for them. Cloudflare operates one such recursive resolver that anyone can use: <a href="https://one.one.one.one/dns/">1.1.1.1</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7osVQH3ASy6i4puJ0UBUJc/192ecf4472c1917ff7ed4273df0bd0c1/pasted-image-0--1--2.png" />
            
            </figure><p>As a simplified example, when a client asks 1.1.1.1 for the IP address where “<a href="http://www.example.com”">www.example.com”</a> lives, 1.1.1.1 will go out and ask the DNS root servers<sup>3</sup> about “.com”, then ask the .com DNS servers about “example.com”, and finally ask the example.com DNS servers about “www.example.com”, which has direct knowledge of it and answers with an IP address. To make things faster for the next client asking a similar question, 1.1.1.1 caches (remembers for a while) both the final answer and the steps in between.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4jugLCRvQVB2NUC0i3qMY/8b12ffa0a9eddb76ba40dbf7051c76c7/pasted-image-0--2--3.png" />
            
            </figure><p>This means 1.1.1.1 is in a very good position to count how often clients try to look up IPv4 addresses (A-type queries) <i>vs.</i> how often they try to look up IPv6 addresses (AAAA-type queries), covering most of the observable Internet.</p><p>But how does a client know when to ask for a server’s IPv4 address or its IPv6 address?</p><p>The short answer is that clients with IPv6 available to them just ask for both — doing separate <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-a-record/">A</a> and <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-aaaa-record/">AAAA</a> lookups for every server they wish to connect to. These IPv6-capable clients will prioritize connecting over IPv6 when they get a non-empty AAAA answer, whether they also get a non-empty A answer (which they almost always get, as we’ll see). The algorithm driving this preference for modernity is called <a href="https://en.wikipedia.org/wiki/Happy_Eyeballs">Happy Eyeballs</a>, if you’re interested in the details.</p><p>We’re now ready to start looking at some actual data…</p>
    <div>
      <h3>IPv6 Adoption on the Client Side (from DNS)</h3>
      <a href="#ipv6-adoption-on-the-client-side-from-dns">
        
      </a>
    </div>
    <p>The first step is establishing a baseline by measuring client IPv6 deployment from 1.1.1.1’s perspective and comparing it with the numbers from HTTP requests that we started with.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/MDeID398Kzy28RT52PMFH/a2553d58d669cbd46f284ca909620c4b/pasted-image-0--3--2.png" />
            
            </figure><p>It’s tempting to count how often clients connect to 1.1.1.1 using IPv6, but the results are misleading for a couple of reasons, the strongest one being hidden in plain sight: 1.1.1.1 is the most memorable <b>address</b> of the set of IPv4 and IPv6 addresses that clients can use to perform DNS lookups through the 1.1.1.1 <b>service</b>. Ideally, IPv6-capable clients using 1.1.1.1 as their recursive resolver should have all four of the following IP addresses configured, not just the first two:</p><ul><li><p><b>1.1.1.1</b> (IPv4)</p></li><li><p><b>1.0.0.1</b> (IPv4)</p></li><li><p><b>2606:4700:4700::1111</b> (IPv6)</p></li><li><p><b>2606:4700:4700::1001</b> (IPv6)</p></li></ul><p>But, when manual configuration is involved4, humans find IPv6 addresses less memorable than IPv4 addresses and are less likely to configure them, viewing the IPv4 addresses as enough.</p><p>A related, but less obvious, confounding factor is that many IPv6-capable clients will still perform DNS lookups over IPv4 even when they have 1.1.1.1’s IPv6 addresses configured, as spreading lookups over the available addresses is a popular default option.</p><p>A more sensible approach to assess IPv6 adoption from DNS client activity is calculating the percentage of AAAA-type queries over the total amount of A-type queries, assuming IPv6-clients always perform both<sup>5</sup>, as mentioned earlier.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ShMNUPncOEfKH8OCGoaKI/96c261719b4916f8fac67e7ce1015673/pasted-image-0--4--2.png" />
            
            </figure><p>Then, from 1.1.1.1’s perspective, IPv6 adoption on the <b>client side</b> is estimated at <b>30.5%</b> by query volume. This is a bit under what we observed from HTTP traffic over the same time period (35.9%) but such a difference between two different perspectives is not unexpected.</p>
    <div>
      <h3>A Note on TTLs</h3>
      <a href="#a-note-on-ttls">
        
      </a>
    </div>
    <p>It’s not only recursive resolvers that cache DNS responses, most DNS clients have their own local caches as well. Your web browser, operating system, and even your home router, keep answers around hoping to speed up subsequent queries.</p><p>How long each answer remains in cache depends on the <a href="https://developers.cloudflare.com/dns/manage-dns-records/reference/ttl/">time-to-live</a> (TTL) field sent back with DNS records. If you’re familiar with DNS, you might be wondering if A and AAAA records have similar TTLs. If they don’t, we may be getting fewer queries for just one of these two types (because it gets cached for longer at the client level), biasing the resulting adoption figures.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3qY93uvMa7SIV80OxTPBVS/db694e99691dfa04825897c69f6f3f14/pasted-image-0--5--2.png" />
            
            </figure><p>The pie charts here break down the minimum TTLs sent back by 1.1.1.1 in response to A and AAAA queries<sup>6</sup>. There is some difference between both types, but the difference is very small.</p>
    <div>
      <h3>IPv6 Adoption on the Server Side</h3>
      <a href="#ipv6-adoption-on-the-server-side">
        
      </a>
    </div>
    <p>The following graph shows how often A and AAAA-type queries get non-empty responses, shedding light on <b>server side</b> IPv6 adoption and getting us closer to the answer we’re after:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3aYzrPLYLFqxH9ublQtOCm/045cf3e5a35bc208775fd531466234e6/pasted-image-0--6--2.png" />
            
            </figure><p>IPv6 adoption by servers is estimated at <b>43.3%</b> by query volume, noticeably higher than what was observed for clients.</p>
    <div>
      <h3>How Often Both Sides Swipe Right</h3>
      <a href="#how-often-both-sides-swipe-right">
        
      </a>
    </div>
    <p>If 30.5% of IP address lookups handled by 1.1.1.1 could make use of an IPv6 address to connect to their intended destinations, but only 43.3% of those lookups get a non-empty response, that can give us a pretty good basis for how often IPv6 connections are made between client and server — roughly <b>13.2%</b> of the time.</p>
    <div>
      <h3>The Potential Impact of Popular Domains</h3>
      <a href="#the-potential-impact-of-popular-domains">
        
      </a>
    </div>
    <p>IPv6 server side adoption measured by query volume for the domains in Radar’s <a href="https://radar.cloudflare.com/domains">Top 100</a> list is 60.8%. If we exclude these domains from our overall calculations, the previous 13.2% figure drops to 8%. This is a significant difference, but not unexpected, as the Top 100 domains make up over 55% of all A and AAAA queries to 1.1.1.1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6cJtOVRwoLQluKLLd0QVzv/38e0caab4e079e60a9b41f4b8a80e78e/pasted-image-0--8--2.png" />
            
            </figure><p>If just a few more of these highly popular domains were to deploy IPv6 today, observed adoption would noticeably increase and, with it, the chance of IPv6-capable clients establishing connections using IPv6.</p>
    <div>
      <h3>Closing Thoughts</h3>
      <a href="#closing-thoughts">
        
      </a>
    </div>
    <p>Observing the extent of IPv6 adoption across the Internet can mean different things:</p><ul><li><p>Counting <b>users</b> with IPv6-capable Internet access;</p></li><li><p>Counting IPv6-capable <b>devices</b> or software on those devices (clients and/or servers);</p></li><li><p>Calculating the amount of <b>traffic</b> flowing through IPv6 connections, measured in bytes;</p></li><li><p>Counting the fraction of <b>connections</b> (or individual <b>requests</b>) over IPv6.</p></li></ul><p>In this exercise we chose to look at connections and requests. Keeping in mind that the underlying reality can only be truly understood by considering several different perspectives, we saw three different IPv6 adoption figures:</p><ul><li><p><b>35.9%</b> (client side) when counting HTTP requests served from Cloudflare's CDN;</p></li><li><p><b>30.5%</b> (client side) when counting A and AAAA-type DNS queries handled by <a href="https://one.one.one.one/dns/">1.1.1.1</a>;</p></li><li><p><b>43.3%</b> (server side) of positive responses to AAAA-type DNS queries, also from 1.1.1.1.</p></li></ul><p>We combined the <i>client side</i> and <i>server side</i> figures from the DNS perspective to estimate how often connections to third-party servers are likely to be established over IPv6 rather than IPv4: just <b>13.2%</b> of the time.</p><p>To improve on these numbers, ISPs, cloud and hosting providers, and corporations alike must increase the rate at which they make IPv6 available for devices in their networks. But large websites and content sources also have a critical role to play in enabling IPv6-capable clients to use IPv6 more often, as <b>39.2%</b> of queries for domains in the Radar <a href="https://radar.cloudflare.com/domains">Top 100</a> (representing over half of all A and AAAA queries to 1.1.1.1) are still limited to IPv4-only responses.</p><p>On the road to full IPv6 adoption, the Internet isn’t quite there yet. But continued effort from all those involved can help it to continue to move forward, and perhaps even accelerate progress.</p><p><i>On the server side, Cloudflare has been helping with this worldwide effort for many years by providing free </i><a href="https://developers.cloudflare.com/support/network/understanding-and-configuring-cloudflares-ipv6-support/"><i>IPv6 support</i></a><i> for all domains. On the client side, the </i><a href="https://1.1.1.1/"><i>1.1.1.1 app</i></a><i> automatically enables your device for IPv6 even if your ISP doesn’t provide any IPv6 support. And, if you happen to manage an IPv6-only network, 1.1.1.1’s </i><a href="https://developers.cloudflare.com/1.1.1.1/infrastructure/ipv6-networks/"><i>DNS64 support</i></a><i> also has you covered.</i></p><p>***</p><p><sup>1</sup>Cloudflare’s public DNS resolver (1.1.1.1) is operated in partnership with APNIC. You can read more about it in the original <a href="/dns-resolver-1-1-1-1/">announcement blog post</a> and in 1.1.1.1’s <a href="https://developers.cloudflare.com/1.1.1.1/privacy/public-dns-resolver/">privacy policy</a>.</p><p><sup>2</sup>There’s more information on how DNS works in the “<a href="https://www.cloudflare.com/learning/dns/what-is-dns/">What is DNS?</a>” section of our website. If you’re a hands-on learner, we suggest you take a look at Julia Evans’ “<a href="https://messwithdns.net/">mess with dns</a>”.</p><p><sup>3</sup>Any recursive resolver will already know the IP addresses of the <a href="https://www.iana.org/domains/root/servers">13 root servers</a> beforehand. Cloudflare also participates at the topmost level of DNS by <a href="/f-root/">providing anycast service to the E and F-Root instances</a>, which means 1.1.1.1 doesn’t need to go far for that first lookup step.</p><p><sup>4</sup>When using the <a href="https://one.one.one.one/">1.1.1.1 app</a>, all four IP addresses are configured automatically.</p><p><sup>5</sup>For simplification, we assume the amount of IPv6-only clients is still negligibly small. It’s a reasonable assumption in general, and other datasets available to us confirm it.</p><p><sup>6</sup>1.1.1.1, like other recursive resolvers, returns adjusted TTLs: the record’s original TTL minus the number of seconds since the record was last cached. Empty A and AAAA answers get cached for the amount of time defined in the domain’s <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-soa-record/">Start of Authority</a> (SOA) record, as specified by RFC 2308.</p> ]]></content:encoded>
            <category><![CDATA[Radar]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[DNS]]></category>
            <guid isPermaLink="false">59O01jCNT1TaLCjWJaDu5m</guid>
            <dc:creator>Carlos Rodrigues</dc:creator>
        </item>
        <item>
            <title><![CDATA[Amazon’s $2bn IPv4 tax — and how you can avoid paying it]]></title>
            <link>https://blog.cloudflare.com/amazon-2bn-ipv4-tax-how-avoid-paying/</link>
            <pubDate>Tue, 26 Sep 2023 13:02:00 GMT</pubDate>
            <description><![CDATA[ In this blog, we’ll explain a little bit more about the technology involved, but most importantly, give you a step-by-step walkthrough of how Cloudflare can help you eliminate the need to pay Amazon for something that they shouldn’t be charging you for in the first place ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5XAwhvgK5l02B9TAvUiy9d/8aed64f222f749b8bc6515e421c624d8/image7-11.png" />
            
            </figure><p>One of the wonderful things about the Internet is that, whether as a consumer or producer, the cost has continued to come down. Back in the day, it used to be that you needed a server room, a whole host of hardware, and an army of folks to help keep everything up and running. The cloud changed that, but even with that shift, services like <a href="https://www.cloudflare.com/application-services/products/ssl/">SSL</a> or unmetered <a href="https://www.cloudflare.com/ddos/">DDoS protection</a> were out of reach for many. We think that the march towards a more accessible Internet — both through ease of use, and reduced cost — is a wonderful thing, and we’re proud to have played a part in making it happen.</p><p>Every now and then, however, the march of progress gets interrupted.</p><p>On July 28, 2023, Amazon Web Services (AWS) announced that they would begin to charge “per IP per hour for all public IPv4 addresses, whether attached to a service or not”, starting February 1, 2024. This change will add at least \$43 extra per year for every IPv4 address Amazon customers use; this may not sound like much, but we’ve seen back of the napkin analysis <a href="https://www.linkedin.com/posts/atoonk_new-aws-public-ipv4-address-charge-public-activity-7091779585368862720-x0zw/">that suggests</a> this will result in an approximately \$2bn tax on the Internet.</p><p>In this blog, we’ll explain a little bit more about the technology involved, but most importantly, give you a step-by-step walkthrough of how Cloudflare can help you not only eliminate the need to pay Amazon for something that they shouldn’t be charging you for in the first place, but also if you’re a Pro or Business subscriber, we want to put \$43 in your pocket instead of taking it out. Don’t give Amazon \$43 for IPv4, let us give you \$43 and throw in IPv4 as well.</p>
    <div>
      <h3><b>How can Cloudflare help avoid AWS IPv4 charges?</b></h3>
      <a href="#how-can-cloudflare-help-avoid-aws-ipv4-charges">
        
      </a>
    </div>
    <p>The only way to avoid Amazon’s IPv4 tax is to transition to IPv6 with AWS. But we recognize that not everyone is ready to make that shift — it can be an expensive and challenging process, and may present problems with hardware compatibility and network performance. We cover the finer details of these challenges below, so keep reading! Cloudflare can help ease this transition: let us deal with communicating to AWS using IPv6. Not only that, you’ll get all the rest of the benefits of using Cloudflare and our global network — including all the <a href="https://www.cloudflare.com/learning/performance/speed-up-a-website/">performance</a> and security that Cloudflare is known for — and a \$43 dollar credit for using us!</p><p>IPv6 services like these are something we’ve been offering at Cloudflare for years - in fact this was first announced during Cloudflare's first birthday week in 2011! We’ve made this process simple to enable as well, so you can set this up as soon as today.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1UYTukqpByLSMhpLwk7rQK/c47a8e37780e14ab2a26353f10bbf12d/image6-2.png" />
            
            </figure><p>To set this feature up you will need to both enable IPv6 Compatibility and set up your origin for <a href="https://docs.aws.amazon.com/vpc/latest/userguide/aws-ipv6-support.html">AWS to be an IPv6 origin</a>.</p><p>To configure this feature simply follow these steps:</p><p>1. Login to your Cloudflare account.</p><p>2. Select the appropriate domain</p><p>3. Click the Network app.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/66Te3OO0yjDXrPqmF4YVYq/5ad20b6f21de07cb239ea2ce16185727/Screenshot-2023-09-25-at-17.01.11.png" />
            
            </figure><p>4. Make sure IPv6 Compatibility is toggled on.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/62DVRA42xpR7KkUFPEqrKt/058d64e5e67472b89732dff7c7debe4b/Screenshot-2023-09-25-at-17.01.24.png" />
            
            </figure><p>To get an IPv6 origin from Amazon you will likely have to follow these steps:</p><ol><li><p>Associate an IPv6 CIDR block with your VPC and subnets</p></li><li><p>Update your route tables</p></li><li><p>Update your security group rules</p></li><li><p>Change your instance type</p></li><li><p>Assign IPv6 addresses to your instances</p></li><li><p>(Optional) Configure IPv6 on your instances</p></li></ol><p>(For more information about this migration, check out <a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6.html#vpc-migrate-ipv6-example">this link</a>.)</p><p>Once you have your IPv6 origins, you’ll want to update your origins on Cloudflare to use the IPv6 addresses. In the simple example of a single origin at root, this is done by creating a proxied (orange-cloud) <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-aaaa-record/">AAAA record</a> in your Cloudflare DNS editor:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6JN8TolCbQmiAUnzrDhnAX/4e3d75ce7cef9536290118c6344a125b/image2-8.png" />
            
            </figure><p>If you are using <a href="https://www.cloudflare.com/application-services/products/load-balancing/">Load Balancers</a>, you will want to <a href="https://developers.cloudflare.com/load-balancing/how-to/create-pool/#edit-a-pool">update the origin(s)</a> there.</p><p>Once that’s done, you can remove the A/IPv4 record(s) and traffic will move over to the v6 address. While this process is easy now, we’re working on how we can make moving to IPv6 on Cloudflare even easier.</p><p>Once you have these features configured and have traffic running through Cloudflare to your origin for at least 6 months, you will be eligible to have a $43 credit deposited right into your Cloudflare account! You can use this credit for your Pro or Biz subscription or even for Workers and <a href="https://www.cloudflare.com/developer-platform/r2/">R2</a> usage. See <a href="https://www.cloudflare.com/lp/avoid-amazon-ipv4-tax/">here</a> for more information on how to opt in to this offer.</p><p>Through this feature Cloudflare provides the flexibility to manage your IPv6 settings as per your requirements. By leveraging Cloudflare's robust IPv6 support, you can ensure seamless connectivity for your users, while avoiding additional costs associated with public IPv4 addresses.</p>
    <div>
      <h3>What’s wrong with IPv4?</h3>
      <a href="#whats-wrong-with-ipv4">
        
      </a>
    </div>
    <p>So if Cloudflare has this solution, why should you even move to IPv6? Well to clearly explain this let's start with the problem with IPv4.</p><p><a href="https://www.cloudflare.com/learning/network-layer/internet-protocol/#:~:text=The%20Internet%20Protocol%20(IP)%20is,Network%20layer">IP addresses</a> are used to identify and reach resources on a network, which could be a private network, like your office's private network, or a complex public network like the Internet. An example of an IPv4 address would be 198.51.100.1 or 198.51.100.50. And there are approximately 4.3 billion unique IPv4 addresses like these for websites, servers, and other destinations on the Internet to use for routing.</p><p>4.3 billion IPv4 addresses may sound like a lot, but it’s not as IPv4 space is running out. In September 2015 ARIN, one of the regional Internet registries that allows people to acquire IP addresses, <a href="https://www.arin.net/resources/guide/ipv4/">announced</a> that they had no available space: if you want to buy an IPv4 address you have to go and talk to private companies who are selling them. These companies charge a pretty penny for their IPv4 addresses. It costs about <a href="https://auctions.ipv4.global/">$40 per IPv4 address today</a>. To buy a grouping of IPv4 addresses, also known as a prefix of which the minimum required size is 256 IP addresses, costs about \$10,000.</p><p>IP addresses are necessary for having a domain or device on the Internet, but today IPv4 addresses are an increasingly more complicated resource to acquire. Therefore, to facilitate the growth of the Internet there needed to be more unique addresses made available without breaking the bank. That’s where IPv6 comes in.</p>
    <div>
      <h3>IPv4 vs. IPv6</h3>
      <a href="#ipv4-vs-ipv6">
        
      </a>
    </div>
    <p>In 1995 the IETF (Internet Engineering Task Force) published the <a href="https://datatracker.ietf.org/doc/html/rfc1883">RFC</a> for IPv6, which proposed to solve this problem of the limited IPv4 space. Instead of 32 bits of addressable space, IPv6 expanded to 128 bits of addressable space. <b>This means that instead of 4.3 billion addresses available, there are approximately 340 undecillion IPv6 addresses available</b>. This is roughly equivalent to the number of grains of sand on Earth.</p><p>So this problem is solved, why should you care?  The answer is because many networks on the Internet still prefer IPv4, and companies like AWS are starting to charge money for IPv4 usage.</p><p>Let's speak on AWS first: AWS today owns one of the largest chunks of the IPv4 space. During a period of time when IPv4 addresses were on the private market to purchase for dollars per IP address, AWS chose to use its large capital to its advantage and buy up a large amount of the space. Today AWS owns 1.7% of the IPv4 address space which equates to <a href="https://toonk.io/aws-and-their-billions-in-ipv4-addresses/index.html">~100 million IPv4 addresses</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/toRGJVmQp33iZlby5l5vi/2528151de1f1655419f715594f0cb389/image1-11.png" />
            
            </figure><p>So you would think that moving to IPv6 is the right move, however, for the Internet community it’s proven to be quite a challenge.</p><p>When IPv6 was published in the 90s very few networks had devices that supported IPv6. However, today in 2023, that is not the case: global networks supporting IPv6 has <a href="https://pulse.internetsociety.org/technologies">increased to 46 percent</a>, so the hardware limitations around supporting it are decreasing. Additionally, anti-abuse and security tools initially had no idea how to deal with attacks or traffic that used IPv6 address space, and this still remains an issue for some of these tools. In 2014, we made it even easier for origin tools to convert by creating <a href="/eliminating-the-last-reasons-to-not-enable-ipv6/">pseudo IPv4</a> to help bridge the gap to those tools.</p><p>Despite all of this, many networks don’t have good support infrastructure for IPv6 networking since most networks were built on IPv4. At Cloudflare, we have built our network to support both protocols, known as “dual-stack”.</p><p>For a while there were also many networks which had markedly worse performance for IPv6 than IPv4. This is not true anymore, as of today we see only a slight degradation in IPv6 performance across the whole Internet compared to IPv4. The reasons for this include things like legacy hardware, sub-optimal IPv6 connectivity outside our network and high cost for deploying IPv6. You can see in the chart below the additional latency of IPv6 traffic on Cloudflare’s network as compared to IPv4 traffic:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1gD5CMwSwUA7X2OkYlrLsT/4716cb91db061e660ccbe3ea8c5b3aae/image5-5.png" />
            
            </figure><p>There were many challenges to adopting IPv6, and for some these issues with hardware compatibility and network performance are still worries. This is why still using IPv4 can be useful to folks while transitioning to IPv6, which is what makes AWS’ decision to charge for IPv4 impactful on many websites.</p>
    <div>
      <h3>So, don’t pay for AWS IPv4 charges</h3>
      <a href="#so-dont-pay-for-aws-ipv4-charges">
        
      </a>
    </div>
    <p>At the end of the day the choice is clear: you could pay Amazon more to rent their IPs than to buy them, or move to Cloudflare and use our free service to help with the transition to IPv6 with little overhead.</p> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <guid isPermaLink="false">6pnijheZgh5VXtQTUnLX9m</guid>
            <dc:creator>Anie Jacob</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare's handling of a bug in interpreting IPv4-mapped IPv6 addresses]]></title>
            <link>https://blog.cloudflare.com/cloudflare-handling-bug-interpreting-ipv4-mapped-ipv6-addresses/</link>
            <pubDate>Thu, 02 Feb 2023 13:32:00 GMT</pubDate>
            <description><![CDATA[ Recently, a vulnerability was reported to our bug bounty about a bug in the way some of our code interprets IPv4 addresses mapped into IPv6 addresses.  ]]></description>
            <content:encoded><![CDATA[ <p>In November 2022, our <a href="https://www.cloudflare.com/disclosure/">bug bounty program</a> received a critical and very interesting report. The report stated that certain types of DNS records could be used to bypass some of our network policies and connect to ports on the loopback address (e.g. 127.0.0.1) of our servers. This post will explain how we dealt with the report, how we fixed the bug, and the outcome of our internal investigation to see if the vulnerability had been previously exploited.</p><p><a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2-5-5">RFC 4291</a> defines ways to embed an IPv4 address into IPv6 addresses. One of the methods defined in the RFC is to use IPv4-mapped IPv6 addresses, that have the following format:</p>
            <pre><code>   |                80 bits               | 16 |      32 bits        |
   +--------------------------------------+--------------------------+
   |0000..............................0000|FFFF|    IPv4 address     |
   +--------------------------------------+----+---------------------+</code></pre>
            <p>In IPv6 notation, the corresponding mapping for <code>127.0.0.1</code> is <code>::ffff:127.0.0.1</code> (<a href="https://datatracker.ietf.org/doc/html/rfc4038">RFC 4038</a>)</p><p>The researcher was able to use DNS entries based on mapped addresses to bypass some of our controls and access ports on the loopback address or non-routable IPs.</p><p>This vulnerability was reported on November 27 to our bug bounty program. Our Security Incident Response Team (SIRT) was contacted, and incident response activities began shortly after the report was filed. A hotpatch was deployed three hours later to prevent exploitation of the bug.</p>
<table>
<thead>
  <tr>
    <th><span>Date</span></th>
    <th><span>Time (UTC)</span></th>
    <th><span>Activity</span></th>
  </tr>
</thead>
<tbody>
  <tr>
    <td><span>27 November 2022</span></td>
    <td><span>20:42</span></td>
    <td><span>Initial report to Cloudflare's bug bounty program</span></td>
  </tr>
  <tr>
    <td></td>
    <td><span>21:04</span></td>
    <td><span>SIRT oncall is paged</span></td>
  </tr>
  <tr>
    <td></td>
    <td><span>21:15</span></td>
    <td><span>SIRT manager on call starts working on the report</span></td>
  </tr>
  <tr>
    <td></td>
    <td><span>21:22</span></td>
    <td><span>Incident declared and team is assembled and debugging starts</span></td>
  </tr>
  <tr>
    <td></td>
    <td><span>23:20</span></td>
    <td><span>A hotfix is ready and deployment starts</span></td>
  </tr>
  <tr>
    <td></td>
    <td><span>23:47</span></td>
    <td><span>Team confirms that the hotfix is deployed and working</span></td>
  </tr>
  <tr>
    <td></td>
    <td><span>23:58</span></td>
    <td><span>Team investigates if other products are affected. Load Balancers and Spectrum are potential targets. Both products are found to be unaffected by the vulnerability.</span></td>
  </tr>
  <tr>
    <td><span>28 November 2022</span></td>
    <td><span>21:14</span></td>
    <td><span>A permanent fix is ready</span></td>
  </tr>
  <tr>
    <td><span>29 November 2022</span></td>
    <td><span>21:34</span></td>
    <td><span>Permanent fix is merged</span></td>
  </tr>
</tbody>
</table>
    <div>
      <h3>Blocking exploitation</h3>
      <a href="#blocking-exploitation">
        
      </a>
    </div>
    <p>Immediately after the vulnerability was reported to our Bug Bounty program, the team began working to understand the issue and find ways to quickly block potential exploitation. It was determined that the fastest way to prevent exploitation would be to block the creation of the DNS records required to execute the attack.</p><p>The team then began to implement a patch to prevent the creation of DNS records that include IPv6 addresses that map loopback or RFC 1918 (internal) IPv4 addresses. The fix was fully deployed and confirmed three hours after the report was filed. We later realized that this change was insufficient because records hosted on external DNS servers could also be used in this attack.</p>
    <div>
      <h3>The exploit</h3>
      <a href="#the-exploit">
        
      </a>
    </div>
    <p>The exploit provided consisted of the following: a DNS entry, and a Cloudflare Worker. The DNS entry was an <code>AAAA</code> record pointing to <code>::ffff:127.0.0.1:</code></p><p><code>exploit.example.com</code> <code>AAAA</code> <code>::ffff:127.0.0.1</code></p><p>The worker included the following code:</p>
            <pre><code>export default {
    async fetch(request) {
        const requestJson = await request.json()
        return fetch(requestJson.url, requestJson)
    }
}</code></pre>
            <p>The Worker was given a custom URL such as <code>proxy.example.com</code>.</p><p>With that setup, it was possible to make the worker attempt connections on the loopback interface of the server where it was running. The call would look like this:</p>
            <pre><code>curl https://proxy.example.com/json -d '{"url":"http://exploit.example.com:80/url_path"}'</code></pre>
            <p>The attack could then be scripted to attempt to connect to multiple ports on the server.</p><p>It was also found that a similar setup could be used with other IPv4 addresses to attempt connections into internal services. In this case, the DNS entry would look like:</p>
            <pre><code>exploit.example.com AAAA ::ffff:10.0.0.1</code></pre>
            <p>This exploit would allow an attacker to connect to services running on the loopback interface of the server. If the attacker was able to bypass the security and authentication mechanisms of a service, it could impact the confidentiality and integrity of data. For services running on other servers, the attacker could also use the worker to attempt connections and map services available over the network. As in most networks, Cloudflare's network policies and ACLs must allow a few ports to be accessible. These ports would be accessible by an attacker using this exploit.</p>
    <div>
      <h3>Investigation</h3>
      <a href="#investigation">
        
      </a>
    </div>
    <p>We started an investigation to understand the root cause of the problem and created a proof-of-concept that allowed the team to debug the issue. At the same time, we started a parallel investigation to determine if the issue had been previously exploited.</p><p>It all happened when two bugs collided.</p><p>The first bug happened in our internal DNS system which is responsible for mapping hostnames to IP addresses of our customers’ origin servers (the DNS system). When the DNS system tried to answer a query for the DNS record from exploit.example.com, it serialized the IP as a string. The <a href="https://pkg.go.dev/net#IP.String">Golang net library</a> used for DNS automatically converted the IP <code>::ffff:10.0.0.1</code> to string “10.0.0.1”. However, the DNS system still treated it as an IPv6 address. So a query response <code>{ipv6: “10.0.0.1”}</code> was returned.</p><p>The second bug was in our internal HTTP system (the proxy) which is responsible for forwarding HTTP traffic to customer’s origin servers. The bug happened in how the proxy validates this DNS response, <code>{ipv6: “10.0.0.1”}</code>. The proxy has two deny lists of IPs that are not allowed to be used, one for IPv4 and one for IPv6. These lists contain localhost IPs and private IPs. The bug was that the proxy system compared the address 10.0.0.1 against the IPv6 deny list because the address was in the “ipv6” section. Naturally the address didn’t match any entry in the deny list. So the address was allowed to be used as an origin IP address.</p><p>The second investigation team searched through the logs and found no evidence of previous exploitation of this vulnerability. The team also checked Cloudflare DNS for entries using IPv4-mapped IPv6 addresses and determined that all the existing entries had been used for testing purposes. As of now, there are no signs that this vulnerability could have been previously used against Cloudflare systems.</p>
    <div>
      <h3>Remediating the vulnerability</h3>
      <a href="#remediating-the-vulnerability">
        
      </a>
    </div>
    <p>To address this issue we implemented a fix in the proxy service to correctly use the deny list of the parsed address, not the deny list of the IP family the DNS API response claimed to be, to validate the IP address. We confirmed both in our test and production environments that the fix did prevent the issue from happening again.</p><p>Beyond maintaining a <a href="https://www.cloudflare.com/disclosure/">bug bounty program</a>, we regularly perform internal security reviews and hire third-party firms to audit the software we develop. But it is through our bug bounty program that we receive some of the most interesting and creative reports. Each report has helped us improve the security of our services. We invite those that find a security issue in any of Cloudflare’s services to report it to us through <a href="https://hackerone.com/cloudflare">HackerOne</a>.</p> ]]></content:encoded>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Bug Bounty]]></category>
            <category><![CDATA[IPv6]]></category>
            <guid isPermaLink="false">2moNY48YbcqIe8gCAZ6P6K</guid>
            <dc:creator>Lucas Ferreira</dc:creator>
            <dc:creator>Aki Shugaeva</dc:creator>
            <dc:creator>Yuchen Wu</dc:creator>
        </item>
        <item>
            <title><![CDATA[Building fast interpreters in Rust]]></title>
            <link>https://blog.cloudflare.com/building-fast-interpreters-in-rust/</link>
            <pubDate>Mon, 04 Mar 2019 16:00:00 GMT</pubDate>
            <description><![CDATA[ In the previous post we described the Firewall Rules architecture and how the different components are integrated together. We created a configurable Rust library for writing and executing Wireshark®-like filters in different parts of our stack written in Go, Lua, C, C++ and JavaScript Workers. ]]></description>
            <content:encoded><![CDATA[ <p>In the <a href="/how-we-made-firewall-rules/">previous post</a> we described the Firewall Rules architecture and how the different components are integrated together. We also mentioned that we created a configurable Rust library for writing and executing <a href="https://www.wireshark.org/">Wireshark</a>®-like filters in different parts of our stack written in Go, Lua, C, C++ and JavaScript Workers.</p><blockquote><p>With a mixed set of requirements of performance, memory safety, low memory use, and the capability to be part of other products that we’re working on like Spectrum, Rust stood out as the strongest option.</p></blockquote>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3emjeRzzAw9z6ipj1FIjoD/fbfb5538cf10d6a5f0c096676dabfa63/Langs.png" />
            
            </figure><p>We have now open-sourced this library under our Github account: <a href="https://github.com/cloudflare/wirefilter">https://github.com/cloudflare/wirefilter</a>. This post will dive into its design, explain why we didn’t use a parser generator and how our execution engine balances security, runtime performance and compilation cost for the generated filters.</p>
    <div>
      <h3>Parsing Wireshark syntax</h3>
      <a href="#parsing-wireshark-syntax">
        
      </a>
    </div>
    <p>When building a custom Domain Specific Language (DSL), the first thing we need to be able to do is parse it. This should result in an intermediate representation (usually called an Abstract Syntax Tree) that can be inspected, traversed, analysed and, potentially, serialised.</p><p>There are different ways to perform such conversion, such as:</p><ol><li><p>Manual char-by-char parsing using state machines, regular expression and/or native string APIs.</p></li><li><p>Parser combinators, which use higher-level functions to combine different parsers together (in Rust-land these are represented by <a href="https://github.com/Geal/nom">nom</a>, <a href="https://github.com/m4rw3r/chomp">chomp</a>, <a href="https://github.com/Marwes/combine">combine</a> and <a href="https://crates.io/keywords/parser-combinators">others</a>).</p></li><li><p>Fully automated generators which, provided with a grammar, can generate a fully working parser for you (examples are <a href="https://github.com/kevinmehall/rust-peg">peg</a>, <a href="https://github.com/pest-parser/pest">pest</a>, <a href="https://github.com/lalrpop/lalrpop">LALRPOP</a>, etc.).</p></li></ol>
    <div>
      <h4>Wireshark syntax</h4>
      <a href="#wireshark-syntax">
        
      </a>
    </div>
    <p>But before trying to figure out which approach would work best for us, let’s take a look at some of the simple <a href="https://wiki.wireshark.org/DisplayFilters">official Wireshark examples</a>, to understand what we’re dealing with:</p><ul><li><p><code>ip.len le 1500</code></p></li><li><p><code>udp contains 81:60:03</code></p></li><li><p><code>sip.To contains "a1762"</code></p></li><li><p><code>http.request.uri matches "gl=se$"</code></p></li><li><p><code>eth.dst == ff:ff:ff:ff:ff:ff</code></p></li><li><p><code>ip.addr == 192.168.0.1</code></p></li><li><p><code>ipv6.addr == ::1</code></p></li></ul><p>You can see that the right hand side of a comparison can be a number, an IPv4 / IPv6 address, a set of bytes or a string. They are used interchangeably, without any special notion of a type, which is fine given that they are easily distinguishable… or are they?</p><p>Let’s take a look at some <a href="https://en.wikipedia.org/wiki/IPv6#Address_representation">IPv6 forms</a> on Wikipedia:</p><ul><li><p><code>2001:0db8:0000:0000:0000:ff00:0042:8329</code></p></li><li><p><code>2001:db8:0:0:0:ff00:42:8329</code></p></li><li><p><code>2001:db8::ff00:42:8329</code></p></li></ul><p>So IPv6 can be written as a set of up to 8 colon-separated hexadecimal numbers, each containing up to 4 digits with leading zeros omitted for convenience. This appears suspiciously similar to the syntax for byte sequences. Indeed, if we try writing out a sequence like <code>2f:31:32:33:34:35:36:37</code>, it’s simultaneously a valid IPv6 and a byte sequence in terms of Wireshark syntax.</p><p>There is no way of telling what this sequence actually represents without looking at the type of the field it’s being compared with, and if you try using this sequence in Wireshark, you’ll notice that it does just that:</p><ul><li><p><code>ipv6.addr == 2f:31:32:33:34:35:36:37</code>: right hand side is parsed and used as an IPv6 address</p></li><li><p><code>http.request.uri == 2f:31:32:33:34:35:36:37</code>: right hand side is parsed and used as a byte sequence (will match a URL <code>"/1234567"</code>)</p></li></ul><p>Are there other examples of such ambiguities? Yup - for example, we can try using a single number with two decimal digits:</p><ul><li><p><code>tcp.port == 80</code>: matches any traffic on the port 80 (HTTP)</p></li><li><p><code>http.file_data == 80</code>: matches any HTTP request/response with body containing a single byte (0x80)</p></li></ul><p>We could also do the same with ethernet address, defined as a separate type in Wireshark, but, for simplicity, we represent it as a regular byte sequence in our implementation, so there is no ambiguity here.</p>
    <div>
      <h4>Choosing a parsing approach</h4>
      <a href="#choosing-a-parsing-approach">
        
      </a>
    </div>
    <p>This is an interesting syntax design decision. It means that we need to store a mapping between field names and types ahead of time - a Scheme, as we call it - and use it for contextual parsing. This restriction also immediately rules out many if not most parser generators.</p><p>We could still use one of the more sophisticated ones (like LALRPOP) that allow replacing the default regex-based lexer with your own custom code, but at that point we’re so close to having a full parser for our DSL that the complexity outweighs any benefits of using a black-box parser generator.</p><p>Instead, we went with a manual parsing approach. While (for a good reason) this might sound scary in unsafe languages like C / C++, in Rust all strings are bounds checked by default. Rust also provides a rich string manipulation API, which we can use to build more complex helpers, eventually ending up with a full parser.</p><p>This approach is, in fact, pretty similar to parser combinators in that the parser doesn’t have to keep state and only passes the unprocessed part of the input down to smaller, narrower scoped functions. Just as in parser combinators, the absence of mutable state also allows to easily test and maintain each of the parsers for different parts of the syntax independently of the others.</p><p>Compared with popular parser combinator libraries in Rust, one of the differences is that our parsers are not standalone functions but rather types that implement common traits:</p>
            <pre><code>pub trait Lex&lt;'i&gt;: Sized {
   fn lex(input: &amp;'i str) -&gt; LexResult&lt;'i, Self&gt;;
}
pub trait LexWith&lt;'i, E&gt;: Sized {
   fn lex_with(input: &amp;'i str, extra: E) -&gt; LexResult&lt;'i, Self&gt;;
}</code></pre>
            <p>The <code>lex</code> method or its contextual variant <code>lex_with</code> can either return a successful pair of <code>(instance of the type, rest of input)</code> or a pair of <code>(error kind, relevant input span)</code>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5L9MIL21iug4jVm8Eo1bGM/a4996c058b046ea785ff40d315772c53/parse.png" />
            
            </figure><p>The <code>Lex</code> trait is used for target types that can be parsed independently of the context (like field names or literals), while <code>LexWith</code> is used for types that need a <code>Scheme</code> or a part of it to be parsed unambiguously.</p><p>A bigger difference is that, instead of relying on higher-level functions for parser combinators, we use the usual imperative function call syntax. For example, when we want to perform sequential parsing, all we do is call several parsers in a row, using tuple destructuring for intermediate results:</p>
            <pre><code>let input = skip_space(input);
let (op, input) = CombinedExpr::lex_with(input, scheme)?;
let input = skip_space(input);
let input = expect(input, ")")?;</code></pre>
            <p>And, when we want to try different alternatives, we can use native pattern matching and ignore the errors:</p>
            <pre><code>if let Ok(input) = expect(input, "(") {
   ...
   (SimpleExpr::Parenthesized(Box::new(op)), input)
} else if let Ok((op, input)) = UnaryOp::lex(input) {
   ...
} else {
   ...
}</code></pre>
            <p>Finally, when we want to automate parsing of some more complicated common cases - say, enums - Rust provides a powerful macro syntax:</p>
            <pre><code>lex_enum!(#[repr(u8)] OrderingOp {
   "eq" | "==" =&gt; Equal = EQUAL,
   "ne" | "!=" =&gt; NotEqual = LESS | GREATER,
   "ge" | "&gt;=" =&gt; GreaterThanEqual = GREATER | EQUAL,
   "le" | "&lt;=" =&gt; LessThanEqual = LESS | EQUAL,
   "gt" | "&gt;" =&gt; GreaterThan = GREATER,
   "lt" | "&lt;" =&gt; LessThan = LESS,
});</code></pre>
            <p>This gives an experience similar to parser generators, while still using native language syntax and keeping us in control of all the implementation details.</p>
    <div>
      <h3>Execution engine</h3>
      <a href="#execution-engine">
        
      </a>
    </div>
    <p>Because our grammar and operations are fairly simple, initially we used direct AST interpretation by requiring all nodes to implement a trait that includes an <code>execute</code> method.</p>
            <pre><code>trait Expr&lt;'s&gt; {
    fn execute(&amp;self, ctx: &amp;ExecutionContext&lt;'s&gt;) -&gt; bool;
}</code></pre>
            <p>The <code>ExecutionContext</code> is pretty similar to a <code>Scheme</code>, but instead of mapping arbitrary field names to their types, it maps them to the runtime input values provided by the caller.</p><p>As with <code>Scheme</code>, initially <code>ExecutionContext</code> used an internal <code>HashMap</code> for registering these arbitrary <code>String</code> -&gt; <code>RhsValue</code> mappings. During the <code>execute</code> call, the AST implementation would evaluate itself recursively, and look up each field reference in this map, either returning a value or raising an error on missing slots and type mismatches.</p><p>This worked well enough for an initial implementation, but using a <code>HashMap</code> has a non-trivial cost which we would like to eliminate. We already used a more efficient hasher - <code>[Fnv](https://github.com/servo/rust-fnv)</code> - because we are in control of all keys and so are not worried about hash DoS attacks, but there was still more we could do.</p>
    <div>
      <h4>Speeding up field access</h4>
      <a href="#speeding-up-field-access">
        
      </a>
    </div>
    <p>If we look at the data structures involved, we can see that the scheme is always well-defined in advance, and all our runtime values in the execution engine are expected to eventually match it, even if the order or a precise set of fields is not guaranteed:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/mMOLvyXxOj9FxO3dIbYwr/6b308db1a7860c67f52209a689226b56/fieldaccess.png" />
            
            </figure><p>So what if we ditch the second map altogether and instead use a fixed-size array of values? Array indexing should be much cheaper than looking up in a map, so it might be well worth the effort.</p><p>How can we do it? We already know the number of items (thanks to the predefined scheme) so we can use that for the size of the backing storage, and, in order to simulate <code>HashMap</code> “holes” for unset values, we can wrap each item an <code>Option&lt;...&gt;</code>:</p>
            <pre><code>pub struct ExecutionContext&lt;'e&gt; {
    scheme: &amp;'e Scheme,
    values: Box&lt;[Option&lt;LhsValue&lt;'e&gt;&gt;]&gt;,
}</code></pre>
            <p>The only missing piece is an index that could map both structures to each other. As you might remember, <code>Scheme</code> still uses a <code>HashMap</code> for field registration, and a <code>HashMap</code> is normally expected to be randomised and indexed only by the predefined key.</p><p>While we could wrap a value and an auto-incrementing index together into a custom struct, there is already a better solution: <code>[IndexMap](https://github.com/bluss/indexmap)</code>. <code>IndexMap</code> is a drop-in replacement for a <code>HashMap</code> that preserves ordering and provides a way to get an index of any element and vice versa - exactly what we needed.</p><p>After replacing a <code>HashMap</code> in the Scheme with <code>IndexMap</code>, we can change parsing to resolve all the parsed field names to their indices in-place and store that in the AST:</p>
            <pre><code>impl&lt;'i, 's&gt; LexWith&lt;'i, &amp;'s Scheme&gt; for Field&lt;'s&gt; {
   fn lex_with(mut input: &amp;'i str, scheme: &amp;'s Scheme) -&gt; LexResult&lt;'i, Self&gt; {
       ...
       let field = scheme
           .get_field_index(name)
           .map_err(|err| (LexErrorKind::UnknownField(err), name))?;
       Ok((field, input))
   }
}</code></pre>
            <p>After that, in the <code>ExecutionContext</code> we allocate a fixed-size array and use these indices for resolving values during runtime:</p>
            <pre><code>impl&lt;'e&gt; ExecutionContext&lt;'e&gt; {
   /// Creates an execution context associated with a given scheme.
   ///
   /// This scheme will be used for resolving any field names and indices.
   pub fn new&lt;'s: 'e&gt;(scheme: &amp;'s Scheme) -&gt; Self {
       ExecutionContext {
           scheme,
           values: vec![None; scheme.get_field_count()].into(),
       }
   }
   ...
}</code></pre>
            <p>This gave significant (~2x) speed ups on our standard benchmarks:</p><p><i>Before:</i></p>
            <pre><code>test matching ... bench:       2,548 ns/iter (+/- 98)
test parsing  ... bench:     192,037 ns/iter (+/- 21,538)</code></pre>
            <p><i>After**:**</i></p>
            <pre><code>test matching ... bench:       1,227 ns/iter (+/- 29)
test parsing  ... bench:     197,574 ns/iter (+/- 16,568)</code></pre>
            <p>This change also improved the usability of our API, as any type errors are now detected and reported much earlier, when the values are just being set on the context, and not delayed until filter execution.</p>
    <div>
      <h4>[not] JIT compilation</h4>
      <a href="#not-jit-compilation">
        
      </a>
    </div>
    <p>Of course, as with any respectable DSL, one of the other ideas we had from the beginning was “...at some point we’ll add native compilation to make everything super-fast, it’s just a matter of time...”.</p><p>In practice, however, native compilation is a complicated matter, but not due to lack of tools.</p><p>First of all, there is question of storage for the native code. We could compile each filter statically into some sort of a library and publish to a key-value store, but that would not be easy to maintain:</p><ul><li><p>We would have to compile each filter to several platforms (x86-64, ARM, WASM, …).</p></li><li><p>The overhead of native library formats would significantly outweigh the useful executable size, as most filters tend to be small.</p></li><li><p>Each time we’d like to change our execution logic, whether to optimise it or to fix a bug, we would have to recompile and republish all the previously stored filters.</p></li><li><p>Finally, even if/though we’re sure of the reliability of the chosen store, executing dynamically retrieved native code on the edge as-is is not something that can be taken lightly.</p></li></ul><p>The usual flexible alternative that addresses most of these issues is Just-in-Time (JIT) compilation.</p><p>When you compile code directly on the target machine, you get to re-verify the input (still expressed as a restricted DSL), you can compile it just for the current platform in-place, and you never need to republish the actual rules.</p><p>Looks like a perfect fit? Not quite. As with any technology, there are tradeoffs, and you only get to choose those that make more sense for your use cases. JIT compilation is no exception.</p><p>First of all, even though you’re not loading untrusted code over the network, you still need to generate it into the memory, mark that memory as executable and trust that it will always contain valid code and not garbage or something worse. Depending on your choice of libraries and complexity of the DSL, you might be willing to trust it or put heavy sandboxing around, but, either way, it’s a risk that one must explicitly be willing to take.</p><p>Another issue is the cost of compilation itself. Usually, when measuring the speed of native code vs interpretation, the cost of compilation is not taken into the account because it happens out of the process.</p><p>With JIT compilers though, it’s different as you’re now compiling things the moment they’re used and cache the native code only for a limited time. Turns out, generating native code can be rather expensive, so you must be absolutely sure that the compilation cost doesn’t offset any benefits you might gain from the native execution speedup.</p><p>I’ve talked a bit more about this at <a href="https://www.meetup.com/rust-atx/">Rust Austin meetup</a> and, I believe, this topic deserves a separate blog post so won’t go into much more details here, but feel free to check out the slides: <a href="https://www.slideshare.net/RReverser/building-fast-interpreters-in-rust">https://www.slideshare.net/RReverser/building-fast-interpreters-in-rust</a>. Oh, and if you’re in Austin, you should pop into our office for the next meetup!</p><p>Let’s get back to our original question: is there anything else we can do to get the best balance between security, runtime performance and compilation cost? Turns out, there is.</p>
    <div>
      <h4>Dynamic dispatch and closures to the rescue</h4>
      <a href="#dynamic-dispatch-and-closures-to-the-rescue">
        
      </a>
    </div>
    <p>Introducing <code>Fn</code> trait!</p><p>In Rust, the <code>Fn</code> trait and friends (<code>FnMut</code>, <code>FnOnce</code>) are automatically implemented on eligible functions and closures. In case of a simple <code>Fn</code> case the restriction is that they must not modify their captured environment and can only borrow from it.</p><p>Normally, you would want to use it in generic contexts to support arbitrary callbacks with given argument and return types. This is important because in Rust, each function and closure implements a unique type and any generic usage would compile down to a specific call just to that function.</p>
            <pre><code>fn just_call(me: impl Fn(), maybe: bool) {
  if maybe {
    me()
  }
}</code></pre>
            <p>Such behaviour (called static dispatch) is the default in Rust and is preferable for performance reasons.</p><p>However, if we don’t know all the possible types at compile-time, Rust allows us to opt-in for a dynamic dispatch instead:</p>
            <pre><code>fn just_call(me: &amp;dyn Fn(), maybe: bool) {
  if maybe {
    me()
  }
}</code></pre>
            <p>Dynamically dispatched objects don't have a statically known size, because it depends on the implementation details of particular type being passed. They need to be passed as a reference or stored in a heap-allocated <code>Box</code>, and then used just like in a generic implementation.</p><p>In our case, this allows to create, return and store arbitrary closures, and later call them as regular functions:</p>
            <pre><code>trait Expr&lt;'s&gt; {
    fn compile(self) -&gt; CompiledExpr&lt;'s&gt;;
}

pub(crate) struct CompiledExpr&lt;'s&gt;(Box&lt;dyn 's + Fn(&amp;ExecutionContext&lt;'s&gt;) -&gt; bool&gt;);

impl&lt;'s&gt; CompiledExpr&lt;'s&gt; {
   /// Creates a compiled expression IR from a generic closure.
   pub(crate) fn new(closure: impl 's + Fn(&amp;ExecutionContext&lt;'s&gt;) -&gt; bool) -&gt; Self {
       CompiledExpr(Box::new(closure))
   }

   /// Executes a filter against a provided context with values.
   pub fn execute(&amp;self, ctx: &amp;ExecutionContext&lt;'s&gt;) -&gt; bool {
       self.0(ctx)
   }
}</code></pre>
            <p>The closure (an <code>Fn</code> box) will also automatically include the environment data it needs for the execution.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7x17xAapCcN3PjapVfoIyh/89ca29faa4b157fc2dcd7af0179eacb6/box.png" />
            
            </figure><p>This means that we can optimise the runtime data representation as part of the “compile” process without changing the AST or the parser. For example, when we wanted to optimise IP range checks by splitting them for different IP types, we could do that without having to modify any existing structures:</p>
            <pre><code>RhsValues::Ip(ranges) =&gt; {
   let mut v4 = Vec::new();
   let mut v6 = Vec::new();
   for range in ranges {
       match range.clone().into() {
           ExplicitIpRange::V4(range) =&gt; v4.push(range),
           ExplicitIpRange::V6(range) =&gt; v6.push(range),
       }
   }
   let v4 = RangeSet::from(v4);
   let v6 = RangeSet::from(v6);
   CompiledExpr::new(move |ctx| {
       match cast!(ctx.get_field_value_unchecked(field), Ip) {
           IpAddr::V4(addr) =&gt; v4.contains(addr),
           IpAddr::V6(addr) =&gt; v6.contains(addr),
       }
   })
}</code></pre>
            <p>Moreover, boxed closures can be part of that captured environment, too. This means that we can convert each simple comparison into a closure, and then combine it with other closures, and keep going until we end up with a single top-level closure that can be invoked as a regular function to evaluate the entire filter expression.</p><p>It’s turtles closures all the way down:</p>
            <pre><code>let items = items
   .into_iter()
   .map(|item| item.compile())
   .collect::&lt;Vec&lt;_&gt;&gt;()
   .into_boxed_slice();

match op {
   CombiningOp::And =&gt; {
       CompiledExpr::new(move |ctx| items.iter().all(|item| item.execute(ctx)))
   }
   CombiningOp::Or =&gt; {
       CompiledExpr::new(move |ctx| items.iter().any(|item| item.execute(ctx)))
   }
   CombiningOp::Xor =&gt; CompiledExpr::new(move |ctx| {
       items
           .iter()
           .fold(false, |acc, item| acc ^ item.execute(ctx))
   }),
}</code></pre>
            <p>What’s nice about this approach is:</p><ul><li><p>Our execution is no longer tied to the AST, and we can be as flexible with optimising the implementation and data representation as we want without affecting the parser-related parts of code or output format.</p></li><li><p>Even though we initially “compile” each node to a single closure, in future we can pretty easily specialise certain combinations of expressions into their own closures and so improve execution speed for common cases. All that would be required is a separate <code>match</code> branch returning a closure optimised for just that case.</p></li><li><p>Compilation is very cheap compared to real code generation. While it might seem that allocating many small objects (one <code>Box</code>ed closure per expression) is not very efficient and that it would be better to replace it with some sort of a memory pool, in practice we saw a negligible performance impact.</p></li><li><p>No native code is generated at runtime, which means that we execute only code that was statically verified by Rust at compile-time and compiled down to a static function. All that we do at the runtime is call existing functions with different values.</p></li><li><p>Execution turns out to be faster too. This initially came as a surprise, because dynamic dispatch is widely believed to be costly and we were worried that it would get slightly worse than AST interpretation. However, it showed an immediate ~10-15% runtime improvement in benchmarks and on real examples.</p></li></ul><p>The only obvious downside is that each level of AST requires a separate dynamically-dispatched call instead of a single inlined code for the entire expression, like you would have even with a basic template JIT.</p><p>Unfortunately, such output could be achieved only with real native code generation, and, for our case, the mentioned downsides and risks would outweigh runtime benefits, so we went with the safe &amp; flexible closure approach.</p>
    <div>
      <h3>Bonus: WebAssembly support</h3>
      <a href="#bonus-webassembly-support">
        
      </a>
    </div>
    <p>As was mentioned earlier, we chose Rust as a safe high-level language that allows easy integration with other parts of our stack written in Go, C and Lua via C FFI. But Rust has one more target it invests in and supports exceptionally well: WebAssembly.</p><p>Why would we be interested in that? Apart from the parts of the stack where our rules would run, and the API that publishes them, we also have users who like to write their own rules. To do that, they use a UI editor that allows either writing raw expressions in Wireshark syntax or as a WYSIWYG builder.</p><p>We thought it would be great to expose the parser - the same one as we use on the backend - to the frontend JavaScript for a consistent real-time editing experience. And, honestly, we were just looking for an excuse to play with WASM support in Rust.</p><p>WebAssembly could be targeted via regular C FFI, but in that case you would need to manually provide all the glue for the JavaScript side to hold and convert strings, arrays and objects forth and back.</p><p>In Rust, this is all handled by <a href="https://github.com/rustwasm/wasm-bindgen">wasm-bindgen</a>. While it provides various attributes and methods for direct conversions, the simplest way to get started is to activate the “serde” feature which will automatically convert types using <code>JSON.parse</code>, <code>JSON.stringify</code> and <code>[serde_json](https://docs.serde.rs/serde_json/)</code> under the hood.</p><p>In our case, creating a wrapper for the parser with only 20 lines of code was enough to get started and have all the WASM code + JavaScript glue required:</p>
            <pre><code>#[wasm_bindgen]
pub struct Scheme(wirefilter::Scheme);

fn into_js_error(err: impl std::error::Error) -&gt; JsValue {
   js_sys::Error::new(&amp;err.to_string()).into()
}

#[wasm_bindgen]
impl Scheme {
   #[wasm_bindgen(constructor)]
   pub fn try_from(fields: &amp;JsValue) -&gt; Result&lt;Scheme, JsValue&gt; {
       fields.into_serde().map(Scheme).map_err(into_js_error)
   }

   pub fn parse(&amp;self, s: &amp;str) -&gt; Result&lt;JsValue, JsValue&gt; {
       let filter = self.0.parse(s).map_err(into_js_error)?;
       JsValue::from_serde(&amp;filter).map_err(into_js_error)
   }
}</code></pre>
            <p>And by using a higher-level tool called <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>, we also got automated npm package generation and publishing, for free.</p><p>This is not used in the production UI yet because we still need to figure out some details for unsupported browsers, but it’s great to have all the tooling and packages ready with minimal efforts. Extending and reusing the same package, it should be even possible to run filters in Cloudflare Workers too (which <a href="/webassembly-on-cloudflare-workers/">also support WebAssembly</a>).</p>
    <div>
      <h3>The future</h3>
      <a href="#the-future">
        
      </a>
    </div>
    <p>The code in the current state is already doing its job well in production and we’re happy to share it with the open-source Rust community.</p><p>This is definitely not the end of the road though - we have many more fields to add, features to implement and planned optimisations to explore. If you find this sort of work interesting and would like to help us by working on firewalls, parsers or just any Rust projects at scale, give us a shout!</p> ]]></content:encoded>
            <category><![CDATA[Rust]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[API]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">2IkqAbjbvhsOMUuOPkvsnL</guid>
            <dc:creator>Ingvar Stepanyan</dc:creator>
            <dc:creator>Andrew Galloni</dc:creator>
        </item>
        <item>
            <title><![CDATA[Fixing an old hack - why we are bumping the IPv6 MTU]]></title>
            <link>https://blog.cloudflare.com/increasing-ipv6-mtu/</link>
            <pubDate>Mon, 10 Sep 2018 09:21:25 GMT</pubDate>
            <description><![CDATA[ Back in 2015 we deployed ECMP routing - Equal Cost Multi Path - within our datacenters. This technology allowed us to spread traffic heading to a single IP address across multiple physical servers. ]]></description>
            <content:encoded><![CDATA[ <p>Back in 2015 we deployed <a href="https://en.wikipedia.org/wiki/Equal-cost_multi-path_routing">ECMP routing</a> - Equal Cost Multi Path - within our datacenters. This technology allowed us to spread traffic heading to a single IP address across multiple physical servers.</p><p>You can think about it as a third layer of load balancing.</p><ul><li><p>First we split the traffic across multiple IP addresses with DNS.</p></li><li><p>Then we split the traffic across <a href="https://www.cloudflare.com/learning/cdn/glossary/anycast-network/">multiple datacenters with Anycast</a>.</p></li><li><p>Finally, we split the traffic across multiple servers with ECMP.</p></li></ul>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6brB6jYvBwnIHL5UyGZZpq/dbc2f52a7ba7056bebc36eb90ec98c55/5799659266_28038df72f_b.jpg" />
            
            </figure><p><a href="https://www.flickr.com/photos/superlatif/5799659266/">photo</a> by <a href="https://www.flickr.com/photos/superlatif/">Sahra</a> by-sa/2.0</p><p>When deploying ECMP we hit a problem with Path MTU discovery. The ICMP packets destined to our Anycast IP's were being dropped. You can read more about that (and the solution) in the 2015 blog post <a href="/path-mtu-discovery-in-practice/">Path MTU Discovery in practice</a>.</p><p>To solve the problem we created a small piece of software, called <code>pmtud</code> (<a href="https://github.com/cloudflare/pmtud">https://github.com/cloudflare/pmtud</a>). Since deploying <code>pmtud</code>, our ECMP setup has been working smoothly.</p>
    <div>
      <h3>Hardcoding IPv6 MTU</h3>
      <a href="#hardcoding-ipv6-mtu">
        
      </a>
    </div>
    <p>During that initial ECMP rollout things were broken. To keep services running until <code>pmtud</code> was done, we deployed a quick hack. We reduced the MTU of  IPv6 traffic to the minimal possible value: 1280 bytes.</p><p>This was done as a tag on a default route. This is how our routing table used to look:</p>
            <pre><code>$ ip -6 route show
...
default via 2400:xxxx::1 dev eth0 src 2400:xxxx:2  metric 1024  mtu 1280</code></pre>
            <p>Notice the <code>mtu 1280</code> in the default route.</p><p>With this setting our servers never transmitted IPv6 packets larger than 1280 bytes, therefore "fixing" the issue. Since all IPv6 routers must have an MTU of at least 1280, we could expect that no ICMP Packet-Too-Big message would ever be sent to us.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/WoQ4atXDbAlJ1mhDnXDcf/0e2df496f1184bf35217d2be59f255b8/ECMP-hashing-ICMP.png" />
            
            </figure><p>Remember - the original problem introduced by ECMP was that ICMP routed back to our Anycast addresses could go to a wrong machine within the ECMP group. Therefore we became ICMP black holes. Cloudflare would send large packets, they would be dropped with ICMP PTB packet flying back to us. Which, in turn would fail to be delivered to the right machine due to ECMP.</p><p>But why did this problem not appear for IPv4 traffic? We believe the same issue exists on IPv4, but it's less damaging due to the different nature of the network. IPv4 is more mature and the great majority of end-hosts support either MTU 1500 or have their MSS option well configured - or clamped by some middle box. This is different in IPv6 where a large proportion of  users use tunnels, have Path MTU strictly smaller than 1500 and use incorrect MSS settings in the TCP header. Finally, Linux implements <a href="https://tools.ietf.org/html/rfc4821">RFC4821</a> for IPv4 but not IPv6. RFC4821 (PLPMTUD) has its disadvantages, but does slightly help to alleviate the ICMP blackhole issue.</p><p>Our "fix" - reducing the MTU to 1280 - was serving us well and we had no pressing reason to revert it.</p><p>Researchers did notice though. We were caught red-handed twice:</p><ul><li><p><a href="https://blog.apnic.net/2016/11/15/scoring-dns-root-server-system/">In 2017 Geoff Huston noticed (pdf)</a> that we sent DNS fragments of 1280 only (<a href="https://blog.apnic.net/2016/11/15/scoring-dns-root-server-system/">older blog post</a>).</p></li><li><p>In June 2018 the paper <a href="http://tma.ifip.org/2018/wp-content/uploads/sites/3/2018/06/tma2018_paper57.pdf">"Exploring usable Path MTU in the Internet" (pdf)</a> mentioned our weird setting - where we can accept 1500 bytes just fine, but transmit is limited to 1280.</p></li></ul>
    <div>
      <h3>When small MTU is too small</h3>
      <a href="#when-small-mtu-is-too-small">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3yo93AUS4hONJUarTUlGP/1c9fd02139519ea6f947b61a39da9d8b/6545737741_077583ca1f_b-1.jpg" />
            
            </figure><p><a href="https://www.flickr.com/photos/nh53/6545737741/">photo</a> by <a href="https://www.flickr.com/photos/nh53">NH53</a> by/2.0</p><p>This changed recently, when we started working on <a href="/spectrum/">Cloudflare Spectrum</a> support for UDP. Spectrum is a terminating proxy, able to handle protocols other than HTTP. Getting Spectrum to <a href="/how-we-built-spectrum/">forward TCP was relatively straightforward</a> (barring couple of <a href="/mmproxy-creative-way-of-preserving-client-ips-in-spectrum/">awesome hacks</a>). UDP is different.</p><p>One of the major issues we hit was related to the MTU on our servers.</p><p>During tests we wanted to forward UDP VPN packets through Spectrum. As you can imagine, any VPN would encapsulate a packet in another packet. Spectrum received packets like this:</p>
            <pre><code> +---------------------+------------------------------------------------+
 +  IPv6 + UDP header  |  UDP payload encapsulating a 1280 byte packet  |
 +---------------------+------------------------------------------------+</code></pre>
            <p>It's pretty obvious, that our edge servers supporting IPv6 packets of max 1280 bytes won't be able to handle this type of traffic. We are going to need at least 1280+40+8 bytes MTU! Hardcoding MTU=1280 in IPv6 may be acceptable solution if you are an end-node on the internet, but is definitely too small when forwarding tunneled traffic.</p>
    <div>
      <h3>Picking a new MTU</h3>
      <a href="#picking-a-new-mtu">
        
      </a>
    </div>
    <p>But what MTU value should we use instead? Let's see what other major internet companies do. Here is a couple of examples of advertised MSS values in TCP SYN+ACK packets over IPv6:</p>
            <pre><code>+---- site -----+- MSS --+- estimated MTU -+
| google.com    |  1360  |    1420         |
+---------------+--------+-----------------+
| facebook.com  |  1410  |    1470         |
+---------------+--------+-----------------+
| wikipedia.org |  1440  |    1500         |
+---------------+--------+-----------------+</code></pre>
            <p>I believe Google and Facebook adjust their MTU due to their use of L4 load balancers. Their implementations do IP-in-IP encapsulation so need a bit of space for the header. Read more:</p><ul><li><p>Google - <a href="https://ai.google/research/pubs/pub44824">Maglev</a></p></li><li><p>Facebook - <a href="https://code.fb.com/open-source/open-sourcing-katran-a-scalable-network-load-balancer/">Katran</a></p></li></ul><p>There may be other reasons for having a smaller MTU. A reduced value may decrease the probability of the Path MTU detection algorithm kicking in (ie: relying on ICMP PTB). We can theorize that for the misconfigured eyeballs:</p><ul><li><p>MTU=1280 will never run Path MTU detection</p></li><li><p>MTU=1500 will always run it.</p></li><li><p>In-between values would have increasing different chances of hitting the problem.</p></li></ul><p>But just what is the chance of that?</p><p>A quick unscientific study of the MSS values we encountered from eyeballs shows the following distributions. For connections going over IPv4:</p>
            <pre><code>IPv4 eyeball advertised MSS in SYN:
 value |-------------------------------------------------- count cummulative
  1300 |                                                 *  1.28%   98.53%
  1360 |                                              ****  4.40%   95.68%
  1370 |                                                 *  1.15%   91.05%
  1380 |                                               ***  3.35%   89.81%
  1400 |                                          ********  7.95%   84.79%
  1410 |                                                 *  1.17%   76.66%
  1412 |                                              ****  4.58%   75.49%
  1440 |                                            ******  6.14%   65.71%
  1452 |                                      ************ 11.50%   58.94%
  1460 |************************************************** 47.09%   47.34%</code></pre>
            <p>Assuming the majority of clients have MSS configured right, we can say that 89.8% of connections advertised MTU=1380+40=1420 or higher. 75% had MTU &gt;= 1452.</p><p>For IPv6 connections we saw:</p>
            <pre><code>IPv6 eyeball advertised MSS in SYN:
 value |-------------------------------------------------- count cummulative
  1220 |                                               ***  4.21%   99.96%
  1340 |                                                **  3.11%   93.23%
  1362 |                                                 *  1.31%   87.70%
  1368 |                                               ***  3.38%   86.36%
  1370 |                                               ***  4.24%   82.98%
  1380 |                                               ***  3.52%   78.65%
  1390 |                                                 *  2.11%   75.10%
  1400 |                                               ***  3.89%   72.25%
  1412 |                                               ***  3.64%   68.21%
  1420 |                                                 *  2.02%   64.54%
  1440 |************************************************** 54.31%   54.34%</code></pre>
            <p>On IPv6 87.7% connections had MTU &gt;= 1422 (1362+60). 75% had MTU &gt;= 1450. (See also: <a href="https://blog.apnic.net/2016/05/19/fragmenting-ipv6/">MTU distribution of DNS  servers</a>).</p>
    <div>
      <h3>Interpretation</h3>
      <a href="#interpretation">
        
      </a>
    </div>
    <p>Before we move on it's worth reiterating the original problem. Each connection from an eyeball to our Anycast network has three numbers related to it:</p><ul><li><p>Client advertised MTU - seen in MSS option in TCP header</p></li><li><p>True Path MTU value - generally unknown until measured</p></li><li><p>Our Edge server MTU - value we are trying to optimize in this exercise</p></li></ul><p>(This is a slight simplification, paths on the internet aren't symmetric so the path from eyeball to Cloudflare could have different Path MTU than the reverse path.)</p><p>In order for the connection to misbehave, three conditions must be met:</p><ul><li><p>Client advertised MTU must be "wrong", that is: larger than True Path MTU</p></li><li><p>Our edge server must be willing to send such large packets: Edge server MTU &gt;= True Path MTU</p></li><li><p>The ICMP PTB messages must fail to be delivered to our edge server - preventing Path MTU detection from working.</p></li></ul><p>The last condition could occur for one of the reasons:</p><ul><li><p>the routers on the path are misbehaving and perhaps firewalling ICMP</p></li><li><p>due to the asymmetric nature of the internet the ICMP back is routed to the wrong Anycast datacenter</p></li><li><p>something is wrong on our side, for example <code>pmtud</code> process fails</p></li></ul><p>In the past we limited our Edge Server MTU value to the smallest possible, to make sure we never encounter the problem. Due to the development of Spectrum UDP support we must increase the Edge Server MTU, while still minimizing the probability of the issue happening.</p><p>Finally, relying on ICMP PTB messages for a large fraction of traffic is a bad idea. It's easy to imagine the cost this induces: even with Path MTU detection working fine, the affected connection will suffer a hiccup. A couple of large packets will be dropped before the reverse ICMP will get through and reconfigure the saved Path MTU value. This is not optimal for latency.</p>
    <div>
      <h3>Progress</h3>
      <a href="#progress">
        
      </a>
    </div>
    <p>In recent days we increased the IPv6 MTU. As part of the process we could have chosen 1300, 1350, or 1400. We choose 1400 because we think it's the next best value to use after 1280. With 1400 we believe 93.2% of IPv6 connections will not need to rely on Path MTU Detection/ICMP. In the near future we plan to increase this value further. We won't settle on 1500 though - we want to leave a couple of bytes for IPv4 encapsulation, to allow the most popular tunnels to keep working without suffering poor latency when Path MTU Detection kicks in.</p><p>Since the rollout we've been monitoring <code>Icmp6InPktTooBigs</code> counters:</p>
            <pre><code>$ nstat -az | grep Icmp6InPktTooBigs
Icmp6InPktTooBigs               738748             0.0</code></pre>
            <p>Here is a chart of the ICMP PTB packets we received over last 7 days. You can clearly see that when the rollout started, we saw a large increase in PTB ICMP messages (Y label - packet count - deliberately obfuscated):</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/64aFjrP5OwJLKlbMfwIofg/abc284d8d6f8b2b0c7441277cfea12cc/Screen-Shot-2018-09-06-at-2.12.28-PM.png" />
            
            </figure><p>Interestingly the majority of the ICMP packets are concentrated in our Frankfurt datacenter:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7rwp7vqya4hZUVtqgALCo0/70c29ca328859bd7330a9399305d7d79/Screen-Shot-2018-09-06-at-2.11.53-PM.png" />
            
            </figure><p>We estimate that in our Frankfurt datacenter, we receive ICMP PTB message on 2 out of every 100 IPv6 TCP connections. These seem to come from only a handful of ASNs:</p><ul><li><p>AS6830 - Liberty Global Operations B.V.</p></li><li><p>AS20825- Unitymedia NRW GmbH</p></li><li><p>AS31334 - Vodafone Kabel Deutschland GmbH</p></li><li><p>AS29562 - Kabel BW GmbH</p></li></ul><p>These networks send to us ICMP PTB messages, usually informing that their MTU is 1280. For example:</p>
            <pre><code>$ sudo tcpdump -tvvvni eth0 icmp6 and ip6[40+0]==2 
IP6 2a02:908:xxx &gt; 2400:xxx ICMP6, packet too big, mtu 1280, length 1240
IP6 2a02:810d:xx &gt; 2400:xxx ICMP6, packet too big, mtu 1280, length 1240
IP6 2001:ac8:xxx &gt; 2400:xxx ICMP6, packet too big, mtu 1390, length 1240</code></pre>
            
    <div>
      <h3>Final thoughts</h3>
      <a href="#final-thoughts">
        
      </a>
    </div>
    <p>Finally, if you are an IPv6 user with a weird MTU and have misconfigured MSS - basically if you are doing tunneling - please let us know of any issues. We know that debugging MTU issues is notoriously hard. To aid that we created <a href="/ip-fragmentation-is-broken/">an online fragmentation and ICMP delivery test</a>. You can run it:</p><ul><li><p>IPv6 version: <a href="http://icmpcheckv6.popcount.org">http://icmpcheckv6.popcount.org</a></p></li><li><p>(for completeness, we also have an <a href="http://icmpcheck.popcount.org">IPv4 version</a>)</p></li></ul><p>If you are a server operator running IPv6 applications, you should not worry. In most cases leaving the MTU at default 1500 is a good choice and should work for the majority of connections.  Just remember to allow ICMP PTB packets on the firewall and you should be good. If you serve variety of IPv6 users and need to optimize latency, you may consider choosing a slightly smaller MTU for outbound packets, to reduce the risk of relying on Path MTU Detection / ICMP.</p><p><i>Low level network tuning sound interesting? Join our </i><a href="https://boards.greenhouse.io/cloudflare/jobs/589572"><i>world famous team</i></a><i> in London, Austin, San Francisco, Champaign and our elite office in Warsaw, Poland.</i></p> ]]></content:encoded>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Anycast]]></category>
            <category><![CDATA[Load Balancing]]></category>
            <guid isPermaLink="false">4jilwfKi5MVWxnIA3ErwZ8</guid>
            <dc:creator>Marek Majkowski</dc:creator>
        </item>
        <item>
            <title><![CDATA[Enable Private DNS with 1.1.1.1 on Android 9 Pie]]></title>
            <link>https://blog.cloudflare.com/enable-private-dns-with-1-1-1-1-on-android-9-pie/</link>
            <pubDate>Thu, 16 Aug 2018 15:01:15 GMT</pubDate>
            <description><![CDATA[ Android 9 Pie includes a slew of new features around digital well-being and privacy. Here's how to use the new Private DNS feature with 1.1.1.1. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/57zPjGaEEfAzjR9eaXnnof/5c2c5cec12dcb52cea584149a32ca509/image2-1.png" />
            
            </figure><p>Recently, Google officially launched <a href="https://www.android.com/versions/pie-9-0/">Android 9 Pie</a>, which includes a slew of new features around digital well-being, security, and privacy. If you’ve poked around the network settings on your phone while on the beta or after updating, you may have noticed a new <a href="https://android-developers.googleblog.com/2018/04/dns-over-tls-support-in-android-p.html">Private DNS Mode</a> now supported by Android.</p><p>This new feature simplifies the process of configuring a custom secure DNS resolver on Android, meaning parties between your device and the websites you visit won’t be able to snoop on your DNS queries because they’ll be encrypted. The protocol behind this, TLS, is also responsible for the green lock icon you see in your address bar when visiting websites over HTTPS. The same technology is useful for encrypting DNS queries, ensuring they cannot be tampered with and are unintelligible to ISPs, mobile carriers, and any others in the network path between you and your DNS resolver. These new security protocols are called <a href="https://developers.cloudflare.com/1.1.1.1/dns-over-https/">DNS over HTTPS</a>, and <a href="https://developers.cloudflare.com/1.1.1.1/dns-over-tls/">DNS over TLS</a>.</p>
    <div>
      <h3>Configuring 1.1.1.1</h3>
      <a href="#configuring-1-1-1-1">
        
      </a>
    </div>
    <p>Android Pie only supports DNS over TLS. To enable this on your device:</p><ol><li><p>Go to Settings → Network &amp; internet → Advanced → Private DNS.</p></li><li><p>Select the Private DNS provider hostname option.</p></li><li><p>Enter <code>1dot1dot1dot1.cloudflare-dns.com</code> and hit Save.</p></li><li><p>Visit <a href="https://1.1.1.1/help">1.1.1.1/help</a> (or <a href="https://1.0.0.1/help">1.0.0.1/help</a>) to verify that “Using DNS over TLS (DoT)” shows as “Yes”.</p></li></ol><p>And you’re done!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/75TkxmEoBX1RdWQx1Gjv9h/07d64cd4c8c7df85f294e81a4d281a05/Screenshot_20180807-102253-1.png" />
            
            </figure>
    <div>
      <h3>Why Use Private DNS?</h3>
      <a href="#why-use-private-dns">
        
      </a>
    </div>
    <p>So how do <a href="https://developers.cloudflare.com/1.1.1.1/dns-over-https/">DNS over HTTPS</a> and <a href="https://developers.cloudflare.com/1.1.1.1/dns-over-tls/">DNS over TLS</a> fit into the current state of internet privacy?</p><p><a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">TLS</a> is the protocol that encrypts your traffic over an untrusted communication channel, like when browsing your email on a cafe’s wireless network. Even with TLS, there is still no way of knowing if your connection to the DNS server has been hijacked or is being snooped on by a third party. This is significant because a bad actor could configure an open WiFi hotspot in a public place that responds to DNS queries with falsified records in order to hijack connections to common email providers and online banks. <a href="https://www.cloudflare.com/dns/dnssec/how-dnssec-works/">DNSSEC</a> solves the problem of guaranteeing authenticity by signing responses, making tampering detectable, but leaves the body of the message readable by anyone else on the wire.</p><p>DNS over HTTPS / TLS solves this. These new protocols ensure that communication between your device and the resolver is encrypted, just like we’ve come to expect of HTTPS traffic.</p><p>However, there is one final insecure step in this chain of events: the revealing of the SNI (server name indication) during the initial TLS negotiation between your device and a specific hostname on a server. The requested hostname is not encrypted, so third parties still have the ability to see the websites you visit. It makes sense that the final step in completely securing your browsing activity involves <a href="https://tools.ietf.org/html/draft-ietf-tls-sni-encryption-03">encrypting SNI</a>, which is an in-progress standard that Cloudflare has joined other organizations to define and promote.</p>
    <div>
      <h3>DNS in an IPv6 World</h3>
      <a href="#dns-in-an-ipv6-world">
        
      </a>
    </div>
    <p>You may have noticed that the private DNS field does not accept an IP address like 1.1.1.1 and instead wants a hostname like 1dot1dot1dot1.cloudflare-dns.com. This doesn’t exactly roll off the tongue, so we’re working on deploying an easier to remember address for the resolver, and will continue to support 1.1.1.1, 1.0.0.1, and 1dot1dot1dot1.cloudflare-dns.com.</p><p>Google requires a hostname for this field because of how mobile carriers are adapting to a dual-stack world in which IPv4 and IPv6 coexist. Companies are adopting IPv6 <a href="https://www.internetsociety.org/resources/doc/2017/state-of-ipv6-deployment-2017/">much more rapidly</a> than generally expected, and all major mobile carriers in the US <a href="http://www.worldipv6launch.org/major-mobile-us-networks-pass-50-ipv6-threshold/">support it</a>, including T-Mobile who has <a href="https://www.internetsociety.org/resources/deploy360/2014/case-study-t-mobile-us-goes-ipv6-only-using-464xlat/">gone completely IPv6</a>. In a world where the <a href="https://www.statista.com/statistics/471264/iot-number-of-connected-devices-worldwide/">approximately 26 billion</a> internet-connected devices vastly outnumber the 4.3 billion IPv4 addresses, this is good news. And in a forward-thinking move, Apple requires that all new iOS apps <a href="/supporting-the-transition-to-ipv6-only-networking-services-for-ios/">must support</a> single-stack IPv6 networks.</p><p>However, we still live in a world with IPv4 addresses, so phone manufacturers and carriers have to architect their systems with backwards compatibility in mind. Currently, iOS and Android request both <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-a-record/">A</a> and AAAA DNS records, which contain the IP address(es) corresponding to a domain in version 4 and version 6 format, respectively. Try it out yourself:</p>
            <pre><code>$ dig A +short 1dot1dot1dot1.cloudflare-dns.com
1.0.0.1
1.1.1.1

$ dig AAAA +short 1dot1dot1dot1.cloudflare-dns.com
2606:4700:4700::1001
2606:4700:4700::1111</code></pre>
            <p>To talk to a device with only an IPv4 address over an IPv6 only network, the DNS resolver has to translate IPv4 addresses into the IPv6 address using <a href="https://en.wikipedia.org/wiki/IPv6_transition_mechanism#DNS64">DNS64</a>. The requests to those translated IP addresses then go through the NAT64 translation service provided by the network operator. This is all completely transparent to the device and web server.</p><p>Learn more about this process <a href="https://blog.apnic.net/2016/06/09/lets-talk-ipv6-dns64-dnssec/">from APNIC</a>.</p> ]]></content:encoded>
            <category><![CDATA[1.1.1.1]]></category>
            <category><![CDATA[Resolver]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Privacy]]></category>
            <guid isPermaLink="false">5YIdDI8hSCNXllagVrj1Di</guid>
            <dc:creator>Stephen Pinkerton</dc:creator>
        </item>
        <item>
            <title><![CDATA[IPv6 in China]]></title>
            <link>https://blog.cloudflare.com/ipv6-in-china/</link>
            <pubDate>Thu, 19 Jul 2018 00:03:37 GMT</pubDate>
            <description><![CDATA[ At the end of 2017, Xinhua reported that there will be 200 Million IPv6 users inside Mainland China by the end of this year.. Halfway into the year, we’re seeing a rapid growth in IPv6 users and traffic originating from Mainland China. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Photo by <a href="https://unsplash.com/@chuttersnap?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">chuttersnap</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></p><p>At the end of 2017, Xinhua reported that there will be 200 Million IPv6 users inside Mainland China <a href="http://www.xinhuanet.com/english/2017-11/26/c_136780735.htm">by the end of this year</a>. Halfway into the year, we’re seeing a rapid growth in IPv6 users and traffic originating from Mainland China.</p>
    <div>
      <h3>Why does this matter?</h3>
      <a href="#why-does-this-matter">
        
      </a>
    </div>
    <p>IPv6 is often referred to the next generation of IP addressing. The reality is, IPv6 is what is needed for addressing today. Taking the largest mobile network in China today, China Mobile has over 900 Million mobile subscribers and over <a href="https://www.chinamobileltd.com/en/ir/operation_m.php">670 Million 4G/LTE subscribers</a>. To be able to provide service to their users, they need to provide an IP address to each subscriber’s device. This means close to a billion IP addresses would be required, which is far more than what is available in IPv4, especially as the available IP address pools have been <a href="https://en.wikipedia.org/wiki/IPv4_address_exhaustion">exhausted</a>.</p>
    <div>
      <h3>What is the solution?</h3>
      <a href="#what-is-the-solution">
        
      </a>
    </div>
    <p>To solve the addressability of clients, many networks, especially mobile networks, will use <a href="https://en.wikipedia.org/wiki/Carrier-grade_NAT">Carrier Grade NAT (CGN)</a>. This allows thousands, possibly up to hundreds of thousands, of devices to be shared behind a single internet IP address. The CGN equipment can be very expensive to scale and further, given the scale of the networks, they might need to layer CGNs behind other CGNs. This increases costs per subscriber, can reduce performance and makes scaling very challenging. A further solution, <a href="https://en.wikipedia.org/wiki/NAT64">NAT64</a>, allows IPv6 addresses to be given to subscribers, but then translated to IPv4 addresses similar to other NATs. This allows networks and ISPs to begin deploying IPv6 to subscribers, a first step in transition to IPv6.</p>
    <div>
      <h3>IPv6 IPv6 IPv6!</h3>
      <a href="#ipv6-ipv6-ipv6">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1iY3FD5e6ymhDdlae7sTwV/b509d4cb412452cba3ab40c467fba9bb/AS9808-BGP-Announcements.png" />
            
            </figure><p>Announcements IPv6 address blocks from China Mobile. Source: <a href="https://bgp.he.net/AS9808#_asinfo">Hurricane Electric</a></p><p>On June 7, China Mobile started to announce IPv6 address blocks to the Internet at large. At the same time, Cloudflare started seeing traffic being exchanged with China Mobile users over IPv6 connections.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/17A2wJdccc2D06GJEFPm2h/22fba6672a36787088cfb24a4f9bd632/AS9808-IPv6-Stats.png" />
            
            </figure><p>IPv4 to IPv6 percentage of traffic as seen from Cloudflare to AS9808 China Mobile’s Guangdong network.</p><p>Throughout the past 45 days, we’ve seen more and more IPv6 address blocks being announced to the internet, along with very aggressive usage. Interestingly this all started on-or-around June 8th 2018 (seven years to the day from <a href="https://en.wikipedia.org/wiki/World_IPv6_Day_and_World_IPv6_Launch_Day">World IPv6 Day</a>)</p><p>It’s natural to see traffic graphs like this go up; then down after a while. This could indicate there’s some testing still going on with the deployment. We fully expect that the traffic percentage will climb back up once this is fully rolled out.</p><p>It’s fantastic to see the IPv6 enablement! We congratulate China Mobile on their successful enablement going forward.</p> ]]></content:encoded>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[China]]></category>
            <guid isPermaLink="false">1SakFiXhHjQEdWaLINxBIt</guid>
            <dc:creator>Tom Paseka</dc:creator>
        </item>
        <item>
            <title><![CDATA[eBPF, Sockets, Hop Distance and manually writing eBPF assembly]]></title>
            <link>https://blog.cloudflare.com/epbf_sockets_hop_distance/</link>
            <pubDate>Thu, 29 Mar 2018 10:43:38 GMT</pubDate>
            <description><![CDATA[ A friend gave me an interesting task: extract IP TTL values from TCP connections established by a userspace program. This seemingly simple task quickly exploded into an epic Linux system programming hack.  ]]></description>
            <content:encoded><![CDATA[ <p>A friend gave me an interesting task: extract IP TTL values from TCP connections established by a userspace program. This seemingly simple task quickly exploded into an epic Linux system programming hack. The result code is grossly over engineered, but boy, did we learn plenty in the process!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1UrWjrMBPW4l3ipvThL0sn/1e78cd221cc63a5fb9964b3bd55cd11d/3845353725_7d7c624f34_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/paulmiller/3845353725/">image</a> by <a href="https://www.flickr.com/photos/paulmiller">Paul Miller</a></p>
    <div>
      <h3>Context</h3>
      <a href="#context">
        
      </a>
    </div>
    <p>You may wonder why she wanted to inspect the TTL packet field (formally known as "IP Time To Live (TTL)" in IPv4, or "Hop Count" in IPv6)? The reason is simple - she wanted to ensure that the connections are routed outside of our datacenter. The "Hop Distance" - the difference between the TTL value set by the originating machine and the TTL value in the packet received at its destination - shows how many routers the packet crossed. If a packet crossed two or more routers, we know it indeed came from outside of our datacenter.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6eYDA3vNOF8Cc9ytLOPo9N/c4862fac898725e1bd54b0284977f251/Screen-Shot-2018-03-29-at-10.52.49-AM-1.png" />
            
            </figure><p>It's uncommon to look at TTL values (except for their intended purpose of mitigating routing loops by checking when the TTL reaches zero). The normal way to deal with the problem we had would be to blocklist IP ranges of our servers. But it’s not that simple in our setup. Our IP numbering configuration is rather baroque, with plenty of Anycast, Unicast and Reserved IP ranges. Some belong to us, some don't. We wanted to avoid having to maintain a hard-coded blocklist of IP ranges.</p><p>The gist of the idea is: we want to note the TTL value from a returned SYN+ACK packet. Having this number we can estimate the Hop Distance - number of routers on the path. If the Hop Distance is:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1LCtnMJcT3dIXlGwBrWf69/0dd6441edca81092fe6c536203657e21/Screen-Shot-2018-03-29-at-10.50.38-AM.png" />
            
            </figure><ul><li><p><b>zero</b>: we know the connection went to localhost or a local network.</p></li></ul>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2ugFXo390P0VMXOpsvqtVQ/04fc3c2133fbcfaa40db47655b131ab3/Screen-Shot-2018-03-29-at-10.49.42-AM.png" />
            
            </figure><ul><li><p><b>one</b>: connection went through our router, and was terminated just behind it.</p></li></ul>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5dwa36qw1gHyNNLKJ24UiX/a3ee616930c1335d4e6f8dc3fa7da5bb/Screen-Shot-2018-03-29-at-10.49.48-AM.png" />
            
            </figure><ul><li><p><b>two</b>: connection went through two routers. Most possibly our router, and one just near to it.</p></li></ul><p>For our use case, we want to see if the Hop Distance was two or more - this would ensure the connection was routed outside the datacenter.</p>
    <div>
      <h3>Not so easy</h3>
      <a href="#not-so-easy">
        
      </a>
    </div>
    <p>It's easy to read TTL values from a userspace application, right? No. It turns out it's almost impossible. Here are the theoretical options we considered early on:</p><p>A) Run a libpcap/tcpdump-like raw socket, and catch the SYN+ACK's manually. We ruled out this design quickly - it requires elevated privileges. Also, raw sockets are pretty fragile: they can suffer packet loss if the userspace application can’t keep up.</p><p>B) Use the IP_RECVTTL socket option. IP_RECVTTL requests a "cmsg" data to be attached to control/ancillary data in a <code>recvmsg()</code> syscall. This is a good choice for UDP connections, but this socket option is not supported by TCP SOCK_STREAM sockets.</p><p>Extracting the TTL is not so easy.</p>
    <div>
      <h3>SO_ATTACH_FILTER to rule the world!</h3>
      <a href="#so_attach_filter-to-rule-the-world">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1qX4zkQCTMRtJsnaqzysvp/a95be0f638ee764a86591c9576671281/315128991_d49c312fbc_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/leejordan/315128991/">image</a> by <a href="https://www.flickr.com/photos/leejordan/">Lee Jordan</a></p><p>Wait, there is a third way!</p><p>You see, for quite some time it has been possible to attach a BPF filtering program to a socket. See <a href="http://man7.org/linux/man-pages/man7/socket.7.html"><code>socket(7)</code></a></p>
            <pre><code>SO_ATTACH_FILTER (since Linux 2.2), SO_ATTACH_BPF (since Linux 3.19)
    Attach a classic BPF (SO_ATTACH_FILTER) or an extended BPF
    (SO_ATTACH_BPF) program to the socket for use as a filter of
    incoming packets.  A packet will be dropped if the filter pro‐
    gram returns zero.  If the filter program returns a nonzero
    value which is less than the packet's data length, the packet
    will be truncated to the length returned.  If the value
    returned by the filter is greater than or equal to the
    packet's data length, the packet is allowed to proceed unmodi‐
    fied.</code></pre>
            <p>You probably take advantage of SO_ATTACH_FILTER already: This is how tcpdump/wireshark does filtering when you're dumping packets off the wire.</p><p>How does it work? Depending on the result of a <a href="/bpf-the-forgotten-bytecode/">BPF program</a>, packets can be filtered, truncated or passed to the socket without modification. Normally SO_ATTACH_FILTER is used for RAW sockets, but surprisingly, BPF filters can also be attached to normal SOCK_STREAM and SOCK_DGRAM sockets!</p><p>We don't want to truncate packets though - we want to extract the TTL. Unfortunately with Classical BPF (cBPF) it's impossible to extract any data from a running BPF filter program.</p>
    <div>
      <h3>eBPF and maps</h3>
      <a href="#ebpf-and-maps">
        
      </a>
    </div>
    <p>This changed with modern BPF machinery, which includes:</p><ul><li><p>modernised eBPF bytecode</p></li><li><p>eBPF maps</p></li><li><p><a href="https://man7.org/linux/man-pages/man2/bpf.2.html"><code>bpf()</code> syscall</a></p></li><li><p>SO_ATTACH_BPF socket option</p></li></ul><p>eBPF bytecode can be thought of as an extension to Classical BPF, but it's the extra features that really let it shine.</p><p>The gem is the "map" abstraction. An eBPF map is a thingy that allows an eBPF program to store data and share it with a userspace code. Think of an eBPF map as a data structure (a hash table most usually) shared between a userspace program and an eBPF program running in kernel space.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/51BMjhXrkIIAlAatG0qsMh/bdd6b955f048ae0a2cd5f5005a460bfe/Screen-Shot-2018-03-29-at-10.59.43-AM.png" />
            
            </figure><p>To solve our TTL problem, we can use eBPF filter program. It will look at the TTL values of passing packets, and save them in an eBPF map. Later, we can inspect the eBPF map and analyze the recorded values from userspace.</p>
    <div>
      <h3>SO_ATTACH_BPF to rule the world!</h3>
      <a href="#so_attach_bpf-to-rule-the-world">
        
      </a>
    </div>
    <p>To use eBPF we need a number of things set up. First, we need to create an "eBPF map". There <a href="https://elixir.bootlin.com/linux/v4.15.13/source/include/uapi/linux/bpf.h#L99">are many specialized map types</a>, but for our purposes let's use the "hash" BPF_MAP_TYPE_HASH type.</p><p>We need to figure out the <i>"bpf(BPF_MAP_CREATE, map type, key size, value size, limit, flags)"</i> parameters. For our small TTL program, let's set 4 bytes for key size, and 8 byte value size. The max element limit is set to 5. It doesn't matter, we expect all the packets in one connection to have just one coherent TTL value anyway.</p><p>This is how it would look in a <a href="https://github.com/cloudflare/cloudflare-blog/blob/master/2018-03-ebpf/ebpf.go#L57">Golang code</a>:</p>
            <pre><code>bpfMapFd, err := ebpf.NewMap(ebpf.Hash, 4, 8, 5, 0)</code></pre>
            <p>A word of warning is needed here. BPF maps use the "locked memory" resource. With multiple BPF programs and maps, it's easy to exhaust the default tiny 64 KiB limit. Consider bumping this with <code>ulimit -l</code>, for example:</p>
            <pre><code>ulimit -l 10240</code></pre>
            <p>The <code>bpf()</code> syscall returns a file descriptor pointing to the kernel BPF map we just created. With it handy we can operate on a map. The possible operations are:</p><ul><li><p><code>bpf(BPF_MAP_LOOKUP_ELEM, &lt;key&gt;)</code></p></li><li><p><code>bpf(BPF_MAP_UPDATE_ELEM, &lt;key&gt;, &lt;value&gt;, &lt;flags&gt;)</code></p></li><li><p><code>bpf(BPF_MAP_DELETE_ELEM, &lt;key&gt;)</code></p></li><li><p><code>bpf(BPF_MAP_GET_NEXT_KEY, &lt;key&gt;)</code></p></li></ul><p>More on this later.</p><p>With the map created, we need to create a BPF program. As opposed to classical BPF - where the bytecode was a parameter to SO_ATTACH_FILTER - the bytecode is now loaded by the <code>bpf()</code> syscall. Specifically: <code>bpf(BPF_PROG_LOAD)</code>.</p><p>In our <a href="https://github.com/cloudflare/cloudflare-blog/blob/master/2018-03-ebpf/ebpf.go#L78-L131">Golang program the eBPF program setup</a> looks like:</p>
            <pre><code>ebpfInss := ebpf.Instructions{
	ebpf.BPFIDstOffSrc(ebpf.LdXW, ebpf.Reg0, ebpf.Reg1, 16),
	ebpf.BPFIDstOffImm(ebpf.JEqImm, ebpf.Reg0, 3, int32(htons(ETH_P_IPV6))),
	ebpf.BPFIDstSrc(ebpf.MovSrc, ebpf.Reg6, ebpf.Reg1),
	ebpf.BPFIImm(ebpf.LdAbsB, int32(-0x100000+8)),
...
	ebpf.BPFIDstImm(ebpf.MovImm, ebpf.Reg0, -1),
	ebpf.BPFIOp(ebpf.Exit),
}

bpfProgram, err := ebpf.NewProgram(ebpf.SocketFilter, &amp;ebpfInss, "GPL", 0)</code></pre>
            <p>Writing eBPF by hand is rather controversial. Most people use <code>clang</code> (from version 3.7 onwards) to compile a code written in a C dialect into an eBPF bytecode. The resulting bytecode is saved in an ELF file, which can be loaded by most eBPF libraries. This ELF file also includes description of maps, so you don’t need to set them manually.</p><p>I personally don't see the point in adding an ELF/clang dependency for simple SO_ATTACH_BPF snippets. Don't be afraid of the raw bytecode!</p>
    <div>
      <h3>BPF calling convention</h3>
      <a href="#bpf-calling-convention">
        
      </a>
    </div>
    <p>Before we go further we should highlight couple of things about the eBPF environment. The official kernel documentation isn't too friendly:</p><ul><li><p><a href="https://www.kernel.org/doc/Documentation/networking/filter.txt">Documentation/networking/filter.txt</a></p></li></ul><p>The first important bit to know, is the calling convention:</p><ul><li><p>R0 - return value from in-kernel function, and exit value for eBPF program</p></li><li><p>R1-R5 - arguments from eBPF program to in-kernel function</p></li><li><p>R6-R9 - callee saved registers that in-kernel function will preserve</p></li><li><p>R10 - read-only frame pointer to access stack</p></li></ul><p>When the BPF is started, R1 contains a pointer to <code>ctx</code>. This data structure <a href="https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L799">is defined as <code>struct __sk_buff</code></a>. For example, to access the <code>protocol</code> field you'd need to run:</p>
            <pre><code>r0 = *(u32 *)(r1 + 16)</code></pre>
            <p>Or in other words:</p>
            <pre><code>ebpf.BPFIDstOffSrc(ebpf.LdXW, ebpf.Reg0, ebpf.Reg1, 16),</code></pre>
            <p>Which is exactly what we do in first line of our program, since we need to choose between IPv4 or IPv6 code branches.</p>
    <div>
      <h3>Accessing the BPF payload</h3>
      <a href="#accessing-the-bpf-payload">
        
      </a>
    </div>
    <p>Next, there are special instructions for packet payload loading. Most BPF programs (but not all!) run in the context of packet filtering, so it makes sense to accelerate data lookups by having magic opcodes for accessing packet data.</p><p>Instead of dereferencing context, like <code>ctx-&gt;data[x]</code> to load a byte, BPF supports the <code>BPF_LD</code> instruction that can do it in one operation. There are caveats though, the documentation says:</p>
            <pre><code>eBPF has two non-generic instructions: (BPF_ABS | &lt;size&gt; | BPF_LD) and
(BPF_IND | &lt;size&gt; | BPF_LD) which are used to access packet data.

They had to be carried over from classic BPF to have strong performance of
socket filters running in eBPF interpreter. These instructions can only
be used when interpreter context is a pointer to 'struct sk_buff' and
have seven implicit operands. Register R6 is an implicit input that must
contain pointer to sk_buff. Register R0 is an implicit output which contains
the data fetched from the packet. Registers R1-R5 are scratch registers
and must not be used to store the data across BPF_ABS | BPF_LD or
BPF_IND | BPF_LD instructions.</code></pre>
            <p>In other words: before calling <code>BPF_LD</code> we must move <code>ctx</code> to R6, like this:</p>
            <pre><code>ebpf.BPFIDstSrc(ebpf.MovSrc, ebpf.Reg6, ebpf.Reg1),</code></pre>
            <p>Then we can call the load:</p>
            <pre><code>ebpf.BPFIImm(ebpf.LdAbsB, int32(-0x100000+7)),</code></pre>
            <p>At this stage the result is in r0, but we must remember the r1-r5 should be considered dirty. For an instruction the <code>BPF_LD</code> looks very much like a function call.</p>
    <div>
      <h3>Magical Layer 3 offset</h3>
      <a href="#magical-layer-3-offset">
        
      </a>
    </div>
    <p>Next note the load offset - we loaded the <code>-0x100000+7</code> byte of the packet. This magic offset is another BPF context curiosity. It turns out that the BPF script loaded under SO_ATTACH_BPF on a SOCK_STREAM (or SOCK_DGRAM) socket, will only see Layer 4 and higher OSI layers by default. To extract the TTL we need access to the layer 3 header (i.e. the IP header). To access L3 in the L4 context, we must offset the data lookups by magical -0x100000.</p><p>This magic constant <a href="https://github.com/torvalds/linux/blob/ead751507de86d90fa250431e9990a8b881f713c/include/uapi/linux/filter.h#L84">is defined in the kernel</a>.</p><p>For completeness, the <code>+7</code> is, of course, the offset of the TTL field in an IPv4 packet. Our small BPF program also supports IPv6 where the TTL/Hop Count is at offset <code>+8</code>.</p>
    <div>
      <h3>Return value</h3>
      <a href="#return-value">
        
      </a>
    </div>
    <p>Finally, the return value of the BPF program is meaningful. In the context of packet filtering it will be interpreted as a truncated packet length.Had we returned 0 - the packet would be dropped and wouldn't be seen by the userspace socket application. It's quite interesting that we can do packet-based data manipulation with eBPF on a stream-based socket. Anyway, our script returns -1, which when cast to unsigned will be interpreted as a very large number:</p>
            <pre><code>ebpf.BPFIDstImm(ebpf.MovImm, ebpf.Reg0, -1),
ebpf.BPFIOp(ebpf.Exit),</code></pre>
            
    <div>
      <h3>Extracting data from map</h3>
      <a href="#extracting-data-from-map">
        
      </a>
    </div>
    <p>Our running BPF program will set a key on our map for any matched packet. The key is the recorded TTL value, the value is the packet count. The value counter is somewhat vulnerable to a tiny race condition, but it's ignorable for our purposes. Later on, to extract the data from userspace program we use this Golang loop:</p>
            <pre><code>var (
	value   MapU64
	k1, k2  MapU32
)

for {
	ok, err := bpfMap.Get(k1, &amp;value, 8)
	if ok {
		// k1 is TTL, value is counter
		...
	}

	ok, err = bpfMap.GetNextKey(k1, &amp;k2, 4)
	if err != nil || ok == false {
		break
	}
	k1 = k2
}</code></pre>
            
    <div>
      <h3>Putting it all together</h3>
      <a href="#putting-it-all-together">
        
      </a>
    </div>
    <p>Now with all the pieces ready we can make it a proper runnable program. There is little point in discussing it here, so allow me to refer to the source code. The BPF pieces are here:</p><ul><li><p><a href="https://github.com/cloudflare/cloudflare-blog/blob/master/2018-03-ebpf/ebpf.go">ebpf.go</a></p></li></ul><p>We haven't discussed how to catch inbound SYN+ACK in the BPF program. This is a matter of setting up BPF before calling <code>connect()</code>. Sadly, it's impossible to customize <code>net.Dial</code> in Golang. Instead we wrote a surprisingly painful and awful custom Dial implementation. The ugly custom dialer code is here:</p><ul><li><p><a href="https://github.com/cloudflare/cloudflare-blog/blob/master/2018-03-ebpf/magic_conn.go">magic_conn.go</a></p></li></ul><p>To run all this you need kernel 4.4+ Kernel with the <code>bpf()</code> syscall compiled in. BPF features of specific kernels are documented in this superb page from BCC:</p><ul><li><p><a href="https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md">docs/kernel-versions.md</a></p></li></ul><p>Run the code to observe the TTL Hop Counts:</p>
            <pre><code>$ ./ttl-ebpf tcp4://google.com:80 tcp6://google.com:80 \
             tcp4://cloudflare.com:80 tcp6://cloudflare.com:80
[+] TTL distance to tcp4://google.com:80 172.217.4.174 is 6
[+] TTL distance to tcp6://google.com:80 [2607:f8b0:4005:809::200e] is 4
[+] TTL distance to tcp4://cloudflare.com:80 198.41.215.162 is 3
[+] TTL distance to tcp6://cloudflare.com:80 [2400:cb00:2048:1::c629:d6a2] is 3</code></pre>
            
    <div>
      <h3>Takeaways</h3>
      <a href="#takeaways">
        
      </a>
    </div>
    <p>In this blog post we dived into the new eBPF machinery, including the <code>bpf()</code> syscall, maps and SO_ATTACH_BPF. This work allowed me to realize the potential of running SO_ATTACH_BPF on fully established TCP sockets. Undoubtedly, eBPF still requires plenty of love and documentation, but it seems to be a perfect bridge to expose low level toggles to userspace applications.</p><p>I highly recommend keeping the dependencies small. For small BPF programs, like the one shown, there is little need for complex clang compilation and ELF loading. Don't be afraid of the eBPF bytecode!</p><p>We only touched on SO_ATTACH_BPF, where we analyzed network packets with BPF running on network sockets. There is more! First, you can attach BPFs to a dozen "things", XDP being the most obvious example. <a href="https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L119">Full list</a>. Then, it's possible to actually affect kernel packet processing, here is a <a href="https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L318">full list of helper functions</a>, some of which can modify kernel data structures.</p><p>In February <a href="https://lwn.net/Articles/747551/">LWN jokingly wrote</a>:</p>
            <pre><code>Developers should be careful, though; this could
prove to be a slippery slope leading toward something 
that starts to look like a microkernel architecture.</code></pre>
            <p>There is a grain of truth here. Maybe the ability to run eBPF on variety of subsystems feels like microkernel coding, but definitely the SO_ATTACH_BPF smells like <a href="https://en.wikipedia.org/wiki/STREAMS">STREAMS</a> programming model <a href="https://cseweb.ucsd.edu/classes/fa01/cse221/papers/ritchie-stream-io-belllabs84.pdf">from 1984</a>.</p><hr /><p>Thanks to <a href="https://twitter.com/akajibi">Gilberto Bertin</a> and <a href="https://twitter.com/dwragg">David Wragg</a> for helping out with the eBPF bytecode.</p><hr /><p><i>Doing eBPF work sound interesting? Join our </i><a href="https://boards.greenhouse.io/cloudflare/jobs/589572"><i>world famous team</i></a><i> in London, Austin, San Francisco, Champaign and our elite office in Warsaw, Poland</i>.</p> ]]></content:encoded>
            <category><![CDATA[TTL]]></category>
            <category><![CDATA[TCP]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[eBPF]]></category>
            <guid isPermaLink="false">6LTjo1ZkNHiWvy46IuloEd</guid>
            <dc:creator>Marek Majkowski</dc:creator>
        </item>
        <item>
            <title><![CDATA[2018 and the Internet: our predictions]]></title>
            <link>https://blog.cloudflare.com/our-predictions-for-2018/</link>
            <pubDate>Thu, 21 Dec 2017 14:01:43 GMT</pubDate>
            <description><![CDATA[ At the end of 2016, I wrote a blog post with seven predictions for 2017. Let’s start by reviewing how I did. I’ll score myself with two points for being correct, one point for mostly right and zero for wrong. That’ll give me a maximum possible score of fourteen. Here goes... ]]></description>
            <content:encoded><![CDATA[ <p>At the end of 2016, I wrote a blog post with <a href="/2017-and-the-internet-our-predictions/">seven predictions for 2017</a>. Let’s start by reviewing how I did.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7zM4Q6zRAwVRz7Ffh2YqQU/c936cf42bddbd81ed8e08337f85a9b66/35619461910_0bbc594bb0_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/publicdomain/mark/1.0/">Public Domain</a> <a href="https://www.flickr.com/photos/151136904@N08/35619461910/in/photolist-34owvg-btghyJ-8w5ywj-bgRUbx-TjZ1QE-bB7KBf-ZUn5LW-e5izhc-aBAQEp-ejkW44-Wgz44C-8LCN5-XgqZfJ-TUMEpF-qJqrch-aNq3ip-9p3jCx-n8ro7-4pw3M6-bVqgoC-j36Sp-cErE8q-VLLr-bVq9wd-bVqf6S-bVqa2f-bVq7TA-bVq7dw-9ddPw-wT8ipq">image</a> by <a href="https://www.flickr.com/photos/151136904@N08/">Michael Sharpe</a></p><p>I’ll score myself with two points for being correct, one point for mostly right and zero for wrong. That’ll give me a maximum possible score of fourteen. Here goes...</p><p><b>2017-1: 1Tbps DDoS attacks will become the baseline for ‘massive attacks’</b></p><p>This turned out to be true but mostly because massive attacks went away as Layer 3 and Layer 4 DDoS mitigation services got good at filtering out high bandwidth and high packet rates. Over the year we saw many DDoS attacks in the 100s of Gbps (up to 0.5Tbps) and then in September announced <a href="/unmetered-mitigation/">Unmetered Mitigation</a>. Almost immediately we saw attackers stop bothering to attack Cloudflare-protected sites with large DDoS.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7zYSDBhiRxTXxR0yDktc2T/bc77555ea56ce9c5b7482ef29501b618/syn.png" />
            
            </figure><p>So, I’ll be generous and give myself one point.</p><p><b>2017-2: The Internet will get faster yet again as protocols like QUIC become more prevalent</b></p><p>Well, yes and no. QUIC has become more prevalent as Google has widely deployed it in the Chrome browser and it accounts for about 7% of Internet traffic. At the same time the protocol is working its way through the IETF <a href="https://datatracker.ietf.org/wg/quic/about/">standardization process</a> and has yet to be deployed widely outside Google.</p><p>So, I’ll award myself one point for this as QUIC did progress but didn’t get as far as I thought.</p><p><b>2017-3: IPv6 will become the defacto for mobile networks and IPv4-only fixed networks will be looked upon as old fashioned</b></p><p>IPv6 continued <a href="https://www.employees.org/~dwing/aaaa-stats/">to grow throughout 2017</a> and seems to be on a pretty steady trajectory upwards. Although it’s not yet deployed on ¼ of the top 25,000 web sites. Note that the large jump in IPv6 support that occurred in the middle of 2016 when Cloudflare enabled it by default for all our customers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4nzOhssnadY4Nc5AbobgjB/166f7f858f5235b1c5835ecf95113077/ipv6.png" />
            
            </figure><p>The Internet Society <a href="https://www.internetsociety.org/resources/doc/2017/state-of-ipv6-deployment-2017/">reported</a> that mobile networks that switch to IPv6 see 70-95% of their traffic use IPv6. Google reports that traffic from Verizon is now 90% IPv6 and T-Mobile is <a href="http://www.rmv6tf.org/wp-content/uploads/2017/04/04-IPv6-NAv6TF-Langerholm-1.pdf">turning off IPv4 completely</a>.</p><p>Here I’ll award myself two points.</p><p><b>2017-4: A SHA-1 collision will be announced</b></p><p>That happened on 23 February 2017 with the announcement of an <a href="https://shattered.io/">efficient way to generate colliding</a> PDF documents. It’s so efficient that here are two PDFs containing the old and new Cloudflare logos. I generated these two PDFs using a <a href="https://alf.nu/SHA1">web site</a> that takes two JPEGs, embeds them in two PDFs and makes them collide. It does this instantly.</p>
            <figure>
            <a href="https://github.com/jgrahamc/sha1collision/raw/master/b.pdf">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/23mueESj493cBGzcNqwCR4/82fd43f492925db82b3a7e1e650bddee/new-cf.jpg" />
            </a>
            </figure>
            <figure>
            <a href="https://github.com/jgrahamc/sha1collision/raw/master/a.pdf">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1zhhwfkFHSuCtBxXl2Ga4A/860eb9de58805669baae35c8cb2c8738/old-cf.jpg" />
            </a>
            </figure><p>They have the same SHA-1 hash:</p>
            <pre><code>$ shasum *.pdf
e1964edb8bcafc43de6d1d99240e80dfc710fbe1  a.pdf
e1964edb8bcafc43de6d1d99240e80dfc710fbe1  b.pdf</code></pre>
            <p>But different SHA-256 hash:</p>
            <pre><code>$ shasum -a256 *.pdf
8e984df6f4a63cee798f9f6bab938308ebad8adf67daba349ec856aad07b6406  a.pdf
f20f44527f039371f0aa51bc9f68789262416c5f2f9cefc6ff0451de8378f909  b.pdf</code></pre>
            <p>So, two points for getting that right (and thanks, <a href="/author/nick-sullivan/">Nick Sullivan</a>, for suggesting it and making me look smart).</p><p><b>2017-5: Layer 7 attacks will rise but Layer 6 won’t be far behind</b></p><p>The one constant of 2017 in terms of DDoS was the prevalence of Layer 7 attacks. Even as attackers decided that large scale Layer 3 and 4 DDoS attacks were being mitigated easily and hence stopped performing them so frequently, Layer 7 attacks continued apace with attacks in the 100s of krps common place.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6QV18HDWFkCyFAqEtQqeOr/05cb31c14e35b00481f5d745f0eb92d8/layer7.png" />
            
            </figure><p>Awarding myself one point because Layer 6 attacks didn’t materialize as much as predicted.</p><p><b>2017-6: Mobile traffic will account for 60% of all Internet traffic by the end of the year</b></p><p>Ericsson reported mid-year that <a href="https://www.ericsson.com/assets/local/mobility-report/documents/2017/ericsson-mobility-report-june-2017.pdf">mobile data traffic was continuing to grow strongly</a> and grew 70% between Q116 and Q117. Stats show that while mobile traffic <a href="https://www.statista.com/statistics/277125/share-of-website-traffic-coming-from-mobile-devices/">continued to increase its share</a> of Internet traffic and passed 50% in 2017 it didn’t reach 60%.</p><p>Zero points for me.</p><p><b>2017-7: The security of DNS will be taken seriously</b></p><p>This has definitely happened. The 2016 Dyn DNS attack was a wake up call that often overlooked infrastructure was at risk of DDoS attack. In April 2017 Wired reported that hackers took over 36 Brazilian banking web sites by <a href="https://www.wired.com/2017/04/hackers-hijacked-banks-entire-online-operation/">hijacking DNS registration</a>, and in June Mozilla and ICANN proposed <a href="https://tools.ietf.org/html/draft-hoffman-dns-over-https-01">encrypting DNS by sending it over HTTPS</a> and the IETF has a <a href="https://datatracker.ietf.org/wg/doh/about/">working group</a> on what’s now being called doh.</p><p>DNSSEC deployment continued with <a href="http://secspider.verisignlabs.com/growth.html">SecSpider</a> showing steady, continuous growth during 2017.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/BnqRCq5jI93WRfoaGy1k3/2f59c7cfe8687d6c43dfdced049ae74b/growth.png" />
            
            </figure><p>So, two points for me.</p><p>Overall, I scored myself a total of 9 out of 14, or 64% right. With that success rate in mind here are my predictions for 2018.</p>
    <div>
      <h2>2018 Predictions</h2>
      <a href="#2018-predictions">
        
      </a>
    </div>
    <p><a href="#20181"></a><b>2018-1: By the end of 2018 more than 50% of HTTPS connections will happen over TLS 1.3</b></p><p>The roll out of TLS 1.3 has been stalled because of difficulty in getting it working correctly in the heterogenous Internet environment. Although Cloudflare has had <a href="/introducing-tls-1-3/">TLS 1.3 in production and available for all customers for over a year</a> only 0.2% of our traffic is currently using that version.</p><p>Given the state of <a href="https://blog.apnic.net/2017/12/12/internet-protocols-changing/">standardization</a> of TLS 1.3 today we believe that major browser vendors will enable TLS 1.3 during 2018 and by the end of the year more than 50% of HTTPS connections will be using the latest, most secure version of TLS.</p><p><a href="#20182"></a><b>2018-2: Vendor lock-in with Cloud Computing vendors becomes dominant worry for enterprises</b></p><p>In Mary Meeker’s 2017 Internet Trends report she <a href="http://www.kpcb.com/internet-trends">gives on statistics</a> (slide 183) on the top three concerns of users of cloud computing. These show a striking change from being primarily about security and cost to worries about vendor lock-in and compliance. Cloudflare believes that vendor lock-in will become the top concern of users of cloud computing in 2018 and that multi-cloud strategies will become common.</p><p><a href="https://www.billforward.net/">BillForward</a> is already taking a <a href="/living-in-a-multi-cloud-world/">multi-cloud approach</a> with Cloudflare moving traffic dynamically between cloud computing providers. Alongside vendor lock-in, users will name data portability between clouds as a top concern.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5gEvIINYt655HbsC7TbZQ5/223c737aeda1ef5328b0c892a293eb7c/Mary-Meeker-Internet-Trends-2017.png" />
            
            </figure><p><a href="#20183"></a><b>2018-3: Deep learning hype will subside as self-driving cars don't become a reality but AI/ML salaries will remain high</b></p><p>Self-driving cars won’t become available in 2018, but AI/ML will remain red hot as every technology company tries to hire appropriate engineering staff and finds they can’t. At the same time <a href="https://www.cloudflare.com/learning/ai/what-is-deep-learning/">deep learning techniques</a> will be widely applied across companies and industries as it becomes clear that these techniques are <a href="http://learningsys.org/nips17/assets/slides/dean-nips17.pdf">not limited</a> to game playing, classification, or translation tasks and can be widely applied.</p><p>Expect unexpected applications of techniques, that are already in use in Silicon Valley, when they are applied to the rest of the world. Don’t be surprised if there’s talk of AI/ML managed traffic management for highways, for example. Anywhere there's a heuristic we'll see AI/ML applied.</p><p>But it’ll take another couple of years for AI/ML to really have profound effects. By 2020 the talent pool will have greatly increased and manufacturers such as Qualcomm, nVidia and Intel will have followed Google’s lead and produced specialized chipsets designed for deep learning and other ML techniques.</p><p><a href="#20184"></a><b>2018-4: k8s becomes the dominant platform for cloud computing</b></p><p>A corollary to users’ concerns about cloud vendor lock-in and the need for multi-cloud capability is that an orchestration framework will dominate. We believe that Kubernetes will be that dominant platform and that large cloud vendors will work to ensure compatibility across implementations at the demand of customers.</p><p>We are currently in the infancy of k8s deployment with the major cloud computing vendors deploying incompatible versions. We believe that customer demand for portability will cause cloud computer vendors to ensure compatibility.</p><p><a href="#20185"></a><b>2018-5: Quantum resistant crypto will be widely deployed in machine-to-machine links across the internet</b></p><p>During 2017 Cloudflare experimented with, and open sourced, <a href="/sidh-go/">quantum-resistant cryptography</a> as part of our implementation of TLS 1.3. Today there is a threat to the security of Internet protocols from quantum computers, and although the threat has not been realized, cryptographers are working on cryptographic schemes that will resist attacks from quantum computers when they arrive.</p><p>We predict that quantum-resistant cryptography will become widespread in links between machines and data centers especially where the connections being encrypted cross the public Internet. We don’t predict that quantum-resistant cryptography will be widespread in browsers, however.</p><p><a href="#20186"></a><b>2018-6: Mobile traffic will account for 60% of all Internet traffic by the end of the year</b></p><p>Based on the continued trend upwards in mobile traffic I’m predicting that 2018 (instead of 2017) will be the year mobile traffic shoots past 60% of overall Internet traffic. Fingers crossed.</p><p><a href="#20187"></a><b>2018-7: Stable BTC/USD exchanges will emerge as others die off from security-based Darwinism</b></p><p>The meteoric rise in the Bitcoin/USD exchange rate has been accompanied by a drumbeat of stories about stolen Bitcoins and failing exchanges. We believe that in 2018 the entire Bitcoin ecosystem will stabilize.</p><p>This will partly be through security-based Darwinism as trust in exchanges and wallets that have security problems plummets and those that survive have developed the scale and security to cope with the explosion in Bitcoin transactions and attacks on their services.</p> ]]></content:encoded>
            <category><![CDATA[DDoS]]></category>
            <category><![CDATA[Attacks]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[Mobile]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[TLS]]></category>
            <guid isPermaLink="false">1aBngzXy6aFhIPVDlFBCdH</guid>
            <dc:creator>John Graham-Cumming</dc:creator>
        </item>
        <item>
            <title><![CDATA[Less Is More - Why The IPv6 Switch Is Missing]]></title>
            <link>https://blog.cloudflare.com/always-on-ipv6/</link>
            <pubDate>Thu, 25 May 2017 17:30:00 GMT</pubDate>
            <description><![CDATA[ At Cloudflare we believe in being good to the Internet and good to our customers. By moving on from the legacy world of IPv4-only to the modern-day world where IPv4 and IPv6 are treated equally, we believe we are doing exactly that. ]]></description>
            <content:encoded><![CDATA[ <p>At Cloudflare we believe in being good to the Internet and good to our customers. By moving on from the legacy world of IPv4-only to the modern-day world where IPv4 and IPv6 are treated equally, we believe we are doing exactly that.</p><p><i>"No matter what happens in life, be good to people. Being good to people is a wonderful legacy to leave behind."</i> - Taylor Swift (whose website has been IPv6 enabled for many many years)</p><p>Starting today with free domains, IPv6 is no longer something you can toggle on and off, it’s always just on.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6UqOfN1xF7mt0PpJ1BbVCy/2d645cfd651e7722c6c0790f039a0aa0/before-after-ipv6.png" />
            
            </figure>
    <div>
      <h3>How we got here</h3>
      <a href="#how-we-got-here">
        
      </a>
    </div>
    <p>Cloudflare has always been a gateway for visitors on IPv6 connections to access sites and applications hosted on legacy IPv4-only infrastructure. Connections to Cloudflare are terminated on either IP version and then proxied to the backend over whichever IP version the backend infrastructure can accept.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7w5o9faqmZFjQSgXnYIVIP/49472b8b1f3eebc0682f3d7fd67eb4fb/ipv4-ipv6-translation-gateway.png" />
            
            </figure><p>That means that a v6-only mobile phone (looking at you, T-Mobile users) can establish a clean path to any site or mobile app behind Cloudflare instead of doing an expensive 464XLAT protocol translation as part of the connection (shaving milliseconds and conserving very precious battery life).</p><p>That IPv6 gateway is set by a simple toggle that for a while now has been default-on. And to make up for the time lost before the toggle was default on, in August 2016 we went back retroactively and enabled IPv6 for those millions of domains that joined before IPv6 was the default. Over those next few months, we <a href="/98-percent-ipv6/">enabled IPv6 for nearly four million domains</a> –– you can see Cloudflare’s <a href="https://www.vyncke.org/ipv6status/plotsite.php?metric=w&amp;global=legacy&amp;pct=y">dent in the IPv6 universe</a> below –– and by the time we were done, 98.1% of all of our domains had IPv6 connectivity.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1yqnG0ahmUyEnfeUjLrqOi/083db64874e3322e8080e0c44183722e/plotsite.png" />
            
            </figure><p>As an interim step, we added an extra feature –– when you turn off IPv6 in our dashboard, we remind you just how archaic we think that is.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3oXyg84nb4l00KrDpmbrez/e7828711f44a4cf0fe78d16277d912be/modal.png" />
            
            </figure><p>With close to 100% IPv6 enablement, it no longer makes sense to offer an IPv6 toggle. Instead, Cloudflare is offering IPv6 always on, with no off-switch. We’re starting with free domains, and over time we’ll change the toggle on the rest of Cloudflare paid-plan domains.</p>
    <div>
      <h3>The Future: How Cloudflare and OpenDNS are working together to make IPv6 even faster and more globally deployed</h3>
      <a href="#the-future-how-cloudflare-and-opendns-are-working-together-to-make-ipv6-even-faster-and-more-globally-deployed">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6NjiPMVo4MsctGZW2P7RvI/b9dc657c93e35a5f7955b1378f1da61c/logos.png" />
            
            </figure><p>In November <a href="/98-percent-ipv6/">we published stats about the IPv6 usage</a> we see on the Cloudflare network in an attempt to answer who and what is pushing IPv6. The top operating systems by percent IPv6 traffic are iOS, ChromeOS, and MacOS respectively. These operating systems push significantly more IPv6 traffic than their peers because they use a routing choice algorithm called Happy Eyeballs. Happy Eyeballs opportunistically chooses IPv6 when available by doing two <a href="https://www.cloudflare.com/learning/dns/what-is-dns/">DNS</a> lookups –– one for an IPv6 address (this IPv6 address is stored in the DNS AAAA record - pronounced quad-A) and then one for the IPv4 address (stored in the DNS A record). Both DNS queries are flying over the Internet at the same time and the client chooses the address that comes back first. The client even gives IPv6 a few milliseconds head start (iOS and MacOS give IPv6 lookups a 25ms head start for example) so that IPv6 may be chosen more often. This works and has fueled some of IPv6’s growth. But it has fallen short of the goal of a 100% IPv6 world.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/27vp45uqt2lIMVqjzndv86/f6136dbc91d329894a131433df044bfb/A-AAAA.png" />
            
            </figure><p>While there are perfectly good historical reasons why IPv6 and IPv4 addresses are stored in separate DNS types, today clients are IP version agnostic and it no longer makes sense for it to require two separate round trips to learn what addresses are available to fetch a resource from.</p><p>Alongside OpenDNS, we are testing a new idea - what if you could ask for all the addresses in just one DNS query?</p><p>With OpenDNS, we are prototyping and testing just that –– a new DNS metatype that returns all available addresses in one DNS answer –– A records and AAAA records in one response. (A metatype is a query type in DNS that end users can’t add into their DNS zone file, it’s assembled dynamically by the authoritative nameserver.)</p><p>What this means is that in the future if a client like an iPhone wants to access a mobile app that uses Cloudflare DNS or using another DNS provider that supports the spec, the iPhone DNS client would only need to do one DNS lookup to find where the app’s API server is located, cutting the number of necessary round trips in half.</p><p>This reduces the amount of bandwidth on the DNS system, and pre-populates global DNS caches with IPv6 addresses, making IPv6 lookups faster in the future, with the side benefit that Happy Eyeballs clients prefer IPv6 when they can get the address quickly, which increases the amount of IPv6 traffic that flows through the Internet.</p><p>We have the metaquery working in code with the reserved TYPE65535 querytype. You can ask a Cloudflare nameserver for TYPE65535 of any domain on Cloudflare and get back all available addresses for that name.</p>
            <pre><code>$ dig cloudflare.com @ns1.cloudflare.com -t TYPE65535 +short
198.41.215.162
198.41.214.162
2400:cb00:2048:1::c629:d6a2
2400:cb00:2048:1::c629:d7a2
$</code></pre>
            <p>Did we mention Taylor Swift earlier?</p>
            <pre><code>$ dig taylorswift.com @ns1.cloudflare.com -t TYPE65535 +short
104.16.193.61
104.16.194.61
104.16.191.61
104.16.192.61
104.16.195.61
2400:cb00:2048:1::6810:c33d
2400:cb00:2048:1::6810:c13d
2400:cb00:2048:1::6810:bf3d
2400:cb00:2048:1::6810:c23d
2400:cb00:2048:1::6810:c03d
$</code></pre>
            <p>We believe in proving concepts in code and through the <a href="https://ietf.org/">IETF</a> standards process. We’re currently working on an experiment with OpenDNS and will translate our learnings to an Internet Draft we will submit to the IETF to become an RFC. We’re sure this is just the beginning to faster, better deployed IPv6.</p> ]]></content:encoded>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[OpenDNS]]></category>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[Reliability]]></category>
            <guid isPermaLink="false">6GuglMyL4s8AnqoL9NOliF</guid>
            <dc:creator>Dani Grant</dc:creator>
        </item>
        <item>
            <title><![CDATA[98.01% of sites on Cloudflare now use IPv6]]></title>
            <link>https://blog.cloudflare.com/98-percent-ipv6/</link>
            <pubDate>Mon, 21 Nov 2016 14:14:46 GMT</pubDate>
            <description><![CDATA[ It's 2016 and almost every site using Cloudflare (more than 4 million of them) is using IPv6. Cloudflare sees significant IPv6 traffic globally where networks have enabled IPv6 to the consumer. ]]></description>
            <content:encoded><![CDATA[ <p>It's 2016 and almost every site using Cloudflare (more than 4 million of them) is using IPv6. Because of this, Cloudflare sees significant IPv6 traffic globally where networks have enabled IPv6 to the consumer.</p><p>The top IPv6 networks are shown here.</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/cloudflare-ipv6-percentage-vs-traffic.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/Gfc6hlj4FtLgaCXSKUIYC/000d16623fe3eabcef6ea100ef8ae4bb/cloudflare-ipv6-percentage-vs-traffic.png" />
            </a>
            </figure><p>The chart shows the percentage of IPv6 within a specific network vs. the relative bandwidth of that network. We will talk about specific networks below.</p>
    <div>
      <h3>Why IPv6? Because fast internet.</h3>
      <a href="#why-ipv6-because-fast-internet">
        
      </a>
    </div>
    <p>IPv6 is faster for two reasons. The first is that many major operating systems and browsers like <a href="https://www.ietf.org/mail-archive/web/v6ops/current/msg22455.html">iOS, macOS</a>, <a href="https://tools.ietf.org/html/rfc6555">Chrome and Firefox</a> impose anywhere from a 25ms to 300ms <a href="https://tools.ietf.org/html/rfc6555">artificial delay</a> on connections made over IPv4. The second is that some mobile networks won’t need to perform extra v4 → v6 and v6 → v4 translations to connect visitors to IPv6 enabled sites if the phone is only assigned an IPv6 address. (IPv6-only phones are becoming very common. If you have a phone on T-Mobile, Telstra, SK Telecom, Orange, or EE UK, to name a few, it’s likely you’re v6-only.)</p><p>How much faster is IPv6? Our data shows that visitors connecting over IPv6 were able to connect and load pages in 27% less time than visitors connecting over IPv4. LinkedIn found an even more dramatic effect, with up to a <a href="https://www.linkedin.com/pulse/ipv6-measurements-zaid-ali-kahn">40% performance boost</a> on mobile connections over IPv6. Facebook also found a significant performance increase, around <a href="https://code.facebook.com/posts/1192894270727351/ipv6-it-s-time-to-get-on-board/">10-15% on IPv6</a>.</p>
    <div>
      <h3>Who and what is driving IPv6?</h3>
      <a href="#who-and-what-is-driving-ipv6">
        
      </a>
    </div>
    <p>IPv6 is clearly important for driving a faster, better internet, so who is driving IPv6 adoption?</p><p>In terms of countries, Belgium leads by a mile. Over the last 30 days, 56.47% of traffic (in bytes) to Belgians on Cloudflare has been over IPv6. This is largely due to Telenet, an ISP in Belgium, doing almost 96.8% of their traffic over IPv6!</p><ol><li><p>Belgium, 56.47%</p></li><li><p>Ireland, 31.75%*</p></li><li><p>Greece, 20.79%</p></li><li><p>Germany, 15.87%</p></li><li><p>Ecuador, 15.62%</p></li><li><p>Luxembourg, 15.51%</p></li><li><p>Portugal, 14.07%</p></li><li><p>Estonia, 13.75%</p></li><li><p>India, 11.84%</p></li><li><p>Peru, 10.57%</p></li></ol><p>*The Irish numbers are artificially high due to <a href="http://bgp.he.net/search?search%5Bsearch%5D=facebook">several of Facebook’s IPv6 ranges being registered in Ireland</a>. Facebook does an enormous amount of traffic over IPv6 –– 81% of Facebook’s traffic through Cloudflare is IPv6. In fact, Facebook’s crawling over IPv6 actually accounts for 6.9% of Cloudflare’s total outbound IPv6 traffic.</p><p>If you look just 6 months ago, less than 1% of India’s traffic was over IPv6. India has experienced an amazing rise in IPv6 connectivity, especially over the last month and a half.</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/Screen-Shot-2016-11-15-at-4.29.22-PM.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/33dr4KAHjtOR7C4gntej7n/81780422e6745b0a0b9404a5fe1576f6/Screen-Shot-2016-11-15-at-4.29.22-PM.png" />
            </a>
            </figure><p>The US is ranked 17th on the global list at 8.78%. And since we have a Canadian co-founder (and three Canadian PoPs), it hasn’t gone unnoticed at Cloudflare that Canada is just beating the US in 16th place at 9.14%.</p><p>A handful of networks are responsible for the majority of IPv6 traffic through Cloudflare. In fact, the top 10 networks by IPv6 traffic to and from Cloudflare are responsible for over half (55.4%) of Cloudflare’s IPv6 traffic. Those networks are:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/Screen-Shot-2016-11-16-at-2.56.58-PM.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1o79gdePPcYaejhm5OIhv6/be78b3e338e79f6258dee2cfde6bac43/Screen-Shot-2016-11-16-at-2.56.58-PM.png" />
            </a>
            </figure><p>The above chart shows which networks account for the highest percentage of IPv6 traffic through Cloudflare. In terms of which networks are promoting IPv6 on their own network traffic, these are the networks Cloudflare sees with the highest ratios of IPv6 to IPv4 traffic:</p><table><tr><td><p><b>#</b></p></td><td><p><b>IPv6 %</b></p></td><td><p><b>ASN</b></p></td><td><p><b>NAME</b></p></td></tr><tr><td><p>1</p></td><td><p>100.0%</p></td><td><p>AS43447</p></td><td><p>Orange Polska</p></td></tr><tr><td><p>2</p></td><td><p>100.0%</p></td><td><p>AS23910</p></td><td><p>China Next Generation Internet CERNET2</p></td></tr><tr><td><p>3</p></td><td><p>100.0%</p></td><td><p>AS17419</p></td><td><p>HiNet IPv6 (Taiwan)</p></td></tr><tr><td><p>4</p></td><td><p>96.8%</p></td><td><p>AS6848</p></td><td><p>Telenet (Belgium)</p></td></tr><tr><td><p>5</p></td><td><p>91.5%</p></td><td><p>AS12271</p></td><td><p>Time Warner Cable</p></td></tr><tr><td><p>6</p></td><td><p>88.9%</p></td><td><p>AS3651</p></td><td><p>Sprint</p></td></tr><tr><td><p>7</p></td><td><p>81.0%</p></td><td><p>AS32934</p></td><td><p>Facebook</p></td></tr><tr><td><p>8</p></td><td><p>74.0%</p></td><td><p>AS54500</p></td><td><p>EGIHosting</p></td></tr><tr><td><p>9</p></td><td><p>65.9%</p></td><td><p>AS21321</p></td><td><p>Areti Internet</p></td></tr><tr><td><p>10</p></td><td><p>63.9%</p></td><td><p>AS3598</p></td><td><p>Microsoft</p></td></tr><tr><td><p>11</p></td><td><p>61.8%</p></td><td><p>AS4250</p></td><td><p>Alentus</p></td></tr><tr><td><p>12</p></td><td><p>60.3%</p></td><td><p>AS21928</p></td><td><p>T-Mobile USA</p></td></tr><tr><td><p>13</p></td><td><p>58.8%</p></td><td><p>AS22394</p></td><td><p>Verizon Wireless</p></td></tr><tr><td><p>14</p></td><td><p>57.6%</p></td><td><p>AS18126</p></td><td><p>Chubu Telecommunications Company</p></td></tr><tr><td><p>15</p></td><td><p>48.5%</p></td><td><p>AS5607</p></td><td><p>Sky (UK)</p></td></tr><tr><td><p>16</p></td><td><p>47.8%</p></td><td><p>AS16591</p></td><td><p>Google Fiber</p></td></tr><tr><td><p>17</p></td><td><p>44.6%</p></td><td><p>AS133481</p></td><td><p>AIS Fibre (Thailand)</p></td></tr><tr><td><p>18</p></td><td><p>43.6%</p></td><td><p>AS7018</p></td><td><p>AT&amp;T</p></td></tr><tr><td><p>19</p></td><td><p>43.3%</p></td><td><p>AS6621</p></td><td><p>Hughes Network Systems</p></td></tr><tr><td><p>20</p></td><td><p>43.2%</p></td><td><p>AS15943</p></td><td><p>wilhelm.tel GmbH Norderstedt</p></td></tr></table><p>In terms of devices, mobile traffic is 50% more likely to use IPv6 than desktop traffic (21.4% of mobile traffic uses IPv6 traffic, whereas only 13.6% of desktop traffic is over IPv6).</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/Screen-Shot-2016-11-15-at-4.40.29-PM.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5m77EbJMCOtPQDZXENxGie/30f33fa5aaf285702b06efab91b25402/Screen-Shot-2016-11-15-at-4.40.29-PM.png" />
            </a>
            </figure><p>In mobile, iOS sends slightly more traffic than Android over IPv6, with iOS sending about a quarter of its traffic (23.5%) and Android sending about one fifth (18.7%).</p><p>For Windows, the newer the OS, the more traffic it sends over IPv6, with XP (2001) sending just 1.1% of requests over IPv6 and Windows 10 (2015) sending 18.7%, almost a fifth of all requests over IPv6.</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/Screen-Shot-2016-11-15-at-3.25.02-PM.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/11qopJH2aqMhCjlPCX6zZu/ad54713703d8eab7c29f2882659287af/Screen-Shot-2016-11-15-at-3.25.02-PM.png" />
            </a>
            </figure><p>Here’s the full breakdown of browsers and operating systems to explain the effect of OS and browser on the percentage of IPv6 traffic. In it, you can see some interesting things, for example, iOS and ChromeOS apps tend to use IPv6 a lot more than other operating systems. Also, Chrome on mobile sends about twice as much IPv6 traffic than Chrome on desktop.</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/Screen-Shot-2016-11-15-at-4.12.19-PM.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3VbCf50ROlGFxsFaRzLCy9/96b64e98522ab7e3fa574ae0a82f1e4b/Screen-Shot-2016-11-15-at-4.12.19-PM.png" />
            </a>
            </figure>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/Screen-Shot-2016-11-15-at-4.07.32-PM.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/19jQCF3xGUoAOwUHS8i7Fh/d321d0cbd90a40178f2468dcbe87d0fa/Screen-Shot-2016-11-15-at-4.07.32-PM.png" />
            </a>
            </figure><p>Below you can see the net effect of using a specific browser or operating system on IPv6 traffic:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/effect-2.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/58ZZ9nTaYFemmvGCb6IWlY/d8f026b8621a204445d3da438a9a5cd8/effect-2.png" />
            </a>
            </figure><p>Even more interesting is that while only 10.97% of our total DNS traffic is over IPv6, 22.03% of our DNS packet floods are IPv6 as well as IPv4 (we see no IPv6-only attacks, all the attacks we see on IPv6 are also seen on IPv4).</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/Screen-Shot-2016-11-16-at-2.06.20-PM.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/77F3ATcp7zVdiI7RynKXaq/db18ace81134e4e286a5d375e155712f/Screen-Shot-2016-11-16-at-2.06.20-PM.png" />
            </a>
            </figure>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/dns-packet-floods.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5KuI9yTKtRmvnPBo0rQ7ll/f2e6af0b3e2dcfd443ec3127a869df6c/dns-packet-floods.png" />
            </a>
            </figure>
    <div>
      <h2>Making the push for IPv6</h2>
      <a href="#making-the-push-for-ipv6">
        
      </a>
    </div>
    <p>At Cloudflare, we weren’t happy with only hundreds of thousands of IPv6-enabled websites. We wanted the millions and millions of Cloudflare customers to have IPv6. Over the last few months, we have been carefully enabling IPv6 for around 100,000 sites a day, all the time monitoring how our systems operated and how our traffic behaved. We also monitored customer support and of course, social media.</p><p>People noticed. People were happy. People posted what they saw!</p>
            <figure>
            <a href="https://www.facebook.com/groups/2234775539/permalink/10154502857425540/">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2zk7ldYLMuufHuBoIV0ZP0/bad69a7358c3e9d17071e4710123aaed/Screen-Shot-2016-11-20-at-11.26.46-PM.png" />
            </a>
            </figure><p>Some with a long range view:</p><blockquote><p>there is rapid growth in number of AAAA websites from 76K (08/2016) to 109K (10/2016) (source <a href="https://twitter.com/dan_wing">@dan_wing</a> dataset: <a href="https://t.co/CRzN5TweKz">https://t.co/CRzN5TweKz</a> ) <a href="https://t.co/0KNhqBMFsS">pic.twitter.com/0KNhqBMFsS</a></p><p>— Vaibhav Bajpai (@bajpaivaibhav) <a href="https://twitter.com/bajpaivaibhav/status/791181419913572352">October 26, 2016</a></p></blockquote><p>Some zoomed into the last few months:</p><blockquote><p>there is rapid growth in number of AAAA websites from 76K (08/2016) to 134K (11/2016) (source <a href="https://twitter.com/dan_wing">@dan_wing</a> dataset: <a href="https://t.co/CRzN5TweKz">https://t.co/CRzN5TweKz</a>) <a href="https://t.co/ygFEVSNSps">pic.twitter.com/ygFEVSNSps</a></p><p>— Vaibhav Bajpai (@bajpaivaibhav) <a href="https://twitter.com/bajpaivaibhav/status/798558510086836224">November 15, 2016</a></p></blockquote><p>In both of the above graphs, you can really see the impact of Cloudflare enabling IPv6 for all of our customers’ sites, starting in August and wrapping up this week. Below is one more public measurement from <a href="https://www.vyncke.org/ipv6status/plotsite.php?metric=w&amp;global=y&amp;pct=y">Eric Vyncke</a> where you can see the effect on world IPv6 measurements:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/11/plotsite-2016-11-21-1.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Q3XTCyc5YRUDIMEABnWHn/2089b5485a6c3b859de0b894277b7bcb/plotsite-2016-11-21-1.png" />
            </a>
            </figure>
    <div>
      <h3>The IETF and IPv6</h3>
      <a href="#the-ietf-and-ipv6">
        
      </a>
    </div>
    <p>As of a late 2016, the IETF’s Internet Architecture Board has taken one more step in its path towards v6 adoption. It's taken the bold step of saying that <a href="https://www.iab.org/2016/11/07/iab-statement-on-ipv6/">new protocols don't need to be v4 backward compatible</a>. This can usher-in some great new protocol designs and solutions that simply don't need to live in v4's <a href="https://tools.ietf.org/html/draft-howard-sunset4-v4historic-00">legacy world</a>. At Cloudflare, we've always been aggressive with our desire to provide our customers cutting edge solutions. We can't wait to see what's cooking!</p>
    <div>
      <h3>The growing IPv6 address usage</h3>
      <a href="#the-growing-ipv6-address-usage">
        
      </a>
    </div>
    <p>Along with the increased bandwidth observed, at Cloudflare, we are seeing a solid increase in unique IPv6 addresses seen.</p><blockquote><p>In June number of IPv6 addresses (/64 masked) crossed IPv4 addresses connecting to <a href="https://twitter.com/Cloudflare">@CloudFlare</a> for the first time. <a href="https://t.co/eTPFNoueHQ">pic.twitter.com/eTPFNoueHQ</a></p><p>— Matthew Prince (@eastdakota) <a href="https://twitter.com/eastdakota/status/765699957449895936">August 17, 2016</a></p></blockquote>
    <div>
      <h3>Final thoughts</h3>
      <a href="#final-thoughts">
        
      </a>
    </div>
    <p>Cloudflare is <a href="/evenly-distributed-future/">committed</a> to bringing the most up to date, fastest and most secure technologies to our customers. We are committed to IPv6, <a href="/tls-1-3-overview-and-q-and-a/">TLS 1.3</a> and <a href="/introducing-universal-dnssec/">ubiquitous DNSSEC</a>. Just like we'd never go back to an unencrypted life, there's no going back to a v4-only world.</p><p>PS - Want to live an IPv6 life? We’re <a href="https://www.cloudflare.com/join-our-team/">hiring</a>.</p><p><i>Big thanks to Dani Grant, Igor Postelnik, Lukasz Mierzwa and Marty Strong.</i></p> ]]></content:encoded>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IPv6]]></category>
            <guid isPermaLink="false">45IUNYDWNgQ5Fw1Ci96Mwb</guid>
            <dc:creator>Martin J Levy</dc:creator>
        </item>
        <item>
            <title><![CDATA[Supporting the transition to IPv6-only networking services for iOS]]></title>
            <link>https://blog.cloudflare.com/supporting-the-transition-to-ipv6-only-networking-services-for-ios/</link>
            <pubDate>Tue, 07 Jun 2016 18:55:29 GMT</pubDate>
            <description><![CDATA[ Early last month Apple announced that all apps submitted to the Apple Store June 1 forward would need to support IPv6-only networking as they transition to IPv6-only network services in iOS 9.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Early last month Apple announced that all apps submitted to the Apple Store June 1 forward would need to support IPv6-only networking as they transition to IPv6-only network services in iOS 9. <a href="https://developer.apple.com/news/?id=05042016a">Apple reports</a> that “Most apps will not require any changes”, as these existing apps support IPv6 through Apple's <a href="https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSession_class/">NSURLSession</a> and <a href="https://developer.apple.com/library/mac/documentation/Networking/Conceptual/CFNetwork/Introduction/Introduction.html">CFNetwork</a> APIs.</p><p>Our goal with IPv6, and any other emerging networking technology, is to make it ridiculously easy for our customers to make the transition. Over 2 years ago, we published <a href="/eliminating-the-last-reasons-to-not-enable-ipv6/">Eliminating the last reasons to not enable IPv6</a> in celebration of World IPv6 Day. CloudFlare has been offering full IPv6 support as well as our IPv6-to-IPv4 gateway to all of our customers since 2012.</p>
    <div>
      <h2>Why is the transition happening?</h2>
      <a href="#why-is-the-transition-happening">
        
      </a>
    </div>
    <p>IPv4 represents a technical limitation, a hard stop to the number of devices that can access the Internet. When the Internet Protocol (IP) was first introduced by Vint Cerf and Bob Kahn in the late 1970s, Internet Protocol Version 4 (IPv4) used a 32-bit (four-byte) number, allowing about 4 billion unique addresses. At the time, IPv4 seemed more than sufficient to power the World Wide Web. On January 31, 2011, the top-level pool of Internet Assigned Numbers Authority (IANA) IPv4 addresses was officially exhausted. On September 24th 2015, The American Registry for Internet Numbers (ARIN) officially ran out of IPv4 addresses.</p><p>It was clear well before 2011 that 4 billion addresses would not be nearly enough for all of the people in the world—let alone all of the phones, tablets, TVs, cars, watches, and the upcoming slew of devices that would need to access the Internet. In 1998, the Internet Engineering Task Force (IETF) had formalized IPv4’s successor, IPv6. IPv6 uses a 128-bit address, which theoretically allows for approximately 340 trillion trillion trillion or 340,000,000,000,000,000,000,000,000,000,000,000,000 unique addresses.</p><p>So here we are nearly 20 years since IPv6 and… we’re at a little over <a href="https://www.google.com/intl/en/ipv6/statistics.html">10% IPv6 adoption</a>. :/</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7auUBz1f5QI5zQ6RshjzIQ/bc922b95265c50403926469f23493fcf/ipv6-adoption.png" />
            
            </figure><p>(<a href="http://www.google.com/intl/en/ipv6/statistics.html">source</a>)</p><p>The good news, as the graph above indicates, is that the rate of IPv6 adoption has increased significantly; last year being a record year with a 4% increase, according to Google. The way Google derives these numbers is by having a small number of their users execute JavaScript code that tests whether a computer can load URLs over IPv6.</p>
    <div>
      <h2>What’s up with the delay?</h2>
      <a href="#whats-up-with-the-delay">
        
      </a>
    </div>
    <p>Transitioning from IPv4 to IPv6 is a complex thing to execute on a global scale. When data gets sent through the Internet, packets of data are sent using the IP protocol. Within each packet you have a number of elements besides the payload (the actual data you’re sending), including the source and destination.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3QaaHehStrAqmqeUfDkgdF/23ebb39301d30906d76a564757e031e0/IPv4-Header.png" />
            
            </figure><p>In order for the transmission to get to its destination, each device passing it along (clients/servers, routers, firewalls, load balancers, etc) needs to be able to communicate with the other. Traditionally, these devices communicate with IPv4, the universal language on the Internet. IPv6 represents an entirely new language. In order for all of these devices to be able to communicate, they all need to talk IPv6 or have some sort of translator involved.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3ldIqoD4iT6MrFRJEUVMaP/75e3c62e41ded36b7271ddcea3e55a9c/IPv6-Header.png" />
            
            </figure><p>Translation requires technologies such as NAT64 and DNS64. NAT64 allow IPv6 hosts to communicate with IPv4 servers by creating a NAT-mapping between the IPv6 and the IPv4 address. DNS64 will synthesize AAAA records from A records. DNS64 has some known issues like DNSSEC validation failure (because the DNS server doing the translation is not the owner’s domain server). For service providers, supporting IPv4/IPv6 translation means providing separate IPv4 and IPv6 connectivity thus incurring additional complexity as well as <a href="/amazon-2bn-ipv4-tax-how-avoid-paying">additional operational and administrative costs</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6n6te48e8rLh9NVwIdUqS1/fdc1bd1eb37eb8bfc7d73811e3038a31/IPv6.png" />
            
            </figure>
    <div>
      <h2>Making the move</h2>
      <a href="#making-the-move">
        
      </a>
    </div>
    <p>Using IP literals (hard coded IP addresses) in your code is a common pitfall to meeting Apple's IPv6 support requirement. Developers should check their configuration files for any IP literals and replace them with domain names. Literals should not be embedded in protocols either. Although literals may seem unavoidable when using certain low-level APIs in communications protocols like SIP, WebSockets, or P2PP, Apple offers <a href="https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW13">high-level networking frameworks</a> that are easy to implement and less error prone.</p><p>Stay away from network preflighting and instead simply attempt to connect to a network resource and gracefully handle failures. Preflighting often attempts to check for Internet connectivity by passing IP addresses to network <a href="https://developer.apple.com/library/mac/documentation/SystemConfiguration/Reference/SCNetworkReachabilityRef/index.html#//apple_ref/doc/uid/TP40007260">reachability APIs</a>. This is bad practice both in terms of introducing IP literals in your code and misusing reachability APIs.</p><p>For iOS developers, it’s important to review <a href="https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html">Supporting IPv6 DNS64/NAT64 Networks</a> to ensure code compatibility. Within Apple’s documentation you’ll find a list of IPv4-specific APIs that need to be eliminated, IPv6 equivalents for IPv4 types, system APIs that can synthesize IPv6 addresses, as well as how to set up a local IPv6 DNS64/NAT64 network so you can regularly test for IPv6 DNS64/NAT64 compatibility.</p><p>CloudFlare offers a number of IPv6 features that developers can take advantage of during their migration. If your domain is running through CloudFlare, enabling IPv6 support is as simple as enabling IPv6 Compatibility in the dashboard.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4T5GBCooyN3nfHgu3lfLvM/c033cbedb4f3f4f497fcd2f60811ebf9/turning-on-ipv6.png" />
            
            </figure><p>Certain legacy IPv4 applications may be able to take advantage of CloudFlare's Pseudo IPv4. Pseudo IPv4 works by adding an HTTP header to requests established over IPv6 with a "pseudo" IPv4 address. Using a hashing algorithm, Pseudo IPv4 will create a <a href="https://en.wikipedia.org/wiki/Classful_network">Class E</a> IPv4 address which always produces the same output for the same input; the same IPv6 address will always result in the same Pseudo IPv4 address. Using the Class E IP space, we have access to 268,435,456 possible unique IPv4 addresses.</p><p>Pseudo IPv4 offers 2 options: Add Header or Overwrite Headers. Add Header will automatically add a header (Cf-Pseudo-IPv4), that can be parsed by software as needed. Overwrite Headers will overwrite the existing Cf-Connecting-IP and X-Forwarded-For headers with a Pseudo IPv4 address. The overwrite option has the advantage (in most cases), of not requiring any software changes. If you choose the overwrite option, we'll append a new header (Cf-Connecting-IPv6) in order to ensure you can still find the actual connecting IP address for debugging.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7mrxwvi0fTQXYOvzaOSddj/30e338e4a96449dc6b8f0311f6170b98/pseudo-ipv4.png" />
            
            </figure><p>For iOS developers under the gun to make the transition to IPv6, there are benefits to the move apart from compliance with Apple’s policy. Beyond the inherent security benefits of IPv6 like mandatory IPSec, many companies have seen performance gains as well. Real User Measurement studies conducted by <a href="https://code.facebook.com/posts/1192894270727351/ipv6-it-s-time-to-get-on-board/">Facebook</a> show IPv6 made their site 10-15 percent faster and <a href="https://www.youtube.com/watch?v=FUtG89C8h_A">LinkedIn</a> realized 40 percent gains on select mobile networks in Europe.</p><p>For domains currently running through CloudFlare, since we currently do not enable IPv6 by default you’ll want to go into your account and make sure IPv6 Compatibility is enabled under the Network tab. CloudFlare has been offering rock solid IPv6 since 2012 with one-click IPv6 provisioning, an IPv4-to-IPv6 translation gateway, Pseudo IPv4, and much more. For more information, be sure to check out our IPv6 page: <a href="https://www.cloudflare.com/ipv6/">https://www.cloudflare.com/ipv6/</a></p> ]]></content:encoded>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[iOS]]></category>
            <category><![CDATA[Mobile]]></category>
            <guid isPermaLink="false">3lLu53EgnErBiBadIuef0s</guid>
            <dc:creator>Dragos Bogdan</dc:creator>
        </item>
        <item>
            <title><![CDATA[Happy 5th Birthday, CloudFlare!]]></title>
            <link>https://blog.cloudflare.com/happy-5th-birthday-cloudflare/</link>
            <pubDate>Mon, 28 Sep 2015 02:00:52 GMT</pubDate>
            <description><![CDATA[ Today is September 27, 2015. It's a rare Super Blood Moon. And it's also CloudFlare's birthday. CloudFlare launched 5 years ago today. It was a Monday. While Michelle, Lee, and I had high expectations, we would never have imagined what's happened since then. ]]></description>
            <content:encoded><![CDATA[ <p>Today is September 27, 2015. It's a rare <a href="http://www.nytimes.com/2015/09/26/science/super-blood-moon-to-make-last-appearance-until-2033.html">Super Blood Moon</a>. And it's also CloudFlare's birthday. CloudFlare launched 5 years ago today. It was a Monday. While Michelle, Lee, and I had high expectations, we would never have imagined what's happened since then.</p><p>In the last five years we've stopped 7 trillion cyber attacks, saved more than 94,116 years worth of time, and served 99.4 trillion requests — nearly half of those in the last 6 months. You can learn more from <a href="https://www.cloudflare.com/five-years">this timeline of the last five years</a>.</p>
    <div>
      <h3>Celebrating by doing the impossible</h3>
      <a href="#celebrating-by-doing-the-impossible">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/23WJdtbfSpiAcioTpNOvxJ/29afdeea8b8ea260a8f54653844a1cf4/network-map-china-1.png" />
            
            </figure><p>Every year we like to celebrate our birthday by giving something seemingly impossible back to our users. Two years ago we enabled on our <a href="/introducing-cloudflares-automatic-ipv6-gatewa/">Automatic IPv6 Gateway</a>, allowing our users to support IPv6 without having to update their own servers. Last year we made <a href="/introducing-universal-ssl/">Universal SSL support</a> available to all our customers, even those on our free plan. And this year, we announced the <a href="/how-we-extended-cloudflares-performance-and-security-into-mainland-china/">expansion across Mainland China</a>, building the first truly global performance and security platform.</p>
    <div>
      <h3>Internet Summit &amp; Party</h3>
      <a href="#internet-summit-party">
        
      </a>
    </div>
    <p>We celebrated in San Francisco last week with CloudFlare's first Internet Summit at our new San Francisco Headquarters with more than 500 of our customers and friends. Speakers discussed their visions for the challenges and opportunities for the Internet over the next five years. We'll be posting videos of those talks over the course of this week. In the meantime, here are some photographs from the Summit and the party later that night with one of our favorite bands, <a href="https://twitter.com/WalkOffTheEarth">Walk Off the Earth</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1sHhA4Bsi7QwEWiy8Z8par/5bc23c9d86dcc2c2b0788f8953e32866/matthew_michelle_summit.jpg" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/YqNjGqCLOJyNsEU0IhKdi/0fb4a2003aad1eb003a286f88d417671/summit_president_estonia.jpg" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3T84fMfr5gnKRT1LY8SG6z/ff58fdaeee49c8762bd5c4570fb3f602/cloudflare_baloons.jpg" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Ih1nUK1cHAU3cr8p6JwpU/a4a059cd1be88f3d7d62f93eaea29afa/party_roof_deck.jpg" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5HdjPst9e2aXVxSlvqCeD8/ab5f6e73d7d6e2286d1c0185accf6a55/WOTE.jpg" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3mWVvHuZCVa8J8eLQ5BcLQ/f4c86c88a70d462a0464ccd769500bd7/confetti_cannon.JPG.jpeg" />
            
            </figure><p>Thanks everyone for your support over the last five years. As Michelle likes to say, we're just getting started.</p> ]]></content:encoded>
            <category><![CDATA[Internet Summit]]></category>
            <category><![CDATA[China]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[Product News]]></category>
            <guid isPermaLink="false">2rvmOBLXbdtkSd2pmRAL2N</guid>
            <dc:creator>Matthew Prince</dc:creator>
        </item>
        <item>
            <title><![CDATA[Test all the things: IPv6, HTTP/2, SHA-2]]></title>
            <link>https://blog.cloudflare.com/test-all-the-things-ipv6-http2-sha-2/</link>
            <pubDate>Wed, 02 Sep 2015 10:15:44 GMT</pubDate>
            <description><![CDATA[ CloudFlare constantly tries to stay on the leading edge of Internet technologies so that our customers' web sites use the latest, fastest, most secure protocols. For example, in the past we've enabled IPv6 and SPDY/3.1. ]]></description>
            <content:encoded><![CDATA[ <p><b>NOTE: The </b><a href="https://http2.cloudflare.com"><b>https://http2.cloudflare.com</b></a><b> site has been shut down. This blog was posted in 2015 and subsequently we took all the technologies here and made them part of our core product.</b></p><p>CloudFlare constantly tries to stay on the leading edge of Internet technologies so that our customers' web sites use the latest, fastest, most secure protocols. For example, in the past we've enabled <a href="https://www.cloudflare.com/ipv6">IPv6</a> and <a href="/staying-up-to-date-with-the-latest-protocols-spdy-3-1/">SPDY/3.1</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3mXGypzyBdMO90CpkHFyIr/c72a20a0df3300f5be24b4a41eca0492/1490956.jpg" />
            
            </figure><p>Today we've switched on a test server that is open for people to test compatibility of web clients. It's a mirror of this blog and is served from <a href="https://http2.cloudflare.com/">https://http2.cloudflare.com/</a>. The server uses three technologies that it may be helpful to test with: IPv4/IPv6, HTTP/2 and an SSL certificate that uses SHA-2 for its signature.</p><p>The server has both IPv4 and IPv6 addresses.</p>
            <pre><code>$ dig +short http2.cloudflare.com A
45.55.83.207
$ dig +short http2.cloudflare.com AAAA
2604:a880:800:10:5ca1:ab1e:f4:e001</code></pre>
            <p>The certificate is based on SHA-2 (in this case SHA-256). This is important because SHA-1 is being deprecated by some browsers <a href="https://blog.filippo.io/the-unofficial-chrome-sha1-faq/">very soon</a>. On a recent browser the connection will also be secured using ECDHE (for <a href="/staying-on-top-of-tls-attacks/">forward secrecy</a>).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4ln91gm5eQAL1msGVkURHp/906918fabce930d0f9d0db264b49770d/Screen-Shot-2015-08-21-at-16-24-37.png" />
            
            </figure><p>And, finally, the server uses HTTP/2 if the browser is capable. For example, in Google Chrome, with the <a href="https://chrome.google.com/webstore/detail/http2-and-spdy-indicator/mpbpobfflnpcgagjijhmgnchggcjblin">HTTP/2 and SPDY indicator</a> extension the blue lightning bolt indicates that the page was served using HTTP/2:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3n6g7gcgyLEALV7dx3ZqTd/631eae6397babc849ce829457405c675/Screen-Shot-2015-08-21-at-16-23-11.png" />
            
            </figure><p>This server isn't on the normal CloudFlare network and is intended for testing purposes only. We'll endeavor to keep it online so that people have an HTTP/2 endpoint to test clients against.</p><p>In Google Chrome's <a>net-internals</a> view you can see the HTTP/2 session in use when connecting to the site.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7A2LQeZ6ZGPQSXQ93XcsBG/3930ce4e4410c5d23198b30e37b7e302/Screen-Shot-2015-09-02-at-09-35-51.png" />
            
            </figure><p>We hope that this will prove useful for people tests HTTP/2 compatible client software. Let us know how it goes.</p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">4FuCyGJPqzq2MiAAMnhbJV</guid>
            <dc:creator>John Graham-Cumming</dc:creator>
        </item>
        <item>
            <title><![CDATA[iOS Developers — Migrate to iOS 9 with CloudFlare]]></title>
            <link>https://blog.cloudflare.com/ios-developers-migrate-to-ios-9-with-cloudflare/</link>
            <pubDate>Thu, 11 Jun 2015 10:31:29 GMT</pubDate>
            <description><![CDATA[ Thousands of developers use CloudFlare to accelerate and secure the backend of their mobile applications and websites. This week is WWDC, where thousands of Apple developers come to San Francisco to talk, learn and share best practices for developing software for Apple platforms.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Thousands of developers use CloudFlare to accelerate and secure the backend of their mobile applications and websites. This week is Apple’s <a href="https://developer.apple.com/wwdc/">Worldwide Developers Conference (WWDC)</a>, where thousands of Apple developers come to San Francisco to talk, learn and share best practices for developing software for Apple platforms. New announcements from Apple this week make CloudFlare an even more obvious choice for application developers.</p>
    <div>
      <h3>New operating systems, new application requirements</h3>
      <a href="#new-operating-systems-new-application-requirements">
        
      </a>
    </div>
    <p>The flagship announcement of WWDC 2015 was a new version of Apple’s mobile operating system, iOS 9, to be released in September with a developer preview <a href="http://www.apple.com/ios/ios9-preview/">available now</a>. They also announced a new Mac operating system, OS X El Capitan, launching in the fall. Apple has a track record of developing and supporting technologies that enhance user privacy and security with <a href="https://www.apple.com/privacy/privacy-built-in/">iMessage and Facetime</a> and the trend is continuing with these new operating systems. In both cases, Apple is requiring application developers to make use of two network technologies that CloudFlare is big fan of: <a href="https://www.cloudflare.com/ssl">HTTPS</a> and <a href="/eliminating-the-last-reasons-to-not-enable-ipv6/">IPv6</a>.</p><p><i>For iOS 9 and El Capitan, all applications submitted to the iOS and Mac App Stores </i><a href="http://www.internetsociety.org/deploy360/blog/2015/06/apple-will-require-ipv6-support-for-all-ios-9-apps/"><i>must work over IPv6</i></a><i>. In previous versions, applications were allowed that only worked with IPv4.</i></p><p>From [Sebastien Marineau, Apple’s VP of Core OS](<a href="https://developer.apple.com/v219">https://developer.apple.com/v219</a> commitsideos/wwdc/2015/?id=102): "Because IPv6 support is so critical to ensuring your applications work across the world for every customer, we are making it an AppStore submission requirement, starting with iOS 9."</p><p><i>By default, all network connections in third party applications compiled for on iOS 9 and El Capitan use a new feature called App Transport Security. This feature forces the application to connect to backend APIs and the web via HTTPS. Plain unencrypted HTTP requests are disallowed unless the developer specifically modifies a configuration file to allow it.</i></p><p>From the <a href="https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html">iOS 9 developer documentation</a>: "If you're developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible."</p><p>What does this mean for application developers? If your application has a web backend component, you will need to update the backend to support these protocols. This can be difficult to do since not all hosting providers support IPv6, and HTTPS certificates can be tricky to obtain and difficult to configure correctly, not to mention maintain.</p>
    <div>
      <h3>Free and automatic IPv6 and SSL</h3>
      <a href="#free-and-automatic-ipv6-and-ssl">
        
      </a>
    </div>
    <p>One of the best things CloudFlare does well is to take modern network protocols and make them affordable (or free) and accessible to everyone. Every CloudFlare-backed website and API backend has support for both IPv6 and HTTPS automatically, and with no configuration necessary.</p><p>With <a href="/introducing-universal-ssl/">Universal SSL</a>, this is now true even for customers on CloudFlare’s free plan. We also make sure your HTTPS configuration is the latest and greatest with <a href="https://support.cloudflare.com/hc/en-us/articles/200311920-What-SSL-protocols-does-CloudFlare-support-">TLS 1.2 support</a> and <a href="/staying-on-top-of-tls-attacks/">Forward secrecy</a>.</p><p>CloudFlare provides its Automatic IPv6 Gateway for <a href="/introducing-cloudflares-automatic-ipv6-gatewa/">free</a> to all CloudFlare users. This makes any content or API required by an Apple iOS app instantly available using IPv4 and IPv6 independent of the inability of your hosting provider to supply IPv6 support. More information about CloudFlare’s IPv6 support can be found <a href="https://www.cloudflare.com/ipv6">here</a>.</p><p>Not only does CloudFlare help keep application service components up to date with the latest Apple requirements, it provides the performance benefits of a globally distributed network and protection against malicious attacks.</p><p>If you’re an iOS developer looking to upgrade your application backend to meet Apple’s new requirements, you can sign up for CloudFlare <a href="https://cloudflare.com/a/sign-up">here</a>.</p><p>To verify that IPv6 is enabled, open your DNS settings and ensure that the IPv6 toggle is on:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1dTaeTvqYSQNGeNuqaZx5y/dcc2fca2216c4cd3f48f1188af495418/image01.png" />
            
            </figure><p>CloudFlare offers HTTPS to the backend, so if you already have HTTPS, you can keep full end-to-end encryption with CloudFlare’s Strict SSL mode. If your backend doesn’t support HTTPS, you can select the Flexible mode to encrypt the communication between your App and CloudFlare. These setting are available in your Crypto settings:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1pPgweR8FUtcY8Xaalie4X/3b1e82aaef376fbcdc8d928cff7b7096/image00.png" />
            
            </figure><p>CloudFlare and iOS 9 were made for each other.</p><p><i>P.S.: We provide the same service to Android apps as well.</i></p> ]]></content:encoded>
            <category><![CDATA[Mobile]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[HTTPS]]></category>
            <category><![CDATA[API]]></category>
            <category><![CDATA[iOS]]></category>
            <category><![CDATA[Cloudflare Apps]]></category>
            <category><![CDATA[Security]]></category>
            <guid isPermaLink="false">5yhF96zEJdHrZWZpA2hc6R</guid>
            <dc:creator>Nick Sullivan</dc:creator>
        </item>
        <item>
            <title><![CDATA[Four years later and CloudFlare is still doing IPv6 automatically]]></title>
            <link>https://blog.cloudflare.com/four-years-later-and-cloudflare-is-still-doing-ipv6-automatically/</link>
            <pubDate>Fri, 05 Jun 2015 18:42:40 GMT</pubDate>
            <description><![CDATA[ Over the past four years CloudFlare has helped well over two million websites join the modern web, making us one of the fastest growing providers of IPv6 web connectivity on the Internet.  ]]></description>
            <content:encoded><![CDATA[ <p>Over the past four years CloudFlare has helped well over two million websites join the modern web, making us one of the fastest growing providers of IPv6 web connectivity on the Internet. CloudFlare's <a href="/introducing-cloudflares-automatic-ipv6-gatewa/">Automatic IPv6 Gateway</a> allows IPv4-only websites to support IPv6-only clients with zero clicks. No hardware. No software. No code changes. And no need to change your hosting provider.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2V14CHrnFNob3rp8bKgyOh/eb4377b774b73ab7b8dee684b13292a6/Screen-Shot-2015-06-05-at-10-07-51-AM.png" />
            
            </figure><p><a href="http://cs.brown.edu/~adf/cerf/Cerf_ipv6_poster.pdf">Image</a> by <a href="http://cs.brown.edu/~adf/">Andrew D. Ferguson</a></p>
    <div>
      <h3>A Four Year Story</h3>
      <a href="#a-four-year-story">
        
      </a>
    </div>
    <p>The story of IPv6 support for customers of CloudFlare is about as long as the story of CloudFlare itself. June 6th, 2011 (four years ago) was the original World IPv6 Day, and CloudFlare participated. Each year since, the global Internet community has pushed forward with additional IPv6 deployment. Now, four years later, CloudFlare is celebrating June 6th knowing that our customers are being provided with a solid IPv6 offering that requires zero configuration to enable. CloudFlare is the only <a href="https://www.cloudflare.com/network-map">global CDN</a> that provides IPv4/IPv6 delivery of content by default and at scale.</p><p>IPv6 has been <a href="/eliminating-the-last-reasons-to-not-enable-ipv6/">featured</a> <a href="/three-years-after-world-ipv6-day/">in</a> <a href="/introducing-cloudflares-automatic-ipv6-gatewa/">our</a> <a href="/ipv6-challenge-to-the-web/">blog</a> various times over the last four years. We have provided support for legacy logging systems to handle IPv6 addresses, provided <a href="https://www.cloudflare.com/ddos">DDoS protection</a> on IPv6 alongside classic IPv4 address space, and provided the open source community with software to handle <a href="/path-mtu-discovery-in-practice/">ECMP load balancing</a> correctly.</p>
    <div>
      <h3>It's all about the numbers</h3>
      <a href="#its-all-about-the-numbers">
        
      </a>
    </div>
    <p>Today CloudFlare is celebrating four years of World IPv6 Day with a few new graphs:</p><p>First, let's measure IPv6 addresses (broken down by /64 blocks).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3g911dZxFjbTq0baNqsATc/41f4610aacbb4dcd3e9a2f2b6f29d1f6/Growth-of-IPv6-IPs-on-CloudFlare-over-the-last-year-2.png" />
            
            </figure><p>While CloudFlare operates the CDN portion of web traffic delivery to end-users, we don’t control the end-user's deployment of IPv6. We do, however, see IP addresses when they are used, and we clearly see an uptick in deployed IPv6 at the end-user sites. Measuring unique IP addresses is a good indicator of IPv6 deployment.</p><p>Next we can look at how end users, using IPv6, access CloudFlare customers' websites.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5XxlbrdqfSNuD7inHmj6rQ/9757467e882831bb824510eb68d56385/Percentage-of-IPv6-Traffic-by-Device-as-seen-by-CloudFlare.png" />
            
            </figure><p>With nearly 25% of our IPv6 traffic being delivered to mobile devices as of today, CloudFlare is happy to help demonstrate that mobile operators have embraced IPv6 with gusto.</p><p>The third graph looks at traffic based on destination country and is a measure of end-users (eyeballs as they are called in the industry) that are enabled for IPv6. The graph shows the top countries that CloudFlare delivers IPv6 web traffic to.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5YPKZmpdawhtnBYDIoJL1S/77a9aa36ec0ddca87e289f431663f53f/IPv6-as-percentage-of-all-traffic-by-country.png" />
            
            </figure><p>On the Y Axis, we have the percentage of traffic delivered via IPv6. On the X Axis we have each of the last eight months. Let's just have a shoutout to Latin America. In Latin America CloudFlare operates five data centers: <a href="/buenos-aires/">Argentina</a>, <a href="/parabens-brasil-cloudflares-27th-data-center-now-live/">Brazil</a>, <a href="/bienvenido-a-chile-cloudflares-24th-data-center-now-live/">Chile</a>, <a href="/listo-medellin-colombia-cloudflares-28th-data-center/">Columbia</a>, and <a href="/lima-peru-cloudflares-29th-data-center/">Peru</a>. CloudFlare would like to highlight our Peru datacenter because it has the highest percentage of traffic being delivered over IPv6 in Latin America. Others <a href="https://twitter.com/lacnic/status/596445340905152512">agree</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6zzlrIo11Q7M09KKW2ojDO/b8e43c1b1b43397dc128fd1e5bb1b3be/twitter-lacnic-peru-ipv6.png" />
            
            </figure>
    <div>
      <h3>What's next for IPv6?</h3>
      <a href="#whats-next-for-ipv6">
        
      </a>
    </div>
    <p>The real question is: What's next for users stuck with only IPv4? Because the RIRs have depleted their IPv4 address space pools, ISPs are simply out of options regarding the need to embrace IPv6. Basically, <a href="/amazon-2bn-ipv4-tax-how-avoid-paying">there are no more IPv4 addresses available</a>.</p><p>Supporting IPv6 is even more important today than it was four years ago and CloudFlare is happy that it provides this automatic IPv6 solution for all its customers. Come try it out and don’t let other web properties languish in the non-IPv6 world by telling a friend about our <a href="https://www.cloudflare.com/ipv6">automatic IPv6 support</a>.</p> ]]></content:encoded>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[World IPv6 Day]]></category>
            <guid isPermaLink="false">89RoHkcpxlReU78VRppFY</guid>
            <dc:creator>Martin J Levy</dc:creator>
        </item>
    </channel>
</rss>