1. Архитектура Netfilter и фундаментальные принципы работы iptables
Архитектура Netfilter и фундаментальные принципы работы iptables
Когда администратор вводит в консоли команду iptables -A INPUT -s 192.168.1.50 -j DROP, система мгновенно перестает отвечать на пинги с указанного адреса. Возникает иллюзия, что утилита iptables постоянно висит в оперативной памяти, перехватывает сетевой трафик, анализирует IP-адреса и уничтожает неугодные пакеты. Это одно из самых глубоких и распространенных заблуждений в системном администрировании. Утилита iptables не фильтрует ни одного байта трафика. Она вообще не работает с сетью напрямую. Если удалить исполняемый файл /sbin/iptables с сервера сразу после применения правил, сервер продолжит безупречно блокировать трафик.
Чтобы получить осознанный контроль над сетевой безопасностью Linux, необходимо разрушить монолитное восприятие «файрвола» и разделить его на два фундаментально разных компонента: инфраструктуру внутри ядра операционной системы и пользовательский интерфейс управления.
Пространство ядра и пространство пользователя
Сетевой стек Linux — это сложный конвейер внутри ядра (kernel-space), который принимает электрические сигналы от сетевой карты, собирает их в кадры Ethernet, извлекает IP-пакеты, проверяет контрольные суммы и передает данные приложениям. Долгое время этот конвейер был закрытым: пакет либо достигал цели, либо отбрасывался из-за сетевых ошибок.
!Расти Рассел, создатель архитектуры Netfilter
В конце 1990-х годов разработчик Расти Рассел (Rusty Russell) спроектировал и внедрил в ядро Linux архитектуру Netfilter. Идея заключалась в том, чтобы сделать сетевой стек расширяемым. Netfilter — это набор специальных точек перехвата (хуков), аккуратно врезанных в исходный код сетевого стека ядра. Когда пакет проходит через такую точку, ядро приостанавливает его нормальное движение и проверяет, не зарегистрированы ли для этой точки какие-либо правила фильтрации или модификации. Если правила есть, ядро выполняет их, а затем (если пакет не был уничтожен) возвращает его на конвейер.
Утилита iptables — это всего лишь программа в пользовательском пространстве (user-space). Ее единственная задача — транслировать понятные человеку команды (с ключами -A, -p, -j) в бинарный формат и передать их ядру через системные вызовы. Как только ядро приняло эти правила и разместило их в своей памяти, работа iptables завершается. Всю тяжелую работу по побайтовому сравнению заголовков пакетов на скорости в миллионы пакетов в секунду выполняет ядро Linux посредством фреймворка Netfilter.
Анатомия перехвата: Пять хуков Netfilter
Сетевой пакет не материализуется в системе случайным образом. Он всегда имеет вектор движения. Пакет может прийти извне и предназначаться локальному процессу (например, веб-серверу Nginx). Он может быть сгенерирован самим Nginx и отправлен наружу. Либо сервер может выступать в роли маршрутизатора, принимая пакет на одном интерфейсе и отправляя через другой.
Чтобы контролировать трафик на всех этапах, Netfilter предоставляет ровно пять точек перехвата (хуков) для протокола IPv4. Понимание их физического расположения в коде ядра — ключ к диагностике любых сетевых проблем.
NF_INET_PRE_ROUTING (Предварительная маршрутизация). Это первая точка, в которую попадает любой входящий пакет сразу после того, как ядро убедилось, что пакет не поврежден. На этом этапе ядро еще не знает, кому предназначен пакет — локальной машине или другой сети. Это идеальное место для подмены адреса назначения (DNAT), чтобы направить пакет по новому пути до того, как система начнет искать маршрут.NF_INET_LOCAL_IN (Локальный вход). Если после этапа PRE_ROUTING таблица маршрутизации ядра определяет, что IP-адрес назначения пакета принадлежит одному из локальных интерфейсов сервера, пакет направляется вверх по стеку к приложениям. Прямо перед тем, как отдать данные приложению, срабатывает этот хук. Здесь происходит 90% блокировок входящего мусорного трафика.NF_INET_FORWARD (Пересылка). Если сервер настроен как маршрутизатор (включен ip_forward), а IP-адрес назначения пакета принадлежит другой сети, пакет направляется транзитом. Он минует локальные приложения и попадает в этот хук. Пакеты, проходящие через FORWARD, никогда не попадают в LOCAL_IN или LOCAL_OUT.NF_INET_LOCAL_OUT (Локальный выход). Когда локальное приложение (например, утилита curl или база данных, отвечающая на запрос) генерирует новый пакет для отправки в сеть, он первым делом попадает в этот хук.NF_INET_POST_ROUTING (Пост-маршрутизация). Это последняя точка перед тем, как пакет будет передан драйверу сетевой карты для отправки в кабель. Сюда стекаются как транзитные пакеты (после FORWARD), так и локально сгенерированные (после LOCAL_OUT). Здесь ядро уже точно знает, через какой интерфейс уходит пакет, что делает этот хук единственно верным местом для подмены адреса источника (SNAT и Masquerade).!Схема расположения хуков Netfilter в сетевом стеке ядра Linux
Критически важный архитектурный элемент, вокруг которого строятся хуки — это Routing Decision (Решение о маршрутизации). В сетевом стеке оно принимается дважды:
PRE_ROUTING. Ядро смотрит на Destination IP и решает: отправить пакет наверх (в LOCAL_IN) или насквозь (в FORWARD).LOCAL_OUT. Когда локальный процесс создает пакет, ядро должно определить, через какой сетевой интерфейс его выпустить, чтобы он достиг цели.Таблицы и Цепочки: Матрица обработки
Хуки ядра — это точки вмешательства. Но как организовать сами правила? Если свалить тысячи правил в одну кучу на каждом хуке, ядро будет тратить слишком много процессорного времени на их перебор. Для структурирования логики iptables вводит абстракции: Таблицы (Tables) и Цепочки (Chains).
Цепочки (Chains)
Цепочка — это прямой пользовательский аналог хука Netfilter. Их названия пишутся в верхнем регистре и жестко привязаны к точкам перехвата:NF_INET_PRE_ROUTING Цепочка PREROUTINGNF_INET_LOCAL_IN Цепочка INPUTNF_INET_FORWARD Цепочка FORWARDNF_INET_LOCAL_OUT Цепочка OUTPUTNF_INET_POST_ROUTING Цепочка POSTROUTINGТаблицы (Tables)
Таблица — это группировка правил по их назначению. Разные задачи требуют вмешательства на разных этапах, поэтому iptables предоставляет пять независимых таблиц:Пересечение таблиц и цепочек
Главная сложность iptables, вызывающая ступор у новичков — это понимание того, что не каждая таблица существует в каждой цепочке. Архитектура Netfilter строго регламентирует, где какая операция имеет смысл.
Например, таблица filter существует только в цепочках INPUT, FORWARD и OUTPUT. Попытка написать правило фильтрации в цепочке PREROUTING завершится синтаксической ошибкой. Почему? Потому что на этапе PREROUTING ядро еще не приняло решение о маршрутизации. Оно не знает, предназначен ли пакет самому серверу или подлежит транзиту. Фильтровать трафик до понимания его вектора — архитектурно неверно.
С другой стороны, таблица nat для подмены адреса назначения (DNAT) доступна в цепочке PREROUTING, но недоступна в INPUT. Если вы хотите пробросить порт, вы обязаны сделать это до принятия решения о маршрутизации, иначе ядро отбросит пакет, адресованный на закрытый порт, еще до того, как вы попытаетесь его перенаправить.
!Интерактивная трассировка пакета через таблицы и цепочки iptables
Анатомия правила: Критерии и Действия
Каждое правило в iptables, помещенное в конкретную таблицу и цепочку, состоит из двух логических частей: Match (Критерий совпадения) и Target (Действие).
Критерии (Matches)
Критерий описывает, как должен выглядеть пакет, чтобы правило сработало. Ядро считывает заголовки пакета и сравнивает их с заданными параметрами. Критерии могут быть:-p tcp), IP источника (-s 10.0.0.5), IP назначения (-d 8.8.8.8), входящий интерфейс (-i eth0).--dport 80), состояние соединения (-m state --state ESTABLISHED), лимиты скорости (-m limit --limit 10/sec), совпадение по содержимому пакета (-m string).Если в правиле не указан ни один критерий (например, iptables -t filter -A INPUT -j DROP), оно становится абсолютным и применяется к любому пакету, попавшему в эту цепочку.
Действия (Targets)
Если пакет полностью совпал со всеми критериями правила, выполняется действие, указанное ключом-j (от слова "jump" — прыжок). Действия делятся на две критически важные категории: завершающие и незавершающие.Завершающие действия (Terminating Targets) немедленно прекращают прохождение пакета по текущей цепочке.
ACCEPT: Пакет признан легитимным. Он немедленно покидает текущую цепочку и передается дальше по конвейеру Netfilter. Ядро больше не проверяет его по нижестоящим правилам в этой цепочке.DROP: Пакет молча уничтожается. Ядро освобождает память, выделенную под пакет, и не отправляет отправителю никаких уведомлений. Для отправителя это выглядит как черная дыра — запрос просто уходит в таймаут.REJECT: Пакет уничтожается, но ядро активно формирует и отправляет отправителю ICMP-ответ (например, "Destination Port Unreachable"). Это вежливый отказ, который позволяет приложению на стороне клиента сразу закрыть соединение, а не ждать таймаута.Незавершающие действия (Non-terminating Targets) выполняют операцию, но заставляют пакет продолжить движение по правилам ниже.
LOG: Записывает информацию о пакете в системный журнал ядра (dmesg/syslog). Пакет при этом не блокируется и переходит к следующему правилу.MARK: Устанавливает внутреннюю метку на пакет для дальнейшей обработки утилитой iproute2.Линейная обработка и Политика по умолчанию
Фундаментальный принцип работы iptables — строго последовательная, линейная проверка правил сверху вниз. Вычислительная сложность этого процесса составляет , где — количество правил в цепочке.
Представьте цепочку INPUT таблицы filter, в которой 1000 правил. Поступает пакет. Ядро берет первое правило и проверяет критерии. Если совпадения нет, ядро переходит ко второму правилу. Если пакет совпадает с критериями на 500-м правиле и действие — DROP, пакет уничтожается, а правила с 501 по 1000 даже не рассматриваются.
Именно поэтому порядок правил имеет критическое значение. Если первым правилом в цепочке стоит блокировка всей подсети (-s 192.168.1.0/24 -j DROP), а вторым — разрешение для конкретного администраторского IP из этой же подсети (-s 192.168.1.50 -j ACCEPT), администратор никогда не получит доступ. Пакет будет уничтожен на первом же шаге.
Но что происходит, если пакет прошел через все 1000 правил в цепочке, и ни одно из них не подошло? Здесь вступает в игру Default Policy (Политика по умолчанию). Каждая стандартная цепочка имеет базовую политику, которая применяется к пакету, «выпавшему» из конца списка. Обычно это ACCEPT (разрешить все, что явно не запрещено) или DROP (запретить все, что явно не разрешено). Настройка политики по умолчанию в DROP для цепочек INPUT и FORWARD — это нулевой шаг в построении концепции "Default Deny" (запрет по умолчанию), на которой базируется безопасность любого современного сервера.
Понимание того, как Netfilter врезается в ядро, как таблицы пересекаются с цепочками и как пакет линейно проваливается сквозь списки правил до первого завершающего действия или политики по умолчанию, переводит администрирование iptables из слепого копирования команд в инженерный процесс. Это знание позволяет не просто писать правила, но и мысленно трассировать путь любого байта через сетевой стек операционной системы.