Новые книги

Задачи рефакторинга тесно связанны с задачами написания понятного, удобного кода. Соответственно, если я пишу как следует писать или чего лучше избегать — это к рефакторингу не относится. С одной стороны. Но ведь следуя этим рекомендациям, вы можете пересмотреть свой код и исправить потенциальные ошибки. А вот это уже чистой воды рефакторинг. Поэтому я не буду особенно зацикливаться именно на рефакторинге, а буду рассказывать о хорошем, понятном коде.

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

Примеры я буду приводить на языке Object Pascal. В основном я работаю на нём, пишу на Delphi. Предвидя нападки со стороны поклонников C-подобных языков, скажу два тезиса:
Представьте: вы садитесь в машину, берете в руки книгу и отправляетесь в путь. Вам не нужно управлять машиной – она управляет собой сама. Вам даже не нужно говорить ей, куда ехать, потому что она уже сверилась с вашим ежедневником, а он, в свою очередь, сам себя заполнил, проверив вашу почту и электронный план тренировок. Автомобиль везет вас не в магазин, потому что дроны уже доставили продукты в ваш холодильник, который еще на прошлой неделе сам отправил заявку в интернет-магазин), и не на работу (необходимость в офисе давно отпала), а, скажем, в оперу. Такой мир предлагает нам Интернет вещей.

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

Сэмюэл Грингард предлагает, не откладывая, отправиться в будущее и поразмыслить над важными вопросами, ответы на которые нам вскоре будут буквально жизненно необходимы.

Netfilter and IP Tables (2.4 Kernels)

Netfilter и таблицы IP (ядра 2.4)

При разработке IP Firewall Chains, Paul Russell решил, что IP firewall должен быть проще. Он стал совершенствовать код фильтра и создал пакет, который оказался много проще и мощнее. Это netfilter.

Внимание: во время подготовки этой книги проект netfilter еще не был стабильным. Я надеюсь, что Вы простите ошибки в описании netfilter или связанных с пакетом инструментальных средств конфигурации, которые следуют из изменений, происшедших после подготовки этого материала. Если возникают сомнения, обратитесь к документам HOWTO в сети. Я постарался описать netfilter максимально точно.

Так, что было неправильно с IP chains? Они значительно улучшили эффективность и управление правилами firewall. Но они все равно обрабатывали пакеты очень длинным путем, особенно в связке с другими возможностями firewall, например, IP masquerade (описан в главе 11) и другими формами трансляции адреса. Часть этой проблемы существовала потому, что IP masquerade (маскировка IP) и Network Address Translation (сетевая трансляция адресов) были разработаны независимо от IP firewall и интегрированы в него позже.

Однако, имелись другие проблемы. В частности, набор правил input описывал весь входной поток уровня IP как одно целое. Этот набор воздействовал как на пакеты, которые предназначены для этого компьютера, так и на те, которые будут переданы им далее. Это было неправильно потому, что такой подход спутал функцию цепочки input с функцией цепочки forward, которая применялась только к исходящим пакетам. Возникали весьма замысловатые конфигурации для разной обработки входящих и транслируемых пакетов.

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

Ключевыми различиями стало удаление из ядра кода для маскировки IP и изменение в логике работы наборов правил input и output. Появился новый расширяемый инструмент конфигурации iptables.

В IP chains набор правил input применяется ко всем пакетам, полученным компьютером, независимо от того, предназначены ли они для локального компьютера или направлены на другой компьютер. В netfilter набор правил input применяется только к пакетам, предназначенным для локального компьютера. Цепочка forward теперь применяется исключительно к пакетам, предназначенным для передачи другому компьютеру. В IP Сhains набор правил output применяется ко всем пакетам, исходящим с компьютера, независимо от того, сгенерированы ли они на локальном компьютере. В netfilter этот набор применяется только к пакетам, сгенерированным на этом компьютере, и не применяется к пакетам, проходящим транзитом. Это изменение резко упростило настройку.

