I use an IKEv2 VPN service with Mode Configuration enabled as client on the Mikrotik router. I am trying to lower the TCP MSS for connections going through the VPN tunnel as there are issues with the MTU and IP fragmentation on this tunnel. I already disabled firewall fasttrack for all connections as I noticed that this functionality is blocking VPN traffic for some tunnels. I’m thinking of adjusting the TCP MSS by using mangle rules with connection marking. Outbound and inbound connections would get marked and after that, another mangle rule would modify the TCP MSS for those marked connections.
What I observed is that, outgoing packets are not detect by the ipsec-policy=out,ipsec mangle rule. Only incoming packets get detected, by the ipsec-policy=in,ipsec rule, thus outgoing connections get marked (I cannot test with incoming connections), but only when the TCP SYN/ACK packet is detected, and consequently, TCP MSS is adjusted on for the incoming TCP flow. So the issue is, how can ipsec outgoing packets be detected for connection marking through mangle rules?
I have tested this setup with another IKEv2 VPN setup with Mode Configuration enabled as responder, and that is working fine, so the issue seems to be only related to the Mode Configuration enabled as client setup.
Postrouting (Mangle) see every forwarded packet, Output (Mangle) sees only the packets generated by the router self and in this case your outgoing encrypted traffic.
To set MSS you have to use Postrouting as then the outgoing packet is still unencrypted. But then you still can’t use ipsec-out because it is still before that is set. And once encrypted your can’t use MSS. You can’t so filter on that and you have to use the connection-mark “Mark” to recognize that traffic.
Optimized to only handle packets bigger than 1383 (in your case) and because it Postrouting (end of the line) you can mark passthrough=no so that the rest of rules in Mangle are ignored
No sure i understand what you’re trying to say; I did manage to have the TCP MSS modified for incoming TCP flows through the VPN tunnel (MSS changed on outgoing IPSec packets), but only through using a mangle rule without IPsec policy matching such as this:
But my purpose is not to adjust TCP MSS for all connections, only for the IPsec outgoing ones, which is why I need the connection or packet marking to work for the IPsec out policiy matching mangle rule. I’ve tested this rule with the chain set to “postrouting” and “output”, but it does not make a difference. In order to only match the IPsec out packets/connections, I need a way to match them after the automatic SNAT form mode configuration has been applied:
0 D ;;; ipsec mode-config
chain=srcnat action=src-nat to-addresses=10.6.0.5 src-address-list=VPNsource dst-address-list=!VPNsource
Once it is natted you can’t do mucht more, see Postrouting marked 4:
SRC-NAT is after Postrouting so you have do the MSS stuff before that.Postrouting the place and it has to be done before it is encrypted, so on the first loop. See diagram above.
You call the traffic incoming and I am calling it outgoing because it leaves after the SRC-NAT. I do not use ipsec-out and I assume that it is encrypted traffic for your VPN provider.
Traffic, with destination the VPN provider: Forward → Postrouting loop one → encryption ( traffic is now encrypted) → Output → Postrouting (second time) → SRC-NAT → VPN tunnel
You sent a packet upstream to the VPN. Normally, the VPN say it is to big (ICMP 3-4) and I can handle 1382 for example. The router tells the client, keep it below 1383. If the VPN provider is not sending a ICMP 3-4 you have to keep it yourself below that 1383 by forcing that MTU for your clients. NordVPN has some troubles sending back those ICMP 3-4.
You need in the end, only one Mangle line and that is a Postrouting. This only if you already have marked all NEW traffic going through the VPN with new-connection-mark=MARK and so the Mark differentiates that traffic from the rest.
Prerouting / Forward → mark traffic and because it is connection-marking the router will keep track of that marked connection for you and you don’t have lift an finger anymore.
Update: I added ipsec-policy=out,none so that Postrouting is ignoring encrypted traffic, which it can’t change after all.
Update 2: new-connection-mark seems to be only possible in prerouting and output. Using ROS v7 here. And it seem logical to do that before the routing decision.
Knowing here the out interface is WireGuard (List in Interface) avoids having to look at the connection-mark. IKEv2 is dynamic so making a List in Interface is not possible.
I’m using 6.49 firmware. I understood what you meant, but I think you did a mistake in the placement of SRC-NAT in outgoing IPsec packet flow processing, it should be as follows:
Forward → Postrouting loop one → SRC-NAT (derived from mode configuration) → encryption ( traffic is now encrypted) → Output → Postrouting (second time) → VPN tunnel
as SRC-NAT applied through the mode configuration functionality is done for inside tunnel traffic. Matching by IPsec out policy (ipsec-policy=out,ipsec) in mangle rules will match by the virtual IP address as source (received via mode configuration from the remote peer, IPsec policy is derived from template), but as you said, because postrouting SRC-NAT is done after mangle, I cannot do anything to match it via mangle rules, perhaps only by destination, which is impractical. It’s not necessary to perform the mangle in postrouting, if matching is done by source address.
The only way it would have worked is to be able to apply mangle rules after SRC-NAT in postrouting. If there was a possibility to define the IPsec tunnels as virtual interfaces and use routing with those, perhaps it would work to apply mangle in postrouting. Other vendors support this type of setting.
One interesting thing I noticed is that TCP MSS mangle rules with clamp-to-pmtu action do work for IPsec tunnels where SRC-NAT (no mode configuration as client) is not applied:
Mode configuration is there to be able to create the dynamic NAT lines. You can use src-address or connection marking or combine those two.
I refined my own MSS line and ended up with doing that in Forward, as I wrote about. This avoids the ipsec:out:none.
You want to MSS traffic going into the tunnel. NAT sees only encrypted traffic and sets a new src-address on encrypted packets heading into the tunnel. You can see that it not going twice throuh the NAT.
Once encrypted you can’t change the content anymore and so not change of MSS.
You write that the PMTU does work, but it will aply that MTU to all forwarded traffic, VPN and not VPN. You have your connection-mark to only MSS your VPN traffic and so can use that there also.
So if PMTU is working for you then you can go to the next level and that is to transfer the ICMP 3-4 to the clients and so no need to do anything about the MTU in Mangle and worry about NAT.
This is done in IPSEC Policies and this a script to add the needed line.
The address range is the one of the internal network or in your case the part of the network allowed to use the VPN → src-address-list=VPNsource
That address range can differ from the one above so you have to adapt that manually.
Since a few weeks, some servers from NordVPN does not return ICMP 3-4 and that goes also for the WireGuard servers of them. This a specific problem with NordVPN.
msatter, I don’t understand what you meant in your first reply. SRC-NAT via mode configuration is applied to unencrypted packets.
There is no need for ICMP 3-4 packets for the router to derive the PMTU for an IPsec tunnel, this is apparently derived form phase2 algorithms negotiations results, and mangle rules with action=change-mss new-mss=clamp-to-pmtu do work in the forward chain to properly change the TCP MSS in relation to the tunnel’s PMTU, but not for the mode configuration as client tunnel setups. My guess is that there is some matching done in the forward chain with IPsec policies, in order to choose the proper PMTU, but for mode configuration as client derived IPsec policies, the match is not happening, probably because the source in the IPsec policy is the mode configuration received IP address.
I did try your suggestion with the IPsec policy but it did not do the trick.
Let’s take a look at another tunnel type - IPSec. This type of VPN does not have logical interfaces but is processed in a similar manner.
Instead of logical interfaces packets are processed through IPSec policies. After routing decision (2) and input firewall processing (3), the router tries to match the source and destination to IPsec policy. When policy matches the packet it is sent to decryption (5). After the decryption packet enters PREROUTING processing again (6) and starts another processing loop, but now with the decapsulated packet.
The same process is with encapsulation but in reverse order. First IP packet gets processed through facilities, then matched against IPsec policies (5), encapsulated (6), and then sent to processing on the second loop (7-10).
Not working, I would need perhaps some dummy IPsec policy using original local client IP address to be able to mangle match in the forward chain, but that also seems impossible.
That is the basic way and should fit your situation.
Next iteration is doing away with the connection-mark because you already decided to use an address-list named VPNsource. I assume the dynamic NAT lines use also VPNsource?
Line 1 and 2 combined (dynamic PMTU):
I already mentioned that i have used successfully the mangle rule based on source, but this adjusts the MSS for all outgoing packets from the source, not just IPsec tunnel outgoing ones (for example, if the VPN tunnel is down):
Can you give the complete and full command? I’m a newbie and it’s painful to understand the article by translation I don’t know what to do I use both nordvpn and protonvpn