HOWTO Использование iptables

Материал из Gentoo Linux Wiki

Перейти к: навигация, поиск

Содержание

[править] Часть I - Простейший фаервол

[править] Введение

Я обнаружил, что общедоступная документация по iptables является слишком сложной для новичка. В большинстве своём она рассчитана на людей, знакомых с ipchains и не освещает некоторые основополагающие понятия или принципы. Моим обычным подходом при изучении новых для меня вещей является так называемый "быстрый старт", без углубления в подробности. И только после такого начала я возвращаюсь к более пристальному изучению вопроса. Именно на таком принципе и основано данное руководство. Я помогу вам быстро подключиться к сети Интернет посредством вашего linux-маршрутизатора с минимальными усилиями, ну а после этого, шаг за шагом, вы будете добавлять всё новые и новые правила и настройки с тем чтобы в любой момент иметь возможность понять и отследить, какая именно команда вызвала возникшую проблему.

Кроме того описываемые здесь приёмы настроки ориентированы в основном на использование pppoe соединения с Интернет и версий ядер 2.6.x, поскольку это то, что использовал я сам. Несмотря на это, для вашей ситуации вам понадобится всего лишь заменить 'ppp0' на 'eth0' (или любой другой сетевой адаптер, используемый вами для подключения к Интернет, это прояснится позже).

[править] Соглашения и начальные предположения

  • Всё ваше аппаратное обеспечение функционирует нормально. Это значит, что вы должны протестировать его и убедиться в этом лично. Проверьте доступность вашего соединения с Интернет до настройки iptables, и тому подобное. Нет ничего неприятнее, чем провести часы, настривая что-нибудь новое, чтобы затем обнаружить неисправность вашей сетевой карты или неправильную настройку модема.
  • Вы можете прочитать соответствующую страницу man. Фактически, я предполагаю, что, изучая это руководство, вы периодически будете обращаться к ней, чтобы узнать, что означает та или иная команда.
  • Предполагается, что вы имеете понятие о сетях вообще и об администрировании Gentoo. Я имею в виду, что вы по крайней мере должны владеть основами использования таких утилит как ifconfig, rc-update, /etc/conf.d/net, и т.п. Если же нет, самое время обратиться за помощью к Настольной книге Gentoo или Linux Help's Networking Basics 101

[править] Конфигурирование ядра

Все, что вам нужно сделать здесь - это включить поддержку iptables.

Linux Kernel Configuration: Включение iptables
Networking--->
     Networking Options---->
           Network Packet Filtering Framework (Netfilter)--->
                Core Netfilter Configuration--->
                IP: Netfilter Configuration--->

Я установил все элементы как модули (на тот случай, если я захочу попробовать другие опции позже) и добавил модуль ip_tables в файл modules.autoload. Этот модуль загружает еще несколько, от которых он зависит. Позже вы можете попробовать ip_conntrack для ведения логов, если захотите.

Предупреждение: Не забудьте выполнить "modprobe ip_tables" перед запуском скриптов

[править] Необходимые инструменты

Теперь вам требуется установить пользовательские инструменты для настройки iptables:

emerge iptables

[править] Настройка интерфейсов

В моём случае есть 3 сетевые карты, одна из которых подключена к WAN через pppoe, а две другие -- к моей внутренней сети. Для того, чтобы все они могли работать с iptables и трансляцией сетевых адресов (NAT-ом), они должны работать в разных подсетях. Например, соединённые с моими внутренними подсетями ("внутренние интерфейсы") карты обладают адресами 192.168.1.1 и 192.168.2.1. Нужно отметить, эти внутренние карты допустимо подключать к любому сетевому устройству, такому как концентратор или коммутатор. В случае pppoe-соединения мы используем интерфейс, подключённый к внешнему миру, то есть ему не назначен IP адрес, и все касающиеся его настройки в файле /etc/conf.d/net должны быть очищены. Это необходимо потому, что интерфейс pppoe выступает в роли виртуального устройства, созданного на базе сетевого адаптера. Мы также должны указать правильные маски подсетей и широковещательные адреса этим интерфейсам. В результате ваш conf.d на сервере должен выглядеть примерно так:

