Simple stateful firewall (Русский)

From ArchWiki
Revision as of 11:29, 8 October 2019 by Duodai (talk | contribs) (update 'TranslationStatus' template)
Jump to navigation Jump to search
Состояние перевода: На этой странице представлен перевод статьи Simple stateful firewall. Дата последней синхронизации: 8 октября 2019. Вы можете помочь синхронизировать перевод, если в английской версии произошли изменения.

В этой статье рассмотрена настройка простого межсетевого экрана с контекстной фильтрацией (stateful firewall) посредством iptables, с описанием основных правил и их назначения. Статья разбита на две части. В первой объяснена настройка межсетевого экрана на одиночной машине, во второй — настройка NAT-шлюза в дополнение к файрволу.

Важно: Описанные ниже правила даны в порядке их выполнения, такая настройка возможна только при локальном входе в систему. Если вы вошли в систему удалённо, то в процессе установки правил соединение с ней будет потеряно. Чтобы обойти эту проблему, воспользуйтесь готовым файлом настроек.

Требования

Примечание: Ядро Linux на вашей машине должно быть скомпилировано с поддержкой iptables. Во всех стандартных ядрах Arch Linux поддержка iptables включена.

В первую очередь установите набор утилит iptables или убедитесь, что он уже установлен.

В этой статье предполагается, что у вас нет действующего набора правил iptables. Чтобы проверить это, выполните:

# iptables-save
# Generated by iptables-save v1.4.19.1 on Thu Aug  1 19:28:53 2013
*filter
:INPUT ACCEPT [50:3763]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [30:3472]
COMMIT
# Completed on Thu Aug  1 19:28:53 2013

или

# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 156 packets, 12541 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 82 packets, 8672 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Если всё же найдены какие-то правила, вы можете сбросить их и загрузить базовый набор правил:

# iptables-restore < /etc/iptables/empty.rules

Информацию о других способах сброса правил можно найти в статье Iptables (Русский)#Сброс правил.

Межсетевой экран для одиночной машины

Примечание: Поскольку iptables проверяет правила в цепочке последовательно, сверху вниз, то имеет смысл переместить часто срабатывающие правила ближе к её началу. Разумеется, этот подход имеет свои ограничения, в зависимости от реализуемой логики. Кроме того, поскольку правила имеют определённую стоимость выполнения, не стоит изменять их порядок исключительно на основе эмпирических наблюдений за счётчиком байт/пакетов.

Создание неоходимых цепочек

Создадим две пользовательские цепочки, которые будут использоваться для открытия портов.

# iptables -N TCP
# iptables -N UDP

В дальнейшем при назначений правил для этих цепочек мы будем всякий раз указывать тип протокола (например, добавив флаг -p tcp). Этим обусловлен выбор названий цепочек, но вообще говоря, названия могут быть любыми.

Цепочка FORWARD

Если вы хотите настроить свою систему в качестве NAT-шлюза, изучите раздел #Настройка NAT-шлюза. Для одиночной же системы можно для цепочки FORWARD ограничиться назначением политики DROP:

# iptables -P FORWARD DROP

Цепочка OUTPUT

Поскольку фильтрация исходящих пакетов нас в данном случае не интересует, да и настраивается она достаточно сложно, для цепочки OUTPUT назначаем политику ACCEPT.

# iptables -P OUTPUT ACCEPT

Цепочка INPUT

Назначаем политику DROP для цепочки INPUT на случай, если что-то каким-то образом проскочит мимо наших правил. Лучший способ создать надёжный файрвол — запретить весь трафик, отдельно указав то, что разрешено.

# iptables -P INPUT DROP
Важно: Если вы вошли в систему через SSH, этот шаг немедленно разорвёт SSH-сессию. Чтобы этого избежать: (1) сперва добавьте цепочку правил INPUT из следующего примера (это позволит сохранить существующее соединение), (2) добавьте обычное правило, разрешающее входящее SSH-подключение (чтобы иметь возможность восстановить соединение в случае потери связи) и (3) настройте политику, как предложено выше.

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

