вторник, 6 ноября 2012 г.

Превращение USB флешки в жесткий диск

Любую флешку можно без проблем превратить с точки зрения Windows в натуральный жесткий диск. То есть для операционной системы USB флешка будет восприниматься как обычный, фиксированный диск, а не как внешнее переносное устройство. Зачем это может понадобится?

Данный прием описывается в первую очередь для тех, кто захочет подготовить флешку для установки Windows 7 из Windows XP с помощью утилиты DISKPART. Вся проблема в том, что в Windows XP утилита DISKPART вообще в упор не видит флешку. Хоть сто раз вводите для DISKPART команду list disk, бесполезно: в результате нам покажут только доступные жесткие диски и не более того.
Следовательно, из Windows XP с помощью DISKPART вообще нельзя сделать загрузочную флешку с Windows 7.
Однако, какое счастье – эту проблему можно решить хитрым способом. А именно: мы превратим флешку в обычный фиксированный диск. Другими словами, для Windows XP флешка станет еще одним жестким диском. И тогда DISKPART покажет нужный нам диск как миленький. Клево? Еще бы!
Такое превращение флешки пригодится вам и для других целей, везде где вместо съемного жесткого диска вы задумаете использовать флешку.
Кстати, вам интересно какого рожна DISKPART вообще не отображает флешку?  Все дело в дескрипторе RMB (removable media bit), записанном на каждой флешке. Именно из-за него Windows XP (да и другие версии Windows) воспринимают флешку как подключаемое устройство (т.е. removable device). Достаточно удалить этот дескриптор и флешка мутирует в жесткий диск, будет отображаться как диск в окне Мой компьютер, всех файловых менеджерах и вообще везде.
Сделать такой финт ушами нам позволит замечательный драйвер от компании Hitachi. Поэтому в первую очередь нам нужно его скачать, а потом и модифицировать.
Скачать драйвер Hitachi для USB флешки
Распакуйте архив драйвера и найдите файл cfadisk.inf. Давайте откроем его. В файле много всякой всячины, но нам нужен один раздел, он называется [cfadisk_device].
И в нем есть основная строка, с которой мы и делаем уличную магию. В файле она выглядит вот так:
%Microdrive_devdesc% = cfadisk_install,USBSTOR\DISK&VEN_JETFLASH&PROD_TS1GJF168&REV_0.00\A7B03577C3F1B5&0
файл cfadisk.inf
Теперь все, что нам нужно сделать – это заменить выделенную часть записи на идентификационные данные флешки, которую мы будем превращать в жесткий диск. А потом изменим и ее название.
Как это сделать? В первую очередь подключите флешку в порт USB. Теперь откройте Диспетчер устройств (например, выберите Пуск > Выполнить, введите devmgmt.msc и нажмите клавишу ).
Раскройте раздел Дисковые устройства, щелкните правой кнопкой мыши на названии флешки и выберите команду Свойства.
диспетчер устройств
Перейдите на вкладку Сведения. Там сразу будет открыто меню Код экземпляра устройства, именно этот код нам и нужен. Выделите код одним щелчком левой кнопкой мыши и нажмите комбинацию клавиш , чтобы его сохранить в буфер обмена.
свойства флешки
Ну а дальше все просто. Открываем файл cfadisk.inf, находим раздел [cfadisk_device], в нем строку что начинается с %Microdrive_devdesc% и меняем указанное значение после %Microdrive_devdesc% = cfadisk_install на скопированное ранее.
Другими словами, нужно изменить строку, выделенную ниже жирным шрифтом на ту, что вы скопировали. Затем сохраните файл cfadisk.inf.
%Microdrive_devdesc% = cfadisk_install,USBSTOR\DISK&VEN_JETFLASH&PROD_TS1GJF168&REV_0.00\A7B03577C3F1B5&0
Теперь меняем название флешки. В самом конце файла cfadisk.inf находим строку Microdrive_devdesc = в разделе [Strings] и меняем значение в скобках на любое другое. Изначально там указано значение “UsbToFix”, можно его и оставить.
название флешки
Осталось самое главное: установить обновленный драйвер cfadisk.inf для нашей USB флешки. Для этого снова щелкните на названии флешки в окне Диспетчер устройств и выберите команду Обновить драйвер.
обновить драйвер
Откроется окно Мастер обновления оборудования. Теперь пошагово.
  • В первом окне выберите переключатель Нет, не в этот раз и щелкните на кнопке Далее.
  • Выберите переключатель Установка из указанного места, щелкните на кнопке Далее.
  • Выберите переключатель Не выполнять поиск. Я сам выберу нужный драйвер и щелкните на кнопке Далее.
сам выберу драйвер
  • Щелкните на кнопке Установить с диска.
  • В окне Установка с диска щелкните на кнопке Обзор и выберите папку драйвера, где находится файл cfadisk.inf.
  • Windows переспросит, действительно ли вы хотите установить драйвер, щелкните на кнопке Продолжить установку и потом на кнопке Готово.
Теперь дело сделано и флешка превратилась в жесткий диск, ура. Отключите ее, подключите снова и отформатируйте. И теперь смотрите: вместо значка переносного устройства флешка будет отображаться как жесткий диск.
бывшая флешка
Ну вот и все, флешка успешно превратилась в жесткий диск, и теперь она станет доступной для утилиты DISKPART, а может, вы найдете ей и другое применение.

оригинал статьи http://windata.ru/windows-world/secrety-i-sovety/prevrashhenie-usb-fleshki-v-zhestkij-disk/

среда, 25 июля 2012 г.

Скрытые возможности IPTables

Оригинал статьи: Linux Journal, April 2004

С помощью этого мощного набора расширений для iptables вы сможете строить свои правила основываясь на анализе содержимого пакетов, диапазона портов и даже создавать ловушки для злоумышленников.
Iptables в Linux позволяет строить весьма мощные брандмауэры, ничуть не уступающие по своим характеристикам многим коммерческим системам защиты. По сути своей, iptables основывается на фильтрации пакетов, проходящих через соединение, и в соответствии с набором правил определяет ту или иную реакцию брадмауэра на эти пакеты. В самых простых случаях iptables может использоваться для того, чтобы сбросить одни пакеты и пропустить другие. При этом обычно анализируются IP-адрес пакета, номер порта и направление движения пакета. Кроме того iptables может анализировать статус пакета (NEW, ESTABLISHED, RELATED и пр. прим. перев.)
Простая и очень эффективная возможность блокировки входящего трафика, инициированного извне, совместно с функциями трансляции сетевых адресов (NAT) дает возможность пользователям свободного выхода во "внешний мир" и надежно защищает их от вторжений извне. Обычно такие наборы правил несколько упрощены, и возможно их следует расширить дополнительными фильтрами, но сама концепция остается неизменной.
Iptables может предложить много больше, чем эти простые критерии. Некоторые из дополнений известны довольно широко и даже включаются в состав некоторых дистрибутивов Linux. Другие не так известны, но тем не менее так же заслуживают пристального внимания. Об этих дополнительных возможностях я и собираюсь рассказать вам в этой статье. Для того, чтобы описать все дополнения потребовалась бы целая книга, я лишь хочу побудить вас к дальнейшему самостоятельному их изучению.

Введение в POM

Netfilter состоит из двух больших групп компонентов, первая -- компоненты включенные в состав ядра (и выполняющиеся в пространстве ядра), вторая -- это команды и утилиты выполняющиеся в пространстве пользователя, сюда можно отнести собственно команду iptables, ряд вспомогательных утилит, библиотеки, страницы справочного руководства и скрипты. К компонентам ядра можно отнести "заплаты" на исходные тексты ядра и дополнительные модули.
Наложение "заплат" на ядро -- задача весьма нетривиальная и для непосвященного может оказаться весьма сложной и запутанной. Ошибки при наложении "заплат" или наложение "заплат" несовместимых с данной версией ядра, могут привести к тому, что ядро невозможно будет собрать или хуже того -- ядро откажется загружаться. Команда разработчиков Netfilter постаралась упростить процесс наложения "заплат", поставляя в составе POM, или Patch-o-matic, сценарии, выполняющие эту работу за нас. POM -- это набор "заплат" на исходные тексты ядра и комплект сценариев, выполняющих наложение этих "заплат", что делает возможным работу с POM даже для новичков.
"Заплаты", входящие в состав POM подразделяются на ряд категорий, в зависимости от хронологии и уровня готовности. Некоторые из них обязательны при каждой установке iptables/Netfilter. Другие -- необязательные или находящиеся на стадии тестирования, но предоставляющие весьма интересные дополнительные возможности, это и есть те самые скрытые возможности, которым посвящена данная статья. В документации к POM они описаны как: "Maybe broken, Maybe cool extensions." ("Возможно неустойчивы в работе. Возможно чертовски хороши." да простит меня читатель за эмоциональный перевод прим. перев.)
Установка POM очень проста: скачайте тарболл с последней версией Patch-o-matic из каталога /pub/patch-o-matic на ftp.netfilter.org, распакуйте и запустите соответствующую команду, само собой разумеется из под пользователя root. Не забудьте указать корректный путь к исходным текстам ядра в параметре KERNEL_DIR:
KERNEL_DIR=/usr/src/linux-2.4 ./runme extra
Сам процесс установки -- интерактивный и достаточно понятный.

Расширение string

Расширение string -- на мой взгляд одно из самых востребованных, среди прочих дополнений из POM. Оно позволяет выполнять фильтрацию пакетов, основываясь на анализе содержимого области данных пакета. Этот модуль имеет очень широкую область применений, но тут главное не перестараться. Как один из вариантов применения, можно привести возможность блокировки скачивания исполняемых файлов в формате ELF через WEB. Известно, что исполняемые файлы в формате ELF начинаются символом с кодом 7Fh, за которым следуют буквы ELF. Таким образом можно проанализировать все пакеты, поступающие из Интернет с исходящего порта 80, на предмет наличия в области данных пакета требуемой комбинации символов. Шестнадцатиричные коды символов должны заключаться между символами "|", например так: |7F|ELF. Если предположить, что в Интернет "смотрит" интерфейс eth0, то фильтрующее правило может выглядеть примерно так:
iptables -A FORWARD -i eth0 -p tcp --sport 80 \
   -m string --string '|7F|ELF' -j DROP
Синтаксис записи шестнадцатиричных кодов символов, в данном виде, поддерживается iptables, начиная с версии 1.2.8. Если вы используете более раннюю версию, то вам придется прибегнуть к "обману", например:
--string "`dd if=/bin/ls bs=4 count=1 2>/dev/null`"
здесь в критерий попадут первые четыре символа из файла /bin/ls, который является исполняемым файлом формата ELF и который содержит требуемую нам комбинацию символов. А теперь несколько расширим этот пример. Допустим, что мы абсолютно доверяем содержимому, поступающему с адреса 192.168.0.5 и потому не хотим фильтровать трафик, поступающий с этого адреса. Делается это простым добавлением инвертированного критерия проверки исходящего IP-адреса, например так:
iptables -A FORWARD -i eth0 -p tcp \
   ! -s 192.168.0.5 --sport 80 -m string \
   --string '|7F|ELF' -j DROP
Однако данные правила не свободны от ошибок. Первое -- приведенный здесь критерий будет срабатывать для любого пакета, в области данных которого содержится указанная комбинация символов, а не только в начале передаваемого исполняемого файла. Это может вызвать ложные срабатывания критерия и привести к блокировке вполне легитимных пакетов. Второе -- если искомая последовательность символов окажется разнесенной по двум, или более, смежным пакетам (начало искомой строки в конце одного пакета, а конец строки в начале другого), то критерий не сработает. Искомая строка должна полностью входить в состав одного пакета. Таким образом, критерий string может сослужить неплохую службу, но вам не следует забывать об упомянутых выше особенностях. Кроме того, он чувствителен к регистру символов и не сможет среагировать на строку, разнесенную по смежным пакетам.

Расширение mport

Расширение mport позволяет указывать в одном правиле список портов и диапазон портов. Без этого расширения iptables позволяет указывать что-то одно -- либо один порт, либо диапазон портов (хочется упомянуть о существовании расширения multiport, которое уже включено в ядро, однако это расширение позволяет подставить только список портов т.е. не позволяет объединять список портов и диапазон в один критерий прим. перев.). С помощью расширения mport допускается более сложный синтакис. Например: мы хотим разрешить соединения с X-терминалов, Web и почту. Для этого мы теперь можем построить единственное правило, например так:
iptables -A INPUT -p tcp -m mport \
   --dports 80,110,21,6000:6003 -j ACCEPT
Без расширения mport нам пришлось бы создать несколько правил:
iptables -A INPUT -p tcp --dports 80 -j ACCEPT
iptables -A INPUT -p tcp --dports 110 -j ACCEPT
iptables -A INPUT -p tcp --dports 21 -j ACCEPT
iptables -A INPUT -p tcp --dports 6000:6003 -j ACCEPT
От переводчика: При использовании расширения multiport нам потребовалось бы написать два правила:
iptables -A INPUT -p tcp -m multiport --dports 21,80,110 -j ACCEPT
iptables -A INPUT -p tcp --dports 6000:6003 -j ACCEPT
Создание единственного правила вместо четырех безусловно влечет за собой повышение пропускной способности брандмауэра и снижение нагрузки на систему, поскольку теперь пакеты обрабатываются одним правилом вместо четырех. Кроме того, набор правил можно упростить, благодаря тому, что теперь сервисы, требующие идентичной обработки легко группируются в одно правило.

Расширение time

Расширение time позволяет строить логику критерия, основанную на текущем времени суток и дне недели. Например, можно ограничить доступ к WEB-серверу в определенное время суток или перенаправить трафик на зеркалирующий WEB-сервер в часы проведения плановых профилактических работ на основном сервере. Следующий пример иллюстрирует ограничение доступа к WEB-серверу по пятницам, с 4 до 6:30 часов утра, на время проведения профилактических работ:
iptables -A INPUT -p tcp -d 80 -m time \
   --timestart 04:00 --timestop 06:30 --days Fri \
   --syn -j REJECT
Следует отметить, что все три ключа -timestart, -timestop и -days обязательно должны быть включены в правило. Таким образом, если необходимо построить аналогичное правило, которое не зависит от дня недели, то вам придется явно указать все семь дней недели.

Создание ловушек

Едва ли кто нибудь из нас желал бы угодить в ловушку, если конечно вы цените свою жизнь. Расширение TARPIT представляет собой эквивалент ловушки -- попавшему в нее не удастся быстро выбраться на свободу. Если вы были настолько неблагоразумны, что попытались установить соединение с портом-ловушкой, то обнаружите, что закрыть такое соединение (и освободить тем самым системные ресурсы) не так-то просто. Чтобы добиться такого эффекта, iptables подтверждает запрос на TCP/IP соединение и устанавливает размер окна равным нулю, что вынуждает атакующую систему прекратить передачу данных -- очень напоминает нажатие комбинации Ctrl+S в терминале. Любые попытки атакующего закрыть соединение игнорируются, таким образом соединение остается открытым, пока не истечет срок тайм аута (обычно 12-24 минуты), что в свою очередь приводит к расходу системных ресурсов атакующей системы (но не системы-ловушки). Правило, создающее ловушку может выглядеть примерно так:
iptables -A INPUT -p tcp -m tcp -dport 80 -j TARPIT
Едва ли стоит использовать conntrack и TARPIT на одной и той же системе, особенно если ожидается большое число соединений, попавших в ловушку. Каждое такое соединение будет расходовать ресурсы conntrack. Еще один пример -- как можно оконфузить злоумышленника, имитируя поведение Microsoft Windows. В ответ на попытку сканирования портов netbios система может отвечать системе атакующего, а затем переводить эти соединения на TARPIT. Атакующий будет тратить время впустую, полагая, что порты открыты и пытаясь установить соединение. Он будет крепко раздосадован долгим ожиданием ответа и явно безумным поведением атакуемой системы. Правило, которое дает такой эффект может выглядеть следующим образом:
iptables -A INPUT -p tcp -m tcp -m mport \
   --dports 135,139,1025 -j TARPIT
Еще один пример использования TARPIT -- установить ловушки на ВСЕ порты, кроме определенных вами. Это опять-таки будет вводить в заблуждение посторонних, демонстрируя им, что все порты открыты и заставляя их тратить свое время на попытки установить соеднение. Более того, это предотвращает возможность определения типа операционной системы на системе-ловушке с помощью tcpdump. В данном примере легитимными считаются только сервисы WEB и E-MAIL, любые другие соединения будут "срываться" в ловушку.
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
iptables -A INPUT -p tcp -m tcp -j TARPIT
На www.spinics.net/lists/netfilter/msg17583.html вы найдете интересный пример из реальной жизни, когда расширение string и TARPIT сослужили неплохую службу системному администратору (не мне) .

Срабатывание критерия с заданной вероятностью

figure Расширение random позволяет строить критерии, срабатывание которых зависит от заданной вероятности. Вы можете построить такой критерий, который будет срабатывать с вероятностью в диапазоне от 0% до 100% случаев. Это расширение можно использовать, например, для эмуляции неустойчивости соединения с сервером или для равномерного распределения нагрузки по нескольким зеркалам. Пример, приведенный ниже, демонстрирует распределение WEB-трафика по трем серверам. Первое правило отправляет 33% соединений на адрес 192.168.0.100. Следующее правило отправляет 33% от общего числа соединений (50% от оставшихся 66% после первого правила прим. перев.) на адрес 192.168.0.101 и последнее правило отправляет все остальные соединения на адрес 192.168.0.102:
iptables -t nat -A PREROUTING -i eth0 -p tcp \
   --dport 80 --syn -m random --average 33 \
   -j DNAT --to-destination 192.168.0.100:80

