| << Previous Entry | Main | Next Entry >> |
|---|---|---|
| « It's (was) the holiday season | Replacing ugly Helvetica fonts in Xorg » |
Introduction
This is a quick mini-howto on how to get IPSec working between an OpenWRT (or any linux gateway) box and a Cisco IOS router, where both are also doing NAT for their networks. I'll also describe how to get the Linux gateway talking IPSec to a standalone Linux host elsewhere on the net. Last but not least, you'll also see how to get an IPV6 over IPv4 tunnel working across this.
I was recently rebuilding my home network topology, and part of that rebuild involved some IPSec tunnels across the Internet. I though I'd share my documentation on this to assist anyone else attempting a similar setup. The setup is built around Linux and Cisco IOS NAT gateways, as well as one standalone host, and the challenge faced here is to have IPSec running between the Linux NAT box and the other two devices.
The basic network topology is shown below. It consists of two NATed networks (Amsterdam and Sydney) and one standalone host (San Jose), all with static public IP addresses. These networks have significant communication between them, and with a desire for privacy and bypassing of ISP filters (eg port 25), tunnels have been built between the devices to give transparency across the network. The use of NAT adds to some of the challenges in building this.
The devices here consist of one standalone Linux host, one OpenWRT-Linux based router and one Cisco 827 ADSL router. The routers are NATting for the networks behind them, and some port redirection is enabling outside access to services on those networks. All networks have global IPv6 connectivity via tunnels (not shown here), and there are IPv6 tunnels directly connecting them. The internal networks behind the NAT gateways will be reachable from each other via IPSec tunnels.
My IPSec daemon of choice is OpenSwan, and a package is available for OpenWRT. There's a reasonable amount of documentation on it, but strangely I found only a few references to getting it working with a Cisco IOS box, and even fewer in combination with NAT.
The Cisco is an 827 ADSL router, running a 12.3 IOS with IPSec features. Conveniently, it also has support for IPv6, however IPSec on IPv6 is not supported, hence the use of tunneling IPv6 over the IPv4 IPSec.
IPSec and tunnel topologyFor the Amsterdam to Sydney connection, I decided to build various tunnels linking the possible communication paths over IPv4. One of the niggles with IPSec is that you've got to define all source and destination combinations as separate tunnels. The IPv6 addresses are tunnelled over an IPv4 IPSec tunnel, using standard 6-in-4. I had to use this for IPv6 anyway, given that the devices don't support IPv6 IPSec.
Between Amsterdam and San Jose, IPv4 is tunnelled with IPSec, but IPv6 would is routed over an IPv6 in IPv4 tunnel, for the same reasons - limited device support.
Configuration
The configuration of OpenSwan is handled within two files. The file /etc/ipsec.conf is the main config file and describes the settings for each IPSec connection. Configuration of crypto keys are in /etc/ipsec.secrets, and if simple preshared keying is used, this is all that needs to be touched. In the following examples, the key will be "SecretKey" but of course you should use something much longer and more obscure.
Amsterdam to SydneyThe following is the OpenSwan configuration for the Amsterdam to Sydney connection. It contains four tunnel definitions, defining all possible traffic flows:
conn sydney1
left=31.31.31.31
leftsubnet=31.31.31.31/32
leftnexthop=%defaultroute
right=61.61.61.61
rightsubnet=61.61.61.61/32
rightnexthop=%defaultroute
authby=secret
esp=3des-md5-96
keyexchange=ike
pfs=yes
auth=esp
auto=start
conn sydney2
left=31.31.31.31
leftsubnet=31.31.31.31/32
leftnexthop=%defaultroute
right=61.61.61.61
rightsubnet=192.168.0.0/24
rightnexthop=%defaultroute
authby=secret
esp=3des-md5-96
keyexchange=ike
pfs=yes
auth=esp
auto=start
conn sydney3
left=31.31.31.31
leftsubnet=192.168.0.0/24
leftnexthop=%defaultroute
right=61.61.61.61
rightsubnet=61.61.61.61/32
rightnexthop=%defaultroute
authby=secret
esp=3des-md5-96
keyexchange=ike
pfs=yes
auth=esp
auto=start
conn sydney4
left=31.31.31.31
leftsubnet=192.168.0.0/24
leftnexthop=%defaultroute
right=61.61.61.61
rightsubnet=10.0.0.0/24
rightnexthop=%defaultroute
authby=secret
esp=3des-md5-96
keyexchange=ike
pfs=yes
auth=esp
auto=start
The sections above are all the same except for the leftsubnet/rightsubnet definitions.In the /etc/ipsec.secrets file is:
31.31.31.31 61.61.61.61: PSK "SecretKey"
And here is the IOS configuration for Sydney:
crypto isakmp policy 10 encr 3des hash md5 authentication pre-share group 2 lifetime 28800 crypto isakmp key SecretKey address 31.31.31.31 ! ! crypto ipsec transform-set SydAms esp-3des esp-md5-hmac ! crypto map Amsterdam 10 ipsec-isakmp set peer 31.31.31.31 set transform-set SydAms set pfs group2 match address 192 ! ! This is the outgoing interface with the public IP address ! interface Dialer1 crypto map Amsterdam ! access-list 192 permit ip host 218.214.47.18 host 80.61.87.81 access-list 192 permit ip 192.168.1.0 0.0.0.255 10.0.0.0 0.0.0.255 access-list 192 permit ip 192.168.1.0 0.0.0.255 host 80.61.87.81 access-list 192 permit ip host 218.214.47.18 10.0.0.0 0.0.0.255
We will now configure the IPv6 tunnel to complete the tunnel config for this connection.
First the Amsterdam configuration:
ip tunnel add Sydney6 mode sit ttl 64 remote 61.61.61.61 \ && ip link set dev Sydney6 mtu 1420 up \ && ip -6 addr add 2001:31::1/128 dev Sydney6 \ && ip -6 route add 2001:61::/48 dev Sydney6
! interface Tunnel0 description IPV6 tunnel to Amsterdam no ip address ipv6 unnumbered Ethernet0 ipv6 enable tunnel source Dialer1 tunnel destination 31.31.31.31 tunnel mode ipv6ip ! ipv6 route 2001:31::/48 Tunnel0 !
Does the connection work yet?
No it doesn't. The problem is related to NAT and firewalling configuration on both ends.
On the Cisco side, the router will attempt to NAT the outgoing packets from the internal hosts before encrypting them with IPSec, and thus mangle the source address of the packet. Ingress traceroutes to an internal address will terminate on the public address, not the internal address. To solve this, we need to exclude IPSec-handled packets from the NAT processing. Somewhere in your IOS configuration will be a line similar to this:
ip nat inside source list 101 interface Dialer1 overload
access-list 101 deny ip any 192.168.0.0 0.0.0.255 access-list 101 deny ip any host 31.31.31.31 access-list 101 permit ip 10.0.0.0 0.0.0.255 any
On the OpenWrt box, NAT doesn't mangle with the IPSec packets, due to the rule processing order in iptables. NAT only affects packets leaving the WAN interface, but IPSec processing occurs before this, and by the time they're encrypted, the source address of the IPSec packets won't match the NAT rule any more.
However, the FORWARD table of the OpenWrt box will be default drop all packets that it can't establish as being related to an existing connection (ie anything not NAT or port forwarded) and so will drop any not destined for the local machine, ie IPSec traffic for any inside host.
Thus, to fix this, we put in a forwarding rule that allows all IPSec traffic through the box. In addition, we'll add a rule that ensures port 500 UDP traffic (IPSec key management aka ISAKMP) is handled locally:
# This is a catch all - it's essential to also put it more secure rules. iptables -A forwarding_rule -i ipsec0 -j ACCEPT iptables -A forwarding_rule -o ipsec0 -j ACCEPT # These rules send ISAKMP traffic to the local OpenSwan daemon. iptables -t nat -A prerouting_rule -i $WAN -p udp --dport 500 -j ACCEPT iptables -A input_rule -i $WAN -p udp --dport 500 -j ACCEPT
At this point, there should be full connectivity between the internal networks of both ends on both IPv4 and IPv6. Traceroute from an internal host at one end to any IP address of the other end should reveal only one WAN hop.
That completes the configuration for the Amsterdam to Sydney link.
Amsterdam to San JoseBetween Amsterdam and San Jose, we'll also configure OpenSwan at both ends. There will be two IPSec tunnels configured here - one will carry traffic between the public addresses, and the other will carry traffic between the Amsterdam internal network and San Jose. So one tunnel will carry traffic between 1.1.1.1 and 31.31.31.31, whilst the other will carry it from 1.1.1.1 to 192.168.0.0/24. The rules for this configuration are quite simple:
Amsterdam config:
conn sj
left=31.31.31.31
leftsubnet=31.31.31.31/32
leftnexthop=%defaultroute
right=1.1.1.1
rightsubnet=1.1.1.1/32
rightnexthop=%defaultroute
authby=secret
keyexchange=ike
pfs=yes
esp=3des-md5-96
auth=esp
auto=start
conn sjpriv
left=31.31.31.31
leftsubnet=192.168.0.0/24
leftnexthop=%defaultroute
right=1.1.1.1
rightsubnet=1.1.1.1/32
rightnexthop=%defaultroute
authby=secret
keyexchange=ike
pfs=yes
esp=3des-md5-96
auth=esp
auto=start
/etc/ipsec.secrets
31.31.31.31 1.1.1.1: PSK "SecretKey"
San Jose config:
conn ams
left=1.1.1.1
leftsubnet=1.1.1.1/32
leftnexthop=%defaultroute
right=1.1.1.1
rightsubnet=1.1.1.1/32
rightnexthop=%defaultroute
authby=secret
keyexchange=ike
pfs=yes
esp=3des-md5-96
auth=esp
auto=start
conn amspriv
left=1.1.1.1
leftsubnet=1.1.1.1/32
leftnexthop=%defaultroute
right=31.31.31.31
rightsubnet=192.168.0.0/24
rightnexthop=%defaultroute
authby=secret
keyexchange=ike
pfs=yes
esp=3des-md5-96
auth=esp
auto=start
/etc/ipsec.secrets
1.1.1.1 31.31.31.31: PSK "SecretKey"
When be bring these connections up, we see that all traffic is successful, and this tunnel works. The forwarding rule for the ipsec0 interface above is important and allows reachability to the inside hosts. Note that you don't need to put an equivalent forwarding rule on the Linux host, as nothing is forwarded through the box. But you may need to configure general input and output rules to allow IPSec packets.
Lastly, we configure an IPv6 tunnel across this IPSec link. It's quite straight forward and this is the configuration:
Amsterdam end:
ip tunnel add US mode sit ttl 64 remote 1.1.1.1 \ && ip link set dev US mtu 1420 up \ && ip -6 addr add 2001:31::1/128 dev US \ && ip -6 route add 2001:1::1/128 dev US
San Jose end:
ip tunnel add NL mode sit ttl 64 remote 31.31.31.31 \ && ip link set dev NL mtu 1420 up \ && ip -6 addr add 2001:1::1/128 dev NL \ && ip -6 route add 2001:31::1/64 dev NL
A quick ping will show the IPv6 tunnel up and there should be reachability to all hosts on the inside of the Amsterdam network. It's also a good idea to configure firewalling rules on the IPv6 side - anyone breaching the public host has full IPv4 and IPv6 access to the Amsterdam network, so be smart and build that firewall.
Last but not least...the IPSec connection between San Jose and Sydney....is left as an excercise to the reader.
ConclusionIPSec is often seen as a mysterious protocol in the IP world, difficult to setup and hard to maintain. But a look into a basic configuration with it reveals it to be not that hard at all. The configurations above should be a good solution for many common network topologies, and with a clear understanding as to what it all does, adapting it to other networks should be relatively painless.
Posted by Ben at July 6, 2006 10:02 PM
| NL time: | 08:27 |
| Book: | Assassini (Thomas Gifford) | Amazon wish list |