2015-02-15

Простой portknock средствами iptables

Подробно описывать что такое portknock и зачем он нужен не стану, благо на просторах интернета много информации по этой теме, приведу лишь пример моего конфига для SSH. В тех же интренетах в основном описывают использование отдельного процесса knockd для этих целей, что в некоторых дистрибах(Centos 6/7 например) затруднительно, да и в целом оказалось избыточно. Для этих целей нам понадобится добавить всего два правила к типовой конфигурации фаервола:

-A INPUT -p icmp -m string --string knock --algo bm -m recent --name SSH --set -j LOG 

тут мы ловим icmp пакет с некоторым ключом(в данном случае это строка "knock") и  выставляем флаг, если его поймали,

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -m recent --rcheck --name SSH --seconds 60 -j ACCEPT

а тут мы проверяем флаг и если за последние 60 секунд он установлен для данного адреса, разрешаем соединение.

Полный конфиг может выглядеть примерно так:

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -m string --string knock --algo bm -m recent --name SSH --set -j LOG
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -m recent --rcheck --name SSH --seconds 60 -j ACCEPT

-A INPUT -j DROP

Отлично, конфиг готов, как же теперь этим пользоваться? А все просто, достаточно выполнить

$ ping -p 6b6e6f636b -c 1 example.com

и мы получаем открытый 22й порт на 60 секунд, далее ssh example.com и все дела.

Чуть подробнее о магической последовательности ping -p 6b6e6f636b -c 1 example.com, это обычный ping(icmp пакет) в теле которого ключ knock задан в виде hex последовательности 6b6e6f636b. Получить нужный hex из строки можно например так:

$ python -c "import sys;h=sys.argv[1];print('%s %s'%(h,''.join(x.encode('hex') for x in h)))" knock
knock 6b6e6f636b