iptables -t nat -A PREROUTING -i eth0 -p tcp \
   --dport 80 --syn -m random --average 50 \
   -j DNAT --to-destination 192.168.0.101:80

iptables -t nat -A PREROUTING -i eth0 -p tcp \
   --dport 80 --syn -j DNAT \
   --to-destination 192.168.0.102:80
Как и прежде предполагается, что в Интернет "смотрит" eth0.



И многое, многое другое

POM предоставляет огромное количество расширений. Я описал здесь лишь очень незначительную их часть. Просто запустите сценарий runme и просмотрите описания к "заплаткам", по мере их появления на экране. Ниже приводится кое что еще из того, что вы сможете обнаружить:
  • Трассировка соединений для RSH, MMS (media streaming), PPTP, Quake, RPC и Talk.
  • Расширенная поддержка доступа к конфигурации и к информации о состоянии через файловую систему /proc.
  • Расширенная поддержка особенностей IPv6.
  • Манипуляции с полем TTL и другими полями в IP-пакетах.
  • Более тонкое управление соединениями через NAT.
  • Ограничение трафика установкой квот и пропускной способности канала.
  • Блокировка попыток определения типа операционной системы (Anti-OS fingerprinting) и обнаружение сканирования портов. Маркировка соединений (и проверка маркировки).


Справочные материалы

Наложение "заплат" из POM не означает установку описаний новых возможностей в страницы справочного руководства по iptables, поэтому вам придется обращаться непосредственно к сопровождающей документации. Базовый синтаксис того или иного расширения вы сможете получить с помощью встроенной подсказки iptables. Например, iptables -m random --help выведет обычное, для iptables, справочное сообщение, но с дополнительной справкой по расширению random в конце. Аналогичную справку вы получите и для других расширений.
Вы так же можете обращаться к файлам справки по конкретным модулям, которые вы найдете в дереве каталогов Patch-o-matic. Например, справку по модулю random вы найдете в base/random/help. Аналогичные файлы-справки существуют и для других "заплат".
И, наконец, можете обратиться на сайт Netfilter, www.netfilter.org/patch-o-matic, где вы всегда найдете описание для каждой из "заплат", включенной в состав POM.

Установка новых модулей iptables

По большей части, расширения для iptables состоят из двух частей -- "заплаты" на ядро и вспомогательной библиотеки, которая используется командой iptables в пространстве пользователя. Детальное описание процедуры добавления POM модулей вы найдете на www.lowth.com/howto/add-iptables-modules.php. В двух словах процесс установки выглядит так: вам необходимо обновить систему, загрузить последний Patch-o-matic, наложить "заплаты" на ядро (с помощью сценария runme), пересобрать и установить пропатченное ядро и пересобрать и установить iptables.

Заключение

Вы уже наверняка убедились, что Netfilter представляет собой замечательный инструментальный набор, пригодный для построения эффективных брандмауэров, но в большинство дистрибутивов Linux попадают далеко не все расширения. Patch-o-matic, с возможностью практически автоматического процесса наложения "заплат" на ядро, позволяет администраторам расширять функциональность своих брандмауэров, .
Заканчивая свою статью хочется еще раз обратить ваше внимание: мы с вами увидели, что iptables/Netfilter предлагает множество интересных дополнений, которые не видны на первый взгляд. Что справедливо для любого другого программного обеспечения. Это одна из замечательных особенностей open-source -- никто ни от кого ничего не прячет, просто нужно поискать как следует!

Благодарности

Спасибо Jane Lowth за красивые рисунки пингвина Тукса (Tux).

вторник, 17 июля 2012 г.

Команды на заметку

Как в Debian/Ubuntu установить отсутствующий в репозитории Perl модуль
В случае отсутствия определенного Perl модуля в стандартных репозиториях Debian
и Ubuntu, можно поставить модуль через задействования механизмов установки
модулей CPAN, но такие модули не впишутся в пакетную инфраструктуру
дистрибутива. Поэтому для установки нестандартных Perl модулей следует
использовать dh-make-perl.

Ставим пакет dh-make-perl:
   apt-get install dh-make-perl

Устанавливаем нужный Perl модуль (в примере Module::Name) из репозитория CPAN:

   dh-make-perl --cpan Module::Name --install

Например: 

   dh-make-perl --cpan HTML::CTPP2 --install

Утилита dh-make-perl сама загрузит нужный модуль, соберет его, оформит deb-пакет и установит его.

Если модуль не из CPAN, можно распаковать модуль и выполнить (--build -
сформировать пакет, но не устанавливать):

 dh-make-perl директория_с_модулем --build
 
Простейший способ установки LAMP сервера на Ubuntu Server заключается в выполнении команды:
sudo tasksel install lamp-server
 

вторник, 10 июля 2012 г.

Запуск RemoteApp на MS Windows XP SP3

Для взаимодействия со службами удаленных приложений RemoteApp, развёрнутых на сервере терминалов Windows Server 2008, должен использоваться клиент RDC (Remote Desktop Connection, подключение к удаленному рабочему столу) версии 6.0 (6.0.6000.x) или более поздней. Клиент RDC с необходимой версией входит в состав ОС Windows Vista. Для Windows Server 2003 и Windows XP он доступен для скачивания и установки по адресу KB925876.
Однако для использования веб-доступа к службам терминалов TS Web Access потребуется версия клиента RDC не ниже 6.1 (6.0.6001.x), входящего в состав ОС Windows Server 2008, Windows Vista SP1 и Windows XP SP3. Причём, если для Windows Server 2008 и Vista SP1 этого вполне достаточно, то в случае использования Windows XP SP3 дополнительно потребуется разрешить использование элемента управления ActiveX при помощи правки реестра. Для этого в ключе
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Ext\Settings
необходимо удалить (или, например, просто переименовать) следующие два подключа:
{4eb89ff4-7f78-4a0f-8b8d-2bf02e94e4b2}
{7390f3d8-0439-4c05-91e3-cf5cb290c3d0}
Перезагрузки для вступления в силу изменений не потребуется. Использование веб-доступа к службам терминалов TS Web Access возможно лишь с использованием браузера Internet Explorer. При первом подключении в панели информации обозревателя Internet Explorer появится предупреждение, что активное содержимое веб-страницы было заблокировано. Необходимо щелкнуть панель информации, выбрать пункт Разрешить заблокированное содержимое и затем нажать кнопку Запустить элемент ActiveX.

четверг, 28 июня 2012 г.

Сила привычки или NTBackup на Windows Server 2008 R2

Статья для заметки.
В Windows 2008 R2 на смену NTBackup пришел Windows Backup, который не умеет восстанавливать отдельные файлы, что не устроило меня абсолютно.
На данной странице http://smallvoid.com/article/win7-ntbackup-install.html наткнулся как вернуть в новую Ось полюбившуюся программу.
просто скопировать файлы


  • C:Windows\System32\Ntbackup.exe
  • C:Windows\System32\Ntmsapi.dll
  • C:Windows\System32\Vssapi.dll
  • C:Windows\Help\Ntbackup.chm
  • C:Windows\Help\Ntbackup.hlp
в одну папку и радоваться жизни дальше!

вторник, 19 июня 2012 г.

Файервол для Linux с простым интерфейсом

оригинал статьи http://habrahabr.ru/post/146116/ 

Файервол представляет из себя bash-скрипт, который интегрирует с помощью соответствующих пакетов следующие функции:

  1. Файервол внешний и внутренний (пакет iptables).
  2. Учёт трафика внешнего и внутреннего (пакет iptables).
  3. Прокси-сервер для локальных сетей (пакет Squid).
  4. Контент-фильтр для локальных сетей (пакет DansGuardian).
  5. DNS-сервер для локальных сетей (пакет BIND).


Скрипт является результатом многолетней работы и претендует на универсальность — он позволяет использовать Linux-машину в качестве Интернет-шлюза как для небольшого офиса, так и для большого предприятия (на данный момент он используется на пяти предприятиях и в одном удалённом офисе — везде стоит CentOS).
Скрипт требует для своей работы наличие как минимум двух сетевых интерфейсов — один из которых является внешним, а остальные считаются внутренними. Внешний интерфейс задаётся переменной EXTIF и определяется автоматически, если эта переменная не задана.
Ещё одно требование — все интерфейсы должны иметь статические адреса, т.е. интерфейсы могут получать их динамически, но адреса должны быть всегда одними и теми же. Это требование вытекает из того, что в правилах iptables используются IP-адреса интерфейсов. Правила генерируются и применяются на основе файла конфигурации fwtraf.conf по команде "fwtraf  fwnormal" и сохраняются по команде "fwtraf  fwsave". Т.е. если IP-адреса интерфейсов изменились, нужно будет опять применить правила (и сохранить их, если нужно чтобы они действовали после перезагрузки).

Режимы работы source NAT и web-прокси можно комбинировать:
  • source NAT: выкл. (SNAT="")
  • source NAT: вкл. (SNAT=«YES»).

  • web-прокси: выкл. (WEBPROXY="")
  • web-прокси: Squid (WEBPROXY=«SQUID»).
  • web-прокси: DansGuardian->Squid (WEBPROXY=«DGSQUID»).

Скрипт поддерживает несколько локальных сетей (переменная LANS) — они перечисляются через пробел:
  LANS=«192.168.0.0/24  10.0.0.0/8»
Также поддерживаются удалённые локальные сети — например, локальные сети офисов, подключенные по технологиям VPN (переменная REMOTE_LANS):
  REMOTE_LANS=«192.168.1.0/24  192.168.3.0/24  192.168.5.0/24»

Скрипт имеет простой конфигурационный файл:





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

  • разрешаются (команда a — сокращение от "allow")
  • запрещаются (команда d — сокращение от "deny")

порты (колонка PORTS):
  • один или несколько TCP-портов через запятую: web,ftp.
  • все TCP-порты кроме, например, smtp: !smtp.
  • все TCP и UDP-порты: all.

Если используется контент-фильтр (WEBPROXY=«DGSQUID») и пользователю разрешаются web-порты, то к нему применяется группа web-доступа (колонка WA — сокращение от "Web Access").

Очень просто делается так называемый проброс портов внешнего интерфейса на внутренние IP-адреса локальных сетей (destination NAT). Это удобно, когда на шлюзе включен режим SNAT и локальные сети из Интернет недоступны. Например, разрешим админу с его компьютера доступ к Интернет (web и ftp-трафик) и ещё разрешим ему подключаться из Интернет по RDP на внешний IP-адрес шлюза, а шлюз будет перенаправлять rdp-трафик на его компьютер:
  a  192.168.1.240  pc30  web,ftp,rdp-rdp  # Админ
Ещё замечу, что пробрасываемые порты не обязаны совпадать — можно, например, слушать порт 2525 на внешнем IP, а пробрасывать его на 25-й порт почтового сервера, находящегося внутри локальной сети:
  a  192.168.1.2  mail  2525-25  # Почтовый сервер
Скрипт также ежедневно создает html-отчеты о трафике и ежечасно их обновляет:




Установка

1. Скачиваем скрипт файервола и помещаем его в /bin/:
    wget  dl.dropbox.com/u/924293/fwtraf/fwtraf
    mv  fwtraf  /bin/
    chmod  755  /bin/fwtraf
2. Скачиваем файл конфигурации файервола и помещаем его в /etc/fwtraf/:
    wget  dl.dropbox.com/u/924293/fwtraf/fwtraf.conf
    mkdir  /etc/fwtraf
    mv  fwtraf.conf  /etc/fwtraf/
3. Скачиваем файл для планировщика задач Cron и помещаем его в /etc/cron.d/:
    wget  dl.dropbox.com/u/924293/fwtraf/fwtraf.cron
    mv  fwtraf.cron  /etc/cron.d/
4. Читаем файл /etc/fwtraf/fwtraf.conf и редактируем его в соответствии со своими
    потребностями.
5. После редактирования fwtraf.conf применяем правила файервола:
    fwtraf  fwnormal  -  нормальный (рабочий) режим.
    fwtraf  fwsave  -  все правила сохраняются и действуют после перезагрузки.

Существует режим с минимальным набором правил:
    fwtraf  fwsimple  -  простой режим, персональные правила не действуют, всё разрешено.

Остальные команды можно узнать так:
    fwtraf  -  справка по командам.

Для включения поддержки работы с BIND (внимание: будут презаписываться DNS-зоны!) нужно раскомментировать строку c "DNSROOTDIR=..." в /bin/fwtraf.



 СКРИПТЫ

/bin/traf


#!/bin/bash
#
#    --------------   -----------   ---------------
#    | PREROUTING |   | FORWARD |   | POSTROUTING |
# -->|------------|-->|---------|-->|-------------|-->
#    | mangle     |   | mangle  |   | mangle      |
#    | nat        |   | filter  |   | nat         |
#    --------------   -----------   ---------------
#          ||                             /\
#          ||                             ||
#          \/                             ||
#    --------------    ---------    ---------------
#    | INPUT      |   |         |   | OUTPUT      |
#    |------------|-->| LOCAL   |-->|-------------|
#    | mangle     |   | PROCESS |   | filter      |
#    | filter     |   |         |   | mangle      |
#    |            |   |         |   | nat         |
#    --------------    ---------    ---------------
#
#
#                (Network)             -------------------------[ mangle ]----------------------------------   --[ nat ]--
#                    |                 |  ---------------   ---------                                      |   |         |
#                  mangle              |  | PREROUTING  |   | _exti |   ------------                       |   |         |
#                PREROUTING            |  |      EXT_IN-+-->|   ALL-+-->| _extiall |-------------> RETURN  |   |         |
#                    |                 |  |             |   |       |   ------------                       |   |         |
#                   nat                |  |             |   |       |   ------------    --------           |   |         |
#                PREROUTING            |  |             |   |   WEB-+-->| _extiweb |-+->| deny |           |   |         |
#                    |                 |  |             |   |       |   ------------ |  |      |           |   |         |
#         ------     |  |             |   |       |   ------------ |  | BAD1-+-> DROP    |   |         |
#         |                      |     |  |             |   |   FTP-+-->| _extiftp |-+  | BAD2-+-> DROP    |   |         |
#       mangle                mangle   |  |             |   |       |   ------------ |  | BAD3-+-> DROP    |   |         |
#       INPUT                 FORWARD  |  |             |   |       |   ------------ |  | BAD4-+-> DROP    |   |         |
#         |                      |     |  |             |   |   EML-+-->| _extieml |-+  | BAD5-+-> DROP    |   |         |
#       filter                filter   |  |             |   |       |   ------------ |  | BAD6-+-> DROP    |   |         |
#       INPUT                 FORWARD  |  |             |   |       |   ------------ |  |  IP1-+-> DROP    |   |         |
#         |                      |     |  |             |   | OTHER-+-->| _extixxx |-+  |  IP2-+-> DROP    |   |         |
#   [Local process]              |     |  |             |   ---------   ------------ |  ---+----           |   |         |
#         |                      |     |  |             |   ---------                |     |               |   |         |
#         |                      |     |  |      INT_IN-+-->| _inti |                |     +-----> ACCEPT -+-->|         |
#         |                      |     |  ---------------   |TO_LAN-+----------------|-----------> ACCEPT -+-->|         |
#         |                      |     |                    | OTHER-+----------------+                     |   |         |
#         |                      |     |                    ---------                                      |   |         |
#              |     |  ---------------   ---------                                      |   |         |
#         |                      |     |  | POSTROUTING |   | _exto |   ------------                       |   |         |
#       mangle                   |     |  |     EXT_OUT-+-->|   ALL-+-->| _extoall |-------------> RETURN  |   |         |
#       OUTPUT                   |     |  |             |   |       |   ------------                       |   |         |
#         |                      |     |  |             |   |       |   ------------                       |   |         |
#        nat                     |     |  |             |   |   WEB-+-->| _extoweb |-------------> ACCEPT -+-->|         |
#       OUTPUT                   |     |  |             |   |       |   ------------                       |   |         |
#         |                      |     |  |             |   |       |   ------------                       |   |         |
#       filter                   |     |  |             |   |   FTP-+-->| _extoftp |-------------> ACCEPT -+-->|         |
#       OUTPUT                   |     |  |             |   |       |   ------------                       |   |         |
#         |                      |     |  |             |   |       |   ------------                       |   |         |
#         ------------------------     |  |             |   |   EML-+-->| _extoeml |-------------> ACCEPT -+-->|         |
#                    |                 |  |             |   |       |   ------------                       |   |         |
#                  mangle              |  |             |   |       |   ------------                       |   |         |
#                POSTROUTING           |  |             |   | OTHER-+-->| _extoxxx |-------------> ACCEPT -+-->|         |
#                    |                 |  |             |   ---------   ------------                       |   |         |
#                   nat                |  |  FROM_EXTIF-+----------------------------------------> ACCEPT -+-->|         |
#                POSTROUTING           |  |             |   ---------                                      |   |         |
#                    |                 |  |             |   | _into |                                      |   |         |
#                    |                 |  |    INT_PROX-+-->|   IP1-+----------------------------> ACCEPT -+-->|         |
#                (Network)             |  | EXT_NONPROX-+-->|   IP2-+----------------------------> ACCEPT -+-->|         |
#                                      |  ---------------   ---------                                      |   |         |
#                                      ---------------------------------------------------------------------   -----------
#
# ВНИМАНИЕ!
# * Только первый пакет из потока проходит через цепочки таблицы nat,
#   трансляция адресов или маскарадинг применяются ко всем последующим пакетам в потоке автоматически.
# * Если в созданной цепочке заканчиваются правила, то пакет возвращается в родительскую цепочку
#   (т.е. в конце цепочки "-j RETURN" писать не нужно).
# * Если в стандартной цепочке заканчиваются правила, то к пакету применяется политика цепочки.

