L2TP/IPSEC not encrypted

6.37.4(bugfix)

I have a hub/spoke VPN setup using three routers with the above version. Most of the time it works OK but on occasions when the link comes up it seems to bypass the IPSEC encrytption:

Server

[admin@O2vpn-hub] > /ppp active print detail
Flags: R - radius 
 0   name="o2vpn2" service=l2tp caller-id="82.132.161.25" address=172.16.3
     encoding="MPPE128 stateless" session-id=0x81800000 limit-bytes-in=0 
     limit-bytes-out=0 

 1   name="o2vpn1" service=l2tp caller-id="82.132.170.6" address=172.16.3.
     encoding="MPPE128 stateless" session-id=0x81800001 limit-bytes-in=0 
     limit-bytes-out=0 

[admin@O2vpn-hub] > /ppp secret print detail
Flags: X - disabled 
 0   name="o2vpn1" service=l2tp caller-id="" password="xxxx" profile=default 
     local-address=172.16.3.1 remote-address=172.16.3.2 routes="" limit-bytes-in=0 
     limit-bytes-out=0 last-logged-out=jan/20/2017 17:48:36 

 1   name="o2vpn2" service=l2tp caller-id="" password="xxxx" profile=default 
     local-address=172.16.3.3 remote-address=172.16.3.4 routes="" limit-bytes-in=0 
     limit-bytes-out=0 last-logged-out=jan/20/2017 22:00:28

 [admin@O2vpn-hub] > /ppp profile print detail
Flags: * - default 
 0 * name="default" remote-ipv6-prefix-pool=none use-ipv6=yes use-mpls=default 
     use-compression=default use-encryption=default only-one=default change-tcp-mss=yes 
     use-upnp=default address-list="" on-up="" on-down="" 

 1 * name="default-encryption" remote-ipv6-prefix-pool=none use-ipv6=yes use-mpls=default 
     use-compression=default use-encryption=yes only-one=default change-tcp-mss=yes 
     use-upnp=default address-list="" on-up="" on-down="" 

[admin@O2vpn-hub] > /ip ipsec policy print detail
Flags: T - template, X - disabled, D - dynamic, I - inactive, * - default 
 0 T * group=default src-address=::/0 dst-address=::/0 protocol=all proposal=default 
       template=yes

Client

[admin@o2vpn1.eng] > /interface l2tp-client print detail
Flags: X - disabled, R - running 
 0  R name="l2tp-out1" max-mtu=1450 max-mru=1450 mrru=disabled 
      connect-to=217.16x.yyy.zzz user="o2vpn1" password="nnn" 
      profile=must-encrypt keepalive-timeout=60 use-ipsec=yes 
      ipsec-secret="zzzzz" allow-fast-path=no add-default-route=yes 
      default-route-distance=0 dial-on-demand=no allow=mschap2

If I clear the connection on the hub (l2tp server) it comes back in the same connected state. If I go to the client, disable then enable the l2tp-client, it re-establishes and works correctly. This behavior isn’t always repeatable but it’s usually after I power up the routers.

Here I’ve reset the interface on connection 1.

[admin@O2vpn-hub] > /ppp active print detail
Flags: R - radius 
 0   name="o2vpn2" service=l2tp caller-id="82.132.161.25" address=172.16.3.4 uptime=11m42s 
     encoding="MPPE128 stateless" session-id=0x81800003 limit-bytes-in=0 
     limit-bytes-out=0 

 1   name="o2vpn1" service=l2tp caller-id="82.132.170.6" address=172.16.3.2 uptime=1m18s 
     encoding="cbc(aes) + hmac(sha1)" session-id=0x81800005 limit-bytes-in=0 
     limit-bytes-out=0

Am I missing something in the configs or is this a possible bug?

Thanks.

Some of my output didn’t paste correctly in the first attempt.

Showing the ppp connections on the hub, 1 is now encrypted (expected behavior) 0 is not.

