Опубликован: 22.06.2005 | Уровень: для всех | Доступ: платный | ВУЗ: Компания IBM
Лекция 15:

Сетевые и серверные возможности

< Лекция 14 || Лекция 15: 12345 || Лекция 16 >

Межсетевой экран

В Linux существует мощный механизм анализа сетевых и транспортных пакетов, позволяющий избавляться от нежелательной сетевой активности, манипулировать потоками данных и даже преобразовывать служебную информацию в них. Обычно такие средства носят название "firewall" ("fire wall" – противопожарная стена, брандмауэр), общепринятый русский термин – межсетевой экран. В более старых версиях межсетевого экрана Linux использовался вариант межсетевого экрана ipchains, который впоследствии был заменен на более мощный, iptables.

Суть iptables в следующем. Обработка сетевого пакета системой представляется как его конвейерная обработка. Пакет нужно получить из сетевого интерфейса или от системного процесса, затем следует выяснить предполагаемый маршрут этого пакета, после чего отослать его через сетевой интерфейс либо отдать какому-нибудь процессу, если пакет предназначался нашему компьютеру. Налицо три конвейера обработки пакетов: "получить – маршрутизировать – отослать" (действие маршрутизатора ), "получить – маршрутизировать – отдать" (действие при получении пакета процессом) и "взять – маршрутизировать – отослать" (действие при отсылке пакета процессом).

Между каждыми из этих действий системы помещается модуль межсетевого экрана, именуемый цепочкой. Цепочка обрабатывает пакет, исследуя, изменяя и даже, возможно, уничтожая его. Если пакет уцелел, она передает его дальше по конвейеру. В этой стройной схеме есть два исключения. Во-первых, ядро Linux дает доступ к исходящему пакету только после принятия решения о его маршрутизации, поэтому связка "взять – маршрутизировать" остается необработанной, а цепочка, обрабатывающая исходящие пакеты (она называется OUTPUT) вставляется после маршрутизации. Во-вторых, ограничения на "чужие" пакеты, исходящие не от нас и не для нас предназначенные, существенно отличаются от ограничений на пакеты "свои", поэтому после маршрутизации транзитные пакеты обрабатываются еще одной цепочкой (она называется FORWARD ). Цепочка, обслуживающая связку "получить – маршрутизировать", называется PREROUTING, цепочка, обслуживающая связку "маршрутизировать – отдать" – INPUT, а цепочка, стоящая непосредственно перед отсылкой пакета – POSTROUTING:

В варианте ipchains каждая цепочка представляла собой таблицу правил. В правиле задаются свойства пакета и действие, которое нужно выполнять со всеми пакетами, обладающими указанными свойствами. Когда пакет попадает в таблицу, к нему начинают последовательно применяться правила.

Обработка пакетов цепочками iptables

Рис. 15.1. Обработка пакетов цепочками iptables
Если пакет не имеет свойств, требуемых первым правилом, к нему применяется второе, если второе также не подходит – третье, и так вплоть до последнего, правила по умолчанию, которое применяется к любому пакету. Если свойства пакета удовлетворяют правилу, над ним совершается действие. Действие DROP уничтожает пакет, а действие ACCEPT немедленно выпускает его из таблицы, после чего пакет движется дальше по конвейеру. Некоторые действия, например LOG, никак не влияют на судьбу пакета, после их выполнения он остается в таблице: к нему применяется следующее правило, и т. д. до ACCEPT или DROP.

Из сказанного выше следует, что действия ACCEPT или DROP в каждой таблице могут применяться к пакету лишь однократно. Для большей гибкости цепочки iptables состоят из нескольких (двух-трех) таблиц. Выходя "живым" из одной таблицы, пакет попадает в следующую, а уж последняя передает его, если завершается действием ACCEPT, на конвейер. Хотя таблицы функционально одинаковы, принято использовать их по разному назначению. Таблицу mangle используют для внесения исправлений в служебную информацию пакета, таблицу filter – для определения того, не стоит ли пакет уничтожить, а таблицу nat – для подмены сетевых адресов. В приведенной выше диаграмме буквами M, N и F отмечено, какие именно таблицы есть в цепочках и в каком порядке их проходит пакет.

Для просмотра правил во всех таблицах всех цепочек iptables можно воспользоваться командой iptables-save:

