MikroTik и CloudFlare: Динамический IP для домена
Нашёл скрипт реализации динамической смены IP адреса из RouterOS напрямую в панели управления CloudFlare при помощи API. Где нашёл скрипт уже не помню, вроде бы на страницах официального форума MikroTik.
Скрипт я немного переделал, удалил лишние переменные, некоторые переопределил, подправил области видимости переменных, обновил метод авторизации скрипта на серверах CloudFlare. Вроде работает.
Сам скрипт нужно настроить под себя, прописав в нём значения переменных. Некоторые значений можно узнать из панели управления доменом в CloudFlare, но для получения значения переменной cfDnsID
необходимо выполнит немного телодвижений. Об этом ниже.
Работа CloudFlare API
Без токена - никак.
Создание токена
Для того, чтобы начать работать с CloudFlare API, нам нужно создать специальный токен:
- Зайти в панель управления токенами.
- Нажать кнопку Create Token.
- На странице выбора шаблонов - выбрать шаблон Edit zone DNS.
- В разделе Zone Resources можно выбрать область доступа токена к зонам (доменам). Можно указать конкретную зону (Specific zone) или выбрать все зоны (All zones).
- Всё, нажимаем кнопку Continue to summary и перемещаемся на следующую станицу…
Проверка токена
По окончании создания токена, CloudFlare переместит нас на страницу проверки токена. На этой странице будут наш созданный токен (его необходимо сохранить) и команда, которой при помощи утилиты curl
можно проверить корректность токена:
При выполнении, команда вернёт следующий результат:
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" -H "Authorization: Bearer <...>" -H "Content-Type: application/json" | python3 -mjson.tool
{
"result": {
"id": "<...>",
"status": "active"
},
"success": true,
"errors": [],
"messages": [
{
"code": 10000,
"message": "This API Token is valid and active",
"type": null
}
]
}
По сообщению “This API Token is valid and active” понятно, что токен корректный и работает.
Получение ID ресурсной записи домена
Когда у нас есть токен, можно полноценно работать с CloudFlare API. Нам нужно получить ID ресурсной записи домена. Получать будем следующей командой:
Обратите внимание на следующие заглушки в команде:
ZONE_ID
- ID домена. Находится в панели оправления доменом на главной странице в поле Zone ID.TOKEN
- токен для доступа к CloudFlare API.
Вместо этих заглушек необходимо подставить свои значения.
Сформировав правильную команду с корректными данными и выполнив её, команда вернёт результат в формате JSON. Результат будет содержать набор всех ресурсных записей конкретного домена. У меня это выглядит так:
curl -X GET "https://api.cloudflare.com/client/v4/zones/<...>/dns_records" -H "Authorization: Bearer <...>" -H "Content-Type: application/json" | python3 -mjson.tool
{
"result": [
{
"id": "gJDSG5la4IWNOEVn6K2PHyope8Q9YhzC",
"zone_id": "<...>",
"zone_name": "example.com",
"name": "example.com",
"type": "A",
"content": "192.168.10.232",
"proxiable": true,
"proxied": true,
"ttl": 1,
"locked": false,
"meta": {
"auto_added": false,
"managed_by_apps": false,
"managed_by_argo_tunnel": false,
"source": "primary"
},
"created_on": "2020-02-23T21:26:27.56227Z",
"modified_on": "2020-02-23T21:26:27.56227Z"
}
],
"success": true,
"errors": [],
"messages": [],
"result_info": {
"page": 1,
"per_page": 20,
"count": 7,
"total_count": 7,
"total_pages": 1
}
}
Как видим, команда вернула нам результат с массивом result
. В этом массиве находятся все ресурсные записи нашего домена. Каждая ресурсная запись содержит поля id
и content
:
id
- ID ресурсной записи. Очень важное поле, как раз его значение необходимо записать в переменнуюcfDnsID
скрипта.content
- содержимое ресурсной записи.
Нам необходимы только записи с типом A
. Обычно в записях с типом A
хранятся IP адреса серверов, к которым привязан домен. У записей с типом A
в поле content
находится IP адрес, который должен изменить наш MikroTik при обращении к CloudFlare API.
Скрипт
# Mikrotik RouterOS script for CloudFlare DDNS
#
# @package RouterOS
# @author Kitsune Solar <mail@kitsune.solar>
# @copyright 2023 Library Online
# @license MIT
# @version 0.0.1
# @link https://lib.onl
# -------------------------------------------------------------------------------------------------------------------- #
# RouterOS: WAN interface name.
:local rosWanInterface "ether1"
# RouterOS: Enables trust chain validation from local certificate store.
# 'no' | Disable certificate check.
# 'yes' | Enable certificate check.
:local rosCheckCert "no"
# CloudFlare: API token.
:local cfToken ""
# CloudFlare: Domain.
:local cfDomain "example.com"
# CloudFlare: Zone ID.
:local cfZoneID ""
# CloudFlare: DNS ID.
:local cfDnsID ""
# CloudFlare: Domain record type.
:local cfRecordType "A"
# CloudFlare: Debug mode.
# 0 | Disable debug mode.
# 1 | Enable debug mode.
:local cfDebug 0
# -------------------------------------------------------------------------------------------------------------------- #
# -------------------------------------------------------------------------------------------------------------------- #
# -------------------------------------------------------------------------------------------------------------------- #
# IP on WAN interface.
:local srcIP ""
# IP on CloudFlare domain.
:local dstIP ""
# Get RouterOS WAN IP.
:set srcIP [/ip address get [/ip address find interface=$rosWanInterface ] address]
:set srcIP [:pick $srcIP 0 [:find $srcIP "/"]]
# Get CloudFlare domain IP.
:set dstIP [:resolve $cfDomain]
# Build CloudFlare API (v4).
:local cfAPI "https://api.cloudflare.com/client/v4/zones/"
:set cfAPI ($cfAPI . "$cfZoneID/dns_records/$cfDnsID")
:local cfAPIHeader "Authorization: Bearer $cfToken, Content-Type: application/json"
:local cfAPIData "{\"type\":\"$cfRecordType\",\"name\":\"$cfDomain\",\"content\":\"$srcIP\"}"
# Write debug info to log.
:if ($cfDebug) do={
:log info ("CloudFlare: Domain = $cfDomain")
:log info ("CloudFlare: Domain IP (dstIP) = $dstIP")
:log info ("CloudFlare: WAN IP (srcIP) = $srcIP")
:log info ("CloudFlare: CloudFlare API (cfAPI) = $cfAPI&content=$srcIP")
};
# Compare and update CF if necessary.
:if ($dstIP != $srcIP) do={
:log info ("CloudFlare: Updating $cfDomain, setting $srcIP = $cfDomain")
/tool fetch \
mode=https \
http-method=put \
http-header-field="$cfAPIHeader" \
http-data="$cfAPIData" url="$cfAPI" \
check-certificate=$rosCheckCert \
output=user as-value
/ip dns cache flush
} else={
:log info "CloudFlare: No Update Needed!"
}
Настройка
Алгоритм настройки довольно прост:
- Получаем токен для работы с CloudFlare API.
- При помощи специальной команды узнаём значение поля
id
ресурсной записи с типомA
. - Это значение вписываем в переменную
cfDnsID
скрипта. - Остальные требуемые значения для переменных уже доступны без каких-либо телодвижений.
Переменные
Опишу переменные и что они из себя представляют:
rosWanInterface
- имя интерфейса WAN в RouterOS.rosCheckCert
- включение / отключение проверки цепочки сертификации при запросе к CloudFlare API. Для корректной работы этой функции необходимо, чтобы в репозитории сертификатов RouterOS присутствовали корневые сертификаты центров сертификации. Про импортирование сертификатов написано в заметке Добавление корневых сертификатов в RouterOS.cfToken
- токен, полученный в панели управления токенами.cfDomain
- название домена, для которого необходимо динамически менять IP адрес.cfZoneID
- ID домена. Находится в панели управления доменом на главной странице в поле Zone ID.cfDnsID
- ID ресурсной записи домена. Для получения значения переменной, необходимо выполнить запрос к CloudFlare API.cfRecordType
- тип ресурсной записи домена. Обычно этоA
. Менять нет необходимости.cfDebug
- включение / отключение отображения технической информации в логе RouterOS.
Рекомендую настраивать скрипт в редакторе с подсветкой синтаксиса, чтобы не ошибиться и не задеть какую-либо кавычку.
Установка
После настройки скрипта, его нужно добавить в репозиторий скриптов RouterOS. Находится репозиторий в System / Scripts. При добавлении скрипта, необходимо выбрать политики read
, write
, test
, policy
.
Планировщик
Скрипт должен переодически запускаться для проверки и синхронизации IP адресов сервера и домена. В этом поможет планировщик RouterOS. Заходим в System / Scheduler и создаём задачу с политиками read
, write
, test
, policy
. В поле On Event вписываем точное название скрипта, ранее добавленного в репозиторий RouterOS.
Проверка
Проверить работу скрипта можно в репозитории по адресу System / Scripts. Выделив скрипт и нажав на кнопку Run, смотрим изменился ли IP адрес у домена в панели управления CloudFlare.
2023-10-19
- Статья переписана под новые реалии работы с CloudFlare API.
- В статью добавлен код скрипта.
- Скрипт немного переделан, в частности, изменён процесс авторизации CloudFlare API.