IPSec VPN connection between MikroTik and Kerio Control



Initial parameters:

  1. The head office of the enterprise with two border proxies is Kerio Control v.9.2.9 build 3171 (there is a Cisco 3550 switch for Kerio, which defines the configuration of the local office network).
  2. Each Kerio has two channels with load balancing up to ISP (ISP # 1 and ISP # 2 in the diagram) with static white IP.
  3. From the remote office, MikroTik 951G-2HnD is installed (OS v.6.43.11).
  4. Two ISPs come to MikroTik (ISP # 3 and ISP # 4 in the diagram).

At the time of this writing, the connection to the providers in the head office and in the remote office was over twisted pair.

Task list:


  1. Establish an IPSec VPN connection between MikroTik and Kerio Control, where MikroTik will be the initiator.
  2. Provide fault tolerance for the VPN connection, i.e. Besides the fact that MikroTik should monitor the performance of its ISPs (article here ), it should also monitor the availability of each Kerio server and determine which channel access (through which ISP from Kerio side) the connection will be made.
  3. Provide the ability to change the network address with which MikroTik connects to Kerio. This is due to the fact that Kerio, and not a router, is located at the head office.


What we get at the output?


  1. When MikroTik (scheduleStartup) is launched, a channel will be organized to the enterprise network (MikroTik will initiate the channel organization), allowing the remote user to work with corporate resources without launching Kerio Client and setting up an additional VPN connection using the operating system tools;
  2. MikroTik will implement a failover that allows you to automatically switch to a “live” ISP;
  3. You will be able to set priorities for points of connection to the enterprise network by changing in MikroTik the identity of peers configured to connect to Kerio Control to one or another Policy Template Group;
  4. MikroTik will be able to automatically monitor the performance of Kerio Control servers, and, if the connection with the priority point is broken, independently switch to the “live” channel;
  5. If your Kerio Control servers are published on external DNS servers, MikroTik will be able to track changes in their IP addresses (for example, if you change the provider) and independently make changes to your configuration (scriptSetIPSecSADstAddrFromDNS).


I’ll just make a reservation that this article is not a tutorial (in principle, with routers, and I got to know MikroTik in particular just two months (end of 2017) before starting to create a configuration) and it doesn’t address the question “why?” describes the working configuration of MikroTik, which is used in a real enterprise.

Note:
  1. So that when you transfer the script code to MikroTik, Russian-language comments are saved before copying the text to the buffer and before pasting from the buffer, make sure that the Russian keyboard layout is turned on;
  2. If you think that logging the operation of scripts is unnecessary, you can comment out or delete lines with “log warning” and “log error”;
  3. You may also notice the commented “log warning” and “log error” in the code, this is an attempt to add the ability to use logging in English ...


So let's get started:

Basic parameters:

  1. Network of the parent organization (for Kerio) - 192.168.77.0/24 (here we use the address of the network where Kerio is located in the enterprise network)
  2. The branch network (for MikroTik) - 192.168.11.0/24
  3. The network to which the branch network will be mapped when connected to Kerio Control # 1 - 192.168.22.0/24
  4. Network in which the branch network will be mapped when connected to Kerio Control # 2 - 192.168.33.0/24
  5. IP address from ISP pool # 1 (Kerio # 1) - 11/11/1111
  6. IP address from ISP pool # 2 (Kerio # 1) - 22.22.22.111
  7. IP address from ISP pool # 1 (Kerio # 2) - 11/11/1122
  8. IP address from ISP pool # 2 (Kerio # 2) - 22.22.22.222
  9. IP address from ISP pool # 3 (MikroTik) - 33.33.33.111
  10. IP address from ISP pool # 4 (MikroTik) - 44.44.44.111

The first thing to do is enable DDNS on MikroTik:

/ip cloud
set ddns-enabled=yes

Due to the fact that MikroTik will not have a static white IP-address, the further work of the configuration and scripts is based on the use of DDNS.

Also IP ---> Cloud is used to determine the external IP address of MikroTik, from which it looks to the Internet.

Now we’ll configure Kerio Control # 1 so that we don’t have to come back to it:
Go to the "Interfaces" section and add a new interface "VPN tunnel" ...

Tuning Tunnels in Kerio Control
1. В поле имя присваиваем имя интерфейсу;
2. Ставим переключатель в положение «Пассивное — только принимает входящие подключения»;
3. Тип оставляем «IPSec»;
4. Закладка «Аутентификация»:

  • 4.1 В поле «Предопределённый ключ:» вводим ключевую фразу, которая будет использована для соединения;
  • Примечание:

    Категорически рекомендую на все VPN-туннели, создаваемые на одном конкретном сервере Kerio, задавать разные ключевые фразы!

    Обусловлено это тем, что замечено, что у Kerio присутствует плавающий баг, который выражается в следующем.

    Представим, что в конфигурации Kerio, как в моём случае, присутствует несколько интерфейсов «VPN-туннель», настроенных на соединение с MikroTik, которые отличаются друг от друга только настройками в поле «Локальный ИД:» (будут рассмотрены ниже).

    Так вот, при создании (назову его так) входящего туннеля, вне зависимости от того, на какой внешний IP-адрес Kerio будет обращаться MikroTik, Kerio (почему-то) активирует первый попавшийся интерфейс, и, если IP-адрес, указанный в настройках туннеля со стороны Kerio, отличается от того, на который обращается MikroTik, туннель не организуется.

    А в случае, когда для всех туннелей указаны разные ключевые фразы, это проблема купируется.
  • 4.2 В поле «Локальный ИД:» вводим IP-адрес из пула адресов ISP #1 (в примере — 11.11.11.111), присвоенных WAN-интерфейсу Kerio Control #1, на который будет обращаться MikroTik;
  • 4.3 В поле «Отдалённый ИД:» вводим FQDN, который был получен нашим MikroTik из DDNS (IP ---> Cloud ---> DNS Name). Эта настройка позволяет нам не заботиться о том, через какого ISP MikroTik обращается к Kerio;
  • 4.4 В поле «Шифр фазы 1 (IKE):» выбираем из списка aes128-sha1-modp2048;
  • 4.5 В поле «Шифр фазы 2 (ESP):» выбираем из списка 3des-sha1-modp2048;
  • Примечание:
    Редактирование используемых настроек по умолчанию через кнопку «Изменить...»;
    Оба шифра подобраны «методом научного тыка».

5. Закладка «Удалённые сети»:

Здесь мы вводим IP-адрес локальной сети, который будет использовать MikroTik при подключении к этому конкретному серверу Kerio Control (в примере — 192.168.22.0/24).
Важно! Во всех остальных (в моём случае определяется количеством ISP со стороны Kerio) туннелях на MikroTik, на этом сервере Kerio, должен быть указан этот же IP-адрес!

Напомню, что это связано с необходимостью настройки маршрута на эту сеть из сети головного офиса.

6. Закладка «Локальные сети»:

  • 6.1 Снимаем флажок «Использовать автоматически определённые локальные сети»;
  • 6.2 Устанавливаем флажок «Использовать пользовательские сети:», а в список сетей добавляем адрес сети «накрывающий» весь диапазон адресов, используемых в локальной сети за Kerio Control (в примере — 192.168.0.0/16).

Повторяем все вышеуказанные действия для второго туннеля на этом же сервере Kerio.

Отличаться настройка второго туннеля будет только использованием другой ключевой фразы (п.4.1) и другого внешнего IP-адреса, из пула адресов ISP #2 (п.4.2) (в примере — 22.22.22.111).

Настройки Kerio Control #2 идентичны вышеописанным, за исключением адреса сети, указываемого на закладке «Удалённые сети» (п.5) (в примере — 192.168.33.0/24) и, соответственно, IP-адресов в поле «Локальный ИД:» (п.4.2), которые должны быть выбраны из IP-адресов присвоенных WAN-интерфейсам Kerio Control #2 (в примере — 11.11.11.222 и 22.22.22.222).

Next, create a permissive rule for pinging our Kerio by MikroTik ...

Kerio Control ping rule
Заходим в раздел «Правила трафика» и создаём новое правило со следующими параметрами:

  • источник — указываем FQDN, который был получен нашим MikroTik из DDNS;
  • назначение — Брандмауэр;
  • служба — Ping;
  • также можно указать версию IP (IPv4), но это не обязательно.

Сохраняем правило с понятным для вас именем и «перетаскиваем» его в самый верх списка правил.

Эту же процедуру повторяем на втором Kerio-сервере.

We do not forget to register routes on the network for MikroTik in switches or routers on the side of the head office, so that the network of the head office knows where to send traffic (in my case these are two static routes on the network 192.168.22.0/24 and 192.168.33.0/24).

From the side of the head office, we did everything, now we are moving to MikroTik.

Let's start with creating basic configuration objects for organizing and testing a VPN tunnel.

First create the Local subnet address list. We will use it in the Firewall rules.

/ip firewall address-list
# адрес основной локальной сети за MikroTik,
# IP-адреса из которой он раздаёт через DHCP
add address=192.168.11.0/24 list="Local subnet"
# адрес сети, в которую будет мапиться основная локальная сеть MikroTik
# при организации VPN-туннеля с Kerio Control #1
# (мы её определили когда настраивали VPN-интерфейсы на Kerio Control #1,
# на закладке "Удалённые сети")
add address=192.168.22.0/24 list="Local subnet"
# адрес сети, в которую будет мапиться основная локальная сеть MikroTik
# при организации VPN-туннеля с Kerio Control #2
# (мы её определили когда настраивали VPN-интерфейсы на Kerio Control #2,
# на закладке "Удалённые сети")
add address=192.168.33.0/24 list="Local subnet"

Next, create an allow rule for IKE traffic and place it at the very top of the list of rules.

add action=accept chain=input comment="VPN Allow IKE" dst-port=500 protocol=udp

Then add two rules to the Firewall Filter for working with VPN traffic ...

/ip firewall filter
add action=accept chain=forward comment="VPN In IpSec" dst-address-list=\
	"Local subnet" ipsec-policy=in,ipsec src-address=192.168.0.0/16 \
	src-address-list="!Local subnet"
add action=accept chain=forward comment="VPN Out" dst-address=192.168.0.0/16 \
	dst-address-list="!Local subnet" src-address-list="Local subnet"

... and move them to the position immediately above the drop-rule , which prohibits incoming traffic from outside the LAN. In my default configuration, it was with the comment “defconf: drop all not coming from LAN”.

Go to the Firewall Mangle and create the following rules:

/ip firewall mangle
# перехватываем входящий трафик из головного офиса,
# маркируем соединение...
add action=mark-connection chain=prerouting comment="VPN In" \
	new-connection-mark=VPN_conn_in passthrough=no src-address=192.168.0.0/16 \
	src-address-list="!Local subnet"
# ...и обратный маршрут
add action=mark-routing chain=output comment="VPN In" connection-mark=\
	VPN_conn_in new-routing-mark=VPN_route_in passthrough=yes
# перехватываем исходящий трафик с MikroTik в головной офис и маркируем соединение.
# Этот маркер используется в NAT.
add action=mark-connection chain=postrouting comment="VPN Out" dst-address=\
	192.168.0.0/16 dst-address-list="!Local subnet" new-connection-mark=\
	VPN_conn_out passthrough=no

Next, we note in the Firewall NAT:

/ip firewall nat
# мапим весь исходящий с MikroTik в головной офис трафик
# по маркеру соединения на адрес сети,
# определённый для используемого Kerio-сервера (напоминаю: для Kerio Control #1 - 192.168.22.0/24, для Kerio Control #2 - 192.168.33.0/24)
# Внимание!
# comment=KerioVpnNatOut используется в скриптах!
add action=netmap chain=srcnat comment=KerioVpnNatOut connection-mark=\
	VPN_conn_out to-addresses=192.168.22.0/24
# мапим весь входящий на MikroTik из головного офиса трафик
# по маркеру соединения на адрес основной локальной сети за MikroTik
add action=netmap chain=dstnat comment=KerioVpnNatIn connection-mark=\
	VPN_conn_in to-addresses=192.168.11.0/24
# разрешаем MikroTik пинговать Kerio-сервера
add action=accept chain=srcnat comment=KerioVpnNatPing out-interface-list=WAN protocol=icmp

Important! These rules should be placed above the masquerading rule.

Now go to the IP ---> IPSec section, where we will need to create a policy, peer, policy template groups (I’ll tell you about their purpose later) and the proposal to set up the Phase 2 cipher.

ip ipsec proposal
/ip ipsec proposal
add enc-algorithms=3des name=KerioVPNProposal#01 pfs-group=modp2048


ip ipsec policy group
/ip ipsec policy group
add name=1
add name=2
add name=3
add name=4


ip ipsec peer
/ip ipsec peer
add address=11.11.11.111/32 comment=vs01-i01-01.domain.ru exchange-mode=\
	main-l2tp local-address=33.33.33.111 my-id=\
	fqdn:mikrotik.sn.mynetname.net policy-template-group=1 profile=\
	profile_4 secret=pass1111


ip ipsec policy
/ip ipsec policy
add comment=KerioVPNPolicy dst-address=192.168.77.0/24 proposal=KerioVPNProposal#01 \
	sa-dst-address=11.11.11.111 sa-src-address=33.33.33.111 src-address=\
	192.168.22.0/24 tunnel=yes


Comment:

1. / ip ipsec proposal — enter the same encryption parameters that we specified when setting up Kerio Control in the Phase 2 Cipher (ESP): field.

Note:

Pay attention to the parameter "name = KerioVPNProposal # 01".

It is not necessary to use this particular name, but if you decide to use another, after changing it, you need to check and, if necessary, change the setting of the associated IPSec policy, and also change the assigned value of the DefKerioPropName variable in the script scriptCheckActiveVpnServer, about which Speech further.

(Actually, most of the names and comments of objects in the described configuration are used in scripts, so renaming them can give you some inconvenience due to the need to make changes to the script code. I will try to make appropriate notes in the text to facilitate the search for such objects.)

2. / ip ipsec policy group

Creating groups is due to the fact that in the future we will handle their names (1, 2, ... n) in the scripts and used to determine the priority of Kerio server IP-address, to which we will With reference sya.

I create four groups at once. I have two ISPs, with two external IPs on each side of Kerio. At this stage, we currently use only one group.

3. / ip ipsec peer

In the peer we specify:

  • Address — The Kerio IP address to which MikroTik will be accessed. The same address that we entered in the / ip ipsec policy sa-dst-address must be specified, only with the mask "/ 32";
  • Local Address - the MikroTik IP address from which Kerio will be accessed. The same address that we entered into the ip ipsec policy sa-src-address must be specified;
  • Auth. Method - choose from the list “pre shared key”;
  • Exchange Mode - choose from the list main-l2tp;
  • If checked, uncheck the “Passive” box;
  • Secret - enter the password phrase that we entered when we configured the VPN interface on Kerio, on the “Authentication” tab, in the “Predefined key:” field;
  • Policy Template Group - choose from the list the group we created earlier with the name "1";
  • Remove the NAT Traversal check box;
  • My ID Type - select the value “fqdn” from the list;
  • My ID - enter the FQDN assigned to MikroTik in the DDNS;
  • On the “Encryption” tab, select the encryption parameters that we entered when we configured the VPN interface on Kerio, on the “Authentication” tab, in the “Phase 1 (IKE) Code:” ”field;
  • Comment ( Attention! Used in scripts! ).

In the comments, I indicate the full technical FQDN of my servers, which are published on the DNS servers serving my external zone.

In addition to using this configuration, it allows me to keep up to date information about the used external IP addresses of Kerio servers (it is enough for me to change the IP address on an external DNS server and it will be automatically changed to MikroTik (article here )).

For those who are too lazy to understand I quote the working code:

/system script
add dont-require-permissions=no name=scriptSetIPSecSADstAddrFromDNS owner=\
	admin policy=read,write

Script listing scriptSetIPSecSADstAddrFromDNS
:if ([:len [/system script job find script=SetIPSecSADstAddrFromDNS]]>1) do={
  :error
}
:local DnsNameFromComment
:local ResolvedIpFromComment
:local ResolvedIpWithMaskFromComment
:local IpPeerAddr
:foreach IpSecPeerCount in=[/ip ipsec peer find] do={
	:set DnsNameFromComment [/ip ipsec peer get $IpSecPeerCount comment]
	:if ($DnsNameFromComment!="") do={
		:do {
			:set ResolvedIpFromComment [:resolve $DnsNameFromComment]
			:set ResolvedIpWithMaskFromComment ($ResolvedIpFromComment . "/32")
			:set IpPeerAddr [/ip ipsec peer get $IpSecPeerCount address]
			:if ($ResolvedIpWithMaskFromComment!=$IpPeerAddr) do={
				:log warning ("[SetIPSecSADstAddrFromDNS] В пире на сервер " . DnsNameFromComment . " изменён IP-адрес с " . $IpPeerAddr . " на " . $ResolvedIpFromComment)
				#:log warning ("[SetIPSecSADstAddrFromDNS] In the peer to the server " . DnsNameFromComment . " changed IP address from " . $IpPeerAddr . " on " . $ResolvedIpFromComment)
				/ip ipsec peer set $IpSecPeerCount address=$ResolvedIpWithMaskFromComment
			}
		} on-error={
			:set ResolvedIpFromComment "unknown"
			:log error ("[SetIPSecSADstAddrFromDNS] Не удалось разрешить имя " . $DnsNameFromComment)
			#:log error ("[SetIPSecSADstAddrFromDNS] Cant resolve name " . $DnsNameFromComment)
		}
	}
}
:log warning ("[SetIPSecSADstAddrFromDNS] Проверка IP-адресов VPN-серверов произведена")
#:log warning ("[SetIPSecSADstAddrFromDNS] The IP-addresses of the VPN-servers are checked")


The basic rule that applies to comments in peers is that the name must begin with any letters and / or numbers, without spaces, followed by a hyphen (“-”), after which any number of arbitrary characters may appear.

I use the following format:

vsNN-pNN-NN.domain.ru

Where:

vsNN - vpn-server #NN (This part of the comment is processed in scripts and used in IP ---> Firewall ---> Address Lists (see below) );
pNN - ISP #NN;
NN - the sequence number of the external IP address in the pool of addresses given to me by the Kerio provider;

4. / ip ipsec policy

The policy defines:

  • Dst. Address - network address for Kerio (dst-address);
  • Src. Address - the network address to which MikroTik will mask (see the following IP configuration ---> Firewall ---> NAT) its local network (src-address). This network address will be visible from Kerio (we indicated it when we configured the VPN interface on Kerio, on the “Remote networks” tab);
  • Protocol - 255 (all);
  • Action - encrypt;
  • Level - require;
  • IPSec Protocols - esp;
  • set the parameter tunnel = yes;
  • SA Src. Address - The external IP address of MikroTik from which Kerio will be contacted (sa-src-address);
  • SA Dst. Address - the Kerio IP address to which MikroTik will be accessed (sa-dst-address);
  • Proposal - Enter the value assigned to the name parameter in the / ip ipsec proposal section (in this configuration, KerioVPNProposal # 01);
  • Comment ( Warning! Used in scripts! ) - KerioVPNPolicy.

If everything is done correctly, then after saving the policy, the value “established” should appear in the “PH2 State” field, indicating that a VPN channel has been established between MikroTik and Kerio.
You can verify this by checking the status of the VPN interface in Kerio Control. There, in the “Information” field, opposite the interface to which the connection was made, the message “Connection to your_MicroTik IP_address_ is established” should appear.

Continuing ...

Now let's create peers for all remaining IP addresses of Kerio servers (in my configuration, we need to create three more peers).

To do this, we need to repeat all the actions specified in paragraph 3 (/ ip ipsec peer), but pay attention to the following changes:

  • Address - change the IP address of Kerio;
  • Secret - enter the password phrase related to the connection being created (pass2222, pass3333, ... passNNNN);
  • Policy Template Group - choose from the list the next in order group (2, 3, ... n).

Note:

Then you can at any time change the priority of your servers by changing the group in the peer settings.

  • Comment - in my case, it is changed to another FQDN of the Kerio-server.

All other parameters are the same as in the first peer. Those that need to be changed are processed by scripts and you can copy them without changes so far.

The final touch of the configuration before connecting the scripts to work is to make MikroTik work as a storage of constants that we will use in the scripts ...
Add two lists to the Firewall Address Lists ( Attention! Used in the scripts! ):

/ip firewall address-list
add address=192.168.22.0/24 list=vs01
add address=192.168.33.0/24 list=vs02

we specify the addresses of the networks in them with reference to the prefixes of the names of the Kerio-servers, into which we will route outgoing VPN traffic.

Well, in order to automate the work of all this disgrace, we will add two scripts and three schedules (if you decide to rename the scripts, do not forget to make the appropriate changes to the code) .

/system script
add dont-require-permissions=no name=scriptFunctionsList owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon

Script listing scriptFunctionsList
# Процедура синхронизации IP --> Cloud с внешними DNS-серверами
# входящий параметр:
#
# $start (true/false);
#
# возвращает "" или "updated"
:global subUpdateCloudDns do={
	put ($start);
	:if ($start=false) do={
		set $CloudDnsStatus;
		# Определяем переменную для счётчика
		set $m 1;
		log warning ("[subUpdateCloudDns] ---> DDNS статус ---> ЗАПУЩЕНА ПРОВЕРКА");
		#log warning ("[subUpdateCloudDns] ---> DDNS status ---> CHECK STARTED");
		do {
			log warning ("[subUpdateCloudDns] ---> DDNS проверка, попытка ---> " . $m);
			[/ip cloud force-update];
			delay 30000ms;
			set $CloudDnsStatus ([/ip cloud get status]);
			set $m ($m+1);
			:if ($CloudDnsStatus="updated") do={
				log warning ("[subUpdateCloudDns] ---> DDNS статус ---> " . $CloudDnsStatus);
				#log warning ("[subUpdateCloudDns] ---> DDNS status ---> " . $CloudDnsStatus);
			} else={
				log error ("[subUpdateCloudDns] ---> DDNS статус ---> " . $CloudDnsStatus);
				#log error ("[subUpdateCloudDns] ---> DDNS status ---> " . $CloudDnsStatus);
			}
		} while=(($CloudDnsStatus!="updated") and ($m<10));
		return ($CloudDnsStatus);
	}
}
# Процедура проверки состояния IP --> Cloud
# возвращает код состояния:
#
# 0 - деактивировано;
# 1 - активно, но не обновлено;
# 2 - активно и обновлено
:global subCheckCloudDDNS do={
	set $CloudDnsActive ([/ip cloud get ddns-enabled]);
	# Значение по-умолчанию ( $m=0 )
	set $m 0;
	:if ($CloudDnsActive=yes) do {
		# Если IP--->Cloud активировано ( $m=1 )
		set $m ($m+1);
		set $CloudDnsStatus ([/ip cloud get status]);
		# Проверяем синхронизацию внешних IP-адресов (сохранённого в IP--->Cloud и на внешних DNS)
		set $CloudDnsIP ([/ip cloud get public-address]);
		set $CheckIpAddr ([resolve [/ip cloud get dns-name]]);
		:if ($CloudDnsIP!=$CheckIpAddr) do={
			# Если IP разные (изменилось подключение MikroTik к провайдеру)...
			set $CloudDnsStatus "updating...";
		}
		:if ($CloudDnsStatus="updated") do {
			# Если IP--->Cloud активировано и обновлено ( $m=2 )
			set $m ($m+1);
		}
	}
	return ($m);
}
# Процедура повторного вызова скрипта на выполнение
# входящий параметр:
#
# $ScriptName (имя скрипта)
:global subRepeatScript do={
	put ($ScriptName);
	:if ($ScriptName!="") do {
		[/system script run $ScriptName];
	}
}
# Процедура формирования списка внешних VPN-серверов из пиров
#
# возвращает список IP-адресов VPN-серверов с привязкой к группам
:global subGetVpnServers do={
	# Получаем группы и IP-адреса VPN-серверов из пиров и считаем общее количество пиров
	:foreach IpSecPeerId in=[/ip ipsec peer find passive!=yes] do={
		set $CheckIpAddr [/ip ipsec peer get $IpSecPeerId address];
		:if ($CheckIpAddr!="") do={
			set $MaskPos [find $CheckIpAddr "/"];
			set $GroupFromPeer ([/ip ipsec peer get $IpSecPeerId policy-template-group]);
			set $IpFromPeer ([pick $CheckIpAddr 0 $MaskPos]);
			set $VpnServersList ($VpnServersList, {{$GroupFromPeer; $IpFromPeer}});
		}
	}
	return ($VpnServersList);
}
# Процедура выключения активных пиров и связанных политик
#
# процедура возвращает список ID всех политик
:global subDisableIpSecPeers do={
	# ...выключаем все включённые, активные (passive=false) пиры...
	:foreach IpSecPeerId in=[/ip ipsec peer find passive!=yes] do={
		log warning ("[IP IPSec Peer] ---> обрабатывается пир на ---> " . [/ip ipsec peer get $IpSecPeerId comment]);
		#log warning ("[IP IPSec Peer] ---> processed peer on ---> " . [/ip ipsec peer get $IpSecPeerId comment]);
		# Получаем address из текущего пира...
		set $CheckIpAddr [/ip ipsec peer get $IpSecPeerId address];
		:if ($CheckIpAddr!="") do={
			# Если address не пустой, отрезаем IP-адрес от маски...
			set $MaskPos ([find $CheckIpAddr "/"]);
			set $CheckIpAddr ([pick $CheckIpAddr 0 $MaskPos]);
			# ...и выключаем связанные IPSec-политики
			:foreach IpSecPolicyId in=[/ip ipsec policy find sa-dst-address=$CheckIpAddr] do={
				:if ($IpSecPolicyId!="") do={
					:if ([/ip ipsec policy get $IpSecPolicyId disabled]!=yes) do={
						[/ip ipsec policy disable $IpSecPolicyId];
						log warning ("[IP IPSec Policy] ---> политика " . [/ip ipsec policy get $IpSecPolicyId comment] . " деактивирована");
						#log warning ("[IP IPSec Policy] ---> policy " . [/ip ipsec policy get $IpSecPolicyId comment] . " deactivated");
					}
					# Заполняем массив списком ID политик для дальнейшего изменения
					set $IdList ($IdList, $IpSecPolicyId);
				}
			}
		}
		# Примечание: пиры выключаются после деактивации политик, чтобы не возникали системные ошибки
		:if ([/ip ipsec peer get $IpSecPeerId disabled]!=yes) do={
			[/ip ipsec peer disable $IpSecPeerId];
			log warning ("[IP IPSec Peer] ---> " . [/ip ipsec peer get $IpSecPeerId comment] . " ---> деактивирован");
			#log warning ("[IP IPSec Peer] ---> " . [/ip ipsec peer get $IpSecPeerId comment] . " ---> deactivated");
		}
	}
	return ($IdList);
}
# Процедура включения активных пиров и связанных политик
# входящие параметры:
#
# $PeerID (ID пира на VPN-сервер);
# $PolIdList (список ID из $subDisableIpSecPeers);
# $CloudIP (IP MikroTik из DDNS);
# $SrcIP (src-address для обращения к VPN-серверу)
:global subEnableIpSecPeers do={
	put ($PeerID);
	put ($PolIdList);
	put ($CloudIP);
	:if (($PeerID!="")&&($PeerID!=nil)&&($PolIdList!="")&&($PolIdList!=nil)&&($CloudIP!="")&&($CloudIP!=nil)) do={
		# Получаем адрес VPN-сервера
		set $ActiveVPN [/ip ipsec peer get $PeerID address];
		:if ($ActiveVPN!="") do={
			# Если найден, отрезаем IP-адрес от маски
			set $MaskPos [find $ActiveVPN "/"];
			set $ActiveVPN ([pick $ActiveVPN 0 $MaskPos]);
		}
		# Если пир выключен, делаем задержку исполнения и включаем
		:if ([/ip ipsec peer get $PeerID disabled]=yes) do={
			delay 5000ms;
			[/ip ipsec peer enable $PeerID];
			log warning ("[IP IPSec Peer] ---> активирован peer на ---> " . [/ip ipsec peer get $PeerID address]);
			#log warning ("[IP IPSec Peer] ---> activated peer on ---> " . [/ip ipsec peer get $PeerID address]);
		}
		# Ищем политики по ID из массива PolIdList, проверяем, при необходимости изменяем Src. Address, SA Src. Address и SA Dst. Address, и активируем
		:foreach IpSecPolicyId in=$PolIdList do={
			:if ($IpSecPolicyId!="") do={
				:if ([/ip ipsec policy get $IpSecPolicyId src-address]!=$SrcIP) do={
					[/ip ipsec policy set $IpSecPolicyId src-address=$SrcIP];
					log warning ("[IP IPSec Policy] ---> изменён src-address");
					#log warning ("[IP IPSec Policy] ---> src-address changed");
				}
				:if ([/ip ipsec policy get $IpSecPolicyId sa-src-address]!=$CloudIP) do={
					[/ip ipsec policy set $IpSecPolicyId sa-src-address=$CloudIP];
					log warning ("[IP IPSec Policy] ---> изменён sa-src-address");
					#log warning ("[IP IPSec Policy] ---> sa-src-address changed");
				}
				:if ([/ip ipsec policy get $IpSecPolicyId sa-dst-address]!=$ActiveVPN) do={
					[/ip ipsec policy set $IpSecPolicyId sa-dst-address=$ActiveVPN];
					log warning ("[IP IPSec Policy] ---> изменён sa-dst-address");
					#log warning ("[IP IPSec Policy] ---> sa-dst-address changed");
				}
				:if ([/ip ipsec policy get $IpSecPolicyId disabled]=yes) do={
					delay 3000ms;
					[/ip ipsec policy enable $IpSecPolicyId];
					log warning ("[IP IPSec Policy] ---> политика активирована");
					#log warning ("[IP IPSec Policy] ---> policy activated");
					# Очищаем DNS-кэш
					[/ip dns cache flush]
				}
			}
		}
	}
}
# Процедура формирования списка политик по ID пира
# входящие параметры:
#
# $PeerIP (IP из пира БЕЗ МАСКИ);
# $CloudIP (IP MikroTik из DDNS);
# $action (enable/disable/skip)
#
# процедура возвращает список ID, связанных с пиром, политик
:global subGetPoliciesByPeer do={
	put ($PeerIP);
	put ($CloudIP);
	put ($action);
	:if (($action="")||($action=nil)) do={
		set $action "skip";
	}
	:foreach IpSecPolicyId in=[/ip ipsec policy find sa-dst-address=$PeerIP] do={
		:if ($IpSecPolicyId!="") do={
			# Если политика включена И $action=disable, выключить политику
			:if (([/ip ipsec policy get $IpSecPolicyId disabled]!=yes)&&($action="disable")) do={
				[/ip ipsec policy disable $IpSecPolicyId];
				log warning ("[IP IPSec Policy] ---> политика деактивирована");
				#log warning ("[IP IPSec Policy] ---> policy deactivated");
			}
			# Если получен не пустой $CloudIP И sa-src-address!=$CloudIP (изменился ISP), выключить политику и изменить sa-src-address
			:if (($CloudIP!="")&&($CloudIP!=nil)&&([/ip ipsec policy get $IpSecPolicyId sa-src-address]!=$CloudIP)) do={
				[/ip ipsec policy disable $IpSecPolicyId];
				[/ip ipsec policy set $IpSecPolicyId sa-src-address=$CloudIP];
				log warning ("[IP IPSec Policy] ---> политика деактивирована ---> новый sa-src-address ---> " . $CloudIP);
				#log warning ("[IP IPSec Policy] ---> policy deactivated ---> new sa-src-address ---> " . $CloudIP);
				# Делаем задержку исполнения, чтобы Kerio разорвал канал
				delay 30000ms;
			}
			# Если политика выключена И $action=enable, включить политику
			:if (([/ip ipsec policy get $IpSecPolicyId disabled]=yes)&&($action="enable")) do={
				[/ip ipsec policy enable $IpSecPolicyId];
				log warning ("[IP IPSec Policy] ---> политика активирована");
				#log warning ("[IP IPSec Policy] ---> policy activated");
				# Очищаем DNS-кэш
				[/ip dns cache flush]
			}
			# Заполняем массив списком ID политик для дальнейшего изменения
			set $IdList ($IdList, $IpSecPolicyId);
		}
	}
	return ($IdList);
}
# Процедура проверки local-address пира
# входящие параметры:
#
# $PeerID (ID пира на VPN-сервер);
# $CloudIP (IP MikroTik из DDNS)
:global subCheckPeerLocalIp do={
	put ($PeerID);
	put ($CloudIP);
	:if (($PeerID!="")&&($PeerID!=nil)&&($CloudIP!="")&&($CloudIP!=nil)) do={
		# Проверяем изменение DDNS-IP
		:if ([/ip ipsec peer get $PeerID local-address]!=$CloudIP) do={
			[/ip ipsec peer set $PeerID local-address=$CloudIP];
			log warning ("[IP IPSec Peer] ---> изменён local-address");
			#log warning ("[IP IPSec Peer] ---> local-address changed");
		}
	}
}


/system script
add dont-require-permissions=no name=scriptCheckActiveVpnServer owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon

Script listing scriptCheckActiveVpnServer
:if ([:len [/system script job find script=scriptCheckActiveVpnServer]]>1) do={
	:error
}
# Библиотеку процедур инициализируем в скрипте scheduleStartup
# и объявляем процедуры, которые будут использованы в этом скрипте
:global subCheckCloudDDNS
:global subCheckPeerLocalIp
:global subDisableIpSecPeers
:global subEnableIpSecPeers
:global subGetPoliciesByPeer
:global subGetVpnServers
:global subUpdateCloudDns
:local CheckIP
:local CheckPeer
# Заполняем переменную статусом активации DDNS (внешняя процедура)
:local CloudDnsStatus ([:put [$subCheckCloudDDNS]])
:local Exit false
:local DefMikroTikSrcNet 192.168.11.0/24
:local DefKerioDstNet 192.168.77.0/24
:local DefKerioPropName KerioVPNProposal#01
:local DefKerioPolName KerioVPNPolicy
:local IpSecPolicyId
:local KerioName
:local KerioVpnNatRuleName KerioVpnNatOut
:local m
:local n 1
:local PeerCount 0
:local PeerDisabled
:local PingCount 3
:local PingResult
:local PoliciesList
:local PublicIp
:local VpnServersList
# Проверяем активацию DDNS и, если активирован, считываем активный внешний IP-адрес MikroTik
:if ($CloudDnsStatus=0) do={
	# Если Cloud DDNS не активно, записываем сообщение в журнал и выходим из скрипта
	:log error ("[schedule CheckActiveVpnServer] ---> для подключения к VPN-серверу требуется активировать Cloud DDNS! (IP -> Cloud)")
#	:log error ("[schedule CheckActiveVpnServer] ---> to connect to the VPN server, you need to activate Cloud DDNS! (IP -> Cloud)")
	:error
}
:if ($CloudDnsStatus=1) do={
	# Если Cloud DDNS активно, но не обновлено, запускаем обновление (внешняя процедура)
	:set CloudDnsStatus [:put [$subUpdateCloudDns start=false]]
	:if ($CloudDnsStatus="updated") do={
		:set CloudDnsStatus 2
	}
}
:if ($CloudDnsStatus=2) do {
	# Если Cloud DDNS активно и обновлено ...
	# Получаем IP из DDNS
	:set PublicIp [/ip cloud get public-address]
	# Получаем список VPN-серверов с группами, определяющими приоритет подключения (внешняя процедура)
	:set VpnServersList ([:put [$subGetVpnServers]])
	# Считаем общее количество пиров
	:foreach VpnIpId in=$VpnServersList do={
		:set PeerCount ($PeerCount+1)
	} 
	# Ищем активный VPN-сервер пингом с внешнего DDNS-IP (для этого, на стороне VPN-сервера необходимо создать разрешающее правило)
	:while (($Exit!=true)&&$n<=$PeerCount) do={
		:foreach VpnIpId in=$VpnServersList do={
			# Перебираем IP-адреса VPN-серверов с учётом приоритета
			:if (($VpnIpId->0)=$n) do={
				:set CheckIP ($VpnIpId->1)
				:if ($CheckIP!="") do={
					# Проверяем доступность найденного IP
					:set PingResult ([:put [/ping address=$CheckIP count=$PingCount src-address=$PublicIp]])
					:if ($PingResult=$PingCount) do={
						:log warning ("[schedule CheckActiveVpnServer] ---> DDNS-IP ---> " . $PublicIp . " ---> VPN-IP ---> " . $CheckIP . " ---> Ping Result ---> " . $PingResult)
						# Если IP доступен, ищем пир на этот IP-адрес
						:set CheckPeer (:put [/ip ipsec peer find address=($CheckIP . "/32")])
						:if ($CheckPeer!="") do={
							# Если пир найден, проверяем наличие в конфигурации src-адреса (IP ---> Firewall ---> Address Lists), использующегося для соединения с Kerio
							# Получаем имя сервера Kerio из комментария пира
							:set KerioName [/ip ipsec peer get $CheckPeer comment]
							# Обрабатываем полученное имя (ИЗМЕНИТЬ АЛГОРИТМ обработки, если FQDN сервера Kerio отличается от KerioName-Parameter1-...-Parameter_n
							:if ($KerioName!="") do={
								# Находим первый дефис
								:set m ([find $KerioName "-"])
								# Отрезаем KerioName от всего остального
								:set KerioName ([pick $KerioName 0 $m])
								# Ищем адрес в Firewall -> Address List (соответственно там должны быть необходимые записи в формате:
								# Name ---> KerioName (eg srv1)
								# Address ---> DefMikroTikSrcNet (eg 192.168.99.0/24))
								:set m [/ip firewall address-list find list=$KerioName]
								:set DefMikroTikSrcNet ([/ip firewall address-list get $m address])
							}
							# ... проверяем наличие в конфигурации политик настроенных на соединение с Kerio
							:set IpSecPolicyId (:put [/ip ipsec policy find comment="$DefKerioPolName"])
							# Если ни одной политики не найдено, создаём политику с настройками по умолчанию
							# (задаются в разделе объявления переменных) и размещаем её в самом верху списка политик
							:if ($IpSecPolicyId="") do={
								[/ip ipsec policy add disabled=yes dst-address=$DefKerioDstNet proposal=$DefKerioPropName sa-dst-address=$CheckIP sa-src-address=$PublicIp src-address=$DefMikroTikSrcNet tunnel=yes comment=$DefKerioPolName place-before=0]
								:log warning ("[schedule CheckActiveVpnServer] ---> создана политика " . $DefKerioPolName . " ---> использованы параметры по умолчанию")
								#:log warning ("[schedule CheckActiveVpnServer] ---> created policy " . $DefKerioPolName . " ---> default parameters used")
							} else={
								# Если политика есть, проверяем указанный в ней src-address, при необходимости меняем.
								:if ($DefMikroTikSrcNet!=[/ip ipsec policy get $IpSecPolicyId src-address]) do={
									[/ip ipsec policy set $IpSecPolicyId src-address=$DefMikroTikSrcNet];
									:log warning ("[schedule CheckActiveVpnServer] ---> политика " . $DefKerioPolName . " изменена ---> src-address изменён на ---> " . $DefMikroTikSrcNet)
									#:log warning ("[schedule CheckActiveVpnServer] ---> policy " . $DefKerioPolName . " changed ---> src-address changed to ---> " . $DefMikroTikSrcNet)
								}
							}
							# очищаем переменную
							:set m
							# ищем NAT-правило для мапинга исходящего в сторону Kerio трафика
							:set m [/ip firewall nat find comment=$KerioVpnNatRuleName]
							:if ($m!="") do={
								# Если изменился src-address в политике ipsec, изменяем правило мапинга исходящего в сторону Kerio трафика
								:if ([/ip firewall nat get $m to-addresses]!=$DefMikroTikSrcNet) do={
									[/ip firewall nat set $m to-addresses $DefMikroTikSrcNet]
									:log warning ("[IP Firewall NAT] ---> изменено правило мапинга ---> " . $KerioVpnNatRuleName)
									#:log warning ("[IP Firewall NAT] ---> netmap rule changed ---> " . $KerioVpnNatRuleName)
								}
							}
							# ...сравниваем local-address найденного пира с текущим внешним IP MikroTik, при необходимости изменяем (внешняя процедура)
							:put [$subCheckPeerLocalIp PeerID=$CheckPeer CloudIP=$PublicIp]
							# ...проверяем состояние найденного пира
							:set PeerDisabled ([/ip ipsec peer get $CheckPeer disabled])
							:if ($PeerDisabled=true) do={
								# Если пир выключен...
								# Выключаем все другие пиры и политики (внешняя процедура)
								:set PoliciesList ([:put [$subDisableIpSecPeers]])
								# Находим пир на активный VPN-сервер и включаем (внешняя процедура)
								:put [$subEnableIpSecPeers PeerID=$CheckPeer PolIdList=$PoliciesList CloudIP=$PublicIp SrcIP=$DefMikroTikSrcNet]
							} else={
								# Если пир включен...
								# Находим все связанные с пиром политики, проверяем и включаем (внешняя процедура)
								:set PoliciesList ([:put [$subGetPoliciesByPeer PeerIP=$CheckIP CloudIP=$PublicIp SrcIP=$DefMikroTikSrcNet action="enable"]])
							}
							:set Exit true
						}
					} else={
						:log error ("[schedule CheckActiveVpnServer] ---> DDNS-IP ---> " . $PublicIp . " ---> VPN-IP ---> " . $CheckIP . " ---> Ping Result ---> " . $PingResult)
					}
				}
			}
		}
		:set n ($n+1)
	}
}


/system scheduler
add interval=1h name=scheduleCheckIPSecSADstAddrFromDNS on-event=\
	"/system script run scriptSetIPSecSADstAddrFromDNS" policy=read,write \
	start-date=oct/30/2017 start-time=00:10:00
add name=scheduleStartup on-event=":global StartupScript true :global RepeatRun false /system script run scriptFunctionsList" policy=\
	ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
	start-time=startup
add interval=5m name=scheduleCheckActiveVpnServer on-event=\
	"/system script run scriptCheckActiveVpnServer" policy=\
	ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
	start-date=nov/29/2017 start-time=00:00:00

Schedule Listing scheduleStartup
:global StartupScript true
:global RepeatRun false
/system script run scriptFunctionsList


Schedule Listing scheduleCheckIPSecSADstAddrFromDNS
/system script run scriptSetIPSecSADstAddrFromDNS


Schedule Listing scheduleCheckActiveVpnServer
/system script run scriptCheckActiveVpnServer



The final touch:
for MikroTik to correctly address the enterprise DNS servers located behind Kerio Control, you need to add static records with their addresses in MikroTik to the IP ---> DNS ---> Static section ...

Well, that's about it!

I hope I never made a mistake and did not forget anything ...

Thank you for your attention!

ps
History of edits and changes:
  1. Added the section “What we get at the output ?:”;
  2. Added a comment to the network address of the parent company;
  3. Changed network IP addresses from ISP pools used in the configuration description;
  4. Added item "Finishing stroke:";

Also popular now: