Chapter 10. Secure Tunnels

Untrusted computer networks (such as the Internet and public wireless networks) can be pretty hostile environments, but they can be tamed to some degree. This chapter primarily deals with how to set up secure, encrypted communications over networks that you don’t completely trust. Some of the hacks focus mainly on providing a secure and encrypted transport mechanism, while others discuss how to create a virtual private network (VPN). As you’ll see here, by leveraging encryption and some encapsulation tricks you can build more trustworthy networks on top of an untrusted network, even if the latter is full of miscreants trying to spy on or otherwise manipulate your data.

By reading this chapter, you’ll learn how to set up IPsec-based encrypted links on several operating systems, how to create virtual network interfaces that can be tunneled through an encrypted connection, and how to forward TCP connections over an encrypted channel. In addition, you’ll learn how to set up a cross-platform VPN solution.

The beauty of most of these hacks is that after reading them, you can mix and match transport-layer encryption solutions with whatever virtual-network-oriented approach best meets your needs. In this way, you can safely build vast, powerful private networks leveraging the public Internet as infrastructure. You can use these techniques for anything from securely connecting two remote offices to building a completely routed private network enterprise on top of the Internet.

Secure your traffic in Linux with Openswan.

The most popular way of configuring IPsec connections under Linux is by using the Openswan (http://www.openswan.org) package. Openswan is made up of two components: pluto and, optionally, KerneL IP Security (KLIPS). As of Version 2.6, the Linux kernel includes support for IPsec, but KLIPS can be used instead for some additional features. pluto is the user-land daemon that controls Internet Key Exchange (IKE) negotiation.

To get started, download the latest source for the Openswan tools from the project’s web site and unpack the source tree. Then, change to the directory that was extracted and build it:

$ tar xfz openswan-2.4.6rc3.tar.gz
$ cd openswan-2.4.6rc3
$ make programs
         

After it finishes compiling, become root and run make install.

If you want to try out Openswan’s opportunistic encryption support [Hack #95], use KLIPS instead of native IPsec support in the kernel. To do this, download the appropriate patch from the Openswan download page. Apply the patch to your kernel source with the following commands:

# cd /usr/src/kernels/linux-2.6.14.6
# zcat /tmp/openswan-2.4.6rc3.kernel-2.6-klips.patch.gz | patch -p1
         

If you configured your kernel source prior to applying the patch, you can quickly and easily enable KLIPS by running make oldconfig. Here are the options that you need enabled:

Openswan IPsec (KLIPS26) (KLIPS) [N/m/y/?] (NEW) m
    *
    * KLIPS options
    *
    Encapsulating Security Payload - ESP ("VPN") (KLIPS_ESP) [Y/n/?] (NEW) 
    Authentication Header - AH (KLIPS_AH) [N/y/?] (NEW) y
    HMAC-MD5 authentication algorithm (KLIPS_AUTH_HMAC_MD5) [Y/n/?] (NEW) 
    HMAC-SHA1 authentication algorithm (KLIPS_AUTH_HMAC_SHA1) [Y/n/?] (NEW) 
    CryptoAPI algorithm interface (KLIPS_ENC_CRYPTOAPI) [N/y/?] (NEW) 
    3DES encryption algorithm (KLIPS_ENC_3DES) [Y/n/?] (NEW) 
    AES encryption algorithm (KLIPS_ENC_AES) [Y/n/?] (NEW) 
    IP compression (KLIPS_IPCOMP) [Y/n/?] (NEW) 
    IPsec debugging (KLIPS_DEBUG) [Y/n/?] (NEW) 

This output shows KLIPS set up to be compiled as a module; however, you can link it into the kernel statically if you prefer.

If you patched your kernel for KLIPS, rebuild it and reboot with it. When you next boot up, the ipsec service will automatically start. If you chose to use the kernel’s built-in IPsec support, you can go ahead and start it now:

# /etc/init.d/ipsec start
ipsec_setup: Starting Openswan IPsec 2.4.6rc3...
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/net/key/af_key.ko 
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/net/ipv4/ah4.ko 
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/net/ipv4/esp4.ko 
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/net/ipv4/ipcomp.ko 
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/net/ipv4/xfrm4_tunnel.ko 
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/crypto/des.ko 
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/crypto/aes.ko 

Now, verify that your system settings are configured correctly to use IPsec:

# /usr/local/sbin/ipsec verify
Checking your system to see if IPsec got installed and started correctly:
Version check and ipsec on-path                                 [OK]
Linux Openswan U2.4.6rc3/K2.6.16-1.2115_FC4 (netkey)
Checking for IPsec support in kernel                            [OK]
NETKEY detected, testing for disabled ICMP send_redirects       [FAILED]

  Please disable /proc/sys/net/ipv4/conf/*/send_redirects
  or NETKEY will cause the sending of bogus ICMP redirects!

NETKEY detected, testing for disabled ICMP accept_redirects     [FAILED]

  Please disable /proc/sys/net/ipv4/conf/*/accept_redirects
  or NETKEY will accept bogus ICMP redirects!

Checking for RSA private key (/etc/ipsec.secrets)               [OK]
Checking that pluto is running                                  [OK]
Two or more interfaces found, checking IP forwarding            [FAILED]
Checking for 'ip' command                                       [OK]
Checking for 'iptables' command                                 [OK]
Opportunistic Encryption Support                                [DISABLED]

Be sure to investigate any item that shows up as FAILED. The previous example shows that you’ll need to disable sending and accepting ICMP redirects and enable IP forwarding. To disable ICMP redirects, run the following commands:

# for f in /proc/sys/net/ipv4/conf/*/accept_redirects; do echo 0 > $f; done
# for f in /proc/sys/net/ipv4/conf/*/send_redirects; do echo 0 > $f; done
         

To disable IP forwarding, run this:

# echo 1 > /proc/sys/net/ipv4/ip_forward 
         

Now, verify the settings again to make sure that everything shows up as OK:

# /usr/local/sbin/ipsec verify
Checking your system to see if IPsec got installed and started correctly:
Version check and ipsec on-path                                 [OK]
Linux Openswan U2.4.6rc3/K2.6.16-1.2115_FC4 (netkey)
Checking for IPsec support in kernel                            [OK]
NETKEY detected, testing for disabled ICMP send_redirects       [OK]
NETKEY detected, testing for disabled ICMP accept_redirects     [OK]
Checking for RSA private key (/etc/ipsec.secrets)               [OK]
Checking that pluto is running                                  [OK]
Two or more interfaces found, checking IP forwarding            [OK]
Checking NAT and MASQUERADEing                                  [N/A]
Checking for 'ip' command                                       [OK]
Checking for 'iptables' command                                 [OK]
Opportunistic Encryption Support                                [DISABLED]

Now, you can get on with the task of configuring Openswan. Openswan’s configuration is controlled by two configuration files: /etc/ipsec.conf and /etc/ipsec.secrets. The ipsec.conf file breaks a VPN connection into right and left segments. This is merely a logical division. The segment on the left can be either the internal or the external network; this allows the same configuration file to be used for both ends of a VPN network-to-network tunnel.

Now, start with a simple ipsec.conf to test out Openswan. Adding an entry like this creates an encrypted tunnel between two hosts:

conn host-to-host
     left=192.168.0.64
     leftid=@colossus.nnc
     #leftnexthop=%defaultroute
     right=192.168.0.62
     rightid=@spek.nnc
     #rightnexthop=%defaultroute
     auto=add             

This will work if the hosts are both on the same network. If they’re not, you can uncomment the leftnexthop and rightnexthop entries. For authentication purposes, this connection uses RSA signatures, which are obtained by running /usr/local/sbin/ipsec showhostkey on both hosts.

Log into the host that you specified for left, run the following command, and then paste the output into your configuration file:

# /usr/local/sbin/ipsec showhostkey --left
        # RSA 2192 bits   colossus.nnc   Thu Jul 13 20:48:58 2006
        leftrsasigkey=0sAQNpOndA2SO5aQnEmxqlM5c3JerA9cMwGB0wPE9PshVFBgY44
Ml8Lw7usdMzZTMNaSeXu3+80fK7aXWqBGVXWpIEw2EAFlGcbg1mrEoAVpLwbpM7ZmZPr6Cl0A
dFyTFxFK4k52y702h6xsdSoeTWabs2vkzPLDR8QqvlzIzPkDHE+MQG4q/F+fVUkn/TNeGL7ax
xfVkepqTHI1nwbNsLdPXdWGKL9c28ho8TTSgmVMgr9jVLYMNwWjN/BgKMF5J/glALr6kjy19u
NEpPFpcq9d0onjTMOts1xyfj0bst2+IMufX21ePuCRDkWuYsfcTMlo7o7Cu+alW0AP4mZHz8Z
e8PzRm9h3oGrUMmwCoLWzMeruud

Now, get the key to paste in for the right host by logging into it and running the same command, this time replacing --left with --right.

Copy the configuration file to both hosts and restart the ipsec service on both systems:

# /etc/init.d/ipsec restart
ipsec_setup: Stopping Openswan IPsec...
ipsec_setup: Starting Openswan IPsec 2.4.6rc3...
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/net/key/af_key.ko 
ipsec_setup: insmod /lib/modules/2.6.16-1.2115_FC4/kernel/net/ipv4/xfrm4_tunnel.ko 

Then, create the IPsec connection by running the following command on one of the hosts:

# /usr/local/sbin/ipsec auto --up host-to-host
104 "host-to-host" #6: STATE_MAIN_I1: initiate
003 "host-to-host" #6: received Vendor ID payload [Openswan (this version) 2.4.6rc3  X.509-1.5.4 PLUTO_SENDS_VENDORID PLUTO_USES_KEYRR]
003 "host-to-host" #6: received Vendor ID payload [Dead Peer Detection]
003 "host-to-host" #6: received Vendor ID payload [RFC 3947] method set to=110 
106 "host-to-host" #6: STATE_MAIN_I2: sent MI2, expecting MR2
003 "host-to-host" #6: NAT-Traversal: Result using 3: no NAT detected
108 "host-to-host" #6: STATE_MAIN_I3: sent MI3, expecting MR3
004 "host-to-host" #6: STATE_MAIN_I4: ISAKMP SA established {auth=OAKLEY_RSA_SIG cipher=oakley_3des_cbc_192 prf=oakley_md5 group=modp1536}
117 "host-to-host" #7: STATE_QUICK_I1: initiate
004 "host-to-host" #7: STATE_QUICK_I2: sent QI2, IPsec SA established {ESP=>0x070009a9 <0xca6c0796 xfrm=AES_0-HMAC_SHA1 NATD=none DPD=none}

If you want to test out your connection, ping one of the hosts in the tunnel from the other one:

$ ping spek.nnc
PING spek.nnc (192.168.0.62) 56(84) bytes of data.
64 bytes from spek.nnc (192.168.0.62): icmp_seq=0 ttl=64 time=3.56 ms
64 bytes from spek.nnc (192.168.0.62): icmp_seq=1 ttl=64 time=0.975 ms
64 bytes from spek.nnc (192.168.0.62): icmp_seq=2 ttl=64 time=1.73 ms
64 bytes from spek.nnc (192.168.0.62): icmp_seq=3 ttl=64 time=2.29 ms
...

Now, start tcpdump on the other host:

# /usr/sbin/tcpdump -n -i eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
23:57:35.280722 IP 192.168.0.43 > 192.168.0.62: ESP(spi=0x070009a9,seq=0x18)
23:57:35.280893 IP 192.168.0.43 > 192.168.0.62: icmp 64: echo request seq 19
23:57:35.280963 IP 192.168.0.62 > 192.168.0.43: ESP(spi=0xca6c0796,seq=0x18)
23:57:36.267451 IP 192.168.0.43 > 192.168.0.62: ESP(spi=0x070009a9,seq=0x19)
23:57:36.267451 IP 192.168.0.43 > 192.168.0.62: icmp 64: echo request seq 20
23:57:36.269713 IP 192.168.0.62 > 192.168.0.43: ESP(spi=0xca6c0796,seq=0x19)

Notice the ESP packets in the output. The contents of these packets are encrypted using IPsec’s Encapsulated Security Payload. Don’t worry about the ICMP echo (ping) packets that you see, though. They show up because the kernel’s IPsec stack uses the same interface for encrypted and decrypted packets, rather than using a virtual interface for the decrypted packets. If you’re able to sniff the packets from a third host, you’ll see only the ESP ones.

Congratulations! All traffic between the two hosts you configured will now be seamlessly encrypted. However, Openswan has many possible configurations, such as network-to-network and host-to-network tunnels, as well as seamless opportunistic encryption [Hack #95]. For more information, check out the ipsec.conf manual page (man ipsec.conf), as well as the examples in the /etc/ipsec.d/examples directory and in the doc/examples file distributed with the Openswan source code.