Настраиваем межсетевой экран на базе Iptables + Patch-o-matic
Виталий «root» Чернов (vr-soft@mail.ru)
Если ты работаешь сисадмином (или исполняешь его обязанности) в более-менее крупной конторе, то наверняка ты не раз задумывался о безопасности своих железных питомцев. Как правило, количество серверов и маршрутизаторов растет пропорционально подсетям, управлять которыми с каждым днем становится все сложнее и сложнее. В особо «критические» дни ты мечтаешь о счастливых временах, когда вся сеть будет администрироваться с одного-единственного сервера парой-тройкой команд в консоли. Администрирование всей сети – тема далеко не одной статьи, но для того, чтобы максимально приблизить мечты к реальности, достаточно пакета iptables и немного терпения.
Содержание:
- Файрвол и маршрутизатор в одном флаконе
- Немного теории
- Как устанавливать
- Как пользоваться
- Как конфигурировать
- Как считать трафик
- Тонкая заточка
- Потаенные возможности
- Расширения
- Подводим итоги
Файрвол и маршрутизатор в одном флаконе
Пакет iptables позволяет как маршрутизировать сети, так и фильтровать входящие и исходящие пакеты. Таким образом, iptables может выступать как в роли маршрутизатора, так и очень мощного файрвола.
Чтобы не быть голословным, хочу показать тебе iptables в действии. Я набросал небольшую схему сети, которую ты можешь увидеть на рисунке. Она содержит в себе один сервер с выходом наружу, четыре рабочие станции в четырех подсетях и удаленную машину, которая работает с одним из внутренних серверов.
Для экспериментов нам понадобится простейшая машина с Linux, в которую нужно воткнуть столько сетевых карт, сколько подсетей мы будем соединять (в нашем случае 4+1=5). Iptables желателен не ниже версии 1.3.5.
Четыре подсети, в каждой из которых может работать <255 пользователей, с общим выходом в интернет и учетом трафика с помощью NetAms (просто для примера). Из серверов – два Web (один из которых с SSL), один с SSH для конфигурирования главного сервера, чтобы на него не открывать доступ снаружи, и MSSQL, ну, например, для одного офиса, который будет работать с базой данных. По своему усмотрению можешь сделать любую другую схему. Принцип от этого не изменится. Главное — понять, как происходит маршрутизация, и разобраться в настройках Iptables.
По умолчанию iptables содержит в себе три таблицы. Mangle – как правило, эта таблица используется для внесения изменений в заголовок пакета, например, для изменения битов TOS и TTL. Nat — используется для выполнения преобразований сетевых адресов. И, наконец, таблица Filter – название говорит само за себя – с ее помощью мы будем фильтровать пакеты, и, в случае необходимости, перенаправлять, зеркалировать или убивать. Все основные действия будем производить в таблице Filter. Прямое назначение каждой из таблиц вовсе не означает, что в ней нельзя делать других действий. Например, за’drop’ить пакет мы можем и в Nat/Mangle, но рекомендуется, все же, делать это в таблице Filter.
Каждая из таблиц содержит в себе несколько логических цепочек, порядок прохождения которых определяется вектором пакета. Вот дефолтные цепочки этих таблиц:
- Mangle: PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING
- Nat: PREROUTING, OUTPUT, POSTROUTING
- Filter: INPUT, FORWARD, OUTPUT
Конечно, ничто не мешает нам добавить свою цепочку. Это может потребоваться для того, чтобы зарулить пакеты на систему учета трафика. Порядок прохождения входящих и исходящих пакетов более наглядно представлен на схеме. Несложно увидеть, что если, допустим, пакет идет через шлюз к рабочей станции, он проходит следующий порядок цепочек: Mangle:PREROUTING -> Nat:PREROUTING -> Filter:FORWARD -> Mangle:FORWARD -> Nat:POSTROUTING -> Mangle:POSTROUTING. Чтобы перенаправить пакет с сетевого интерфейса сервера на порт 1433 машины 192.168.2.100, нам нужно добавить соответствующее правило в таблицу nat, в цепочку PREROUTING.
Для начала убедись, что ядро собрано с поддержкой Netfiler. Для этого зайди в исходники ядра и набери «make menuconfig» (или «make xconfig»). Затем переходи в следующую ветку (для ядра 2.6.x): Networking -> Networking options -> Network packet filtering framework (Netfilter) -> IP: Netfiler Configuration и отметь все опции как модули. Затем открывай /etc/sysctl.conf и добавь в конец строку «net.ipv4.ip_forward = 1».
Теперь качай свежий пакет iptables и устанавливай стандартными «./configure; make; make install». После этого у тебя должен появиться файл /etc/init.d/iptables. Он заставит работать iptables в роли сервиса. Убедись, что файл реально запустится при загрузке, для этого набери в консоли «chkconfig --level 345 iptables on». На этом установку можно считать завершенной.
Теперь я вкратце поясню, как работать с iptables, и какие команды при этом нужно использовать. Команда «iptables -L» – просмотр содержимого таблицы. По умолчанию используется таблица filter. Для того чтобы явным образом указать другую, добавляем «-t tablename». Вместе с ключом
В пакет iptables входят еще две утилиты: iptables-save – для сохранения таблиц и iptables-restore – для их восстановления. Если для того чтобы сохранить таблицы, достаточно написать «iptables-save -t nat > /etc/iptables.save», то утилита восстановления воспринимает только стандартный поток вывода на экран: «iptables-restore | cat /etc/iptables.save». Но не спеши прописывать это в rc.local, все гораздо проще, для сохранения настроек, которые после перезагрузки будут сами восстанавливаться, нужно написать «service iptables save» и все!
Для начала закроем все лишнее снаружи, отфильтруем левые адреса от MSSQL и переадресуем необходимые порты по их прямому назначению.
Проверь с помощью nmap наличие открытых портов: «nmap 127.0.0.1». Допустим, у тебя открыты: 21, 22, 80, 111, 139, 445, 953, 993, 1723 и 2628. У меня нет никакого желания открывать доступ на 22 порт снаружи, поэтому сделаем так, чтобы стучаться изнутри на него могла только одна машина – 192.168.1.100. А извне направим на нее все пакеты с 22 порта. Если злоумышленник и зайдет по SSH, пусть думает, что захватил сервер! Но на самом деле он будет находиться на пустой машине с одним только SSH. А до шлюза еще далеко…
# iptables -A PREROUTING -i eth0 -p tcp -m tcp --dport 22
-j DNAT --to-destination 192.168.1.100 -t nat
Именно так будет выглядеть строка, которая перенаправит пакеты с 22 порта шлюза на сервер 192.168.1.100. Теперь закроем этот порт для всех машин и откроем только для 192.168.1.100:
# iptables -I INPUT 1 -i 192.168.1.100 -p tcp --dport 22 -j ACCEPT
# iptables -I INPUT 2 -p tcp --dport 22 -j REJECT
--reject-with icmp-port-unreachable
Примечание: правило, стоящее в цепочке выше, является более привилегированным.
Для того чтобы отрезать пакет, используется правило DROP, но если внимательно почитать руководство по iptables на сайте разработчика, то можно увидеть, что автор рекомендует использовать REJECT, во избежание различных *DoS-атак.
И последним шагом мы отрубим все лишние порты. Пусть они по-прежнему будут видны изнутри, но на внешнем интерфейсе eth0 нужно оставить самый минимум:
# iptables -A INPUT -i eth0 -p tcp -m multiport
--dports 21,111,139,445,953,993,1723,2628 -j REJECT
--reject-with icmp-port-unreachable
Кстати, в последней строчке вместо «-m multiport» можно поставить «-m tcp» и сформировать отдельное правило для каждого из портов. В этом есть свой плюс — ты сможешь видеть количество пакетов, полученных на каждый отдельный порт, и, соответственно, реально оценить нагрузку и возможную угрозу.
# iptables -A PREROUTING -d 100.100.100.100 -p tcp -m tcp
--dport 443 -j DNAT --to-destination 192.168.3.100 -t nat
# iptables -A PREROUTING -d 100.100.100.100 -p tcp -m tcp
--dport 80 -j DNAT --to-destination 192.168.0.100 -t nat
# iptables -A PREROUTING -d 100.100.100.100 -p tcp -m tcp
--dport 1433 -j DNAT --to-destination 192.168.2.100 -t nat
Так мы зарулим пакеты по их прямому назначению на другие серваки.
Следующими строчками мы подружим сетевые интерфейсы между собой. Как правило, для таких целей используют хардварные маршрутизаторы, но мы же не собираемся менять несколько ящиков пива на какие-то железные поделки, которые, к тому же, элементарно заменяются одним-единственным Linux+Iptables :).
# iptables -A FORWARD -i eth1 -o eth2 -j ACCEPT # iptables -A FORWARD -i eth1 -o eth3 -j ACCEPT # iptables -A FORWARD -i eth1 -o eth4 -j ACCEPT ... # iptables -A FORWARD -i eth4 -o eth3 -j ACCEPT
Понятно, что если все пакеты рулятся, порты фильтруются, но сервак не умеет считать проходящий через него трафик, то грош цена такому админству. Эту проблему можно решить следующим образом. Мы создадим цепочку, которая с помощью правила QUEUE будет ссылаться на любую понравившуюся тебе систему учета. Я выбрал NeTAMS. Последнюю версию этой замечательной программы можно скачать на netams.com. Различные faq и инструкции по установке лежат там же.
Правило QUEUE занимается только тем, что посылает поступивший пакет в очередь на пользовательское приложение. Для того чтобы им воспользоваться, в ядро нужно воткнуть стандартный обработчик очереди для IPv4 — модуль ip-queue. Делается это примерно так:
# modprobe iptable_filter # modprobe ip_queue
Теперь создадим цепочку, в которую будем отправлять весь трафик для подсчета:
# iptables -N COUNTER
Напишем одно-единственное правило, а по цепочке пустим все оставшиеся пакеты:
# iptables -A COUNTER -j QUEUE # iptables -A FORWARD -i eth0 -j COUNTER # iptables -A FORWARD -o eth0 -j COUNTER
Здесь есть один очень важный момент. Дело в том, что с помощью приведенных выше правил все входящие и исходящие пакеты поступают в системную очередь, откуда их будет брать NeTAMS. Однако если в момент активизации iptables NeTAMS не будет запущен, пакеты будут поступать в системную очередь и там пропадать, т.к. не будет программы, которая отправит их обратно. В результате пропадет коннект до сервера. Поэтому в процессе отладки надо либо сидеть за консолью сервера, либо в случае удаленного администрирования — тренироваться на ICMP-трафике. А порядок запуска такой: сначала запускаем NeTAMS, потом iptables. Соответственно, порядок остановки обратный – сначала останавливаем iptables, потом NeTAMS.
Вот, собственно, и все, что требовалось для того, чтобы пакеты начали ходить по струнке, а порты отпинывали незваных гостей. Теперь самое время заняться тонкой настройкой. При необходимости можно отступить от стандартных правил:
// Вместо прямого адреса можно указать доменное имя: # iptables -A INPUT -s test.host.jp -j DROP // В качестве пункта назначения задаем целую подсеть: # iptables -A INPUT -s 192.168.133.0/24 -j DROP // Восклицательный знак означает исключение. // Т.е. в данном случае дропятся все адреса кроме указанного: # iptables -A INPUT -s ! 192.168.133.156 -j DROP
Как ты уже заметил, несколько раз в правилах мы указывали опцию ‘-p’. Она задает обрабатываемый протокол. Можно использовать all, icmp, tcp, udp.
Ниже описаны стандартные правила для цепочек, которые указываются с ключом ‘-j’: ACCEPT — разрешить пакет; DROP — уничтожить пакет; REJECT — будет отправлено ICMP сообщение, что порт недоступен; LOG — информация об этом пакете будет добавлена в системный журнал (syslog).
Вот мы и подошли к самому сладкому… Если ты считаешь, что у iptables слишком ограниченный набор возможностей, то эта часть как раз для тебя. С сайта ftp.netfilter.org скачай последнюю версию тарболла patch-o-matic, этот патч добавляет к iptables 54 расширения. Есть версии для ядер 2.4 и 2.6. Установка пакета достаточно проста (возможно, patch-o-matic уже собран в твоем «коробочном» ядре, особенно, если ты счастливый обладатель серверного дистрибутива):
// Для Linux 2.4
# KERNEL_DIR=путь_к_исходникам_ядра_2.4 ./runme pending
// Для Linux 2.6
# KERNEL_DIR=путь_до_исходников_ядра_2.6
IPTABLES_DIR=путь_к_исходникам_iptables ./runme pending
Затем следует перекомпилировать ядро и iptables. После этого patch-o-matic становится частью iptables, и со всеми его правилами и целями можно работать как со встроенными. Для того чтобы получить помощь по любому расширению, введи в консоли:
# iptables -m любая_цель_или_правило -–help
- Length
Обрабатывает правила в соответствии с заданной длиной пакета:
# iptables -A INPUT -p icmp --icmp-type echo-request -m length
--length 86:0xffff -j DROP
Это перекроет кислород всем, кто будет пинговать тебя больше чем по 86 байт за один присест.
- Nth
Еще одна полезная надстройка над iptables. Она обрабатывает каждый N-й пакет по заданному правилу. Например, следующая строчка задропит каждый второй пакет типа icmp echo-request:
# iptables -A INPUT -p icmp --icmp-type echo-request -m nth
--every 2 -j DROP
Если тебя постоянно терроризируют DOS/DDOS-атаками, советую поближе познакомиться с двумя вышеописанными модулями.
- Psd
Очень полезное расширение, которое перехватывает сканирование портов. Против грамотного использования nmap psd будет бессилен, но большинство топорных проб распознает и пресекает на корню. Этим правилом мы захватываем сразу все имеющиеся порты:
# iptables -A INPUT -m psd -j DROP
- String
Анализирует область данных пакета и на основе этого производит фильтрацию. Здесь главное не перестараться. Если тебя одолевают спамеры, а от слова «porno» тебя слегка потрясывает, можешь добавить следующую строку:
# iptables -A FORWARD -i eth0 -p tcp --sport 25 -m string
--string 'porno' -j DROP
Пакет исчезнет прежде, чем дойдет до твоего спам-фильтра. Не забывай, что расширение чувствительно к регистру символов!
- Time
Это расширение обрабатывает пакеты в указанное время. Следующий пример демонстрирует ограничение доступа к серверу по пятницам, с 2 до 4:15 часов (например, для выполнения планового обновления):
# iptables -A INPUT -p tcp -d 80 -m time --timestart 02:00
--timestop 04:15 --days Fri --syn -j REJECT
Все три ключа ‘—timestart’, ‘—timestop’ и ‘—days’ должны быть обязательно включены в правило.
- Random
Используя это расширение, можно построить такой критерий, который будет срабатывать с вероятностью в диапазоне от 0% до 100%. К примеру, для балансировки нагрузки распределим трафик по четырем серверам:
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 --syn
-m random --average 25 -j DNAT --to-destination 192.168.0.100:80
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 --syn
-m random --average 25 -j DNAT --to-destination 192.168.0.101:80
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 --syn
-m random --average 25 -j DNAT --to-destination 192.168.0.102:80
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 --syn
-m random --average 25 -j DNAT --to-destination 192.168.0.103:80
Вот мы и настроили абсолютно полноценный сервак-шлюз с помощью практически одного только iptables. Выводы делай сам, но лично я давным-давно уже перевел все свои серваки именно на такое управление. И тебе советую.
Статья опубликована в августовском номере журнала «Xakep» за 2007 год.