#################################################################################################
# ПЕРЕМЕННЫЕ
#################################################################################################

         PATH='/bin:/sbin:/usr/bin:/usr/sbin'; export PATH                                      #
     MESSAGES='/var/log/messages'                                                               # Лог-файл IPTables.
 IPTABLESFILE='/etc/sysconfig/iptables'                                                         # Файл правил IPTables.
      IPTFILE='/etc/sysconfig/ipt'                                                              # Файл с командами iptables.
     LOCKFILE='/var/lock/subsys/fwtraf'                                                         # Файл блокировки.
    CONFIGDIR='/etc/fwtraf'                                                                     # Каталог с файлами конфигурации.
      IPDBDIR='/var/log/ipdb'                                                                   # Каталог ip-базы данных.
    REPORTDIR='/var/www/fwtraf'                                                                 # Каталог с отчетами о трафике.
 STATICROUTES='/etc/sysconfig/static-routes'                                                    # Файл со статическими маршрутами
   DHCPD_CONF='/etc/dhcpd.conf'                                                                 # Файл конфигурации DHCPd.
   CONFIGFILE="$CONFIGDIR/fwtraf.conf"                                                          # Файл конфигурации FWTraf.
   REPORTFILE="$REPORTDIR/$(date +%Y-%m-%d).htm"                                                # Файл отчета о трафике.
#  DNSROOTDIR='/var/named/chroot'; [ -d "$DNSROOTDIR" ] || DNSROOTDIR='/'                       # Корневой каталог DNS.
   DNSNAMESIG=''; [[ "$(named -v)" > 'BIND 9.2.4' ]] && DNSNAMESIG='check-names ignore; '       # Уст. опцию игн. проверку имён для новых версий BIND.
      DG_CONF='/etc/dansguardian/dansguardian.conf'                                             # Основной конфиг-файл DansGuardian.
      DG_FGRP=`grep 2>/dev/null -aw ^filtergroups     "$DG_CONF"|awk 'BEGIN{FS="="}{print $2}'` # Последняя группа фильтрации.
      DG_FGRP=${DG_FGRP//[ \'\"]/}                                                              #
  DG_FGRPLIST=`grep 2>/dev/null -aw ^filtergroupslist "$DG_CONF"|awk 'BEGIN{FS="="}{print $2}'` # Фильтруемые IP и соотв. им группы фильтрации.
  DG_FGRPLIST=${DG_FGRPLIST//[ \'\"]/}                                                          #
  DG_EXIPLIST=`grep 2>/dev/null -aw ^exceptioniplist  "$DG_CONF"|awk 'BEGIN{FS="="}{print $2}'` # Нефильтруемые IP (группа 0).
  DG_EXIPLIST=${DG_EXIPLIST//[ \'\"]/}                                                          #
    LIMIT_EML='100'                                                                             # Лимит для EMLSERVICES.
    LIMIT_WEB='100'                                                                             # Лимит для WEBSERVICES.

#################################################################################################
# ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ
#################################################################################################

     HOSTNAME=`hostname 2>/dev/null -s`                                                         # Имя хоста.
   DOMAINNAME=`hostname 2>/dev/null -d`                                                         # Имя домена.
        STATE='-m conntrack --ctstate'                                                          # Критерий iptables - ctstate.
 _HOST_OR_NET='[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*'                                                  # Критерий - хост или сеть.
         _NET='[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/[0-9]*'                                           # Критерий - сеть.
       BLANK1='[ \t]\+'                                                                         # Строка, содерж. минимум 1 пробел/таб.
       BLANK0='[ \t]\?\+'                                                                       # Строка, содерж. минимум 0 пробелов/табов.
            N='[0-9]\+'                                                                         # Строка, содерж. минимум 1 цифру.

  LOGGED_TERM="$SSH_TTY"; [ "$LOGGED_TERM" ] || LOGGED_TERM=`tty 2>/dev/null`                   # Имя терминала, с которого запущен скрипт.
  LOGGED_USER=`last 2>/dev/null -a|awk 2>/dev/null -v t=${LOGGED_TERM#/dev/} '{if ($2==t && $8=="logged") print $1 }'`
    LOGGED_IP=`last 2>/dev/null -a|awk 2>/dev/null -v t=${LOGGED_TERM#/dev/} '{if ($2==t && $8=="logged") print $10}'`

#################################################################################################
# ФУНКЦИИ
#################################################################################################

lock_set()   { echo>"$LOCKFILE" "locked by $LOGGED_USER ($LOGGED_IP)"; }
lock_run()   { echo>"$LOCKFILE" "already running by $LOGGED_USER ($LOGGED_IP)"; }
lock_unset() { rm -f "$LOCKFILE"; }
lock_check() { local status=`cat 2>/dev/null "$LOCKFILE"`; [ "$status" ] && { printf "ERROR: $status\a\n"; exit 1; }; }

move_file() # (SRC_FILE,DST_FILE)
{
  [ -a "$1" ] || return 1
  [ -a "$2" ] && rm -f "$2"
  mv -f "$1" "$2"
}

check_net() # (HOST_OR_NET) - Проверяет: это сеть или нет.
{
  case "$1" in
         '') return 3 ;;
        0.*) return 2 ;;
    ${_NET}) return 0 ;;
          *) return 1 ;;
  esac
}

check_local() # (HOST_OR_NET) - Проверяет: это локальный IP/сеть или нет.
{
  case "$1" in
           '') return 2 ;;
         10.*) return 0 ;;
     172.16.*) return 0 ;;
    192.168.*) return 0 ;;
            *) return 1 ;;
  esac
}

summa()  # (DATEMASK,FILE) - Выводит суммарный трафик, соотв. указанной маске даты [YYYYMMDDHHMM].
{
  cat 2>/dev/null "$2"|awk -v datemask="^$1" 'BEGIN{sum=0}{if ($1 ~ datemask) sum+=$2};END{CONVFMT="%.0f";printf "%s\n",sum}'
}

ip_or_net_valid()  # (STRING) - Проверяет корректность IP или сети.
{
  local ip=$1
  ip=${ip/%\/[0-9]/}
  ip=${ip/%\/[0-9][0-9]/}
  [[ "${ip//[0-9]/}" != "..."     ]] && return 1 # Выходим, если посторонние символы или нет трех точек.
  [[ ".$ip."         == *..*      ]] && return 1 # Выходим, если не четыре элемента.
  [[ ".$ip"          == *.0[0-9]* ]] && return 1 # Выходим, если хотя бы один ведущий 0.
  for i in ${ip//./ }; do                        # Разбиваем IP на четыре числа и проверяем каждое.
    [ $i -gt 255 ]                   && return 1 # Выходим, если число больше 255.
  done
  return 0
}
ip()  # (STRING) - Проверяет корректность и возвращает $IP.
{
  IP='255.255.255.255'
  ip_or_net_valid "$1" && IP="$1" || printf "\nERROR: \"$1\" - bad ip or net\a\n"
}
name()  # (STRING) - Проверяет корректность и возвращает $NAME.
{
  NAME='noname'
  case "$1" in
    [a-zA-Z0-9_-]*) NAME="$1"                               ;;
                 *) printf "\nERROR: \"$1\" - bad name\a\n" ;;
  esac
}
prot()  # (STRING) - Проверяет корректность и возвращает $PROT.
{
  PROT='' # Возвращаемый протокол.
  case "$1" in
    tcp|udp|gre) PROT="-p $1"                                ;;
              *) printf "\nERROR: \"$1\" - bad protocol\a\n" ;;
  esac
}
ports()  # (STRING) - Проверяет корректность и возвращает $PORTS,$SPORTS,$DPORTS,$DNAT_DPORT,$DNAT_TPORT.
{
  SPORTS='' # Возвращаемые порты-источники.
  DPORTS='' # Возвращаемые порты-назначения.
  PORTS=`echo "$1"|sed -e "s/\/5443,48491/g;
                           s/\/14112/g;
                           s/\/9091/g;
                           s/\/1024,9443/g;
                           s/\/87/g;
                           s/\/3239/g;
                           s/\/7235/g;
                           s/\/613,614/g;
                           s/\/3411/g;
                           s/\/53/g;
                           s/\/25,110,143,587,995/g;
                           s/\/36789/g;
                           s/\/50025,50110/g;
                           s/\/20,21/g;
                           s/\/69/g;
                           s/\/2226/g;
                           s/\/80/g;
                           s/\/443/g;
                           s/\/5190/g;
                           s/\/143/g;
                           s/\/6667/g;
                           s/\/5222,5223/g;
                           s/\/1433,1434/g;
                           s/\/123/g;
                           s/\/81/g;
                           s/\/1521/g;
                           s/\/110/g;
                           s/\/995/g;
                           s/\/1723/g;
                           s/\/5750,9999,15100/g;
                           s/\/4899/g;
                           s/\/3389/g;
                           s/\/873/g;
                           s/\/5060/g;
                           s/\/137,138,139/g;
                           s/\/25/g;
                           s/\/2525/g;
                           s/\/587/g;
                           s/\/161,162/g;
                           s/\/22/g;
                           s/\/3128/g;
                           s/\/23/g;
                           s/\/6881,6882,6883,6884,6885,6886,6887,6888,6889/g;
                           s/\/33434:33459/g;
                           s/\/$WEBPORT,443/g;
                           s/\/8088,8089/g;
                           s/\/10000/g;
                           s/\/2802/g;
                           s/!/! /g"`
  DNAT_DPORT=`echo "$PORTS"|sed -e "s/all//; s/[0-9:]\+,//g; s/^[0-9:]\+$//g; s/! $N//g"|cut -d'-' -f1`
  DNAT_TPORT=`echo "$PORTS"|sed -e "s/all//; s/,[0-9:]\+//g; s/^[0-9:]\+$//g; s/! $N//g"|cut -d'-' -f2`
  PORTS=${PORTS//-/,} # Замещает все вхождения "-" строкой ",".
  case "$PORTS" in
               all|'')                                                                               return ;; # Все порты/нет портов.
    [^0-9!]*|*[^0-9!]) printf "\nERROR: \"$1\" - bad ports\a\n";                                     return ;; # Неправильные порты.
        [0-9]*,[0-9]*) SPORTS="-m multiport --sports $PORTS"; DPORTS="-m multiport --dports $PORTS"; return ;; # Несколько портов.
    '! '[0-9]*|[0-9]*) SPORTS="--sport $PORTS"              ; DPORTS="--dport $PORTS"              ; return ;; # Кроме порта/один порт.
                    *) printf "\nERROR: \"$1\" - bad ports\a\n";                                     return ;; # Неправильные порты.
  esac
}
limit()  # (STRING) - Проверяет корректность и возвращает $LIMIT.
{
  LIMIT='' # Возвращаемый лимит.
  case "$1" in
        '')                                          ;;
    [0-9]*) LIMIT="-m limit --limit $1/s"            ;;
         *) printf "\nERROR: \"$1\" - bad limit\a\n" ;;
  esac
}
conn_limit()  # (STRING) - Проверяет корректность и возвращает $CONN_LIMIT - макс. число подключений в минуту.
{
  CONN_LIMIT='' # Возвращаемый лимит.
  case "$1" in
        '')                                               ;;
    [0-9]*) CONN_LIMIT="$1"                               ;;
         *) printf "\nERROR: \"$1\" - bad conn_limit\a\n" ;;
  esac
}
wa()  # (STRING) - Проверяет корректность и возвращает $WA.
{
  WA='' # Возвращаемый web-доступ.
  case "$1" in
       '') WA=''                                               ;;
    [0-9]) WA="$1"                                             ;;
        *) printf "\nERROR: \"$1\" - bad web access group\a\n" ;;
  esac
}

