Общая тема: Использование iptables. Часть 1.

Использование iptables на автономной dual-up машине.

Быстрый старт.

Обновлено март 2002

Содержание.

1. Введение.

2. Ядро и модули.

3. Пакет iptables.

4. Запуск firewall вручную.

5. Настраиваем автозапуск.


1. Введение.

Может возникнуть законный вопрос. Зачем он нужен, этот firewall, да еще на автономной dual-up машине? Во первых, правильно настроенный, он совершенно "прозрачен", выполняет функции защиты и позволяет добавить много интересных возможностей. Во вторых, а точнее первых, начав игры с firewall сразу с ответственных инсталляций можно сильно проколоться. Для успеха требуется скорее не знание "теоретических основ", а опыт исправления собственных (неизбежных) ошибок и привычка читать записи системных журналов в поисках "проблем на ровном месте". Фильтрация на сетевом уровне затрагивает все клиент-сервер приложения и невозможно предсказать последствий порой самой незначительной правки кода. В третьих, а может во первых, следует избегать статуса сапожника без сапог. Firewall из разряда вещей, которые безусловно являются сильной стороной Linux.


2. Ядро и модули.

Для работы iptables требуется ядро 2.4.x-xx. Ядро должно быть собрано с поддержкой ряда возможностей. Предполагается, что используется предкомилированное ядро из дистрибутива. Будет не лишним проверить наличие некоторых модулей, требуемых для работы firewall. Отсутствие таких модулей - еще не приговор. Ядро может быть собрано со "статическими" feature, но для firewal это не характерно.

Итак, переходим <где-то>


$ cd /lib/modules/2.4.xx-xx/kernel/net/ipv4/netfilter
$ ls
<.....листинг файлов......>

В подкаталоге находятся kernel modules, отвечающие за поддержку iptables. Их число, имена, размер и т.п. могут меняться при изменении версий ядра и используемых patch. Работу предлагаемого для dual-up машины firewall поддерживают, максимум, следующие.

При работающем firewall:


# lsmod | grep ip
 Module                      Size              Used by
 ip_conntrack_talk           1664              0 (unused)
 ip_conntrack_rpc_udp        2656              0 (unused)
 ip_conntrack_rpc_tcp        2816              0 (unused)
 ip_conntrack_netlink        4288              0 (unused)
 ip_conntrack_irc            2528              0 (unused)
 ip_conntrack_ftp            3296              0 (unused)
 ip_conntrack_egg            2048              0 (unused)
 ipt_limit                   896               3 (autoclean)
 ipt_LOG                     3424              4 (autoclean)
 ipt_state                   544               5 (autoclean)
 ip_conntrack                13676             9 (autoclean) [ip_conntrack_talk
                                                 ip_conntrack_rpc_udp
                                                 ip_conntrack_rpc_tcp
                                                 ip_conntrack_netlink
                                                 ip_conntrack_irc
                                                 ip_conntrack_ftp
                                                 ip_conntrack_egg
                                                 ipt_state]
 iptable_filter              1664              0 (autoclean) (unused)
 ip_tables                   10624             4 [ipt_limit 
                                                  ipt_LOG 
                                                  ipt_state 
                                                  iptable_filter]



3. Пакет iptables.

Убедимся, что пакет iptables инсталлирован.


$ rpm -qa | grep iptables
 iptables-1.2.4-alt1

Смотрим его содержимое.


$ rpm -ql iptables
 /etc/rc.d/init.d/iptables
 /sbin/ip6tables
 /sbin/iptables
 /sbin/iptables-restore
 /sbin/iptables-save
 /usr/lib/iptables
 <.......много чего........>
 /usr/share/man/man8/iptables.8.gz

Документ не претендует на замену man pages, поэтому рекомендую открыть дополнительную консоль и запустить man iptables.

Теперь основное внимание на сценарий /etc/rc.d/init.d/iptables.

С места в карьер!


# cd /etc/rc.d/init.d
# ./iptables
 Usage: ./iptables {start|stop|restart|condrestart|status|panic|save}

