Home computer ↔ Mikrotik with NAT ↔ Internet ↔ Server
Home connects to Server using L2TP
There is an IPSec transport established between the Mikrotik and the Server, so the Home computer’s L2TP traffic is encrypted as it goes out to server.
So far so good.
Now I’d also like to make this IPSec mandatory - i.e. stop unencrypted L2TP from leaving the Mikrotik.
Sadly, now I see (in tcpdump udp proto 1701) that the Home computer is still talking to the Server, over UDP 1701. In other words, the rule to block unencrypted L2TP did not work.
An almost identical rule works just fine for GRE but the GRE tunnel is configured on the Mikrotik itself.
The chain=output is for packets from router itself (process running on router). Packets from home computer to server will go through chain=forward.
The ipsec-policy matcher also works only for IPSec configured on router itself. Router has no way of knowing that some packets from home computer to server should use IPSec, because IPSec is on home computer and it didn’t tell router about it (there’s no way how it could).
… so what you actually need to do is to block access to protocol=udp dst-port=1701 dst-address=the.ip.of.the.server in chain=forward. The L2TP packets encapsulated into IPsec transport ones won’t be affected by that rule.
About the policy, probably not. I’m not exactly sure about behaviour of policies for unconnected peers without testing it, maybe there’s a chance to do something with it that way, but IMHO it would be a dirty trick. If you want to make sure that home computer won’t be able to use bare L2TP, blocking the port in forward chain is the right solution.
Thanks. As it turned out, blocking on forward will block no matter if it’s encrypted or not.
Maybe I’m doing something wrong, but it seems kind of logical - as there is no special chain that specifically targets “forwarding, but after IPSec encryption before it’s sent out”.
I was able to block unencrypted L2TP on the server - where it’s possible to use iptables directly - and the connection just wouldn’t establish if not encrypted. Fine. But this made things unstable, xl2tp on the client behind the Mikrotik would start getting weird errors after a while and abort.
Long story short… I already had a GRE / IPSec tunnel to this server - so ended up creating a firewall mangle to route L2TP through that encrypted GRE. A hack but it works and seems stable.
Matching on IPsec policy is only working when your router itself is terminating the IPsec.
It can do that, but this is not what you are doing now (the router is forwarding encrypted traffic to your server).
In this case, you simply allow only UDP port 500, UDP port 4500, and IP protocol 50 to be forwarded to your server.
(the latter is probably not necessary as you have NAT in your path anyway)
Don’t allow UDP port 1701 forwarding across your router. It is the unencrypted L2TP traffic.
It can do that, but this is not what you are doing now (the router is forwarding encrypted traffic to your server).
Actually no, encryption was handled by the router.
There is an IPSec transport established between the Mikrotik and the Server, so the Home computer’s L2TP traffic is encrypted as it goes out to server.
Home computer L2TP client ↔ Mikrotik with IPSec policy for UDP dport 1701 ↔ Internet ↔ Server with IPSec and L2TP
And now it’s like this and it works:
Home computer L2TP client ↔ Mikrotik with IPSec policy for GRE, wraps L2TP into GRE ↔ Internet ↔ Server unpacks IPSec, GRE, deals with L2TP
That changes a lot - better to say, it invalidates all the advice we’ve given you so far.
When the IPsec encryption of the L2TP is provided by the Mikrotik, the task of preventing non-encapsulated L2TP from leaving the router cannot be done using firewall rules as they are handled before the IPsec policies. If things worked the way they should, you could place the policy with action=encrypt first, and place another policy with the same traffic selector (src-address, dst-address, protocol, src-port, dst-port) and action=discard next to it, so whenever the first policy wouldn’t be active, the second one would discard the traffic, but it doesn’t work this way because a second policy with traffic selector identical to another one is ignored, and using a wider traffic selector works but you it would cause you other problems.
So my solution in these cases, when I want traffic to only get out if the IPsec security association for it is up and running, is to set up a route for that traffic to a gateway which leads to nowhere. You create an /interface bridge, assign no IP to it, and use it as a gateway for the /ip route for that traffic. As the IPsec policy steals the traffic just before it would be sent down the gateway, it saves it from being sent to nowhere if it is active.
In your case, as you want to drop only unencrypted traffic from your PC’s local IP to the server’s IP and UDP port 1701, it is not enough to create an /ip route with dst-address matching the server IP and gateway=br-blackhole, but you have to create a default route (dst-address=0.0.0.0/0 with that gateway and some routing-mark, and use a rule in /ip firewall mangle chain=output to assign that routing-mark to packets matching protocol=udp src-address=your.pc’s.ip.address dst-address=your.server’s.ip.address dst-port=1701.
Oh, and I haven’t noticed that you have GRE between the L2TP and IPsec layers; this only changes the mangle rule in what I wrote above, as you need to prevent the GRE transport packets from being delivered if the IPsec SA is down rather than the L2TP ones.
But I have to say I don’t understand why you need a three-layer tunneling, wasting so much of the available MTU.
There is an IPSec transport established between the Mikrotik and the Server, so the Home computer’s L2TP traffic is encrypted as it goes out to server.
I perhaps should have written
There is an IPSec transport established between the Mikrotik and the Server, so the Home computer’s L2TP traffic is encrypted > by the Mikrotik > as it goes through and out to server.
And then
cannot be done using firewall rules as they are handled before the IPsec policies
yes this makes sense.
And your tip about routing-mark - does too. Thanks again!
The GRE / IPSec tunnel exists for different reasons and it was already there.
Routing L2TP into that GRE was just an experiment which seemed to work - yes inefficient but before I got your advice about mangle and stuff, it was the best I could come up with.
I had a look at my VPN and up goes no traffic over port 1701 up but down I traffic on port 1701 coming from the VPN connection and the packey count are almost the same as on ipsec-esp in the line above in RAW.
If I disable the accept for 1701 incoming, in RAW, my VPN is death.
Is my traffic down encrypted?
update: with the ipsec-esp disbabled the connection still works and I am going to try dropping the epsec-esp.
This is a feature of the IPsec implementation - packet sniffing shows both encrypted and decrypted version of the incoming traffic on an interface although only the encrypted version is actually present “on the wire”. In outbound direction, the not-yet-encrypted traffic is not sniffed. You can sniff on the opposite end (L2TP client) to double-check this.
If your client is behind a NAT, the ESP is encapsulated into UDP so it is not visible to the firewall at all. ESP is only used “naked” if no NAT exists between the peers.
Can you explain your goal in deeper detail and ask a clear question? From what you wrote I didn’t understand what you want to hear from me
What I got from the previous post is that you have several VPN accounts (probably at the same provider) and you want to load balance your traffic between these accounts, but I don’t know what you expect from this an how is NAT related to that goal.
Thanks for your patience and I am looking for a way to skip NAT. I have marked the route in Mangle and it puzzles me why I still need NAT.
In the default client setup for L2TP(-IPSEC) the local address is set in the 172.20.12.x range and I changed that to a address that is my local network thinking that NAT would be then obsolete. That did not work.