function forwarders()  # () - Ищем внешние DNS-сервера в /etc/resolv.conf и выводим.
{
  cat 2>/dev/null '/etc/resolv.conf' \
  |awk '{if ($1=="nameserver" && $2!~/127\.0\.0\./ && $2~/[0-9]/) forwarders=forwarders$2"; "};
         END{if (forwarders!="") printf "           forwarders      { %s};\n",forwarders}'
}
write_dns_cfg_head()  # () - Устанавливаем флаг начала и пишем его заголовок.
{
F_DNS_CFG='Y'
cat>"$DNSROOTDIR/etc/named.conf"<<*
options  { directory "/var/named/";
           allow-query     {"trusted";};
           allow-transfer  {"trusted";};
           allow-recursion {"trusted";};
$(forwarders)
           // * If there is a firewall between you and nameservers you want to talk to, you might need to uncomment
           // * the query-source directive below. Previous versions of BIND always asked questions using port 53,
           // * but BIND 8.1 uses an unprivileged port by default.
           // query-source address * port 53;
         };
acl      "trusted"                      { 127.0.0.1; 10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16; };
include  "/etc/rndc.key";
#controls                               { inet 127.0.0.1 allow {localhost;} keys {rndckey;}; };
zone     "."                            { type hint  ; file "named.ca"; };
zone     "$DOMAINNAME"                  { type master; file "$DOMAINNAME.zone"; $DNSNAMESIG};
zone     "localdomain"           IN     { type master; file "localdomain.zone"; allow-update {none;}; };
zone     "localhost"                    { type master; file "localhost.zone"  ; allow-update {none;}; };
zone     "0.0.127.in-addr.arpa"         { type master; file "named.local"     ; allow-update {none;}; };
zone     "255.in-addr.arpa"      IN     { type master; file "named.broadcast" ; allow-update {none;}; };

*
}
write_dns_z_head()  # (ZONE) - Пишем заголовок прямой или обратной зоны.
{
cat>"$DNSROOTDIR/var/named/$1.zone"<<*
;TTL - Time To Live (время жизни записей).
;SOA - marks of start of zone of authority (начало полномочий).
;@   - имя зоны.

\$TTL 86400
@                          IN  SOA  @       root.localhost. (
                                                              2002112100  ; Serial
                                                              28800       ; Refresh
                                                              7200        ; Retry
                                                              604800      ; Expire
                                                              86400       ; TTL
                                                            )

@                          IN  NS           127.0.0.1    ; Name Server для зоны
@                          IN  MX   0       127.0.0.1    ; Mail eXchanger для зоны

*
}
write_dns_rz_head()  # (RZONE,IPN3,IPN2,IPN1) - Пишем заголовок обратной DNS-зоны, описываем ее в конфиг.файле.
{
  let F_DNS_RZ_${2}_${3}_${4}='Y'                                                                                   # Устанавливаем флаг начала зоны,
  write_dns_z_head "$1"                                                                                             # пишем заголовок обратной зоны.
  printf>>"$DNSROOTDIR/etc/named.conf" "zone %30s     { type master; file %31s; $DNSNAMESIG};\n" \"$1\" \"$1.zone\" # Дописываем конфиг.файл DNS.
}
write_dns_dz_head()  # (DZONE) - Устанавливаем флаг начала прямой зоны и пишем ее заголовок.
{
  F_DNS_DZ='Y'                                                                                                      # Устанавливаем флаг начала зоны,
  write_dns_z_head "$1"                                                                                             # пишем заголовок прямой зоны.
}
write_dns_edz_head()  # (EDZONE,NAME) - Устанавливаем флаг начала прямой внешней зоны и пишем ее заголовок.
{
  let F_DNS_EDZ_${2}='Y'                                                                                            # Устанавливаем флаг начала зоны,
  write_dns_z_head "$1"                                                                                             # пишем заголовок прямой зоны.
  printf>>"$DNSROOTDIR/etc/named.conf" "zone %30s     { type master; file %31s; $DNSNAMESIG};\n" \"$1\" \"$1.zone\" # Дописываем конфиг.файл DNS.
}
write_dns() # (IP,NAME) - Пишем хост в зоны DNS.
{
  [ -d "$DNSROOTDIR" ] || return                                                                   # Если каталог не задан или не существует.

  check_net   "$1" && return                                                                       # Если это сеть.
  check_local "$1" || return                                                                       # Если это не локальный IP.

       local -a   IPN=(${1//./ })
       local     IPN1=${IPN[0]}
       local     IPN2=${IPN[1]}
       local     IPN3=${IPN[2]}
       local     IPN4=${IPN[3]}
       local       RZ="$IPN3.$IPN2.$IPN1.in-addr.arpa"                                             # Имя обратной зоны.
       local       DZ="$DOMAINNAME"                                                                # Имя прямой зоны.

  eval local F_DNS_RZ=\${F_DNS_RZ_${IPN3}_${IPN2}_${IPN1}}

  [ "${F_DNS_CFG}" ] || write_dns_cfg_head                                                         # Если в конфиг.файл DNS еще не писали.
  [ "${F_DNS_DZ}"  ] || write_dns_dz_head "$DZ"                                                    # Если в прямую DNS-зону еще не писали.
  [ "${F_DNS_RZ}"  ] || write_dns_rz_head "$RZ" "$IPN3" "$IPN2" "$IPN1"                            # Если в эту обратную DNS-зону еще не писали.

  printf>>"$DNSROOTDIR/var/named/$DZ.zone"  '%-25s  IN  A            %s\n' "$2"          "$1"      # Дописываем прямую   DNS-зону.
  printf>>"$DNSROOTDIR/var/named/$RZ.zone"  '%-25s  IN  PTR          %s\n' $IPN4         "$2.$DZ." # Дописываем обратную DNS-зону.
  [ "$2" == 'kms' ] && \
  printf>>"$DNSROOTDIR/var/named/$DZ.zone"  '%-25s  IN  SRV 0 0 1688 %s\n' '_vlmcs._tcp' "$2"      # Дописываем SRV-запись в прямую DNS-зону.
  [ "$EXTDOMAINFLAG" ] || return                                                                   # Проверяем, нужно ли писать в зону внешнего домена.
  [ "$EXTDOMAINNAME" ] || return                                                                   # Проверяем, указан ли внешний домен.

       local       EDZ="$2.$EXTDOMAINNAME"                                                         # Имя прямой зоны внешнего домена.

  eval local F_DNS_EDZ=\${F_DNS_EDZ_${2}}

  [ "${F_DNS_EDZ}"   ] || write_dns_edz_head "$EDZ" "$2"                                           # Если в прямую внешнюю DNS-зону еще не писали.
  printf>>"$DNSROOTDIR/var/named/$EDZ.zone" '%-25s  IN  A            %s\n' '@'           "$1"      # Дописываем прямую внешнюю DNS-зону.
}
write_dg_exiplist_head()  # () - Устанавливаем флаг начала exceptioniplist и очищаем его.
{
  F_DG_EXIPLIST='Y'    # Устанавливаем флаг начала файла.
  :>"$DG_EXIPLIST.tmp" # Очищаем временный файл exceptioniplist.
}
write_dg_fgrplist_head()  # () - Устанавливаем флаг начала filtergroupslist и очищаем его.
{
  F_DG_FGRPLIST='Y'    # Устанавливаем флаг начала файла.
  :>"$DG_FGRPLIST.tmp" # Очищаем временный файл filtergroupslist.
}
write_dg()  # (IP,GROUP_NUM) - Пишем IP и номер фильтрующей группы GROUP_NUM в файл filtergroupslist.
{
  [[ "$WEBPROXY" == 'DGSQUID' ]] || return               # Если не используется DansGurdian.
  [[ "$1"        == ${_NET}   ]] && return               # Если это сеть.
  case "$2" in
    '') return                                           # WEB-доступ: нет группы.
        ;;
     0) [ "$DG_EXIPLIST"     ] || return                 # WEB-доступ: нефильтруемый.
        [ "${F_DG_EXIPLIST}" ] || write_dg_exiplist_head # Если в exceptioniplist еще не писали, то создаем его.
        echo>>"$DG_EXIPLIST.tmp" "$1"                    # Дописываем временный файл exceptioniplist.
        ;;
     *) [ "$DG_FGRPLIST"     ] || return                 # WEB-доступ: фильтруемый в соотв. с номером группы.
        [ "${F_DG_FGRPLIST}" ] || write_dg_fgrplist_head # Если в filtergroupslist еще не писали, то создаем его.
        echo>>"$DG_FGRPLIST.tmp" "$1=filter$2"           # Дописываем временный файл filtergroupslist.
        ;;
  esac
}
write_ipdb()  # (IP) - Пишем информацию в ip-базу данных.
{
  add_uniqstr()  # (FILE,STR) - Дописываем уникальную строку, время игнорируем.
  {
    local file="$1"
    local  str=`echo $2` # Удаляем пробелы в начале и в конце.
    [ "$file" ] || return
    [ "$str"  ] || return
    cat 2>/dev/null "$file"|grep -av "^.* $str\$">"/tmp/fwtraf.add_uniqstr.$$"
    move_file "/tmp/fwtraf.add_uniqstr.$$" "$file"
    echo>>"$file" "$DATE $str"
  }

  local ip="${1/\/*}"

  [[ "$IPDBDIR" ]]  || return # Если каталог не задан.
  check_local "$ip" || return # Если это не локальный IP.

  declare    local   line=`sed -n "/^${BLANK0}[ad]${BLANK1}.*${ip}[\/[0-9]\+]\?${BLANK1}/p" $CONFIGFILE|sed -e 's/^#//p'|sed q`; [ "$line" ] || return
  declare -a local a_line=( ${line%% #*} )
  declare    local    cmd=' '; [[ "${a_line[0]}" == [ad]           ]] &&   cmd=${a_line[0]}
  declare    local   name=' '; [[ "${a_line[2]}" == [0-9a-zA-Z_-]* ]] &&  name=${a_line[2]}
  declare    local     wa=' '; [[ "${a_line[3]}" == [0-9]*         ]] &&    wa=${a_line[3]}
  declare    local  ports=' '; [[ "${a_line[4]}" == [0-9a-z!]*     ]] && ports=${a_line[4]}
  declare    local  limit=' '; [[ "${a_line[5]}" == [0-9]*         ]] && limit=${a_line[5]}
  declare    local   desc=' '; [[ "${line/*#/}"  >  ' '            ]] &&  desc="${line/*#/}"
  declare    local   DATE="$(date +%Y%m%d%H%M)"
  mkdir -p    "$IPDBDIR/$ip"
  add_uniqstr "$IPDBDIR/$ip/fwtraf_name"   "$name"
  add_uniqstr "$IPDBDIR/$ip/fwtraf_access" "$cmd $ports $wa $limit"
  add_uniqstr "$IPDBDIR/$ip/fwtraf_desc"   "$desc"
}
ipt_begin()  # () - Начинаем запись команд iptables в файл $IPTFILE.tmp.
{
  echo>"$IPTFILE.tmp" '#!/bin/bash'
}
ipt()  # (RULES...) - Пишем команды iptables в файл $IPTFILE.tmp.
{
  echo>>"$IPTFILE.tmp" "iptables $@"
}
ipt_end()  # () - Применяем команды iptables из файла $IPTFILE.tmp.
{
  printf '\n'
  [ -a "$IPTFILE.tmp" ] || return
  diff &>/dev/null "$IPTFILE" "$IPTFILE.tmp" && { rm -f "$IPTFILE.tmp"; return; }
  move_file "$IPTFILE"     "$IPTFILE.old"
  move_file "$IPTFILE.tmp" "$IPTFILE"
  printf '[ save traffic counters ]\n'; trafhourly # Сохраняем трафик, т.к. сейчас цепочки будут созданы заново.
  printf '[ all rules apply ]\n'      ; time nice -n -20 bash -c ". $IPTFILE"
}
dg_begin()  # () - Сохраняем списки DG, чтобы потом узнать, были ли в них изменения.
{
  [ "$WEBPROXY" == 'DGSQUID' ] || return               # Если не используется DansGurdian.
  [ "$DG_EXIPLIST"           ] && :>"$DG_EXIPLIST.tmp" # Очищаем временный файл exceptioniplist.
}
dg_end()  # () - Перезапускаем DG, если были изменения.
{
  printf '\n'
  [ "$WEBPROXY" == 'DGSQUID' ] || return # Если не используется DansGurdian.
  [ -a "$DG_EXIPLIST"        ] || return # Если не существует файл exceptioniplist.
  [ -a "$DG_FGRPLIST"        ] || return # Если не существует файл filtergroupslist.
  local dg_restart=''
  if [ -a "$DG_EXIPLIST.tmp" ]; then
    diff &>/dev/null "$DG_EXIPLIST" "$DG_EXIPLIST.tmp"
    if [ $? -eq 0 ]; then
      rm -f "$DG_EXIPLIST.tmp"
    else
      dg_restart='Y'
      move_file "$DG_EXIPLIST"     "$DG_EXIPLIST.old"
      move_file "$DG_EXIPLIST.tmp" "$DG_EXIPLIST"
    fi
  fi
  if [ -a "$DG_FGRPLIST.tmp" ]; then
    diff &>/dev/null "$DG_FGRPLIST" "$DG_FGRPLIST.tmp"
    if [ $? -eq 0 ]; then
      rm -f "$DG_FGRPLIST.tmp"
    else
      dg_restart='Y'
      move_file "$DG_FGRPLIST"     "$DG_FGRPLIST.old"
      move_file "$DG_FGRPLIST.tmp" "$DG_FGRPLIST"
    fi
  fi
  if [ "$dg_restart" ]; then
    [ "$WEBPROXY" == "DGSQUID" ] && $NICE service dansguardian restart # Перезапускаем DansGuardian.
  fi
}
dnat()  # (IP,DPORT,TPORT) - Перенаправляем внешний входящий tcp-трафик с $IF_EXT:$DPORT на $IP:$TPORT.
{
  ip "$1" # Получаем $IP
  ipt -t nat    -A PREROUTING  -p tcp -i $IF_EXT --dport $2 -d $IP_EXT  -j DNAT --to-destination $1:$3
  ipt -t filter -A FORWARD     -p tcp -i $IF_EXT --dport $3             -j ACCEPT
  ipt -t filter -A FORWARD     -p tcp -s $IP $STATE ESTABLISHED,RELATED -j ACCEPT # Установленные соединения с IP.
  ipt -t filter -A FORWARD     -p tcp -d $IP $STATE ESTABLISHED,RELATED -j ACCEPT # Установленные соединения к IP.
# ipt -t nat    -A POSTROUTING -p tcp -o $IF_EXT            -s $1       -j SNAT --to-source $IP_EXT
# ipt -t nat    -A POSTROUTING -p tcp -o $IF_EXT --dport $3 -s $1       -j SNAT --to-source $IP_EXT
  printf '-'
}
i()  # (PROT,PORTS,LIMIT) - Разрешаем порты/протоколы c лимитом для внутренней сети.
{
  [ "$ENABLE_IEC" ] || return                        # Проверяем, разрешено ли исполнять команду.
  prot "$1"; ports "$2"; limit "$3"; conn_limit "$4" # Получаем $PROT; $PORTS,$SPORTS,$DPORTS,DNAT_DPORT,$DNAT_TPORT; $LIMIT; $CONN_LIMIT.
  if [ "$CONN_LIMIT" ]; then
  CONN_NAME=$((CONN_NAME+1))
  ipt -t filter -A INPUT   $PROT $DPORTS -i $IFs_INT $STATE NEW -m recent --name i$CONN_NAME --update --seconds 60 --hitcount $CONN_LIMIT -j LOG --log-prefix "fwtraf_i$CONN_NAME:"
  ipt -t filter -A INPUT   $PROT $DPORTS -i $IFs_INT $STATE NEW -m recent --name i$CONN_NAME --update --seconds 60 --hitcount $CONN_LIMIT -j DROP
  ipt -t filter -A INPUT   $PROT $DPORTS -i $IFs_INT $STATE NEW -m recent --name i$CONN_NAME --set
  fi
  for lan in $LANS; do
  ipt -t filter -A INPUT   $PROT $DPORTS -i $IFs_INT -d $lan     $LIMIT -j ACCEPT
  ipt -t filter -A INPUT   $PROT $SPORTS -i $IFs_INT -d $lan     $LIMIT -j ACCEPT
# ipt -t filter -A OUTPUT  $PROT $DPORTS -s $lan     -o $IFs_INT $LIMIT -j ACCEPT
  ipt -t filter -A OUTPUT  $PROT $SPORTS -s $lan     -o $IFs_INT $LIMIT -j ACCEPT
  done
  ipt -t filter -A FORWARD $PROT $DPORTS -i $IFs_INT -o $IFs_INT $LIMIT -j ACCEPT
  ipt -t filter -A FORWARD $PROT $SPORTS -i $IFs_INT -o $IFs_INT $LIMIT -j ACCEPT
  # Для доступа к внешнему интерфейсу из LAN.
  ipt -t filter -A INPUT   $PROT $DPORTS -i $IFs_INT -d $IP_EXT  $LIMIT -j ACCEPT
  ipt -t filter -A INPUT   $PROT $SPORTS -i $IFs_INT -d $IP_EXT  $LIMIT -j ACCEPT
# ipt -t filter -A OUTPUT  $PROT $DPORTS -s $IP_EXT  -o $IFs_INT $LIMIT -j ACCEPT
  ipt -t filter -A OUTPUT  $PROT $SPORTS -s $IP_EXT  -o $IFs_INT $LIMIT -j ACCEPT
  printf 'i'
}
e()  # (PROT,PORTS,LIMIT) - Разрешаем порты/протоколы c лимитом для внешней сети.
{
  [ "$ENABLE_IEC" ] || return                        # Проверяем, разрешено ли исполнять команду.
  prot "$1"; ports "$2"; limit "$3"; conn_limit "$4" # Получаем $PROT; $PORTS,$SPORTS,$DPORTS,DNAT_DPORT,$DNAT_TPORT; $LIMIT; $CONN_LIMIT.
  if [ "$CONN_LIMIT" ]; then
  CONN_NAME=$((CONN_NAME+1))
  ipt -t filter -A INPUT  $PROT $DPORTS -i $IF_EXT $STATE NEW -m recent --name e$CONN_NAME --update --seconds 60 --hitcount $CONN_LIMIT -j LOG --log-prefix "fwtraf_e$CONN_NAME:"
  ipt -t filter -A INPUT  $PROT $DPORTS -i $IF_EXT $STATE NEW -m recent --name e$CONN_NAME --update --seconds 60 --hitcount $CONN_LIMIT -j DROP
  ipt -t filter -A INPUT  $PROT $DPORTS -i $IF_EXT $STATE NEW -m recent --name e$CONN_NAME --set
  fi
  ipt -t filter -A INPUT  $PROT $DPORTS -i $IF_EXT $LIMIT -j ACCEPT
  ipt -t filter -A INPUT  $PROT $SPORTS -i $IF_EXT $LIMIT -j ACCEPT
  ipt -t filter -A OUTPUT $PROT $DPORTS -o $IF_EXT $LIMIT -j ACCEPT
  ipt -t filter -A OUTPUT $PROT $SPORTS -o $IF_EXT $LIMIT -j ACCEPT
  printf 'e'
}
c()  # (PROT,PORTS,LIMIT) - Разрешаем порты/протоколы c лимитом для внутренней и внешней сетей.
{
  [ "$ENABLE_IEC" ] || return                        # Проверяем, разрешено ли исполнять команду.
  prot "$1"; ports "$2"; limit "$3"; conn_limit "$4" # Получаем $PROT; $PORTS,$SPORTS,$DPORTS,DNAT_DPORT,$DNAT_TPORT; $LIMIT; $CONN_LIMIT.
  if [ "$CONN_LIMIT" ]; then
                   CONN_NAME=$((CONN_NAME+1))
                   ipt -t filter -A INPUT       $PROT $DPORTS $STATE NEW -m recent --name c$CONN_NAME --update --seconds 60 --hitcount $CONN_LIMIT -j LOG --log-prefix "fwtraf_c$CONN_NAME:"
                   ipt -t filter -A INPUT       $PROT $DPORTS $STATE NEW -m recent --name c$CONN_NAME --update --seconds 60 --hitcount $CONN_LIMIT -j DROP
                   ipt -t filter -A INPUT       $PROT $DPORTS $STATE NEW -m recent --name c$CONN_NAME --set
  fi
                   ipt -t filter -A INPUT       $PROT $DPORTS $LIMIT             -j ACCEPT
  [ "$SPORTS" ] && ipt -t filter -A INPUT       $PROT $SPORTS $LIMIT             -j ACCEPT
                   ipt -t filter -A OUTPUT      $PROT $DPORTS $LIMIT             -j ACCEPT
  [ "$SPORTS" ] && ipt -t filter -A OUTPUT      $PROT $SPORTS $LIMIT             -j ACCEPT
                   ipt -t filter -A FORWARD     $PROT $DPORTS $LIMIT             -j ACCEPT
  [ "$SPORTS" ] && ipt -t filter -A FORWARD     $PROT $SPORTS $LIMIT             -j ACCEPT
  [ "$SNAT" ] && [ "$PROT" != 'gre' ] && \
  for lan in $LANS; do
                   ipt -t nat    -A POSTROUTING $PROT $DPORTS -s $lan -o $IF_EXT -j SNAT --to-source $IP_EXT
  done
  printf 'c'
}
count_ip()  # (IP) - Считаем трафик для IP-адреса хоста или сети.
{
  check_local "$1" || return # Если это не локальный IP.
  ipt -t mangle -A _into -d $1 -j ACCEPT # Если это локальный хост, то учитываем внешний входящий трафик.
}
allow_ip()  # (IP) - Разрешаем tcp-трафик для IP (а также udp-трафик, если не заданы порты).
{
  [ "$DPORTS" ] && PROT='-p tcp' || PROT=''
  ipt -t filter -A INPUT       $PROT -s $1 $DPORTS            $LIMIT -j ACCEPT # Разрешаем входящий tcp-трафик для портов от клиента к     серверу.
  ipt -t filter -A FORWARD     $PROT -s $1 $DPORTS            $LIMIT -j ACCEPT # Разрешаем          tcp-трафик для портов от клиента через сервер.
  ipt -t filter -A OUTPUT      $PROT -d $1                    $LIMIT -j ACCEPT # Режем скорость отдачи пакетов сервером клиенту.
  [ "$SNAT" ] && \
  ipt -t nat    -A POSTROUTING $PROT -s $1 $DPORTS -o $IF_EXT $LIMIT -j SNAT --to-source $IP_EXT # Разрешаем SNAT для трафика, стремящегося наружу.
}
allow_tcpservice()  # (IP,PORTS,LIMIT) - Разрешаем обращения к внешним сервисам (ip,tcp-портам) для всей внутренней сети.
{
  ip "$1"; ports "$2"; limit "$3" # Получаем $IP; $PROT; $PORTS; $LIMIT.
  ipt -t nat    -A PREROUTING  -p tcp -i $IFs_INT $DPORTS         -d $IP $LIMIT -j ACCEPT
  ipt -t filter -A FORWARD     -p tcp -i $IFs_INT $DPORTS         -d $IP $LIMIT -j ACCEPT
  [ "$SNAT" ] && \
  for lan in $LANS; do
  ipt -t nat    -A POSTROUTING -p tcp -o $IF_EXT  $DPORTS -s $lan -d $IP $LIMIT -j SNAT --to-source $IP_EXT
  done
  printf '@'
}
deny_ip()  # (IP) - Запрещаем tcp/udp-трафик для IP.
{
  ipt -t mangle -A deny -p tcp -s $1 $DPORTS -j DROP # Запрещаем весь входящий tcp-трафик с IP.
  ipt -t mangle -A deny -p tcp -s $1 $SPORTS -j DROP # Запрещаем весь входящий tcp-трафик с IP.
  ipt -t mangle -A deny -p udp -s $1 $DPORTS -j DROP # Запрещаем весь входящий udp-трафик с IP.
  ipt -t mangle -A deny -p udp -s $1 $SPORTS -j DROP # Запрещаем весь входящий udp-трафик с IP.
}
deny_ip_all()  # (IP) - Запрещаем весь tcp/udp-трафик для IP.
{
  ipt -t mangle -A deny -s $1 -j DROP # Запрещаем весь входящий tcp/udp-трафик с IP.
}
d()  # (IP,NAME,WA,PORTS) - Запрещаем весь входящий трафик для IP.
{
  [ "$ENABLE_D" ] || return        # Проверяем, разрешено ли исполнять команду.
  ip "$1"; name "$2"; wa "$3"; ports "$4" # Получаем $IP; $NAME; $WA; $PORTS,$SPORTS,$DPORTS,DNAT_DPORT,$DNAT_TPORT.
  case "$PORTS" in
     '') write_dns   "$IP" "$NAME" # Прописываем в DNS, если адрес из локальной сети.
         write_ipdb  "$IP"         # Пишем информацию в ip-базу данных, если адрес из локальной сети.
         ;;
    all) deny_ip_all "$IP"         # Запрещаем весь tcp/udp-трафик для IP.
         write_dns   "$IP" "$NAME" # Прописываем в DNS, если адрес из локальной сети.
         write_ipdb  "$IP"         # Пишем информацию в ip-базу данных, если адрес из локальной сети.
         ;;
      *) deny_ip     "$IP"         # Запрещаем tcp/udp-трафик для IP.
         count_ip    "$IP"         # Считаем трафик для IP.
         write_dns   "$IP" "$NAME" # Прописываем в DNS, если адрес из локальной сети.
         write_dg    "$IP" "$WA"   # Определяем права WEB-доступа.
         write_ipdb  "$IP"         # Пишем информацию в ip-базу данных, если адрес из локальной сети.
         ;;
  esac
  printf 'd'
}
a()  # (IP,NAME,WA,PORTS,LIMIT) - Разрешаем tcp-порты для IP хоста/сети, определяем группу WEB-доступа, устанавливаем лимит.
{
  [ "$ENABLE_A" ] || return       # Проверяем, разрешено ли исполнять команду.
  ip "$1"; name "$2"; wa "$3"; ports "$4"; limit "$5" # Получаем $IP; $NAME; $WA; $PORTS,$SPORTS,$DPORTS,DNAT_DPORT,$DNAT_TPORT; $LIMIT.
  case "$PORTS" in
     '') write_dns  "$IP" "$NAME" # Прописываем в DNS, если адрес из локальной сети.
         write_ipdb "$IP"         # Пишем информацию в ip-базу данных, если адрес из локальной сети.
         ;;
    all) allow_ip   "$IP"         # Разрешаем порты для IP, устанавливаем лимит.
         count_ip   "$IP"         # Считаем трафик для IP.
         write_dns  "$IP" "$NAME" # Прописываем в DNS, если адрес из локальной сети.
         write_dg   "$IP" "$WA"   # Определяем права WEB-доступа.
         write_ipdb "$IP"         # Пишем информацию в ip-базу данных, если адрес из локальной сети.
         ;;
      *) allow_ip   "$IP"         # Разрешаем порты для IP, устанавливаем лимит.
         count_ip   "$IP"         # Считаем трафик для IP.
         [ "$DNAT_DPORT" ] && [ "$DNAT_TPORT" ] && dnat "$IP" "$DNAT_DPORT" "$DNAT_TPORT"
         write_dns  "$IP" "$NAME" # Прописываем в DNS, если адрес из локальной сети.
         write_dg   "$IP" "$WA"   # Определяем права WEB-доступа.
         write_ipdb "$IP"         # Пишем информацию в ip-базу данных, если адрес из локальной сети.
         ;;
  esac
  printf 'a'
}
D()  # (IP,NAME,WA,PORTS) - Запрещаем весь входящий трафик для IP.
{
  EXTDOMAINFLAG='Y' # Уст. флаг записи в зону внешнего домена.
  d $1 $2 $3 $4
  EXTDOMAINFLAG=''  # Сбрасываем флаг записи в зону внешнего домена.
}
A()  # (IP,NAME,WA,PORTS,LIMIT) - Разрешаем tcp-порты для IP хоста/сети, определяем группу WEB-доступа, устанавливаем лимит.
{
  EXTDOMAINFLAG='Y' # Уст. флаг записи в зону внешнего домена.
  a $1 $2 $3 $4 $5
  EXTDOMAINFLAG=''  # Сбрасываем флаг записи в зону внешнего домена.
}
enable_gw()  # () - Включаем маршрутизацию/NAT через внутренний шлюз к сетям.
{
  [ "$NETS_VIA_GW" ] || NETS_VIA_GW=`cat 2>/dev/null "$STATICROUTES"|grep -a '.*/.*'|awk '{print $3}'`
  # Удаляем из STATICROUTES добавленные ранее сети.
  cat 2>/dev/null "$STATICROUTES"|grep -av '.*/.*'>"/tmp/fwtraf.enable_gw.$$"
  move_file "/tmp/fwtraf.enable_gw.$$" "$STATICROUTES"
  chmod 644                            "$STATICROUTES"
  chown root:root                      "$STATICROUTES"
  # Удаляем сети, и если задан шлюз GW, добавляем их снова в таблицу маршрутизации и в STATICROUTES.
  for net in $NETS_VIA_GW; do
    route 2>/dev/null del -net $net
    [ "$GW" ] || continue

    printf "Add route to $net via $GW"
    route 2>/dev/null add -net $net gw $GW
    if [ $? -eq 0 ]; then
      # Определяем интерфейс, через который подключен шлюз.
      local if_to_gw=`route -n|grep -a "^${net%%\/*} "|awk '{print $8}'`
      # Добавляем в STATICROUTES сеть.
      echo>>"$STATICROUTES" "$if_to_gw net $net gw $GW"
      # Разрешаем пакеты через шлюз к сетям.
      ipt -t mangle -A PREROUTING  -i $IFs_INT -d $net -j ACCEPT
      for lan in $LANS; do
      ipt -t mangle -A POSTROUTING -s $lan     -d $net -j ACCEPT
      done
      # Разрешаем пакеты конкретно на шлюз (нужно только для его контроля).
      ipt -t mangle -A PREROUTING  -i $IFs_INT -d $GW  -j ACCEPT
      for lan in $LANS; do
      ipt -t mangle -A POSTROUTING -s $lan     -d $GW  -j ACCEPT
      done
      [ "$SNAT_TO_GW" ] || { echo; continue; }
      echo ". Enable SNAT to $net on $SNAT_TO_GW"
      for lan in $LANS; do
      ipt -t nat -A POSTROUTING -s $lan -d $net -j SNAT --to-source $SNAT_TO_GW
      ipt -t nat -A POSTROUTING -s $lan -d $GW  -j SNAT --to-source $SNAT_TO_GW
      done
    else
      echo ': Error'
    fi
  done
}
fwprepare()  # (POLICY) - Подготавливает IPTables.
{
  # Задаем политики на цепочки.
  ipt -t mangle -P PREROUTING  ACCEPT; ipt -t filter -P INPUT   $1; ipt -t nat -P PREROUTING  ACCEPT
  ipt -t mangle -P OUTPUT      ACCEPT; ipt -t filter -P FORWARD $1; ipt -t nat -P OUTPUT      ACCEPT
  ipt -t mangle -P POSTROUTING ACCEPT; ipt -t filter -P OUTPUT  $1; ipt -t nat -P POSTROUTING ACCEPT
  # Удаляем все правила и очищаем цепочки.
  ipt -t mangle -F; ipt -t mangle -X
  ipt -t filter -F; ipt -t filter -X
  ipt -t nat    -F; ipt -t nat    -X
  # Разрешаем трафик с петлевого интерфейса.
  ipt -t mangle -A PREROUTING  -i $IF_LO -j ACCEPT; ipt -t filter -A INPUT  -i $IF_LO -j ACCEPT # входящий.
  ipt -t mangle -A POSTROUTING -o $IF_LO -j ACCEPT; ipt -t filter -A OUTPUT -o $IF_LO -j ACCEPT # исходящий.
  # Загружаем модули.
  depmod -a
  modprobe &>/dev/null ip_conntrack
  modprobe &>/dev/null ip_conntrack_ftp ports=21,2121
  modprobe &>/dev/null ip_nat_ftp       ports=21,2121
  modprobe &>/dev/null ip_nat_pptp
  modprobe &>/dev/null ip_conntrack_pptp
  modprobe &>/dev/null ip_gre
  echo>'/proc/sys/net/ipv4/ip_conntrack_max' '131072'
}
fwaccept()  # () - Разрешаем все пакеты, отключаем SNAT.
{
  lock_check # Проверяем, не запущен ли скрипт уже.
  lock_run   # Устанавливаем блокировку запуска.
  ipt_begin  # Начинаем запись команд iptables в файл $IPTFILE.
  fwprepare ACCEPT
  ipt_end    # Применяем команды iptables из файла $IPTFILE.
  lock_unset # Удаляем блокировку запуска.
}
fwsimple()  # () - Устанавливает простые правила для всех локалых сетей.
{
  [ "$IF_EXT" ] || { printf 'ERROR: external interface not found\a\n'; exit 1; }
  lock_check # Проверяем, не запущен ли скрипт уже.
  lock_run   # Устанавливаем блокировку запуска.
  ipt_begin  # Начинаем запись команд iptables в файл $IPTFILE.
  fwprepare ACCEPT
  enable_gw  # Включаем маршрутизацию/NAT через внутренний шлюз к сетям.
  # Перенаправляем http на Squid/DansGuardian.
  [ "$WEBPROXY" == 'SQUID'   ] && ipt -t nat -A PREROUTING  -p tcp -i $IFs_INT --dport 80   -j REDIRECT --to-ports 3128
  [ "$WEBPROXY" == 'SQUID'   ] && ipt -t nat -A PREROUTING  -p tcp -i $IFs_INT --dport 8080 -j REDIRECT --to-ports 3128
  [ "$WEBPROXY" == 'DGSQUID' ] && ipt -t nat -A PREROUTING  -p tcp -i $IFs_INT --dport 80   -j REDIRECT --to-ports 8080
  [ "$SNAT"                  ] && \
  {
    # Запрещаем NAT для SMTP.
    ipt     -t nat -A POSTROUTING -p tcp -o $IF_EXT --dport 25 -j DROP
    for lan in $LANS; do
      [ "$REMOTE_LANS" ] && \
      for remote_lan in $REMOTE_LANS; do
        ipt -t nat -A POSTROUTING -s $lan -d $remote_lan -j ACCEPT
      done
      ipt   -t nat -A POSTROUTING -s $lan -o $IF_EXT     -j SNAT --to-source $IP_EXT
    done
  }
  ipt_end    # Применяем команды iptables из файла $IPTFILE.
  lock_unset # Удаляем блокировку запуска.
}
fwsingle()  # (IP) - Устанавливает простые правила для одного локального IP (опасно).
{
  ip "$1" # Получаем $IP
  [ "$IP"     ] || { printf 'ERROR: local IP not specified\a\n'      ; exit 1; }
  [ "$IF_EXT" ] || { printf 'ERROR: external interface not found\a\n'; exit 1; }
  lock_check # Проверяем, не запущен ли скрипт уже.
  lock_run   # Устанавливаем блокировку запуска.
  ipt_begin  # Начинаем запись команд iptables в файл $IPTFILE.
  fwprepare ACCEPT
  enable_gw  # Включаем маршрутизацию/NAT через внутренний шлюз к сетям.
  [ "$SNAT" ] && \
  {
    # Запрещаем NAT для SMTP.
    ipt   -t nat -A POSTROUTING -p tcp -o $IF_EXT --dport 25 -j DROP
    [ "$REMOTE_LANS" ] && \
    for remote_lan in $REMOTE_LANS; do
      ipt -t nat -A POSTROUTING -s $IP -d $remote_lan -j ACCEPT
    done
    ipt   -t nat -A POSTROUTING -s $IP -o $IF_EXT     -j SNAT --to-source $IP_EXT
  }
  ipt_end    # Применяем команды iptables из файла $IPTFILE.
  lock_unset # Удаляем блокировку запуска.
}
fwnormal()  # () - Устанавливает правила для нормальной работы сервера.
{
  [ "$HOSTNAME"   ] || { printf 'ERROR: host name unknown - check /etc/hosts\a\n'  ; exit 1; }
  [ "$DOMAINNAME" ] || { printf 'ERROR: domain name unknown - check /etc/hosts\a\n'; exit 1; }
  [ "$IF_EXT"     ] || { printf 'ERROR: external interface not found\a\n'          ; exit 1; }
  lock_check # Проверяем, не запущен ли скрипт уже.
  lock_run   # Устанавливаем блокировку запуска.
  dg_begin   # Сохраняем списки DG, чтобы потом узнать, были ли в них изменения.
  ipt_begin  # Начинаем запись команд iptables в файл $IPTFILE.
  printf '\n[ base rules processing ]\n'; fwprepare DROP # Подготавливаем IPTables.

  ###################################    Правила, в которые попадает больше всего трафика,
  ###   Цепочки (таблица mangle)  ###    ставим повыше для увеличения скорости и снижения нагрузки на CPU).
  ###################################

# # Маркируем внешний трафик (Type Of Service: 0x02 - Minimize Cost).
# ipt -t mangle -A PREROUTING -i $IF_EXT -j TOS  --set-tos  0x02
# ipt -t mangle -A PREROUTING -i $IF_EXT -j MARK --set-mark 0x02

  ############################################################################
  ###   Цепочка и правила для отсева ненужных пакетов - (таблица mangle)   ###
  ############################################################################

  ipt -t mangle -N deny # Создаем цепочку для отсева ненужных пакетов.
  ipt -t mangle -A deny -p tcp --tcp-flags SYN,ACK                  SYN,ACK $STATE NEW      -j DROP
  ipt -t mangle -A deny -p tcp ! --syn                                      $STATE NEW      -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG  NONE                    -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,SYN                  FIN,SYN                 -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags SYN,RST                  SYN,RST                 -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,RST                  FIN,RST                 -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,ACK                  FIN                     -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags PSH,ACK                  PSH                     -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags ACK,URG                  URG                     -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG  FIN                     -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG  FIN,PSH,URG             -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG  FIN,SYN,RST,ACK,URG     -j DROP
  ipt -t mangle -A deny -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG  FIN,SYN,RST,PSH,ACK,URG -j DROP

  ##############################################################
  ###   Цепочки и правила учета трафика - (таблица mangle)   ###
  ##############################################################

  # Создаем цепочки учета трафика и добавляем туда правила, с которых снимается статистика
  # (поик по ключ. словам "deny", "ACCEPT" и "RETURN").
  ipt -t mangle -N _exti              # Цепочка учета внешнего входящего         трафика.
  ipt -t mangle -N _extiall           # Цепочка учета внешнего входящего   всего трафика.
  ipt -t mangle -N _extiweb           # Цепочка учета внешнего входящего     WEB-трафика.
  ipt -t mangle -N _extiftp           # Цепочка учета внешнего входящего     FTP-трафика.
  ipt -t mangle -N _extieml           # Цепочка учета внешнего входящего     EML-трафика.
  ipt -t mangle -N _extixxx           # Цепочка учета внешнего входящего прочего трафика.
  ipt -t mangle -A _exti                                                 -j _extiall
  ipt -t mangle -A _exti -p tcp -m multiport --dports 80,443             -j _extiweb
  ipt -t mangle -A _exti -p tcp -m multiport --sports 80,443             -j _extiweb
  ipt -t mangle -A _exti -p tcp              --dport  20:21              -j _extiftp
  ipt -t mangle -A _exti -p tcp              --sport  20:21              -j _extiftp
  ipt -t mangle -A _exti -p tcp -m multiport --dports 25,110,143,587,995 -j _extieml
  ipt -t mangle -A _exti -p tcp -m multiport --sports 25,110,143,587,995 -j _extieml
  ipt -t mangle -A _exti                                                 -j _extixxx
  ipt -t mangle -A _extiall -j RETURN # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extiweb -j deny   # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extiftp -j deny   # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extieml -j deny   # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extixxx -j deny   # Это правило используется для подсчета трафика.

  ipt -t mangle -N _exto              # Цепочка учета внешнего исходящего         трафика.
  ipt -t mangle -N _extoall           # Цепочка учета внешнего исходящего   всего трафика.
  ipt -t mangle -N _extoweb           # Цепочка учета внешнего исходящего     WEB-трафика.
  ipt -t mangle -N _extoftp           # Цепочка учета внешнего исходящего     FTP-трафика.
  ipt -t mangle -N _extoeml           # Цепочка учета внешнего исходящего     EML-трафика.
  ipt -t mangle -N _extoxxx           # Цепочка учета внешнего исходящего прочего трафика.
  ipt -t mangle -A _exto                                         -j _extoall
  ipt -t mangle -A _exto -p tcp -m multiport --dports 80,443     -j _extoweb
  ipt -t mangle -A _exto -p tcp -m multiport --sports 80,443     -j _extoweb
  ipt -t mangle -A _exto -p tcp              --dport  20:21      -j _extoftp
  ipt -t mangle -A _exto -p tcp              --sport  20:21      -j _extoftp
  ipt -t mangle -A _exto -p tcp -m multiport --dports 25,110,143 -j _extoeml
  ipt -t mangle -A _exto -p tcp -m multiport --sports 25,110,143 -j _extoeml
  ipt -t mangle -A _exto                                         -j _extoxxx
  ipt -t mangle -A _extoall -j RETURN # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extoweb -j ACCEPT # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extoftp -j ACCEPT # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extoeml -j ACCEPT # Это правило используется для подсчета трафика.
  ipt -t mangle -A _extoxxx -j ACCEPT # Это правило используется для подсчета трафика.

  ipt -t mangle -N _inti                   # Цепочка фильтрации входящего локального трафика.
  for lan in $LANS; do
  ipt -t mangle -A _inti -d $lan -j ACCEPT # Внутренний входящий трафик к серверу.
  done
  ipt -t mangle -A _inti -j deny           # Переходим в цепочку запрета.

  ipt -t mangle -N _into # Цепочка учета внешнего входящего трафика по хостам и сетям.

  # Отлавливаем внешний
  ipt -t mangle -A PREROUTING  -i $IF_EXT                                     -j _exti  # входящий трафик.
  ipt -t mangle -A POSTROUTING -o $IF_EXT                                     -j _exto  # исходящий трафик.
  # Отлавливаем внутренний
  ipt -t mangle -A PREROUTING  -i $IFs_INT                                    -j _inti  # входящий трафик.
  ipt -t mangle -A POSTROUTING -o $IFs_INT                         -s $IP_EXT -j ACCEPT # исходящий в LAN, с внешнего интерфейса - его не считаем.
  [ "$WEBPROXY" ] && \
  for lan in $LANS; do
  ipt -t mangle -A POSTROUTING -o $IFs_INT -p tcp --sport $WEBPORT -s $lan    -j _into  # проксируемый LAN->LAN, WEB.
  ipt -t mangle -A POSTROUTING -o $IFs_INT                         -s $lan    -j ACCEPT # остальной    LAN->LAN - его не считаем.
  done
  ipt -t mangle -A POSTROUTING -o $IFs_INT                                    -j _into  # остальной       ->LAN - внешний непроксируемый (HTTPS,FTP,EML,ICQ,...).
# # Отлавливаем маркированный исходящий трафик с внутреннего интерфейса.
# ipt -t mangle -A POSTROUTING -o $IFs_INT -m tos --tos 0x02 -o $IFs_INT -j _into

# ipt -t mangle -A FORWARD -i $IFs_INT -s 10.5.33.212 -j TOS --set-tos 0x10

  enable_gw # Включаем маршрутизацию/NAT через внутренний шлюз к сетям.

  # Разрешаем почтовые сервисы.
  [ "$EMLSERVICES" ] && \
  for emlservice in $EMLSERVICES; do
  allow_tcpservice "$emlservice" '25,110' $LIMIT_EML
  done

  # Разрешаем web-сервисы.
  [ "$WEBSERVICES" ] && \
  for webservice in $WEBSERVICES; do
  allow_tcpservice "$webservice" '80,443' $LIMIT_WEB
  done

  ###################################################
  ###   DNAT - Цепочка PREROUTING (таблица nat)   ###
  ###################################################

# # DNAT из локальной сети для FTP.
# ipt -t nat -A PREROUTING -p tcp -i $IFs_INT -d 192.168.0.5 --dport 20:21 -j DNAT --to-destination 192.168.34.211
# # DNAT из Интернет для RDP.
# ipt -t nat -A PREROUTING -p tcp             -d $IP_EXT     --dport 3389  -j DNAT --to-destination 192.168.1.103:3389
# ipt -t nat -A PREROUTING -p tcp             -d 57.67.17.135              -j DNAT --to-destination 192.168.100.1
# ipt -t nat -A PREROUTING -p tcp             -d 63.87.6.92                -j DNAT --to-destination 192.168.100.1
  # DNAT для Exchange (RPC Over HTTPs)
  [ "$HOSTNAME" == 'main' ] && dnat '10.124.8.133' '443' '443'

  #######################################################
  ###   REDIRECT - Цепочка PREROUTING (таблица nat)   ###
  #######################################################

  # Закрываем порты, на которые делаем перенаправление.
  if [ "$FTPPROXY" == 'FROX'    ]; then
                               ipt -t nat -A PREROUTING -p tcp -i $IF_EXT                         --dport 2121       -j DROP
    for ip_int in $IPs_INT; do ipt -t nat -A PREROUTING -p tcp -d $ip_int                         --dport 2121       -j DROP; done
  fi
  if [ "$WEBPROXY" == 'SQUID'   ]; then
                               ipt -t nat -A PREROUTING -p tcp -i $IF_EXT                         --dport 3128       -j DROP
    for ip_int in $IPs_INT; do ipt -t nat -A PREROUTING -p tcp -d $ip_int                         --dport 3128       -j DROP; done
  fi
  if [ "$WEBPROXY" == 'DGSQUID' ]; then
                               ipt -t nat -A PREROUTING -p tcp -i $IF_EXT -d $IP_EXT -m multiport --dports 3128,8080 -j DROP
    for ip_int in $IPs_INT; do ipt -t nat -A PREROUTING -p tcp            -d $ip_int -m multiport --dports 3128,8080 -j DROP; done
  fi
  # Избавляемся от LAN->LAN/REMOTE_LAN-трафика в этой цепочке.
  for lan in $LANS $REMOTE_LANS; do ipt -t nat -A PREROUTING -i $IFs_INT -d $lan -j RETURN; done
  # Перенаправляем LAN->EXT-трафик.
  [ "$FTPPROXY" == 'FROX'    ] && ipt -t nat -A PREROUTING -i $IFs_INT -p tcp --dport 21   -j REDIRECT --to-ports 2121
  [ "$WEBPROXY" == 'SQUID'   ] && ipt -t nat -A PREROUTING -i $IFs_INT -p tcp --dport 80   -j REDIRECT --to-ports 3128
  [ "$WEBPROXY" == 'SQUID'   ] && ipt -t nat -A PREROUTING -i $IFs_INT -p tcp --dport 8080 -j REDIRECT --to-ports 3128
  [ "$WEBPROXY" == 'DGSQUID' ] && ipt -t nat -A PREROUTING -i $IFs_INT -p tcp --dport 80   -j REDIRECT --to-ports 8080

  ###################################    Правила, в которые попадает больше всего трафика,
  ###   Цепочки (таблица filter)  ###    ставим повыше для увеличения скорости и снижения нагрузки на CPU).
  ###################################

# ipt -t filter -A INPUT -m mac --mac-source 00:18:f3:a3:3f:24  -j DROP # Блокируем входящий трафик с MAC-адреса (ogk812).
# ipt -t filter -A FORWARD -p udp -m length --length 39 -m u32 --u32 '27&0x8f=7' --u32 '31=0x527c4833' -j DROP # Режем Skype.

  ipt -t filter -A INPUT               $STATE ESTABLISHED,RELATED -j ACCEPT # Установленные соединения к серверу.
  ipt -t filter -A FORWARD -o $IFs_INT $STATE ESTABLISHED,RELATED -j ACCEPT # Исходящие установленные соединения с внутренних интерфейсов.
  ipt -t filter -A OUTPUT  -o $IF_EXT -s $IP_EXT                  -j ACCEPT # Исходящий с внешнего интерфейса наружу.

  for lan in $LANS; do
    ipt -t filter -A FORWARD -i $IFs_INT        -d $lan                    -j ACCEPT # Транзитный из локальных сетей в локальные сети.
    ipt -t filter -A OUTPUT  -o $IFs_INT -p tcp -s $lan --sport ! $WEBPORT -j ACCEPT # Исходящий TCP, кроме WEB, с внутреннего интерфейса вовнутрь.
    ipt -t filter -A OUTPUT  -o $IFs_INT -p udp -s $lan                    -j ACCEPT # Исходящий UDP с внутренних интерфейсов вовнутрь.
    [ "$REMOTE_LANS" ] && \
    for remote_lan in $REMOTE_LANS; do
      ipt -t filter -A INPUT       -s $remote_lan -d $lan        -j ACCEPT # Входящий   из удалённых локальных сетей в           локальные сети.
      ipt -t filter -A FORWARD     -s $remote_lan -d $lan        -j ACCEPT # Транзитный из удалённых локальных сетей в           локальные сети.
      ipt -t filter -A FORWARD     -s $lan        -d $remote_lan -j ACCEPT # Транзитный из           локальных сетей в удалённые локальные сети.
      ipt -t filter -A OUTPUT      -s $lan        -d $remote_lan -j ACCEPT # Исходящий  из           локальных сетей в удалённые локальные сети.
      ipt -t nat    -A POSTROUTING -s $lan        -d $remote_lan -j ACCEPT # Не допускаем SNAT из    локальных сетей в удалённые локальные сети.
    done
  done

  # ICMP (type: 0-ответ "Echo reply", 8-запрос "Echo request", 11-ответ "TTL equals 0").
  ipt -t filter -A INPUT       -p icmp                    -j ACCEPT                   # Входящий  ICMP.
# ipt -t filter -A INPUT       -p icmp --icmp-type 0      -j ACCEPT                   # Входящий  ICMP.
# ipt -t filter -A INPUT       -p icmp --icmp-type 8      -j ACCEPT                   # Входящий  ICMP.
# ipt -t filter -A INPUT       -p icmp --icmp-type 11     -j ACCEPT                   # Входящий  ICMP.
  ipt -t filter -A OUTPUT      -p icmp                    -j ACCEPT                   # Исходящий ICMP.
  ipt -t filter -A FORWARD     -p icmp                    -j ACCEPT                   #           ICMP.
  [ "$SNAT" ] && \
  for lan in $LANS; do
    ipt -t nat  -A POSTROUTING -p icmp -s $lan -o $IF_EXT -j SNAT --to-source $IP_EXT # NAT для   ICMP.
  done

  [ "$FTPPROXY" ] && \
  for lan in $LANS; do
    ipt -t filter -A INPUT -p tcp -i $IFs_INT -d $lan --dport 2121 -j ACCEPT # Входящий локальный Frox.
  done

  printf '\n[ deny rules processing ]\n'  ; ENABLE_D='Y'; ENABLE_IEC='' ; ENABLE_A='' ; . $CONFIGFILE # Подключаем $CONFIGFILE 2 раз - выполняем d().
  printf '\n[ policy rules processing ]\n'; ENABLE_D='' ; ENABLE_IEC='Y'; ENABLE_A='' ; . $CONFIGFILE # Подключаем $CONFIGFILE 3 раз - выполняем i(),e(),c().
  printf '\n[ allow rules processing ]\n' ; ENABLE_D='' ; ENABLE_IEC='' ; ENABLE_A='Y'; . $CONFIGFILE # Подключаем $CONFIGFILE 4 раз - выполняем a(),A().

  ipt -t filter -A FORWARD -i $IF_EXT -p tcp --sport 1024: --dport 1024: -j DROP # Запрещаем соединения с
  ipt -t filter -A FORWARD -o $IF_EXT -p tcp --sport 1024: --dport 1024: -j DROP # непривелигированных портов
  ipt -t filter -A FORWARD -i $IF_EXT -p udp --sport 1024: --dport 1024: -j DROP # на непривелигированные
  ipt -t filter -A FORWARD -o $IF_EXT -p udp --sport 1024: --dport 1024: -j DROP # на внешнем интерфейсе.

  # Чтобы оставшийся трафик не вернулся в родительские цепочки подсчета, разрешаем его.
  ipt -t mangle -A deny -j ACCEPT

  ipt_end                                                            # Применяем команды iptables, если необходимо.
  dg_end                                                             # Перезапускаем DansGuardian, если необходимо.
  [ -a "$DNSROOTDIR/etc/named.conf" ] && $NICE service named reload  # Перечитываем DNS-зоны.
  lock_unset                                                         # Удаляем блокировку запуска.
  status                                                             # Показываем статус.
}
fwsave()  # fwsave () - Сохраняет правила.
{
  lock_check # Проверяем, не запущен ли скрипт уже.
  lock_run   # Устанавливаем блокировку запуска.
  iptables-save>"$IPTABLESFILE"
  lock_unset # Удаляем блокировку запуска.
}
fwview()  # (OPTIONS,SUBSTR) - Просм. цепочки [совп. с п/строкой]
{
  printf '\n************\nMANGLE table\n************\n\n' >"/tmp/fwtraf.fwview.$$"; iptables -t mangle -L $1>>"/tmp/fwtraf.fwview.$$"
  printf '\n************\nFILTER table\n************\n\n'>>"/tmp/fwtraf.fwview.$$"; iptables -t filter -L $1>>"/tmp/fwtraf.fwview.$$"
  printf '\n************\nNAT table   \n************\n\n'>>"/tmp/fwtraf.fwview.$$"; iptables -t nat    -L $1>>"/tmp/fwtraf.fwview.$$"
  if [ "$2" ]; then
    cat 2>/dev/null "/tmp/fwtraf.fwview.$$"|grep -ai "$2">"/tmp/fwtraf.fwview1.$$"
    move_file "/tmp/fwtraf.fwview1.$$" "/tmp/fwtraf.fwview.$$"
  fi
  mc -e "/tmp/fwtraf.fwview.$$"
  rm -f "/tmp/fwtraf.fwview.$$"
}
fwviewb() { mc -v "$IPTABLESFILE";       }  # Просм. правила, уст. при загрузке.
fwviewi() { mc -v "$IPTFILE";            }  # Просм. тек. команды iptables.
fwviewio(){ mc -v "$IPTFILE.old";        }  # Просм. предыд. команды iptables.
fwconf()  { mc -e "${CONFIGFILE//.tmp}"; }  # Редакт. конфиг. файл.
dginet()  # (MODE) - Меняет последнюю группу фильтрации на первую (т.е. включает Интернет) или наооборот.
{
  [    "$DG_CONF"     ] || { printf 'ERROR: variable "DG_CONF" not found\a\n'          ; exit 1; }
  [ -a "$DG_CONF"     ] || { printf "ERROR: file \"$DG_CONF\" not found\a\n"           ; exit 1; }
  [    "$DG_FGRP"     ] || { printf 'ERROR: parameter "filtergroups" not found\a\n'    ; exit 1; }
  [    "$DG_FGRPLIST" ] || { printf 'ERROR: parameter "filtergroupslist" not found\a\n'; exit 1; }
  [ -a "$DG_FGRPLIST" ] || { printf "ERROR: file \"$DG_FGRPLIST\" not found\a\n"       ; exit 1; }
  lock_check # Проверяем, не запущен ли скрипт уже.
  lock_run   # Устанавливаем блокировку запуска.
  case "$1" in
    on ) cat 2>/dev/null "$DG_FGRPLIST"|sed 2>/dev/null -e "s/=filter${DG_FGRP}/= filter1/g">"/tmp/filtergroupslist.$$" ;;
    off) cat 2>/dev/null "$DG_FGRPLIST"|sed 2>/dev/null -e "s/= filter1/=filter${DG_FGRP}/g">"/tmp/filtergroupslist.$$" ;;
  esac
  [ -a "/tmp/filtergroupslist.$$" ] || { printf "ERROR: file \"/tmp/filtergroupslist.$$\" not found\a\n"; exit 1; }
  diff &>/dev/null "/tmp/filtergroupslist.$$" "$DG_FGRPLIST" || \
  {
    cat 2>/dev/null "/tmp/filtergroupslist.$$">"$DG_FGRPLIST"
    service dansguardian restart
  }
  rm -f "/tmp/filtergroupslist.$$"
  lock_unset # Удаляем блокировку запуска.
}
trafhourly()  # () - Выполняется в 58 минут каждого часа.
{
  local dt=`date +%Y%m%d%H%M`
  mkdir -p "$IPDBDIR/EXT_IN"  "$IPDBDIR/EXT_IN_WEB"  "$IPDBDIR/EXT_IN_FTP"  "$IPDBDIR/EXT_IN_EML"  "$IPDBDIR/EXT_IN_XXX"
  mkdir -p "$IPDBDIR/EXT_OUT" "$IPDBDIR/EXT_OUT_WEB" "$IPDBDIR/EXT_OUT_FTP" "$IPDBDIR/EXT_OUT_EML" "$IPDBDIR/EXT_OUT_XXX"
  iptables 2>/dev/null -t mangle -L _extiall -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="RETURN") {print date,$2>>outdir"/EXT_IN/fwtraf_counter"     }}'
  iptables 2>/dev/null -t mangle -L _extiweb -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="deny")   {print date,$2>>outdir"/EXT_IN_WEB/fwtraf_counter" }}'
  iptables 2>/dev/null -t mangle -L _extiftp -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="deny")   {print date,$2>>outdir"/EXT_IN_FTP/fwtraf_counter" }}'
  iptables 2>/dev/null -t mangle -L _extieml -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="deny")   {print date,$2>>outdir"/EXT_IN_EML/fwtraf_counter" }}'
  iptables 2>/dev/null -t mangle -L _extixxx -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="deny")   {print date,$2>>outdir"/EXT_IN_XXX/fwtraf_counter" }}'
  iptables 2>/dev/null -t mangle -L _extoall -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="RETURN") {print date,$2>>outdir"/EXT_OUT/fwtraf_counter"    }}'
  iptables 2>/dev/null -t mangle -L _extoweb -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="ACCEPT") {print date,$2>>outdir"/EXT_OUT_WEB/fwtraf_counter"}}'
  iptables 2>/dev/null -t mangle -L _extoftp -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="ACCEPT") {print date,$2>>outdir"/EXT_OUT_FTP/fwtraf_counter"}}'
  iptables 2>/dev/null -t mangle -L _extoeml -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="ACCEPT") {print date,$2>>outdir"/EXT_OUT_EML/fwtraf_counter"}}'
  iptables 2>/dev/null -t mangle -L _extoxxx -v -x -n -Z|awk -v outdir=$IPDBDIR -v date=$dt '{if ($3=="ACCEPT") {print date,$2>>outdir"/EXT_OUT_XXX/fwtraf_counter"}}'
  iptables 2>/dev/null -t mangle -L _into    -v -x -n -Z \
  |while read pkts bytes target prot opt in out src dst; do
     if [ "$target" == 'ACCEPT' -a "$bytes" != '0' ]; then
       mkdir -p "$IPDBDIR/${dst/\/*}"
       echo>>"$IPDBDIR/${dst/\/*}/fwtraf_counter" "$dt $bytes"
     fi
   done
  find 2>/dev/null $IPDBDIR/*/fwtraf_counter -type f -mtime +90 -exec rm -rf {} \; # Удаляем файлы, не обновлявшиеся в течение 90 суток.
}
trafmake_body()  # (FILEMASK,FILEMASK_DESC) - Дописывает тело отчета по указанной маске.
{
  cat>>"$REPORTFILE"<<*

*
  :>"/tmp/fwtraf.trafmake_body.$$"
  local yyyymmdd=`date +%Y%m%d`
  local   yyyymm=`date +%Y%m`
  local     yyyy=`date +%Y`
  cd "$IPDBDIR"
  for ip in $1; do
    [ -a "$ip/fwtraf_counter" ] || continue
    local   tr_d=`summa "$yyyymmdd" "$ip/fwtraf_counter"`
    local   tr_m=`summa "$yyyymm"   "$ip/fwtraf_counter"`
    local   tr_y=`summa "$yyyy"     "$ip/fwtraf_counter"`
    local   name=`tail 2>/dev/null -n1 "$ip/fwtraf_name"  |sed -e "s/${N}${BLANK1}//"`
    local access=`tail 2>/dev/null -n1 "$ip/fwtraf_access"|sed -e "s/${N}${BLANK1}//"`
    local   desc=`tail 2>/dev/null -n1 "$ip/fwtraf_desc"  |sed -e "s/${N}${BLANK1}//"`
    local    cmd=`echo "$access"|awk '{print $1}'`
    local  ports=`echo "$access"|awk '{print $2}'`
    local     wa=`echo "$access"|awk '{print $3}'`
    local  limit=`echo "$access"|awk '{print $4}'`
    local  title=' '; [[ "$access" > ' ' ]] && \
    {
      case "$cmd" in
        a) title="${ports//all/Все}"          ;;
        d) title="Закрыты: ${ports//all/все}" ;;
      esac
      case "$ports" in
        *web*|all|!*) case "$wa" in
                        0) title="$title. Web-доступ: полный"     ;;
                        *) title="$title. Web-доступ: $wa группа" ;;
                      esac
                      ;;
      esac
      [[ "$limit" == [0-9]* ]] && title="$title. Скорость: $limit пакет./сек."
    }
    echo>>"/tmp/fwtraf.trafmake_body.$$" "$tr_d $tr_m $tr_y $ip %$name %${title// /%} %${desc// /%}"
  done
  # Одеваем тело в HTML.
  sort -rnk3<"/tmp/fwtraf.trafmake_body.$$" \
  |awk '{if ($3>"")
           {
              CONVFMT="%0.f";
              printf "\n"                               , c=c?"":" bgcolor=#E0E0E0", $6;
              printf "  \n";
           }
        }' \
  |sed -e 's/\/весь/g;
           s/\/весь/g;
           s/\/- web/g;
           s/\/- web/g;
           s/\/- ftp/g;
           s/\/- ftp/g;
           s/\/- email/g;
           s/\/- email/g;
           s/\/- прочий/g;
           s/\/- прочий/g;
           s/%/ /g;' \
  >>"$REPORTFILE"
  echo>>"$REPORTFILE" '
$2 трафик (Мб) с начала: суток месяца года Комментарии
%s\n" , n+=1; printf " \n"; if ($5>"%") printf " %s\n", $4, $4; else printf " %s\n" , $4; printf " \n"; printf " %s\n" , $5; printf " %s\n" , $1/1048576; printf " %s\n" , $2/1048576; printf " %s\n" , $3/1048576; printf " \n"; printf " %s\n" , $7; printf "
' echo>>"$REPORTFILE" ' ' rm -f "/tmp/fwtraf.trafmake_body.$$" } trafmake() # () - Создает отчет о трафике с начала суток/месяца/года по текущее время в $REPORTFILE. { echo >"$REPORTFILE" '' echo>>"$REPORTFILE" '' echo>>"$REPORTFILE" "$(env LC_ALL=ru_RU.KOI-8R date +'%e %b %Y. %A, %T')" trafmake_body 'EXT_IN*' 'Суммарный входящий' trafmake_body 'EXT_OUT*' 'Суммарный исходящий' trafmake_body '*.*' 'Входящий' echo>>"$REPORTFILE" '' # Создаем индексный файл. cd "$REPORTDIR" printf>'index.htm' 'FwTraf\n' for file in ????-??-??.htm; do [[ ${file//*-/} == '01.htm' ]] && printf>>'index.htm' '

\n' printf>>'index.htm' "${file//.htm/}\n" done printf>>'index.htm' '\n' } trafsend() # (REPEML) - Отправляет отчет о трафике на адрес $REPEML. { [ "$1" ] && sendmail $1<<* From: <$HOSTNAME> To: <$1> Subject: FWTraf Report MIME-Version: 1.0 Content-Type: text/html; charset="koi8-r" Content-Transfer-Encoding: quoted-printable `cat 2>/dev/null "$REPORTFILE"` * } status() # () - Показывает статус. { local all_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\' "$CONFIGFILE"|wc -l` local _users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\!' "$CONFIGFILE"|wc -l` local web_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*[^\!]\<(web|http|https|80|443)\>' "$CONFIGFILE"|wc -l` local _web_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\!\<(web|http|https|80|443)\>' "$CONFIGFILE"|wc -l` local ftp_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*[^\!]\<(ftp|21)\>' "$CONFIGFILE"|wc -l` local _ftp_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\!\<(ftp|21)\>' "$CONFIGFILE"|wc -l` local smtp_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*[^\!]\<(smtp|25)\>' "$CONFIGFILE"|wc -l` local _smtp_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\!\<(smtp|25)\>' "$CONFIGFILE"|wc -l` local pop3_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*[^\!]\<(pop3|110)\>' "$CONFIGFILE"|wc -l` local _pop3_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\!\<(pop3|110)\>' "$CONFIGFILE"|wc -l` local imap_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*[^\!]\<(imap|143)\>' "$CONFIGFILE"|wc -l` local _imap_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\!\<(imap|143)\>' "$CONFIGFILE"|wc -l` local icq_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*[^\!]\<(icq|5190)\>' "$CONFIGFILE"|wc -l` local _icq_users=`egrep '^[ \t]*a[ \t]+[0-9\.]+[ \t]+[A-Za-z0-9_-]+[ \t]+.*\!\<(icq|5190)\>' "$CONFIGFILE"|wc -l` local dns_records1=`egrep '^[ \t]*[ad][ \t]+10\.*' "$CONFIGFILE"|wc -l` local dns_records2=`egrep '^[ \t]*[ad][ \t]+172\.16\.*' "$CONFIGFILE"|wc -l` local dns_records3=`egrep '^[ \t]*[ad][ \t]+192\.168\.*' "$CONFIGFILE"|wc -l` local ipdbdir_size=`du -s -l -m ${IPDBDIR%%/}|awk '{print $1}'` echo echo " Внешний интерфейс: $IF_EXT" echo "Пользователей с полным доступом: $all_users" echo " WEB-пользователей: $((web_users + all_users + _users - _web_users ))" echo " FTP-пользователей: $((ftp_users + all_users + _users - _ftp_users ))" echo " SMTP-пользователей: $((smtp_users + all_users + _users - _smtp_users))" echo " POP3-пользователей: $((pop3_users + all_users + _users - _pop3_users))" echo " IMAP-пользователей: $((imap_users + all_users + _users - _imap_users))" echo " ICQ-пользователей: $((icq_users + all_users + _users - _icq_users ))" echo " Записей в DNS: $((dns_records1 + dns_records2 + dns_records3 ))" echo " Размер базы: $ipdbdir_size Мб" echo local warning=`cat 2>/dev/null '/var/log/messages'|grep -a 'ip_conntrack: table full'|tail -n1` if [ "$warning" ]; then printf "WARNING: $warning\a\n\n" printf 'Run the command "fwtraf topconntrack" to view details.\n\n' fi } topconnects() # () - Показывает IP, превышающие лимиты подключений к серверу на порт. { cat 2>/dev/null "$MESSAGES" \ |grep -a 'fwtraf_' \ |awk '{print $9,$18,$19}' \ |sed -e 's/SRC=//;s/SPT=[0-9]\+//;s/DPT=//;s/WINDOW=[0-9]\+//' \ |sort -gr \ |uniq -c \ |sort -gr \ |head -n20 \ |while read top ip port; do local desc=`tail 2>/dev/null -n1 "$IPDBDIR/$ip/fwtraf_desc"|sed -e "s/${N}${BLANK1}//"` if [ -z "$desc" ]; then desc=`dig +short -x $ip|head -n1` desc=${desc//;;*/} desc=${desc%.} fi printf '%-7s %-7s %-15s #%s\n' "$top" "[$port]" "$ip" " $desc" done echo } toptraffic() # () - Показывает счётчики трафика файервола. { iptables -t mangle -L _into -v -x -n \ |while read pkts bytes target prot opt in out src dst; do [ "$target" == "ACCEPT" -a "$bytes" != '0' ] && echo "$bytes ${dst/\/*}" done \ |sort -gr \ |head -n20 \ |while read bytes ip; do local desc=`tail 2>/dev/null -n1 "$IPDBDIR/$ip/fwtraf_desc"|sed -e "s/${N}${BLANK1}//"` printf '%-8s %-15s %s\n' "$((bytes/1048576))" "$ip" "$desc" done } topconntrack() { # Состояние Время ожидания # ----------- -------------- # NONE 30 минут # ESTABLISHED 5 дней # SYN_SENT 2 минуты # SYN_RECV 60 секунд # FIN_WAIT 2 минуты # TIME_WAIT 2 минуты # CLOSE 10 секунд # CLOSE_WAIT 12 часов # LAST_ACK 30 секунд # LISTEN 2 минуты local tmpfile="/tmp/fwtraf_topconntrack.$$" echo echo "Maximal connections count: `cat 2>/dev/null /proc/sys/net/ipv4/ip_conntrack_max`" echo "Current connections count: `cat 2>/dev/null /proc/net/ip_conntrack|wc -l`" echo cat 2>/dev/null '/proc/net/ip_conntrack'>"$tmpfile" echo 'Top protocols:' echo cat 2>/dev/null "$tmpfile" \ |awk '{print $1}' \ |sort \ |uniq -c \ |sort -gr echo echo 'Top state:' echo cat 2>/dev/null "$tmpfile" \ |egrep -a ' (NONE|ESTABLISHED|SYN_SENT|SYN_RECV|FIN_WAIT|TIME_WAIT|CLOSE|CLOSE_WAIT|LAST_ACK|LISTEN) ' \ |awk '{print $4}' \ |sort \ |uniq -c \ |sort -gr echo echo 'Top source IP (tcp):' echo cat 2>/dev/null "$tmpfile" \ |grep -a 'tcp' \ |awk '{print $5}' \ |sort \ |uniq -c \ |sort -gr \ |head -n 20 \ |sed -e 's/src=//g' echo echo 'Top destination IP (tcp):' echo cat 2>/dev/null "$tmpfile" \ |grep -a 'tcp' \ |awk '{print $6}' \ |sort \ |uniq -c \ |sort -gr \ |head -n 20 \ |sed -e 's/dst=//g' echo echo 'Top detination port (tcp):' echo cat 2>/dev/null "$tmpfile" \ |grep -a 'tcp' \ |awk '{print $8}' \ |sort \ |uniq -c \ |sort -gr \ |head -n 20 \ |sed -e 's/dport=//g' echo rm -f "$tmpfile" } backup() # () - Сохраняет скрипт, конфигурацию, логи и отчеты в архив. { lock_check # Проверяем, не запущен ли скрипт уже. lock_run # Устанавливаем блокировку запуска. mkdir -p '/backup' tar czf "/backup/fwtraf_${HOSTNAME}_$(date +%Y%m%d).tgz" "$0" "$CONFIGDIR" "$IPDBDIR" "$REPORTDIR" '/etc/cron.d/fwtraf' /bin/phoss* /bin/nbtscan* lock_unset # Удаляем блокировку запуска. } restore() # () - Восстанавливает все из архива. { [ -a "$1" ] || { printf 'ERROR: backup file not found\a\n'; exit 1; } lock_check # Проверяем, не запущен ли скрипт уже. lock_run # Устанавливаем блокировку запуска. tar xzf "$1" -C / lock_unset # Удаляем блокировку запуска. } ipdbfind() # (SUBSTR,[IP_FIELD]) - Ищет все строки, совп. с заданной подстрокой в БД. { [[ "$@" < '!' ]] && { printf 'ERROR: substring not specified\a\n'; exit 1; } cat 2>/dev/null "$CONFIGFILE"|grep -ai "$1"|sed -e "s/^$BLANK1//g; s/$BLANK1/ /g" echo cat 2>/dev/null "$DHCPD_CONF"|grep -ai "$1"|sed -e "s/^$BLANK1//g; s/$BLANK1/ /g" echo grep 2>/dev/null -air "$1" "$IPDBDIR$2" \ |sort -k1 -r \ |sed -e 's/^\/var\/log\/ipdb\/\(.*\)\/\(.*\):\([0-9]\{4\}\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\) \(.*\)/\3-\4-\5 \6:\7 \1 \2 \8/' echo } ipdbdel() # (SUBSTR) - Удаляет все строки, совп. с заданной подстрокой из БД. { [[ "$@" < '!' ]] && { printf 'ERROR: substring not specified\a\n'; exit 1; } grep -air "$@" "$IPDBDIR" \ |cut -d':' -f1 \ |sort \ |uniq \ |while read file other; do cat 2>/dev/null "$file" \ |grep -aiv "$@" \ >"/tmp/fwtraf.ipdbdel.$$" move_file "/tmp/fwtraf.ipdbdel.$$" "$file" done } ipdbclear() # () - Очищает ip-базу данных от старых данных (время выполнения ~1,5 мин). { local cutdate=`date -d '-12 month' +%Y%m%d0000` # Дата, до которой удаляются данные. for file in $IPDBDIR/*/{fwtraf,nbtscan,phoss}_*; do cat 2>/dev/null "$file" \ |egrep -av '^[0-9]+ 0$' \ |awk -v cdate=$cutdate '{if ($1>cdate) printf "%s\n",$0}' \ >"/tmp/fwtraf.ipdbclear.$$" if [[ "`ls 2>/dev/null -s /tmp/fwtraf.ipdbclear.$$`" == '0 '* ]]; then rm -f "/tmp/fwtraf.ipdbclear.$$" "$file" else move_file "/tmp/fwtraf.ipdbclear.$$" "$file" fi done } ipmove() # (IP_SRC,IP_DST) - Удаляет каталог IP_DST и переименовывает каталог IP_SRC в IP_DST. { [[ "$IPDBDIR" < '/#' ]] && { printf 'ERROR: IPDBDIR not valid\a\n'; exit 1; } ip_or_net_valid "$1" || { printf 'ERROR: ip_src not valid\a\n'; exit 1; } ip_or_net_valid "$2" || { printf 'ERROR: ip_dst not valid\a\n'; exit 1; } if [ -d "$IPDBDIR/$1" ]; then [ -d "$IPDBDIR/$2" ] && rm -fr "$IPDBDIR/$2" mkdir -p "$IPDBDIR/$2" cp 2>/dev/null -fR --reply=yes $IPDBDIR/$1/* $IPDBDIR/$2/ [ -d "$IPDBDIR/$2" ] && rm -fr "$IPDBDIR/$1" else printf "ERROR: \"$IPDBDIR/$1\" not exist\a\n"; exit 1 fi } help() # () - Выводит помощь. { clear cat<<* ---------------------------------- УПРАВЛЕНИЕ FIREWALL / УЧЕТ ТРАФИКА ---------------------------------- Использование: fwtraf [команда] Команды: fwaccept - разрешить все пакеты, отключить SNAT fwsimple - уст. простые правила для всех локальных сетей fwsingle ip - уст. простые правила для одного локального IP fwnormal - уст. правила для нормальной работы fwsave - сохр. тек. правила fwconf - редакт. конфиг. файл fwview ["substr"] - просм. тек. цепочки iptables fwviewb - просм. правила, уст. при загрузке fwviewi - просм. тек. команды iptables fwviewio - просм. предыд. команды iptables dginet_on - вкл. Интернет пользователям с гр. дост. "$DG_FGRP" dginet_off - выкл. Интернет пользователям с гр. дост. "$DG_FGRP" trafmake - создать отчет о трафике trafsend "email" - отослать отчет о трафике ipdbfind "substr" [/ip/field] - искать все строки в БД, совп. с п/строкой ipdbdel "substr" - удалить все строки из БД, совп. с п/строкой ipdbclear - очистить БД от данных годичной давности ipmove ip_src ip_dst - переименовать ip_src в ip_dst backup - сделать резервную копию restore "backupfile" - восстановить резервную копию lock - заблокировать выполнение (выполняется авт.) unlock - разблокировать выполнение (опасно) status - показать статус topconnects - показать IP, превышающ. лимиты подкл. к серверу toptraffic - показать счётчики трафика файервола topconntrack - показать статистику таблицы отслеживанияй соединений * exit 1 } ################################################################################################ # НАЧАЛО ПРОГРАММЫ ################################################################################################ mkdir -p "$CONFIGDIR" "$IPDBDIR" "$REPORTDIR" # Создаем каталоги. if [ -a "$CONFIGFILE" ]; then # Если существует $CONFIGFILE rm -f "$CONFIGFILE.tmp" cp -af "$CONFIGFILE" "$CONFIGFILE.tmp" CONFIGFILE=$CONFIGFILE.tmp ENABLE_D=''; ENABLE_IEC=''; ENABLE_A=''; . $CONFIGFILE # Подключаем $CONFIGFILE 1 раз - импортируем переменные. else printf "ERROR: configuration file \"$CONFIGFILE\" not found\a\n"; exit 1 fi # Определяем внешний интерфейс. if [ "$EXTIF" ]; then IF_EXT=$EXTIF else IF_EXT=`route -n|awk '{if ($1=="0.0.0.0" && $3=="0.0.0.0") print $8}'` [ "$IF_EXT" ] || \ IF_EXT=`route -n|awk '{if ($2=="0.0.0.0" \ && $1!~/0\.0\.0\.0/ \ && $1!~/^10\./ \ && $1!~/^169\.254\./ \ && $1!~/^172\.1[6-9]\./ \ && $1!~/^172\.2[0-9]\./ \ && $1!~/^172\.31\./ \ && $1!~/^192\.168\./ \ && $1 ~/[0-9]+/ ) print $8}'|head -n1` fi IF_LO='lo' # Петлевой интерфейс. IFs_INT="! $IF_EXT" # Внутренние интерфейсы. IP_LO='127.0.0.1' # IP-адрес петлевого интерфейса. IP_EXT=`ifconfig|grep -A1 "^${IF_EXT//+/[0-9]\+} "|sed -n 's/inet addr://p'|awk 'END{print $1}'` # IP-адрес внешнего интерфейса (поддержка int+). # IP_EXT=`ifconfig $IF_EXT|sed -n 's/inet addr://p'|awk '{print $1}'` # IP-адрес внешнего интерфейса. IPs_INT=`ifconfig|grep -a 'inet addr'|cut -d: -f2|cut -d' ' -f1|grep -av "\<$IP_EXT\>"` # IP-адреса внутренних интерфейсов. case "$WEBPROXY" in SQUID)WEBPORT=3128;; DGSQUID)WEBPORT=8080;; *)WEBPORT=80;; esac # Определяем WEB-порт. NICE=`nice 2>/dev/null` # Компенсируем низкий приоритет. if [[ "$NICE" == -* ]]; then NICE="nice -n ${NICE/-/+}" else NICE='' fi case "$1" in fwaccept ) fwaccept ;; fwsimple ) fwsimple ;; fwsingle ) fwsingle "$2" ;; fwnormal ) fwnormal ;; fwsave ) fwsave ;; dginet_on ) dginet 'on' ;; dginet_off ) dginet 'off' ;; fwconf ) fwconf ;; fwview ) fwview '-v -n' "$2" ;; fwviewb ) fwviewb ;; fwviewi ) fwviewi ;; fwviewio ) fwviewio ;; trafhourly ) trafhourly ;; trafdaily ) trafdaily ;; trafmonthly ) trafmonthly ;; trafyearly ) trafyearly ;; trafmake ) trafmake ;; trafsend ) trafsend "$2" ;; ipdbfind ) ipdbfind "$2" "$3" ;; ipdbdel ) ipdbdel "$2" ;; ipdbclear ) ipdbclear ;; ipmove ) ipmove "$2" "$3" ;; backup ) backup ;; restore ) restore "$2" ;; lock ) lock_check; lock_set ;; unlock ) lock_unset ;; status ) status ;; topconnects ) topconnects ;; toptraffic ) toptraffic ;; topconntrack) topconntrack ;; * ) help ;; esac 
 
 
 