Ну чем не "интуитивно понятный интерфейс"?

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

  • Новость хорошая - все просто. Если запустить с параметром start, то правила фильтрации загружаются из файла-дампа /etc/sysconfig/iptables.
  • Новость плохая - файл /etc/sysconfig/iptables пустой.
  • Новость хорошая - если запустить с параметром save, то текущий ruleset сбрасывается в /etc/sysconfig/iptables.
  • Новость плохая - сбрасывать собственно нечего.
Предполагаемый план действий примерно следующий:

1. Создаем вспомогательный файл и делаем его исполняемым.


# cd /etc/sysconfig
# touch iptables_ppp.sh
# chown root.root iptables_ppp.sh
# chmod 0700 iptables_ppp.sh

2. Пишем в созданный файл сценарий "Восход солнца вручную" (смотри дальше).

3. Убедившись, что ruleset пуст (параметр status и при необходимости stop), загружаем firewall из написанного сценария.


# cd /etc/sysconfig
# ./iptables_ppp.sh

4. Если при загрузке ошибок нет - последний штрих.


# cd /etc/init.d
# ./iptables status
# ./iptables save
# ./iptables stop

Все, круг замкнулся! Теперь firewall загружается "стандартно" из файла - дампа.

Небольшое отступление. Загрузка из дампа происходит быстрее, чем из shell script (не на проценты, а в 60-90 раз!). На инсталлированном firewall выполняем:


# time /etc/sysconfig/iptables_ppp.sh

 3.61user 1.09system 0:05.06elapsed 92%CPU (0avgtext+0avgdata 0maxresident)k
 0inputs+0outputs (158major+45minor)pagefaults 0swaps
теперь вариант с загрузкой из дампа:

# time grep -v "^[[:space:]]*#" < /etc/sysconfig/iptables | /sbin/iptables-restore

 0.03user 0.02system 0:00.11elapsed 45%CPU (0avgtext+0avgdata 0maxresident)k
 0inputs+0outputs (158major+45minor)pagefaults 0swaps

К сожалению, в ранних версиях (iptables-1.2.1-ipl2mdk) исполняемые файлы iptables, iptables-restore, iptables-save не имели полной совместимости по синтаксису. Обновляйтесь, или загружайтесь из shell script. Загрузка из shell script дает больше гибкости и единственно возможна, если требуется "на лету" подхватывать изменяющиеся параметры (ip адреса, ID процессов и т.п.).


4. Запуск firewall вручную.

Пишем сценарий для инициализации firewall.

Сценарий рассчитан на дальнейшие расширения. "Идея" взята у Oskar Andreasson, автора iptables Tutorial. В этой версии я отказался от цепочки allowed, по ссылке "стандартно" открывавшей любое соединение. Неудачная ссылка в неудачном месте имела бы следствием открытие firewall для всех.


