Назад | Перейти на главную страницу

Как закрыть все _существующие_ TCP-соединения на некоторых портах с помощью IPTables?

Скажем, у меня есть быстрый тест сетевого раздела, который я хотел бы запустить, например отключение двух половин ReDiS кластера друг от друга, и я хочу использовать IPTables для временного отключения одной группы серверов от другой группы.

Это очень похоже на вопрос, заданный в списке рассылки Fedora:

https://www.redhat.com/archives/rhl-list/2006-January/msg03380.html

Если я не увижу EXISTING,RELATED на выходе из iptables --list, мне нужно об этом беспокоиться?

Следующий ответ в списке рассылки Fedora, кажется, говорит, что да, существующие соединения будут закрыты, если я не увижу EXISTING,RELATED на выходе из iptables --list.

https://www.redhat.com/archives/rhl-list/2006-January/msg03396.html

Замечание для рефлексивных флагманов: в этом вопросе и, что более важно, в ответах на него будет обсуждаться, удаляется ли IPTables существующий подключений при обновлении его правил.

Насколько я могу судить, другие вопросы на этом сайте по этой теме не касаются различий между существующими и попытками подключения:

Как закрыть определенные порты TCP / UDP (входящие) для ВСЕХ сетей, кроме перечисленных через IPTABLES

Я нашел большую часть своих результатов поиска в Google на странице по следующей URL-ссылке:

https://duckduckgo.com/?q=iptables+close+existing+connections

Ни одно правило iptables никогда не закроет существующее TCP-соединение, так как оно предполагает активную передачу сообщение с битом FIN. Это делается приложением, а не фильтром пакетов.

С другой стороны, iptables может в любой момент заблокировать ваше приложение от получения или передачи новых пакетов по любому существующему соединению, а также может запретить установление любых новых соединений.

Это независимо от того, есть ли у вас брандмауэр с отслеживанием состояния или нет.

Все зависит от того, куда именно вы вставляете новые правила брандмауэра. Так как, помните, что правила вашего брандмауэра проверяются в том порядке, в котором они перечислены и обработка остановится при первом совпадении диспозитивов.

Т.е. простой межсетевой экран с отслеживанием состояния:

[root@host ~]# iptables-save
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [441:59938]
                     #1  < INSERT NEW RULE HERE
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
                     #2  < INSERT NEW RULE HERE
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
                     #3  < INSERT NEW RULE HERE
-A INPUT -j REJECT --reject-with icmp-host-prohibited
                     #4  < iptables -A WILL APPEND NEW RULE HERE
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

Теперь, если вам нужно новое правило:

INPUT -s 10.0.0.89/32 -j REJECT --reject-with icmp-port-unreachable

и вставьте его в позицию # 1, все пакеты, полученные от этого хоста, будут заблокированы.

Вставьте это правило в позицию # 2, и пакеты по существующим соединениям по-прежнему будут разрешены, но новые соединения не могут быть установлены.

Вставка этого конкретного нового правила в позицию # 3 бесполезна, поскольку эффект такой же, как и отсутствие специальной политики для 10.0.0.89 вообще, но это было бы правильное место для размещения правила для предоставления доступа к 10.0.0.89 дополнительным порты.

И используя iptables -A INPUT к добавить новый правило в цепочку INPUT бесполезно, так как это поместит правило в позицию # 4, где весь трафик уже отклонен INPUT -j REJECT --reject-with icmp-host-prohibited правило.

Вкратце: используйте опцию номера правила в iptables -I (вместо того ipatbles -A), чтобы разместить новое (временное) правило там, где оно будет иметь желаемый эффект:

sudo iptables -I <rule number> INPUT -s 10.0.0.89/32 -j REJECT --reject-with icmp-port-unreachable

Если с той же конфигурацией брандмауэра с отслеживанием состояния вы хотите запретить простой HTTP, вы можете удалить правило, разрешающее трафик на порт 80.

sudo iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT

но это не приведет к очистке таблицы состояний сеанса, используемой iptables, и существующие подключения к порту 80 по-прежнему будут разрешены правилом -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

Вы можете решить эту проблему, просто остановив / перезапустив веб-сервер, который правильно закроет эти открытые сеансы, отправив сообщения FIN и очистив их из таблицы состояний сеансов.

В качестве альтернативы вы можете добавить правило блокировки пакетов на порт 80 в позиции №1.