Solved L2TP/IPSec Client Setup

I'm trying to vpn from my FreeBSD laptop to a Ubiquiti EdgeRouter. An IKE connection is established by security/strongswan and an IP address is assigned to the ng0 interface created by net/mpd5. But how do I make traffic pass through this tunnel? From what I gather in other threads this should be more or less automatic but I must be missing something since I'm unable to access anything on my corporate network. Here are my configs for reference.

mpd5.conf
Code:
startup:

      # Set web self 127.0.0.1 5008

      # Set user vpntest vpntest admin

      # Set web open

log +ALL +EVENTS -FRAME -ECHO

default:

      load L2TP_client


L2TP_client:

        create bundle static B1

        create link static L1 l2tp

        set link action bundle B1

        set auth authname "username"

        set auth password "password"

        set link max-redial 0

        set link mtu 1460

        set link keep-alive 20 75


        set l2tp peer X.X.X.X

        open
ipsec.conf
Code:
config setup

conn %default

        ikelifetime=60m

        keylife=20m

        rekeymargin=3m

        keyingtries=1

        keyexchange=ikev1

        authby=secret              # psk or secret

conn wesd                          # name used in ipsec(1) commands

        type=transport

        leftfirewall=yes

#       leftsourceip=%config

        rightsourceip=10.200.220.0/24

        right=X.X.X.X       # target server (same IP as the L2TP peer)

        rightsubnet=0.0.0.0/0       # network from the server

        auto=add                   # Add routing entries?

        left=%defaultroute

        leftprotoport=17/%any

        rightprotoport=17/1701
 
Do you have a firewall enabled on the client machine? You want to allow all traffic over ng0.

In addition have a look at the output of netstat -nr. The routing table should got an entry for the internal IP address of the remote endpoint. For example, when I connect to a remote L2TP/IPsec-VPN using strongSwan/MPD5, then I see:

ifconfig:
Code:
ng0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> metric 0 mtu 1500
        inet 10.0.1.161 --> 10.0.1.1 netmask 0xffffffff
        inet6 fe80::7285:c2ff:fe5d:e86d%ng0 prefixlen 64 scopeid 0x3
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
netstat -nr:
Code:
Routing tables

Internet:
Destination        Gateway            Flags     Netif Expire
default            192.168.1.1        UGS         em0
10.0.1.1           link#3             UH          ng0
10.0.1.161         link#3             UHS         lo0
localhost          link#2             UH          lo0
192.168.1.0/24     link#1             U           em0
192.168.1.10       link#1             UHS         lo0

...
 
Hmm. It appears that I'm not actually connecting to the remote endpoint even though I receive an IP address from it. I would expect the endpoint to be 10.200.220.1 not the incorrect subnet mask listed in the output below. I turned off firewall services while troubleshooting.
ifconfig:
Code:
ng0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> metric 0 mtu 1460
        inet 10.200.220.211 --> 10.255.255.0 netmask 0xffffffff
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
netstat -nr:
Code:
Routing tables

Internet:
Destination        Gateway            Flags     Netif Expire
default            192.168.0.1        UGS       wlan0
10.200.220.211     link#3             UHS         lo0
10.255.255.0       link#3             UH          ng0
127.0.0.1          link#1             UH          lo0
192.168.0.0/24     link#2             U         wlan0
192.168.0.8        link#2             UHS         lo0
mpd5:
Code:
[B1] IPCP: LayerStart
[B1] IPCP: Up event
[B1] IPCP: state change Starting --> Req-Sent
[B1] IPCP: SendConfigReq #1
[B1]   IPADDR 192.168.0.8
[B1]   COMPPROTO VJCOMP, 16 comp. channels, no comp-cid
[B1] IPCP: rec'd Configure Request #1 (Req-Sent)
[B1]   IPADDR 10.255.255.0
[B1]     10.255.255.0 is OK
[B1] IPCP: SendConfigAck #1
[B1]   IPADDR 10.255.255.0
[B1] IPCP: state change Req-Sent --> Ack-Sent
[B1] IPCP: rec'd Configure Reject #1 (Ack-Sent)
[B1]   COMPPROTO VJCOMP, 16 comp. channels, no comp-cid
[B1] IPCP: SendConfigReq #2
[B1]   IPADDR 192.168.0.8
[B1] IPCP: rec'd Configure Nak #2 (Ack-Sent)
[B1]   IPADDR 10.200.220.211
[B1]     10.200.220.211 is OK
[B1] IPCP: SendConfigReq #3
[B1]   IPADDR 10.200.220.211
[B1] IPCP: rec'd Configure Ack #3 (Ack-Sent)
[B1]   IPADDR 10.200.220.211
[B1] IPCP: state change Ack-Sent --> Opened
[B1] IPCP: LayerUp
[B1]   10.200.220.211 -> 10.255.255.0
[B1] IFACE: Up event
 
I've made it a bit further. I discovered that although IKE_SA was established, CHILD_SA was not.
ipsec statusall:
Code:
Tasks queued: QUICK_MODE
I added modeconfig=push to my ipsec.conf and was able to see the following output, which looked promising because it assigned the correct IP address to the peer, but it failed for other reasons.
ipsec wesd up:
Code:
assigning virtual IP 10.200.220.1 to peer 'X.X.X.X'
...
peer selected invalid traffic selectors: 192.168.0.8/32[udp] for 192.168.0.8/32[udp], X.X.X.X/32[udp/l2f] for 10.200.220.1/32[udp/l2f]
establishing connection 'wesd' failed
 
Hmm. It appears that I'm not actually connecting to the remote endpoint even though I receive an IP address from it. I would expect the endpoint to be 10.200.220.1 not the incorrect subnet mask listed in the output below. I turned off firewall services while troubleshooting.
ifconfig:
Code:
ng0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> metric 0 mtu 1460
        inet 10.200.220.211 --> 10.255.255.0 netmask 0xffffffff
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
netstat -nr:
Code:
Routing tables

