Фильтрующие межсетевые мосты на FreeBSD

Введение

Если вы еще не знаете, то DSL отличается от более традиционных методов подключения тем, что "розетка для подключения", которая располагается на стене, не имеет возможности по фильтрации пакетов. Если вы получили канал T1 или подобный, то он дается с маршрутизатором, который, в общем, может содержать пакетный фильтр. Если вы получили связь по каналу ISDN или коммутируемое соединение, вы также имеете дело либо с компонентом программной маршрутизации (а именно даемон PPP), который может сам выполнять фильтрацию, либо может работать вместе с фильтром на машине, обслуживающей соединение. Но в случае с DSL вы получаете всего лишь маленькую белую коробочку с несколькими световыми индикаторами и порт Ethernet, который передает и принимает ваш Интернет-трафик, и ничего более (в некотором смысле то же самое можно сказать о других широко распространенных на рынке высокоскоростных методах подключения, таких, как кабельные модемы или беспроводные каналы связи. К ним, впрочем, так же, как и к любой другой технологии, предоставляющие порт Ethernet без фильтрации пакетов, точно так же применима техника, о которой я собираюсь рассказать).

1. Зачем использовать сетевой мост с функцией фильтрации?

Организация моста не является единственным возможным решением. Вместо моста можно настроить две машины с Ethernet в качестве маршрутизатора. Хотя сделать это можно, но на самом деле это не самая лучшая идея. Мосты работают со своими интерфейсами в режиме приема всех пакетов, поэтому они должны обрабатывать каждый пакет, появляющийся на интерфейсах. Проблема состоит в том, что маршрутизаторы могут перенаправлять трафик только между разными подсетями. К тому же подсети могут быть создаваться путем усекания существующего пространства наполовину либо путем определения нового пространства, которое, как правило, не может быть маршрутизируемым (обратитесь к RFC 1918). При этом теряется половина полезного адресного пространства (или по крайней мере она размещается "не с той" стороны маршрутизатора -- программное обеспечение, выполняющее фильтрацию пакетов, защищает внутреннюю сеть). Использование сетевых мостов несколько увеличивает нагрузку на CPU, но избавляет от всех проблем, связанных с добавлением второго маршрутизатора.

2. Настройка ядра

Важно: После настройки и установки ядра, как это показано здесь, вы должны выполнить остальные последние приготовления до того, как загружать ваше новое ядро.

Добавление функций сетевого моста на машину FreeBSD делается несложно. При этом предусматривается наличие двух (или более, но мы будем использовать только два) адаптеров Ethernet и добавление нескольких строк к файлу конфигурации ядра. С мая 2000 в ветках RELENG_4 и -current имеется поддержка функции сетевого моста для всех типов Ethernet-интерфейсов. Это не означает, что любой интерфейс Ethernet будет работать. Чтобы он работал, он должен иметь поддержку работы в режиме приема всех пакетов как для приема, так и для передачи -- то есть он должен иметь возможность передавать пакеты Ethernet с любым адресом отправителя, а не только со своим. Чтобы получить хорошую пропускную способность, адаптеры должны быть типа PCI с поддержкой прямой работы с шиной (bus mastering). Лучшим решением остаются адаптеры Intel EtherExpress Pro 100 и адаптеры 3com 3c9xx (на втором месте).

Итак, вам нужно будет добавить в ваш файл конфигурации ядра следующее:

device fxp (или что-то, соответствующее используемым вами адаптерам)

options BRIDGE

options IPFIREWALL

options IPFIREWALL_VERBOSE

Заметьте, что последние версии FreeBSD поддерживают динамическую загрузку в ядро кода межсетевого экрана IP. Вы, однако, не можете поступать так с кодом сетевого моста, так как он сам по себе требует особого взаимодействия с IPFIREWALL.

Для получения указаний по построению и установке нового ядра обратитесь к разделу Руководства построении и установке собственного ядра.

3. Последние приготовления

Перед тем, как загрузить новое ядро, вы должны выполнить некоторые приготовления, касающиеся файлов rc.boot и rc.firewall. По умолчанию для межсетевого экрана применяется правило, которое отбрасывает все пакеты. Вам потребуется переопределить это, задав 'открытый' межсетевой экран в файле /etc/rc.conf. Для этого поместите в файл /etc/rc.conf такие строки:

firewall_enable="YES"

firewall_type="open"

Есть еще одно необходимое действие. При работе IP по Ethernet на самом деле используются два Ethernet-протокола. Один из них IP, а другой называется ARP. ARP используется, когда машине требуется определить, какой адрес Ethernet соответствует некоторому адресу IP. ARP не является частью IP, так как он применяется при работе IP по Ethernet. Стандартным правилом межсетевого экрана IP для открытого межсетевого экрана является

pass ip from any to any

