Skip to content

Instantly share code, notes, and snippets.

@dferg
Last active December 18, 2023 21:49
  • Star 20 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save dferg/50c378701a192bc8ce6a to your computer and use it in GitHub Desktop.
HOWTO: Install L2TP/IPsec Server on TomatoUSB

Introduction

This howto describes setting up a LT2P over IPsec VPN server on your router with TomatoUSB firmware. This should allow you to connect using the built-in client to your Mac, iPhone or Android device. (Not sure about Windows.)

At the end of this tutorial, you should have a L2TP/IPsec VPN server that starts automatically on boot. Mac/iPhone/Android devices can connect with their native client and will be assigned an IP address within your LAN subnet. They should be able to talk to other devices on your LAN and should be able to contact hosts on the Internet NAT'd behind your WAN IP address.

Requirements

  • Router running Shibby's fork of TomatoUSB
  • entware installed to a USB stick mounted at /opt (howto)
  • Shibby's kernel module extras installed at /opt/extras (howto)
  • Dynamic DNS properly configured

This Howto Was Tested With

  • Shibby's fork of TomatoUSB version 1.28 build 121
  • ASUS RT-N66U

Setting Up L2TP/IPsec VPN Server

Load necessary kernel modules

Place the following in /opt/etc/init.d/S01extras:

#!/bin/sh

# Load the ipsec modules
modprobe /opt/extras/ipsec/af_key                # racoon
modprobe /opt/extras/ipsec/esp4                  # racoon
modprobe /opt/extras/ipsec/xfrm4_mode_transport  # racoon <-> xl2tpd
modprobe /opt/extras/ipsec/xfrm_user             # ip xfrm policy

And make the script executable:

chmod 0644 /opt/etc/init.d/S01extras

This script will be executed upon boot by entware.

Add firewall and policy rules

We need to open up ports for IPsec (udp 4500, 500) and for L2TP (udp 1701). We also need to manually set the policy for clients behind NAT. Apparently racoon generates the wrong policy (reference).

To automatically setup the firewall and policy rules for L2TP/IPsec, place the following in /opt/bin/post_firewall:

#!/bin/sh

# Add the IPsec/L2TP rules if they have not already been added
iptables-save | grep -- "-A INPUT -p udp -m udp --dport 500 -j ACCEPT" > /dev/null
if [ $? = 1 ]; then
    # Allow IPSEC connections
    iptables -A INPUT -p udp -m udp --dport 500 -j ACCEPT
    iptables -A INPUT -p udp -m udp --dport 4500 -j ACCEPT

    # Allow L2TP connections
    iptables -A INPUT -p udp -m udp --dport 1701 -j ACCEPT

fi

# If the logdrop rule exists, we need to move it to the end
#   - This helps if our manual rules were added (above).
#   - This also fixes what appears to be a Tomato bug. With some services,
#     like the PPTP server, their rules will be placed after the logdrop
#     rule. The result is incorrectly dropping packets for valid services.
iptables-save | grep -- "-A INPUT -j logdrop" > /dev/null
if [ $? = 0 ]; then
    # Get the number of the logdrop rule in the INPUT chain
    LINENUM=`iptables -L INPUT|grep -nr logdrop|cut -f 1 -d :`
    RULENUM=`expr $LINENUM - 2`

    # Delete the logdrop rule from the INPUT chain
    iptables -D INPUT $RULENUM

    # Readd the logdrop rule at the end of the INPUT chain
    iptables -A INPUT -j logdrop
fi

# Set manual policy (this is needed for clients behind nat, because racoon generates the wrong policy)
#
# Source: http://tomatousb.org/forum/t-625093/ipsec-l2tp-racoon-xl2tpd-tomato-shibby-asus-rt-n16
myServer=`nvram get wan_ipaddr`
ip xfrm policy add src $myServer dst 0.0.0.0/0 proto udp sport 1701 dir out tmpl proto esp mode transport level required
ip xfrm policy add src 0.0.0.0/0 dst $myServer proto udp dport 1701 dir in tmpl proto esp mode transport level required

And then make the script executable:

chmod 0644 /opt/bin/post_firewall

In the web GUI, go to Administration->Scripts. In the "Firewall" tab, paste the following:

/opt/bin/post_firewall

NOTE: The correct rule for L2TP appears to be:

iptables -I INPUT -p udp -m policy --dir in --pol ipsec -m udp --dport 1701 -j ACCEPT

However, there is something missing in the kernel used by Shibby Tomato. When I run the above command, I get the error, "iptables: No chain/target/match by that name". I believe we are missing the xt_policy kernel module. Anyway, as a work around, the post_firewall script just allows all UDP packets on port 1701. This is less slightly secure, but should not be an issue.

Have dnsmasq service VPN clients

By default, dnsmasq responds to DNS queries only on your local LAN interface. Now that we have VPN clients connecting, we need to tell dnsmasq to respond to DNS queries on the pppX interfaces too.

In the web GUI, click on the Advanced->DHCP/DNS section. Add the following to the "Dnsmasq Custom configuration" text input box":

interface=ppp0,ppp1,ppp2,ppp3,ppp4,ppp5,ppp6,ppp7,ppp8,ppp9
no-dhcp-interface=ppp0,ppp1,ppp2,ppp3,ppp4,ppp5,ppp6,ppp7,ppp8,ppp9

Install ipsec-tools

Install the ipsec-tools package. This includes the racoon daemon responsible for IPsec.

opkg install ipsec-tools

Setup the pre-shared key

Replace the contents of /opt/etc/racoon/psk.txt with the following:

# * is a wildcard, means any IP address
* this_is_my_pre_shared_key

Change "this_is_my_pre_shared_key" to something unique. This is the pre-shared key (also known as a shared secret) that you will enter into your client configs.

Make the file readable only by root:

chmod 0600 /opt/etc/racoon/psk.txt

Configure racoon

Replace the contents of /opt/etc/racoon.conf with:

path pre_shared_key "/opt/etc/racoon/psk.txt";

remote anonymous
{
        exchange_mode main;
        nat_traversal on;
        generate_policy on;
        proposal_check obey;    # obey, strict, or claim

        proposal {
                encryption_algorithm 3des;
                hash_algorithm sha1;
                authentication_method pre_shared_key;
                dh_group 2;
        }
}

sainfo anonymous
{
        encryption_algorithm aes;
        authentication_algorithm hmac_sha1;
        compression_algorithm deflate;
}

Install pppd

I had trouble overriding the configuration of Tomato's built-in pppd. So, I installed the entware version. Do this with:

opkg install ppp

However, the entware version apparently does not have the necessary pppol2tp.so plugin. The Shibby built-in pppd does have this plugin, so link to it:

cd /opt/lib/pppd/2.4.5
ln -s /usr/lib/pppd/pppol2tp.so

Setup credentials for VPN users

Create a file called /opt/etc/ppp/chap-secrets with the following contents:

# USERNAME PROVIDER PASSWORD           IPADDRESS
user1      *        password_for_user1 *
user2      *        password_for_user2 *

Set the user names and passwords for all the users that you want to be able to login remotely to the VPN. Add as many users to this file as needed.

Restrict the permissions of this file ot only root:

chmod 0600 /opt/etc/ppp/chap-secrets

Install xl2tpd

Run the following command to install the xl2tpd package:

opkg install xl2tpd

Configure xl2tpd

Replace the contents of /opt/etc/xl2tpd/xl2tpd.conf with:

[global]
port = 1701
access control = no
ipsec saref = yes
;debug avp = yes
;debug network = yes
;debug packet = yes
;debug state = yes
;debug tunnel = yes

[lns default]
exclusive = yes
ip range = 192.168.1.91-192.168.1.99
local ip = 192.168.1.1
;hidden bit = no
length bit = yes
name = VPNServer
ppp debug = yes
require authentication = yes
unix authentication = no
require chap = yes
refuse pap = yes
pppoptfile = /opt/etc/ppp/options.xl2tpd

Set "local ip" to the IP address of your Tomato router. Set "ip range" to an unused range of IP's on your subnet. Make sure this range is outside the range of your DHCP server!

Setup the ppp options for xl2tpd

Create /opt/etc/ppp/options.xl2tpd with the following:

lock
auth
name "l2tp-server"
# DUMP crashes the daemon - do not uncomment
#dump
# CCP seems to confuse Android clients, better turn it off
noccp
#novj
#novjccomp
nopcomp
noaccomp
require-mschap
require-mschap-v2
ms-dns 192.168.1.1
lcp-echo-interval 120
lcp-echo-failure 10
idle 1800
connect-delay 5000
nodefaultroute
noipdefault

proxyarp
mtu 1400
mru 1400

ip-up-script /opt/etc/ppp/ip-up.sh
ip-down-script /opt/etc/ppp/ip-down.sh

Replace "ms-dns" with the address of your desired DNS server. Usually, this should be the IP address of your router's LAN address.

Setting up clients

Mac OS X

This was tested on Mac OS X 10.10.0 DP5.

  1. Open System Preferences and click on Network.
  2. Click on the + symbol to add a new interface.
  3. Set the "Interface" to VPN. Set the "VPN Type" to "L2TP over IPSec." Set the "Service Name" to whatever you would like. Click the Create button.
  4. Set the "Server Address" to your DDNS name. (e.g. myhouse.dyndns.org)
  5. Set the "Account Name" to your user name--this corresponds to the user names in /opt/etc/ppp/chap-secrets
  6. Click on "Authenication Settings"
  7. Under "User Authentication" choose "Password" and fill in the password of your user--again, this corresponds to /opt/etc/ppp/chap-secrets.
  8. Under "Machine Authentication" choose "Shared Secret" and fill in the pre-shared key from /opt/etc/racoon/psk.txt.
  9. Leave "Group Name" blank.
  10. Click OK.
  11. Click "Advanced" and tick "Send all traffic over VPN connection". Click OK. This will make sure your Internet browsing traffic goes over the VPN instead of just packets destined for your home's LAN.
  12. Click Apply.

iOS

This was tested on iOS 7 and 8 beta 5.

  1. Launch the Settings app.
  2. Tap through General->VPN
  3. Tap "Add VPN Configuration..."
  4. Choose L2TP and set the "Description" to whatever you want to name the connection.
  5. Set "Server" to your DDNS name. (e.g. myhouse.dyndns.org)
  6. Set "Account" to your user name--this corresponds to the user names in /opt/etc/ppp/chap-secrets
  7. "RSA SecurID" should be off.
  8. Set "Password" to the password of your user--again, this corresponds to /opt/etc/ppp/chap-secrets.
  9. Set "Secret" to the pre-shared key from /opt/etc/racoon/psk.txt.
  10. "Send All Traffic" should be on.
  11. "Proxy" should be off.
  12. Click "Save"

Android

This was tested on Android 4.4.4 (CyanogenMod CM11 M9). The instructions for your device or version of Android may vary.

  1. Launch the Settings app.
  2. Under "WIRELESS & NETWORKS" tap "More..."
  3. Tap "VPN" and then tap the + button.
  4. Choose "L2TP/IPSec PSK" as the type.
  5. Set the Name to whatever you want to name the connection.
  6. Set "Server address" to your DDNS name. (e.g. myhouse.dyndns.org)
  7. Leave "L2TP secret" and "IPSec identifier" empty.
  8. Set "IPSec pre-shared key" to the pre-shared key from /opt/etc/racoon/psk.txt.
  9. Tap "Save"
  10. Tap on the newly created VPN profile.
  11. Fill in "Username" with your user name--this corresponds to the user names in /opt/etc/ppp/chap-secrets
  12. Fill in "Password" with the password of your user--again, this corresponds to /opt/etc/ppp/chap-secrets.
  13. Tick "Save account information" (optional)
  14. Click "Connect"

