Разводной мост на Linux (Bridging Firewalls)::Журнал СА 4.2003
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Наука и технологии
Подписка
Где купить
Авторам
Рекламодателям
Архив номеров
Контакты
   

  Опросы
  Статьи

Электронный документооборот  

5 способов повысить безопасность электронной подписи

Область применения технологий электронной подписи с каждым годом расширяется. Все больше задач

 Читать далее...

Рынок труда  

Системные администраторы по-прежнему востребованы и незаменимы

Системные администраторы, практически, есть везде. Порой их не видно и не слышно,

 Читать далее...

Учебные центры  

Карьерные мечты нужно воплощать! А мы поможем

Школа Bell Integrator открывает свои двери для всех, кто хочет освоить перспективную

 Читать далее...

Гость номера  

Дмитрий Галов: «Нельзя сказать, что люди становятся доверчивее, скорее эволюционирует ландшафт киберугроз»

Использование мобильных устройств растет. А вместе с ними быстро растет количество мобильных

 Читать далее...

Прошу слова  

Твердая рука в бархатной перчатке: принципы soft skills

Лауреат Нобелевской премии, специалист по рынку труда, профессор Лондонской школы экономики Кристофер

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 9885
Комментарии: 0
Потоковая обработка данных

 Читать далее...

19.03.2018г.
Просмотров: 8097
Комментарии: 0
Релевантный поиск с использованием Elasticsearch и Solr

 Читать далее...

19.03.2018г.
Просмотров: 8198
Комментарии: 0
Конкурентное программирование на SCALA

 Читать далее...

19.03.2018г.
Просмотров: 5194
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 5872
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

Друзья сайта  

 Разводной мост на Linux (Bridging Firewalls)

Архив номеров / 2003 / Выпуск №4 (5) / Разводной мост на Linux (Bridging Firewalls)

Рубрика: Администрирование /  Документация

ПАВЕЛ ЗАКЛЯКОВ

Разводной мост на Linux (Bridging Firewalls)

Для подключения телекоммуникационных сетей к Интернету провайдер на целую сеть обычно выделяет всего лишь один реальный IP-адрес, а далее вы организуете у себя компьютер-шлюз, за которым располагаете вашу сетку с адресами вида 192.168.x.x (либо 172.16.0.0/12, либо 10.0.0.0/8) из RFC 1918. На компьютере-шлюзе обычно имеется две сетевые карты, поднимаются прокси-сервера тех или иных сервисов либо NAT (трансляция адресов или маскарадинг), либо всё сразу. Такая конфигурация встречается очень часто, поэтому в литературе хорошо описано, что и как настраивать. Однако в случае, когда все адреса, выделенные провайдером, являются реальными, существует несколько решений по организации сети. В литературе об этом пишут меньше, поэтому об одном весьма удобном способе организации я и попробую рассказать.

Ситуация с адресами на сегодняшний день критическая, в том смысле, что IP-адресов v.4 не хватает, а конечные пользователи никак не планируют свой переход на IP v.6.

С одной стороны, хорошо, если все компьютеры в сети будут иметь реальные адреса. Но с другой, это породит и часть проблем, таких как сокрытие внутренней организации сети, сокрытие числа пользователей в сети, расходуемого ими трафика и получаемых в итоге доходов. Удобно, когда все внутренние хосты маскируются за одним адресом, поэтому это очень популярно у нас в России. Также это удобно с точки зрения настройки. В случае смены провайдера (или внешнего IP-адреса) менять настройки придётся на одном компьютере, а не на всех компьютерах внутренней сети. Хотя бывают случаи, когда упрощения процесса перенастройки не происходит (если используются DNS- и SMTP-сервера провайдера). Возникает логичный вопрос: «А как следует правильно развивать сети, чтобы иметь при этом меньше проблем?». Однозначного ответа на этот вопрос дать нельзя. Вопрос о том, что лучше: реальные (легитимные) или маскируемые (нелегитимные) адреса и как их использовать, на мой взгляд, заслуживает отдельной статьи. Поэтому дискуссию по этому вопросу я предлагаю перенести на форум сайта журнала.

Итак, вам предстоит работать с реальными адресами. Правила организации сетей никто не отменял, и если вам нужен всего лишь один IP-адрес, то реально провайдер выделяет вам подсетку из 4-х адресов. Запишем адрес в двоичном виде и посмотрим только на два последних бита в двоичной записи: 00 – адрес сети; 11 – широковещание (broadcast), а два оставшихся – 01 и 10 – ваши адреса. Так как для общения с внешним миром в вашей сетке обязательно должен быть шлюз, которому также надо выделить один реальный адрес, пусть им будет 01. В результате для нас остаётся один-единственный адрес, заканчивающийся на 10.

Небольшое замечание: при подсчёте трафика провайдер будет суммировать всё, что будет попадать на все адреса сети, в последнем примере – это 4 адреса, а не тот один, который присвоен вашему компьютеру. Так что это следует учесть и не удивляться, что при правильном учёте трафика ваши данные и данные провайдера будут расходиться не в вашу пользу. Но, как известно, всегда бывают исключения.

Если же провайдером выделяется несколько большая подсесть, скажем, в два раза большая, то реально будет выделено не 8, а 8-3=5 адресов. Иметь 8 адресов подряд куда более выгоднее, чем 4+4. Вот вам и арифметика – «1+1=5». Если адресов будет 16, то возможных к использованию будет уже 16-3=13 и т. д. Обычно большие сети делятся на подсети, если адресов много, то потери невелики, и от деления получается только выгода. А вот если поделить 8 адресов, то явно будут большие потери. Легко понять, что потери кроются вроде как в лишнем адресе подсети и лишнем адресе для шлюза. Каким образом поделить сеть, чтобы не терять адреса? Это мы и попытаемся сделать. Довольно часто бывает, что шлюз, используемый в провайдерской сети, не имеет большого числа настроек, либо вообще находится на попечении провайдера и не подвластен для вашего контроля. Поэтому областью наших настроек и экспериментов будет все, что находится за зтим шлюзом.

Ограничим область наших действий. Для этого предлагаемые советы по организации нелегитимной сети следует сразу отклонить. Компьютеры внутри сети должны иметь реальные адреса. Для подсчёта трафика можно поставить хаб у шлюза и, подключив к нему сниффер, можно будет считать трафик – это выход. Но что делать, если надо какой-то пакет не пропустить? Скажем, если надо иметь небольшой межсетевой экран (МЭ), а не только подсчёт трафика.

Собственно, зачем нужно разделение сетей на подсети? Именно для того, чтобы одни другим «не мешали».

У многих для решения этого вопроса часто приходит в голову мысль: а почему бы не поставить компьютер с двумя сетевыми карточками. С одной стороны его надо соединить со шлюзом, а с другой стороны к нему подключить все компьютеры сети. Решение, вообще говоря, правильное, но далее начинаются проблемы. (Для удобства изложения наш компьютер «посередине» назовём межсетевым экраном (МЭ), а так как на нём стоит Linux, то будем называть его также и Linux.) Если вы хоть раз сталкивались с тем, что у вас справа и слева от МЭ одна и та же сетка, то вы поймёте, почему возникали проблемы. Разумный до этого (при работе NAT) компьютер перестаёт понимать, как ему работать. Наверное, он «думает», что обе карточки смотрят в одну строну, а не в разные. (Замечание: использование с одним адресом двух стоящих вместе сетевых карт в виде одной логической, более производительной сетевой карты, не новость, а способ повышения быстродействия сети при минимизации затрат.)

Я спрашивал многих людей, как это сделать и мне отвечали по-разному: начиная с советов по настройке масок 255.255.255.255 на интерфейсах МЭ и заканчивая покупкой профессиональных средств, таких как CISCO PIX Firewall и др. При этом необходимость покупки обосновывалась тем, что сделать так, чтобы и слева и справа (на разных сетевых интерфейсах) у компьютера на базе Linux была одна и та же сеть, и пакеты попадали с одного интерфейса на другой – невозможно. Поэтому у меня и родилась идея написать эту статью, дабы поделиться своим опытом.

Пусть карточка на МЭ, смотрящая на интернет-шлюз, будет eth0, а смотрящая в сеть с компьютерами – eth1.

Рисунок 1

Тогда даже прописанные вручную правила:

# route add -host x.x.x.1 dev eth0

# route add -host x.x.x.2 dev eth0

# route add -host x.x.x.3 dev eth1

# route add -host x.x.x.4 dev eth1

# route add -host x.x.x.5 dev eth1

  ..

# route add -host x.x.x.y dev eth1

# route add default gw x.x.x.1

показывающие, что тот или иной IP-адрес следует искать на том или ином интерфейсе, не помогают.

Сам компьютер, на котором стоит МЭ, «видит» все машины после прописывания подобных правил, машины сети и Интернет «видят» Linux. Но машины сети отказываются видеть шлюз, ну а шлюз, в свою очередь, отказывается видеть машины в сети. Указание в настройке машин сети шлюзом адреса x.x.x.3, привязанного к интерфейсу eth1, ни к чему не приводит, и дело кажется тупиковым. Всё это происходит, потому что умный шлюз не знает о том, что надо передавать пакеты для адресов x.x.x.4, x.x.x.5 и др. на адрес x.x.x.2. Если провести эксперимент: при вышеописанной конфигурации назначить на eth0 вместо адреса x.x.x.2 ненадолго адрес x.x.x.4, далее обратиться с него куда-либо в Интернет, чтобы шлюз его «увидел», а затем быстро поменять всё обратно, то некоторое время общение с компьютером x.x.x.4 будет нормальным. Он будет «видеть» шлюз и Интернет. Интернет также будет видеть его. Такая ситуация многих вдохновляет: заработало! Шлюз пингуется, а машины сети видны из Интернета. Но радость быстро проходит, когда происходит обновление arp-таблицы шлюза. Если шлюз ваш, то проблема в принципе решается просто. Необходимо на шлюзе для адресов, находящихся за МЭ, указать адрес x.x.x.2 в качестве gateway, подобно тому как в настройках Linux шлюзом является адрес x.x.x.1. Тогда наш шлюз будет слать пакеты на MAC-адрес eth0 и всё должно работать. Не следует искать проблем в отсутствии 1 в файле /proc/sys/net/ipv4/ip_forward или в отсутствии поддержки ip_forward в ядре, ошибок в настройке iptables (ipchains) или где-то ещё. В нашем случае проблема состоит в том, что мы не можем перенастраивать шлюз.

Существует решение этой проблемы в виде моста (bridge). Логично предположить: а кто мешает Linux брать пакеты с одной карточки из одной физической сети и передавать их в другую физическую сеть, в которую смотрит другая его карточка. Сразу хочу вас обрадовать, что у меня всё это работает (более года) довольно быстро и не требует больших ресурсов. Меня же, до того как я это сделал, многие «теоретики» уверяли, что сделать такое можно, но работать это будет медленно, особенно если я захочу, чтобы вдобавок происходила фильтрация пакетов. «О МЭ и думать забудь, – говорили они, – если у тебя не Dual Xeon». У меня AMD K7 (Duron) великолепно справляется с этой задачей, причём на 100-мегабитной сетке по команде:

# top

загрузка от пересылки и фильтрации не превышает 3-4%. Так что можно смело говорить о том, что при сегодняшних ценах решение получается дешёвое.

Большую часть загрузки процессора забирают на себя другие процессы, как snort и httpd сервера apache, как видно из рисунка. Если же обращения к веб-серверу нечастые, то большую часть загрузки потребляет сама программа top. Данный screenshot был сделан сразу после завершения скачивания 50-мегабайтного файла, который скачивался несколько секунд.

Рисунок 2

Хочу порекомендовать следующие ссылки:

В результате у вас должна появиться возможность прозрачного фильтрования и учёта трафика. Можно сказать, что мы с вами сделаем МЭ-мост, который при желании можно сделать почти неуязвимым и невидимым, но об этом чуть далее, в процессе настройки. Также за счёт фильтрования и возможной установки не двух, а более сетевых карточек, у вас появится возможность очень гибкой настройки вашей сети или ваших псевдо-подсетей. Если докупить отдельно расширитель, увеличивающий число PCI-слотов в вашей системе, то можно соорудить что-то вроде коммутатора CISCO серии 2900.

