NordVPN (IPSEC/IKEv2) + killswitch (For ROS6)

Overview

  • I’ve wasted hours making RouterOS to work perfectly with NordVPN and I wrote this guide, so you don’t have to waste your time.
  • You must have RouterOS 6. It must be minimum version of 6.45. Some steps in ROS7 will be different.
  • Nearly identical setup is possible with Surfshark. See here.
  • To get around geo restrictions (e.g. for bbc player, Netflix content) as well as DNS leaking, you must use NordVPN DNS servers. Disclaimer: I did not test if it works.
  • Below steps uses the “considered to be perfectly safe” ciphers & their levels, but NordVPN does support higher levels of encryption. Check what hardware acceleration is supported by your Mikrotik router and you might want to use such encryption instead for below steps. P.S. “SHA384 hash algorithm support for phase 1” is supported since 6.48 (might be CLI only).
  • Instead of reducing MSS size using below given commands, one can also do this using IPSEC functionality. See here for instructions.

Preparation

  1. Get recommended NordVPN server from here. In below steps I used “lv55.nordvpn.com”.
  2. Get your Service Credentials from here and use them for this setup.
  3. Import NordVPN CA to your router:
/tool fetch url="https://downloads.nordcdn.com/certificates/root.der"
/certificate import file-name=root.der name="NordVPN CA" passphrase=""

Use-case #1: Specific traffic (by source) routed through VPN server

Example: You want only 2 LAN devices (192.168.88.10 and 192.168.88.11) to reach internet through VPN server, but the rest of LAN devices to reach internet normally (without VPN server).


# Mark traffic that you want to route through VPN server
/ip firewall address-list add address=192.168.88.10 list=under_nordvpn
/ip firewall address-list add address=192.168.88.11 list=under_nordvpn
/ip firewall mangle add action=mark-connection chain=prerouting src-address-list=under_nordvpn new-connection-mark=under_nordvpn passthrough=yes

# IPsec/IKEv2 configuration
/ip ipsec mode-config add connection-mark=under_nordvpn name="NordVPN mode config" responder=no
/ip ipsec policy group add name=NordVPN
/ip ipsec profile add dh-group=modp2048 enc-algorithm=aes-256 hash-algorithm=sha512 name="NordVPN profile"
/ip ipsec peer add address=lv55.nordvpn.com exchange-mode=ike2 name="NordVPN server" profile="NordVPN profile"
/ip ipsec proposal add auth-algorithms=sha256 enc-algorithms=aes-256-cbc lifetime=0s name="NordVPN proposal" pfs-group=none
/ip ipsec identity add auth-method=eap certificate="NordVPN CA" eap-methods=eap-mschapv2 generate-policy=port-strict mode-config="NordVPN mode config" password=XXXXXXXXXX peer="NordVPN server" policy-template-group=NordVPN username=XXXXXXXXXX
/ip ipsec policy add dst-address=0.0.0.0/0 group=NordVPN proposal="NordVPN proposal" src-address=0.0.0.0/0 template=yes

# In "/ip ipsec policy" you should be able to see a new dynamic rule added next to your NordVPN policy. It MUST exist, otherwise configuration is not working.

# (OPTIONAL) Implement a killswitch
/interface bridge add name=nordvpn_blackhole protocol-mode=none
/ip route add gateway=nordvpn_blackhole routing-mark=nordvpn_blackhole
/ip firewall mangle add chain=prerouting src-address-list=under_nordvpn action=mark-routing new-routing-mark=nordvpn_blackhole passthrough=yes

# Exclude such VPN traffic from fasttrack
/ip firewall filter add action=accept chain=forward connection-mark=under_nordvpn place-before=[find where action=fasttrack-connection]

# Reduce MSS (should be about 1200 to 1400, but 1360 worked for me)
/ip firewall mangle add action=change-mss chain=forward new-mss=1360 passthrough=yes protocol=tcp connection-mark=under_nordvpn tcp-flags=syn tcp-mss=!0-1360

Use-case #2: Specific traffic (by destination) routed through VPN server

Example: You want to reach website wtfismyip.com via VPN server, but the rest of the traffic should go as it is (without VPN).

Note: You can’t effectively route all the traffic of Youtube, Netflix or any other big websites through VPN. They have many different domains and IP addresses which constantly change. Instead, route all the traffic of your device through VPN.

Note 2: You might be able to route all traffic of the company, but you might end up routing 30-40% of the websites under NordVPN if company uses popular hosting, e.g. Amazon AWS or Linode. For example, Mikrotik.com resolves to “159.148.147.196”. Quick google revealed the Mikrotik has it’s own ASN which contains 512 ips, or in other words, If you wish to access Mikrotik services/websites under NordVPN, you should add 159.148.147.0/24 and 159.148.172.0/24 to your address list using this (2nd) method.


# Mark traffic that you want to route through VPN server
/ip firewall address-list add address=wtfismyip.com list=under_nordvpn
/ip firewall mangle add action=mark-connection chain=prerouting dst-address-list=under_nordvpn new-connection-mark=under_nordvpn passthrough=yes

# IPsec/IKEv2 configuration
/ip ipsec mode-config add connection-mark=under_nordvpn name="NordVPN mode config" responder=no
/ip ipsec policy group add name=NordVPN
/ip ipsec profile add dh-group=modp2048 enc-algorithm=aes-256 hash-algorithm=sha512 name="NordVPN profile"
/ip ipsec peer add address=lv55.nordvpn.com exchange-mode=ike2 name="NordVPN server" profile="NordVPN profile"
/ip ipsec proposal add auth-algorithms=sha256 enc-algorithms=aes-256-cbc lifetime=0s name="NordVPN proposal" pfs-group=none
/ip ipsec identity add auth-method=eap certificate="NordVPN CA" eap-methods=eap-mschapv2 generate-policy=port-strict mode-config="NordVPN mode config" password=XXXXXXXXXX peer="NordVPN server" policy-template-group=NordVPN username=XXXXXXXXXX
/ip ipsec policy add dst-address=0.0.0.0/0 group=NordVPN proposal="NordVPN proposal" src-address=0.0.0.0/0 template=yes

# In "/ip ipsec policy" you should be able to see a new dynamic rule added next to your NordVPN policy. It MUST exist, otherwise configuration is not working.

# (OPTIONAL) Implement a killswitch
/interface bridge add name=nordvpn_blackhole protocol-mode=none
/ip route add gateway=nordvpn_blackhole routing-mark=nordvpn_blackhole
/ip firewall mangle add chain=prerouting dst-address-list=under_nordvpn action=mark-routing new-routing-mark=nordvpn_blackhole passthrough=yes

# Exclude such VPN traffic from fasttrack
/ip firewall filter add action=accept chain=forward connection-mark=under_nordvpn place-before=[find where action=fasttrack-connection]

# Reduce MSS (should be about 1200 to 1400, but 1360 worked for me)
/ip firewall mangle add action=change-mss chain=forward new-mss=1360 passthrough=yes protocol=tcp connection-mark=under_nordvpn tcp-flags=syn tcp-mss=!0-1360

That killswitch is not great (*). Quite dangerous in fact. It will kill bidirectional communication to internet (under normal circumstances = when nobody is trying to get you), but it doesn’t prevent leaking packets.

For example, if client uses VPN to ask some super secret DNS queries, they will go out to ISP when VPN is down. This killswitch doesn’t prevent that. It doesn’t matter how far will they get, there won’t be any response coming back. But the point is, someone will have chance to see them. I chose DNS, because query is just one UDP packet and it can contain sensitive data.

And the lack of responses, well, it’s not exactly true. There could be someone in ISP’s network (Men in Black, …) waiting for exactly this mistake. They can send fake responses to you. In fact, they can give you full internet access. They’ll know that your LAN subnet is behind your router, so they will know where to route responses. And doing outgoing srcnat for you, so that the internet will work, is no problem either. And you won’t know that you’re not doing your super secret stuff through VPN (unless there’s some IP-based blocking on target servers, or something else you’d notice).

Bad enough? It’s even worse, they don’t have to wait, they can sabotage (block) your connection to VPN server any time they want and get your secret traffic this way.

I’d use something else, for example (only briefly tested, improvements are welcome):

/interface bridge
add name=vpn-blackhole protocol-mode=none
/ip route
add gateway=vpn-blackhole routing-mark=to_vpn
/ip firewall mangle
add chain=prerouting src-address-list=under_vpn action=mark-routing new-routing-mark=to_vpn passthrough=yes

Empty bridge is used as default gateway with alternative routing table “to_vpn”. Everything from address list “under_vpn” (from your mode config) gets routing mark “to_vpn”, so it will use this routing table. When VPN is down, packets will try to go to empty bridge and won’t get anywhere. With VPN up, it will work, because of how IPSec works, it steals packets just before they are sent out, encrypts them and creates different packets. And those are output packets from router and there’s new routing decision for them.


(*) Original version excluded outgoing traffic from NAT using accept rule in srcnat chain. Running tunnel adds dynamic srcnat rule at the top, so it has priority. With tunnel down, the traffic would go out with original source address (private address from LAN subnet), so communication with internet would not work, because servers can’t send responses to private addresses, and ISP should drop such traffic anyway.

Thank you for your feedback. I completely agree with you, and after testing your provided commands seems that it’s working perfectly. +1 for brief explanation.

I’ve updated commands in initial post. If someone has any better suggestions - let me know and I will update accordingly.

Should I see traffic when I torch the bridge acting as blackhole for the VPN when it is going up or down?

The only traffic I saw was ARP. When I re-enable my own killswitch lines (dst 100.69.69.69) then those lines in NAT do catch traffic.

Looking in /IP routing the PPPoE-out has a distance of zero and the blackhole an distance of one. I can’t set the blackhole to zero.

I see the same…


it does not matter since you specify which routing mark to use. You can even set distance to 10 and it would still work.

EDIT: I wrote some crap in this commented. Deleted it. :slight_smile:

The bridge is like any other non-point-to-point interface. If you use it as gateway, router needs to get MAC addresses for target IP addresses, to be able to send data to them, so it sends ARP requests. And in this case can’t get any response.

With use case #2, how to killswitch websites like youtube.com that with multiple IP address?

You can’t, because:

Note: You can’t effectively route all the traffic of Youtube, Netflix or any other big websites through VPN. They have many different domains and IP addresses which constantly change. Instead, route all the traffic of your device through VPN.

I’ve updated those steps and given above quoted note. You need to route all the traffic of your device through VPN in order to achieve this. See 2nd method again for updated steps.

Thanks!

Hi, have a bit of a problem to get it working with multiple VLANs. So, I tried some tweaks but I’m a bit confused, so I like some inputs. For if I understand the packet flow it should not work but it does. Or I think it does, for I get the result I want. But as you see below here, I have put in some extra thing. For in the original one you will not be able to reach other VLANs.

/ip firewall mangle
add action=mark-connection chain=postrouting new-connection-mark=under_vpn out-interface-list=!ALL_LAN passthrough=yes src-address-list=HOST-NeedVPN
add action=change-mss chain=forward connection-mark=under_vpn new-mss=1360 passthrough=yes protocol=tcp tcp-flags=syn tcp-mss=!0-1360
add action=mark-routing chain=prerouting connection-mark=under_vpn new-routing-mark=to_vpn passthrough=yes src-address-list=HOST-NeedVPN

But the thing that make me confuse is that I can mark in postrouting and use it in prerouting, does it only work for its Ikev2/IPsec? Or maybe it does not work but I think it dose for I get the result I except when the tunnel is down. :blush: (I’m pretty new to Mikrotik, but I rely don’t like it when it just works but I don’t know how)

It’s the killswitch, it affects all packets from hosts listed in “under_vpn” list, including those to other local subnets.

Your modification kind of breaks the killswitch, because it now works only for packets with connection-mark=under_vpn, but you set that when first packet goes out, so only subsequent ones will be affected, i.e. the first one will leak out when VPN is down.

That also answers your question, how mark set in postrouting can work in prerouting. It can, but not for same packet. Connection marks are like that, router automatically identifies packets that belong to same connection and assigns connection mark to them (that differs from packet and routing marks).

What you want is for killswich to always work, but exclude local subnets. One way is to add dst-address-list=! to it. Another is using routing rules:

/ip route rule
add action=lookup-only-in-table dst-address=<local subnet 1> table=main
add action=lookup-only-in-table dst-address=<local subnet 2> table=main
...

I prefer the latter, because it can also help with other things. For example, if you’d be doing hairpin NAT to your internal server, then this one would work, while the former wouldn’t (without additional changes).

Tanks lot for the clarifying and solution.
It worked grate, I used the router rules with summarization.

I see in the use cases the following line which is obsolete if you do that directly in IPSEC Policy.

It is this line in mangle:

# Reduce MSS (should be about 1200 to 1400, but 1360 worked for me)
/ip firewall mangle add action=change-mss chain=forward new-mss=1360 passthrough=yes protocol=tcp src-address-list=under_vpn tcp-flags=syn tcp-mss=!0-1360

My posting about this and Sindy was the one who solved it: http://forum.mikrotik.com/t/sector-writes-growing/160/1

/ip ipsec policy
move *ffffff destination=0
add action=none dst-address=192.168.88.0/24 src-address=0.0.0.0/0 place-before=1

The first line is I think not needed anymore because it will be always at the top in policy. I have used here an internal network: 192.168.88.0/24 and you have to adapt it to the internal network you are using to connect to the router providing IKEv2.

Also NordVPN and other allow to use SHA384 in profiles which gives a higher level of encrypting in phase 1 of the connection.

@msatter - thanks for your input.

I don’t actually see it as a improvement to my given guide. I mean it does work, but using simple a mangle rule is a more dynamic way of dealing with VPN traffic.

e.g. in address-list I gave domain which is being resolved by Mikrotik router. If it’s updated, then it’s also being routed through VPN. This wouldn’t be the case with ipsec policies. I would need to update it manually then.

Am I missing something here?


Also NordVPN and other allow to use SHA384 in profiles which gives a higher level of encrypting in phase 1 of the connection.

I’ve heard about it, but it’s not “officially” supported as per here. I believe SHA256 is enough as of now, but it’s up to the user to increase it.

It is for sync that is needed and RouterOS does not know where to sent those returning packets to. Those packets are now sent to where they are expected and being processed to lower the MTU till no, please lower the MTU are send anymore.

IKEv2/IPsec significantly increases the security and privacy of users by employing strong cryptographic algorithms and keys. NordVPN uses NGE (Next Generation Encryption) in IKEv2/IPsec. The ciphers used to generate Phase1 keys are AES-256-GCM for encryption, coupled with SHA2-384 to ensure integrity, and combined with PFS (Perfect Forward Secrecy) using 3072-bit Diffie-Hellman keys. IPsec then secures the tunnel between the client and server, using the strong AES-256. The protocol provides the user with peace-of-mind security, stability, and speed. That’s why it is highly recommended by NordVPN and is used by default in the NordVPN apps for iOS and macOS.

Source: https://support.nordvpn.com/FAQ/1047408592/Which-protocol-should-I-choose.htm

RouterOS does not support AES-256-GCM so that is not possible.
Update: the router I have can do also CGM but most others do not and no mentioning of SHA384.

Releasenotes latest stable 6.48: *) ipsec - added SHA384 hash algorithm support for phase 1

Update2: NordVPN also supports DH19 - ecp256

/ip ipsec profile add name="NordVPN" hash-algorithm=sha384 enc-algorithm=aes-256 dh-group=ecp256,modp3072

Thanks for all the input! I’ve updated instructions accordingly.

I’m glad I find this guide. Just wanna say thanks!

Works like a charm with Windows but still have issues with Android devices with TCP MSS 1360. Any way to guess the sweet size?
Tnx and HNY!

UPDATE
upgraded to v 6.48 (rel Dec, 22, 2020)and retested with Android. Now is working, before upload on Android was almost zero

Please tell me how to correctly forward the port for example for torrent in this configuration?

  1. How is it related to this thread?
  2. Why would you need port forward for…torrents?