Начальные параметры:
- Головной офис предприятия с двумя пограничными прокси Kerio Control v.9.2.9 build 3171 (за Kerio расположен свич Cisco 3550, определяющий конфигурацию локальной сети офиса).
- На каждом Kerio организовано по два канала с балансировкой нагрузки до ISP (на схеме — ISP #1 и ISP #2) со статичными белыми IP.
- Со стороны удалённого офиса установлен MikroTik 951G-2HnD (OS v.6.43.11).
- На MikroTik приходят два ISP (на схеме — ISP #3 и ISP #4).
На момент написания статьи и в головном и в удалённом офисе соединение с провайдерами было по витой паре.
Список задач:
- Организовать IPSec VPN-соединение между MikroTik и Kerio Control, где инициатором будет выступать MikroTik.
- Обеспечить отказоустойчивость VPN-соединения, т.е. кроме того, что MikroTik должен отслеживать работоспособность своих ISP(статья здесь), он также должен мониторить доступность каждого сервера Kerio и определять, доступ по какому каналу (через какого ISP со стороны Kerio) будет производиться подключение.
- Обеспечить возможность изменения адреса сети, с которым MikroTik подключается к Kerio. Это обусловлено тем, что в головном офисе «на границе» стоят Kerio, а не маршрутизатор.
Что получим на выходе?
- При запуске MikroTik (scheduleStartup) будет организован канал к сети предприятия (инициатором организации канала выступит MikroTik), позволяющий удалённому пользователю работать с корпоративными ресурсами без запуска Kerio Client и без настройки дополнительного VPN-подключения средствами операционной системы;
- В MikroTik будет реализован Failover, позволяющий автоматически переключаться на «живой» ISP;
- Вы сможете настроить приоритеты для точек подключения к сети предприятия, изменяя в MikroTik принадлежность peers, настроенных на подключение к Kerio Control, к той или иной Policy Template Group;
- MikroTik сможет в автоматическом режиме отслеживать работоспособность Kerio Control серверов, и, в случае, если связь с приоритетной точкой разорвана, самостоятельно переключиться на «живой» канал;
- Если ваши Kerio Control серверы опубликованы на внешних DNS-серверах, MikroTik сможет отслеживать изменения их IP-адресов (напр. в случае, если у вас поменяется провайдер) и самостоятельно вносить изменения в свою конфигурацию (scriptSetIPSecSADstAddrFromDNS).
Сразу оговорюсь, что эта статья не является учебным пособием (с маршрутизаторами в принципе, и с MikroTik в частности я познакомился всего за два месяца (конец 2017 года) до начала создания конфигурации) и в ней не рассматриваются вопросы «почему?», здесь будет приведено описание рабочей конфигурации MikroTik, которая используется на реальном предприятии.
Примечание:
- Чтобы при переносе кода скриптов в MikroTik сохранились русскоязычные комментарии, перед тем как скопировать текст в буфер и перед вставкой из буфера проверьте, чтобы была включена русская раскладка клавиатуры;
- Если вы посчитаете, что логирование работы скриптов — это лишнее, вы можете закомментировать или удалить строки с «log warning» и «log error»;
- Также вы можете заметить в коде закомментированные «log warning» и «log error», это попытка добавить возможность использовать логирование на английском языке...
Итак, приступим:
Базовые параметры:
- Сеть головной организации (за Kerio) — 192.168.77.0/24 (здесь используем адрес сети, в которой находится Kerio в сети предприятия)
- Сеть филиала (за MikroTik) — 192.168.11.0/24
- Сеть, в которую будет мапиться сеть филиала при подключении к Kerio Control #1 — 192.168.22.0/24
- Сеть, в которую будет мапиться сеть филиала при подключении к Kerio Control #2 — 192.168.33.0/24
- IP-адрес из пула ISP #1 (Kerio #1) — 11.11.11.111
- IP-адрес из пула ISP #2 (Kerio #1) — 22.22.22.111
- IP-адрес из пула ISP #1 (Kerio #2) — 11.11.11.222
- IP-адрес из пула ISP #2 (Kerio #2) — 22.22.22.222
- IP-адрес из пула ISP #3 (MikroTik) — 33.33.33.111
- IP-адрес из пула ISP #4 (MikroTik) — 44.44.44.111
Первое, что необходимо сделать, это включить на MikroTik использование DDNS:
/ip cloud
set ddns-enabled=yes
В связи с тем, что на MikroTik не будет статического белого IP-адреса, дальнейшая работа конфигурации и скриптов построена на использовании DDNS.
Также IP ---> Cloud используется для определения внешнего IP-адреса MikroTik, с которого он смотрит в интернет.
Теперь произведём настройку Kerio Control #1, чтобы потом к нему уже не возвращаться:
Заходим в раздел «Интерфейсы» и добавляем новый интерфейс «VPN-туннель»…
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).
Далее создаём разрешающее правило на пингование наших Kerio со стороны MikroTik…
- источник — указываем FQDN, который был получен нашим MikroTik из DDNS;
- назначение — Брандмауэр;
- служба — Ping;
- также можно указать версию IP (IPv4), но это не обязательно.
Сохраняем правило с понятным для вас именем и «перетаскиваем» его в самый верх списка правил.
Эту же процедуру повторяем на втором Kerio-сервере.
Не забываем прописать маршруты на сети за MikroTik в свичи или маршрутизаторы на стороне головного офиса, чтобы сеть головного офиса знала куда направлять трафик (в моём случае это два статических маршрута на сети 192.168.22.0/24 и 192.168.33.0/24).
Со стороны головного офиса мы всё сделали, теперь переходим к MikroTik.
Начнём с того, что создадим базовые объекты конфигурации для организации и проверки VPN-туннеля.
Первым делом создадим список адресов «Local subnet». Его мы будем использовать в правилах Firewall.
/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"
Далее создадим разрешающее правило для IKE-трафика и поместим его в самый верх списка правил.
add action=accept chain=input comment="VPN Allow IKE" dst-port=500 protocol=udp
Затем добавим два правила в Firewall Filter для работы с VPN-трафиком…
/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"
… и переместим их в позицию сразу над drop-правилом, запрещающим входящий трафик не из LAN. В моей дефолтной конфигурации оно было с комментарием «defconf: drop all not coming from LAN»
Идём в Firewall Mangle и создаём следующие правила:
/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
Далее отметимся в 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
Важно! Эти правила должны размещаться выше правила маскарадинга.
Теперь переходим в раздел IP ---> IPSec, где нам потребуется создать политику, peer, policy template groups (об их назначении я расскажу позже) и proposal для настройки шифра фазы 2.
/ip ipsec proposal
add enc-algorithms=3des name=KerioVPNProposal#01 pfs-group=modp2048
/ip ipsec policy group
add name=1
add name=2
add name=3
add name=4
/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
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
Комментарий:
1. /ip ipsec proposal — вводим те же параметры шифрования, которые были нами указаны при настройке Kerio Control, в поле «Шифр фазы 2 (ESP):».
Примечание:
Обратите внимание на параметр «name=KerioVPNProposal#01».
Использовать конкретно это имя не обязательно, но в случае, если вы решите использовать другое, то после его изменения вам необходимо проверить и, при необходимости, изменить настройку связанной IPSec-политики, а также изменить присваиваемое значение переменной DefKerioPropName в скрипте scriptCheckActiveVpnServer, о котором пойдёт речь далее.
(Собственно, большинство имен и комментариев объектов, в описываемой конфигурации, используются в скриптах, поэтому их переименование может доставить вам некоторые неудобства в связи с необходимостью внесения изменений в код скриптов. Я постараюсь далее по тексту делать соответствующие пометки для облегчения поиска таких объектов.)
2. /ip ipsec policy group
Создание групп обусловлено тем, что в дальнейшем мы будем обрабатывать их имена (1, 2, ...n) в скриптах и использовать для определения приоритетности IP-адресов серверов Kerio, к которым мы будем обращаться.
Я создаю сразу четыре группы т.к. у меня два ISP, с двумя внешними IP на каждом со стороны Kerio. На данном этапе мы пока используем только одну группу.
3. /ip ipsec peer
В peer указываем:
- Address — IP-адрес Kerio, на который будет производиться обращение с MikroTik. Должен быть указан тот же адрес, который мы ввели в /ip ipsec policy sa-dst-address, только с маской "/32";
- Local Address — IP-адрес MikroTik, с которого будет производиться обращение к Kerio. Должен быть указан тот же адрес, который мы ввели в /ip ipsec policy sa-src-address;
- Auth. Method — выбираем из списка «pre shared key»;
- Exchange Mode — выбираем из списка main-l2tp;
- Если установлен, снимаем флажок «Passive»;
- Secret — вводим парольную фразу, которую мы вводили, когда настраивали VPN-интерфейс на Kerio, на закладке «Аутентификация», в поле «Предопределённый ключ:»;
- Policy Template Group — выбираем из списка созданную ранее нами группу с именем «1»;
- Снимаем флажок NAT Traversal;
- My ID Type — выбираем из списка значение «fqdn»;
- My ID — вводим FQDN, присвоенное MikroTik в DDNS;
- На закладке «Encryption» выбираем параметры шифрования, которые мы вводили, когда настраивали VPN-интерфейс на Kerio, на закладке «Аутентификация», в поле «Шифр фазы 1 (IKE):»;
- Comment (Внимание! Используется в скриптах!).
В комментарии я указываю полный технический FQDN своих серверов, которые опубликованы на DNS-серверах, обслуживающих мою внешнюю зону.
Кроме применения в этой конфигурации, это позволяет мне поддерживать в актуальном состоянии информацию об используемых внешних IP-адресах Kerio-серверов (мне достаточно изменить IP-адрес на внешнем DNS-сервере и он будет автоматически изменён на MikroTik (статья здесь)).
Для тех, кому лень разбираться привожу рабочий код:
/system script
add dont-require-permissions=no name=scriptSetIPSecSADstAddrFromDNS owner= admin policy=read,write
: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")
Основное правило, применяемое к комментарию в peers — имя должно начинаться с любых букв и/или цифр, без пробелов, за которыми ОБЯЗАТЕЛЬНО следует дефис ("-"), после которого может располагаться любое количество произвольных символов.
Я использую следующий формат:
vsNN-pNN-NN.domain.ru
Где:
vsNN — vpn-server #NN (Эта часть комментария обрабатывается в скриптах и используется в IP ---> Firewall ---> Address Lists (см. далее));
pNN — ISP #NN;
NN — порядковый номер внешнего IP-адреса в пуле адресов, выданных мне провайдером на Kerio;
4. /ip ipsec policy
В политике определяем:
- Dst. Address — адрес сети за Kerio (dst-address);
- Src. Address — адрес сети, в который MikroTik будет маскировать (см. далее настройку IP ---> Firewall ---> NAT) свою локальную сеть (src-address). Этот адрес сети будет виден со стороны Kerio (его мы указывали, когда настраивали VPN-интерфейс на Kerio, на закладке «Удалённые сети»);
- Protocol — 255 (all);
- Action — encrypt;
- Level — require;
- IPSec Protocols — esp;
- устанавливаем параметр tunnel=yes;
- SA Src. Address — Внешний IP-адрес MikroTik, с которого будет производиться обращение к Kerio (sa-src-address);
- SA Dst. Address — IP-адрес Kerio, на который будет производиться обращение с MikroTik (sa-dst-address);
- Proposal — Вводим значение, присвоенное параметру name в разделе /ip ipsec proposal (в данной конфигурации — KerioVPNProposal#01);
- Comment (Внимание! Используется в скриптах!) — KerioVPNPolicy.
Если всё сделано правильно, то после сохранения политики, в поле «PH2 State» должно появиться значение «established», что говорит об установке VPN-канала между MikroTik и Kerio.
Убедиться в этом можно проверив состояние VPN-интерфейса в Kerio Control. Там в поле «Сведения», напротив того интерфейса, к которому произведено подключение, должна появиться надпись «Соединение с IP_адрес_вашего_MikroTik установлено».
Продолжаем…
Теперь создадим пиры на все оставшиеся у нас IP-адреса Kerio-серверов (в моей конфигурации необходимо создать ещё три пира).
Для этого нам необходимо повторить все действия указанные в п.3 (/ip ipsec peer), но обратить внимание на следующие изменения:
- Address — изменяем IP-адрес Kerio;
- Secret — вводим парольную фразу относящуюся к создаваемому соединению (pass2222, pass3333, ...passNNNN);
- Policy Template Group — выбираем из списка следующую по порядку группу (2, 3, ...n).
Примечание:
Потом вы можете в любой момент изменить приоритетность своих серверов, изменив группу в настройках пира.
- Comment — в моём случае изменяется на другой FQDN Kerio-сервера.
Все остальные параметры вводим такие же, как и в первом пире. Те, которые необходимо будет изменять, обрабатываются скриптами и вы можете пока их копировать без изменений.
Завершающий штрих конфигурирования перед подключением в работу скриптов — заставим MikroTik работать хранилищем констант, которые мы будем использовать в скриптах…
Добавим два списка в Firewall Address Lists (Внимание! Используется в скриптах!):
/ip firewall address-list
add address=192.168.22.0/24 list=vs01
add address=192.168.33.0/24 list=vs02
в них указываем адреса сетей с привязкой к префиксам имен Kerio-серверов, в которые мы будем мапить исходящий VPN-трафик.
Ну и для того, чтобы автоматизировать работу всего этого безобразия добавим два скрипта и три расписания (если решите переименовать скрипты, не забудьте внести соответствующие изменения в код).
/system script
add dont-require-permissions=no name=scriptFunctionsList owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon
# Процедура синхронизации 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
: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
:global StartupScript true
:global RepeatRun false
/system script run scriptFunctionsList
/system script run scriptSetIPSecSADstAddrFromDNS
/system script run scriptCheckActiveVpnServer
Завершающий штрих:
для корректного обращения MikroTik к DNS-серверам предприятия, находящимся за Kerio Control, необходимо добавить статические записи с их адресами в MikroTik, в раздел IP ---> DNS ---> Static…
Ну вот где-то так!
Надеюсь, нигде не ошибся и ничего не забыл…
Спасибо за внимание!
p.s.
История правок и изменений:
- Добавлен раздел «Что получим на выходе?:»;
- Добавлен комментарий к адресу сети головного предприятия;
- Изменены IP-адреса сетей, из пулов ISP, использующиеся в описании конфигурации;
- Добавлен пункт «Завершающий штрих:»;
Комментарии (9)
0o0
11.02.2019 16:26Я правильно понял, что в микротике до сих пор такой туннель не появляется в интерфейсах?
Со всеми вытекающими…domovoy-77 Автор
11.02.2019 16:56Если вы имеете ввиду, что в MikroTik, как в Kerio создаётся отдельный VPN-интерфейс, то нет
0o0
11.02.2019 17:05Не обязатель, как в керио.
Заходим в Интерфейсы, нажимаем плюсик и другие тоннели там есть. А с этим ipsec'ом подстава. Просто я тоже юзаю эту связку и жду очередного обновления микротика где они уже это пофиксят. Что бы дальше можно было создать правило «этот пакетик идет в этот интерфейс», а не «ползет на костылях».domovoy-77 Автор
11.02.2019 17:44Меня IPSec вполне устраивает своей функциональностью, а ждать, согласитесь, лучше, когда что-то уже работает! Да и, собственно, эта конфигурация, наверняка может быть адаптирована и под будущие новые, потенциальные возможности MikroTik.
0o0
11.02.2019 20:39Да у меня тоже работает. Просто подумал, вдруг уже пора переделать нормально. Ну раз нет, то окей
domovoy-77 Автор
11.02.2019 20:56Если быть совсем честным, я пока сильно не мониторил изменения в новых версиях RouterOS. Вполне вероятно, что могло что-нибудь и появиться, просто эта статья именно про IPSec.
DaemonGloom
12.02.2019 08:55+1Особенность в том, что и в линуксе ipsec не создаёт отдельный интерфейс. Отсюда, видимо, и идут проблемы.
DickCancer
Отличная статья! Низкий Вам поклон за столь обширный труд.
domovoy-77 Автор
Спасибо за добрые слова! Очень надеюсь, что она облегчит кому-нибудь жизнь.