Настройка межсетевого экрана Iptables

Я думаю, что каждый пользователь Linux задавал себе вопрос «Где в Linux межсетевой экран». Когда-то этот вопрос встал и передо мной. При обнаружении iptables, я долго не мог понять, что с ним делать. Но со временем я стал немного разбираться, научился писать правила. В этом мне помогла хорошая статья Оскара Андерсона в переводе Андрея Киселева (http://www.opennet.ru/docs/RUS/iptables/). Сразу скажу, что эта статья довольно-таки сложна, сразу по ней ничему не научишься. Тем более не у всех есть время читать, разбираются, вдаватся во все тонкости. Поэтому я и написал эту статью. Здесь я попытаюсь рассказать, как настраивать iptables и писать к нему правила фильтрации.
Итак сначала не помешает изучить принцип работы межсетевого экрана Iptables: Когда пакет приходит на наш межсетевой экран, то он сперва попадает на сетевое устройство, перехватывается соответствующим драйвером и далее передается в ядро. Далее пакет проходит ряд таблиц и затем передается либо локальному приложению, либо переправляется на другую машину.
В Iptables используется три вида таблиц:
  1. Mangle — обычно эта цепочка используется для внесения изменений в заголовок пакета, например для изменения битов TOS и пр.
  2. Nat — эта цепочка используется для трансляции сетевых адресов (Destination Network Address Translation). Source Network Address Translation выполняется позднее, в другой цепочке. Любого рода фильтрация в этой цепочке может производиться только в исключительных случаях.
  3. Filter — здесь производится фильтрация трафика. Помните, что все входящие пакеты, адресованные нам, проходят через эту цепочку, независимо от того с какого интерфейса они поступили.
Соответственно, нас интересует третья таблица Filter. В этой таблицы имеются три встроенные цепочки:
  1. INPUT — для входящих пакетов.
  2. FORWARD — для проходящих через данную машину к другой.
  3. OUTPUT — для исходящих.
Пакет, проходящий через эти цепочки, исходя из правила может быть пропущен (ACCEPT) или отброшен (DROP).
Iptables можно настраивать разными способами:
  1. с помощью webmin — web-интерфейс для настройки системы;
  2. программой Guarddog (http://www.simonzone.com/software/guarddog/), представляющей собой KDE-интерфейс для редактирования настроек стенки путем установки/снятия галочек;
  3. с помощью программы, которая так и называется — Iptables.
Последней мы и будем пользоваться.
Программа Iptables позволяет редактировать правила через терминал путем ввода команд.
Немного о написании правил:
Каждое правило—это строка, содержащая в себе критерии, определяющие, подпадает ли пакет под заданное правило, и действие, которое необходимо выполнить в случае выполнения критерия. В общем виде правила записываются примерно так:
iptables [-t table] command [match] [target/jump]
Нигде не утверждается, что описание действия (target/jump) должно стоять последним в строке, однако, такая нотация более удобочитаемая. Как бы то ни было, но чаще всего вам будет встречаться именно такой способ записи правил.
Если в правило не включается спецификатор -t table, то по умолчанию предполагается использование таблицы filter, если же предполагается использование другой таблицы, то это требуется указать явно. Спецификатор таблицы так же можно указывать в любом месте строки правила, однако более или менее стандартом считается указание таблицы в начале правила.
Далее, непосредственно за именем таблицы, должна стоять команда. Если спецификатора таблицы нет, то команда всегда должна стоять первой. Команда определяет действие iptables, например: вставить правило, или добавить правило в конец цепочки, или удалить правило и т.п.
Раздел match задает критерии проверки, по которым определяется подпадает ли пакет под действие этого правила или нет. Здесь мы можем указать самые разные критерии — IP-адрес источника пакета или сети, IP-адрес места назначения, порт, протокол, сетевой интерфейс и т.д. Существует множество разнообразных критериев.
И наконец target указывает, какое действие должно быть выполнено при условии выполнения критериев в правиле. Здесь можно заставить ядро передать пакет в другую цепочку правил, «сбросить» пакет и забыть про него, выдать на источник сообщение об ошибке и т.п.
И вот мы напрямую подошли к написанию правил. Возможно в некоторых дистрибутивах уже есть готовые правила, но они не всегда корректно написаны. А в некоторых их вовсе нет.
Если в вашем дистрибутиве уже есть правила фильтрации, то они должны находится в каталоге /etc/init.d/ и называться rc.firewall или rc.fw. В принципе вы их можете удалить, так как ниже я публикую свойrc.firewall и попытаюсь подробно описать каждое правило.
#!/bin/sh
 
# Задаем некоторые переменные:
 
# Переменная, задающая путь к файлу запуска iptables.
IPT=  «/sbin/iptables»
 
# Ваш сетевой интерфейс. Это нужно, чтобы не писать в правилах одно и тоже.
INET_IFACE=  «ppp0»
 
# Номера непривилегированных портов 
UNPRIPORTS=  «1024:65535»
 
start_fw  ()
{
    # Включить перенаправление пакетов через ядро.
    echo 1 > /proc/sys/net/ipv4/ip_forward
    
    # Сбросить правила и удалить цепочки.
    $IPT -F
    $IPT -X
    
    # Политики по умолчанию.
    $IPT -P INPUT DROP
    $IPT -P FORWARD ACCEPT
    $IPT -P OUTPUT DROP
 
    # Разрешаем прохождение любого трафика по интерфейсу обратной петли.
    $IPT -A INPUT -i lo -j ACCEPT
    $IPT -A OUTPUT -o lo -j ACCEPT
    
    # Запрещаем любые новые подключения с любых интерфейсов, кроме lo к компьютеру.
    $IPT -A INPUT -m state!  -i lo --state NEW -j DROP
    
    # Если интерфейс не lo, то запрещаем входить в список его адресов.
    $IPT -A INPUT -s 127.0.0.1/255.0.0.0!  -i lo -j DROP
    
    # Отбрасывать все пакеты, которые не могут быть идентифицированы и поэтому не могут иметь определенного статуса.
    $IPT -A INPUT   -m state --state INVALID -j DROP
    $IPT -A FORWARD -m state --state INVALID -j DROP
    
    # Принимать все пакеты, которые инициированы из уже установленного соединения, и имеющим признак ESTABLISHED.
    # Состояние ESTABLISHED говорит о том, что это не первый пакет в соединении.
    $IPT -A INPUT   -m state --state ESTABLISHED,RELATED -j ACCEPT
    $IPT -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    # Предупреждаю вас о туповатых провайдерах, которые назначают IP адреса, отведенные IANA для локальных сетей.
    # Например адреса 10.X.X.X. Для этого надо установить правило, пропускающие трафик с этих серверов, ранее цепочки INPUT.
    $IPT -t nat -I PREROUTING -i $INET_IFACE -s 10.0.0.1/32 -j ACCEPT
    
    # Эти правила предохраняют от некоторых типов атак:
    
    # SYN наводнение.
    # Приводит к связыванию системных ресурсов, так что реальных обмен данными становится не возможным.
    $IPT -A INPUT -p tcp!  --syn -m state --state NEW -j DROP
    $IPT -A OUTPUT -p tcp!  --syn -m state --state NEW -j DROP
    
    # UDP наводнение 
    # Службы использующие UDP, очень часто становятся мишенью для атак с целью вывода системы из строя.
    $IPT -A INPUT -p UDP -s 0/0 --destination-port 138 -j DROP 
    $IPT -A INPUT -p UDP -s 0/0 --destination-port 113 -j REJECT 
    $IPT -A INPUT -p UDP -s 0/0 --source-port 67 --destination-port 68 -j ACCEPT  
    $IPT -A INPUT -p UDP -j RETURN 
    $IPT -A OUTPUT -p UDP -s 0/0 -j ACCEPT 
    
    # ICMP — перенаправление 
    # ICMP — сообщение указывает системе изменить содержимое таблиц маршрутизации с тем, что бы направлять 
    # пакеты по более короткому маршруту. Может быть использовано взломщиком для перенаправления вашего трафика через свою машину.
    $IPT -A INPUT --fragment -p ICMP -j DROP 
    $IPT -A OUTPUT --fragment -p ICMP -j DROP 
    
    # Разрешаем  ICMP соединение. Значительная часть ICMP используется для передачи сообщений о 
    # том, что происходит с тем или иным UDP или TCP соединением.
    $IPT -A INPUT -p icmp -m icmp -i $INET_IFACE --icmp-type source-quench -j ACCEPT
    $IPT -A OUTPUT -p icmp -m icmp -o $INET_IFACE --icmp-type source-quench -j ACCEPT
    
    # Разрешаем себе ping наружу — нас же не попингуешь — пакеты отбрасываются.
    $IPT -A INPUT -p icmp -m icmp -i $INET_IFACE --icmp-type echo-reply -j ACCEPT
    $IPT -A OUTPUT -p icmp -m icmp -o $INET_IFACE --icmp-type echo-request -j ACCEPT
 
    # Разрешаем передачу пакета — некорректный параметр — используется, если в заголовке пакета содержится недопустимая запись,
    # или если контрольная сумма заголовка не соответствует контрольной сумме, указанной передающим узлом.
    $IPT -A INPUT -p icmp -m icmp -i $INET_IFACE --icmp-type parameter-problem -j ACCEPT
    $IPT -A OUTPUT -p icmp -m icmp -o $INET_IFACE --icmp-type parameter-problem -j ACCEPT
 
    # Запрещаем подключение к X серверу через сетевые интерфейсы.
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport 6000:6063 -j DROP --syn
    
    # Прописываем порты, которые открыты в системе, но которые не должны быть открыты на сетевых интерфейсах:
    # $IPT -A INPUT -p tcp -m tcp -m multiport -i $INET_IFACE -j DROP --dports #порта
    $IPT -A INPUT -p tcp -m tcp -m multiport -i $INET_IFACE -j DROP --dports 783
    $IPT -A INPUT -p tcp -m tcp -m multiport -i $INET_IFACE -j DROP --dports 3310
    $IPT -A INPUT -p tcp -m tcp -m multiport -i $INET_IFACE -j DROP --dports 10000
    
    # DNS сервер имен разрешаем.
    $IPT -A OUTPUT -p udp -m udp -o $INET_IFACE --dport 53 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 53 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p udp -m udp -i $INET_IFACE --dport $UNPRIPORTS --sport 53 -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport 1024:65353 --sport 53 -j ACCEPT
    
    # Разрешаем AUTH-запросы на удаленные сервера, на свой же компьютер — запрещаем.
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 113 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 113 -j ACCEPT!  --syn
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport 113 -j DROP
    
    # Открываем некоторые порты:
    
    # SMTP клиент  (25)
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 25 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 25 -j ACCEPT!  --syn
    
    # POP3 клиент  (110)
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 110 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 110 -j ACCEPT!  --syn
    
    # IMAP4 клиент  (143)
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 143 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 143 -j ACCEPT!  --syn
    
    # SSH клиент  (22)
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 22 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 22 -j ACCEPT!  --syn
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 22 --sport 1020:1023 -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport 1020:1023 --sport 22 -j ACCEPT!  --syn
    
    # FPT клиент  (21)
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 21 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 21 -j ACCEPT!  --syn
    
    # HTTP/HTTPS клиент  (80, 443)
    $IPT -A OUTPUT -p tcp -m tcp -m multiport -o $INET_IFACE --sport $UNPRIPORTS -j ACCEPT --dports 80,443
    $IPT -A INPUT -p tcp -m tcp -m multiport -i $INET_IFACE --dport $UNPRIPORTS -j ACCEPT --sports 80,443!  --syn
    
    # Разрешаем finger, whois, gorper, wais. Traceroute — разрешаем себе, к нам не проломятся — запрещено. Telnet 
    # запретил, чтобы соблазна не было передавать пароли прямым текстом.
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 20 -j ACCEPT
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 20 --sport $UNPRIPORTS -j ACCEPT!  --syn
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport $UNPRIPORTS --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport $UNPRIPORTS -j ACCEPT!  --syn
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 23 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 23 -j ACCEPT!  --syn
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 79 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 79 -j ACCEPT!  --syn
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 43 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 43 -j ACCEPT!  --syn
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 70 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 70 -j ACCEPT!  --syn
    $IPT -A OUTPUT -p tcp -m tcp -o $INET_IFACE --dport 210 --sport $UNPRIPORTS -j ACCEPT
    $IPT -A INPUT -p tcp -m tcp -i $INET_IFACE --dport $UNPRIPORTS --sport 210 -j ACCEPT!  --syn
    $IPT -A OUTPUT -p udp -m udp -o $INET_IFACE --dport 33434:33523 --sport 32769:65535 -j ACCEPT
      
    # Разрешаем прохождение DHCP запросов через iptables. Нужно, если IP адрес динамический.
    $IPT -A OUTPUT -p udp -m udp -o $INET_IFACE --dport 67 --sport 68 -j ACCEPT
    $IPT -A INPUT -p udp -m udp -i $INET_IFACE --dport 68 --sport 67 -j ACCEPT
    
}
 
case  «$1» in
start)  echo -n  «Starting firewall: iptables»
        start_fw
        echo  «
        ;;
stop)   echo -n  «Stopping firewall: iptables»
        iptables -F
        iptables -X
        echo  «
        ;;