Предполагается, что вы немного знакомы с Linux и знаете, где можно скачать нужную версию ядра. (Для тех, кто не знает – ядра лучше брать на http://www.kernel.org или http://www.ru.kernel.org.)

После скачивания нужного ядра следует наложить на него патчи, которые качаем отсюда: http://bridge.sourceforge.net/download.html. Для различных версий ядра нужны различные патчи. У меня всё работало на ядрах версий 2.4.18 и 2.4.19. С ядром версии 2.4.20 я не экспериментировал, но и патча пока не видел, возможно, ядро уже подкорректировано нужным образом, так что патч ему не нужен.

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

# patch -p0 -E <файл_с_патчем

Опция -p0 указывает на то, что вы будете накладывать патч, находясь в директории уровня 0, то есть где находятся файлы и директории ядра, либо:

# patch -p1 -E <файл_с_патчем

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

Первый вариант лучше, так как вашу директорию вы можете называть хоть linux, хоть linux-2.4.19 и пр. Ключ -E говорит о том, что следует удалять пустые файлы, если таковые окажутся после наложения патча. Если у вас ядро версии 2.4.19, то имя файла патча будет bridge-nf-0.0.7-against-2.4.19.diff. После успешного наложения патча следует начать обычную процедуру конфигурирования ядра. Можно править руками файл .config, а можно запустить

# make menuconfig

находясь в директории с ядром. (Если у вас не появляется меню или что-то не работает, то, возможно, вы не установили средства разработки ядра. Придерживайтесь выводимых сообщений об ошибках – они содержат достаточную информацию. Часто забывают установить библиотеку ncurses.)

Рисунок 3

В меню настройки конфигурации ядра в разделе «Networking options» нужно поставить звёздочку (или букву М), выбрав слудующий пункт:

<*> 802.1d Ethernet Bridging

Для .config равносильно внесению строчки CONFIG_BRIDGE=y, либо CONFIG_BRIDGE=m.

Рисунок 4

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

[*] Frame Diverter (EXPERIMENTAL)

либо CONFIG_NET_DIVERT=y.

Если в меню такого пункта нет, возможно, что вы не включили в самом первом меню:

Code maturity level options --->

пункт

[*]Prompt for development and/or incomplete code/drivers

либо CONFIG_EXPERIMENTAL=y.

Далее включаем поддержку сетевого фильтра iptables, если она не была включена:

[*] Network packet filtering (replaces ipchains)

либо CONFIG_NETFILTER=y.

У нас появится подменю:

IP: Netfilter Configuration  --->

Здесь разумно включить все, что может вам понадобиться. Если сомневаетесь, то попробуйте включить всё, лучше пусть что-то пригодится с меньшей вероятностью, чем что-то не будет работать (правда, и работать такое ядро будет чуть медленнее).

При включении поддержки сетевого фильтра, под выбранным нами ранее пунктом 802.1d Ethernet Bridging, должен появиться пункт:

[*] netfilter (firewalling) support

либо CONFIG_BRIDGE_NF=y.

Выбираем его. Это нужно, чтобы мы могли фильтровать пакеты – «делать мост разводным». Далее идут стандартные шаги компиляции ядра. Запустите команды из директории, где установлены исходники ядра:

 # make dep

 # make clean

 # make bzImage

Далее можно скомпилировать модули, но если у вас что-то не будет грузиться, то вы зря потратите время на компиляцию модулей два раза, так что разумнее на этом этапе прописать новую конфигурацию, а модули скомпилировать потом, после того как станет ясно, что ядро у нас рабочее и не надо его перекомпилировать в новой конфигурации. Для этого надо взять созданный файл bzImage: при успешном создании он будет лежать, скорее всего, в директории /usr/src/linux-2.4.x/arch/i386/boot.

Его желательно переименовать во что-то более удобное, чем bzImage, например в vmlinuz-2.4.x, и поместить в директорию /boot. Следует подправить либо /etc/lilo.conf, либо /etc/grub.conf, в зависимости от установленного у вас загрузчика. Допишите новую конфигурацию по аналогии, не удаляя при этом старую! В случае загрузчика grub можно просто перезапускаться. В случае lilo следует его запустить, чтобы он внёс необходимые изменения.

# lilo

Не забудьте это сделать! Для grub файл /etc/grub.conf есть символическая ссылка на /boot/grub/grub.conf. (На всякий случай, initrd – это команда инициализации ramdisk, она прописывается для конфигурации виртуального диска в памяти и загрузки его из образа; при установке по умолчанию такой образ имеется в той же директории /boot. Строчку, содержащую initrd, копировать по аналогии совсем не обязательно.)

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

 # make modules

 # make modules_install

запускать их следует из той же директории, что и make menuconfig, make dep... После успешной компиляции и установки модулей следует перезагрузиться. Если всё прошло успешно, то можно приступить к настройке моста. Для начала нам понадобятся bridge-utils. Для Red Hat-подобных Linux имеется rpm-файл, который устанавливается командой:

 # rpm -i bridge-utils-0.9.6-1.i386.rpm

иногда пишут

 # rpm -ihv bridge-utils-0.9.6-1.i386.rpm

(Что означают те или иные ключи, смотрите man rpm.)

Обладателям RPM-несовместимых дистрибутивов придётся немного посложнее, но для них имеется .tag.gz файл почти того же самого содержания. При установке программы из него у вас не должны возникнуть проблемы.

После установки можно попробовать создать новый мост. Придумаем нашему мосту разумное имя, пусть он будет называться bridge0 (можно давать имена без цифр, например, mybridge) и создадим его командой

 # brctl addbr bridge0

Имеющийся у нас мост следует закрепить, прояснив для себя, на какие берега он будет крепиться, другими словами, выделить сетевые интерфейсы, которые будут работать с мостом. Заметьте, что карточек в сервере может быть много и совсем необязательно все из них задействовать для организации моста. Вот она, гибкость Linux! В принципе можно организовать мост при различных конфигурациях и необязательно при этом должны быть реальные адреса, о чём я писал в начале статьи. Итак, для добавления интерфейсов eth0 и eth1 следует запустить команды:

 # brctl addif bridge0 eth0

 # brctl addif bridge0 eth0

Если что-то не будет получаться, то вызывайте помощь.

 # brctl --help

Далее следует поднять интерфейсы eth0 и eth1 так, чтобы они ловили все пакеты у себя в сегменте.

 # ifconfig eth0 0.0.0.0 promisc

 # ifconfig eth1 0.0.0.0 promisc

Давать интерфейсам какие-либо адреса не нужно. Это будет гарантией вашей безопасности. Если у нашего моста, в частности МЭ, нет адреса, то его и просканировать невозможно! Вот где прелесть этого метода. Я не говорю уже об атаках. Даже чтобы устроить syn-flood или какую-нибудь другую атаку на отказ в обслуживании, то надо будет очень постараться, и в конечном итоге при достаточной производительности мост будет жив и будет считать и фильтровать пролетающий через него трафик. Для конфигурирования можно использовать ещё одну доверенную сетевую карточку или делать это с консоли. В любом случае за такую высокую надёжность и безопасность можно заплатить ценой неудобного конфигурирования. Настраивать же правила для такого МЭ – одно удовольствие. При желании на МЭ можно установить систему обнаружения атак, скажем, тот же snort (www.snort.org), который сможет динамически отслеживать проходящий трафик и запускать нужный скрипт, способный переконфигурировать фильтр, добавляя или убирая правила в цепочках/таблицах iptables (ipchains). То есть можно динамически менять фильтрующую способность такой системы. Однако возможны и минусы: система может заблокировать или выкинуть нужные данные в случае ложного срабатывания. Далее я расскажу, как в ущерб безопасности можно получить удобства. Всё-таки я не про МЭ начинал писать, а про организацию моста и возможную пользу из этого, помимо экономии IP-адресов.

Далее можно поднять интерфейс нашего моста, присвоив ему один из IP-адресов из нашей сети. (Это разумно: зачем серверу иметь 2 адреса, если вы, уже опередивши, подумали вместо 0.0.0.0 для eth0 и eth1 прописать реальные адреса, то скажу, что работать с двумя адресами тоже будет, но один адрес будет явно «лишним».)

Сделать это просто: как обычно, запустите:

 # ifconfig mybridge x.x.x.2 netmask 255.255.y.y broadcast x.x.x.z up

далее работа компьютера ничем не будет отличаться от того, как если бы этот адрес был присвоен интерфейсу eth0.

Для фильтрации пакетов, проходящих через наш мост, используется цепочка FORWARD iptables. Если она у вас по умолчанию не имеет политику пропускания или явно не прописано, что разрешено, то мост у вас работать не будет. Для обработки пакетов доступны все возможности iptables.

Если у вас всё заработало, и вы не хотите каждый раз вручную поднимать мост при загрузке системы, то следующий скрипт для вас. Он делает всё вышеописанное в автоматическом режиме стандартным способом во время загрузки. Итак, файл называется bridge (вы можете назвать его по-другому), его следует поместить в директорию инициализационных скриптов /etc/rc.d/init.d.

#! /bin/bash

#

# chkconfig: 2345 11 89

# мой скрипт моста

return=$rc_done

case "$1" in

    start)

           echo "Starting service bridge bridge0"

           brctl addbr bridge0 || return=$rc_failed

           brctl addif bridge0 eth0 || return=$rc_failed

           brctl addif bridge0 eth1 || return=$rc_failed

           ifconfig eth0 0.0.0.0 promisc || return=$rc_failed

           ifconfig eth1 0.0.0.0 promisc || return=$rc_failed

           brctl sethello bridge0 1 || return=$rc_failed

           brctl setmaxage bridge0 4 || return=$rc_failed

           brctl setfd bridge0 4 || return=$rc_failed

           ifconfig bridge0 promisc up || return=$rc_failed

             # ifconfig bridge0 x.x.x.x netmask 255.255.x.x broadcast x.x.x.x up || return=$rc_failed

             # route add default gw z.z.z.z || return=$rc_failed

           arp -f || return=$rc_failed

           echo -e "$return"

           ;;

    stop)

           echo "Shutting down service bridge bridge0"

           # route del default gw z.z.z.z || return=$rc_failed

           brctl delif bridge0 eth0 || return=$rc_failed

           brctl delif bridge0 eth1 || return=$rc_failed

           ifconfig bridge0 down

           brctl delbr bridge0 || return=$rc_failed

           echo -e "$return"

           ;;

    status)

           ifconfig bridge0

           brctl show bridge0

           ;;

    restart)

           $0 stop || return=$rc_failed

           $0 start || return=$rc_failed

           ;;

    *)

           echo "Usage: $0 {start|stop|status|restart}"

           exit 1

esac

test "$return" = "$rc_done" || exit 1

exit 0

Если вы хотите мосту присвоить IP-адрес, то закомментируйте строчку:

#ifconfig bridge0 promisc up || return=$rc_failed

а у строчек

  #ifconfig bridge0 x.x.x.x netmask 255.255.x.x broadcast x.x.x.x up || return=$rc_failed

  #route add default gw z.z.z.z || return=$rc_failed

  #route del default gw z.z.z.z || return=$rc_failed

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

# chkconfig bridge on

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

Поэтому для автозапуска нам следует самостоятельно создать файлы для необходимых уровней. Я у себя таковыми посчитал 2-й, 3-й, 4-й и 5-й. Мне кажется, что разумнее запускать мост после сервиса network, поэтому номер для запуска я выбрал 11 (10 для network плюс один). С выключением моста ситуация обратная, я выбрал номер 89. Чем меньше номер, тем раньше произойдёт событие.

Затем следует создать ссылки K89bridge во всех директориях rс?.d и S11bridge в rc2.d, rc3.d, rc4.d, rc5.d. Делается это, находясь в нужной директории командами:

 # ln -s ../init.d/bridge K89bridge

 # ln -s ../init.d/bridge S11bridge

Некоторые особенности настройки iptables и ещё одну маленькую хитрость я хотел бы написать сейчас, а именно о Frame Diverter, который может быть очень полезным средством при создании многофункциональных мостов, фактически являющихся прозрачными прокси-серверами с вытекающими удобствами.

У читателя может возникнуть мысль: если можно создать прозрачный МЭ, который даже по traceroute (tracert для Windows) не виден, то почему бы не сделать прозрачными и другие функции? Скажем, вы собрались почистить вентиляторы от пыли, и можете смело выключать свой сервер в рабочий день, заменив его патчкордом. Удобно, не так ли? Или если у вас 1000 и более машин, вам не надо идти и менять на всех конфигурацию. Удобства всем понятны, так что перейдём лучше к описанию их реализации.

Если вы на МЭ поднимете прокси-сервер, например, sqiud, то логично предположить, что можно сделать правило, берущее все пакеты, уходящие в Интернет на 80-е порты с интерфейса и заворачивающее их на локальный прокси:

iptables -t nat -A PREROUTING -i eth1 -p tcp -d 0/0 --dport 80 -j REDIRECT --to-ports 3128

(ipchains -A input -i eth1 -p tcp -d 0/0 80 -j REDIRECT 3128 )

Но не тут-то было – эффекта нужного не будет, так как пакеты изначально не адресованы нашему МЭ. Если бы заменить MAC-адрес в пакетах, идущих на 80 порт с MAC-адреса шлюза на MAC-адрес интерфейса Linux eth1, то тогда бы такой проблемы не было. Но счастье открытого кода в том и заключается, что если кому-то одному нужно было что-то сделать, то он это написал и выложил на всеобщее пользование – так что добро пожаловать на http://diverter.sourceforge.net.

К сожалению, на сегодня развитие данного проекта прекращено, последние версии упоминаемых ядер на сайте – 2.2.19 и 2.4.10. Возможно, это связано с тем, что принципиально нового ничего не появилось, ошибок не найдено, поэтому данную программу divert-utils-0.221.tar.gz можно использовать и для новых ядер. Завёртывание нужного нам трафика осуществляется парой команд:

# divert on eth1 proto tcp add dst 80

# divert on eth1 enable

после чего вышеуказанные правила iptables (ipchains) работают. Для реализации такого простого решения необходимо: скомпилировать ядро с поддержкой моста (мы это уже сделали с успехом), однако если у вас старые ядра, то, возможно, вам понадобится скачать патч для вашей версии. А также необходимо скомпилировать саму программу divert-командой:

 # make

Любому заинтересовавшемуся в программе, не должно это всё показаться сложным.

Замечание1: я не использую у себя frame diverter, так как нет необходимости (следовательно, не могу гарантировать вам его работу на 100%), что же касается моста, то всё работает великолепно, если что-то не так – пишите, попробуем разобраться.

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

Как заставить мост разводиться, то есть пропускать нужные нам пакеты, а ненужные выбрасывать в глубоко вырытый ров? Для этого следует настроить правила фильтрации пакетов в iptables (или ipchains для старых версий).

Очень полезным будет прочтение книги «Брандмауэры в Linux» [1]. К сожалению, в ней не говорится ничего об iptables, так что всё написанное вам придётся адаптировать самим. Теория изложена автором очень грамотно. Если вы изучите эту книгу и поймёте отличия ipchains от iptables (документы об их различии легко найти в сети), то вы без труда будете писать правила как для первого, так и для второго. Набрав в поисковой системе «Packet Filtering HOWTO: применение iptables», можно найти много ссылок, содержащих русский HOWTO:

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

Тем, кто пока сомневается в написании своих правил самостоятельно, посоветую разобраться с правилами и как они «включаются» в приведенном далее примере.

Будем считать, что у нашего шлюза адрес x.x.x.1, адрес Linux будет x.x.x.2, а всё остальное – наши машины в сети. Перед запуском файла не забудьте поправить конфигурацию под вашу. Дня начала создадим скрипт, в котором напишем следующее:

#!/bin/bash

echo "Starting firewalling, setting rules..."

# Чтобы наш процесс не запускался молча, выведем информацию.

# Укажем переменные, которые нам пригодятся.

SERVER_IP="x.x.x.2"

PRIVPORTS="0:1023"

UNPRIVPORTS="1024:65535"

TRACEROUTE_SRC_PORTS="32769:65535"

TRACEROUTE_DST_PORTS="33434:33523"

CLASS_A="10.0.0.0/8"

CLASS_B="172.16.0.0/12"

CLASS_C="192.168.0.0/16"

OUR_NET="x.x.x.??/??"

OUR_BROADCAST="x.x.x.???

# Здесь указываем IP и MAC компьютеров в нашей сети

COMPUTER1_IP="x.x.x.3"

COMPUTER1_MAC="XX:XX:XX:XX:XX:XX"

COMPUTER2_IP="x.x.x.4"

COMPUTER2_MAC="XX:XX:XX:XX:XX:XX"

COMPUTER3_IP="x.x.x.5"

COMPUTER3_MAC="XX:XX:XX:XX:XX:XX"

COMPUTER4_IP="x.x.x.6"

COMPUTER4_MAC="XX:XX:XX:XX:XX:XX"

...

# Сбрасываем все правила.

iptables -F

# Устанавливаем на всех цепочках политику, по умолчанию – всё запрещено.

iptables -P INPUT DROP

iptables -P FORWARD DROP

iptables -P OUTPUT DROP

# При необходимости следует повторить всё то же самое для  дополнительных таблиц, если они используются, например, iptables -t mangle -F

# Правила для loopback, разрешить прохождение пакетов по интерфейсу обратной петли

iptables -A INPUT -i lo -j ACCEPT

iptables -A OUTPUT -o lo -j ACCEPT

# Выкидывать все пакеты, которые имеют адрес интерфейса обратной петли и попадают к нам из других интерфейсов,

# отличающихся от lo. При работе это правило не используется, скорее оно служит защитой «от дурака» или «умного

# взломщика».

iptables -A INPUT -d 127.0.0.1/8 -i ! lo -j DROP

# считаем весь приходящий трафик на адрес сервера $SERVER_IP

iptables -A INPUT -p tcp -i bridge0 -d $SERVER_IP

# Запрещаем «плохим» пакетам прохождение через мост, чтобы они не попадали на компьютеры за мостом. Делаем запись в логах.

# При нормальной работе сети таких пакетов быть не должно.

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags ALL FIN,URG,PSH -m limit --limit 5/minute -j LOG --log-level notice

--log-prefix "NMAP-XMAS: "

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags ALL FIN,URG,PSH -j DROP

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags SYN,FIN SYN,FIN -m limit --limit 5/minute -j LOG --log-level notice

 --log-prefix "SYN/FIN: "

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags SYN,FIN SYN,FIN -j DROP

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags SYN,RST SYN,RST -m limit --limit 5/minute -j LOG --log-level notice

