[ Main / Projects / Docs / Files / FAQ / Links ]

Introduction

WEP and WPA are imperfect solutions to wireless security that exact great performance costs for marginal or nonexistent gains in security. IPSec is a relatively proven solution for creating private, secure VPNs over untrusted networks. It is cross-platform and extensively used, but the Linux 2.6 implementation is rather poorly documented for use in wireless networks. In this document, I attempt to outline a viable IPSec setup that will provide a secure IPSec tunnel between a wireless client and a wireless Linux gateway.

Prerequisites

In my personal network, I have one computer that I use as a gateway for my wireless network. I have one 100Mbit NIC to the Internet, one 1Gbit NIC to my local LAN, and one Atheros A/B/G NIC for my wireless. Both private networks take advantage of the private address space and do not use publically routable IPs. A client machine on my wireless network is equipped with a single wireless NIC and is given an address on the wireless subnet.

Before you start, your wireless network should be tested to work with no encryption enabled. Once IPSec is working, it is a good idea to disable any sort of WEP/WPA encryption that may have been in use -- IPSec is more secure and both WEP and WPA introduce unnecessary protocol overhead that will slow your wireless network.

Diagram of example network:


<->   == NIC
<-w-> == Wireless NIC
[]    == Network

 Internet <-> OUTSIDE|172.16.1.1 <-> [172.16.1.0/24] <-w-> 172.16.1.2
                   mastergw                                 notebook

Recent versions of Linux 2.6 must be used; I've used Linux 2.6.17 for my configuration. The kernel networking should be built to include PF_KEY sockets (CONFIG_NET_KEY), IP: AH transformation (CONFIG_INET_AH), IP: ESP transformation (CONFIG_INET_ESP), IP: IPComp transformation (CONFIG_INET_IPCOMP), and IPsec user configuration interface (CONFIG_XFRM_USER). Netfilter should be configured for use as a firewall on the gateway machine. The Linux cryptographic API should be enabled to include HMAC support, SHA256, AES, and Deflate compression. Other cryptographic ciphers and hashes may be enabled at the user's discretion. The kernel should be compiled and installed as usual.

The necessary userspace utilities must be compiled and installed as well. setkey and racoon are the essentials. Also, if you haven't done so recently, it may be a good idea to make sure that your iptables is up-to-date.

Certificates

X.509 certificates must be generated for the wireless gateway and for all machines that will be connecting to it. The Gentoo IPSec-HOWTO does an excellent job of explaining the process, so I will simply direct you to that site for this step. For my configuration, I placed certificates in /etc/ssl/certs on each machine. I will assume that you do the same.

ipsec.conf

The gateway machine's /etc/ipsec.conf should look something like this:

#!/usr/local/sbin/setkey -f

flush;
spdflush;

spdadd 0.0.0.0/0 172.16.1.2 any -P out ipsec
	esp/tunnel/172.16.1.1-172.16.1.2/require;
spdadd 172.16.1.2 0.0.0.0/0 any -P in ipsec
	esp/tunnel/172.16.1.2-172.16.1.1/require;

The matching client configuration would be:

#!/usr/local/sbin/setkey -f

flush;
spdflush;

spdadd 0.0.0.0/0 172.16.1.2 any -P in ipsec
	esp/tunnel/172.16.1.1-172.16.1.2/require;
spdadd 172.16.1.2 0.0.0.0/0 any -P out ipsec
	esp/tunnel/172.16.1.2-172.16.1.1/require;

Notice the symmetry. Also note that the server configuration would require a pair of entries for each machine connected to the wireless network as they are all independent 'networks' and act as tunnel endpoints only for themselves. Each client needs only to be aware of the gateway.

/etc/ipsec.conf should be set as executable, as it is nothing more than a script. The necessary setkey information may then be communicated to the kernel by simply invoking /etc/ipsec.conf. SA and SPD information may be cleared from the kernel with setkey -F.

racoon.conf

Since we are using dynamic keying, we will next need to configure racoon, the program that handles IKE. The gateway's /etc/racoon/racoon.conf would look like:

path certificate "/etc/ssl/certs";

listen {
	isakmp 172.16.1.1;
}

remote 172.16.1.2 {
        exchange_mode main;
        certificate_type x509 "gateway_cert.pem" "gateway_key.pem";
        verify_cert on;
        my_identifier asn1dn;
        peers_identifier asn1dn;
        proposal {
                encryption_algorithm aes;
                hash_algorithm sha256;
                authentication_method rsasig;
                dh_group modp1024;
        }
}

sainfo anonymous {
        pfs_group modp1024;
        encryption_algorithm aes;
        authentication_algorithm hmac_sha256;
        compression_algorithm deflate;
}

Our client's racoon.conf would be:

path certificate "/etc/ssl/certs";

remote 172.16.1.1 {
        exchange_mode main;
        certificate_type x509 "client_cert.pem" "client_key.pem";
        verify_cert on;
        my_identifier asn1dn;
        peers_identifier asn1dn;
        proposal {
                encryption_algorithm aes;
                hash_algorithm sha256;
                authentication_method rsasig;
                dh_group modp1024;
        }
}

sainfo anonymous {
        pfs_group modp1024;
        encryption_algorithm aes;
        authentication_algorithm hmac_sha256;
        compression_algorithm deflate;
}

Before you test, keep in mind that your iptables rules may not permit ipsec traffic. Make sure you have a very permissive set of rules while testing -- rules can be made more restrictive once ipsec is properly working.

Testing

At this point, racoon should be run on both the gateway and the client. Check the logs to see if racoon starts cleanly. If not, try to look back at the earlier steps in the document, find the problem, and fix it (Google is your friend here, too!). If you are planning on using privsep, I would suggest setting that up after your network works without privsep racoon; configuration of privsep is non-trivial, and ipsec is already hard to debug.

Now the ipsec configuration should be tested to be sure that it works before the firewall is instituted. Load the setkey information by invoking /etc/ipsec.conf. Then try to ping the gateway from the client and the client from the gateway. If both sides can ping each other, then everything is working fine so far.

Firewall

Now our traffic that travels from the gateway to the client and vice versa is authenticated by AH and encrypted by ESP; it will be very difficult for a wardriver to intercept traffic travelling between the two machines. However, we have done nothing so far to prevent a wardriver from being able to access services on the gateway or to use our upstream Internet connection. We will now make sure that wardrivers will be unable access our network with the help of an old friend, Netfilter.

# the following default policies are assumed
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT ACCEPT

# Allow DHCP requests on wifi
$IPT -A INPUT -i $WIFI_IF -p udp --dport 67:68 --sport 67:68 -j ACCEPT
$IPT -A INPUT -i $WIFI_IF -p udp  --dport 500 -j ACCEPT
$IPT -A INPUT -i $WIFI_IF -p ah -j ACCEPT
$IPT -A INPUT -i $WIFI_IF -p esp -j ACCEPT

$IPT -A FORWARD -i $WIFI_IF -s $WIFI_NET -m state  \
	--state NEW,ESTABLISHED -m policy --dir in --pol ipsec \
	-j ACCEPT
$IPT -A FORWARD -i ! $WIFI_IF -o $WIFI_IF -d $WIFI_NET -m state \
	--state ESTABLISHED -m policy --dir in --pol ipsec -j ACCEPT
$IPT -A FORWARD -i $WIFI_IF -s $WIFI_NET -m state  \
	--state NEW,ESTABLISHED -m policy --dir out --pol ipsec \
	-j ACCEPT
$IPT -A FORWARD -i ! $WIFI_IF -o $WIFI_IF -d $WIFI_NET -m state \
	--state ESTABLISHED -m policy --dir out --pol ipsec -j ACCEPT
$IPT -t nat -A POSTROUTING -o $EXT_IF -s $WIFI_NET -j MASQUERADE

These rules require a relatively recent 2.6 kernel for the -m policy match to exist.

The first stanza will allow DHCP, IKE, ESP, and AH on the wifi interface. The second stanza will do stateful forwarding and masquerading for traffic travelling over any authenticated ipsec tunnels between the wireless hosts and the gateway machine. Since these setkey rules require the IPs to send all traffic via AH/ESP, clients that do not correctly negotiate IPsec connections will be denied access to our network. Suspicious packets will be logged before they are dropped. Randoms are kept out and legitimate, authenticated users enjoy strong transport-level encryption and authentication.

If you're willing to deal with the extra administrative overhead and general annoyance, it's also possible to tell Netfilter to filter against client MAC addresses. Your reward will be a negligible security gain that may discourage neophyte wardrivers. Layers of security are a good thing, however.

Client security

If you're not confident of the security of the services on your client, it may be a good idea to run a standard deny-by-default stateful firewall on it, as client machines will not be protected from being probed by other clients without a firewall of their own.

Interoperability with other platforms

I haven't yet set up a WinXP client to communicate with the gateway, although it should be possible. I'll document the process once I get it working.

Links

Documentation on Linux 2.6's IPsec layer is a bit sparse, but here are the sites I found helpful while setting up my own network.

The Linux Advanced Routing and Traffic Control HOWTO
The official IPsec Howto for Linux

Nicholas J. Kain  | n i c h o l a s | a t | k a i n | d o t | u s |