[admin@O2vpn-hub] > /ppp active print detail
Flags: R - radius 
 0   name="o2vpn2" service=l2tp caller-id="82.132.161.25" address=172.16.3.4 uptime=24m13s 
     encoding="MPPE128 stateless" session-id=0x81800003 limit-bytes-in=0 
     limit-bytes-out=0 

 1   name="o2vpn1" service=l2tp caller-id="82.132.170.6" address=172.16.3.2 uptime=13m49s 
     encoding="cbc(aes) + hmac(sha1)" session-id=0x81800005 limit-bytes-in=0 
     limit-bytes-out=0

Yes I have seen this happen as well. When the IPsec does not succeed for some reason the L2TP
still proceeds and the traffic is not encrypted. You can avoid this with suitable firewall rules.

/ip firewall filter
add action=reject chain=input comment=\
    "reject unprotected L2TP even when established!" dst-port=1701 \
    ipsec-policy=in,none protocol=udp reject-with=icmp-admin-prohibited

This rule has to be before the established/related rule in the input chain.
Of course it is always good to allow port 1701 only via IPsec in the input firewall:

add action=accept chain=input dst-port=1701 ipsec-policy=in,ipsec \
    log-prefix=l2tp protocol=udp

(this can be further down in the list below established/related matching)
It is not sufficient to prevent the problem because when there is an existing L2TP/IPsec link
between two routers, then one is rebooted, it can happen that the L2TP comes back unprotected
and is matched by the existing connection tracking entry and thus by established/related, that
is why you need the first rule as well.

Thanks for the suggestion!

I’ve modified the firewall rules to implement this. I’d just adapted the default firewall adding two rules to permit ESP and permit UDP 500,4500,1701 from the spoke routers (O2 UK broadband address range). Firstly I removed port 1701, which was intersting to see the IPSEC come up but no L2TP established. I then added the new rules and the L2TP came back up.

   [admin@O2vpn-hub] > /ip firewall filter print
Flags: X - disabled, I - invalid, D - dynamic
 0  D ;;; special dummy rule to show fasttrack counters
      chain=forward action=passthrough

 1    ;;; defconf: accept ICMP
      chain=input action=accept protocol=icmp log=no log-prefix=""

 2    chain=input action=accept protocol=ipsec-esp src-address=82.132.160.0/20
      in-interface=ether1 log=no log-prefix=""

 3    chain=input action=accept protocol=udp src-address=82.132.160.0/20
      in-interface=ether1 dst-port=500,4500 log=no log-prefix=""

 4    ;;; reject unprotected L2TP even when established!
      chain=input action=reject reject-with=icmp-admin-prohibited protocol=udp
      src-address=82.132.160.0/20 dst-port=1701 ipsec-policy=in,none

 5    chain=input action=accept protocol=udp src-address=82.132.160.0/20
      dst-port=1701 log-prefix="l2tp" ipsec-policy=in,ipsec

 6    ;;; defconf: accept establieshed,related
      chain=input action=accept connection-state=established,related log=no
      log-prefix=""

I’ll just give it another tweak to log any rejected unoprotected L2TP so I can see how often it occurs.

It is most efficient to move the established/related rule up as much as possible. Even the ICMP rule can be below that.
The rules are evaluated top to bottom and you want the established/related rule to hit as quick as possible, all rules
below that will be evaluated only once for each new connection.
And remember you have no real firewall unless you drop some traffic, as the default is to accept.
Normally there is some rule near the end that drops everything from ether1 so all unexpected incoming traffic from
internet is dropped. Actually I prefer instead to put an accept rule for traffic from the LAN and a drop rule for everything
at the end. Be careful not to lock yourself out when you experiment, use “safe mode”.

I do have a drop rule, just posted the relevant stuff above to show the input chain. I can drag the rules around in winbox to optimise things. If I add a rule dropping everything apart from the LAN won’t that block traffic from the l2tp connections as they appear as interfaces?

Yes, but normally you would not do input from those, only forwarding.
You can keep the explicit drop as long as you understand what you are doing.
E.g. when your internet is via PPPoE the explict drop should be on the PPPoE interface, not the ether1 interface.
That is where lots of people go wrong.

So now I’ve re-ordered a few rules based on your suggestions, traffic flow etc. Most of my understanding is based on experience with Cisco ACLs, ip inspect rules and some BSD pf. Cisco ACL has an implied deny-all at the bottom of the list, so need to double check I’ve done that on Mikrotik!

[admin@O2vpn-hub] > /ip firewall filter print 
Flags: X - disabled, I - invalid, D - dynamic 
 0  D ;;; special dummy rule to show fasttrack counters
      chain=forward action=passthrough 

 1    ;;; reject unprotected L2TP even when established!
      chain=input action=reject reject-with=icmp-admin-prohibited protocol=udp src-address=82.132.160.0/20 in-interface=ether1 
      dst-port=1701 log=no log-prefix="" ipsec-policy=in,none 

 2    ;;; defconf: accept establieshed,related
      chain=input action=accept connection-state=established,related in-interface=ether1 log=no log-prefix="" 

 3    chain=input action=accept protocol=ipsec-esp src-address=82.132.160.0/20 in-interface=ether1 log=no log-prefix="" 

 4    chain=input action=accept protocol=udp src-address=82.132.160.0/20 in-interface=ether1 dst-port=1701 log=no log-prefix="l2tp" 
      ipsec-policy=in,ipsec 

 5    chain=input action=accept protocol=udp src-address=82.132.160.0/20 in-interface=ether1 dst-port=500,4500 log=no log-prefix="" 

 6    ;;; defconf: accept ICMP
      chain=input action=accept protocol=icmp log=no log-prefix="" 

 7    ;;; defconf: drop all from WAN
      chain=input action=drop in-interface=ether1 log=no log-prefix="" 

 8    ;;; defconf: fasttrack
      chain=forward action=fasttrack-connection connection-state=established,related log=no log-prefix="" 

 9    ;;; defconf: accept established,related
      chain=forward action=accept connection-state=established,related log=no log-prefix="" 

10    ;;; defconf: drop invalid
      chain=forward action=drop connection-state=invalid log=no log-prefix="" 

11    ;;; defconf:  drop all from WAN not DSTNATed
      chain=forward action=drop connection-state=new connection-nat-state=!dstnat in-interface=ether1 log=no log-prefix=""

And here are the stats after it’s been running for 24 hours -

[admin@O2vpn-hub] > /ip firewall filter print stats
Flags: X - disabled, I - invalid, D - dynamic 
 #    CHAIN                                                        ACTION                            BYTES         PACKETS
 0  D ;;; special dummy rule to show fasttrack counters
      forward                                                      passthrough                 113 549 020         142 542
 1    ;;; reject unprotected L2TP even when established!
      input                                                        reject                              904              18
 2    ;;; defconf: accept establieshed,related
      input                                                        accept                       59 096 572         397 885
 3    input                                                        accept                       46 461 904          60 136
 4    input                                                        accept                       32 634 008          47 988
 5    input                                                        accept                       16 605 124          20 734
 6    ;;; defconf: accept ICMP
      input                                                        accept                            4 018              56
 7    ;;; defconf: drop all from WAN
      input                                                        drop                            235 019           1 684
 8    ;;; defconf: fasttrack
      forward                                                      fasttrack-connection         46 893 729          68 934
 9    ;;; defconf: accept established,related
      forward                                                      accept                       46 893 729          68 934
10    ;;; defconf: drop invalid
      forward                                                      drop                                229               5
11    ;;; defconf:  drop all from WAN not DSTNATed
      forward                                                      drop                                  0               0

I can see from the stats that a few unprotected L2TP connections have been rejected.

Mikrotik access lists are similar to Cisco ACL in that they are processed from top to bottom and that you want
to have the common cases as near to the top as possible. But they are also much more powerful, because they
allow you to make branches that make some broad match and then jump to another list that does more detailed
matching for that case. And it is also very useful that you can put comments at every rule. Linux would allow
a default-deny policy but apparently MikroTik has chosen not do do that. It is however easy to add a deny rule
at the end of every list, with the benefit that you get statistics and can do logging.
(of course not a good idea for an internet traffic dropping rule, but I normally use this for LAN rules where any
traffic being dropped at the end of the list points to potential problems)

The hits that you now see may not be all from your own environment, there may be “portscanners” on the
internet that try to send traffic to port 1701. With your previous setup you would not have seen these as a
separately counted item, but they would still be blocked by a “drop everything from internet” rule.