Подробная настройка iptables
Материал из Википедии - свободной энциклопедии.
- Вернутся в раздел руководства
Пожалуйста приведите эту статью в соответствии с wiki разметкой, и затем удалите {{Wikify}} из текста статьи
Содержание |
1.1 Прежде чем двигаться дальше - убедитесь, что ... |
Введение
Документация по iptables в сети не рассчитана на новичков. В этой статье будет сжато и быстро описаны команды, затем, возможно, будут правки и добавления для расширенного обьяснения. Так что это будет минимальная установка которую мы в дальнейшем расширим и упрочним с помощью правил.
- Так же примите во внимание, что будет использованно pppoe соединение и 2.6.x ядро. Для настройки сетевой карты надо будет заменить ppp0 на eth0 (или подходящую по смыслу вашу сетевую карточку глядящую в интернет)
Прежде чем двигаться дальше - убедитесь, что ...
- 1.Всё ваше аппаратное обеспечение работоспособно. То есть вы все подключили, модули грузятся, девайсы видны в системе. Полезно в начале проверить, что соединение с интернетом возможно и без всяких там iptables. Нет ничего хуже, чем в течении многих часов возиться с упрямой программой, ругая её почём зря, а потом понять, что сетевуха не работает или модем сконфигурирован неправильно.
- 2.Вы читали маны по теме. Предполагается, что пока вы изучаете это руководство, man iptables постоянно открыт в соседнем терминале для точного понимания и уточнения, что же та или иная команда означает на самом деле.
- 3.Вы имеете представление о сетевых технологиях и Вы знакомы с администрированием Linux и Gentoo Linux в частности. То есть необходимы навыки работы с такими базовыми вещами как ifconfig, rc-update, /etc/conf.d/net, и так далее. Если для вас это пока пустые звуки, то, пожалуйста предварительно изучите The Gentoo Handbook (http://www.gentoo.org/doc/en/handbook/index.xml) и Linux Help's Networking Basics 101 (http://www.linuxhelp.ca/guides/networkbasics/)
Конфигурация ядра
Все что вам нужно - это включить поддержку iptables.
Device Drivers---> Networking Support---> Networking Options----> Network Packet Filtering (replace Ipchains)---> Netfilter Configuration
- Я включил все опции как модули (с тем рассчетом, что я захочу попробовать другие опции позже) и добавил ip_iptables в modules.autoload. Это загрузит еще несколько модулей в качестве зависимостей. Позже вы можете добавить модуль ip_conntrack для логирования. Не забудьте сделать "modprobe ip_tables" до запуска скриптов
Необходимые утилиты
Далее вы должны установить пакет iptables:
- emerge iptables
Конфигурация интерфейсов
В моем случае имеется 3 сетевых адаптера. Один подключен к WAN через ppoe. Другие два - к моей внутренней сети. Для того, чтобы не было проблем с iptables и маскардингом (NAT'ом), они должны быть сконфигурированы для различных подсетей. Для примера, 2 сетевых адаптера подключены к моим внутренним компьютерам (внутренние сетевые интерфейсы). Им присвоены IP-адреса: 192.168.1.1 и 192.168.2.1.
Следует заметить, что будет лучше если подключать эти внутренние адаптеры в любое сетевое устройство, такие как свитч и хаб. Для pppoe подключений мы должны убедиться, что сетевой адаптер подключен к внешнему миру, то есть внешним интерфейсам не присвоены никакие IP-адреса. Его запись в /etc/conf.d/net должна оставаться пустой. Это делается потому, что pppoe выступает в качестве виртуального устройства, которое включается вслед за сетевым интерфейсом. Мы также должны присвоить правильные сетевые маски и широковещательные адреса для этих интерфейсов. Ваш conf.d/ должна выглядеть примерно так:
Сервер
File: /etc/conf.d/net |
# Для pppoe подключений вы не должны указывать значения для [[eth0]], # просто добавьте net.ppp0 или rc-pppoe в default уровень загрузки. iface_eth1="192.168.1.1 broadcast 192.168.1.255 netmask 255.255.255.0" iface_eth2="192.168.2.1 broadcast 192.168.2.255 netmask 255.255.255.0" |
- Заметьте, что не было указано никаких шлюзов.
Клиент1
File: /etc/conf.d/net |
iface_eth0="192.168.1.77 broadcast 192.168.1.255 netmask 255.255.255.0" gateway="eth0/192.168.1.1" |
Клиент2
File: /etc/conf.d/net |
iface_eth0="192.168.2.77 broadcast 192.168.2.255 netmask 255.255.255.0" gateway="eth0/192.168.2.1" |
Шлюз для клиентов установлен на внутренний IP сетевого интерфейса сервера, что и логично. Теперь добавьте все интерфейсы в default уровень загрузки и перезапустите подключения:
- Для сервера:
- 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
Проверка настроек
Теперь убедитесь в том, что ваш сервер подключен к интернету, а также все интерфейсы могут пинговать друг друга. Для сервера:
Code: ping |
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
Scripting
- Теперь интересная часть... iptables и NAT(трансляция адресов). Для начала сделаем простое перенаправление адресов с минимальными правилами, чтобы убедиться что можем выходить в сеть. *ВНИМАНИЕ* Если вы параноик, то это не самое секретное, что можно сделать... мы открываемся в сеть с мизерной защитой. Однако будем считать, что сеть настраиваем для дома или там игрового класса:
Code: |
#!/bin/bash IPTABLES='/sbin/iptables' # Определяем интерфейсы EXTIF='ppp0' INTIF1='eth1' INTIF2='eth2' # Включаем форвардинг ip в ядре. /bin/echo 1 > /proc/sys/net/ipv4/ip_forward # Сбросить правила и удалить цепочки $IPTABLES -F $IPTABLES -X # Включаем маскарадинг для разрешения доступа в интернет $IPTABLES -t nat -A POSTROUTING -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. Если все нормально, то можно переходить ниже по тексту. Если нет - проверьте синтаксические ошибки и прочее... Удостоверьтесь, что IP-адреса и маски клиентов и сервера введены правильно... Ну или...
- Если все работает, как задумали, сохраняем конфигурацию:
- /etc/init.d/iptables save
- И бэкапим вашу рабочую конфигурацию для возможного восстановления "как было":
- cp /var/lib/iptables/rules-save /var/lib/iptables/rules.working
- Проверим iptables start-up скрипт перед тем как добавить iptables в default runlevel:
- /etc/init.d/iptables start; /etc/init.d/iptables stop; /etc/init.d/iptables start
- Смысл в запуске-остановке-запуске в том, что у нас нет скрипта запуска iptables... поэтому нужно “инициализировать” статус перед остановкой. Остановка, по существу, обнуляет настройки и возвращает все к исходному. Перезапуск покажет нам работает ли наша сеть после перезагрузки. Если все в порядке, то добавляем iptables в default runlevel:
- rc-update add iptables default
- Не забудем также установить net.ipv4.ip_forward = 1 в /etc/sysctl.conf.
- Часть II рассматривает правила установок и политики для обороны Вашего маршрутизатора.
ЧАСТЬ II - Оборона Firewall
- Далее мы сделаем наш, уже работающий файрвол безопасным, т.е. защищающим нашу систему от проникновений извне. На самом деле нам придется настроить файрвол таким образом, чтобы он не только защищал нас, но и защищал внешнюю сеть от нас. :) Защита такого рода является обязательной, она нужна для того, чтобы, в том случае, если наша система все-таки была взломана, взломщик не смог воспользоваться нашими ресурсами для дальнейшей атаки любого рода. Этот аспект является важнейшим в сетях класса SOHO, т.е. небольших офисах. Обыкновенно вирусы не оказывают никакого влияния на малые сети и заражение ими редко приводит к потереданных. Для нас, пользователей *nix, этой проблемы практически не существует. В любом случае, т.к. небольшие сети, как правило, защищены гораздо хуже больших, хакеры стараются использовать их в качестве “опорной базы” для DoS атак, или другой своей извращенной активности.
- В последующем я опишу всю конфигурацию по кусочкам, дабы мы смогли бы проверить пошагово каждый фрагмент. Каждый шаг может потребовать от вас вставки чего-либо до, после или в середину указываемого скрипта. Все действия производятся так что бы (я надеюсь) ваша не работала только лишь коротки промежуток времени во время настройки. Это сделано мною потому как я предположил что у многих из вас (таких как я) выделен сервер под Firewall. И так как я предпочитаю настраивать свой сервер через SSH, the network going down can be a PITA involving crawling under tables and such. Если же вы смелы, то вы можете скопировать скрипт в конце этого документа и запустить его на своей машине. Этот скрипт должен быть работоспособен на все сто, но тестировал я его только на своей машине, так что ymmv (http://lingvo.yandex.ru/en?text=YMMV).
Установка переменных окружения
- Вы можете установить необходимые переменные окружения следующим скриптом:
Code: |
#!/bin/sh # # Внешний интерфейс EXTIF="ppp0" # Внутренний интерфейс INTIF="eth1" # Loop device/localhost 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" # Последующие команды могут работать некорректно при локализации. # Установка переменных окружения внешнего интерфейса 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" # Due to absence of EXTBC I manually set it to 255.255.255.255 # this (hopefully) will serve the same purpose # Установка переменных окружения внутреннего интерфейса 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
- Теперь мы должны установить ACCEPTS, что позволит нам соединяться с нашим сервером. На самом деле это очень больной вопрос. Правила для надежного маршрутизатора должны запрещать нежели разрешать. Однако, если вы сделаете это, то потеряете все соединения. Продолжайте тестирование пока не будете уверены что ваш ACCEPT работает как надо. Однако думаю, что сперва мы введем следующее и это будет предпоследним правилом в окончательном скрипте.
Code: |
$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
- Теперь мы определим пару цепочек (chains) которые должны фиксировать события DROP и REJECT. Таким образом нам не придется вводить отдельные строки для каждой введенной команды. Сообщения о событиях будут отправлены сервису syslog, (обычно они фиксируются в /var/log/messages). Позже я (переводчик не имеет к этому никакого отношения) отправлюсь писать скрипт для sed/grep который будет разбирать и организовывать события для облегченного просмотра и установлю это как ежедневную работу для сервиса cron.
- Это должно быть вставлено непосредственно после приведенных выше определений. Когда закончите, запустите скрипт снова. Это не окажет влияния на функциональность сети, пока вы просто устанавливаете определения (как бы лучше выразиться?). Но это поможет убедиться что мы не имеем ошибок thusfar???.
Code: |
# ********** Цепочки журналирования событий ********** # # Теперь мы определяем несколько цепочек которые служат для записи # событий о сбрасываемых пакетах. Это позволит нам избежать ввода # команд для каждого правила. Сперва мы фиксируем 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 |
Сброс правил
- Теперь, когда мы видим наши устройства, правильно определенные, вставляем команду сброса правил. Однако все уже назначенные правила будут сброшены. Эти строки должны быть вставлены после определения утилит, которые заканчиваются строкой: ECHO='/bin/echo'
Code: |
# Сброс всех существующих и очистка персональных цепочек. 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 интерфейса, имеющие в качестве адреса назначения один из адресов наших интерфейсов.
Code: |
$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 атаки против кого либо другого. Если бы все системные администраторы следовали этим правилам, тогда много суровых и дорогих DoS атак не состоялись или были максимально ограниченными.
Code: Блокировка широковещательных пакетов |
$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 |
- Теперь проверим скрипт еще раз, чтобы убедиться в том, что мы не наделали синтаксических ошибок. Также отмечу, что мы используем определенные нами DROP1 цепочки (chains). Это означает, что отбрасываемые пакеты будут отмечены в журнале событий (log file).
Блокировка доступа в локальную сеть из глобальной
- Теперь мы блокируем доступ из глобальной сети в нашу локальную сеть, если мы не хотим что бы интернет провайдер назначал IP адреса для нашей внутренней сети.
Code: |
# Блокировать внешний доступ к локальной сети # Это позволит остановить боевых хакеров от использования # нашей сети как стартовой точки для других атак. # # Нижеприведенная строчка на человеческом языке будет выглядеть как # "если входящий пакет, пришедший на наш внешний интерфейс, # имеет адрес назначения, отличный от адреса нашего внешнего интерфейса, # то этот пакет не будет пропущен." $IPT -A INPUT -i $EXTIF -d ! $EXTIP -j DROPl |
Изолирование локальных сетей
- Теперь мы предпримем некоторые действия для наших локальных сетей. Другими словами - все пакеты не относящиеся к локальным сетям должны быть блокированы.
Code: |
# Теперь мы должны заблокировать все пакеты не относящиеся к # адресному пространству наших локальных сетей. # Запомните, если вы подключите свой ноутбук к другому разъему, # вам надо убедиться, что ваш сетевой адрес соответствует адресам этой сети. # # Первая локальная сеть $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 # Вторая локальная сеть $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 |
- Дальше мы сделаем некоторые дополнительные проверки исходящих пакетов и остановим все icmp пакеты кроме ping.
Code: |
# Дополнительная проверка $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
- Предполагая что у нас все сработало мы заткнем еще несколько портов, доступ по которым может представлять для нас серьезную опасность:
# COMmon ports: # 0 is tcpmux; SGI had vulnerability, 1 is common attack # 13 is daytime # 98 is Linuxconf # 111 is sunrpc (portmap) # 137:139, 445 is Microsoft # SNMP: 161,2 # Squid flotilla: 3128, 8000, 8008, 8080 # 1214 is Morpheus or KaZaA # 2049 is NFS # 3049 is very virulent 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-5!5 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 ""
- Ok, now with iptables each time we run the script it simply appends these to already existing chains...so things are probably getting a bit messy. For that reason we're going to jump to the beginning of our script....right after the enviroment variables for sed and grep, but before those of EXTIP and EXTBC and add a loop that deletes and flushes. This ensure we're working from a clean state. We didn't want to do that before because we couldn't have tested our script without either shutting down our connection or dropping our firewall completely. This script first sets all policies to DROP, than flushes and deletes our chains. In order to ensure that we can still ssh back into our server after a script restart we are going to append an INPUT chain for ssh. This should always be placed at the end of the script for now. This done in order to prevent a window from opening up while we reset rules which is a common error made:
# Deny than accept: this keeps holes from opening up # while we close ports and such $IPT -P INPUT DROP $IPT -P OUTPUT DROP $IPT -P FORWARD DROP
# Flush all existing chains and erase personal chains 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's
- Right afterwards we are going to activate the sysctl's for tcp_syncookies, icmp_echo_ignore_broadcasts, rp_filter, and accept_source_route. Heretofore many of the rules we've been "testing" haven't been able to actually work. In essence we were simply doing syntax error tests. Now our rules will be "for real":
echo 1 > /proc/sys/net/ipv4/tcp_syncookies echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Source Address Verification for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f done # Disable IP source routing and ICMP redirects 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
- Now we're going to add ftp connection tracking so that we won't get PASV errors when emerging packages:
# Opening up ftp connection tracking MODULES="ip_nat_ftp ip_conntrack_ftp" for i in $MODULES; do echo "Inserting module $i" modprobe $i done
Basic Service NAT
- Now back to end of our script, we are going to open up services for systems behind our firewall. I have included services such as IRC, MSN, ICQ, and NFS, FTP, domain, and time. And some others. The important thing to note is that these will ONLY be availabe BEHIND the firewall. So this will not enable someone to ftp into your LAN:
IRC='ircd' MSN=1863 ICQ=5190 NFS='sunrpc' # We have to sync!! PORTAGE='rsync' OpenPGP_HTTP_Keyserver=11371 # All services ports are read from /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 ""
- Now we're done all that's left is allowing us to ping the outside world by opening up pinging out of the firewall:
# Allow to ping out $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 # Allow firewall to ping internal systems $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
- Now we are going to default to DROP and Log anything that's left in case we overlooked something. The ACCEPT entry's we made at the very beginning would come right before this in the final script:
# Log & block whatever is left $IPT -A INPUT -j DROPl $IPT -A OUTPUT -j REJECTl $IPT -A FORWARD -j DROPl
- And your done. I had a friend nmap and nessus my connection with this rule set and as far as both of them were concerned the only thing it was even slightly sure about was that the ip existed...other than that nothing. I can IRC, MSN, ICQ, ane emerge sync to my hearts content.
- PART III will cover setting up some essential SOHO services like NFS and CUPS in a security conscious manner.
The full script
- А сейчас, полноценный скрипт во всей своей красе (Заодно я поместил форвардинг ssh в более подходящее для него место):
# Внешний интерфейс EXTIF=ppp0 # Внутренний интерфейс INTIF1=eth1 INTIF2=eth2 # Loop-устройство/localhost 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' # Последнее (но немаловажное) - пользователи JAMES=192.168.1.77 TERESA=192.168.2.77 # Deny вместо accept: предотвращает открытие "дыр" # в то время, как мы закрываем порты и все такое $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 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 # Установка переменных среды для внешнего интерфейса EXTIP="`$IFC $EXTIF|$G addr:|$SED 's/.*addr:\([^ ]*\) .*/\1/'`" #EXTBC="`$IFC $EXTIF|$G Bcast:|$SED 's/.*Bcast:\([^ ]*\) .*/\1/'`" EXTBC="255.255.255.255" EXTMSK="`$IFC $EXTIF|$G Mask:|$SED 's/.*Mask:\([^ ]*\)/\1/'`" EXTNET="$EXTIP/$EXTMSK" #echo "EXTIP=$EXTIP EXTBC=$EXTBC EXTMSK=$EXTMSK EXTNET=$EXTNET" echo "EXTIP=$EXTIP EXTBC=$EXTBC EXTMSK=$EXTMSK EXTNET=$EXTNET" # Так как EXTBC отсутствует, я устанавливаю ее вручную как it to 255.255.255.255 # Это (надеюсь) послужит тем же целям # Устанвка переменных среды для первого внутреннего интерфейса INTIP1="`$IFC $INTIF1|$G addr:|$SED 's/.*addr:\([^ ]*\) .*/\1/'`" INTBC1="`$IFC $INTIF1|$G Bcast:|$SED 's/.*Bcast:\([^ ]*\) .*/\1/'`" INTMSK1="`$IFC $INTIF1|$G Mask:|$SED 's/.*Mask:\([^ ]*\)/\1/'`" INTNET1="$INTIP1/$INTMSK1" echo "INTIP1=$INTIP1 INTBC1=$INTBC1 INTMSK1=$INTMSK1 INTNET1=$INTNET1" # Установка переменных среды для второго внутреннего интерфейса INTIP2="`$IFC $INTIF2|$G addr:|$SED 's/.*addr:\([^ ]*\) .*/\1/'`" INTBC2="`$IFC $INTIF2|$G Bcast:|$SED 's/.*Bcast:\([^ ]*\) .*/\1/'`" INTMSK2="`$IFC $INTIF2|$G Mask:|$SED 's/.*Mask:\([^ ]*\)/\1/'`" INTNET2="$INTIP2/$INTMSK2" echo "INTIP2=$INTIP2 INTBC2=$INTBC2 INTMSK2=$INTMSK2 INTNET2=$INTNET2" # Сейчас мы собираемся создать несколько собственных цепочек, результатом работы # которых будет логгинг отброшенных пакетов. Это поможет нам избежать необходимости # вводить команду log перед каждым отбрасыванием пакета, что мы хотим запротоколировать. # Первыми идут лог отброшенных пакетов и собственно отброс, затем лог пакетов с отказами # и собственно отказы. # Отключаем сообщения о том, что цепочки уже существуют (чтобы перезапуск был без мусора) $IPT -N DROPl 2> /dev/null $IPT -A DROPl -j LOG --log-prefix 'DROPl:' $IPT -A DROPl -j DROP $IPT -N REJECTl 2> /dev/null $IPT -A REJECTl -j LOG --log-prefix 'REJECTl:' $IPT -A REJECTl -j REJECT # Весь траффик от устройства 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 # Широковещательные пакеты блокируем $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 # Блокируем доступ к внутренней сети из WAN # Это также призвано не дать нечестивым крякерам использовать нашу сетку # в качестве отправной точки для атак на других людей # Перевод с языка iptables: # "если пришедшие на наружный интерфейс пакеты были отправлены не с выданного # nefarious адреса, выкинуть их как горячую картошку" $IPT -A INPUT -i $EXTIF -d ! $EXTIP -j DROPl # А сейчас мы блокируем внутренние адреса, кроме двух, присвоенных нашим двум # внутренним интерфейсам.....только помните, что если вы воткнете свой лэптоп или # какой другой pc в напрямую в одну из этих сетевых карт, то нужно удостовериться, # что они имеют именно эти IP-адреса или добавить соответствующий адрес отдельно. # Первый интерфейс/первая внутренняя сеть $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 # Второй интерфейс/вторая внутренняя сеть $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-проверка $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 # печально известные порты: # 0 - tcpmux; у SGI есть уязвимость, через которую можно атаковать # 13 - daytime # 98 - Linuxconf # 111 - sunrpc (portmap) # 137:139, 445 - Microsoft # SNMP: 161,2 # Флотилия Squid: 3128, 8000, 8008, 8080 # 1214 - Morpheus или KaZaA # 2049 - NFS # 3049 - очень заразный троян для Linux, часто путаемый с NFS # Часто атакуемые: 1999, 4329, 6346 # Частые трояны 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: # 98 - Linuxconf # 512-5!5 - rexec, rlogin, rsh, printer(lpd) # [очень серьезеные уязвимости; продолжаются ежедневные атаки] # 1080 - прокси-серверы Socks # 6000 - X (ЗАМЕЧАНИЕ. X через SSH - безопасен, и работает на порту TCP 22) # Блокировка 6112 (CDE у Sun и HP) TCPBLOCK="$COMBLOCK 98 512:515 1080 6000:6009 6112" # Порты UDP: # 161:162 - SNMP # 520=RIP, 9000 - Sangoma # 517:518 - talk и ntalk (самые надоедливые) UDPBLOCK="$COMBLOCK 161:162 520 123 517:518 1427 9000" 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 "" # Открываем отлеживание соединений по ftp MODULES="ip_nat_ftp ip_conntrack_ftp" for i in $MODULES; do echo "Inserting module $i" modprobe $i done # Защищаем некоторые распространенные клиенты для чата. # Уберите из списка допустимых для пущей безопасности. 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 --dport $i -m state --state NEW -j ACCEPT done echo "" # Разрешается ping наружу $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 # Файерволу разрешается ping внутренних систем $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 $IPT -A INPUT -i $INTIF1 -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT $IPT -t nat -A PREROUTING -j ACCEPT $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 # Заблокировать и запротоколировать все, что мы могли забыть. $IPT -A INPUT -j DROPl $IPT -A OUTPUT -j REJECTl $IPT -A FORWARD -j DROPl