ICMP port knocking в OpenWRT

в 8:39, , рубрики: icmp, linux, openvpn, OpenWrt, системное администрирование, метки: , ,

Впечатлённый статьёй решил реализовать подобное решение на домашнем роутере, под управлением OpenWRT (Bleeding Edge r38381). Решение наверно не настолько елегантное как на Miktotik, но главное что рабочее и без скриптов и cron. Так же его можно взять за основу для реализации на других ОС Linux. Кому интересно прошу под кат.

Пришлось облазить много ресурсов. Думал и скрипты писать по отслеживанию LOG или ULOG событий от iptables в системном журнале. Даже наткнулся на проект — Specter, с помошью которого можно реализовать реакцию (выполнение скриптов) на события ULOG от iptables, чего нет в ulogd. Тут большая подборка старых проектов по реализации Port knocking, но совсем не хотелось заниматься компиляцией на роутере или виртуалке. При поиске решения, часто наталкивался на советы про быстроту и удобство ipset-ов, что бы не нагромождать iptables кучей «одинаковых» по деуствию правил. И в них были замечены ключи "--match-set" и "--add-set", дальнейшие поиски и привели к решению.
В общем итоге было принято решение использовать ipset-ы, т.к. не нужно что-либо отслеживать и писать реакции на события за пределами iptables.

Итак, решение реализовано с использованием сугубо iptables и ipset. Для простоты восприятия комбинация «стуков» будет такой же, как и в упомянутой статье. Напомню это — 2-а ICMP пакета подряд размером 70 байт и за ними 2-а ICMP пакета подряд размером 100 байт. Ну и не забываем о размере заголовка ICMP паркета (28 байт).
В моём случае после соответвующих «стуков» разрешаеться соединение на порту 1194/tcp для OpenVPN сервера для IP адреса, с которого произвели «стуки». С инструкцией по настройке OpenVPN сервера на OpenWRT можно ознакомиться на официальной Wiki, т.к. это выходит за рамки данной статьи.

Подготовка ipset-ов

Стоит отметить, что поддержка правил для создания ipset-ов в файле настроек файрвола OpenWRT появилось только с релиза Attitude Adjustment, правда в ревизии r36349 не работало (При применении правил, выдавало предупреждение, что datatype для ipset-ов не указан).

Но ipset-ы можно создать ручками, желательно создавать их при загрузке, например: прописать в /etc/rc.local.

ipset create knock1 hash:ip
ipset create knock2 hash:ip
ipset create knock3 hash:ip
ipset create AllowedVPN hash:ip

Если же fw3 поддерживает создание ipset-ов (fw3 — это сам инструмент управления файрволом в OpenWRT, с детальным описанием настроек можно ознакомиться на официальной Wiki), то в файл настроек файрвола /etc/config/firewall добавляються следующие пункты:

config ipset
  option enabled 1
  option name knock1
  option storage hash
  option match src_ip

config ipset
  option enabled 1
  option name knock2
  option storage hash
  option match src_ip

config ipset
  option enabled 1
  option name knock3
  option storage hash
  option match src_ip

config ipset
  option enabled 1
  option name AllowedVPN
  option storage hash
  option match src_ip

Логика отлавливания последовательности ICMP пакетов

Ловим первый knock

icmptype 8 length 98 ! match-set knock1 src ! match-set knock2 src ! match-set knock3 src ! match-set AllowedVPN src add-set knock1 src

Исходящий адрес ICMP пакета размером 98 байт заносим в ipset knock1, если его нет в остальных ipset-ах.

Ловим второй knock

icmptype 8 length 98 match-set knock1 src ! match-set knock2 src ! match-set knock3 src ! match-set AllowedVPN src add-set knock2 src

Исходящий адрес ICMP пакета размером 98 байт заносим в ipset knock2, если он уже есть в ipset-е knock1 и нет в остальных.

Ловим третий knock

icmptype 8 length 128 match-set knock1 src match-set knock2 src ! match-set knock3 src ! match-set AllowedVPN src add-set knock3 src

Исходящий адрес ICMP пакета размером 128 байт заносим в ipset knock3, если он так же присутсвует в ipset-ах knock1 и knock2, но нет в AllowedVPN.

Ловим четвёртый knock

icmptype 8 length 128 match-set knock1 src match-set knock2 src match-set knock3 src ! match-set AllowedVPN src add-set AllowedVPN src

Исходящий адрес ICMP пакета размером 128 байт заносим в ipset AllowedVPN, если он так же присутсвует в ipset-ах knock1, knock2 и knock3.
Для того что бы последовательность отлавливалась правильно, правила в iptables необходимо заносить в обратном порядке. Иначе первый «стук» будет отловлен первым и вторым правилами сразу так же как третий «стук» отловиться третим и четвёртым правилами сразу.
Дополнительные проверки на отсутсвие в других ipset-ах указаны для чёткого срабатывания последовательности «стуков».

Ниже приведена последовательность команд iptables для занесения в чепочку input_rule (специально созданная чепочка в файрволе OpenWRT для правил пользователя), добавляются в /etc/firewall.user.

iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock1 src

Теже правила, но с логированием в системный журнал

iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK4 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK3 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK2 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK1 O) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set ! --match-set AllowedVPN src -j SET --add-set knock1 src

«Самое главное» правило

Именно это правило и разрешает входящее соединение на порт 1194/tcp, если IP адрес с которого производиться соединение, находиться в ipset-е AllowedVPN.

config 'rule'
  option enabled 1
  option 'target' 'ACCEPT'
  option 'name' 'VPN'
  option 'src' 'wan'
  option 'proto' 'tcp'
  option 'dest_port' '1194'
  option 'extra' '-m set --match-set AllowedVPN src'

Иначе его можно прописать в /etc/firewall.user

iptables -A input_rule -p tcp --dport 1194 -m set --match-set AllowedVPN src -j ACCEPT

Port knocking

Произвести Port knocking в Windows можно командой:
ping readyshare.mydomain.ua -l 70 -n 2 && ping readyshare.mydomain.ua -l 100 -n 2

ICMP port knocking в OpenWRT

Закрытие доступа

Полностью расписывать логику не буду, т.к. она очень схожа с описаной выше, просто логика проверки в правилах инвертирована и происходит удаление из ipset-ов. Ну и соответсвенно если IP адреса нет в ipset-e AllowedVPN — то и нет доступа.
Последовательность «стуков» такая же как и при открытии доступа.
Ниже приведена последовательность команд iptables для занесения в чепочку input_rule, файл /etc/firewall.user

iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set ! --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock1 src

Теже правила для блокирования, но с логированием в системный журнал

iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK4 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set ! --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set AllowedVPN src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK3 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 128 -m limit --limit 10/s -m set ! --match-set knock1 src -m set ! --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock3 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set ! --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK2 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set ! --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock2 src
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j LOG --log-prefix "(KNOCK1 C) "
iptables -A input_rule -p icmp -m icmp --icmp-type echo-request -m length --length 98  -m limit --limit 10/s -m set --match-set knock1 src -m set --match-set knock2 src -m set --match-set knock3 src -m set --match-set AllowedVPN src -j SET --del-set knock1 src

Надеюсь мой опыт пригодиться другим.

Хорошая презентация по ipset-ам Chris Cooper-а из QC Co-Lab, от которой я начал отталкиваться при построении решения.

Автор: SkyRE

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js