--log-prefix "SYN/RST: "

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags SYN,RST SYN,RST -j DROP

# То же самое, но запрещаем «плохим» пакетам попадание на сервер.

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags ALL FIN,URG,PSH -m limit --limit 5/minute -j LOG --log-level notice

--log-prefix "NMAP-XMAS: "

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags ALL FIN,URG,PSH -j DROP

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags SYN,FIN SYN,FIN -m limit --limit 5/minute -j LOG --log-level notice

--log-prefix "SYN/FIN: "

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags SYN,FIN SYN,FIN -j DROP

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags SYN,RST SYN,RST -m limit --limit 5/minute -j LOG --log-level notice

--log-prefix "SYN/RST: "

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags SYN,RST SYN,RST -j DROP

# Вводим правила, ограничивающие число RST/ACK-пакетов и делающие запись в лог-файле, чтобы через пингование хостов

# были трудности с определением ОС, установленной на этих хостах.

#Drop RST/ACKs to limit OS detection through pinging

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags RST RST,ACK -m limit --limit 5/minute -j LOG --log-level notice

--log-prefix "SYN/RST: "

iptables -A FORWARD -p tcp -d $OUR_NET --tcp-flags RST RST,ACK -j DROP

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags RST RST,ACK -m limit --limit 5/minute -j LOG --log-level notice

--log-prefix "SYN/RST: "

iptables -A INPUT -p tcp -d $SERVER_IP --tcp-flags RST RST,ACK -j DROP

# Защита от Syn-flood, (принцип работы подробнее см. выше в HOWTO)

iptables -A FORWARD -p tcp -d $OUR_NET   --syn -m limit --limit 1/s -j ACCEPT

iptables -A INPUT   -p tcp -d $SERVER_IP --syn -m limit --limit 1/s -j ACCEPT

# Защита от скрытого сканирования портов (Furtive port scanner)

iptables -A FORWARD -p tcp -d $OUR_NET   --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT

iptables -A INPUT   -p tcp -d $SERVER_IP --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT

# Ping of Death

iptables -A FORWARD -p icmp -d $OUR_NET  --icmp-type echo-request -m limit --limit 1/s -j ACCEPT

iptables -A INPUT -p icmp  -d $SERVER_IP --icmp-type echo-request -m limit --limit 1/s -j ACCEPT

# Разрешаем прохождение пакетов от и к нашему http (https) серверу. Обращение к веб-серверу из внутренней сети

# считать будем отдельно

iptables -A INPUT  -p tcp -i bridge0 -s $OUR_NET --sport $UNPRIVPORTS -d $SERVER_IP --dport 80 -j ACCEPT

iptables -A OUTPUT -p tcp -o bridge0 -d $OUR_NET --dport $UNPRIVPORTS -s $SERVER_IP --sport 80 -j ACCEPT

# остальные обращения

iptables -A INPUT  -p tcp -i bridge0 --sport $UNPRIVPORTS -d $SERVER_IP --dport 80 -j ACCEPT

iptables -A OUTPUT -p tcp -o bridge0 --dport $UNPRIVPORTS -s $SERVER_IP --sport 80 -j ACCEPT

iptables -A INPUT  -p tcp -i bridge0 --sport $UNPRIVPORTS -d $SERVER_IP --dport 443 -j ACCEPT

iptables -A OUTPUT -p tcp -o bridge0 --dport $UNPRIVPORTS -s $SERVER_IP --sport 443 -j ACCEPT

# Задаём адреса, с которых можно администрировать наш сервер через ssh, пусть это будут COMPUTER1 и COMPUTER2

iptables -A INPUT  -p tcp -i bridge0 -s $COMPUTER1_IP --sport $UNPRIVPORTS -d $SERVER_IP --dport 22 -m mac

--mac-source $COMPUTER1_MAC -j ACCEPT

iptables -A OUTPUT -p tcp -o bridge0 -s $SERVER_IP --sport 22 -d $COMPUTER1_IP --dport $UNPRIVPORTS -j ACCEPT

iptables -A INPUT  -p tcp -i bridge0 -s $COMPUTER2_IP --sport $UNPRIVPORTS -d $SERVER_IP --dport 22 -m mac

--mac-source $COMPUTER2_MAC -j ACCEPT

iptables -A OUTPUT -p tcp -o bridge0 -s $SERVER_IP --sport 22 -d $COMPUTER2_IP --dport $UNPRIVPORTS -j ACCEPT

# Выбрасываем все нелегитимные пакеты (RFC 1918). При правильной настройке их не должно быть в сети с реальными адресами.

iptables -A FORWARD -s $CLASS_A -j DROP

iptables -A FORWARD -s $CLASS_B -j DROP

iptables -A FORWARD -s $CLASS_C -j DROP

# Блокируем пакеты, которые мы считаем ненужными. Допишите правила сами. Ниже блокируется «сетевое окружение

# (smb-протокол)» и иже с ним. Чтобы из внешней сети никто не нашёл забытые share-ресурсы в локальной сети,

# если кто-то что-то забыл закрыть. А из сети в Интернет вряд ли кто-то полезет.

iptables -A FORWARD -s ! $OUR_NET -d $OUR_NET -p tcp --dport 137:139 -j DROP

iptables -A FORWARD -s ! $OUR_NET -d $OUR_NET -p udp --dport 137:139 -j DROP

iptables -A FORWARD -s $OUR_NET -d ! $OUR_NET -p tcp --dport 137:139 -j DROP

iptables -A FORWARD -s $OUR_NET -d ! $OUR_NET -p udp --dport 137:139 -j DROP

# У меня возникло желание прикрыть часто приходящие проверки на наличие proxy и mssql в процессе работы моста.

iptables -A FORWARD -d $OUR_NET -p tcp --dport 1433 -j DROP

iptables -A FORWARD -d $OUR_NET -p tcp --dport 3128 -j DROP

# Разрешим серверу общаться с DNS-серверами, если есть опасения о безопасности, то правила можно переписать

# для конкретных проверенных DNS-cерверов.

iptables -A OUTPUT -p tcp -s $SERVER_IP --sport $UNPRIVPORTS --dport 53 -j ACCEPT

iptables -A INPUT  -p tcp --syn -d $SERVER_IP --dport $UNPRIVPORTS --sport 53 -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport $UNPRIVPORTS --dport 53 -j ACCEPT

iptables -A INPUT  -p udp -d $SERVER_IP --dport $UNPRIVPORTS --sport 53 -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport 53 --dport 53 -j ACCEPT

iptables -A INPUT  -p udp -d $SERVER_IP --dport 53 --sport 53 -j ACCEPT

# Разрешаем whois (у меня этих правил нет за ненадобностью)

iptables -A OUTPUT -p tcp -s $SERVER_IP --sport $UNPRIVPORTS --dport 43 -j ACCEPT

iptables -A INPUT  -p tcp ! --syn -d $SERVER_IP --dport $UNPRIVPORTS --sport 43 -j ACCEPT

# Если у нас стоит SAMBA, то разрешаем SMB to/from server внутри локальной сети

iptables -A INPUT -p tcp -s $OUR_NET --sport $UNPRIVPORTS -d $SERVER_IP --dport 139 -j ACCEPT

iptables -A OUTPUT -p tcp -s $SERVER_IP --sport 139 -d $OUR_NET --dport $UNPRIVPORTS -j ACCEPT

iptables -A OUTPUT -p tcp -s $SERVER_IP --sport $UNPRIVPORTS -d $OUR_NET  --dport 139 -j ACCEPT