Файл: /etc/conf.d/net

Сервер:

 # Для pppoe соединений мы не хотим устанавливать значения на eth0, просто добавим
 # net.ppp0 или rp-pppoe в ваш уровень запуска по умолчанию.
config_eth1=( "192.168.1.1 broadcast 192.168.1.255 netmask 255.255.255.0" )
config_eth2=( "192.168.2.1 broadcast 192.168.2.255 netmask 255.255.255.0" )

Клиент номер один:

config_eth0=( "192.168.1.77 broadcast 192.168.1.255 netmask 255.255.255.0" )
gateway="eth0/192.168.1.1"

Клиент номер два:

config_eth0=( "192.168.2.77 broadcast 192.168.2.255 netmask 255.255.255.0" )
gateway="eth0/192.168.2.1"

Как и ожидалось, в качестве шлюза по умолчанию для клиентов используется внутренний адрес NIC на сервере. Теперь добавьте все интерфейсы в уровень исполнения по умолчанию и перезапустите соединения:

[править] Перезапуск сервисов на сервере

rc-update add net.eth1 default
rc-update add net.eth2 default
rc-update add net.ppp0 default
/etc/init.d/net.eth1 start
/etc/init.d/net.eth2 start
/etc/init.d/net.ppp0 start

[править] Перезапуск сервисов на клиенте

/etc/init.d/net.eth0 restart

Теперь проверьте на стороне сервера, что вы подключены к интернету (клиентов можеть еще не быть) и что все интерфейсы могут пинговать друг друга.

[править] Проверка сервера

ping www.google.com 
ping 192.168.1.78 
ping 192.168.2.78
ping 192.168.1.77
ping 192.168.2.77

Теперь убедитесь, что ваши клиентские машины содержат правильные настройки DNS в файле /etc/resolv.conf.

[править] Пишем скрипты

Приступаем к самой интересной части... iptables и трансляция адресов. Для начала мы просто выполним перенаправление пакетов с абсолютным минимумом правил, просто чтобы убедиться, что мы можем покинуть сеть.

Предупреждение: Если вы параноик, то знайте, что это не самый безопасный способ. В результате вы откроете себя миру при очень слабой защите.
Файл: firewall.sh
 #!/bin/bash
  IPTABLES='/sbin/iptables'
 # Назовём для удобства наши интерфейсы
  EXTIF='ppp0'
  INTIF1='eth1'
  INTIF2='eth2'
 # Включаем перенаправление пакетов в ядре
  /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
 # Сбросим правила и удалим цепочки
  $IPTABLES -F
  $IPTABLES -X
 # Используем маскарадинг для того, чтобы первая локальная сеть получила доступ к интернет
  $IPTABLES -t nat -A POSTROUTING -s 192.168.1.0/24 -o $EXTIF -j MASQUERADE
# Используем маскарадинг для того, чтобы вторая локальная сеть получила доступ к интернет
  $IPTABLES -t nat -A POSTROUTING -s 192.168.2.0/24 -o $EXTIF -j MASQUERADE
 # Перенаправим трафик от  $INTIF1 на интерфейс $EXTIF, подключенный к интернету
  $IPTABLES -A FORWARD -i $INTIF1 -o $EXTIF -m state --state NEW,ESTABLISHED -j ACCEPT
 # Перенаправим трафик от  $INTIF2 на интерфейс $EXTIF, подключенный к интернету
  $IPTABLES -A FORWARD -i $INTIF2 -o $EXTIF -m state --state NEW,ESTABLISHED -j ACCEPT
  #echo -e "       - Разрешим доступ к серверу SSH"
  $IPTABLES -A INPUT --protocol tcp --dport 22 -j ACCEPT
  #echo -e "       - Разрешим доступ к HTTP-серверу"
  $IPTABLES -A INPUT --protocol tcp --dport 80 -j ACCEPT
 # Закроем любой другой доступ из интернет к нам через интерфейс $EXTIF
  $IPTABLES -A INPUT -i $EXTIF -m state --state NEW,INVALID -j DROP
  $IPTABLES -A FORWARD -i $EXTIF -m state --state NEW,INVALID -j DROP