#!/bin/sh
#
# file /etc/sysconfig/iptable_ppp.sh - Initial IP Firewall script for 2.4.x
#
# Author: Vladimir Kholmanov
# use at your own risk
#
###########
# Конфигурационные параметры.
# При необходимости - отредактируйте.
#
# Script не требует указания ни статического, ни "подхвата"
# динамического IP адреса.
# Правила фильтрации привязаны к интерфейсам.
#
# Проверьте правильность пути к iptables.
#
INET_IFACE="ppp0"
LOCAL_IFACE="lo"
IPTABLES="/sbin/iptables"
#########
# Проверка зависимостей в загружаемых IPTables modules
#
/sbin/depmod -a
#
######### t
# Устанавливаем default policies для INPUT, FORWARD и OUTPUT chains
#
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD DROP
#########
# Создаем дочерние chains для ICMP, TCP и UDP протоколов.
#
$IPTABLES -N icmp_in_ppp
$IPTABLES -N tcp_in_ppp
$IPTABLES -N udp_in_ppp
#
# Загружаем ICMP rules для входящих потоков
#
$IPTABLES -A icmp_in_ppp -p ICMP --icmp-type 3 -j ACCEPT
$IPTABLES -A icmp_in_ppp -p ICMP --icmp-type 0 -j ACCEPT
$IPTABLES -A icmp_in_ppp -p ICMP --icmp-type 11 -j ACCEPT
$IPTABLES -A icmp_in_ppp -m limit --limit 6/minute --limit-burst 1 \
-p ICMP --icmp-type 8 -j ACCEPT
$IPTABLES -A icmp_in_ppp -m limit --limit 2/minute --limit-burst 4 -j LOG \
--log-prefix "ICMP in ppp died: "
$IPTABLES -A icmp_in_ppp -p ICMP -j DROP
#
# Загружаем TCP rules для входящих потоков
#
# $IPTABLES -A tcp_in_ppp -p TCP --syn --dport 22 -j ACCEPT
# $IPTABLES -A tcp_in_ppp -p TCP --syn --dport 113 -j ACCEPT
$IPTABLES -A tcp_in_ppp -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A tcp_in_ppp -m limit --limit 2/minute --limit-burst 4 -j LOG \
--log-prefix "TCP in ppp died: "
$IPTABLES -A tcp_in_ppp -p TCP -j DROP
#
# Загружаем UDP rules для входящих потоков
#
$IPTABLES -A udp_in_ppp -p UDP --source-port 53 -j ACCEPT
# $IPTABLES -A udp_in_ppp -p UDP --source-port 123 -j ACCEPT
$IPTABLES -A udp_in_ppp -p UDP --source-port 4000 -j ACCEPT
$IPTABLES -A udp_in_ppp -m limit --limit 3/minute --limit-burst 6 -j LOG \
--log-prefix "UDP in ppp died: "
$IPTABLES -A udp_in_ppp -p UDP -j DROP
##########
# INPUT chain
#
# Регистрируем и удаляем "проблемные" TCP пакеты.
#
$IPTABLES -A INPUT -i $INET_IFACE -p tcp ! --syn -m state --state NEW -j LOG \
--log-prefix "New not syn:"
$IPTABLES -A INPUT -i $INET_IFACE -p tcp ! --syn -m state --state NEW -j DROP
#
# "Направляющие" для локальных и "пере направляющие" для inet пакетов rules.
#
$IPTABLES -A INPUT -p TCP -i $LOCAL_IFACE -j ACCEPT
$IPTABLES -A INPUT -p TCP -i $INET_IFACE -j tcp_in_ppp
$IPTABLES -A INPUT -p UDP -i $LOCAL_IFACE -j ACCEPT
$IPTABLES -A INPUT -p UDP -i $INET_IFACE -j udp_in_ppp
$IPTABLES -A INPUT -p ICMP -i $LOCAL_IFACE -j ACCEPT
$IPTABLES -A INPUT -p ICMP -i $INET_IFACE -j icmp_in_ppp
#
# "Регистрирующее rule для "неохваченных" пакетов.
#
$IPTABLES -A INPUT -m limit --limit 3/minute --limit-burst 6 -j LOG \
--log-prefix "IP INPUT packet died: "


Теперь примечания. Не забывайте "бегать" на консоль с открытым man iptables. Не забывайте, что "связавшись" с firewall вы сделаете файл /etc/services своей "консольной книгой".