Еще одной новостью стало вынесение компонентов работы с маскировкой IP в отдельные модули ядра. Они были переписаны как модули netfilter.

Рассмотрим случай конфигурации, в которой по умолчанию для input, forward и output задана стратегия deny. В IP chains для пропуска всех пакетов потребовалось бы шесть правил.

В netfilter эта сложность исчезает полностью. Для сервисов, которые должны проходить через firewall, но не завершаются на локальном компьютере, требуются только два правила: по одному для прямого и обратного прохода в наборе правил forward.

Документ PACKET-FILTERING-HOWTO предлагает очень подробный список изменений, которые были сделаны. Поэтому давайте сосредоточимся на более практических аспектах.

Обратная совместимость с ipfwadm и ipchains

Замечательная гибкость Linux netfilter иллюстрируется способностью подражать интерфейсам ipfwadm и ipchains. Эмуляция делает переход к новому поколению программного обеспечения firewall немного проще.

Два модуля ядра из netfilter с именами ipfwadm.o и ipchains.o обеспечивают обратную совместимость с ipfwadm и ipchains. Можно загрузить одновременно только один из этих модулей и использовать его только при условии, что модуль ip_tables.o не загружен. Когда соответствующий модуль загружен, netfilter работает аналогично заданной реализации firewall.

Чтобы netfilter копировал интерфейс ipchains скомандуйте:

# rmmod ip_tables
# modprobe ipchains
# ipchains
...

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

Утилита iptables используется для настройки правил netfilter. Синтаксис заимствован у ipchains, но имеет важное отличие: он расширяемый. Это означает, что функциональные возможности могут быть расширены без перекомпиляции пакета. Для этого используются разделяемые библиотеки. Имеются стандартные расширения, ряд которых мы сейчас изучим.

Перед использованием команды iptables Вы должны загрузить модуль ядра netfilter, который позволяет ей работать. Проще всего сделать это командой modprobe:

# modprobe ip_tables

Команда iptables используется для настройки IP filter и Network Address Translation. Для этого используются две таблицы: filter и nat. Если не задана опция -t, используется таблица filter. Доступны пять встроенных цепочек (наборов правил): INPUT и FORWARD для таблицы filter, PREROUTING и POSTROUTING для таблицы nat и OUTPUT для всех таблиц. В этой главе я расскажу только о таблице filter, таблица nat описана в главе 11.

Синтаксис команд iptables в общем виде таков:


iptables command rule-specification extensions

Теперь мы будем рассмотрим некоторые параметры подробно, после чего перейдем к примерам.

Команды

Команды позволяют управлять правилами и наборами правил iptables. К IP firewall относятся:

-A chain

Добавляет одно или большее количество правил к концу назначенной цепочки. Если имя машины задано для источника или адресата, и оно соответствует нескольким IP-адресам, правило будет добавлен для каждого адреса.

-I chain rulenum

Добавляет одно или большее количество правил в начало назначенной цепочки. Если имя машины задано для источника или адресата, и оно соответствует нескольким IP-адресам, правило будет добавлен для каждого адреса.

-D chain

Удаляет одно или несколько правил из определенной цепочки, которая соответствует заданной спецификации правил.

-D chain rulenum

Удаляет правило в позиции rulenum указанной цепочки. Нумерация начинается с 1.

-R chain rulenum

Заменяет правило в позиции rulenum указанной цепочки заданным правилом.

-C chain

Проверяет пакет спецификацией правила по заданной цепочке. Эта команда возвратит сообщение, описывающее, как пакет обработан цепочкой. Это очень полезно для тестирования Вашей конфигурации firewall, и мы рассмотрим это подробно чуть позже.

-L [chain]

Выведет список правил в наборе, или всех правил, если конкретный набор не задан.

-F [chain]

Стирает правила в наборе или во всех наборах, если конкретный набор не задан.

-Z [chain]

