Pull to refresh

ICMP port knocking в OpenWRT

Reading time8 min
Views14K
Впечатлённый статьёй решил реализовать подобное решение на домашнем роутере, под управлением OpenWRT (Bleeding Edge r38381). Решение наверно не настолько элегантное как на Mikrotik, но главное что рабочее и без скриптов и 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, от которой я начал отталкиваться при построении решения.
Tags:
Hubs:
+13
Comments0

Articles