Первое правило цепочки INPUT будет разрешать трафик установленных соединений и любой новый трафик, относящийся к ним, например, сообщения ICMP об ошибке или эхо-ответы (пакеты, которые хост возвращает, когда его пингуют). ICMP — протокол управляющих сообщений (Internet Control Message Protocol). Некоторые сообщения ICMP имеют важное значение для управления перегрузками и определения MTU, и мы разрешаем их этим правилом:

# iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Состояние соединения ESTABLISHED подразумевает одну из двух ситаций: либо первичная (--ctstate NEW) попытка соединения была одобрена ранее другим правилом, либо соединение уже было активно (например, удалённое SSH-подключение) на момент задания правила.

Второе правило разрешит весь трафик от петлевого (loopback) интерфейса, который необходим многим приложениям и службам:

# iptables -A INPUT -i lo -j ACCEPT
Примечание: Вы можете добавить другие интерфейсы (например, "enp2s0") в список доверенных, если не желаете, чтобы какая-то часть трафика фильтровалась файрволом; но имейте в виду, что если NAT настроен перенаправлять весь трафик из любого места сети (скажем, от маршрутизатора) к этому интерфейсу, то он пройдет мимо всех настроек, которые вы сделали.

Третье правило будет отбрасывать все пакеты с состоянием INVALID. Существует четыре категории состояния (state): NEW, ESTABLISHED, RELATED и INVALID. Именно наличие категорий отличает межсетевой экран с контекстной фильтрацией от менее безопасного экрана без неё. Состояния отслеживаются посредством модулей ядра nf_conntrack_*, которые загружаются автоматически после добавления правил.

# iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
Примечание:
  • Это правило будет отбрасывать все пакеты с неверными заголовками или контрольными суммами, неверными флагами TCP, неправильными ICMP-сообщениями (например, входящее сообщение "порт недостижим", если мы не посылали ничего другому хосту), а также пакеты без очереди, которые могут быть результатом попыток угадывания последовательности или схожих атак. Политика DROP означает отбрасывание пакетов безо всякого ответа, в то время как REJECT отклоняет их вежливо, с уведомлением отправителя. Мы используем DROP, поскольку нет подходящего ответа REJECT для INVALID-пакетов и мы не хотим подтверждать их получение.
  • Пакеты протокола обнаружения соседей ICMPv6 остаются неотслеживаемыми и всегда классифицируются как INVALID, хотя они по всем параметрам являются годными. Следует иметь это в виду и разрешить их перед предыдущим правилом командой iptables -A INPUT -p 41 -j ACCEPT.

Следующее правило разрешает все новые входящие ICMP эхо запросы (ECHO_REQUEST), также известные как ping. Только первый пакет будет считаться относящимся к категории NEW, остальные будут обрабатываться правилом "RELATED, ESTABLISHED". Если компьютер не является маршрутизатором, нет необходимости разрешать какой-либо другой ICMP-трафик с состоянием NEW.

# iptables -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT

Теперь мы прикрепим TCP- и UDP-цепочки к цепочке INPUT для обработки всех новых входящих соединений. Если соединение разрешено цепочкой TCP или UDP, оно обрабатывается правилом "RELATED, ESTABLISHED". TCP или UDP цепочки будут либо разрешать новые входящие соединения, либо вежливо отклонять их. Новые TCP соединения должны начинаться с SYN-сегмента.

# iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
# iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
Примечание: NEW-соединение, начинающееся не с SYN-сегмента — единственный неверный флаг для протокола TCP, который не описывается состоянием INVALID. Это связано с тем, что данные пакеты редко бывают вредоносными и нет смысла просто их отбрасывать (drop). Вместо этого они отклоняются (reject) с сообщением TCP RESET в соответствии со следующим правилом.

Мы отклоняем TCP-соединения пакетами TCP RESET, а UDP-потоки — сообщениями ICMP "port unreachable", если запрашиваемый порт закрыт. Это имитирует поведение Linux по умолчанию (в соответствии с RFC), и позволяет отправителю быстро закрыть соединение.

# iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
# iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset

Для других протоколов мы добавляем последнее правило в цепочку INPUT, чтобы отклонить остальной входящий трафик с ICMP-сообщением "protocol unreachable". Это также соответствует поведению Linux по умолчанию.

# iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable

Итоговый файл iptables.rules

Пример файла iptables.rules после выполнения всех команд, описанных выше:

/etc/iptables/iptables.rules
# Generated by iptables-save v1.4.18 on Sun Mar 17 14:21:12 2013
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:TCP - [0:0]
:UDP - [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
COMMIT
# Completed on Sun Mar 17 14:21:12 2013

Файл генерируется и сохраняется командой

# iptables-save -f /etc/iptables/iptables.rules

Данный файл конфигурации можно использовать как исходный для дальнейших настроек в следующих разделах. Если вы настраиваете межсетевой экран удалённо через SSH, перед продолжением добавьте правило, разрешающее новые SSH-подключения (вместо порта 22 можно выбрать нужный):

-A TCP -p tcp --dport 22 -j ACCEPT

Цепочки TCP и UDP

Цепочки TCP и UDP содержат правила для разрешения новых TCP-соединений и UDP-потоков к определённым портам.

Примечание: Также в эти цепочки можно добавлять правила для разрешения удалённых соединений, таких как SSH, HTTP и других служб, к которым вы желаете получить удалённый доступ.

Открытие портов для входящих соединений

Разрешить входящие TCP-соединения на порт 80 для веб-сервера (HTTP):

# iptables -A TCP -p tcp --dport 80 -j ACCEPT

Разрешить входящие TCP-соединения на порт 443 для веб-сервера (HTTPS):

# iptables -A TCP -p tcp --dport 443 -j ACCEPT

Разрешить удаленные SSH-соединения (на порт 22):

# iptables -A TCP -p tcp --dport 22 -j ACCEPT

Разрешить входящие TCP/UDP запросы для DNS-сервера (порт 53):

# iptables -A TCP -p tcp --dport 53 -j ACCEPT
# iptables -A UDP -p udp --dport 53 -j ACCEPT

Более сложные правила, вроде проверки по нескольким портам, можно найти в iptables(8).

Port knocking

Port knocking — способ открыть извне порты, которые файрвол по умолчанию держит закрытыми. Принцип работы port knocking заключается в создании последовательности попыток соединений с заранее выбранными закрытыми портами. При получении корректной последовательности "простукиваний" межсетевой экран открывает определенный порт и разрешает соединение. Подробная информация дана в статье Port knocking.

Защита от спуфинга

Примечание: В настоящее время параметру rp_filter в файле /usr/lib/sysctl.d/50-default.conf по умолчанию присвоено значение 2, поэтому в описанных ниже действиях нет необходимости.

Блокировка пришедших из внешней сети пакетов с локальным адресом отправителя (что говорит о подмене адреса, address spoofing), производится посредством встроенной в ядро Linux проверки. Добавьте следующую строку в файл /etc/sysctl.d/90-firewall.conf (подробную информацию можно найти в статье sysctl):

net.ipv4.conf.all.rp_filter=1

То же самое можно сделать посредством netfilter, если необходимо ведение статистики и лог-файлов:

# iptables -t raw -I PREROUTING -m rpfilter --invert -j DROP
Примечание: Включать эту функцию одновременно в двух местах не нужно. Реализованная в netfilter проверка вполне удовлетворительна и, кроме того, работает с адресами IPv6.

Для случая асинхронной маршрутизации нужно использовать опцию sysctl rp_filter=2. Добавление флага --loose к модулю rpfilter сделает то же самое посредством netfilter.

Защита от обнаружения

Если вы хотите сделать вашу машину менее заметной в сети, хорошей идеей будет блокировать некоторые входящие запросы.

Блокирование ping-запросов

Запрос "ping" представляет собой ICMP-пакет, посланный с целью убедиться, что между двумя хостами есть связь. Если сеть в порядке, вы можете безопасно блокировать все ping-запросы. Нужно отметить, что это не сделает ваш компьютер необнаружимым — каждый входящий пакет будет отклоняться, поэтому вы всё ещё будете видны при простом "ping-сканировании" по диапазону IP-адресов посредством nmap. Кроме того, нужно иметь в виду, что эта элементарная "защита" усложнит вам жизнь случае возникновения необходимости отладки сети.

Чтобы заблокировать эхо-запросы (echo requests), добавьте следующую строку в файл /etc/sysctl.d/90-firewall.conf (подробную информацию можно найти в статье sysctl):

net.ipv4.icmp_echo_ignore_all = 1

Больше сведений об этой защите вы найдёте в руководстве iptables(8), а также в документации и примерах на странице http://www.snowman.net/projects/ipt_recent/

Обман сканеров портов

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

Состояние INVALID в правилах iptables "позаботится" обо всех типах сканирования, за исключением сканирований UDP, ACK и SYN (флаги nmap -sU, -sA и -sS соответственно).

ACK-сканирование не используется для определения открытых портов, но зато покажет порты, защищённые межсетевым экраном. Подобно SYN-пакету в TCP-соединениях с состоянием NEW, каждый пакет ACK-сканирования будет отклонен с отправкой ответа TCP RESET по обратному адресу. Некоторые межсетевые экраны вместо этого просто отбрасывают такие пакеты, что позволяет атакующему определить действующие правила.

Модуль recent поможет обмануть остальные типы сканирования портов. Он добавляет хосты к списку недавних соединений, который используется для обнаружения и блокирования попыток атак. Просмотреть списки недавних соединений можно в каталоге /proc/net/xt_recent/.

Примечание: Использование модуля resent для защиты от сканирований может привести к тому, что:
  • Система станет уязвимой к разновидности DoS-атаки. Атакующий посылает пакеты с подменёными IP-адресами, чтобы добиться их блокировки вашими службами.
  • Может оказаться заблокированным обычный IP-адрес, если несколько пакетов с этого адреса на порт получателя будут признаны INVALID модулем conntrack. Чтобы избежать занесения в чёрный список, следует разрешить все пакеты, поступающие на этот порт.
SYN-сканирование

При SYN-сканировании сканер портов посылает синхронизационные пакеты на каждый порт с целью создать TCP-соединение. Если порт закрыт, то возвращается ответ TCP RESET, межсетевой экран просто отбрасывает входящий пакет, а открытый порт возвращает ответ SYN ACK.

Модуль recent может использоваться для отслеживания хостов с отклонёнными попытками соединения и возвращения ответа TCP RESET для каждого SYN-пакета, поступившего на открытый порт, как если бы порт был закрыт. Если открытый порт оказался первым в порядке сканирования, то будет возвращён ответ SYN ACK, поэтому приложения вроде ssh следует размещать на нестандартных портах.

Сначала добавьте правило в начало цепочки TCP. Это правило будет отвечать пакетом TCP RESET любому хосту, входившему в список TCP-PORTSCAN в течение последних 60 секунд. Флаг --update управляет периодическим обновлением списка.

# iptables -I TCP -p tcp -m recent --update --rsource --seconds 60 --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset

Затем необходимо модифицировать правило отклонения TCP-пакетов, чтобы добавлять все хосты с отклонёнными пакетами к списку TCP-PORTSCAN:

# iptables -D INPUT -p tcp -j REJECT --reject-with tcp-reset
# iptables -A INPUT -p tcp -m recent --set --rsource --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
UDP-сканирование

Сканирование UDP схоже со сканированием TCP SYN за исключением того факта, что UDP является протоколом без установления соединения. В нём нет "рукопожатий" и подтверждений. Вместо этого сканер посылает UDP-пакеты на каждый UDP-порт. Закрытые порты должны возвращать сообщение ICMP port unreachable, а открытые не возвращают ничего. Поскольку UDP — "ненадежный" протокол, у сканера нет возможности узнать о потере пакетов, поэтому он посылает серию запросов на каждый порт, с которого не вернулся ответ.

Ядро Linux посылает сообщения ICMP port unreachable довольно медленно, поэтому продолжительность полного UDP-сканирования может превысить 10 часов. Однако часто используемые порты проверяются гораздо быстрее, поэтому хорошей идеей будет применить контрмеры, аналогичные защите от SYN-сканирований.

Сначала добавляем правило отклонения пакетов от хостов из списка UDP-PORTSCAN в начало цепочки UDP:

# iptables -I UDP -p udp -m recent --update --rsource --seconds 60 --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable

Затем модифицируем правило отклонения пакетов для UDP:

# iptables -D INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
# iptables -A INPUT -p udp -m recent --set --rsource --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
Восстановление последнего правила

Если вы применили хотя бы один из способов защиты выше, бывшее последним правило цепочки INPUT более таковым не является. Теперь оно находится перед правилами защиты от сканирования и те по сути бесполезны. Просто удалите (-D) это правило, а затем добавьте его снова (-A), это переместит его в конец цепочки.

# iptables -D INPUT -j REJECT --reject-with icmp-proto-unreachable
# iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable

Защита от других типов атак

В статье sysctl#TCP/IP stack hardening можно найти описание важных с точки зрения безопасности параметров ядра.

Атака полным перебором

Доступные по внешнему IP-адресу сервисы подвергаются атакам полным перебором довольно часто. Реализовать атаку этого типа несложно, а инструментарий — обширен и доступен. К счастью, существует несколько способов защиты от атак полным перебором. Первый способ заключается в создании правил iptables, которые заносят IP-адрес в чёрный список после нескольких попыток установить соединение. При втором способе защиты запускается специализированный демон, который отслеживает лог-файл на предмет неудачных попыток соединения.

Важно: Защита посредством занесения адресов в чёрный список остановит простые атаки, но она полагается на дополнительный демон и успешное логирование (в случае мощной атаки может закончиться свободное место разделе, содержащем каталог /var с лог-файлами). Кроме того, узнав ваш IP-адрес, атакующий может посылать пакеты с подменённым адресом отправителя, чтобы добиться вашей блокировки. Элегантное решение этой проблемы заключается в использовании ключей SSH.

Приложения Fail2ban и (в случае sshd) Sshguard используются для блокировки IP-адресов при превышении допустимого количества попыток аутентификации. Суть их работы состоит в обновлении правил iptables с целью временно или навсегда воспрепятствовать будущим соединениям атакующих.

Ниже представлен пример правил iptables для предотвращения атак полным перебором на сервис SSH.

# iptables -N IN_SSH
# iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH
# iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 3 --seconds 10 -j DROP
# iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 4 --seconds 1800 -j DROP 
# iptables -A IN_SSH -m recent --name sshbf --set -j ACCEPT

Большая часть правил очевидна: первое разрешает три попытки соединения в течение 10 секунд, после чего дальнейшие попытки будут отклоняться. Второе — добавляет ограничение на четыре попытки в течение получаса. Дело в том, что атаки полным перебором обычно выполняются медленно и за несколько серий попыток. Дополнительную информацию об этих правилах и их опциях можно найти в оригинальной статье на сайте compilefailure.blogspot.com.

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

Необходимо также убедиться, что правило -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH находится в верной позиции в последовательности iptables, перед точкой прикрепления цепочки TCP к цепочке INPUT. Это позволит успешно перехватывать новые попытки установления SSH-соединений. Если вы выполнили все предыдущие шаги в этой статье, порядок правил должен быть следующим:

...
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j IN_SSH
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
...
Совет: При проверке правил после настройки реальное занесение в чёрный список может замедлить тесты, что усложнит тонкую настройку. Входящие попытки соединений можно отслеживать посредством команды cat /proc/net/xt_recent/sshbf. Чтобы разблокировать собственный IP-адрес во время тестирования, вам понадобятся права root: # echo / > /proc/net/xt_recent/sshbf.

IPv6

Если вы не используете протокол IPv6, то лучше будет его отключить. В противном случае стоит создать соответствующий набор правил межсетевого экрана.

Скопируйте созданные ранее правила для протокола IPv4 и замените все IPv4-адреса на адреса формата IPv6:

# cp /etc/iptables/iptables.rules /etc/iptables/ip6tables.rules

Некоторые правила нужно адаптировать под IPv6. Так, для IPv6 используется обновлённая версия протокола ICMP, и коды ответов при отклонении соединений --reject-with icmp-port-unreachable и --reject-with icmp-proto-unreachable необходимо преобразовать в коды ICMPv6.

Коды ошибок ICMPv6 перечислены в RFC 4443, согласно которому при блокировке межсетевым экраном попыток установления соединения необходимо использовать код --reject-with icmp6-adm-prohibited. Это проинформирует удалённую систему о том, что соединение было отклонено брандмауэром, а не прослушивающей порт службой.

Если уведомлять удалённую систему о наличии файрвола нежелательно, то можно отклонить пакет без сообщения:

 -A INPUT -j REJECT

Отклонение пакетов по этому правилу будет производиться с сообщением об ошибке --reject-with icmp6-port-unreachable. Следует однако отметить, что одной из основных функций приложений-сканеров является как раз обнаружение межсетевых экранов и обмануть их этим правилом не получится.

Tango-view-fullscreen.pngThis article or section needs expansion.Tango-view-fullscreen.png

Reason: Какие особенности ICMPv6 нужно добавить, чтобы привести правила в полное соответствие с правилами IPv4? (Discuss in Talk:Simple_stateful_firewall#ICMP blocking)

Следующее правило для протокола IPv6 настроит поведение межсетевого экрана по отношению к новым входящим пингам (ICMP echo requests):

# ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT

Модуль conntrack не отслеживает действия ICMPv6 Neighbor Discovery Protocol (аналог протокола ARP), поэтому необходимо разрешить трафик ICMPv6 вне зависимости от его состояния для всех прилежащих подсетей. Следующее правило нужно вставить после правила отбрасывания некорректных пакетов --ctstate INVALID, но перед любыми другими правилами DROP или REJECT. Создаётся по одному правилу на каждую подсеть:

# ip6tables -A INPUT -s fe80::/10 -p ipv6-icmp -j ACCEPT

Поскольку в ядре Linux нет встроенной фильтрации по обратному маршруту (reverse path filter) для протокола IPv6, то стоит включить её посредством ip6tables:

# ip6tables -t raw -A PREROUTING -m rpfilter -j ACCEPT
# ip6tables -t raw -A PREROUTING -j DROP

Сохранение правил

Набор правил межсетевого экрана завершён и осталось только сохранить его в файл, который будет загружаться при каждом запуске системы.

Сохраняем правила IPv4 и IPv6 командами:

# iptables-save -f /etc/iptables/iptables.rules
# ip6tables-save -f /etc/iptables/ip6tables.rules

Итоговый файл ip6tables.rules

Пример файла правил ip6tables.rules после выполнения представленных выше команд:

/etc/iptables/ip6tables.rules
# Generated by ip6tables-save v1.8.2 on Sat Apr 20 10:53:41 2019
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:TCP - [0:0]
:UDP - [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -s fe80::/10 -p ipv6-icmp -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p udp -j REJECT --reject-with icmp6-adm-prohibited
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp6-adm-prohibited
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT
COMMIT
# Completed on Sat Apr 20 10:53:41 2019

В завершение включите и запустите службы iptables.service и ip6tables.service. Проверьте статус служб, чтобы убедиться, что правила загрузились корректно.

Настройка NAT-шлюза

В этом разделе рассмотрена настройка межсетевого экрана для NAT-шлюза. Предполагается, что вы уже прочитали первую часть данного руководства и настроили цепочки INPUT, OUTPUT, TCP и UDP как было предложено. До этого момента созданные правила относились к таблице filter, при настройке NAT-шлюза нам также понадобится таблица nat.

Таблица filter

Создание необходимых цепочек

Создадим две новые цепочки — fw-interfaces и fw-open:

# iptables -N fw-interfaces
# iptables -N fw-open

Цепочка FORWARD

Настройка цепочки FORWARD схожа с настройкой цепочки INPUT в первой части.

Сначала добавляем правило с модулем conntrack, идентичное правилу из цепочки INPUT:

# iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Затем включаем пересылку для доверенных интерфейсов и пропускаем все пакеты через цепочку fw-open:

# iptables -A FORWARD -j fw-interfaces 
# iptables -A FORWARD -j fw-open 

Остальные пакеты блокируются с отправкой ICMP-сообщения:

# iptables -A FORWARD -j REJECT --reject-with icmp-host-unreachable
# iptables -P FORWARD DROP

Цепочки fw-interfaces и fw-open

Назначение цепочек fw-interfaces и fw-open будет объяснено позже, когда мы будем работать с цепочками POSTROUTING и PREROUTING соответственно в таблице nat.

Таблица nat

В этом разделе предполагается, что исходящий интерфейс (с публичным IP-адресом) носит имя ppp0. Если ваш интерфейс называется иначе, то во всех приведённых ниже правилах следует заменить название на настоящее.

Цепочка POSTROUTING

Сначала мы должны определить, кому разрешено подключаться к сети Интернет. Предположим, имеется подсеть 192.168.0.0/24 (т.е. в неё входят все адреса в диапазоне 192.168.0.0-255), подключённая к интерфейсу eth0. Чтобы разрешить исходящие соединения хостам в этой подсети, настраиваем цепочку fw-interfaces в таблице FORWARD:

# iptables -A fw-interfaces -i eth0 -j ACCEPT

Затем необходимо отредактировать все исходящие пакеты, чтобы в поле "адрес отправителя" значился публичный адрес шлюза вместо локального LAN-адреса. Для этого используем таргет MASQUERADE:

# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

Не забудьте указать параметр -o ppp0, потому что в противном случае сеть не будет функционировать.

Предположим, что есть другая подсеть, 10.3.0.0/16 (с адресами 10.3.*.*), подключённая к интерфейсу eth1. Добавляем аналогичные правила:

# iptables -A fw-interfaces -i eth1 -j ACCEPT
# iptables -t nat -A POSTROUTING -s 10.3.0.0/16 -o ppp0 -j MASQUERADE

Наконец, нужно разрешить пересылку пакетов (если она ещё не включена).

Хосты данных подсетей теперь могут использовать вашу NAT-систему в качестве шлюза. Возможно, вы также захотите настроить DNS- и DHCP-сервер, например, dnsmasq или комбинацию BIND и dhcpd, с целью упрощения настройки разрешения имён (DNS resolving) на клиентских машинах, но эта тема выходит за рамки данного руководства.

Цепочка PREROUTING

В некоторых случаях может понадобиться изменить адрес получателя в заголовке входящего пакета с адреса шлюза на адрес хоста в локальной сети. Для этого нужно настроить созданную ранее цепочку fw-open, а также цепочку PREROUTING таблицы nat.

Например, чтобы изменить адрес получателя входящих SSH-пакетов (порт 22) на адрес ssh-сервера 192.168.0.5 выполните команды:

# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 22 -j DNAT --to 192.168.0.5
# iptables -A fw-open -d 192.168.0.5 -p tcp --dport 22 -j ACCEPT

Во втором примере меняется не только адрес получателя, но и порт. Порт входящего соединения 8000 заменяется на порт 80 веб-сервера по адресу 192.168.0.6:

# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to 192.168.0.6:80
# iptables -A fw-open -d 192.168.0.6 -p tcp --dport 80 -j ACCEPT

Настройка для UDP-пакетов производится аналогично.

Сохранение правил

Чтобы сохранить новые правила межсетевого экрана для NAT-шлюза, выполните:

# iptables-save -f /etc/iptables/iptables.rules

При этом поздразумевается, что служба systemd iptables.service уже работает, потому что была включена ранее.

Смотрите также