ICMP port knocking в 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

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

Полностью расписывать логику не буду, т.к. она очень схожа с описаной выше, просто логика проверки в правилах инвертирована и происходит удаление из 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, от которой я начал отталкиваться при построении решения.

ссылка на оригинал статьи http://habrahabr.ru/post/198108/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *