7.4. Building VPNs with SSHWe have already seen how SSH can provide a secure tunnel between applications, and in this sense, it might be said to function as a VPN as we've previously defined that term. In this section, we show how to use SSH to join two networksinstead of two applicationswith a secure tunnel. Like its SSL counterpart, this VPN can suffer from performance problems due to the interactions between two instances of TCP. For this reason, the VPNs that we describe are probably not suitable for production environments, but they are easy to set up and so make excellent ad hoc solutions to small problems or as a way of temporarily linking two networks with a VPN. In Chapter 6, we built our VPN by running PPP through an SSL connection. We could do that here as well in an essentially identical way.
Instead of using PPP, we illustrate another method by making use of a gtunnel-based application that we call sshvpn. We set up our tunnel between bsd and laptop, using the architecture shown in Figure 7.58. Figure 7.58. Architecture for the SSH VPN
Notice that the figure is similar to Figure 7.22: sshvpn starts an SSH client, with which it communicates via pipes. The SSH client, in turn, connects to the SSH server on laptop, and the SSH server starts another instance of sshvpn, which it communicates with via pipes. As in Figure 7.22, we have shown the two spawned processes as dashed boxes. All communication between the two instances of sshvpn TRavels through the SSH tunnel and so is encrypted and authenticated. The rest of Figure 7.58 shows that the two instances of sshvpn are connected to their hosts' TCP/IP stacks via the tun0 interface. Thus, data written into the tun0 interface on bsd will be read by the sshvpn on bsd, sent through the SSH tunnel to the sshvpn on laptop, and, finally, written into the tun0 interface on laptop by the sshvpn running there.
A convenient way of visualizing this process is to think of the sshvpn/ssh combination on bsd and the sshvpn/sshd combination on laptop as network interfaces that happen to communicate with each other using the SSH protocol. To the applications that use the VPN, the tun0 interface appears to be exactly this. On the one hand, it appears like any other network interfacean Ethernet interface, sayand on the other hand, it communicates with its peer interface over an SSH tunnel. The sshvpn ApplicationAs with our gtunnel-based IP-in-IP tunnel from Chapter 4, we need specify only startup, inbound, and outbound functions to add to our gtunnel skeleton. Let's begin with startup (Figure 7.59). This function behaves differently, depending on whether it is run on the local (SSH client) side or the remote (SSH server) side. On the local side, it must start ssh and establish the pipes between ssh and itself. On the remote side, sshvpn will be started by sshd, so startup need only map infd and outfd to STDIN and STDOUT. We signal which action startup should perform by calling sshvpn with a single parameter containing our peer's name or address when on the local side and with no parameters on the remote side. Figure 7.59. The sshvpn startup Function
startup
The outbound function is shown in Figure 7.60. Figure 7.60. The sshvpn outbound Function
outbound
The inbound function, shown in Figure 7.61, is equally simple. Figure 7.61. The sshvpn inbound Function
inbound
Running sshvpnRunning the sshvpn program is easy. After configuring the tun0 devices on bsd and laptop, we start sshvpn: bsd# ./sshvpn laptop Password: enter laptop's root password VPN runs until we kill it ^CKilled by signal 2. VPN killed The password prompt is from SSH, asking us to authenticate ourselves to the SSH server on laptop. After the authentication, sshd on laptop starts a local copy of sshvpn, and the VPN is up and ready to pass traffic. We can test this by pinging laptop from bsd: $ ping 192.168.2.1 PING 192.168.2.1 (192.168.2.1): 56 data bytes 64 bytes from 192.168.2.1: icmp_seq=0 ttl=64 time=2.999 ms 64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=2.600 ms 64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=1.791 ms 64 bytes from 192.168.2.1: icmp_seq=3 ttl=64 time=1.741 ms ^C --- 192.168.2.1 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max/stddev = 1.741/2.283/2.999/0.536 ms As in the case of our SSL VPN from Chapter 6, it is instructive to consider what the packets traveling through the tunnel look like. In the case of our pings from the preceding example, we have Figure 7.62. Figure 7.62. SSH VPN Datagram Format
In this case, the ping packet is 84 bytes. The entire packet is 176 bytes, so there is a 92-byte overhead (55 percent). This overhead would be less dramatic if the payload packet were larger. For example, the overhead would be only 7 percent for a 1,300-byte payload. As with all VPNs that use TCP as a transport medium, the more significant overhead is with round-trip time. The average ping response was 2.283 milliseconds, which is comparable to what we saw with the SSL VPN in Chapter 6. As before, the ping response times over the LAN, without the VPN, are about an order of magnitude less: $ ping laptop
PING laptop.jcs.local (172.30.0.6): 56 data bytes
64 bytes from 172.30.0.6: icmp_seq=0 ttl=64 time=0.252 ms
64 bytes from 172.30.0.6: icmp_seq=1 ttl=64 time=0.258 ms
64 bytes from 172.30.0.6: icmp_seq=2 ttl=64 time=0.357 ms
64 bytes from 172.30.0.6: icmp_seq=3 ttl=64 time=0.262 ms
^C
--- laptop.jcs.local ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.252/0.282/0.357/0.043 msAs mentioned in Chapter 6, the ping test is optimal in the sense that the payload is not TCP, so there are not two instances of TCP with competing reliability mechanisms. SSH VPNs are easy to set up and may make sense if performance is not an issue or if the majority of the traffic will be UDP datagrams. SSH VPNs are especially handy for temporary ad hoc VPNs. |