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