Reducing latency of SSH tunnelled connections (BASH)

The ability to tunnel connections over an SSH connection is incredibly useful, essentially creating a poor man's VPN, whether to a specific port (ssh -L 1443:google.com:443 ssh-server.domain) or by standing up a SOCKS proxy (ssh -D 8080 ssh-server.domain).

The most common complaint when doing this, though, is that the latency sucks. This is because of the TCP over TCP Problem. You're essentially running two layers of TCP congestion control, so any loss hurts - a lot.

This can be addressed by installing and using SShuttle (docs here).

It works (on Linux and Mac OS X) by intercepting and termination TCP connections locally, and transmitting payload and packet metadata over a SSH connection as data. The remote end re-assembles the packets and transmits on your behalf. The remote end only needs to have Python installed (as sshuttle remotely runs a python snippet to handle receipt and re-assembly of packet information).

The result is, there's no TCP connection within the tunnel, so you're still only contending with a single layer of congestion control

Details

  • Language: BASH

Snippet

# Tunnel any packets destinated for 192.168.1.0/24 via ssh-server.domain
sshuttle -r ssh-server.domain 192.168.1.0/24 

# Send everything via the tunnel
sshuttle -r ssh-server.domain 0.0.0.0/0

# Send only port 80 traffic via the tunnel
sshuttle -r ssh-server.domain 0.0.0.0/0:80 

# Send connections to port numbers between 2000 and 3000 via tunnel
sshuttle -r ssh-server.domain 192.168.1.0/24:2000-3000

# Bind to port 1234 and forward connections to 8.8.8.8 via the tunnel
# can be used to provide a proxy to other machines on your LAN
sshuttle -l 0.0.0.0:1234 -r ssh-server.domain 8.8.8.8/32

# Check whether a DNS name is valid at the remote end, and update /etc/hosts
#
# Useful to save mucking around with changing DNS whenever you bring a tunnel up
sshuttle -H -r ssh-server.domain 192.168.1.0/24

# Intercept local DNS queries and send them all over the tunnel (to avoid DNS leaks)
sshuttle --dns -r ssh-server.domain 0.0.0.0/0

# Forward everything but 192.168.2.0/24
sshuttle -X 192.168.2.0/24 -r ssh-server.domain 0.0.0.0/0

Usage Example

# Any of the config options can be dumped into a config file (one per line):

cat /etc/sshuttle.conf
-r ssh-server.domain
--dns
-X 192.168.2.0/24
0.0.0.0/0

# When calling sshuttle, pass it the path to the config file, prefixed with @
sshuttle @/etc/sshuttle.conf