Is it possible for L2TP VPN to do auto route configuration for client during connected?

OK, this question is asked over and over again over the Internet and most of the time there is a (semi-) incorrect answer that you cannot do what was described in the original post. Let me clarify it once and for all :)

The short answer is L2TP (and PPTP for that matter) do not have facilities to do route pushes inside the protocol, but it can be achieved outside the protocol.

Since L2TP is a Microsoft invention, the best source of information is their technical documentation (and they are quite good at it, by the way). The technical description of what I am going to explain down below can be found at VPN Addressing and Routing. The keywords for setting everything up properly (if you are going to do your own research) are: DHCPINFORM and "classless static routes".

First of all, how it works:

  1. a client connects to the VPN server
  2. after successful authentication a secure tunnel is established
  3. the client uses a DHCPINFORM message after the connection to request the DHCP Classless Static Routes option. This DHCP option contains a set of routes that are automatically added to the routing table of the requesting client (I slavishly copy-and-pasted this line directly from Microsoft documentation :) )
  4. the VPN server replies to that message with appropriate set of routes

Well, there is a caveat:

  • there is RFC-3442 describing "DHCP Classless Static Routes" and there it states that the code for this option is 121. Microsoft decided to re-invent the wheel (as always) and uses code 249 for this option. Hence, to support a wider range of clients we need to respond back with both codes

I am going to describe a typical configuration using Linux box as the VPN server (you can configure MS servers using the link to the Microsoft documentation).

To configure routes on the clients we will need the following ingredients:

  • L2TP/IPSEC (or PPTP) = for example, accel-ppp is a nice open source L2TP/PPTP server
  • DHCP server = there are many, but I am going to describe dnsmasq's configuration

The following is a dump of a working accel-ppp configuration. I am providing it in its entirety, otherwise it would be difficult to explain what goes where. If you already have your VPN working you may skip this configuration file and concentrate on the DHCP configuration described below.

[root@vpn ~]# cat /opt/accel-ppp/config/accel-ppp.conf
[modules]
log_syslog
pptp
l2tp
auth_mschap_v2
ippool
sigchld
chap-secrets
logwtmp

[core]
log-error=/var/log/accel-ppp/core.log
thread-count=4

[ppp]
verbose=1
min-mtu=1280
mtu=1400
mru=1400
check-ip=1
single-session=replace
mppe=require
ipv4=require
ipv6=deny
ipv6-intf-id=0:0:0:1
ipv6-peer-intf-id=0:0:0:2
ipv6-accept-peer-intf-id=1

[lcp]
lcp-echo-interval=30
lcp-echo-failure=3

[auth]
#any-login=0
#noauth=0

[pptp]
echo-interval=30
echo-failure=3
verbose=1

[l2tp]
host-name=access-vpn
verbose=1

[dns]
dns1=192.168.70.251
dns2=192.168.70.252

[client-ip-range]
disable

[ip-pool]
gw-ip-address=192.168.99.254
192.168.99.1-253

[log]
log-file=/var/log/accel-ppp/accel-ppp.log
log-emerg=/var/log/accel-ppp/emerg.log
log-fail-file=/var/log/accel-ppp/auth-fail.log
log-debug=/var/log/accel-ppp/debug.log
copy=1
level=3

[chap-secrets]
gw-ip-address=192.168.99.254
chap-secrets=/etc/ppp/chap-secrets

[cli]
telnet=127.0.0.1:2000
tcp=127.0.0.1:2001

[root@vpn ~]# 
===

At this point our clients can connect via L2TP (or PPTP) and communicate with the VPN server. So, the only missing part is a DHCP server that is listening on the created tunnels and that responds back with the necessary information. Below is an excerpt from the dnsmasq configuration file (I am providing DHCP related options only):

[root@vpn ~]# grep -E '^dhcp' /etc/dnsmasq.conf 
dhcp-range=192.168.99.254,static
dhcp-option=option:router
dhcp-option=121,192.168.70.0/24,192.168.99.254,192.168.75.0/24,192.168.99.254,10.0.0.0/24,192.168.99.254
dhcp-option=249,192.168.70.0/24,192.168.99.254,192.168.75.0/24,192.168.99.254,10.0.0.0/24,192.168.99.254
dhcp-option=vendor:MSFT,2,1i
[root@vpn ~]#

In the above excerpt we are pushing routes 192.168.70.0/24, 192.168.75.0/24, and 10.0.0.0/24 via 192.168.99.254 (the VPN server).

Finally, if you sniff the network traffic (e.g. on the VPN server) you will see something like the following for the response on the DHCPINFORM message:

19:54:46.716113 IP (tos 0x0, ttl 64, id 10142, offset 0, flags [none], proto UDP (17), length 333)
    192.168.99.254.67 > 192.168.99.153.68: BOOTP/DHCP, Reply, length 305, htype 8, hlen 6, xid 0xa27cfc5f, secs 1536, Flags [none]
      Client-IP 192.168.99.153
      Vendor-rfc1048 Extensions
        Magic Cookie 0x63825363
        DHCP-Message Option 53, length 1: ACK
        Server-ID Option 54, length 4: 192.168.99.254
        Domain-Name Option 15, length 18: "vpn.server.tld"
        Classless-Static-Route-Microsoft Option 249, length 24: (192.168.70.0/24:192.168.99.254),(192.168.75.0/24:192.168.99.254),(10.0.0.0/24:192.168.99.254)
        Vendor-Option Option 43, length 7: 2.4.0.0.0.1.255

P.S. I almost forgot an essential part required for the successful use of the above configuration. Well, it was described in the Microsoft docs I referred to, but who read the documentation? :) OK, clients should be configured without 'Use default gateway' on the VPN connection (on Windows it is in connection's properties -> Networking -> Internet Protocol Version 4 (TCP/IPv4) -> Properties -> Advanced -> IP Settings). On some clients there is also an option called 'Disable class based route addition' - it must be unset since it explicitly disables the functionality we are trying to implement.