<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Ryan Lahfa&#39;s blog</title>
  <subtitle>Essays on Linux, NixOS, deterministic infrastructure, and security.</subtitle>
  <link href="https://ryan.lahfa.xyz/feed.xml" rel="self" />
  <link href="https://ryan.lahfa.xyz/" />
  <updated>2023-03-20T00:00:00Z</updated>
  <id>https://ryan.lahfa.xyz/</id>
  <author>
    <name>Ryan Lahfa</name>
  </author>
  <entry>
    <title>Surprising applications to sandboxing and network namespaces: the case of Command &amp; Conquer 3: Tiberium Wars</title>
    <link href="https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/" />
    <updated>2022-03-02T00:00:00Z</updated>
    <id>https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/</id>
    <content type="html">&lt;h1 id=&quot;command-conquer-3-tiberium-wars&quot; tabindex=&quot;-1&quot;&gt;Command &amp;amp; Conquer 3 : Tiberium Wars&lt;/h1&gt;
&lt;p&gt;This is a RTS&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; game that I play a lot as I know it well, so, sometimes I wound up re-running the game.&lt;/p&gt;
&lt;p&gt;Nowadays, I do not run anymore Windows except for Call of Duty, Black Desert Online and other annoying games.&lt;/p&gt;
&lt;p&gt;Plus, Proton / Wine got a lot better, with an awesome compatibility layer with Vulkan and Intel Graphics cards.&lt;/p&gt;
&lt;p&gt;So here is the thing, I more than often wants to play with my friends, but CNC3 has a very bad netcode&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; : it do not handle multiple Linux interfaces at all and it uses layer 2 networking features, e.g. broadcasting over UDP, to find out LAN games.&lt;/p&gt;
&lt;p&gt;Most of the time, I want to play with friends across Internet, meaning I need some virtual private networking supporting layer 2 networking &lt;strong&gt;and&lt;/strong&gt; the ability to force a specific interface for the game.&lt;/p&gt;
&lt;h1 id=&quot;solution-1-bruteforce-your-way&quot; tabindex=&quot;-1&quot;&gt;Solution 1 : bruteforce your way&lt;/h1&gt;
&lt;p&gt;Multiple VPN providers supports L2 networking, even WireGuard could do with some help&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;, pick one, mine was ZeroTier.&lt;/p&gt;
&lt;p&gt;Now, how can I make it so CNC3 knows only about the ZeroTier interface? Well, enter network namespaces.&lt;/p&gt;
&lt;h2 id=&quot;interlude-network-namespaces&quot; tabindex=&quot;-1&quot;&gt;Interlude: Network namespaces&lt;/h2&gt;
&lt;p&gt;Network namespace is a Linux kernel feature akin to the family of &amp;quot;xxx namespaces&amp;quot;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;, it provides an hermetic world for the network subsystem of the Linux kernel for your children processes.&lt;/p&gt;
&lt;p&gt;It fits the bill here as we do want to make believe our CNC3 program that we only have one interface and this is the ZeroTier one.&lt;/p&gt;
&lt;h2 id=&quot;using-gdf-ion-canon-to-play-a-game-quickly&quot; tabindex=&quot;-1&quot;&gt;Using GDF Ion Canon to play a game quickly&lt;/h2&gt;
&lt;p&gt;Well, building network namespaces requires reading documentation, I can actually do it, but it takes time and I really want to play.&lt;/p&gt;
&lt;p&gt;Thanksfully for me, &lt;code&gt;firejail&lt;/code&gt; packages a lot of sandboxing features, including network namespaces in a way I am interested in: providing a list of &amp;quot;allowed&amp;quot; interfaces in the target namespace.&lt;/p&gt;
&lt;p&gt;So here we go, &lt;code&gt;firejail --net=ztxxx wine CNC3.exe&lt;/code&gt; ; thanks firejail!&lt;/p&gt;
&lt;p&gt;Does it work? Absolutely. Did I expect for it to work? At first, no. Now, thinking to what happened, it is obvious as &lt;code&gt;wine&lt;/code&gt; is only translating Windows syscalls and they will fall in the kernel under the network namespace feature, there is no magic involved here, &lt;code&gt;wine&lt;/code&gt; has no special right and this is the actual magic at work here.&lt;/p&gt;
&lt;p&gt;This trick works too on LAN when your computer has too much interfaces and multiple paths but at the end, you just want to play on a very specific physical LAN.&lt;/p&gt;
&lt;h1 id=&quot;solution-2-use-actually-proper-network-namespaces&quot; tabindex=&quot;-1&quot;&gt;Solution 2 : use actually proper network namespaces&lt;/h1&gt;
&lt;p&gt;Well, yes, use proper tools for the problem ahem ; anyway, &lt;code&gt;unshare&lt;/code&gt; would do the job in theory, this is left as an exercise to the reader.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Real-time strategy &lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;So bad, I should look into patching it myself, I guess, that would be faster than what I am going to describe here. &lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I guess, some UDP relays stuff which would do unicast to everyone through some list of &amp;quot;connected&amp;quot; hosts. &lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;User namespaces, process namespaces, PID namespaces, etc. &lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2022-03-02-surprising-applications-to-sandboxing/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>One trick to build a TLS-enabled IPv6-only empire with only ONE legacy IP</title>
    <link href="https://ryan.lahfa.xyz/en/posts/2023-03-20-ipv6-only/" />
    <updated>2023-03-20T00:00:00Z</updated>
    <id>https://ryan.lahfa.xyz/en/posts/2023-03-20-ipv6-only/</id>
    <content type="html">&lt;p&gt;IPv4 is the fourth version of the Internet Protocol, which has been in use for over three decades. However, the rapid growth of the internet and the explosion of connected devices have made it clear that the available pool of IPv4 addresses is no longer sufficient to meet the demand. Moreover, IPv4 suffers from several limitations, such as lack of built-in security features and the inability to support advanced routing and network management capabilities. These limitations have been addressed by the newer IPv6 protocol, which offers a much larger address space, enhanced security features, and better support for modern network technologies.&lt;/p&gt;
&lt;p&gt;Therefore, it&#39;s high time to move on from IPv4 and adopt IPv6 as the standard protocol for the internet to ensure better scalability, security, and performance.&lt;/p&gt;
&lt;p&gt;Assuming you adopted IPv6, you still have some users which cannot access your service while travelling or for any reason related to a legacy network deployment (i.e. IPv4-only).&lt;/p&gt;
&lt;p&gt;Here, I will explain a simple trick to move the problem to border nodes, in exchange of some performance degradation which can be mitigated with extra unimplemented efforts, inspired by &lt;a href=&quot;https://www.mythic-beasts.com/support/topics/proxy&quot;&gt;https://www.mythic-beasts.com/support/topics/proxy&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;the-key-server-name-indication-sni&quot; tabindex=&quot;-1&quot;&gt;The key: Server Name Indication (SNI)&lt;/h1&gt;
&lt;p&gt;SNI stands for Server Name Indication, which is an extension to the Transport Layer Security (TLS) protocol. It allows a client to indicate which hostname it is attempting to connect to, so that the server can use the appropriate certificate to establish a secure connection. This is particularly useful in cases where multiple domains are hosted on the same IP address, which is common with shared services, e.g. NGINX virtual hosts.&lt;/p&gt;
&lt;p&gt;When it comes to proxying an IPv4 connection to an IPv6 connection, SNI is useful because it allows the proxy to inspect the SNI header and determine which IPv6 address to route the connection to, allowing the client to access the IPv6-only service.&lt;/p&gt;
&lt;h1 id=&quot;how-to-leverage-sni-to-proxy-ipv4-to-ipv6-in-nixos&quot; tabindex=&quot;-1&quot;&gt;How to leverage SNI to proxy IPv4 to IPv6 in NixOS ?&lt;/h1&gt;
&lt;p&gt;Assuming you have &lt;a href=&quot;https://github.com/RaitoBezarius/nixexprs/blob/master/modules/servers/sniproxy.nix&quot;&gt;a sniproxy NixOS module&lt;/a&gt;, you can write expressions like those:&lt;/p&gt;
&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lib&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; 
  mkDirectRule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    match &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# Proxy the whole *.domain (not domain!).&lt;/span&gt;
  mkWholeSubdomainRule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    match &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.*&#92;&#92;.${lib.replaceStrings [&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;] [&quot;&lt;/span&gt;&#92;&#92;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;] domain}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*:443&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
  publicIPv4 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;my only and sole IPv4&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firewall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;allowedTCPPorts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sniproxy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    enable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    resolver &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      mode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ipv6_first&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    listeners &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; publicIPv4&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vhosts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        fallback &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;127.0.0.1:443&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    tables&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vhosts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mkDirectRule &lt;span class=&quot;token string&quot;&gt;&quot;ryan.lahfa.xyz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And get nice logs such as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Mar 20 00:32:48 amadeus sniproxy[926982]: 1.1.1.1:6601 -&amp;gt; 2.2.2.2:443 -&amp;gt; [2001:470:ca5e::1]:443 [ryan.lahfa.xyz] 1385/1385 bytes tx 1971/1971 bytes rx 66.058 seconds
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is very helpful to enable legacy IP users to access your service whatever it is as long it uses TLS and can use SNI therefore.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2023-03-20-ipv6-only/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h1 id=&quot;the-problem-lost-origin-legacy-ip-information&quot; tabindex=&quot;-1&quot;&gt;The problem : lost origin legacy IP information!&lt;/h1&gt;
&lt;p&gt;Doing naive IPv4 → IPv6 proxies like this is bound to give you headaches when you will want to understand the nature of your traffic by reading your server logs, and if you want to do moderation by blocking some IPv4, it is almost impossible.&lt;/p&gt;
&lt;p&gt;Indeed, the target host does not receive the original IP, it only receives the previous hop IP information.&lt;/p&gt;
&lt;p&gt;Though, this is not an inherent limitation for most software.&lt;/p&gt;
&lt;h1 id=&quot;the-solution-proxy-protocol&quot; tabindex=&quot;-1&quot;&gt;The solution : PROXY protocol&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt&quot;&gt;PROXY protocol&lt;/a&gt; is a protocol that enables a load balancer, such as HAProxy, to transparently pass on client connection information to a backend server. This is useful in cases where the backend server needs to know the original source IP address and port of the client, rather than the IP address of the load balancer.&lt;/p&gt;
&lt;p&gt;The PROXY protocol works by encapsulating the original client connection information in a special header, which is then passed on to the backend server. This header contains information about the original source IP address, source port, destination IP address, and destination port, among other details.&lt;/p&gt;
&lt;p&gt;By using the PROXY protocol, the backend server can make more informed decisions about how to handle the connection, such as applying different firewall rules or routing the traffic to a different server based on the original client IP address.&lt;/p&gt;
&lt;p&gt;HAProxy, initial developers of the PROXY protocol, supports both the PROXY v1 and v2 protocols, and can be configured to use the PROXY protocol for incoming connections, outgoing connections, or both. However, it&#39;s important to note that not all backend servers support the PROXY protocol, so it&#39;s important to verify compatibility before enabling it.&lt;/p&gt;
&lt;p&gt;In our case, we use NGINX and sniproxy, which both support PROXY protocol v1.&lt;/p&gt;
&lt;h1 id=&quot;what-does-it-look-like-in-nixos&quot; tabindex=&quot;-1&quot;&gt;What does it look like in NixOS?&lt;/h1&gt;
&lt;p&gt;It is easy to enable PROXY protocol listener on a virtual host in NGINX one by one by adding a &lt;code&gt;listen&lt;/code&gt; directive.&lt;/p&gt;
&lt;p&gt;Nevertheless, this is not good for us because we have 50+ virtual hosts and we would like to have a smart &amp;quot;default&amp;quot; of having a PROXY listener.&lt;/p&gt;
&lt;p&gt;We introduced &lt;a href=&quot;https://github.com/NixOS/nixpkgs/pull/213510&quot;&gt;https://github.com/NixOS/nixpkgs/pull/213510&lt;/a&gt; to this effect which enable to have default PROXY protocol listeners separate from non PROXY ones.&lt;/p&gt;
&lt;p&gt;Here&#39;s what it looks like to have a &amp;quot;global PROXY protocol&amp;quot; aware system, create a profile called &lt;code&gt;v6-proxy-aware.nix&lt;/code&gt; for example:&lt;/p&gt;
&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lib&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
  withFirewall &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  allowedUpstream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2001:db8::1/128&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nginx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# IPv6-only server&lt;/span&gt;
    defaultListen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; addr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[::0]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; proxyProtocol &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;444&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ssl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; addr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[::0]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ssl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; addr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[::0]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ssl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    appendHttpConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;
      # Your central sniproxy node
      set_real_ip_from &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token antiquotation important&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;allowedUpstream&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;;
      real_ip_header proxy_protocol;
    &#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# Move to nftables if firewall is enabled.&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nftables&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; withFirewall&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firewall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;allowedTCPPorts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lib&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mkIf &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;withFirewall&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;444&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firewall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extraInputRules &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lib&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mkIf withFirewall &lt;span class=&quot;token string&quot;&gt;&#39;&#39;
    ip6 saddr &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token antiquotation important&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;allowedUpstream&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; tcp dport 444 accept
  &#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what is used in production, the nftables stuff is a bit verbose because we are not modern and we were using iptables on some hosts, so we will use it as an excuse to transition, but any kind of firewalling can be used. :)&lt;/p&gt;
&lt;p&gt;And now, you can transform the previous &lt;code&gt;sniproxy&lt;/code&gt; example:&lt;/p&gt;
&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lib&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; 
  mkDirectRule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    match &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Notice the difference here.&lt;/span&gt;
    dest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token antiquotation important&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;:444&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    useProxyProtocol &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# Proxy the whole *.domain (not domain!).&lt;/span&gt;
  mkWholeSubdomainRule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    match &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.*&#92;&#92;.${lib.replaceStrings [&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;] [&quot;&lt;/span&gt;&#92;&#92;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;] domain}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Notice the difference here.&lt;/span&gt;
    dest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*:444&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    useProxyProtocol &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
  publicIPv4 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;my only and sole IPv4&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firewall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;allowedTCPPorts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sniproxy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    enable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    resolver &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      mode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ipv6_first&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    listeners &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; publicIPv4&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vhosts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        fallback &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;127.0.0.1:443&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    tables&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vhosts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mkDirectRule &lt;span class=&quot;token string&quot;&gt;&quot;ryan.lahfa.xyz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now, not only no one can spoof their original address, but you can recover the information in your access logs in the destination endpoints!&lt;/p&gt;
&lt;h1 id=&quot;how-to-test-this&quot; tabindex=&quot;-1&quot;&gt;How to test this?&lt;/h1&gt;
&lt;pre class=&quot;language-console&quot;&gt;&lt;code class=&quot;language-console&quot;&gt;$ curl --haproxy-protocol https://vhost:444&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you can read the access logs of your server looking for the IPv4.&lt;/p&gt;
&lt;p&gt;In a future version of curl, I hope to add ways to change the client IP information using a flag &lt;code&gt;--haproxy-client-ip&lt;/code&gt; with &lt;a href=&quot;https://github.com/curl/curl/pull/10779&quot;&gt;https://github.com/curl/curl/pull/10779&lt;/a&gt;, it will also provide ways to test actively for spoofing situations.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h1&gt;
&lt;h2 id=&quot;run-everything-ipv6-only&quot; tabindex=&quot;-1&quot;&gt;Run everything IPv6-only !&lt;/h2&gt;
&lt;p&gt;Yes, you can run IPv6-only services for most of them nowadays, it&#39;s practical and feasible even for legacy IP users with &lt;strong&gt;proper logs&lt;/strong&gt;. No excuse!&lt;/p&gt;
&lt;p&gt;I run Jellyfin behind such proxies and do not notice any significant latency induced by this proxy mechanism, of course, your mileage may vary, I have good peering between my servers, therefore, the cost is small.&lt;/p&gt;
&lt;p&gt;It is probably possible to add more optimizations such as &lt;a href=&quot;https://github.com/dlundquist/sniproxy/pull/321&quot;&gt;TCP Fast Open&lt;/a&gt; or ditch TCP for QUIC, etc, etc. The sky is the limit.&lt;/p&gt;
&lt;h2 id=&quot;what-about-mail-servers-ssh&quot; tabindex=&quot;-1&quot;&gt;What about mail servers, SSH, &lt;insert non=&quot;&quot; TLS=&quot;&quot; service=&quot;&quot;&gt; ?&lt;/insert&gt;&lt;/h2&gt;
&lt;p&gt;Ha… Unfortunately :).&lt;/p&gt;
&lt;p&gt;Stuff like IRCd works fine because it has indeed TLS so can benefit from SNI.&lt;/p&gt;
&lt;p&gt;I would definitely behind getting a modern reimplementation of SSH with &lt;strong&gt;TLS&lt;/strong&gt; as a data transport part.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2023-03-20-ipv6-only/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;And for mail servers, SMTPS/IMAPS are actually a thing and I don&#39;t understand why are we not using them yet except for legacy reasons.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;There is also ALPN too, but this is out of scope for this simple post. &lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2023-03-20-ipv6-only/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;SSH has some shortcomings with encrypt-and-MAC encryption, encrypted &amp;quot;length&amp;quot; field, which are apparently solved in the newer ETM modes and its chacha20-poly1305 implementation. &lt;a href=&quot;https://ryan.lahfa.xyz/en/posts/2023-03-20-ipv6-only/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
</feed>