Примечание: Этот скрипт был написан кем-то на другом форуме... Я уже потерял адрес того обсуждения..., но все благодарности отправляются туда.

Теперь проверьте на любом из ваших клиентских компьютеров, что он может выходить в Интернет или подсоединиться по ssh к вашему серверу. Если на данном этапе всё работает как надо, можно продолжить процесс настройки. Если же нет, проверьте ошибки и опечатки в конфигурации, а также возможность нормального пинга интерфейсов. Убедитесь, что на сервере и клиентах указаны правильные адреса и маски подсетей. В общем, принцип вы уловили. Если всё заработало, сохраните настройки:

/etc/init.d/iptables save

Затем сделайте резервную копию вашей рабочей конфигурации, чтобы быстро её восстановить, если что-то пойдёт не так:

cp /var/lib/iptables/rules-save /var/lib/iptables/rules.working

Перед добавлением iptables в уровень запуска по умолчанию проверьте, все ли нормально при запуске iptables:

/etc/init.d/iptables start; /etc/init.d/iptables stop; /etc/init.d/iptables start

Причина, по которой мы запускаем, затем останавливаем, затем опять запускаем, в том, что мы еще не запустили iptables, поэтому мы должны установить статус “запущено”. Остановка по существу стирает все настройки и приводит вас в исходное состояние. Перезапуск покажет вам, будет ли работать сеть после перезагрузки. Предполагая, что все нормально, добавляем iptables в уровень запуска по-умолчанию:

rc-update add iptables default

[править] PART II - Усиление защиты

Далее мы усовершенствуем наш фаервол, который уже вполне работоспособен. Через некоторое время мы должны получить набор правил и политик, которые не только защитят наше сервер, но и предотвратят его использование для атак в сети Интернет. К сожалению, часто этот аспект защиты упускается из вида, хотя он довольно важен с точки зрения общепринятого сетевого этикета. Я бы сказал, что для сетей класса SOHO это наиболее важный этап защиты. Вообще говоря, вирусная активность здесь не так уж страшна и редко приводит к потере данных, ну а для сетей, на 100%, состоящих из *nix-пользователей, такой угрозы практически не существует. Однако небольшие SOHO-класса сети менее защищены в отличие от крупных и представляют собой лакомый кусочек для злоумышленников, только и ищущих "стартовую площадку" для организации DoS-атак и прочих подобных нападений.

Дальнейшие усовершенствования мы будем проводить с таким расчётом, чтобы можно было легко добавлять и тестировать новые правила. Каждое такое дополнение потребует всего-навсего вставить несколько строк в начало, конец или в середину нашего скрипта. Действуя таким образом (мы надеемся) сеть будет недоступна только на короткий период настройки. Я делаю это таким образом, предпологая что многие из вас (как и я) имеют выделеный firewall/сервер под linux. Поскольку в основном работаю через ssh, падение сети это гемморой, включающий в себя лазанье под столами и тому подобное. Если вы смелый, можете просто скопировать скрипт в конец и запустить. Все должно работать, но тестировал их на своей системе, потому результат у вас может и отличаться.

[править] Устанавливаем переменные окружения

Определим переменные, указывающие на параметры наших интерфейсов, а также определим пути к нужным утилитам:

