четверг, 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/