By Bill Brassfield – Dev Ops Technical Consultant
First, a review of simple TCP SSH tunnels:
Many of us are quite familiar with the setup of SSH tunnels using the “-L” and “-R” options to do TCP port-forwarding — to access a web server behind a NAT and/or firewall, to connect to a MySQL or Oracle database that isn’t directly reachable, or to make a desktop workstation at the office reachable via SSH through a bastion host which is SSH-reachable. Here are some examples of SSH commands that probably look quite familiar:
Forwarding a local TCP port to a remote TCP port:
(using the -L option)ssh -L 127.0.0.1:2022:10.150.35.74:22
ssh -L 8080:localhost:80 email@example.com
ssh -L 192.168.3.45:8080:web01.example.com:80
Forwarding a remote TCP port to a local TCP port:
(using the -R option)ssh -R localhost:2022:localhost:22
sudo ssh -R web99.example.com:80:localhost:80 firstname.lastname@example.org
A few quick notes on sshd_config directives:
- Make sure that “AllowTcpForwarding” is enabled (set to “yes”).
- If setting up a TCP-forwarding listener on a non-loopback network interface,
it may be necessary to set “GatewayPorts” to “yes”.
- If setting up a TCP-forwarding listener on a privileged port (0 to 1023), this must be done
as root. If opening a privileged port for listening on a remote system, the “PermitRootLogin” the directive must be set to either “yes” or “without-password”.
Useful command-line options for the commands discussed above:
- The “-f” option tells SSH to run in the background.
- The “-N” option tells SSH to not run any command on the remote server.
- Adding both the “-f” and “-N” options to the SSH commands listed above will effectively run them quietly in the background (in a “daemonized” mode). To terminate these tunnels, it will be necessary to find their process-ID (PID) and send a SIGTERM kill signal.
- Adding the “-o ServerAliveInterval=30” option will help to keep the tunnels up by keeping the TCP connections are active. (Some network appliances terminate TCP sessions which sit idle for a few minutes.)
Tunneling non-TCP protocols with Layer-2 and Layer-3 VPN tunnels:
SSH can do much more than the TCP port-forwarding examples shown above. It’s actually possible to do ICMP pings, DNS lookups, NTP time syncing, and TFTP file transfers over a Layer-3 SSH VPN tunnel. For protocols such as DHCP, or for bridging remote networks together, a Layer-2 SSH VPN tunnel can be used.
Establishing a layer-3 SSH VPN using “tun” devices:
On the local server, issue the following command:sudo ssh -f -w 0:0 email@example.com true
(NOTE: You must be root on BOTH the local system and the remote system in order to create the “tun0” virtual network devices and connect them via SSH’s tunneling protocol.) On the local server:sudo ifconfig tun0 192.168.1.101 netmask 255.255.255.0
On the remote server:sudo ifconfig tun0 192.168.1.102 netmask 255.255.255.0
At this point, it should be possible for the local and remote servers to ICMP ping each other at their 192.168.1.x IP addresses. If the pings are successful, then it should also be possible to pass TCP and UDP traffic over the tunnel. To shut down the tunnel, find the process-ID (PID) of the ssh command on the local server and send it a SIGTERM kill signal.
- Make sure “PermitTunnel” is set to “yes” in sshd_config on both ends.
- Check to make sure IPTables isn’t blocking traffic in/out of the tun0 network interfaces.
- Make sure “PermitRootLogin” is set to “yes” in sshd_config on the remote system.
Establishing a layer-2 SSH VPN using “tap” devices:
On both the local and remote servers, run the following command to create a “tap0” virtual network interface:sudo tunctl -t tap0
orsudo ip tuntap add dev tap0 mode tap
Next, configure the “tap0” interfaces on both ends: On the local host:sudo ifconfig tap0 192.168.1.101 netmask 255.255.255.0
On the remote host:sudo ifconfig tap0 192.168.1.102 netmask 255.255.255.0
Now start the SSH Layer-2 VPN tunnel by issuing the following command on the localhost:ssh -o Tunnel=ethernet -f -w 0:0 firstname.lastname@example.org true
Assuming all went well, the tunnel should be up, and it should be possible for the local and remote servers to ping each other on their 192.168.1.x IP addresses. Also, running the command “ethtool tap0” on both ends should show “Link detected: yes” in the output. TCP and UDP protocols should work over the tunnel (provided that there are no IPTables firewall rules blocking such traffic). Additionally, DHCP and network-bridging can also be done over the tunnel. (For details on how to do this, see the white paper on Advanced SSH Tunneling.)
SSH offers much more than just TCP port-forwarding; it has VPN-tunneling capabilities which can be used to seamlessly join local and remote networks. The performance of SSH VPN tunnels can’t compete against that of hardware-based VPNs (Cisco, Juniper, etc.) or that of VPN-specific software like OpenVPN. Activities such as PXE-boot network OS installations can be quite slow, and protocols such as VoIP, streaming audio, or streaming video are likely to suffer greatly, with buffering-delays and dropouts. In a pinch, though, SSH VPN tunneling can be a convenient, temporary means of “getting the job done” if other VPN implementations aren’t immediately available.