Internet:
Destination        Gateway            Flags     Netif Expire
default            192.168.0.1        UGS       wlan0
10.200.220.211     link#3             UHS         lo0
10.255.255.0       link#3             UH          ng0
127.0.0.1          link#1             UH          lo0
192.168.0.0/24     link#2             U         wlan0
192.168.0.8        link#2             UHS         lo0
mpd5:
Code:
[B1] IPCP: LayerStart
[B1] IPCP: Up event
[B1] IPCP: state change Starting --> Req-Sent
[B1] IPCP: SendConfigReq #1
[B1]   IPADDR 192.168.0.8
[B1]   COMPPROTO VJCOMP, 16 comp. channels, no comp-cid
[B1] IPCP: rec'd Configure Request #1 (Req-Sent)
[B1]   IPADDR 10.255.255.0
[B1]     10.255.255.0 is OK
[B1] IPCP: SendConfigAck #1
[B1]   IPADDR 10.255.255.0
[B1] IPCP: state change Req-Sent --> Ack-Sent
[B1] IPCP: rec'd Configure Reject #1 (Ack-Sent)
[B1]   COMPPROTO VJCOMP, 16 comp. channels, no comp-cid
[B1] IPCP: SendConfigReq #2
[B1]   IPADDR 192.168.0.8
[B1] IPCP: rec'd Configure Nak #2 (Ack-Sent)
[B1]   IPADDR 10.200.220.211
[B1]     10.200.220.211 is OK
[B1] IPCP: SendConfigReq #3
[B1]   IPADDR 10.200.220.211
[B1] IPCP: rec'd Configure Ack #3 (Ack-Sent)
[B1]   IPADDR 10.200.220.211
[B1] IPCP: state change Ack-Sent --> Opened
[B1] IPCP: LayerUp
[B1]   10.200.220.211 -> 10.255.255.0
[B1] IFACE: Up event

Actually, the L2TP part looks good. I see also a netmask of 0xffffffff. Also the internal IP of the remote endpoint is a valid one, even if it looks a bit strange. Seems that the corporate allocated quite a generous IP address pool for its L2TP service, which might be reasonable, though.

You said, that the IPsec connection failed at the same time. This actually means, that the L2TP connection has been established by normal UDP traffic, i.e. non-IPsec = non-secure. If the corporate really allows incoming UDP 1701 connections on the public interface and furthermore allow this to establish ordinary non-encrypted L2TP-VPNs into their network, then I consider this a security flaw. A MITM only would need to make the IPsec connection attempt fail and dumb clients simply go over normal UDP 1701 which pass all traffic in clear. This must not be allowed, neither on the client side nor on the server side. Here, my firewalls take care of this.
 
Thank you for pointing out the security flaw in this design. I will make the appropriate adjustments to fix this issue. Meanwhile, I've changed the rightsourceip parameter from the remote private address to the public one. So now the CHILD_SA is established correctly. I can finally connect via l2tp through the ipsec tunnel. Now I'll adjust some routes and firewalls to make this solution more robust and secure.
 
OK, let’s go through my setup.

The L2TP/IPsec service is provided by FreeBSD 12-RELEASE-p3 on an AWS-EC2 instance running strongSwan/mpd5. Since this is a virtual machine, it got no interface with it’s public IP addresse, instead AWS operates a transparent NAT outside of the VM, and therefore the IPsec service must be able to do NAT-T. /usr/local/etc/ipsec.conf on this server side is:
Code:
conn L2TP/IPsec-Server:
   keyexchange = ikev1
   type = transport
   ike = aes256-sha1-modp1024

   leftauth = psk
   left = %defaultroute
   leftprotoport=17/1701

   rightauth = psk
   right = %any
   rightprotoport=17/%any

   auto = add

I need to specify the older cipher aes256-sha1-modp1024 only, because among other modern machines, the service must serve also an old iPhone 4, which is limited to iOS 7.1.2.

leftprotoport (local) is limted to UDP 1701 (udp/l2f), while, and that is crucial for NAT’ed traffic, rightprotoport (remote) must be allowed on %any port, since the NAT may and does change the ports, specially when there are more than 1 connections at the same time.

When I connect from a FreeBSD 12-RELEASE-p3 client at home (also behind NAT) running strongSwan/mpd5, I see the following:
Code:
Feb 26 13:44:00 example-server.com charon[630]: 05[IKE] CHILD_SA L2TP/IPsec-Server{15} established with SPIs cc8b4278_i c8ca81e8_o and TS 172.16.x.x/32[udp/l2f] === 189.x.x.x/32[udp]

At the same time, I see on the client:
Code:
Feb 26 13:44:00 example-client.com ipsec[1878]: 01[IKE] <L2TP/IPsec-Client|1> CHILD_SA L2TP/IPsec-Client{1} established with SPIs c8ca81e8_i cc8b4278_o and TS 192.168.x.x/32[udp] === 18.x.x.x/32[udp/l2f]

192.168.x.x is the private IP address of the client at home
189.x.x.x is the public IP address of my gateway at home
18.x.x.x is the public IP address of the AWS-EC2 instance
172.16.x.x is the private IP address of the network interface of the AWS-EC2 instance

Said FreeBSD client at home got the following /usr/local/etc/ipsec.conf:
Code:
conn L2TP/IPsec-Client
   keyexchange = ikev1
   type = transport

   leftauth = psk
   left = %defaultroute
   leftprotoport=17/%any

   rightauth = psk
   rightid = %any
   right = example-server.com
   rightprotoport=17/1701

   auto = start
 
Back
Top