Проверка зависимостей в загружаемых IPTables modules  Обычно, "предкомпилированные" ядра из дистрибутивов поддерживают автозагрузку модулей по требованию. Для автономной машины это всегда приемлемо. Для ответственных инсталляций ядро можно собирать без такой поддержки и управлять процессом вручную. Загрузку модулей можно организовать "стиле BSD" (в каталоге /etc/rc.d имеется файл rc.firewall.

Устанавливаем default policies  Для автономной машины допустимо установить политику ACCEPT для OUTPUT chain и отказаться от "регулирования" выходящих пакетов.

Создаем дочерние chains...  Хорошее средство для структурирования ruleset и последующих модернизаций.

Загружаем ICMP rules  Очень тонкое место в ruleset. Протокол ICMP горячо любим хакерами и есть соблазн запретить как можно больше его типов и кодов. Но, не выплескивайте с водой ребенка! На запрет отдельных code из icmp-type 3 вообще следует наложить табу. Удалите соответствующую строку из ruleset и вы получите множество замечательных глюков! Наборчик допустимых icmp-type / code беден, но запись в журнал "неохваченных" ICMP позволит со временем уточнить ruleset..

Загружаем TCP rules для инициализации...  Порт 22 - ssh, возможно вы разрешите авторизованным пользователем работать на своей машине. Порт 113 - identd, используется для "скрытой" аутентификации некоторыми протоколами (автор сталкивался с подобной аутентификацией для SMTP, у squid тоже имеется такой режим). В любом случае смотрите в журналах "неохваченные" пакеты и принимайте решения по изменению ruleset.

Примечание 1. Порт 113 обычно работает из-под суперсервера, а значит, защищен (в терминологии xinetd сервис AUTH). Как это согласуется с firewall? Firewall работает на сетевом уровне и, дополнительно, "видит" headers смежных транспортного и канального уровня (модель OSI 2-3-4 уровни). Суперсервер xinetd фильтрует соединения на уровне сессии (модель OSI 5 уровень). То есть, firewall и xinetd решают схожие задачи последовательно и независимо. Помните, для разрешения - запрета AUTH при работающих iptables и xinetd требуется настройка правил в двух местах!

Примечание 2. Порт 22 обычно работает автономно. В конфигурации SSH, помимо шифрования, настраивается защита прослушивания интерфейсов (с возможностью указывать допустимые режимы аутентификации). Опять же, собственная настройка SSH на уровне сессии работает последовательно и независимо от iptables. Настраивать правила требуется в двух местах.

Загружаем UDP rules  Есть подозрение, что DNS (порт 53) все же нужен. Порт 123 (NTP или network time protocol) - используется достаточно редко... Порт 4000 (ICQ) - решайте сами и смотрите в журнале, что еще забыли явно разрешить-запретить.

INPUT chain  Самая загруженная цепочка. Перенаправления в дочерние chains снижает нагрузку на процессор без компромисса с безопасностью (пакеты "ходят" коротким путем - отследите). Кроме того, структурированный ruleset легче для восприятия и модернизации.

И еще одно замечание. "Фрагмент" из iptables Tutorial от Oskar Andreasson:

Статус NEW пакетов отличается от простого SYN bit set.

Имеется "feature" в iptables, которая не достаточно документирована и может оказаться незамеченной многими. Если используете state NEW, то в некоторых случаях пакеты и со снятым SYN bit пройдут через ваш firewall! Эта возможность может пригодится в некоторых случаях, допустим, пакет может быть частью уже ESTABLISHED подключения, сделанного через другой firewall. Тем самым, становится возможным иметь резервный firewall для подключения LAN к Internet. Если основной firewall "падает", то имеющиеся соединения могут быть "подхвачены" резервным. Статус NEW примет многие TCP connection, а не только те, которые находились в фазе "тройного рукопожатия". Та же самая возможность потенциально может "выйти боком" (что там еще выдумают хакеры). Если резервного firewall у вас нет, дополнительно обезопасьте себя следующим (добавьте правила не только в INPUT, но и в FORWARD chain на шлюзе):


$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j LOG \
--log-prefix "New not syn:"
$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

Сказанное - потенциальная "дыра" в новых netfilter/iptables и должна быть как можно шире документирована. Другими словами, большое предупреждение для администраторов firewall.

Появление записей "New not syn:" в журналах не должно вызывать паники. Есть множество "не хакерских" причин появления таких пакетов. Нужно учиться анализировать. Например, при получении динамического IP адреса в случае, если тот, кто им пользовался до вас, не закрыл свои TCP связи, мы имеем соответствующие записи в журнале. Подобные примеры можно продолжать.

Запускаем firewall и смотрим, что получилось.


# cd /etc/init.d
# ./iptables start
# ./iptables status
# ./iptables stop
# ./iptables start
# ./iptables restart
# /sbin/iptables -vnL
....................
# ./iptables stop

Если все OK, пол дела сделано. В качестве отдыха читаем, что пишут журналы (/var/log/syslog/, /var/log/user/ и т.д.).


5. Настраиваем автозапуск.

Многие сценарии из /etc/init.d/ загружаются в boot time, а выгружаются при выключении системы. Для firewall на автономной dual-up машине это не требуется. Впрочем, сценарий запуска не содержит ничего, что мешало бы firewall "торчать" в памяти постоянно и такой вариант даже предпочтительней по времени готовности (тем более, если каждое включение машины предполагает подключение к Internet).

Настроим следующее. Iptables загружаются в boot time и выгружаются при разрыве dual-up с сохранением статистики сеанса в файл (или при выключении машины "без статистики", если сеанса связи с ISP не было). Iptables повторно загружаются из ip-up при втором и последующих подключениях к ISP и выгружаются при разрыве dual-up.

Проверяем, что у нас с загрузкой:


# /sbin/chkconfig --list
<......много чего.......>
iptables        0:off 1:off 2:off 3:off 4:off 5:off 6:off
<......много чего.......>

Можно так и оставить, но, если "время готовности дороже", делаем:


# /sbin/chkconfig --add iptables
# /sbin/chkconfig --list | grep iptables
iptables        0:off 1:off 2:on 3:on 4:on 5:on 6:off

см. man page по chkconfig

Осталось сделать привязку к start dual-up и drop dual-up. Но, сначала, создадим каталог для сбора статистики сессий (файлы будут создаваться автоматически). Наиболее подходящим местом для этого будет:


# cd /var/lib
# mkdir iptables

Продолжаем. Находим файл /etc/ppp/ip-up


#!/bin/bash
# This file should not be modified -- make local changes to
# /etc/ppp/ip-up.local instead
<.....много чего.......>
IP_UP_LOCAL=/etc/ppp/ip-up.local
[ -x "$IP_UP_LOCAL" ] && "$IP_UP_LOCAL" "$@"
<.....много чего.......>

Думаю, что нет оснований отказаться от совета. Кстати, из текста следует, что вставляемый файл должен иметь те же права, как основной, быть исполняемым, но не требует "магической первой строки". Начало с "#! /bin/sh" запустит "лишний" дочерний процесс, что не фатально, но не аккуратно. Итак (если еще не сделано для иных целей):


# cd /etc/ppp
# touch ip-up.local ip-down.local
# chown root.root ip-up.local ip-down.local
# chmod 755 ip-up.local ip-down.local

Добавляем в созданный ip-up.local примерно следующие строки:


# file /etc/ppp/ip-up.local
if [ -f /var/lock/subsys/iptables ]
    then
        /sbin/iptables -Z > /dev/null 2>&1
    else
        /etc/rc.d/init.d/iptables start > /dev/null 2>&1
fi
#last line

Комментарий. Проверка наличия lock файла требуется, так как заранее не известно, запущен или нет firewall (он может быть загружен или нет в boot time, выгружен при разрыве dual-up и т.п.). Просмотрите сценарий /etc/rc.d/init.d/iptables на предмет когда создается - удаляется блокирующий файл. Обратите внимание, блокировка "условна" и действует только в прогаммах, знающих о такой "методе". Строки в файле должны находится до запуска fetchmail и чего там еще.

Теперь добавляем в файл /etc/ppp/ip-down.local:


# file /etc/ppp/ip-down.local
(/sbin/iptables -vnL > /var/lib/iptables/`date +iptb_acc_%Y-%m-%d_%H.%M` && \
/etc/init.d/iptables stop > /dev/null 2>$1) &
# 
 echo Login: ${PEERNAME} `date +'%d/%m/%Y %T' -d "-${CONNECT_TIME} sec"` - \
 `date +'%T'` " Time: $[$CONNECT_TIME/60+1]m, Sent: $[$BYTES_SENT/1024]Kb, \
 Rcvd: $[$BYTES_RCVD/1024]Kb" >> /var/lib/iptables/acc_ppp 
# last line

Комментарий. Ключ -n отключит DNS lookup, но, если у вас работает cache-only или cache-forward named, можно и без него (у меня pdnsd, но DNS lookup отключен). Статистика firewall складывается в отдельный файл (с суффиксом в имени от функции date) для каждого сеанса (посмотрел, можно удалить). Статистика PPP построчно добавляется в один файл ("подсмотрено" в ppp.html от Ruwa).

Удачи!



Vladimir Kholmanov.

Наш баннер
Вы можете установить наш баннер на своем сайте или блоге, скопировав этот код:
RSS новости