Обнуляет счетчикик пакетов и байтов для всех правил в наборе или для всех наборов, если конкретный набор не задан.

-N chain

Создает новую цепочку с заданным именем. Таким способом создаются задаваемые пользователем цепочки.

-X [chain]

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

-P chain policy

Задает стратегию по умолчанию для указанной цепочки. Допустимые стратегии: ACCEPT, DROP, QUEUE и RETURN. ACCEPT пропускает пакет. DROP отбрасывает пакет. QUEUE передает пакет пользовательской цепочке для дальнейшей обработки. RETURN заставляет IP firewall вернуться к цепочке, правило которой вызвало эту ситуацию, и предписывает продолжить ее обработку со следующего правила.

Параметры определения правил

Параметры iptables создают правила, определяя какие типы пакетов соответствуют критериям. Если любой из этих параметров опущен из спецификации правила, он предполагается по умолчанию.

-p [!]protocol

Указывает протокол, соответствующий правилу. Допустимы имена протоколов tcp, udp, icmp. Можно задать номер протокола для протоколов, которые здесь не определены. Например, 4 для протокола ipip. Если задан префикс !, правило превращается в отрицательное, и принимаются все пакеты, не соответствующие этому протоколу. Значение по умолчанию: все протоколы.

-s [!]address[/mask]

Указывает исходный адрес и порт, с которого пришел пакет. Адрес может задавать имя машины, имя сети или IP-адрес. Опция mask задает сетевую маску. Она может быть задана в обычной форме (например, /255.255.255.0) или в новой (например, /24). Опция port задает порт TCP или UDP, или тип пакетов ICMP. Вы можете задать спецификацию порта только, если Вы задали параметр -p с одним из протоколов tcp, udp или icmp. Порты могут быть определены как диапазон, определяя верхние и нижние границы диапазона с двоеточием в качестве разделителя. Например, 20:25 определяет порты с 20 по 25 включительно. Символ ! превращает правило в его противоположность.

-d [!]address[/mask]

Задает адрес и порт назначения. Во всем остальном аналогичен параметру -s.

-j target

Указывает, что делать при срабатывании правила. Допустимые действия: ACCEPT, DROP, QUEUE и RETURN. Ранее я уже описал значение каждого действия. Однако, Вы можете также задать имя определяемой пользователем цепочки, в которой продолжится обработка. Если этот параметр опущен, будут только изменены данные пакетов и счетчиков, но ничего с этим пакетом сделано не будет.

-i [!]interface-name

Задает интерфейс, с которого пришел пакет, или через который пакет будет передан. Символ ! переворачивает результат сравнения. Если имя интерфейса кончается на +, ему будут соответствовать все интерфейсы, имена которых начинаются на заданную строку. Например, -i ppp+ совпадает со всеми PPP-интерфейсами, а -i ! eth+ соответствует всем интерфейсам, кроме Ethernet.

-o [!]interface-name

Указывает, что пакеты будут передаваться через этот интерфейс. В остальном аналогично -i.

[!] -f

Указывает, что это правило применяется ко второму и последующим, но не к первому, фрагментам пакета.

Опции

Опции iptables имеют более широкое значение. Они предоставляют доступ к тайным свойствам этой программы.

-v

Предписывает iptables выдавать подробную информацию.

-n

Предписывает iptables использовать IP-адреса и порты, не пытаясь преобразовать их в имена.

-x

Любые числа в выводе iptables будут точными (округление не используется).

- -line-numbers

Задает номера строк, которые нужно отобразить при распечатке наборов правил. Номер строки будет соответствовать позиции правила внутри цепочки.

Расширения (Extensions)

Ранее мы рассматривали, что iptables расширяется с помощью модулей. Имеется стандарт расширений, который обеспечивает некоторые из свойств ipchains. Чтобы использовать расширение, Вы должны определить имя через параметр -m name в iptables. Следующий список показывает опции -m и -p, которые устанавливают расширения контекста.