iptables -A INPUT -p tcp -s $OUR_NET --sport 139 -d $SERVER_IP --dport $UNPRIVPORTS -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport $UNPRIVPORTS -d $SERVER_IP --dport 139 -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport 139 -d $OUR_NET --dport $UNPRIVPORTS -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport $UNPRIVPORTS -d $OUR_NET  --dport 139 -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport 139 -d $SERVER_IP --dport $UNPRIVPORTS -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport $UNPRIVPORTS -d $SERVER_IP --dport 137 -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport 137 -d $OUR_NET --dport $UNPRIVPORTS -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport $UNPRIVPORTS -d $OUR_NET  --dport 137 -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport 137 -d $SERVER_IP --dport $UNPRIVPORTS -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport $UNPRIVPORTS -d $SERVER_IP --dport 138 -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport 138 -d $OUR_NET --dport $UNPRIVPORTS -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport $UNPRIVPORTS -d $OUR_NET  --dport 138 -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport 138 -d $SERVER_IP --dport $UNPRIVPORTS -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport 137 -d $OUR_NET --dport 137 -j ACCEPT

iptables -A OUTPUT -p udp -s $OUR_NET --sport 137 -d $OUR_NET --dport 137 -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport 138 -d $OUR_NET --dport 138 -j ACCEPT

iptables -A OUTPUT -p udp -s $OUR_NET --sport 138 -d $OUR_NET --dport 138 -j ACCEPT

iptables -A INPUT -p udp -s $OUR_NET --sport 138 -d $OUR_BROADCAST --dport 138 -j ACCEPT

iptables -A OUTPUT -p udp -s $SERVER_IP --sport 138 -d $OUR_BROADCAST --dport 138 -j ACCEPT

# Запрещаем Ping of Death и пропускаем обычные ping внутрь

iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT

iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

# Рекомендую исправить и запретить, многие сканеры вначале пингуют хост, прежде чем его сканировать.

# Разрешаем прохождение icmp-пакетов. При требованиях повышенной безопасности можно пересмотреть (запретить)

# эти правила.

iptables -A INPUT -p icmp --icmp-type source-quench -j ACCEPT

iptables -A OUTPUT -p icmp --icmp-type source-quench -j ACCEPT

iptables -A INPUT -p icmp --icmp-type parameter-problem -j ACCEPT

iptables -A OUTPUT -p icmp --icmp-type parameter-problem -j ACCEPT

iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT

iptables -A OUTPUT -p icmp --icmp-type destination-unreachable -j ACCEPT

iptables -A OUTPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT

iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT

iptables -A OUTPUT -p icmp --icmp-type time-exceeded -j ACCEPT 

# Разрешаем на сервере делать ping и получать ответы

iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT

iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT

# Для работы traceroute на сервере

iptables -A OUTPUT -p udp -s $SERVER_IP --sport $TRACEROUTE_SRC_PORTS --dport $TRACEROUTE_DST_PORTS -j ACCEPT

# Отбрасываем с уведомлением все пакеты, что сервер пытается послать наружу. При грамотной настройке пакеты не должны

# доходить до этого правила.

iptables -A OUTPUT -s $SERVER_IP -j REJECT

# Счётчики трафика + разрешение на пропускание трафика через мост: если можно разрешить, можно и запретить. Исходящий

# трафик привязываем к MAC-адресу сетевых карточек

iptables -A FORWARD -s $COMPUTER1_IP -m mac --mac-source $COMPUTER1_MAC -j ACCEPT

iptables -A FORWARD -d $COMPUTER1_IP -j ACCEPT

iptables -A FORWARD -s $COMPUTER2_IP -m mac --mac-source $COMPUTER2_MAC -j ACCEPT

iptables -A FORWARD -d $COMPUTER2_IP -j ACCEPT

iptables -A FORWARD -s $COMPUTER3_IP -m mac --mac-source $COMPUTER3_MAC -j ACCEPT

iptables -A FORWARD -d $COMPUTER3_IP -j ACCEPT

....

iptables -A FORWARD -s $COMPUTERn_IP -m mac --mac-source $COMPUTERn_MAC -j ACCEPT

iptables -A FORWARD -d $COMPUTERn_IP -j ACCEPT

# Правила только для подсчёта следует писать без -j опции

# iptables -A FORWARD -s $COMPUTER001_IP -m mac --mac-source $COMPUTER001_MAC

# iptables -A FORWARD -d $COMPUTER001_IP

# Поэкспериментируйте.

Далее, после запуска созданного вами файла, мост должен фильтровать пакеты так, как вы этого хотите. В случае если у вас всё настроено правильно, то при выключении правила должны автоматически сохраняться и загружаться заново при включении компьютера с сохранением всех значений счётчиков. Способ, описываемый в книге «Брандмауэры в Linux» [1] имеет этот недостаток: после перезапуска значения счётчиков не восстанавливаются. Я правил у себя файл /etc/rc.d/init.d/iptables, чтобы при выключении (опция stop) он сохранял параметры, а после останавливал интерфейс. Возможно, вам также следует сделать небольшие изменения.

Для просмотра значений (простейший биллинг) используйте команду:

# iptables -L -v -x –n

  • -L выводит все цепочки;
  • -v – информативный вывод, у цепочек выводятся значения счётчиков;
  • -x означает, что значения счётчиков не округляются до Кб и Мб и выводятся точно в байтах;
  • -n означает, что не надо преобразовывать IP-адреса и номера портов/сервисов в их имена.

Последняя опция часто не указывается, так как вроде бы является бесполезной, однако необходимость в ней появляется тогда, когда у вас пропадет Интернет, а точнее, перестанут правильно работать DNS-сервера. В случае падения DNS ответ от iptables может задерживаться до 10 минут, а если указать -n, то вывод цепочек будет быстрым, как обычно. Если iptables запускается у вас из других скриптов, то задержка его выполнения «повесит» эти скрипты и приведёт к глюкам. В частности, поначалу у меня mrtg не понимал тот факт, что ему передавались пустые значения.

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

Создадим небольшой файл на perl и, придав ему исполняемые атрибуты, поместим в директорию для cgi-скриптов (в RedHat 7.3 /var/www/cgi-bin), рекомендую книгу «CGI-программирование» [2]. Результат его исполнения можно увидеть на рисунке:

Рисунок 5

#!/usr/bin/perl

$SERVER_IP="x.x.x.2";

$COMPUTER1_IP="x.x.x.3"; $COMPUTER1_MAC="XX:XX:XX:XX:XX:XX";

$COMPUTER2_IP="x.x.x.3"; $COMPUTER2_MAC="XX:XX:XX:XX:XX:XX";

...

# создадим функцию, которая будет ставить точки, удобнее смотреть на 10.000.000.000 чем на 10000000000

sub DOTS {

# расставление точек разрядов

$string1 = shift;

if(not($string1 =~ /\D/)){

$string1 =~s/(\d{3})$/\.$1/;

while ($string1 =~ /^\d{3}/){$string1 =~s/(\d{3}\.\d)/\.$1/;}

        }

$string1 =~s/(^\.)(.*)/$2/;

return $string1;

        }

print "Content-type:text/html; charset=koi8-r\n\n";

print "<html>\n<head>";

print "<TITLE>Traffic shower</TITLE>\n<META NAME=\"content\" CONTENT=\"text/html; charset=koi8-r\">\n";

print "</HEAD><BODY BGCOLOR=\"white\" LINK=\"red\"\nleftmargin=\"10\" marginwidth=\"10\" topmargin=\"2\" marginheight=\"2\">\n";

$date = localtime time;

$ip=$ENV{"REMOTE_ADDR"};

print $date,"\n<br>";

# Для работы программы придётся отдельно создать файл-копию для iptables c установленным флагом SETUID, иначе работать

# не будет, файл-копию можно поместить куда угодно, скажем, в /dir1. C точки зрения безопасности тут возможны слабые места.

