1. 18
  1.  

  2. 2

    I had a similar proposal a couple of years ago, which is almost the same as this one, with one notable difference.

    Instead of communicating the IP through the proxy protocol, I had envisioned the IPv4 address could be encoded in the IPv6 source address form the proxy; you’d simply have to give the proxy a /96 for itself.

    But before I was able to implement it, someone else already did it better than I ever could, although they used the PROXY protocol, like in this article; sniproxy by dlundquist does everything this article mentions, and I’ve been running it in front of multiple projects myself.

    Although when I looked at the Github issues back then, it seemed that this project was a lot more popular for setting up Netflix proxies than it was for the purpose in this article.

    1. 3

      Author here. The PR https://github.com/dlundquist/sniproxy/pull/372 implements a PoC for your suggestion. I did not want to use this method because downstream software (let’s say NGINX / applications, etc.) does not support it in an easy way.

      The solution here is built on the expectation that most downstream software understand what is a PROXY protocol or we can use a proper reverse proxy to make them understand it.

      So BTW, unsure if I misunderstood your comment:

      ; sniproxy by dlundquist does everything this article mentions, and I’ve been running it in front of multiple projects myself.

      Yes, sniproxy was used in this article, someone showed me https://github.com/jameysharp/sniproxy-rs which is interesting too. But any SNI-enabled proxy can do the trick here.

      Although when I looked at the Github issues back then, it seemed that this project was a lot more popular for setting up Netflix proxies than it was for the purpose in this article.

      And censorship evasion measures! Anyway, not surprising given SNI is particularly powerful and ESNI even better for this.

      1. 1

        The PR https://github.com/dlundquist/sniproxy/pull/372 implements a PoC for your suggestion

        I noticed! I think this patch is Linux-only, so it doesn’t help me much, but it’s cool to see someone with the same idea.

        downstream software (let’s say NGINX / applications, etc.) does not support it in an easy way.

        That’s the neat part; they don’t have to. You can always extract the IPv4 address from the IPv6 address in your log, even if software in between doesn’t know what’s going on.

        If you also want reverse DNS to work, you’d need an interesting DNS server. But I don’t do reverse queries just for logging.

        So BTW, unsure if I misunderstood your comment:
        Yes, sniproxy was used in this article

        Ah, I see, it is I who mistunderstood the article. I thought you implemented another reverse proxy, but you actually made a Nix setup with sniproxy. I only saw services.sniproxy, but I’m not very familiar with Nix so I didn’t notice it was the same thing.

        And censorship evasion measures! Anyway, not surprising given SNI is particularly powerful and ESNI even better for this.

        ESNI [ECH now] makes SNI proxying harder for hosts that you don’t own, because without the private key, your man in the middle doesn’t know where to proxy anymore. I don’t think this particular sniproxy implementation is getting support for it anytime soon.

        1. 2

          That’s the neat part; they don’t have to. You can always extract the IPv4 address from the IPv6 address in your log, even if software in between doesn’t know what’s going on.

          Indeed, but I’m not exactly sure stuff like goaccess support it out of the box, but I do agree.

          Ah, I see, it is I who mistunderstood the article. I thought you implemented a reverse proxy, but you made a Nix setup with sniproxy. I only saw service.sniproxy, but I’m not very familiar with Nix so I didn’t notice it was the same thing.

          Indeed, I am using a sniproxy NixOS module to configure sniproxy because it gives me a lot of flexibility and abstraction as I host 30+ proxied vhosts.

          ESNI [ECH now] makes SNI proxying harder for hosts that you don’t own, because without the private key, your man in the middle doesn’t know where to proxy anymore. I don’t think this particular sniproxy implementation is getting support for it anytime soon.

          Oh makes sense. It’s a bit sad though. I really like not being custodian of the keys, ugh.

    2. 1

      Congrats on submitting the (by my count) 9th Lobsters article that mentions IPv6 in the title! A real tragedy that so few devs are interested in this stuff.

      Wouldn’t SIIT serve this purpose better? My router doesn’t support SIIT so I may be misunderstanding it, but I believe your router would do the translation at Layer 3. Then you could do SNI or “Host” header routing like normal in some other proxy like nginx inside your IPv6-only network. The IPv4 source IP would be visible in logs and can be blocked with normal tools since it just appears as a padded IPv6 IP.

      1. 1

        Hmm, uncertain if SIIT fits the bill. As you remarked, it will still produce an overhead to process those IPv6-only logs. But I am definitely going to play with SIIT to solve other issues for non-TLS stuff.

        1. 1

          I found a few more submissions with “ipv6” in the title: https://gist.github.com/gustafe/607aafbddfa7624509ff31e3f5213d36

          They are ordered in reverse submission date order.

          1. 1

            Thanks! I’ll read every one! Maybe the native search didn’t like the number “6” or something

            1. 1

              Hehe, it seems to be “smarter” than just looking at the titles.

              The result above is from scraping every submission title.

        2. 1

          For the HardenedBSD build infrastructure, which I host out of my home behind a single IPv4 address and tunneled IPv6 (with HE’s TunnelBroker service), I use nginx as a web reverse proxy. Below is a sanitized version of the nginx configuration.

          All hostname-related records in the hardenedbsd.lan domain have ONLY an IPv6 AAAA record. No A records exist for *.hardenedbsd.lan.

          Here’s the nginx.conf file:

          worker_processes  8;
          
          events {
              worker_connections  1024;
          }
          
          
          http {
              include       mime.types;
              default_type  application/octet-stream;
          
              keepalive_timeout  65;
          
              upstream gitlab {
          	    server gitlab.hardenedbsd.lan:443;
              }
          
              upstream hbsd-os-build-01 {
          	    server hbsd-os-build-01.hardenedbsd.lan:443;
              }
          
              upstream hbsd-pkg-13-stable-01 {
          	    server hbsd-pkg-13-stable-01.hardenedbsd.lan:443;
              }
          
              upstream hbsd-pkg-current-01 {
          	    server hbsd-pkg-current.hardenedbsd.lan:443;
              }
          
              ssl_certificate [redacted];
              ssl_certificate_key [redacted];
          	server_names_hash_bucket_size 128;
          
              server {
                  listen       80;
          	listen [::]:80;
                  server_name 
          		git.hardenedbsd.org
          		dacxzjk3kq5mmepbdd3ai2ifynlzxsnpl2cnkfhridqfywihrfftapid.onion;
          
                  #charset koi8-r;
          
                  #access_log  logs/host.access.log  main;
          
                  location / {
          			proxy_pass https://gitlab;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
                  }
              }
          
          	server {
          		listen 80;
          		listen [::]:80;
          		server_name
          			rsync.hardenedbsd.org
          			installers.hardenedbsd.org
          			qspcqclhifj3tcpojsbwoxgwanlo2wakti2ia4wozxjcldkxmw2yj3yd.onion;
          
          		location / {
          			proxy_pass https://hbsd-os-build-01;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
          		}
          	}
          
          	server {
          		listen 80;
          		listen [::]:80;
          		server_name
          			x4tlazkltc5ttgk6friorlmlgqx4kopaqsom4hhw5blrmww7sszk2vad.onion;
          
          		location / {
          			proxy_pass https://hbsd-pkg-13-stable-01;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
          		}
          	}
          
          	server {
          		listen 80;
          		listen [::]:80;
          		server_name
          			hbsd-pkg-current-01.hardenedbsd.org;
          
          		location / {
          			proxy_pass https://hbsd-pkg-current-01;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
          		}
          	}
          
          	server {
          		listen 443 ssl;
          		listen [::]:443 ssl;
          		server_name git.hardenedbsd.org;
          
          		location / {
          			proxy_pass https://gitlab;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
          		}
          		break;
          	}
          
          	server {
          		listen 443 ssl;
          		listen [::]:443 ssl;
          		server_name rsync.hardenedbsd.org installers.hardenedbsd.org;
          
          		location / {
          			proxy_pass https://hbsd-os-build-01;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
          		}
          		break;
          	}
          
          	server {
          		listen 443 ssl;
          		listen [::]:443 ssl;
          		server_name hbsd-pkg-13-stable-01.hardenedbsd.org;
          
          		location / {
          			proxy_pass https://hbsd-pkg-13-stable-01;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
          		}
          		break;
          	}
          
          	server {
          		listen 443 ssl;
          		listen [::]:443 ssl;
          		server_name hbsd-pkg-current-01.hardenedbsd.org;
          
          		location / {
          			proxy_pass https://hbsd-pkg-current-01;
          			proxy_set_header Host $http_host;
          			proxy_set_header X-Forwarded-For $remote_addr;
          			break;
          		}
          		break;
          	}
          
          }
          

          As a bonus, here’s a snippet of the unbound config file for the HardenedBSD build infrastructure DNS server:

          server:
          	log-servfail: yes
          	local-zone: "md.hardenedbsd.lan" static
          	local-data: "hbsd-pkg-current-01.hardenedbsd.lan. IN AAAA 2001:470:e1e1:100::125"
          
          1. 2

            Hmm, it seems like to me you are re-doing encryption right? It’s not exactly a SNI technique per se, is it? I wonder though what is the impact of connecting two TLS segments like this in terms of performance or traffic increase.

            1. 1

              nginx is doing SNI behind-the-scenes automatically for me.

              1. 2

                But then, what is the ssl_certificate / ssl_certificate_key used for? SNI should not require any TLS certificates as far as I understand it?

                1. 1

                  Cryptographic key material is required regardless. In this context, SNI is used simply to determine which host the client is trying to reach. nginx doesn’t require any extra configuration parameters for SNI (meaning: full native transparent support for SNI) when SSL/TLS support is compiled in.

                  1. 2

                    Cryptographic key material is required regardless.

                    This is the part I don’t understand; what is the minimal requirement for the material? dhparams or?

                    So if I understand well, your NGINX cannot “dump” the plaintext communication between a client and git.hardenedbsd.org for example, right? Do you have any link on the matter? I am definitely confused a bit on this.

                    1. 1

                      Doesn’t TLS require cryptographic key material? This is just regular HTTPS with TLS and SNI. I’m unsure as to the source of your confusion…

                      1. 2

                        If you take a look to my article, I never use any cryptographic key material. See https://github.com/dlundquist/sniproxy for examples too. It never use any cryptographic key material, neither it does decrypt the traffic. So that’s why I’m wondering why this is needed in your case.

          2. 1

            I wonder, could you use something like Boundary or Teleport for SSH where TLS is built in? So you do v6 to the proxy and that does v4 to the target.

            1. 1

              I find it a lot easier to just set up an SSH jump host (hop host) on the IPv4 address, and use -o ProxyJump hop.$DOMAIN.

              Or even set up your ~/.ssh/config:

              Host hop.example.com
              	ProxyJump none
              Host *.example.com
              	ProxyJump hop.example.com