Rule-based Routing & Traffic Forwarding with IPsec Site to Site VPN and Linux

This article is adapted from https://www.v2ex.com/t/180070 and http://hjc.im/shi-yong-strongswanda-jian-ipsecikev2-vpn/. The major difference is ShadowVPN is replaced by StrongSwan IPsec VPN in this article.

Readiness Check

  • Upgrade your staging/production environment to the latest version. Make sure all security patches are installed.
  • Make sure you have packages libpam0g-dev libssl-dev make gcc installed.

Building StrongSwan

Download the latest version here: http://download.strongswan.org/strongswan.tar.gz

Unarchive it, and configure using the following params:

./configure  --enable-eap-identity --enable-eap-md5 
--enable-eap-mschapv2 --enable-eap-tls --enable-eap-ttls --enable-eap-peap  
--enable-eap-tnc --enable-eap-dynamic --enable-eap-radius --enable-xauth-eap  
--enable-xauth-pam  --enable-dhcp  --enable-openssl  --enable-addrblock --enable-unity  
--enable-certexpire --enable-radattr --enable-tools --enable-openssl --disable-gmp --enable-kernel-libipsec

We have to specify routing table’s priority on client server(not IPsec Access Server) since we wants to specify routing table manually: –with-routing-table-prio=32800.  Also, TAP/TUN device is enabled instead of StrongSwan’s own kernel module. It will simplify the configuration later.

Then make and install it.

Configure IPsec Access Server

Just a reminder, if you have any issues about IP range, please refer to the demo topology graph. The image is unavailable right now for some reason. I’ll fix it ASAP.

Go to /usr/local/etc. Edit ipsec.secrets:

: PSK "<IPsec PRE SHARED KEY, PLEASE REMEMBER TO REPLACE IT WITH YOU OWN KEY>"
s2s : XAUTH "<ANY PASSWORD YOU WANT, PLEASE REMEMBER TO REPLACE IT WITH YOU OWN PASSWORD>"

Go to /usr/local/etc. Edit ipsec.conf:

config setup
    uniqueids=never 

conn s2sbj1_xauth_psk
    keyexchange=ikev1
    left=%defaultroute
    leftauth=psk
    leftsubnet=0.0.0.0/0
    right=%any
    rightauth=psk
    rightauth2=xauth
    rightsourceip=100.11.2.0/24
    auto=add

Go to /usr/local/etc. Edit strongswan.conf:

 charon {
         load_modular = yes
         duplicheck.enable = no
         compress = yes
         plugins {
                 include strongswan.d/charon/*.conf
         }
         # In China, please consider about replacing 8.8.8.8/8.8.4.4 to 114.114.114.114. They do offer correct DNS query results outside mainland China, as long as you have configured the Chinese routing exception for it(route to non-mainland China outbound server)
         dns1 = 8.8.8.8
         dns2 = 8.8.4.4
         nbns1 = 8.8.8.8
         nbns2 = 8.8.4.4
 }
 include strongswan.d/*.conf

Turn on IPv4 forwarding in sysctl.conf.

Edit iptables. The following configuration is for Ubuntu 14.04 LTS. For other Linux distro, check out its documentation.

iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 100.11.0.0/24  -j ACCEPT
iptables -A FORWARD -s 100.11.1.0/24  -j ACCEPT
iptables -A FORWARD -s 100.11.2.0/24  -j ACCEPT
iptables -A INPUT -i eth0 -p esp -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport 500 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 500 -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport 4500 -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport 1701 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 1723 -j ACCEPT
iptables -A FORWARD -j REJECT
iptables -t nat -A POSTROUTING -s 100.11.0.0/24 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 100.11.1.0/24 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 100.11.2.0/24 -o eth0 -j MASQUERADE

Save it

iptables-save > /etc/iptables.rules
cat > /etc/network/if-up.d/iptables<<EOF
#!/bin/sh
iptables-restore < /etc/iptables.rules
EOF
chmod +x /etc/network/if-up.d/iptables

Configure IPsec client

Suppose you have the correct StrongSwan with TAP/TUN and routing table priority installed.

Go to /usr/local/etc, edit ipsec.secrets, just put what you have in the previous step.

Go to /usr/local/etc, edit ipsec.conf:

config setup
    uniqueids=never 
    strictcrlpolicy=no
    

conn s2sbj1
    keyexchange=ikev1
    ikelifetime=1440m
    keylife=120m
    # Enable this will cause authentication failure
    aggressive=no
    ike=aes-sha2-modp2048
    esp=ase-sha2
    xauth=client
    left=<eth0's IP address>
    # Ask your server
    leftsourceip=%config
    leftauth=psk
    leftauth2=xauth
    rightauth=psk
    rightauth2=xauth
    right=<Your IPsec VPN Server's public IP address>
    # For Microsoft Azure and other service providers who use SNAT, specify that to prevent IKE_SA failure
    rightid=%any
    xauth_identity=s2s
    auto=add
    rightsubnet=0.0.0.0/0

Establish Connection

On your IPsec VPN server, type sudo ipsec start .

On your client server, type:

sudo ipsec start
sudo ipsec up s2sbj1

It should get connected shortly. Go to ifconfig and you should find a new network adapter called ipsec0.

Configure rule-based routing

Create a new routing table.

user@ibntwkstgepbj1:~$  sudo vim /etc/iproute2/rt_tables
200 bj1s2s
:q
user@ibntwkstgepbj1:~$

Get the routing configuration in table 220 (IPsec table).

user@ibntwkstgepdm1:~$  sudo ip route list table 220
default dev ipsec0  proto static  src 100.11.2.1
42.159.66.233 via 10.0.0.1 dev eth0  proto static  src 10.0.0.4

Specify the default route for this table (copy it from 220):

user@ibntwkstgepdm1:~$  sudo ip route add default dev ipsec0  proto static  src 100.11.2.1 table bj1s2s

(You don’t have to copy the second line I guess, but I added that)

Add IP rules.

user@ibntwkstgepdm1:~$  ip rule add from <IP Range> table bj1s2s

Refresh routing table.

user@ibntwkstgepdm1~$  ip route flush cache

Compose a shell script if you want to compelte that automatically for every reconnection.

Conclusion

We implemented a simple line optimization using rule-based routing in this example. For application-based service, you are all set and ready to go. For VPN access services, configuration for iptables is needed in order to tag data packets and route them correctly. Check out this article for more details.

I didn’t offer a auto routing script in this example. I strongly recommend you to write it since it saves your time by configuring routing table automatically.

For multiple IPsec connections and routings, just specify the source IP, which is 100.11.2.1 and 100.21.2.1 in routing tables. They use the same adapter.