Файл: newfirewall.sh
#!/bin/sh
#
# ********** VARIABLE DEFINITIONS **********
#
# Внешний интерфейс
EXTIF="eth0"
# Внутренний интерфейс
INTIF="eth1"
# Интерфейс "обратной петли"
LPDIF="lo"
LPDIP="127.0.0.1"
LPDMSK="255.0.0.0"
LPDNET="$LPDIP/$LPDMSK"
# Пути к утилитам
IPT="/sbin/iptables"
IFC="/sbin/ifconfig"
G="/bin/grep"
SED="/bin/sed"
AWK="/usr/bin/awk"
ECHO="/bin/echo"
# Устанавливаем переменные окружения, описывающие внешний интерфейс
# Установите значение переменной LC_ALL в "en" 
# чтобы awk и ему подобные нормально работали в случае локализованного
# вывода данных на консоль
export LC_ALL="en"
EXTIP="`$IFC $EXTIF|$AWK /$EXTIF/'{next}//{split($0,a,":");split(a[2],a," ");print a[1];exit}'`"
EXTBC="255.255.255.255"
EXTMSK="`$IFC $EXTIF|$G Mask:|$SED 's/.*Mask:\([^ ]*\)/\1/'`"
EXTMSK="`$IFC $EXTIF|$AWK /$EXTIF/'{next}//{split($0,a,":");split(a[4],a," ");print a[1];exit}'`"
EXTNET="$EXTIP/$EXTMSK"
$ECHO "EXTIP=$EXTIP EXTBC=$EXTBC EXTMSK=$EXTMSK EXTNET=$EXTNET"
# Поскольку широковещательный адрес EXTBC на внешнем интерфейсе не определён,
# устанавливаем его вручную, равным 255.255.255.255, что (я надеюсь)
# не будет неправильным
# Устанавливаем переменные окружения, описывающие внутренний интерфейс
INTIP="`$IFC $INTIF|$AWK /$INTIF/'{next}//{split($0,a,":");split(a[2],a," ");print a[1];exit}'`"
INTBC="`$IFC $INTIF|$AWK /$INTIF/'{next}//{split($0,a,":");split(a[3],a," ");print a[1];exit}'`"
INTMSK="`$IFC $INTIF|$AWK /$INTIF/'{next}//{split($0,a,":");split(a[4],a," ");print a[1];exit}'`"
INTNET="$INTIP/$INTMSK"
$ECHO "INTIP=$INTIP INTBC=$INTBC INTMSK=$INTMSK INTNET=$INTNET"

[править] Описываем разрешающие правила iptables (ACCEPTS)

Хорошо, теперь мы определим содержимое цепочки ACCEPT с тем чтобы разрешить соединения с нашим сервером. На самом деле, это совсем неправильно. Любая защита должна скорее запрещать нежели разрешать. Но если вы так поступите сейчас, вы уничтожите все ваши соединения с сервером на время его тестирования и вообще не сможете проверить работоспособность цепочки ACCEPT. Поэтому, хотя мы и сделали это правило первым в списке, в окончательном варианте оно станет вторым.

Файл: accepts-firewall.sh
$IPT -t nat -A PREROUTING -j ACCEPT
# $IPT -t nat -A POSTROUTING -o $EXTIF -s $INTNET -j SNAT --to $EXTIP
# Закомментируйте следующую строку (там где "MASQUERADE"), чтобы не 
# использовать NAT для внутренней сети
$IPT -t nat -A POSTROUTING -o $EXTIF -s $INTNET1 -j MASQUERADE
$IPT -t nat -A POSTROUTING -o $EXTIF -s $INTNET2 -j MASQUERADE
$IPT -t nat -A POSTROUTING                       -j ACCEPT
$IPT -t nat -A OUTPUT                            -j ACCEPT
$IPT -A INPUT   -p tcp --dport auth --syn -m state --state NEW -j ACCEPT
$IPT -A INPUT   -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

[править] Описываем запрещающие правила iptables (цепочки DROP и REJECT)

Далее мы собираемся определить правила, которые будут записывать в лог события DROP и REJECT. Поступая таким образом, нам не нужно будет вводить целую строчку для подобных целей. Логи будут отправлены туда, куда обычно отправляются ваши системные логи по умолчанию(обычно это /var/log/messages) В дальнейшем я собираюсь написать grep/sed скрипт, который будет обрабатывать и упорядочивать их для удобства, и укажу планировщику выполнять его ежедневно. Он должен быть вставлен немедленно после вышеупомянутого определения цепочек. Когда вы все сделаете, запустите скрипт опять. Он не должен влиять на функциональность сети , так как мы всего лишь установили некоторые определения. Так мы просто будем уверены, что пока что не внесли никаких ошибок.

Файл: logging-firewall.sh
# ********** LOGGING CHAINS **********
#
# Теперь мы определим несколько правил, которые будут журналировать "сбрасываемые" пакеты
# Это позволит избежать вставки правила перед каждым исследуемым событием
# Первые правила затронут действие DROP, остальные обработают REJECT

# Подавить сообщения о существовании цепочки, чтобы сделать вывод на консоль при рестарте "чистым"
$IPT -N DROPl   2> /dev/null
$IPT -A DROPl -m limit --limit 3/minute --limit-burst 10 -j LOG --log-prefix 'FIREWALL DROP BLOCKED:'
$IPT -A DROPl   -j DROP
$IPT -N REJECTl 2> /dev/null
$IPT -A REJECTl -m limit --limit 3/minute --limit-burst 10 -j LOG --log-prefix 'FIREWALL REJECT BLOCKED:'
$IPT -A REJECTl -j REJECT
$IPT -N DROP2   2> /dev/null
$IPT -A DROP2 -m limit --limit 3/second --limit-burst 10 -j LOG --log-prefix 'FIREWALL DROP UNKNOWN:'
$IPT -A DROP2   -j DROP
$IPT -N REJECT2 2> /dev/null
$IPT -A REJECT2 -m limit --limit 3/second --limit-burst 10 -j LOG --log-prefix 'FIREWALL REJECT UNKNOWN:'
$IPT -A REJECT2 -j REJECT
# А теперь, для теста, журналируемый ACCEPT
$IPT -N ACCEPTl   2> /dev/null
$IPT -A ACCEPTl -m limit --limit 10/second --limit-burst 50 -j LOG --log-prefix 'FIREWALL ACCEPT:'
$IPT -A ACCEPTl   -j ACCEPT

[править] Очищаем таблицы

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

Файл: sed-script.sed
SED='/bin/sed'
 # Очистить все существующие цепочки и удалить вновь созданные
  CHAINS=`cat /proc/net/ip_tables_names 2>/dev/null`
  for i in $CHAINS
  do
   $IPT -t $i -F
  done
  for i in $CHAINS
  do
   $IPT -t $i -X
  done

[править] Локальные интерфейсы

Теперь мы готовы начинать применять правила. Для начала мы собираемся принять все пакеты от нашего устройства внутренней петли (loopback), если ip адрес соответствует одному из наших локальных интерфейсов:

$IPT -A INPUT   -i $LPDIF -s   $LPDIP   -j ACCEPT
$IPT -A INPUT   -i $LPDIF -s   $EXTIP   -j ACCEPT
$IPT -A INPUT   -i $LPDIF -s   $INTIP1  -j ACCEPT
$IPT -A INPUT   -i $LPDIF -s   $INTIP2  -j ACCEPT

[править] Блокируем широковещательный трафик

Теперь мы будем блокировать широковещательный трафик, как входящий, так и исходящий. Эта мера поможет нам избежать DoS-атак, и предотвратить использование DoS-атак нашими клиентами. Это часть того, что называется "Egress Protection" (Защита от использования нашей сети в качестве платформы для атак злоумышленника). Если бы все системные администраторы следовали этой политике, то многие серьёзные, стоившие жертвам немалых убытков, атаки можно было бы предотвратить, или же чрезвычайно снизить их эффективность.

# Blocking Broadcasts
 $IPT -A INPUT   -i $EXTIF  -d  $EXTBC   -j DROPl
 $IPT -A INPUT   -i $INTIF1 -d  $INTBC1  -j DROPl
 $IPT -A INPUT   -i $INTIF2 -d  $INTBC2  -j DROPl
 $IPT -A OUTPUT  -o $EXTIF  -d  $EXTBC   -j DROPl
 $IPT -A OUTPUT  -o $INTIF1 -d  $INTBC1  -j DROPl
 $IPT -A OUTPUT  -o $INTIF2 -d  $INTBC2  -j DROPl
 $IPT -A FORWARD -o $EXTIF  -d  $EXTBC   -j DROPl
 $IPT -A FORWARD -o $INTIF1 -d  $INTBC1  -j DROPl
 $IPT -A FORWARD -o $INTIF2 -d  $INTBC2  -j DROPl

Теперь перепроверим скрипт, дабы убедиться, что в нем нет синтаксических ошибок. Также замечу, что мы используем новоопределенную цепочку DROPl. Это значит, что информация об отброшенных пакетах будет отображена в логах.

[править] Блокирование доступа из WAN в LAN

Затем мы будем блокировать доступ из WAN в нашу LAN, отбрасывая все пакеты, не предназначенные для нашего IP-адреса, назначенного провайдером:

# Block WAN access to internal network
# This also stops nefarious crackers from using our network as a
# launching point to attack other people
# iptables translation:
# "if input going into  our external interface does not originate from our isp assigned
# ip address, drop it like a hot potato
 $IPT -A INPUT   -i $EXTIF -d ! $EXTIP  -j DROPl

[править] Защита внутренних LAN сетей

Тот же принцип можно применить для защиты внутренней сети -- все пакеты, приходящие из любой сети, отличной от заданной, будут отвергнуты:

# Заблокируем внутренние адреса всех сетей, кроме наших двух 
# интерфейсов. При прямом подключении компьютера
# к одному из интерфейсов, необходимо выдать этому компьютеру
# незаблокированный IP, или же добавить новое разрешающее правило,
# соответствующее новому IP.

# Interface one/internal net one
 $IPT -A INPUT   -i $INTIF1 -s ! $INTNET1 -j DROPl
 $IPT -A OUTPUT  -o $INTIF1 -d ! $INTNET1 -j DROPl
 $IPT -A FORWARD -i $INTIF1 -s ! $INTNET1 -j DROPl
 $IPT -A FORWARD -o $INTIF1 -d ! $INTNET1 -j DROPl
# Interface two/internal net two
 $IPT -A INPUT   -i $INTIF2 -s ! $INTNET2 -j DROPl
 $IPT -A OUTPUT  -o $INTIF2 -d ! $INTNET2 -j DROPl
 $IPT -A FORWARD -i $INTIF2 -s ! $INTNET2 -j DROPl
 $IPT -A FORWARD -o $INTIF2 -d ! $INTNET2 -j DROPl
# Теперь проведём добавочную проверку (Egress) исходящих пакетов и заблокируем все   
# icmp запросы, за исключением пингов:
# дополнительная проверка на Egress
 $IPT -A OUTPUT  -o $EXTIF -s ! $EXTNET -j DROPl
# Блокировка исходящих ICMP (исключение: PING)
 $IPT -A OUTPUT  -o $EXTIF -p icmp --icmp-type ! 8 -j DROPl
 $IPT -A FORWARD -o $EXTIF -p icmp --icmp-type ! 8 -j DROPl

[править] Ports

Если пока всё понятно, то теперь прикроем несколько портов, попытки атак на которые особо часты:

# Некоторые распространённые:
# 0 это tcpmux; SGI обладала уязвимостью, порт 1 также используется (нужно уточнение Fank)
# 13 это daytime
# 98 обслуживает Linuxconf
# 111 - sunrpc (или portmap)
# 137:139, 445 это протоколы NetBIOS от Microsoft
# SNMP: 161,2
# Squid flotilla: 3128, 8000, 8008, 8080
# 1214 это Morpheus или KaZaA
# 2049 - NFS
# 3049 это очень опасный Linux Trojan, mistakable for NFS
# Common attacks: 1999, 4329, 6346
# Common Trojans 12345 65535
 COMBLOCK="0:1 13 98 111 137:139 161:162 445 1214 1999 2049 3049 4329 6346 3128 8000 8008 8080 12345 65535"
# TCP ports:
# 98 is Linuxconf
# 512-515 is rexec, rlogin, rsh, printer(lpd)
#   [very serious vulnerabilities; attacks continue daily]
# 1080 is Socks proxy server
# 6000 is X (NOTE X over SSH is secure and runs on TCP 22)
# Block 6112 (Sun's/HP's CDE)
 TCPBLOCK="$COMBLOCK 98 512:515 1080 6000:6009 6112"

# UDP ports:
# 161:162 is SNMP
# 520=RIP, 9000 is Sangoma
# 517:518 are talk and ntalk (more annoying than anything)
 UDPBLOCK="$COMBLOCK 161:162 520 123 517:518 1427 9000 9 6346 3128 8000 8008 8080 12345 65535"