save)   echo -n  «Saving firewall: iptables»
        iptables-save > /etc/rules-save
        echo  «
        ;;    
restart) echo -n  «Restarting firewall: iptables»
        iptables -F
        iptables -X
        cat /etc/rules-save | iptables-restore
        echo  «
        ;;
reload|force-reload) echo -n  «Reloading configuration files for firewall: iptables»
        echo  «
        ;;
*)      echo  «Usage: /etc/init.d/rc.iptables start|stop|restart|reload|force-reload»
        exit 1 
        ;;
esac
exit 0 
Ну вот и все. Выше рассмотрена настройка Iptables для домашней машины. Сохраните этот скрипт, сделайте его выполняемым и поместите в /etc/init.d/; если там уже есть файл rc.firewall, удалите его, выполнив команду из этого каталога:
$ update-rc.d -f rc.firewall remove
Дальше сделайте, чтобы новый скрипт инициализации запускался во время загрузки:
$ update-rc.d new.rc.iptables start 40 S.  stop 89 0 6. 
Теперь правила Iptables вступают в силу во время загрузки. Если вы хотите остановить Iptables:
$ /etc/init.d/rc.iptables stop
Для сохранения правил в /etc/rules-save
$ /etc/init.d/rc.iptables save
Для нового запуска Iptables:
$ /etc/init.d/rc.iptables start