но что насчет ARP? Если ARP не будет пропускаться, то IP не будет работать вообще. Однако IPFIREWALL не предусматривает работу с не-IP протоколами, включая ARP. К счастью, к коду межсетевого экрана IP было сделано некоторое хакерское расширение для работы с фильтрующими мостами. ] Если вы зададите специальное правило для пакетов UDP, исходящих от адреса 0.0.0.0, то номер UDP-порта будет использоваться для задания номера протокола Ethernet для проходящих через мост пакетов. Таким способом ваш сетевой мост может быть настроен для пропуска или отклонения не-IP протоколов. Поэтому просто добавьте ниже двух строк около начала файла /etc/rc.firewall (тех, что говорят о том, что вам практически никогда не нужно менять эти два правила) следующую строку, которая работает с lo0.

${fwcmd} add allow udp from 0.0.0.0 2054 to 0.0.0.0

Это правило с точки зрения обычной работы IPFIREWALL не имеет никакого смысла, но код сетевого моста будет использовать его для беспрепятственного прохождения ARP-пакетов (что вам заведомо нужно делать).

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

4. Включение функций сетевого моста

Теперь вы должны сделать следующее:

# sysctl -w net.link.ether.bridge_ipfw=1

# sysctl -w net.link.ether.bridge=1

В этот момент должны включиться функции сетевого моста, а из-за ранее сделанных изменений в файле /etc/rc.conf межсетевой экран должен быть широко открыт. На этом этапе вы должны с легкостью суметь включить машину между двумя наборами хостов и откатиться назад. Если это так, то следующим шагом будет добавление этих двух строк в файл /etc/rc.local либо добавление нескольких строк net.link.[ля-ля]=1 в файл /etc/sysctl.conf (какой способ вы выберите, зависит от используемой вами версии FreeBSD).

Теперь до того, как мы начнем, вы должны иметь машину с двумя интерфейсами Ethernet, но только один из этих интерфейсом настроен. То есть в файле /etc/rc.conf должна быть только одна строка ifconfig. С настроенным сетевым мостом это остается так. Но есть одна деталь, требующая некоторых размышлений. По умолчанию функции сетевого моста не включены. Это означает, что до тех, пока не будут выполнены вызовы sysctl, включающие функции сетевого моста, и не в самом начале загрузки, эта машина остается обычной машиной с двумя интерфейсами, только один из которых настроен из файла /etc/rc.conf. Э то обстоятельство становится важным для тех частей начального запуска, которые требуют сетевого доступа, скажем, для обращения к DNS. Следует внимательно выбирать интерфейс, который должен быть настроен. В большинстве случаев вам лучше выбрать "внешний" (то есть интерфейс, подключенный к Интернет). В дальнейшем давайте будем полагать, что интерфейс fxp0 является "внешним", а fxp1 "внутренним". Это означает, что fxp0 должен фигурировать в разделах конфигурации интерфейсов файла /etc/rc.conf, а fxp1 не должен. Вызовы sysctl, включающие функции сетевого моста, заставят работать fxp1 автоматически.

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

Теперь самое время начать пополнять набор правил межсетевого экрана IP для защиты внутренней сети. Здесь есть некоторые сложности, потому что не вся функциональность межсетевого экрана IP применима для проходящих через сетевой мост пакетов. К тому же имеется разница между пакетами, которые будут передаваться через сетевой мост, и пакетами, которые получает локальная машина. В общем, пакеты, передаваемые через сетевой мост, проходят через правила межсетевого экрана IP только один раз, а не два, как это обычно бывает. Пакеты, передаваемые через сетевой мост, фильтруются в процессе приема, поэтому правила, использующие ключевые слова 'out' или 'xmit', никогда не будут применяться. Обычно я использую 'in via', что является несколько устаревшим, но удобочитаемым синтаксисом. Другим ограничением является то, что для фильтрации проходящих через сетевой мост пакет вы можете использовать только операции 'pass' или 'drop'. Сложные операции, такие, как 'divert', 'forward' или 'reject', недоступны. Эти операции все же можно использовать, но только для трафика к или от машины, являющейся сетевым мостом.

Новой во FreeBSD 4.0 является концепция фильтрацией с отслеживанием состояния. Это дает большой эффект для трафика UDP, который обычно представляет собой исходящий запрос, за которым вскоре следует ответ с точно тем же набором адресов IP и номеров портов (но, конечно, с обратным порядком следования параметров отправителя и получателя). Для межсетевых экранов, которые не отслеживают состояние, практически нет способа для работы с таким типом трафика, кроме как посредством организации прокси. Но для межсетевого экрана, который может "запомнить" исходящий пакет UDP и в течение следующих нескольких минут разрешить прохождение ответа, работа с сервисами UDP представляется тривиальной задачей. В следующем примере показано, как это сделать. Настоящий параноик может также задать подобные правила для работы с TCP. Это позволяет вам избежать некоторых типов атак типа отказа в обслуживании или других не менее веселых вещей, но также обычно приводит к быстрому росту таблицы состояний.