После определения переменных окружения, все что нам нужно сделать, это простой цикл для назначения правил для всех:

echo -n "FW: Blocking attacks to TCP port"
for i in $TCPBLOCK;
do
 echo -n "$i "
  $IPT -A INPUT   -p tcp --dport $i  -j DROPl
  $IPT -A OUTPUT  -p tcp --dport $i  -j DROPl
  $IPT -A FORWARD -p tcp --dport $i  -j DROPl
done
echo ""
echo -n "FW: Blocking attacks to UDP port "
for i in $UDPBLOCK;
do
 echo -n "$i "
   $IPT -A INPUT   -p udp --dport $i  -j DROPl
   $IPT -A OUTPUT  -p udp --dport $i  -j DROPl
   $IPT -A FORWARD -p udp --dport $i  -j DROPl
done
echo ""

Хорошо, теперь каждый раз при запуске нашего скрипта он будет добавлять правила к уже существующим, то есть можно столкнуться с весьма неожиданными результатами. Поэтому сейчас самое время вернуться к самому началу нашего скрипта, там где закончилось определение переменных окружения для sed и grep, перед вычислением EXTIP и EXTBC, и добавить несколько строчек кода для очистки существующих правил и удаления созданных нами цепочек. Это позволит нам быть уверенными в том, что мы добавляем правила, будучи в "изначальном" состоянии, когда набор правил еще пуст. Мы не делали этого прежде, поскольку до конца не могли убедиться в работоспособности нашего фаервола без того, чтобы прервать соединение или полностью отключить наш фаервол. Этот скрипт сначала устанавливает все политики как DROP, а затем очищает и удалает наши (то есть определённые нами) цепочки. Для того, чтобы убедиться в возможности зайти по ssh на наш сервер после рестарта скрипта, мы собираемся добавить правило в INPUT цепочку специально для ssh. Сейчас это правило должно быть помещено в самый конец скрипта. Это делается для того, чтобы не открывать дыры в фаерволе в момент рестарта скрипта, что я вляется очень распространённой ошибкой (это очень правильно и верно, поскольку если мы напишем много разрешающих правил, а последним напишем запрещающее, при этом не переопределяя политики по умолчанию, которые ACCEPT, то при рестарте, который все же занимает какое-то время, мы получим ACCEPT политику до того момента, пока не вступит в действие последнее правило, то есть DROP - прим. переводчика):

# Запретить все, прежде чем что либо разрешить: это избавит нас от дырок в защите
# пока мы открываем порты и осуществляем прочие разрешающие действия
 $IPT        -P INPUT       DROP
 $IPT        -P OUTPUT      DROP
 $IPT        -P FORWARD     DROP
# Сброс всех существующих цепочек и удаление всех созданных нами (цепочек)
 CHAINS=`cat /proc/net/ip_tables_names 2>/dev/null`
 for i in $CHAINS;
 do
   $IPT -t $i -F
 done
 for i in $CHAINS;
 do
   $IPT -t $i -X
 done
 $IPT -A INPUT   -i $INTIF1 -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT

[править] Sysctl

Теперь мы активируем sysctl для tcp_syncookies, icmp_echo_ignore_broadcasts, rp_filter и accept_source_route. До настоящего момента многие правила, которые мы "тестировали", фактически были неработоспособны. В сущности, мы тестировали их только на наличие синтаксических ошибок. Теперь зададим эти правила "по-настоящему":

echo 1 > /proc/sys/net/ipv4/tcp_syncookies
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Проверка адреса источника
for f in /proc/sys/net/ipv4/conf/*/rp_filter;
do
 echo 1 > $f
done
# Отключить маршрутизацию по источнику IP и перенаправления ICMP
for f in /proc/sys/net/ipv4/conf/*/accept_source_route;
do
 echo 0 > $f
