Тем, кому надо обеспечить себе, любимому, доступ к своим серверам из любой точки мира по SSH/RDP/иное — небольшое RTFM/шпора.
Нам нужно обойтись без VPN и других наворотов, с любого устройства под руками.
И так, чтобы с сервером не слишком упражняться.
Всё, что для этого нужно — knockd, прямые руки и 5 минут работы.
"В интернете всё есть", конечно (даже на Хабре), но когда дело доходит до конкретной реализации — тут и начинается...
Будем упражняться на примере Fedora/CentOS, но это неважно.
Шпора подойдет как новичкам, так и зубрам этого дела, поэтому будут комментарии, но покороче.
1. Сервер
ставим knock-server:
yum/dnf install knock-server
настраиваем его (например на ssh) — /etc/knockd.conf:
[options] UseSyslog interface = enp1s0f0 [SSHopen] sequence = 33333,22222,11111 seq_timeout = 5 tcpflags = syn start_command = iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT cmd_timeout = 3600 stop_command = iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT [SSHclose] sequence = 11111,22222,33333 seq_timeout = 5 tcpflags = syn command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
"Открывающая" часть настроена на автозакрытие через 1 час. Мало ли...
/etc/sysconfig/iptables:
... -A INPUT -p tcp -m state --state NEW -m tcp --dport 11111 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22222 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 33333 -j ACCEPT ...
вперед:
service iptables restart service knockd start
можно добавить RDP на крутящийся внутри виртуальный Windows Server (/etc/knockd.conf; название интерфейса подставить по вкусу):
[RDPopen] sequence = 44444,33333,22222 seq_timeout = 5 tcpflags = syn start_command = iptables -t nat -A PREROUTING -s %IP% -i enp1s0f0 -p tcp -m tcp --dport 3389 -j DNAT --to-destination 192.168.0.2 cmd_timeout = 3600 stop_command = iptables -t nat -D PREROUTING -s %IP% -i enp1s0f0 -p tcp -m tcp --dport 3389 -j DNAT --to-destination 192.168.0.2 [RDPclose] sequence = 22222,33333,44444 seq_timeout = 5 tcpflags = syn command = iptables -t nat -D PREROUTING -s %IP% -i enp1s0f0 -p tcp -m tcp --dport 3389 -j DNAT --to-destination 192.168.0.2
Все наши пинки от клиента отслеживаем на сервере командой
iptables -S
.
2. Путеводитель по граблям
knockd.conf:
В манах тоже всё есть (но это неточно), однако knockd — товарищ довольно скупой на сообщения, поэтому надо быть очень внимательным.
- версия
В репозитариях Fedora/CentOS крайний knockd на сегодня — 0.63. Кто хочет UDP — ищите пакеты 0.70. - interface
В дефолтной конфигурации Fedora/CentOS эта строка отсутствует. Добавить руками, иначе не будет работать. - timeout
Здесь подобрать по вкусу. Надо чтобы и клиенту времени хватило на все пинки — и бот-сканер портов обломался (а сканировать будут 146%). - start/stop/command.
Если команда одна — то command, если две — то start_command+stop_command.
Если ошибетесь — knockd промолчит, но работать не будет. - proto
Теоретически можно использовать UDP. На практике я было смешал tcp и udp, а клиент с пляжа в Бали смог открыть себе калитку только с пятого раза. Ибо TCP долетели когда надо, а UDP — не факт. Но это дело вкуса, опять же. - sequence
Неявные грабли в том, что последовательности не должны пересекаться… как бы это сказать...
Например, такое:
open: 11111,22222,33333
close: 22222,11111,33333
По пинку 11111 open будет ждать следующего пинка на 22222. Однако по этому (22222) пинку начнет работать close и всё поломается. Это зависит от delay клиента в том числе. Такие дела ©.
iptables
Если в /etc/sysconfig/iptables вот это вот:
*nat
:PREROUTING ACCEPT [0:0]
нам особо не мешает, то вот это вот:
*filter
:INPUT ACCEPT [0:0]
...
-A INPUT -j REJECT --reject-with icmp-host-prohibited
Таки мешает.
Так как knockd добавляет правила в конец цепочки INPUT, то мы получим reject.
А отключить этот reject — это открыть машину всем ветрам.
Дабы не изгаляться в iptables что куда перед чем вставлять (как вот люди предлагают) сделаем проще:
- дефолтное в CentOS/Fedora первое правило ("что не запрещено — разрешено") заменим на обратное,
- а последнее правило убираем.
В итоге должно получиться:
*filter
:INPUT DROP [0:0]
...
#-A INPUT -j REJECT --reject-with icmp-host-prohibited
Можно, конечно, вместо DROP сделать REJECT, но с DROP ботам будет жить веселее.
3. Клиент
В этом месте самое интересное (с моей точки зрения), так как надо работать не только с любого пляжа, но и с любого устройства.
В принципе ряд клиентов перечислены на сайте проекта, но это из той же серии "в интернете всё есть". Поэтому перечислю то, что здесь и сейчас работает у меня под руками.
При выборе клиента необходимо проследить, чтобы он поддерживал опцию delay между пакетами. Да, пляж пляжу рознь и 100 мегабит ни разу не гарантируют долетание пакетов в нужном порядке в нужное время из данного места.
И да — при настройке клиента delay надо подбирать самостоятельно. Много timeout — боты нападут, мало — клиент не успеет. Много delay — клиент не успеет или будет конфликт простуков (см. "грабли"), мало — пакеты перезаблудятся в интернетах.
При timeout=5s вполне рабочий вариант delay=100..500ms
Windows
Как это ни смешно звучит, но нагуглить внятный knock-клиент под эту платформу довольно нетривиально. Такой, чтобы CLI, поддерживал delay, TCP — и без бантиков.
Как вариант можно попробовать это вот. Видимо у меня гугль не торт.
Linux
Здесь всё просто:
dnf install knock -y
knock -d <delay> <dst_ip> 11111 22222 33333
MacOS
Проще всего поставить порт из homebrew:
brew install knock
и нарисовать себе нужные батники командники вида:
#!bin/sh
knock -d <delay> <dst_ip> 11111 22222 33333
iOS
Рабочий вариант — KnockOnD (бесплатный, из магазина).
Android
"Knock on Ports". Не реклама, а просто он работает. И разработчики достаточно отзывчивые.
P.S. markdown на Хабре, конечно, дай бог ему здоровья когда-нибудь...
UPD1: благодаря хорошему человеку нашелся рабочий клиент под Windows.
UPD2: еще один хороший человек напомнил, что ставить новые правила в конец iptables не всегда полезно. Но — it depends.
Комментарии (25)
KoPBuH
03.10.2019 20:57Что под виндой, что под линем вполне хватает обычного telnet. Небольшой скрипт или bat со sleep'ами и готов дятел.
Shtucer
04.10.2019 06:32Так как knockd добавляет правила в конец цепочки INPUT, то мы получим reject.
А это точно кнокд тупой, а не вот это вот кто написал:
start_command = iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
вместо
start_command = iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT
Или он ещё чего-то накидывает?
justhabrauser Автор
04.10.2019 09:19И то и то работает — knock'у всё равно что запускать.
Просто во втором случае мне было лениво.
Да и небезопасно — я могу в очередной раз переколпашить свой развесистый iptables и про нюансы для knockd забыть.Shtucer
04.10.2019 09:57Забыть "нюансы кнока" (какие?) это "небезопасно", поэтому давайте откроем нахрен всё? Интересный подход.
justhabrauser Автор
04.10.2019 10:14Забыть перепилить (и проверить!) в knockd номер правила в iptables после пересобачивания этого iptables — легко. Или не забыть и перепилить — но поломать iptables.
Поэтому давайте не откроем нахрен всё, а закроем нахрен всё (что и предложено в данной статье).Shtucer
04.10.2019 11:02Забыть перепилить (и проверить!) в knockd номер правила в iptables
Зачем запоминать номер правила в iptables?!
justhabrauser Автор
04.10.2019 11:27Нет, ну если согласиться с собой чтобы knockd ставил свои правила в начало, а не в конец — то да, тоже вариант, согласен.
НО:
* тот же knock может добавить в начало правило типа «все порты — прямо мне» — и в Вашем случае 22 может поломаться.
* или же я временно сам поставил в начало подобное правило (бывает для полного контроля сервера издалека) — в Вашем случае это может перестать работать.
* если же добавить в конец правило «всем остальным — в мусорку» (перенаправить ботов в honey point) — то мой вариант может не работать.
It depends.
Но за напоминание спасибо, добавил в конец статьи.Tangeman
04.10.2019 14:35Логичнее создать отдельную ветку для knockd в iptables, и писать в неё. Как-то так:
:KNOCK -
-A INPUT -m state --state NEW -p tcp --dport 22 -j KNOCK
А в самой конифигурации уже ссылаться на неё:
start_command = iptables -A KNOCK -s %IP% -j ACCEPT
Таким образом, творите в своих обычных правилах что хотите, а knockd будет в своей песочнице, и ничего другого при всём желании не испортит. Есть правило — ок, порт открыт, нет его — не открыт, и никакой мешанины.
MaxRAF
04.10.2019 09:59В CentOS по умолчанию firewalld, но все равно многие упорно его отключают и устанавливают iptables. В чем причина?
justhabrauser Автор
04.10.2019 10:09Сложность и непривычность firewalld.
Сисадмины — народ довольно консервативный: «Работает — не трожЪ»!
Поэтому эти ваши firewalld, systemd и прочие NetworkManager'ы сисадминам как серпом по я не знаю как проще выразить.
PS. а всяким поттерингам в аду приготовлена отдельная серверная.
sohmstyle
04.10.2019 14:101) Привычка работы с iptables т.к. не всё можно сделать с помощью firewalld без direct-rules.
2) Многие приложения динамически добавляют правила iptables в runtime. И restart/reload firewalld стирает runtime-rules.
Возможно есть ещё причины, но они не столь значительны.
impalex
04.10.2019 14:01На мой взгляд «автозакрытие» через час — перебор. Открытый порт нужен только на время установления соединения. Минуты — за глаза хватит, а то и несколькими секундами обойтись можно. Т.е. открыли, подключились, закрыли. Соединение остаётся активным. При этом «ручное» закрытие порта становится не особо нужным. Всё сказанное справедливо при наличии правила ACCEPT для state RELATED,ESTABLISHED.
PS: Спасибо за то, что отметили «Knock on Ports», было приятно :) Это мой маленький проект, делается just for fun и больше для себя :)justhabrauser Автор
04.10.2019 14:07Все циферки проставлены для примера. У меня обычно стоит таймаут 15 минут. Иногда интернет может быть ну очень печален. И обрывист.
Но если справился быстро — то лучше закрыть побыстрее. На всякий случай.
За «Knock on Port» — не за что, с вами приятно работать (это насчет issue о непроверке наличия интернетов). Еще бы сделали это дело перемещаемым на SD-карту (а не как поделия яндекса прибиты гвоздями к системному разделу) — и вообще отлично. Но это я попозже побаграпортую.impalex
04.10.2019 14:41Еще бы сделали это дело перемещаемым на SD-карту
Не выйдет, к сожалению. Приложения с виджетами и сервисами (процесс нокинга — сервис) не могут быть установлены на карту. Такое вот ограничение, могу только развести руками.
MarvinD
04.10.2019 16:26Хотел бы обратить внимание:
дефолтное в CentOS/Fedora первое правило («что не запрещено — разрешено») заменим на обратное, а последнее правило убираем.
Имхо, практически всегда при настройке нового сервера надо ставить INPUT DROP для всего, и только по мере необходимости разрешать что-то. Т.е. в нормальной ситуации должно быть «что не разрешено — то запрещено».justhabrauser Автор
04.10.2019 18:14Это статья не об iptables, но раз уж так зашло…
Пару раз было накосячил в iptables и если бы не дефолтное «всё всем» — видел бы я свой сервер (в датацентре в другой стране).
Так что где-то дефолтное правило имеет смысл.MarvinD
04.10.2019 18:38Да, статья не про это, но мне глаз резануло то, что в статье подразумевается, что по дефолту все можно, хотя даже домашние роутеры на input wan ничего не разрешают, пока явно не разрешить, а в статье речь так и вообще про сервер.
Заодно вопрос — после того, как клиент knock отработал, порт открылся, дальнейшая работа возможно либо до истечения таймаута knock, либо до разрыва stateful сессии на iptables сервера? Там никаких служебных пингов, скажем, раз в 5 сек, клиент не отправляет для поддержания сессии?
justhabrauser Автор
04.10.2019 19:11Knockd — это не чудо и не магия.
Он просто выполняет команду по приходу определенных последовательностей на прослушиваемые порты.
Любую команду. И только её.
Всё.MarvinD
05.10.2019 00:27Поэтому я и спросил про клиента ;) а не про серверную часть.
justhabrauser Автор
05.10.2019 12:52А клиенту что? Пнул — и на выход.
Кстати, клиентом могут быть обыкновенные сетевые утилиты.
Вроде бы в Linux и MacOS какие-то «искаропки».
barbos6
-A INPUT -i eth0 -p tcp -m tcp --dport 20:10000 -j TARPIT --tarpit
sshd убрать с 22 порта, диапазон левых портов по вкусу, боты упарятся стучаться.
И кто ж так сможет синхронизировать предполагаемый ботнет, что 100500 тазов cтукнут одновременно во все порты одного и того же ip?
Разве что специально, чтобы попалиться.
В общем фантазии. :)
justhabrauser Автор
1. Это статья больше не для гуру iptables, а для «компьютерщиков широкого профиля» — кому нужно быстро, просто и достаточно надежно.
2. Не упарятся, стучат по всем портам постоянно. Бот-нету из нескольких сотен тысяч хостов нетрудно в100500ром стукнут оптом по всем портам всеми протоколами.
justhabrauser Автор
Кстати, в ответ на Ваш ответ — выписка из
протоколаlogwatch одного из серверов сегодня утром:Не спрашивайте меня кто их синхронизирует и что они забыли на портах вида 56789.