TCP-расширения: использование с опциями -m tcp -p tcp

- -sport [!] [port[:port]]

Определяет порт, который должен использовать источник пакетов, чтобы соответствовать этому правилу. Можно задать диапазон, указав верхние и нижние границы, например: 20:25 задает все порты с 20 по 25 включительно. Символ ! переворачивает значение.

- -dport [!] [port[:port]]

Задает порт, который должны использовать исходящие пакеты. В остальном аналогичен - -sport.

- -tcp-flags [!] mask comp

Определяет, что это правило должно работать, когда флажки в TCP-пакете соответствуют определениям mask и comp. mask задает (через запятую) перечень флажков, а comp указывает их состояние. Допустимы флажки: SYN, ACK, FIN, RST, URG, PSH, ALL или NONE. Это сложный параметр: ознакомьтесь со значением флажков в каком-нибудь хорошем описании протокола TCP, например, в RFC-793. Действие символа ! обычное для всех правил: он переворачивает значение.

[!] - -syn

Устанавливает, что у пакета должны быть выставлены в 1 флажок SYN и в 0 флажки ACK и FIN. Пакет с этими параметрами используется для создания TCP-соединения, и эту опцию можно использовать для отлова запросов подключения. Эта опция эквивалент для:

- -tcp-flags SYN,RST,ACK SYN
Когда Вы используете оператор отрицания, правило будет соответствовать всем пакетам, флажки SYN и ACK которых вместе не установлены в 1.

UDP-расширения: использование с опциями -m udp -p udp

- -sport [!] [port[:port]]

Определяет порт, который должен использовать источник пакетов, чтобы соответствовать этому правилу. Можно задать диапазон, указав верхние и нижние границы, например: 20:25 задает все порты с 20 по 25 включительно. Символ ! переворачивает значение.

- -dport [!] [port[:port]]

Задает порт, который должны использовать исходящие пакеты. В остальном аналогичен - -sport.

ICMP-расширения: использование с опциями -m icmp -p icmp

- -icmp-type [!] typename

Указывает подходящие этому правилу сообщения ICMP. Типы сообщений можно задать номерами или именами. Допустимые имена: echo-request, echo-reply, source-quench, time-exceeded, destination-unreachable, network-unreachable, host-unreachable, protocol-unreachable и port-unreachable.

MAC-расширения: использование с опциями -m mac

- -mac-source [!] address

Задает, с какого адреса в сети Ethernet должен придти пакет для этого правила. Это имеет смысл только в правилах input или forward, поскольку любой передаваемый нами пакет должен соответствовать правилам output.

Вернемся к нашим примерам

Теперь используя netfilter, Вы могли бы просто загружать модуль ipchains.o и работать с ним, как с ipchains. Вместо этого, мы повторно напишем наши правила, используя iptables.

Как и раньше, мы предполагаем, что есть сеть некоей организации, на Linux-машине запущен firewall. Все внутренние пользователи имеют доступ к WWW-серверам в Internet, но и только.

Если сеть использует сетевую маску в 24 бита (класс C) и имеет адрес сети 172.16.1.0, нужно использовать правила iptables:

# modprobe ip_tables
# iptables -F FORWARD
# iptables -P FORWARD DROP
# iptables -A FORWARD -m tcp -p tcp -s 0/0 --sport 80 -d 172.16.1.0/24 / --syn -j DROP
# iptables -A FORWARD -m tcp -p tcp -s 172.16.1.0/24 --sport / 80 -d 0/0 -j ACCEPT
# iptables -A FORWARD -m tcp -p tcp -d 172.16.1.0/24 --dport 80 -s 0/0 -j / ACCEPT

В этом примере iptables работает точно как команда ipchains. Вся разница в том, что надо предварительно загрузить модуль ip_tables.o. Обратите внимание, что iptables не поддерживает опцию -b, так что мы должны отдельно задать правило для каждого направления.