system "/dir1/iptables -L -v -x -n >/temp/traffic-dump";

# Вывод сбрасывается в отдельный файл, чтобы можно было этот файл по нескольку раз просматривать. Если запускать iptables

# несколько раз, то при каждом новом запуске будет новая ситуация (на момент запуска). Открываем файл и "вырезаем" из него

# нужные нам значения, помещая их в нужные нам переменные.

open(TRAFFIC,"/temp/traffic-dump") or die ("Cannot open file trafic-dump");

for ($index=1; !eof(TRAFFIC); $index++) {

$str=<TRAFFIC>;

chomp($str);

###### Web server 80 port #########

if ($str=~/tcp  --  bridge0 \* 0.0.0.0\/0 $SERVER_IP tcp spts:1024:65535 dpt:80/) {

 if ($str=~/\s*(\d+)\s+(\d+)\s(.*)/) {$webserver_in=$2;}

 }

if ($str=~/tcp  --  \* bridge0 $SERVER_IP 0.0.0.0\/0 tcp spt:80 dpts:1024:65535/) {

 if ($str=~/\s*(\d+)\s+(\d+)\s(.*)/) {$webserver_out=$2;}

 }

# Во время отладки обратите внимание на число пробелов и  символы, записываемые через "\": при не совпадении строчки

# с эталоном будет выведено пустое значение. Значения для срабатывания регулярных выражений следует брать из файла

# /temp/traffic-dump, иначе, если что-то не так с пробелами и пр, то у вас могут получиться пустые значения в переменных

# $webserver_in, $webserver_out $str=~/\s*(\d+)\s+(\d+)\s(.*)/ должно передавать значение второго столбца в переменную $2

# (подробнее см. книгу А.Павлова [2] или любой справочник по Perl, раздел «Регулярные выражения»)

###### Computer1 #########

if ($str=~/all  --  \*  \*  $COMPUTER1_IP  0.0.0.0\/0  MAC $COMPUTER1_MAC/) {

 if ($str=~/\s*(\d+)\s+(\d+)\s(.*)/) {$COMPUTER1_out=$2;}

 }

if ($str=~/all  --  \*  \*  0.0.0.0\/0  $COMPUTER1_IP/) {

 if ($str=~/\s*(\d+)\s+(\d+)\s(.*)/) {$COMPUTER1_in=$2;}

 }

###### Computer2 #########

if ($str=~/all  --  \*  \*  $COMPUTER2_IP  0.0.0.0\/0  MAC $COMPUTER2_MAC/) {

 if ($str=~/\s*(\d+)\s+(\d+)\s(.*)/) {$COMPUTER2_out=$2;}

 }

if ($str=~/all  --  \*  \*  0.0.0.0\/0  $COMPUTER2_IP/) {

 if ($str=~/\s*(\d+)\s+(\d+)\s(.*)/) {$COMPUTER2_in=$2;}

 }

# ... и так далее для других компьютеров...

} # for ($index=1; !eof(TRAFFIC); $index++)

close(TRAFFIC);

# Далее, из полученных значений мы создаём собственно html-отчёт. Для этого проверяем IP-адрес, с которого запрошен скрипт,

#  и выводим значения. Если это IP администратора ($COMPUTER1_IP), то выводим более сложный отчёт, со всеми пользователями.

#  Если это другой IP, то выводим для него свой отчёт – обычно это статистика только на этот адрес и всё.

if ($ip eq $COMPUTER1_IP) {

print "\n\n<table cellpadding=\"3\" border=\"1\">\n";

print "<tr align=\"center\"><td>&nbsp;</td><td>output</td> <td>input</td></tr>\n";

print "<tr><td>Computer1</td><td>",DOTS($COMPUTER1_out),"</td>";

print "<td>",DOTS($COMPUTER1_in),"</td>";

print "</tr>\n";

print "<tr><td>Webserver 80 port</td><td>",DOTS($webserver_out),"</td>";

print "<td>",DOTS($webserver_in),"</td>";

print "</tr>\n";

print "<tr><td>Computer2</td><td>",DOTS($COMPUTER2_out),"</td>";

print "<td>",DOTS($COMPUTER2_in),"</td>";

print "</tr>\n";

#(и так далее для других компьютеров).

$total_out=$webserver_out+$COMPUTER1_out+$COMPUTER2_out;

$total_in=$webserver_in+$COMPUTER1_in+$COMPUTER2_in;

print "<tr><td>Total</td>";

print "<td>",DOTS($total_out),"</td>";

print "<td>",DOTS($total_in),"</td></tr>\n";

print "</table>\n\n";

}

elsif ($ip eq $COMPUTER2_IP) {

print "\n\n<table cellpadding=\"3\" border=\"1\">\n";

print "<tr align=\"center\"><td>&nbsp;</td><td>output</td> <td>input</td></tr>\n";

print "<tr><td>Computer2</td><td>",DOTS($COMPUTER2_out),"</td>";

print "<td>",DOTS($COMPUTER2_in),"</td>";

print "</tr>\n";

print "</table>\n\n";

}

#elsif ($ip eq ...) {

# ...

#}

}

else { print "Unknown IP!";}

print " </body>";

print "</html>";

Для начала такая статистика очень даже подойдёт. Реально же рекомендуется поднимать БД, в которую периодически заносить показания счётчиков, а сами счётчики обнулять (iptables -Z) во избежание их переполнения и последующей выдачи неправильных значений. Хотя в RedHat 7.x/8.x проблема переполнения менее актуальна, чем в более ранних версиях.

Для повышения точности можно одновременно просматривать и обнулять.

# iptables -L -v -x -n -Z

При таком способе снятия показаний точно ничего не проскочит неучтённым после момента снятия значений, но до обнуления. Если же разбираться с БД вам не хочется, а хочется иметь что-то красивое, чтобы видеть визуально, как расходуется трафик, то за 10 минут можно установить mrtg. Для тех, кто не знает – это небольшая программа, считающая трафик и рисующая красивые графики. Это не единственно возможная программа своего класса.

Рисунок 6

Для тех, кто любит изучать первоисточники, сообщу следующие ссылки:

Для остальных скажу, что в поставке Red Hat 7.3 mrtg идёт в комплекте и чаще уже установлен. Единственным узким местом по его настройке становится его конфигурационный файл, про который я кратко расскажу. Если мы посмотрим в файл /etc/crontab, то увидим строчку вида:

0-59/5 * * * * root /usr/bin/mrtg /etc/mrtg/mrtg.cfg --logging /var/log/mrtg.log

или похожую. Если таковой нет, напишем сами. (Так как mrtg есть в стандартном дистрибутиве, считаю его уже установленным у вас.) Как видим, конфигурационный файл для mrtg называется mrtg.cfg и находится в /etc/mrtg. Идём туда, делаем резервную копию и правим его до следующего вида:

# Multi Router Traffic Grapher -- Example Configuration File

# Minimal mrtg.cfg

#--------------------

WorkDir: /var/www/html/mrtg

Language:ru

Target[computer1]:`/sbin/stat/comp1`

MaxBytes[computer1]: 125000000000

Title[computer1]: Traffic Analysis for Computer1

PageTop[computer1]: <H1>Stats for Computer1</H1>

Directory[computer1]: comp1

XSize[computer1]: 600

YSize[computer1]: 160

Options[computer1]: growright

Target[computer2]:`/sbin/stat/comp2`

MaxBytes[computer2]: 125000000000

Title[computer2]: Traffic Analysis for Computer2

PageTop[computer2]: <H1>Stats for Computer2</H1>

Directory[computer2]: comp2

XSize[computer2]: 600

YSize[computer2]: 160

Options[computer2]: growright

Target[web]:`/sbin/stat/web`

MaxBytes[web]: 125000000000

Title[web]: Traffic Analysis for Web server 80

PageTop[web]: <H1>Stats for Web server 80</H1>

