Accessing the ssh server over a very congested connection

This article is the result of my visit to a car service. While waiting for the car, I connected my laptop to the guest wifi network and read the news. To my surprise, I found that I could not visit some sites. Knowing about sshuttle (and being a big fan of this project) I tried to establish an sshuttle session with my server, but it didn't work. Port 22 was tightly blocked. At the same time, nginx on port 443 responded normally. By the next visit to the car service, I installed the sslh multiplexer on the server .The server is running gentoo and I added the following line to the /etc/conf.d/sslh file:



DAEMON_OPTS="-p 0.0.0.0:443 --ssl 127.0.0.1:8443 --ssh 127.0.0.1:22 --user nobody"
      
      





Depending on the type of connection, connections to port 443 are either forwarded to the local port:



  • 8433 in case of https (nginx is running on this port)
  • 22 in case of ssh


But when I tried to establish an ssh connection to the server, I again failed. Apparently, the filtering was carried out not just by ports, but deep packet investigation was also used. This makes the task more difficult. Ssh traffic must be wrapped in https. Fortunately, it's not difficult thanks to the websocat project . On the project page, you can find many compiled binaries. If for some reason you want to compile the binary yourself from source, this is also not very difficult. I do this with hashicorp's packer with the following configuration:



{
  "min_packer_version": "1.6.5",
  "builders": [
    {
      "type": "docker",
      "image": "ubuntu:20.04",
      "privileged": true,
      "discard": true,
      "volumes": {
        "{{pwd}}": "/output"
      }
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "skip_clean": true,
      "environment_vars": [
        "DEBIAN_FRONTEND=noninteractive"
      ],
      "inline": [
        "apt-get update && apt-get install -y git curl gcc libssl-dev pkg-config gcc-arm-linux-gnueabihf",
        "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs >/tmp/rustup.sh && chmod +x /tmp/rustup.sh && /tmp/rustup.sh -y",
        "git clone https://github.com/vi/websocat.git && cd websocat/",
        ". $HOME/.cargo/env && cargo build --release --features=ssl",
        "printf '[target.armv7-unknown-linux-gnueabihf]\nlinker = \"arm-linux-gnueabihf-gcc\"\n' >$HOME/.cargo/config",
        "rustup target add armv7-unknown-linux-gnueabihf",
        "cargo build --target=armv7-unknown-linux-gnueabihf --release",
        "strip target/release/websocat",
        "tar czf /output/websocat.tgz target/armv7-unknown-linux-gnueabihf/release/websocat target/release/websocat",
        "chown --reference=/output /output/websocat.tgz"
      ]
    }
  ]
}

      
      





The client side is on ubuntu 20.04, the server runs on nvidia tegra jetson tk1, so for it I am doing a cross-assembly for the armv7 platform. Please note that the server build is done without ssl support, since ssl termination for me is performed by nginx, which processes incoming connections. The nginx configuration looks like this:



http {
    server {
        listen 0.0.0.0:8443 ssl;
        server_name your.host.com;
        ssl_certificate /etc/letsencrypt/live/your.host.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/your.host.com/privkey.pem;
        location /wstunnel/ {
            proxy_pass http://127.0.0.1:8022;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }
    }
}

      
      





I run Websocat from the crown of my user:



* * * * * netstat -lnt|grep -q :8022 || $HOME/bin/websocat -E --binary ws-l:127.0.0.1:8022 tcp:127.0.0.1:22|logger -t websocat &
      
      





Now you can connect to your server like this:



ssh -o ProxyCommand='websocat --binary wss://your.host.com/wstunnel/' your.host.com
      
      





How much does wrapping in https reduce bandwidth? In order to check this, I used the following command:



ssh -o ProxyCommand='websocat --binary wss://your.host.com/wstunnel/' your.host.com 'dd if=/dev/zero count=32768 bs=8192' >/dev/null
      
      





In my experiments, I got a 2x reduction in bandwidth. When using the ws: // protocol, i.e. http, the connection bandwidth is identical to non-wrapped ssh.



Here's how you can set up an sshuttle session:



sshuttle -e 'ssh -o ProxyCommand="websocat --binary wss://your.host.com/wstunnel/"' -r your.host.com 0/0 -x $(dig +short your.host.com)/32
      
      





At the next visit to the car service, I made sure that everything works as it should. As a nice bonus, the number of attempts to log in to the server via ssh from the left addresses dropped sharply.



All Articles