[root@sakura root]# iptables-save
# Generated by iptables-save v1.2.11 on Fri Dec 24 21:06:12 2004
*nat
:PREROUTING ACCEPT [1:261]
:POSTROUTING ACCEPT [3:220]
:OUTPUT ACCEPT [3:220]
COMMIT
# Completed on Fri Dec 24 21:06:12 2004
# Generated by iptables-save v1.2.11 on Fri Dec 24 21:06:12 2004
*filter
:INPUT ACCEPT [7:1077]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [5:355]
COMMIT
# Completed on Fri Dec 24 21:06:12 2004
# Generated by iptables-save v1.2.11 on Fri Dec 24 21:06:12 2004
*mangle
:PREROUTING ACCEPT [7:1077]
:INPUT ACCEPT [7:1077]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [5:355]
:POSTROUTING ACCEPT [5:355]
COMMIT
# Completed on Fri Dec 24 21:06:12 2004
Пример 15.12. Пустые цепочки iptables

Команда группирует одинаковые таблицы каждой цепочки. В пустой таблице присутствует только правило по умолчанию (policy), в этом примере все умолчания равны ACCEPT (пропускать пакет).

Фильтрация

Мефодий озаботился судьбой изобретенного им "календарного сервера", показанного в примере на прошлой лекции. Как уже было замечено, он запустил этот сервис на порту 26000, используемом популярной сетевой компьютерной игрой, что может помешать игрокам. Поэтому Мефодий решил запретить обращение к 26000-му порту отовсюду, кроме самой машины, то есть со всех интерфейсов, кроме lo. С этой задачей справлялась настройка only_from = 127.0.0.1 метадемона, но ее пришлось выключить, так как она автоматически запрещала доступ из сети ко всем сервисам компьютера:

[root@sakura root]# iptables --append INPUT --in-interface lo --protocol
tcp --destination-port quake --jump ACCEPT
[root@sakura root]# iptables --append INPUT --protocol tcp
--destination-port quake --jump REJECT
[root@sakura root]# iptables-save
. . .
*filter
:INPUT ACCEPT [1030:72984]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [730:69581]
-A INPUT -i lo -p tcp -m tcp --dport 26000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 26000 -j REJECT --reject-with
icmp-port-unreachable
COMMIT
. . .
[root@sakura root]# service iptables save
saving current rules to /etc/sysconfig/iptables: [ DONE ]
Пример 15.13. Фильтрация TCP-запросов из сети

Команды iptables получаются довольно длинными: нужно аккуратно описать свойства каждого фильтруемого пакета. В примере Мефодий добавил два правила в таблицу filter цепочки INPUT (таблица filter выбирается по умолчанию, если не указан ключ "-t таблица "). Первое правило разрешает принимать TCP-пакеты, адресуемые на порт 26000, если они пришли из интерфейса lo. Проверка таких пакетов не дойдет до второго правила: по действию ACCEPT они немедленно отправятся дальше по конвейеру. Второе правило не просто уничтожает пакет, пришедший на 26000 порт, но и, как предписывает действие REJECT, посылает отправителю ICMP-пакет, сообщающий о том, что такие запросы не обслуживаются (при обычном действии DROP клиент некоторое время дожидается подтверждения). Из примера видно, что полнословные ключи iptables можно заменять однобуквенными. Кроме того, пример показывает, что стартовый сценарий iptables (в этом дистрибутиве) обрабатывает параметр save, который делает изменения, внесенные вручную, постоянными ( service iptables start, выполняемый при загрузке системы, использует /etc/sysconfig/iptables ).

Подмена адресов

Если в некоторой сети используются адреса из описанного стандартом RFC1918 внутреннего диапазона (например, из сети 10.0.0.0/8 ), то без дополнительных действий абоненты этой сети доступа к Internet иметь не будут. Пакеты с такими адресами запрещено передавать в Internet, а даже если они туда просочатся через маршрутизатор, соединяющий "внутреннюю" и "внешнюю" сети, следующий же маршрутизатор откажется их пересылать. Простая, казалось бы, мысль научить межсетевой экран, установленный на маршрутизаторе, подменять IP-адреса в пакетах, приходящих из внутренней сети, своим внешним IP-адресом, наталкивается на серьезное препятствие.

Допустим, абоненты с адресом 10.0.0.3 и 10.0.0.7 устанавливают TCP-соединение с адресом в Internet (скажем, 209.173.53.26 ). Специально обученный маршрутизатор подменяет 10.0.0.3 и 10.0.0.7 на адрес своего сетевого интерфейса, подключенного к внешней сети (допустим, 194.87.0.50 ). Пакеты уходят адресату, как если бы и тот, и другой были отправлены самим маршрутизатором. 209.173.53.26 отвечает на два запроса двумя пакетами, оба – на адрес 194.87.0.50. Что делать дальше? Как отличить пакет, предназначенный для 10.0.0.3 от такого же для 10.0.0.7?