done
for f in /proc/sys/net/ipv4/conf/*/accept_redirects;
do
 echo 0 > $f
done
echo 1 > /proc/sys/net/ipv4/ip_forward

Теперь добавим отслеживание соединений FTP, чтобы не получать ошибок PASV при использовании emerge:

# Открытие отслеживания соединений FTP
MODULES="ip_nat_ftp ip_conntrack_ftp"
for i in $MODULES;
do
 echo "Inserting module $i"
 modprobe $i
done

[править] Основы системы NAT

Теперь вернёмся в конец нашего скрипта, где откроем сетевые службы для программ за вашим сетевым экраном. Я включил такие службы как IRC, MSN, ICQ, NFS, FTP, domain, time и некоторые другие. Важно отметить, что эти службы будут доступны ТОЛЬКО программам ЗА сетевым экраном. Таким образом, это не позволит кому-нибудь подключиться через ftp к вашей локальной сети:

IRC='ircd'
MSN=1863
ICQ=5190
NFS='sunrpc'
# Нам нужна синхронизация!!
PORTAGE='rsync'
OpenPGP_HTTP_Keyserver=11371
# Все порты для сетевых служб взяты из /etc/services
TCPSERV="domain ssh http https ftp ftp-data mail pop3 pop3s imap3 imaps imap2 time $PORTAGE $IRC $MSN $ICQ $OpenPGP_HTTP_Keyserver"
UDPSERV="domain time"
echo -n "FW: Allowing inside systems to use service:"
for i in $TCPSERV;
do
 echo -n "$i "
 $IPT -A OUTPUT  -o $EXTIF -p tcp -s $EXTIP --dport $i --syn -m state --state NEW -j ACCEPT
 $IPT -A FORWARD -i $INTIF1 -p tcp -s $INTNET1 --dport $i --syn -m state --state NEW -j ACCEPT
 $IPT -A FORWARD -i $INTIF2 -p tcp -s $INTNET2 --dport $i --syn -m state --state NEW -j ACCEPT
done
echo ""
echo -n "FW: Allowing inside systems to use service:"
for i in $UDPSERV;
do
 echo -n "$i "
 $IPT -A OUTPUT  -o $EXTIF -p udp -s $EXTIP --dport $i -m state --state NEW -j ACCEPT
   $IPT -A FORWARD -i $INTIF1 -p udp -s $INTNET1 --dport $i -m state --state NEW -j ACCEPT
   $IPT -A FORWARD -i $INTIF2 -p udp -s $INTNET2
done
echo ""

Мы почти всё сделали. Осталось только разрешить себе пинговать другие системы:

# Разрешим пинг наружу
$IPT -A OUTPUT  -o $EXTIF -p icmp -s $EXTIP --icmp-type 8 -m state --state NEW -j ACCEPT
$IPT -A FORWARD -i $INTIF1 -p icmp -s $INTNET1 --icmp-type 8 -m state --state NEW -j ACCEPT
$IPT -A FORWARD -i $INTIF2 -p icmp -s $INTNET2 --icmp-type 8 -m state --state NEW -j ACCEPT
# Разрешим серверу пинговать машины локальной сети
$IPT -A OUTPUT  -o $INTIF1 -p icmp -s $INTNET1 --icmp-type 8 -m state --state NEW -j ACCEPT
$IPT -A OUTPUT  -o $INTIF2 -p icmp -s $INTNET2 --icmp-type 8 -m state --state NEW -j ACCEPT

Теперь нам нужно уничтожить и записать в журнал всё что мы недосмотрели. В окончательном варианте скрипта нижеприведённые правила должны стоять после правил ACCEPT:

# Ведение лога и блокировка всего что осталось
 $IPT -A INPUT             -j DROPl
 $IPT -A OUTPUT            -j REJECTl
 $IPT -A FORWARD           -j DROPl
Примечание: Обратите внимание, что правила DROPl и REJECTl не являются родными для iptables -- они были созданы нами ранее, чтобы каждый раз не набирать длинные правила заново. С моей точки зрения, это весьма спорное решение, поскольку осложняет читаемость. -- прим. перев.

Теперь всё сделано. Один знакомый проверял моё соедниение с помощью nmap и nessus, и единственное о чём могли сказать эти программы, что мой IP существует... и больше ни о чём. При том я свободно пользуюсь IRC, MSN, ICQ, синхронизацией в emerge к своему удовольствию.


Личные инструменты
На других языках