/etc/fwtraf/fwtraf.conf
 
#!/bin/bash
#----------------------
# Персональные политики
#----------------------

#C IP               NAME              WA  PORTS  [LIMIT]            DESC
#- ---------------  ----------------  --  ------------------------  ---------------------------------------
 a 10.0.250.1       pc113             1   !smtp                     # Компу разрешено всё, кроме SMTP
 a 10.1.114.200     nb124             2   web,pop3 10               # Ноутбук, скорость 10 пакетов в секунду
 a 10.1.114.201     pc115             3   web                       # Только WEB
 a 10.1.118.200     pc12              3   web,smtp,pop3             # Только WEB и почта
 a 10.1.118.201     pc152             2   web,ftp,8888              # Разрешено WEB,FTP, и ещё что-то
 a 10.1.124.202     pc128             3   web,ftp,pop3 50           # Разрешено WEB,FTP и получение почты
 a 10.1.130.200     pc194             3   web,bc_tc 10              # Финансисты, лимит 10 пакетов/секунду
 a 10.1.130.201     pc175             3   web,200,quik,bc_sb        # Финансисты. Quick, Банк-клиент "СберБанк"
 a 10.3.42.37       pc102                                           # Ничего не разрешено, кроме PING,TRACEROUTE
 d 10.3.46.21       pc417             6   all                       # Тупой юзер - запрещаем всё
 a 10.4.36.101      nb11              1   web,ftp,pop3,rdp 10       # Слишком продвинутый юзер - режем скорость
 a 10.5.14.103      pc210             1   all                       # Начальник отдела - открываем всё что можно
 a 10.8.91.202      pc24              2   web,ftp,pop3,oracle       # Программер
 a 10.16.26.207     pc77              3   web,bc_sb,bc_uc           # Банк-клиенты "СберБанк", "ЮникредитБанк"
 A 10.127.255.2     mail                                            # Почтовый сервер - оставляем запись в DNS
 A 10.127.255.2     mx1                                             # Почтовый сервер - оставляем запись в DNS
 a 10.127.255.128   vpn-user          3   rdp,telnet                # VPN-юзер - только RDP и TELNET

#---------------
# Запрещённые IP
#---------------

#C IP               NAME                                                   WA  PORTS     DESC
#- ---------------  -----------------------------------------------------  --  --------  ---------------------------------------
 d 64.233.161.99    google-analytics.com                                   6   all       # Google Spy
 d 72.14.209.99     google-analytics.com                                   6   all       # Google Spy
 d 72.14.253.99     google-analytics.com                                   6   all       # Google Spy
 d 72.14.217.91     sb.l.google.com                                        6   all       # Google Spy
 d 72.14.217.93     bu-in-f93.google.com                                   6   all       # Google Spy
 d 209.85.137.99    mg-in-f99.google.com                                   6   all       # Google Spy
 d 66.249.91.91     kh.l.google.com                                        6   all       # Google

#----------------------------------------------
# Общая политика: разрешённые протоколы и порты
#----------------------------------------------

#C  PROT  PORTS                               [LIMIT]  [CONN_LIMIT]  DESC
#-  ----  ----------------------------------  -------  ------------  -------------------------
 c  udp   dns                                 1000                   # DNS
 c  udp   ntp                                 10                     # NTP
 c  udp   traceroute                          10                     # TRACEROUTE
 c  tcp   fns                                 1000                   # FNS (Федеральная налоговая служба)
 c  udp   bc_sb_udp                           1000                   # BANKCLIENT СберБанка. VPN
 c  tcp   feanor                              100                    # FEANOR
 c  tcp   pptp                                100                    # PPTP
 c  gre   all                                                        # GRE for PPTP
 c  udp   500,4500                            1000                   # CiscoVPN
 e  tcp   openvpn                             1000     10            # OpenVPN
 e  tcp   http,https                          1000                   # HTTP,HTTPS
 i  tcp   http,https                          5000                   # HTTP,HTTPS
 e  tcp   smtp,smtpalt                        5000     5             # SMTP,SMTPALT
 i  tcp   smtp,smtpalt                                               # SMTP,SMTPALT
 e  tcp   pop3,imap                           1000     10            # POP3,IMAP
 i  tcp   pop3,imap                           1000     15            # POP3,IMAP
 e  tcp   ftp                                 1000     10            # FTP
 i  tcp   ftp                                 5000     10            # FTP
 e  tcp   ssh                                 20       10            # SSH
 i  tcp   ssh                                 1000     20            # SSH
 e  tcp   9090                                10       10            # OPENFIRE_CONSOLE
 i  tcp   9090                                10       10            # OPENFIRE_CONSOLE
 i  tcp   webmin,rdp,radmin                   1000     20            # WEBMIN,RDP,RADMIN
 i  udp   tftp                                100                    # TFTP
 i  tcp   smb,rsync                           5000                   # SMB,RSYNC
 i  udp   smb                                 5000                   # SMB
 i  udp   snmp                                20                     # SNMP
 c  tcp   jabber                              50                     # JABBER

#-------------------
# Основные настройки
#-------------------

         EXTIF=""                                                                         # Внешний интерфейс (опр. автоматически, если "")
 EXTDOMAINNAME="domain.com"                                                               # Внешний домен ("", "domain.com")
          LANS="192.168.0.0/24 10.0.0.0/24"                                               # Локальные сети ("xxx.xxx.xxx.xxx/yy")
#  REMOTE_LANS="10.128.0.0/16"                                                            # Удалённые сети ("xxx.xxx.xxx.xxx/yy")
          SNAT="YES"                                                                      # Трансляция адресов на внешний интерфейс ("","YES")
      WEBPROXY=""                                                                         # WEB-прокси ("","SQUID","DGSQUID")
      FTPPROXY=""                                                                         # FTP-прокси ("","FROX")
        REPEML=""                                                                         # Отчеты по почте ("","root","pupkin@mail.ru")
#           GW="192.168.10.254"                                                           # Маршрутизация к сетям через шлюз ("","IP")
#   SNAT_TO_GW="192.168.10.1"                                                             # IP локального интерфейса для SNAT к сетям ("","IP")
#  NETS_VIA_GW="194.84.224.0/26 212.176.66.0/24 212.176.70.0/24"                          # Сети, доступные через шлюз
          sbis="83.242.250.67 83.242.250.68"                                              # СБИС++ - электронная отчетность (порт 25)
         fstrf="87.226.173.3"                                                             # Федеральная служба по тарифам
        feanor="195.135.214.6"                                                            # Феанор
   EMLSERVICES="$sbis $fstrf $feanor"                                                     # Сервисы, использующие порты 25,110
           dc1="173.194.69.0/24"                                                          # Dicter
           tc1="46.182.25.0/24 66.102.13.0/24 74.125.0.0/16 74.125.79.96/28"              # Translate Client
           tc2="74.125.87.96/28 74.125.232.16/29 173.194.32.0/24 174.120.221.88"          # Translate Client
           tc3="207.46.192.223 209.85.146.0/23 209.85.148.0/23 209.85.173.0/24"           # Translate Client
           tc4="209.85.175.0/24 209.85.225.0/24 209.85.227.0/24 209.85.229.100/30"        # Translate Client
          mse1="4.23.0.0/16 64.4.0.0/18 64.209.77.25 65.52.0.0/14 74.125.232.48/30"       # Microsoft Security Essentials
          mse2="77.67.4.0/24 77.67.29.0/24 80.239.224.0/24 80.239.230.0/24"               # Microsoft Security Essentials
          mse3="80.239.254.0/24 92.122.208.112 92.123.69.0/24 94.245.64.0/18"             # Microsoft Security Essentials
          mse4="95.100.131.235 194.221.65.0/26 195.10.0.0/18 207.46.0.0/16"               # Microsoft Security Essentials
          mse5="213.155.154.0/24 213.199.149.98 217.212.252.128/25"                       # Microsoft Security Essentials
            ds="168.75.151.72"                                                            # DraftSight
   WEBSERVICES="$dc1 $tc1 $tc2 $tc3 $tc4 $mse1 $mse2 $mse3 $mse4 $mse5 $ds"               # Сервисы, использующие порты 80,443