Давайте рассмотрим пример настройки. Заметьте сначала, что в самом начале файла /etc/rc.firewall мы уже позаботились о loopback-интерфейсе и хак для ARP уже должен работать. Так что в дальнейшем мы больше о нем заботиться не будем.

us_ip=192.168.1.1

oif=fxp0

iif=fxp1

# Things that we've kept state on before get to go through in a hurry.

${ipfw} add check-state

# Throw away RFC 1918 networks

${ipfw} add deny log ip from 10.0.0.0/8 to any in via ${oif}

${ipfw} add deny log ip from 172.16.0.0/12 to any in via ${oif}

${ipfw} add deny log ip from 192.68.0.0/16 to any in via ${oif}

# Allow the bridge machine to say anything it wants (keep state if UDP)

${ipfw} add pass udp from ${us_ip} to any keep-state

${ipfw} add pass ip from ${us_ip} to any

# Allow the inside net to say anything it wants (keep state if UDP)

${ipfw} add pass udp from any to any in via ${iif} keep-state

${ipfw} add pass ip from any to any in via ${iif}

# Allow all manner of ICMP

${ipfw} add pass icmp from any to any

# TCP section

# established TCP sessions are ok everywhere.

${ipfw} add pass tcp from any to any established

# Pass the "quarantine" range.

${ipfw} add pass tcp from any to any 49152-65535 in via ${oif}

# Pass ident probes. It's better than waiting for them to timeout

${ipfw} add pass tcp from any to any 113 in via ${oif}

# Pass SSH.

${ipfw} add pass tcp from any to any 22 in via ${oif}

# Pass DNS. Only if you have name servers inside.

#${ipfw} add pass tcp from any to any 53 in via ${oif}

# Pass SMTP to the mail server only

${ipfw} add pass tcp from any to mailhost 25 in via ${oif}

# UDP section

# Pass the "quarantine" range.

${ipfw} add pass udp from any to any 49152-65535 in via ${oif}

# Pass DNS. Only if you have name servers inside.

#${ipfw} add pass udp from any to any 53 in via ${oif}

# Everything else is suspect

${ipfw} add deny log ip from any to any

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

${ipfw} add deny ip from ${us_ip}/24 to any in via ${oif}

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

Отметьте также, что последнее правило является почти что точной копией правила по умолчанию с номером 65536. Однако когда оно применяется при организации сетевого моста, проявляются два больших отличия. Наше правило записывает протокол, когда, конечно же, происходит отбрасывание пакетов, но наше правило будет работать только для трафика IP. Кроме хитрости с UDP 0.0.0.0, нет способа работать с не IP трафиком, так что правило, используемое по умолчанию с номером 65536 будет отбрасывать ВЕСЬ трафик, не только весь не IP трафик. Сетевым эффектом будет то, что будет протоколироваться трафик IP, не удовлетворяющий правилам, кроме не-IP трафика. Если хотите, вы можете добавить параметр IPFIREWALL_DEFAULT_TO_ACCEPT к вашему файлу конфигурации ядра и не-IP трафик будет проходить через мост, а не отбрасываться. Но в случае сетевого моста с фильтрацией между вами и Интернет, вряд ли вы будете это делать (если вы достаточно параноидальны).

Здесь есть правило для пропуска SMTP к почтовому серверу, если он у вас имеется. Очевидно, что полный набор правил выше должен быть испробован, и это является примером исключения для некоторой службы. Заметьте, что для того, чтобы 'почтовый сервер' работал, сервер имен должен заработать ДО того, как будет включена функция сетевого моста. Это пример проверки на то, что вы включили правильный интерфейс.

Другим стоящим внимания моментом является то, что правила DNS настроены так, что относятся только к работе серверов DNS. Это значит, что если у вас нет сервера DNS, то вам эти правила не нужны.

Те, кто настраивал межсетевые экраны IP, также использовали правило 'reset' или 'forward' для пакетов ident (порт TCP с номером 113). К сожалению, в коде сетевого моста нет такой опции, поэтому остается только просто пропускать их к получателю. Пока эта машина-получатель не заработает даемон ident, это не страшно. Другим способом является отбрасывание соединений к порту 113, что повредит таким программам, как IRC (проверка ident должна приводить к таймауту).

Единственным не очень хорошим моментом, который вы уже могли заметить, является то, что есть правило, позволяющее работать ${us_ip}, и отдельное правило, разрешающее работать внутренней сети. Запомните, что это нужно, потому что эти два типа трафика проходят разную обработку в ядре и фильтре пакетов. Внутренняя сеть обрабатывается кодом сетевого моста. Однако локальная машина будет использовать для работы обычный стек протоколов IP. Таким образом имеются два правила для обработки различных случаев. Правила для входящего через ${oif} трафика работают в обоих случаях. В общем, если в фильтре вы используете правила in via, то вам нужно будет делать исключение для локально генерируемых пакетов, потому что они не могут "войти" как-то иначе.

Обновлено: 12.03.2015