На помощь приходит знание TCP. Как известно, TCP-соединение идентифицируется шестью параметрами: IP-адресами отправителя и получателя, портами на отправителе и получателе и номерами последовательности (SEQN) входящего и исходящего потока данных. В нашей схеме межсетевой экран обязательно заменяет IP-адреса одним, поэтому у двух принятых пакетов они совпадают. А вот с четырьмя оставшимися параметрами он волен поступать, как заблагорассудится: в любом случае каждому из сеансов должны соответствовать разные SEQN и разные номера исходящих портов. Осталось только держать в памяти таблицу соответствия TCP-соединений из внутренней сети TCP-соединениям во внешнюю сеть.

Этот механизм носит название "преобразование сетевых адресов" ( N etwork A dress T ranslation, NAT). Следует помнить, что чем больше транспортных соединений отслеживается межсетевым экраном, тем больше требуется оперативной памяти ядру Linux и тем медленнее работает процедура сопоставления проходящих пакетов таблице. Впрочем, мощность современных компьютеров позволяет без каких-либо затруднений обслуживать преобразование адресов для сети с пропускной способностью 100Мбит/с и даже выше. В iptables есть специальный модуль для NAT и соответствующие действия в правиле. Такие правила принято помещать в таблицы типа nat:

[root@fuji root]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
83.237.29.1 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0
192.168.102.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
10.13.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
0.0.0.0 83.237.29.1 0.0.0.0 UG 0 0 0 ppp0
[root@fuji root]# iptables-save
# Generated by iptables-save v1.2.11 on Sat Dec 25 14:02:44 2004
*nat
:PREROUTING ACCEPT [216:12356]
:POSTROUTING ACCEPT [242:27148]
:OUTPUT ACCEPT [1428:91596]
-A POSTROUTING -o ppp+ -j MASQUERADE
COMMIT
. . .
Пример 15.14. Использование простейшего преобразования адресов

На том самом маршрутизаторе, где, по словам Гуревича, "всего один настоящий адрес, да и тот – PPP", как раз и настроено преобразование адресов. Делается это всего одним правилом, добавленным в таблицу nat цепочки POSTROUTING. Действие MASQUERADE отличается от действия SNAT (Source NAT) только тем, что может быть использовано на интерфейсах с изменяемым IP-адресом, таких как ppp или настраиваемый по DHCP eth. Если в процессе работы IP-адрес интерфейса поменяется, правило SNAT продолжит менять адреса на старый, заданный во время настройки iptables. Зато MASQUERADE вынуждено спрашивать у системы IP-адрес указанного интерфейса для каждого преобразуемого пакета, что может быть неудобно на очень медленных или очень загруженных разнообразными службами компьютерах.

Преобразование адресов работает не только для TCP-соединений, но и для многих других протоколов, где возможно отследить либо настоящего адресата на внутренней сети, либо идентификатор сеанса связи. Например, ICMP-пакет команды ping содержит уникальный идентификатор, который используется в ответе на него, поэтому не составляет труда отследить, на чей именно ping пришел ICMP-ответ. Таблица отслеживаемых соединений отражается в файле net/ip_conntrack виртуальной файловой системы /proc:

[root@fuji root]# cat /proc/net/ip_conntrack
. . .
icmp 1 30 src=192.168.102.125 dst=209.173.53.26 type=8 code=0
id=50179 [UNREPLIED] src=209.173.53.26 dst=83.237.29.65 type=0 code=0
id=50179 use=1
tcp 6 431981 ESTABLISHED src=192.168.102.125 dst=194.87.0.50
sport=1027 dport=80 src=194.87.0.50 dst=83.237.29.65 sport=80 dport=1027
[ASSURED] use=1
Пример 15.15. Просмотр таблицы подменяемых адресов

Так и есть: во-первых, Мефодий (скорее всего) что-то рассматривает на сайте www.ru (он же 194.87.0.50), а во-вторых, он зачем-то запустил ping www.us: команда cat подана как раз между ICMP-запросом по адресу 209.173.53.26 и ответом на него. Левая часть таблицы описывает соединение до подмены адресов, а правая – после. Точно так же можно "ловить" и UDP-запросы к службе доменных имен, и многое другое.

Конечно, фильтрацией и маскарадом функции iptables не исчерпываются. Можно, например, задать статическую таблицу подмены адресов, тогда появится возможность принимать из Internet соединения, предназначенные для внутренних серверов. Того же можно добиться, используя подмену адреса только для соединений по определенным портам и т. д.

< Лекция 14 || Лекция 15: 12345 || Лекция 16 >
Аягоз Имансакипова
Аягоз Имансакипова
Тимур Булатов
Тимур Булатов

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