#--------
# СПРАВКА
#--------

# Доступные команды:
#   i    PROT PORTS [LIMIT [CONN_LIMIT]] - разрешить трафик из внутренних сетей к заданным портам шлюза, уст. лимиты.
#   e    PROT PORTS [LIMIT [CONN_LIMIT]] - разрешить трафик из внешней    сети  к заданным портам шлюза, уст. лимиты.
#   c    PROT PORTS [LIMIT [CONN_LIMIT]] - разрешить трафик из любых      сетей к заданным портам шлюза и через него, уст. лимиты.
#   [dD] IP   NAME  [WA [PORTS        ]] - прописать в DNS, определить группу WEB-доступа, закрыть tcp/udp-порты.
#   [aA] IP   NAME  [WA [PORTS [LIMIT]]] - прописать в DNS, определить группу WEB-доступа, открыть tcp-порты, уст. лимит.
#   Примечание: Большие буквы D,A - прописать в DNS и перезаписать A-запись во внешнем домене IP-адресом из LAN.
#
# Параметры команд:
#       PROT: (tcp|udp|gre|icmp) - протокол.
#
#      PORTS: p1,..,pN                                   - разрешить порты p1,..,pN (не более 15).
#             p1:p2                                      - разрешить диапазон портов p1-p2.
#             [..,]p1-p2[,..]                            - разрешить порты p1 и p2 и сделать DNAT c EXT_IP:p1 на IP:p2.
#             !p1                                        - разрешить все порты кроме p1.
#             all                                        - разрешить все порты и протоколы.
#             dns,smtp,pop3,imap,smtpstls,pop3tls,eml,   - разрешить порты (не более 15).
#             fns,ftp,gpsmon,http,icq,irc,mssql,ntp,
#             openvpn,oracle,quik,rdp,radmin,sip,smb,
#             snmp,ssh,telnet,torrent,traceroute,web,
#             webinar,webmin,webmoney.
#
#      LIMIT: N  - ограничить скорость N пакетов/сек (2 пак/с=3Кб/с, 5 пак/с=7Кб/с, 10 пак/с=12Кб/с, 30 пак/с=20Кб/с).
#             "" - ограничить скорость Squid`ом.
#
# CONN_LIMIT: 0..20 - ограничить кол-во подключений/мин. Лимит действует для каждого IP отдельно.
#
#         IP: x.x.x.x[/y] - IP-адрес хоста или сети. Если сеть - группа WEB-доступа не применяется.
#
#       NAME: hostname - Имя хоста. Допустимые символы - буквы лат. алфавита, цифры и тире. Точка допускается, но используется
#             в качестве разделителя. Имя kms - служебное, для него будет создана SRV-запись, указывающая на KMS.
#
#         WA: 0..N - Группа фильтрации (WEB-доступ):
#             0 - разрешено всё (фильрация выключена - IP добавлен в exceptioniplist).
#             1 - разрешено всё.
#             2 - разрешено всё кроме скачивания audio/video.
#             3 - полная фильтрация (для простых пользователей).
#             4 - полная фильтрация + запрещены закачки.
#             5 - запрещено всё кроме domain.com,microsoft.com,windowsupdate.com (для серверов).
#             6 - запрещено всё кроме domain.com. 
 
/etc/cron.d/fwtraf.cron
 
# Минута  Час     День месяца  Месяц   День недели  Пользователь             Задание
# (0-59)  (0-23)  (1-31)       (1-12)  (0-7)
# ------  ------  -----------  ------  -----------  ------------  ---------  --------------------------------------------
  58      *       *            *       *            root                     /bin/fwtraf trafhourly; /bin/fwtraf trafmake
  30      23      *            *       0            root                     /bin/fwtraf ipdbclear
   
 
оригинал статьи http://habrahabr.ru/post/146116/