Troubleshooting

racoon complaining something about pskey

Make sure you use a patched racoon. Standard racoon does not recognize "*" in psk.txt

racoon and xl2tpd started up, racoon connects but xl2tpd is not receiving anything

Make sure you have the relevant kernel modules loaded

xl2tpd says something about "Peer requested tunnel 22 twice, ignoring second one."

Make sure you have the right policies (ip xfrm…)

xl2tpd says something about "LCP: timeout sending Config-Requests"

Make sure you have "force userspace = yes" in xl2tpd.conf

Ok, I connected, but DNS is not responding

Make sure you have interface=ppp4,ppp5,ppp6,ppp7,ppp8,ppp9 in /etc/dnsmasq.conf

"Couldn't load plugin pppol2tp.so" from pppd

Make sure the soft link in /opt/lib/pppd/2.4.5 is valid and resolves to /usr/lib/pppd/pppol2tp.so.

Enable more debugging

Events are logged to /var/log/messages. You can "tail -f /var/log/messages" to watch what happens when a client attempts to connect.

You can enable more verbose debugging in /opt/etc/xl2tpd/xl2tpd.conf. Uncomment one or more of the "debug" lines.

TODO

  • Figure out how to use the built-in pppd installation. It would be better if we did not have to install pppd from entware--I don't think it is buying us anything.
  • Debug possible issues with two VPN clients connecting from the same source address.

Credits

dborca wrote up an excellent tutorial on setting up this server here: http://tomatousb.org/forum/t-625093/ipsec-l2tp-racoon-xl2tpd-tomato-shibby-asus-rt-n16. However, since then the tools within entware have matured resulting in a much less complicated install that I outline here. Thanks for the write up dborca!

@tweak19
Copy link

tweak19 commented Aug 17, 2015

Hello,
thats a really nice tutorial, but i think there is something missing in it. I make the same configuration on my WNR3500Lv2 running Tomato Shibby 1.30 and there i get some troubles with the policity.

I think the reason could be that i have an dynamic ip at the wan port. So if i set the policitiys every reconnect manually everything works like charm. But that can't be the solution, because at the and of a year would have a lot of policity rules insert.

Especually setkey can fix this problem?

@TheJeremyP
Copy link

Thanks for the writeup @dferg.
I followed the tutorial and it seems I have only one hiccup. I have no idea how to patch racoon myself to read the * in /opt/etc/racoon/psk.txt The version of ipsec-tools available from entware is now 0.8.2 and not 0.8.1 that's talked about @ http://tomatousb.org/forum/t-625093/ipsec-l2tp-racoon-xl2tpd-tomato-shibby-asus-rt-n16. Would the same patch still be able to be applied to a newer version without breaking stuff? Can you explain how to do it for a layman?

Also the correct rule for L2TP doesn't give an error if you add modprobe xt_policy to /opt/etc/init.d/S01extras.

@gatitofroilan
Copy link

gatitofroilan commented Nov 26, 2016

Hi, i have configured as described but when i try to conect fron ios it give me time out, and dont see nothing it messages, i think that firewall isnt working good, any ideas?

EDIT: Was a problem with NAT & Port Foward beetwen PPPoE Wan interface and Router LAN address, a little bit of iptables and working like a charm. 👍

thanks

@dborca
Copy link

dborca commented Jan 6, 2017

Or just
git clone git://repo.or.cz/tomato/lycopene.git
export PATH=/opt/brcm/hndtools-mipsel-linux/bin:/opt/brcm/hndtools-mipsel-uclibc/bin:$PATH
cd lycopene/release/src-rt && make V1="RT-" V2="-131.1" r2y
:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment