Community discussions

MikroTik App
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 1459
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Keep IKEv2 connections running [ script ]

Sat Mar 07, 2020 11:29 am

Now we can use IKEv2 (NordVPN etc.) to encrypt our traffic it sometimes occurs that connection are not made/reconnected for any reason. That connection does nor recover and if you have several connections you only will notice that some web pages are not loading or after a delay.

I have written a script that looks if the connection is present and if not restarts it:
#Change to IPsec peer, to have that as default location to run commands
/ip ipsec peer
## Check  NordVPN IKEv2
:local peername NordVPN-1; :if ([/ip ipsec policy find where peer=$peername] = "") do={:log error "$peername not active, restarting.."; disable $peername; :delay 2000ms; enable $peername};
:local peername NordVPN-2; :if ([/ip ipsec policy find where peer=$peername] = "") do={:log error "$peername not active, restarting.."; disable $peername; :delay 2000ms; enable $peername};
:local peername NordVPN-2; :if ([/ip ipsec policy find where peer=$peername] = "") do={:log error "$peername not active, restarting.."; disable $peername; :delay 2000ms; enable $peername};

:local peername the variable peername stores the name you given to that specific connection.

If the connection is not found then that is logged and the connection is disabled in IPsec peer then wait 2 seconds and then enable it again. I check every 5 minutes in scheduler, but that could be more frequent.

I don't think that I need the where in find and if there are more optimization possible then please share it.
Two RB760iGS (hEX S) in series. One does PPPoE and both do IKEv2.
Running:
RouterOS 6.47.beta.x / Winbox 3.21 / MikroTik APP 1.3.12
NordVPN viewtopic.php?f=2&t=158439&p=781009 for multiple connections.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 1459
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Keep IKEv2 connections running [ script ]

Tue Mar 10, 2020 1:26 pm

I am now checking if the IKEv2 connection is enabled so that it not restarted if the user disabled it:
# Change to IPsec peer, to have that as default location to run commands
/ip ipsec peer
## Check  NordVPN
:local pn NordVPN-1; :if ([ find name="$pn"&&.dead ]!="") do={:if ([/ip ipsec policy find peer=$pn]="") do= {:log error "$pn not active, restarting.."; disable $pn; :delay 1500ms; enable $pn}};
:local pn NordVPN-2; :if ([ find name="$pn"&&.dead ]!="") do={:if ([/ip ipsec policy find peer=$pn]="") do= {:log error "$pn not active, restarting.."; disable $pn; :delay 1500ms; enable $pn}};
:local pn NordVPN-3; :if ([ find name="$pn"&&.dead ]!="") do={:if ([/ip ipsec policy find peer=$pn]="") do= {:log error "$pn not active, restarting.."; disable $pn; :delay 1500ms; enable $pn}};
I shortened the variable $peername to $pn

Next, make an array of the enabled Peers and so I don't have to check if a Peer is death or not. Automating also the filling of the variable $pn so I can use a loop.
Two RB760iGS (hEX S) in series. One does PPPoE and both do IKEv2.
Running:
RouterOS 6.47.beta.x / Winbox 3.21 / MikroTik APP 1.3.12
NordVPN viewtopic.php?f=2&t=158439&p=781009 for multiple connections.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 1459
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Keep IKEv2 connections running [ script ]

Thu Mar 19, 2020 5:50 pm

Made it more efficient and it will run without having to define the names upfront:
#Change to IPsec peer to have that as default location to run commands
/ip ipsec peer

#Loop through names of the peers and see if they need restart
:foreach i in=[find] do={
   :local pn "$[get value-name=name $i]";
   :if (!"$[get value-name=disabled $i]") do={:if ([/ip ipsec policy find peer=$pn]="") do= {:log error "$pn not active, restarting.."; disable $pn; :delay 1500ms; enable $pn}};
}
$i is a local counter
$pn contains the Peername defined in /ip ipsec peer

I am pleased with the result.
Two RB760iGS (hEX S) in series. One does PPPoE and both do IKEv2.
Running:
RouterOS 6.47.beta.x / Winbox 3.21 / MikroTik APP 1.3.12
NordVPN viewtopic.php?f=2&t=158439&p=781009 for multiple connections.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 1459
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Keep IKEv2 connections running [ script ]