Directory[web]: webdir

XSize[web]: 600

YSize[web]: 160

Options[web]: growright

Эту конфигурацию следует понимать так: рабочей директорией для mrtg будет /var/www/html/mrtg. В ней будут создаваться поддиректории по именам аккаунтов:

  • /var/www/html/mrtg/comp1
  • /var/www/html/mrtg/comp2
  • /var/www/html/mrtg/webdir

При желании можно писать всё в одну директорию, хотя это не очень удобно. Файлы для просмотра будут соответственно:

  • /var/www/html/mrtg/comp1/computer1.html
  • /var/www/html/mrtg/comp2/computer2.html
  • /var/www/html/mrtg/webdir/web.html

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

  • /sbin/stat/comp1
  • /sbin/stat/comp2
  • /sbin/stat/web

У вас это могут быть любые файлы и лежать они могут где угодно. Сначала разумнее создать и проверить работу этих файлов, а после править mrtg.cfg.

Рассмотрим на примере файла /sbin/stat/web:

#!/bin/bash

# web/80 (не забудьте исправить на свой IP)

ip=x.x.x.2

# Так как статистика снимается раз в 5 минут, и у нас может быть много счётчиков, то неразумно запускать каждый раз iptables.

# Поэтому мы вывод iptables скидываем в файл и  далее работаем с файлом, читая его сколь угодно раз. Смотрим, когда создан файл:

# если давно (>5 минут), то делаем его заново (обратите внимание: " и ` различны):

if [ -f /temp/traffic-dump ]

then

currenttime=`date +%s`

locktime=`date -r /temp/traffic-dump +%s`

secondsdiff=`expr $currenttime - $locktime`

  if [ $secondsdiff -gt 300 ]

# если файл устаревший, то есть созданный более 5 минут назад – генерируем новый:

   then

   /sbin/www/iptables -L -v -x -n >/temp/traffic-dump

  fi

else

/sbin/www/iptables -L -v -x -n >/temp/traffic-dump

fi

# для совпадения важно число пробелов

out=`cat /temp/traffic-dump |grep "ACCEPT tcp -- * bridge0     $ip 0.0.0.0/0 tcp spt:80 dpts:1024:65535"`

out=`echo $out|cut -d" " -f2` 

in=`cat /temp/traffic-dump |grep "ACCEPT tcp -- bridge0 *      0.0.0.0/0 $ip tcp spts:1024:65535 dpt:80"`

in=`echo $in|cut -d" " -f2`

echo $in

echo $out

echo 0

echo web

Если есть проблемы с написанием скриптов для bash, то рекомендую неплохую книгу «Linux и UNIX: программирование в shell» [3].

В целях безопасности, возможно, следует использовать директорию, отличную от /temp (/tmp), для хранения временного файла.

Отладка датчиков заключается в том, чтобы при их запуске они выводили на экран 4 строчки, где нам важны первые две – они должны показывать реально вырезанные значения из файла /temp/traffic-dump с показаниями счётчиков на цепочках. Остальные две носят скорее информативный характер – uptime и название того, с чего эти показания снимаются. Видимо, это важно для тех случаев, когда сеть очень большая.

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

# mrtg /etc/mrtg/mrtg.cfg

Это будет быстрее, чем ждать 10-15 минут и после идти в /var/log/messages, если что-то было не так. Далее можете просматривать html-файлы с полученными красивыми картинками через поднятый на вашем сервере apache.

Единственное дополнение состоит в том, что не всегда нужно, чтобы директории с отчётом были доступны всем, поэтому пару слов о том, как к этим директориям ограничить доступ. Для этого находим файл конфигурации apache. У меня это /etc/httpd/conf/httpd.conf и дописываем в нём: 

    Order deny,allow

    Deny from all

    Allow from x.x.x.3

    Order deny,allow

    Deny from all

    Allow from x.x.x.3 x.x.x.4

    Order deny,allow

    Deny from all

    Allow from x.x.x.3

Это позволит компьютеру с IP x.x.x.3 просматривать все три статистики, а компьютеру x.x.x.4 только свою.

Разумной может быть небольшая правка вышеописанного в статье CGI-скрипта, чтобы он генерировал в отчёте для просмотра сразу html-ссылки на страницы просмотра mrtg статистики. Тогда можно будет просто щелчком мыши смотреть графики.

Если вас не устраивает привязка к IP-адресу, то вместо привязки можно сделать доступ по паролю средствами apache, для этого: создаём директорию, где будут храниться пароли, если такой у нас ещё нет

# mkdir /usr/lib/apache/passwords

и заносим туда пользователей с паролями.

Если файла /usr/lib/apache/passwords/passwords нет, то пишем:

# htpasswd -с /usr/lib/apache/passwords/passwords userlogin1

далее, уже без опции create (-c):

# htpasswd /usr/lib/apache/passwords/passwords userlogin2

Когда нас будут спрашивать про пароль при вводе строк, то придумываем и вводим пароль. Поставьте нужные права, ограничивающие чтение директории /usr/lib/apache/passwords другими пользователями в целях безопасности. Если apache ругается на невозможность доступа к файлу, то вы перестарались.

Далее правим /etc/httpd/conf/httpd.conf и дописываем/правим в нём: 

    AuthType Basic

    AuthName "yourcompany"

    AuthUserFile /usr/lib/apache/passwords/passwords

    Require user userlogin1

    AllowOverride None

    AuthType Basic

    AuthName "yourcompany"

    AuthUserFile /usr/lib/apache/passwords/passwords

    Require user userlogin2

    AllowOverride None

    Order deny,allow

    Deny from all

    Allow from x.x.x.3 

Заходить следует как обычно, при запросе имени вводим userlogin1 или userlogin2, пароль и наслаждаемся графиками. Если же вы хотите придумать что-то более изощрённое или совместить парольную аутентификацию с идентификацией по IP, то можно и так сделать, но я этого делать не буду, а порекомендую хорошую книгу, в которой вы прочитаете много нового о сервере Apache: «Apache для профессионалов» [4].

Небольшое замечание: через мост проходят не IP-протоколы, вне зависимости от правил iptables, такие как Cisco Discovery Protocol (CDP) и Spanning Tree Protocol (STP), возможно, и другие. Думаю, что iptables умеет и их фильтровать, надо просто хитро записать ему правила, но так как особой надобности в этом не было, то я до этого «не дошёл» пока. Если кто-то знает – напишите, буду рад. Выключение же на мосту поддержки STP не влияет на прохождение пакетов STP через него.

Mrtg, Apache, perl и всё вышеописанное у меня великолепно уживается с мостом, МЭ и дополняет их, также у меня на сервере вместе с ними живёт система обнаружения атак snort и система бесперебойного питания, но о них, я думаю, что если получится что-то интересное, то я расскажу в следующих статьях. Что же касается параметров, то в эксперименте участвовал и по сей день работает мост на Red Hat Linux v.7.3 (Valhalla). Железо: AMD K7 (Duron) 750/256/80/с двумя 100-мегабитными сетевыми карточками Compex RE-100TX/WOL на базе чипсета Realtek RTL-8139. (Остальные несущественные параметры, как двух- или трёхкнопочная мышь или её отсутствие – не заслуживают внимания и упоминания).

Литература:

  1. Роберт Л. Зиглер. Брандмауэры в Linux. Перевод с англ.: Уч. пос. – М.: Издательский дом «Вильямс», 2000.
  2. Павлов А. CGI-программирование: Учебный курс. – СПб.: Питер, 2000.
  3. Девид Тейнсли. Linux и UNIX: программирование в shell. Руководство разработчика: Перев. с англ. – К.: Издательская группа BHV, 2001.
  4. Питер Уэнрайт. Apache для профессионалов. М.: Издательство «Лори», 2001.

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru