Всем привет!!!
В этом материале я расскажу свою реализацию GeoIP на MikroTik для фильтрации трафика по странам на фаерволе.
Оглавление
Введение
Я недавно купил себе Mikrotik RB5009 о чем рассказал тут Роутер MikroTik RB5009UG+S+IN для IT энтузиастов и оказалось, что на таком навороченном девайсе как MikroTik нет элементарной функции GeoIP, что бы можно было фильтровать трафик на фаерволе по странам. Например, у Synology такой GeoIP на фаерволе встроенный и достаточно просто его настроить. Но MikroTik не был бы микротиком, если бы в нем нельзя было бы реализовать это самостоятельно.
Ниже я описал подробно как я добился того чего хотел, что бы вы имели понимание и при желании могли повторить на своем сервере. Тем не менее я создал готовый сайт mikrotik-geoip.bafista.ru где можно скачать уже готовые списки. Все что нужно будет это настроить сам MikroTik о чем будет рассказано ниже.
Итоговая страница может отличаться
Я не претендую на идеальность, правильность и корректность созданного мною решения. Но я старался сделать его для себя как можно лучше. Быть может это пригодится и вам. Вы так же можете предложить любые улучшения и доработки.
Существующие решения
Поискав решения в интернете я не шел несколько сервисов помогающих решить задачу с GeoIP в MikroTik. Давайте разберу каждый из них и расскажу почему я не стал ими пользоваться.
Но для начала давайте поймем как это работает. Устройство с начала должно получить список сетей той или иной страны, а уже потом применять этот список к нужным правилам. Где такой список берет Synology я не знаю, но для работы MikroTik GeoIP нужно где-то такой список раздобыть самостоятельно, т.к. в MikroTikOS не заложено ничего подобного разработчиками.
mikrotik-geoip
Самый первый ресурс это mikrotik-geoip.com. Данный ресурс предлагает готовые команды, которые по факту можно просто вставить в планировщике как скрипт и запустить.
Выглядит все просто и замечательно, но есть несколько нюансов.
Вот так выглядят строчки конфига взятые с этого ресурса:
/ip/firewall/address-list/add list=MikroTik-GeoIP address=1.173.94.92/30 comment="MikroTik-GeoIP.com - Russia" timeout=7d
На первый взгляд все нормально, а на самом деле нет. Во-первых, если запускать лист раз в сутки, то тупо будет выходить ошибка пока тайм-аут в 7 дней не истечет. Соответственно нужно запускать это дело раз в 7 дней. Соответственно, если не поместить эти правила через 7 дней опять в этот адрес лист MikroTik-GeoIP, то их там и не будет, а значит не будет и доступа на ваше устройство. Есть очень большая опасность такой ситуации.
Во вторых, обратите внимание на IP адрес 1.173.94.92/30 это не Россия это Тайвань и если поискать в этом адрес листе по лучше, то там будет встречаться и Китай и Индия и кто знает что еще. При этом если удалить вручную все лишнее, то вроде как РФ адреса присутствуют полностью.
Мне не понятно зачем данный ресурс такое вытворяет. В общем использовать его я точно не буду.
iwik
Второй ресурс это http://www.iwik.org. Например, вот по такой ссылке http://www.iwik.org/ipcountry/mikrotik/RU можно получить заветный адрес лист для Mikrotik
Тут уже видно, что ребята заморочились хорошо, что бы можно было выполнять скрипт раз в сутки без ошибок. И вроде бери да пользуйся, но обратите внимание на сети. В этом списке как и в предыдущем, но еще больше, левых адресов. Для чего опять они там есть?
Нет, я таким пользоваться точно не буду.
mikrotikconfig
Следующий ресурс mikrotikconfig.com.
Выглядит тоже хорошо. Отмечаем галочкой нужные страны и скачиваем сформированный адрес лист
Содержание данного адрес листа:
Вот тут уже нет левых сетей, по крайней мере я их не нашел, но как автоматизировать это? Никак. Нет возможности получить ссылку на адрес лист, можно только через браузер, а даже если вы придумаете как получить эту ссылку, то вас так же ждет неудача. В этом адрес листе не предусмотрено повторное выполнение, а значит повторное выполнение приведет к ошибке. В общем и этот ресурс не подходит для MikroTik GeoIP.
Мое решение
Мое решение заключается в том, что бы сделать аналог вышеупомянутых ресурсов, но без недостатков, которые присутствуют там. В общем нужен WEB сервер и скрипт, который будет формировать нужные файлы, а уже MikroTik будет их скачивать и импортировать.
Получение IP адресов
Первый метод
Первая задача это получить IP адреса. И тут казалось бы поможет статья на хабре, в которой уже есть готовый скрипт на Python для формирования таких листов. К слову это все выложено на github и любой может взять и воспользоваться. Но есть нюансы.
Данный скрипт предлагает использовать два варианта.
Первый вариант как ни странно формирует практически точно такой же список адресов как и первые два MikroTik GeoIP ресурса представленные выше. Т.е. формирует список с левыми адресами.
А второй метод делает все четко, по крайней мере я не нашел левых сетей. Этот метод скачивает из сайта базы stat.ripe.net в формате json и формирует список.
И все бы хорошо, но есть один момент. Если бы я запускал на обычном сервере с Ubuntu, то я бы так и сделал. Я же собираюсь запускать это на Synology а у данного скрипта есть зависимости, которые я не могу установить в DSM.
aggregate_prefixes>=0.6.4
pyasn>=1.6.1
requests>=2.27.1
Поэтому перехожу ко второму методу.
Второй метод
Я буду использовать shell для формирования списка как самое универсальное решения для Linux, которое практически не требует никаких зависимостей. Осталось только где-то скачать этот список адресов.
На github есть готовые списки по странам ipverse-rir-ip формируемый бывшим ipverse.net. По их словам список обновляется раз в сутки. Вот это я и возьму. Нужно только написать скрипт
Это только часть скрипт
#!/bin/bash
# Инициализация переменной COUNTRY по умолчанию
COUNTRY="ru"
# Обработка параметров командной строки
while getopts "c:" opt; do
case $opt in
c) COUNTRY="$OPTARG" ;;
*) echo "Использование: $0 [-c код_страны]" >&2; exit 1 ;;
esac
done
echo "Используется код страны $COUNTRY"
echo "Для изменения кода страны используйте параметр \"-с code\" не заглавными"
# Директория для сохранения файлов
OUTPUT_DIR="/volume1/web/mikrotik-geoip/$COUNTRY"
# URL файла
URL="https://github.com/ipverse/rir-ip/raw/refs/heads/master/country/$COUNTRY/ipv4-aggregated.txt"
# Имя входного файла
INPUT_FILE="$OUTPUT_DIR/$COUNTRY-ipv4-aggregated.txt"
# Создаем директорию, если она не существует
mkdir -p "$OUTPUT_DIR"
# Скачиваем файл
wget -q "$URL" -O "$INPUT_FILE"
Что делает этот скрипт? Он скачивает с github нужный список страны, создает папку и сохраняет этот список в эту папку. Если запускать скрипт без опции, то он скачивает по умолчанию список адресов России. Можно задать опцией -с хх нужную страну (маленькими буквами)
script.sh -c by
Таким образом в папке by появится файл by-ipv4-aggregated.txt со списком сетей страны Беларусь. Соответственно подставлять можно любую страну, единственное нужно учесть, что писать код страны нужно маленькими буквами. Мой навык программирования на shell не смог преобразовать большие в маленькие и наоборот.
Файл Mikrotik
Теперь нужно сформировать из полученного списка сетей файл для импорта на MikroTik.
Берем нужный файл со списком сетей и формируем из него нужные нам строчки, при этом пропускаем строки с символами решетки
Это только часть скрипт
{
echo "/log info \"Loading MikroTik-GeoIP-$COUNTRY ipv4 address list\""
echo "/ip firewall address-list remove [/ip firewall address-list find list=GeoIP-$COUNTRY]"
echo "/ip firewall address-list"
# Преобразуем содержимое файла
while IFS= read -r line; do
# Игнорируем строки, начинающиеся с #
if [[ ! "$line" =~ ^# ]]; then
echo ":do { add address=$line list=GeoIP-$COUNTRY } on-error={}"
fi
done < "$INPUT_FILE"
} > "$OUTPUT_FILE"
Получаем примерно такое содержание файла для MikroTik
/log info "Loading MikroTik-GeoIP-ru ipv4 address list"
/ip firewall address-list remove [/ip firewall address-list find list=GeoIP-ru]
/ip firewall address-list
:do { add address=2.56.24.0/22 list=GeoIP-ru } on-error={}
:do { add address=2.56.88.0/22 list=GeoIP-ru } on-error={}
:do { add address=2.56.180.0/22 list=GeoIP-ru } on-error={}
:do { add address=2.57.0.0/24 list=GeoIP-ru } on-error={}
:do { add address=2.57.36.0/22 list=GeoIP-ru } on-error={}
:do { add address=2.57.52.0/22 list=GeoIP-ru } on-error={}
:do { add address=2.57.80.0/22 list=GeoIP-ru } on-error={}
В этом файле при импорте будет сначала происходить логирование, затем удаление старых записей и только потом добавление новых записей.
Соглашусь, что есть опасность удалить записи из адрес листа и потом их не добавить снова, но других вариантов я не придумал к сожалению. На этапе тестирования такого не произошло ни разу.
Ну и итоговый файл скрипта выглядит так:
Нужно только заменить /volume1/web/mikrotik-geoip в переменной OUTPUT_DIR на свое значение
#!/bin/bash
# Инициализация переменной COUNTRY по умолчанию
COUNTRY="ru"
# Обработка параметров командной строки
while getopts "c:" opt; do
case $opt in
c) COUNTRY="$OPTARG" ;;
*) echo "Использование: $0 [-c код_страны]" >&2; exit 1 ;;
esac
done
echo "Используется код страны $COUNTRY"
echo "Для изменения кода страны используйте параметр \"-с code\" не заглавными"
# Директория для сохранения файлов
OUTPUT_DIR="/volume1/web/mikrotik-geoip/$COUNTRY"
# URL файла
URL="https://github.com/ipverse/rir-ip/raw/refs/heads/master/country/$COUNTRY/ipv4-aggregated.txt"
# Имя входного файла
INPUT_FILE="$OUTPUT_DIR/$COUNTRY-ipv4-aggregated.txt"
# Имя выходного файла
OUTPUT_FILE="$OUTPUT_DIR/MikroTik-GeoIP-$COUNTRY.rsc"
# Создаем директорию, если она не существует
mkdir -p "$OUTPUT_DIR"
COUNT_OLD=`cat $INPUT_FILE | wc -l`
echo "Старое количество префиксов $COUNT_OLD"
# Скачиваем файл
wget -q "$URL" -O "$INPUT_FILE"
# Проверка, существует ли файл и не пуст ли он
if [ ! -s "$INPUT_FILE" ]; then
echo "Файл пуст или не существует. Скрипт будет завершен."
exit 1 # Завершение скрипта с кодом 1
fi
COUNT_NEW=`cat $INPUT_FILE | wc -l`
echo "Новое количество префиксов $COUNT_NEW"
# Начинаем вывод в нужном формате и сохраняем в файл
{
echo "/log info \"Loading MikroTik-GeoIP-$COUNTRY ipv4 address list\""
echo "/ip firewall address-list remove [/ip firewall address-list find list=GeoIP-$COUNTRY]"
echo "/ip firewall address-list"
# Преобразуем содержимое файла
while IFS= read -r line; do
# Игнорируем строки, начинающиеся с #
if [[ ! "$line" =~ ^# ]]; then
echo ":do { add address=$line list=GeoIP-$COUNTRY } on-error={}"
fi
done < "$INPUT_FILE"
} > "$OUTPUT_FILE"
# Обновления даты и времени изменений на папку
touch $OUTPUT_DIR
echo "Результат сохранен в файл $OUTPUT_FILE"
В итоге получим такой вывод скрипта:
Я добавил старые и новые значения, что бы можно было видеть как они изменились с момента прошлого запуска.
Автоматизация скрипта
Все что нужно это добавить в планировщик команды для формирования нужных файлов по странам. Например, так:
/volume1/web/mikrotik-geoip/mikrotik-geoip-converter.sh -c ru
/volume1/web/mikrotik-geoip/mikrotik-geoip-converter.sh -c by
/volume1/web/mikrotik-geoip/mikrotik-geoip-converter.sh -c kz
/volume1/web/mikrotik-geoip/mikrotik-geoip-converter.sh -c cn
В Synology DSM это выглядит так:
На почту можно не отправлять или отправлять только при ошибке выполнения
Веб сервер
Развернуть данный скрипт можно на любом linux сервере. Нужно только настроенный Apache или Nginx ну и запускать скрипт в соответствующих директориях.
Как это все реализовать на Synology NAS расписано на сайте и в видеороликах.
Настройка Mikrotik
Теперь настроим Mikrotik. Пригодится такой скрипт для РФ:
Изменяя RU или ru можно изменить страну
/tool/fetch url="http://mikrotik-geoip.bafista.ru/ru/MikroTik-GeoIP-ru.rsc" \
output=file dst-path=MikroTik-GeoIP-RU.rsc
/import MikroTik-GeoIP-RU.rsc
Или для KZ
/tool/fetch url="http://mikrotik-geoip.bafista.ru/kz/MikroTik-GeoIP-kz.rsc" \
output=file dst-path=MikroTik-GeoIP-KZ.rsc
/import MikroTik-GeoIP-KZ.rsc
Убедитесь, что путь и сам файл есть на веб сервере
После выполнения данного скрипта на MikroTik у вас в адрес листе должны появится соответствующие списки
Соответственно теперь в правилах переадресации портов указываем дополнительный параметр Src. Address list и указываем лист нужной страны. Если нужно разрешить сразу несколько стран, то делаем два одинаковых правила с разными странами. так же можно поступить и в правилах открытых портов на самом фаерволе в MikroTik.
Что бы автоматизировать процесс на MikroTik нужно создать в планировщике правило. Например, запуск скриптов по очереди раз в сутки с интервалом в 10 минут.
Нерешенная проблема
Что произойдет если скрипт не сможет скачать с сервера файл?
Если отвалится по time out, то применит предыдущий файл. Если скачает с левым содержимым, например ошибка 404, то вообще ничего не произойдет, адрес лист останется прежним.
Проблемы будут, если на сервере окажется пустой файл без сетей. Это может произойти, если скрипт на сервере не сможет скачать список сетей страны. Вот тогда да, MikroTik просто применит его предварительно удалив старые записи. Как итог у вас будет пустой список в адрес листе. А так как разрешены только адреса из этого списка, то никто не сможет пройти фаервол.
Как этого избежать вопрос открытый. Если поможете решить, то я буду очень вам признателен.
Нашел такое решение:
# Проверка, существует ли файл и не пуст ли он
if [ ! -s "$INPUT_FILE" ]; then
echo "Файл пуст или не существует. Скрипт будет завершен."
exit 1 # Завершение скрипта с кодом 1
fi
Данный код проверят файл на существование и что бы он был не пуст. Если не существует или пустой, то скрипт не изменяет файл rsc и как следствие он останется корректным, пусть и не обновленным. Таким образом, когда mikrotik его скачает с сервера, он просто по сути применит старые настройки. Самое главное, что в адрес листе будет список сетей и тогда проблем не должно быть.
Данный код я уже внес в общий скрипт выше и на своем сервере.
Что в итоге
В итоге есть ресурс mikrotik-geoip.bafista.ru, с которого можно получить список нужных IP адресов стран и добавить их в MikroTik либо создать свой аналогичный ресурс. Таким образом вы сможете настроить MikroTik GeoIP и отфильтровать не нужные страны, а значит атак на ваш роутер или сервер за ним будет гораздо меньше, а может и не будет совсем.
Часть 2 (Хостинг)
В связи с переездом на хостинг пришлось много чего поменять. Для начала сам скрипт формирования файлов. Его пришлось переделывать. Тееперь он берет список нужных стран из файла countries.txt следующего содержания:
ru
kz
by
cn
tr
us
eg
И наконец сам скрипт, в котором я добавил все возможные на мой взгляд проверки
#!/bin/bash
# Директория для сохранения файлов
BASE_OUTPUT_DIR="/var/www/"
# Файл с кодами стран
COUNTRIES_FILE="$BASE_OUTPUT_DIR/countries.txt"
# Проверка существования файла с кодами стран
if [ ! -f "$COUNTRIES_FILE" ]; then
echo "Файл $COUNTRIES_FILE не найден. Скрипт будет завершен."
exit 1
fi
# Читаем файл с кодами стран и обрабатываем каждый код
while IFS= read -r COUNTRY; do
echo "Обрабатывается код страны: $COUNTRY"
# Директория для текущей страны
OUTPUT_DIR="$BASE_OUTPUT_DIR/$COUNTRY"
# URL файла
URL="https://github.com/ipverse/rir-ip/raw/refs/heads/master/country/$COUNTRY/ipv4-aggregated.txt"
# Имя входного файла
INPUT_FILE="$OUTPUT_DIR/$COUNTRY-ipv4-aggregated.txt"
# Имя выходного файла
OUTPUT_FILE="$OUTPUT_DIR/MikroTik-GeoIP-$COUNTRY.rsc"
# Создаем директорию, если она не существует
mkdir -p "$OUTPUT_DIR"
COUNT_OLD=$(wc -l < "$INPUT_FILE" 2>/dev/null || echo 0)
echo "Старое количество префиксов: $COUNT_OLD"
# Скачиваем файл
wget -q "$URL" -O "$INPUT_FILE"
# Проверка, существует ли файл и не пуст ли он
if [ ! -s "$INPUT_FILE" ]; then
echo "Файл пуст или не существует для кода страны $COUNTRY. Переход к следующему коду."
continue # Переход к следующему коду страны
fi
COUNT_NEW=$(wc -l < "$INPUT_FILE")
echo "Новое количество префиксов: $COUNT_NEW"
# Начинаем вывод в нужном формате и сохраняем в файл
{
echo "/log info \"Loading MikroTik-GeoIP-$COUNTRY ipv4 address list\""
echo "/ip firewall address-list remove [/ip firewall address-list find list=GeoIP-$COUNTRY]"
echo "/ip firewall address-list"
# Преобразуем содержимое файла
while IFS= read -r line; do
# Игнорируем строки, начинающиеся с #
if [[ ! "$line" =~ ^# ]]; then
echo ":do { add address=$line list=GeoIP-$COUNTRY } on-error={}"
fi
done < "$INPUT_FILE"
} > "$OUTPUT_FILE"
touch $OUTPUT_DIR
echo "Результат сохранен в файл $OUTPUT_FILE"
done < "$COUNTRIES_FILE"
Затем на хостинге в корне там же где и срипты создаем файл index.php следующего содержания:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Содержимое каталогов</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f9f9f9;
}
header {
background-color: #4CAF50;
color: white;
padding: 20px;
text-align: center;
}
.description {
margin: 20px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:hover {
background-color: #f1f1f1;
}
.directory {
margin-bottom: 20px;
}
</style>
</head>
<body>
<header>
<h1>Страница для Mikrotik GeoIP</h1>
<p>Автор: Александр Linux</p>
</header>
<div class="description">
<p>Разбивка адресных листов по странам.</p>
<p>Файлы обновляются раз в сутки в 06:00 MSK.</p>
<p>Вы можете скачать и посмотреть файлы:</p>
<ul>
<li>Файл с расширением <strong>.rsc</strong> предназначен для Mikrotik RouterOS.</li>
<li>Файл с расширением <strong>.txt</strong> — обычный список сетей.</li>
</ul>
<p>Подробную информацию можно найти на сайте <a href="https://bafista.ru/mikrotik-nastrojka-geoip-faervol/" target="_blank">bafista.ru</a>.</p>
<p>Забросить донат по ссылке: <a href="https://yoomoney.ru/to/4100118186635091" target="_blank">YooMoney</a>.</p>
<p>По вопросам добавления страны пишите в форме обратной связи: <a href="https://bafista.ru/contact/" target="_blank">Обратная связь</a>.</p>
</div>
<?php
// Ассоциативный массив с названиями каталогов и их подписями
$directories = [
'ru' => 'Россия',
'us' => 'США',
'tr' => 'Турция',
'by' => 'Беларусь',
'cn' => 'Китай',
'eg' => 'Египет',
'kz' => 'Казахстан'
];
// Сортируем массив по значениям (названиям каталогов)
asort($directories);
// Проходим по каждому каталогу
foreach ($directories as $dirKey => $dirName) {
echo '<div class="directory">';
echo '<h2>' . htmlspecialchars($dirName) . ' (' . htmlspecialchars($dirKey) . ')</h2>';
echo '<table>';
echo '<tr><th>Имя файла</th><th>Дата и время изменения</th></tr>';
// Получаем список файлов в текущем каталоге
$files = scandir($dirKey);
// Проходим по каждому элементу в каталоге
foreach ($files as $file) {
// Пропускаем специальные элементы '.' и '..'
if ($file !== '.' && $file !== '..') {
// Создаем ссылку на файл
$filePath = htmlspecialchars($dirKey . '/' . $file);
// Получаем время последнего изменения файла
$fileTime = filemtime($dirKey . '/' . $file);
$formattedTime = date('Y-m-d H:i:s', $fileTime); // Форматируем дату и время
echo '<tr>';
echo '<td><a href="' . $filePath . '">' . htmlspecialchars($file) . '</a></td>';
echo '<td>' . $formattedTime . '</td>';
echo '</tr>';
}
}
echo '</table>';
echo '</div>';
}
?>
</body>
</html>
Получаем такой вид страницы как тут https://mikrotik-geoip.bafista.ru (ну почти, я подправил у себя еще украшений). Естественно, что вы можете брать и править все под себя на своем сервере или хостинге.
Если будите пользоваться моим сайтом прошу не забывайте забрасывать донаты, если у вас есть такая возможность. Да же 1000 рублей от 10 человек поможет оплатить хостин на один год.
Видео ролик
Видео ролик так же доступен на Youtube, ВК, Rutube и Дзен
В целом теперь вы знаете сервисы и MikroTik настройка GeoIP