Sat Mar 21, 2020 9:16 pm

I am even more pleased that I managed to create a script that look at the active IKEv2 connections and create the distribution rules for traffic over those multiple connection.

It is adapts when a connection is halted or a connection is added and it evens makes the last one in the lists, a catch-all so not data is lost. You can set it up to use for PCC or NTH.

PCC very stable and NTH is all over the place when having more than two connections.

Finally, yesssssss, I don't have to open up Winbox to change mannually the distribution when a IKEv2 connection drops. It will now not point traffic to that IKEv2 connection within 5 seconds.

I made it so, that the short recheck time of every five seconds has no impact on the performance of the router.
# Free to use. Created by Blacklister 20200324-2.3
# Traffic distributor based on dynamicly generated based on active IKEv2 connections
# IKEv2 distributor creater that can jumped to and all lines have not passthrough when setting the connection-mark
# This will create distribution based on PCC-sourceport or NTH and it change the last in the list to a catch-all
# ChainName can be set to the desired name
# Naming of the IKEv2  connections must contain the the lettergroup VPN and have per provider a unique naming like:
# NordVPN-1 NordVPN-2 or MikrotikVPN-1 NordVPN-1 NordVPN-2


:local chainName       "Nord-IKEV";    # Name of the chain 
:local distributeType  "PCC";          # Change to PCC (bit of randomness) or NTH (no randomness which connection is used)
:local peerNamePart    "(NORD|OTHER)"; # RegEX (regular expression). Contains the unique namepart(s) or just "VPN" to only select all the active ones. Format "(xyx|zxy)"
:local varName         "NORD";         # Unique part of the variable shortName
:local shortName       ($varName."prevCount"); # Used for creating :global variable. Do not edit!

/ip firewall mangle; # Change to default location to run commands easier

# Check if the parse of $shorName exists and if not, create a global variable value 99 indicating fresh run.
:if ([/system script environment find name=$shortName]) do={} else={[:parse "global $shortName 99"];};
:local localNew "$[:len [/ip ipsec policy find peer~$peerNamePart]]"; # Count number of selected active IKEv2 connections
# Check if the distributor has to be renewed or even be created.
:if (($localNew != [/sys scr env get [find name="$shortName"] value-name=value]) or ("$[:len [/ip fire man find chain=$chainName ]]")=0) do={                    
    :do { remove [find chain="$chainName"] } on-error={};
    :local linePCC 0; :local lineNTH $localNew; :global peerName; # Counter for PCC/NTH and define global variable peerName containing the last peername
   :foreach lineID in=[/ip ipsec policy find peer~$peerNamePart] do={ # Loop through the names of the peers using .id
     :set $peerName "$[/ip ipsec policy get value-name=peer $lineID]";
     # Create individual distribution lines in Mangle  
     :if ($distributeType = "PCC") do={\ 
      :if ($linePCC = 0) do={add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no\
         per-connection-classifier=("both-addresses-and-ports:"."$localNew"."/"."$linePCC") comment="Start of the distributor for IKEv2 chain: $chainName"}\
      else={ add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no per-connection-classifier=("both-addresses-and-ports:"."$localNew"."/"."$linePCC")}
     };

:if ($distributeType = "NTH") do={\ 
     :if ($lineNTH = $localNew) do={add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no nth=("$lineNTH".","."1")  comment="Start of the distributor for IKEv2 chain: $chainName"}\
       else={ add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no nth=("$lineNTH".","."1")}
     };

    # Increase / decrease the counters by 1
    :set $linePCC ($linePCC +1); :set $lineNTH ($lineNTH -1); 
    }; # End of the [foreach loop]
   :if ($distributeType = "PCC") do={
      unset [find chain="$chainName" new-connection-mark="$peerName"] value-name=per-connection-classifier}; # remove PPC from last added line to create a Catch-all line
   :if ($distributeType = "NTH") do={
      unset [find chain="$chainName" new-connection-mark="$peerName"] value-name=nth};                       # remove NTH from last added line to create a Catch-all line

# Do some logging 
:if ([/sys scr env get [find name="$shortName"] value-name=value] = 99)  do={:log info "New IKEv2 distributionlist chain named $chainName buid\
 in /ip firewall mangle based on your selected active IKEv2 connections"};
:if ([/sys scr env get [find name="$shortName"] value-name=value] != 99) do={:log info "Current IKEv2 distributionlist chain named $chainName rebuid\
 in /ip firewall mangle based on your selected active IKEv2 connections"};
}; # End of [if do] 
[:parse "global $shortName $localNew"]; # Save current number of IKEv2 connection for the next run 
Last edited by msatter on Thu Mar 26, 2020 3:25 pm, edited 3 times in total.
Two RB760iGS (hEX S) in series. One does PPPoE and both do IKEv2.
Running:
RouterOS 6.47.beta.x / Winbox 3.21 / MikroTik APP 1.3.12
NordVPN viewtopic.php?f=2&t=158439&p=781009 for multiple connections.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 1459
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Keep IKEv2 connections running [ script ]

Wed Mar 25, 2020 10:56 pm

When using IKEv2 connection to a VPN provider Mikrotik inserts dynamic src-address lines at the top of the NAT table. If you are directing traffic to it those dynamic lines can still be in the buildup phase and so leak traffic. This added line is insert after the dynamic lines at the top atleast if you have the name-part "VPN" or "IKEV" in the dynamic lines. If the Blackhole comment text is not present then the line is created. I put this in scheduler and have it executed on startup with repeat time set to zero so it only runs once.
# Insert a block to leak IKEv2 traffic when the Dynamic "ipsec mode-config" are not yet in place. 
/ip firewall nat
:local commentBlackhole "Catches traffic when IKEV is inactive";
:if ([find comment=$commentBlackhole]) do={} else={
   :local localNew "$[:len [ find connection-mark~("VPN|IKEV")]]";
   add place-before="$localNew" action=src-nat chain=srcnat comment="$commentBlackhole" connection-mark=!no-mark log=yes log-prefix=blackhole to-addresses=127.0.0.1;
:log info "IKEv2 blackhole in /ip firewall nat inserted";
};
Two RB760iGS (hEX S) in series. One does PPPoE and both do IKEv2.
Running:
RouterOS 6.47.beta.x / Winbox 3.21 / MikroTik APP 1.3.12
NordVPN viewtopic.php?f=2&t=158439&p=781009 for multiple connections.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 1459
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Keep IKEv2 connections running [ script ]

Sat Mar 28, 2020 3:59 pm

And I have not included the option to use also a KILL SWITCH in case you IKEv2 connections are not up. You will need to kill it in NAT and this is the script for that:
viewtopic.php?f=2&t=158439&p=782424#p781870

# Free to use. Created by Blacklister 20200328-2.5
# Traffic distributor based on dynamicly generated based on active IKEv2 connections
# IKEv2 distributor creater that can jumped to and all lines have not passthrough when setting the connection-mark
# This will create distribution based on PCC-sourceport or NTH and it change the last in the list to a catch-all
# ChainName can be set to the desired name
# Naming of the IKEv2  connections must contain the the lettergroup VPN and have per provider a unique naming like:
# NordVPN-1 NordVPN-2 or MikrotikVPN-1 NordVPN-1 NordVPN-2


:local   chainName              "NordVPN";   # Name of the chain
:local   distributeType         "PCC";       # Change to PCC or NTH
:local   peerNamePart           "(VPN)";     # RegEX (regular expression) Contains the unique namepart(s) or just "VPN" to only select all the active ones. Format "(xyx|zxy)"
:local   varName                "Local";
:local   shortName              ($varName."prevCount") ; # Used for creating :global variable. Do not edit!
:local   killSwitch             true;        # Kill switch for IKEv2 connections. actve = true and not active = false

/ip firewall mangle;                         # Change to default location to run commands easier
# Check if :global DNSpreviousCount exists, if not create Global with value 99
:if ([/system script environment find name=$shortName]) do={} else={[:parse "global $shortName 99"];};
:local localNew "$[:len [/ip ipsec policy find peer~$peerNamePart]]"; # Count number of selected active IKEv2 connections
:if ($localNew != 0)  do={                   # if localNew is not 0 then there are active IKEv2 connections
# Check if the distributor chain has to be renewed or even be created
:if (($localNew != [/sys scr env get [find name="$shortName"] value-name=value]) or ("$[:len [/ip fire man find chain=$chainName ]]")=0) do={
    :do { remove [find chain="$chainName"] } on-error={};
    :local linePCC 0; :local lineNTH $localNew; :global peerName;      # Counter for PCC/NTH and define global variable peerName
   :foreach lineID in=[/ip ipsec policy find peer~$peerNamePart] do={  # Loop through the names of the peers using .id
     :set $peerName "$[/ip ipsec policy get value-name=peer $lineID]";

:if ($distributeType = "PCC") do={\ 
     :if ($linePCC = 0) do={add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no per-connection-classifier=("both-addresses-and-ports:"."$localNew"."/"."$linePCC") comment="Start of the distributor for IKEv2 chain: $chainName"}\
       else={ add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no per-connection-classifier=("both-addresses-and-ports:"."$localNew"."/"."$linePCC")}};

:if ($distributeType = "NTH") do={\ 
     :if ($lineNTH = $localNew) do={add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no nth=("$lineNTH".","."1")  comment="Start of the distributor for IKEv2 chain: $chainName"}\
       else={ add action=mark-connection chain="$chainName" new-connection-mark=$peerName passthrough=no nth=("$lineNTH".","."1")}};

    :set $linePCC ($linePCC +1); :set $lineNTH ($lineNTH -1);          # Increase the counter by one
    };                                        # foreach
    :if ($distributeType = "PCC") do={
       unset [find chain="$chainName" new-connection-mark="$peerName"] value-name=per-connection-classifier}; # remove PPC from last added line to create a Catch-all line
    :if ($distributeType = "NTH") do={
       unset [find chain="$chainName" new-connection-mark="$peerName"] value-name=nth};                       # remove NTH from last added line to create a Catch-all line

:if ([/sys scr env get [find name="$shortName"] value-name=value] = 99)  do={:log info "New IKEv2 distributionlist chain named $chainName build in /ip firewall mangle based on your selected active IKEv2 connections"};
:if ([/sys scr env get [find name="$shortName"] value-name=value] != 99) do={:log info "Current IKEv2 distributionlist chain named $chainName rebuild in /ip firewall mangle based on your selected active IKEv2 connections"};

};                                            # if do localNew !={.......
};                                            # if do localNew != 0

:if ($localNew = 0 and $killSwitch)  do={     # do nothing if the killSwitch = false and so letting through traffic unencrypted
    :do { remove [find chain="$chainName"] } on-error={};
    # Create a Catch-all line in case there are not active IKEv2 connections
    add chain="$chainName" action=mark-connection passthrough=no new-connection-mark="NoActiveIKEv2" comment="W A R N  I N G  - IKEv2 distributor: $chainName NOT ACTIVE! ";  
    :log warning "K I L L  S W I T C H - For IKEv2 chain $chainName. No (selected) active IKEv2 connections found. ";
};

:if ($localNew = 0 and !$killSwitch)  do={
    :do { remove [find chain="$chainName"] } on-error={};
    # Warning that the Kill Switch is disabled and there are no active IKEv2 connections
    :log warning "U N E N C T Y P T E D  T R A F F I C - For IKEv2 chain $chainName. No active IKEv2 selected connections found. (Kill Switch = off)"};   

[:parse "global $shortName $localNew"];      # Save current number of IKEv2 connection for the next run number of IKEv2 connection for the next run
Two RB760iGS (hEX S) in series. One does PPPoE and both do IKEv2.
Running:
RouterOS 6.47.beta.x / Winbox 3.21 / MikroTik APP 1.3.12
NordVPN viewtopic.php?f=2&t=158439&p=781009 for multiple connections.

Who is online

Users browsing this forum: BartoszP, erlinden, MSN [Bot], sindy, vasilevkirill and 161 guests