/ferm_documentation_on_russian

Дока по ferm. Переводил для себя, чтобы лучше запомнить. Написано на полу-русском, поэтому без умения в iptables будет не очень понятно.

Название

ferm - парсер файерволл-правил для линукс

Синтаксис

ferm options inputfile

Описание

ferm это фронтенд для iptables. Он читает правила из структурированного конфигурационного файла и вызывает iptables(8) для вставки их в запущенное ядро.

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

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

ferm произносится как "firm", и означает "For Easy Rule Making".

Предупреждение

Этот мануал не стремится научить тебя тому как работает файерволл и как писать хорошие правила. На эту тему уже есть достаточно документации.

Вступление

Начнем с простого примера:

chain INPUT {
  proto tcp ACCEPT;
}

Здесь добавляется правило во встроенную цепочку INPUT, которое сопоставляет и принимает все TCP пакеты. Хорошо, давайте усложним его:

chain (INPUT OUTPUT) {
        proto (udp tcp) ACCEPT;
}

Здесь будет вставлено 4 правила, а именно 2 правила в цепочку INPUT и 2 в OUTPUT. Правила будут принимать UDP и TCP пакеты.
Обычно ты бы напечатал так:

iptables -A INPUT -p tcp -j ACCEPT
iptables -A OUTPUT -p tcp -j ACCEPT
iptables -A INPUT -p udp -j ACCEPT
iptables -A OUTPUT -p udp -j ACCEPT

Заметил насколько меньше нам нужно печатать чтобы сделать это? :-)

В основном это все что нужно делать, однако, ты можешь сделать его более сложным. Что-то похожее на:

chain INPUT {
    policy ACCEPT;
    daddr 10.0.0.0/8 proto tcp dport ! ftp jump mychain sport :1023 TOS 4 settos 8 mark 2;
    daddr 10.0.0.0/8 proto tcp dport ftp REJECT;
}

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

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

Попробуй использовать комментарии, чтобы показать что ты делаешь:

# this line enables transparent http-proxying for the internal network:
proto tcp if eth0 daddr ! 192.168.0.0/255.255.255.0
    dport http REDIRECT to-ports 3128;

Потом сам скажешь спасибо!

chain INPUT {
    policy ACCEPT;
    interface (eth0 ppp0) {
        # deny access to notorious hackers, return here if no match
        # was found to resume normal firewalling
        jump badguys;

        protocol tcp jump fw_tcp;
        protocol udp jump fw_udp;
    }
}

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

chain FORWARD {
    proto ! udp DROP;
    proto tcp dport ftp ACCEPT;
}

потому что второе правило никогда не сработает. Лучший путь это сперва определить все что разрешено, а затем запретить все остальное. Смотри на примеры, чтобы было больше "хороших снимков". Многие люди делают что-то похожее на это:

proto tcp {
    dport (
        ssh http ftp
    ) ACCEPT;
    dport 1024:65535 ! syn ACCEPT;
    DROP;
}

Структура конфигурационного файла

Структура корректного файерволл-файла похожа на упрощенный C-код. Лишь несколько синтаксических символов используются в конфигурационных файлах ferm. Кроме этих специальных символов, ferm использует 'keys' и 'values', думай об этом как об опциях и параметрах или как о переменных и значениях.

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

Ты можешь описать условия которые будут валидны для kernel interface program которую ты используешь, скорее всего это iptables(8). Например, в iptables, если ты попытаешься сопоставить TCP пакеты, ты бы написал:

iptables --protocol tcp

В ferm это превращается в:

protocol tcp;

Просто набранное это, не сделает ничего, тебе нужно сказать ferm'у (на самом деле нужно сказать iptables(8) и ядру), что делать с трафиком который совпадает с этим условием:

iptables --protocol tcp -j ACCEPT

Или, в переводе ferm'a:

protocol tcp ACCEPT;

Символ ; есть на конце каждого ferm-правила. Ferm игнорирует переносы строк, значит пример выше идентичен следующему:

protocol tcp
  ACCEPT;

Далее список специальных символов:

;

Этот символ заканчивает правило. Разделяя точкой с запятой, ты можешь писать множество правил в одну строку, хоть это и уменьшает читабельность:

protocol tcp ACCEPT; protocol udp DROP;
{}

Символ вложенности определяет 'блок' правил.

Фигурные скобки содержат некоторое количество вложенных правил. Все совпадения до блока переносятся к ним.

Закрывающая фигурная скобка завершает набор правил. Тебе не нужно писать ';' после нее потому что это будет пустым правилом.

Пример:

chain INPUT proto icmp {
    icmp-type echo-request ACCEPT;
    DROP;
}

Этот блок показывает два правила внутри блока, они оба будут объединены с чем-либо перед этим блоком и ты получишь два правила:

iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp -j DROP

Здесь может быть множество уровней вложенности:

chain INPUT {
    proto icmp {
        icmp-type echo-request ACCEPT;
        DROP;
    }
    daddr 172.16.0.0/12 REJECT;
}

Заметь что на правило 'REJECT' не влияет 'proto icmp', однако там нет ';' после закрывающей фигурной скобки. В переводе на iptables:

iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp -j DROP
iptables -A INPUT -d 172.16.0.0/12 -j REJECT
$

Раскрытие переменной. Заменяет '$FOO' на значение переменной. Смотри в секцию VARIABLES для деталей.

&

Вызов функции. Смотри секцию FUNCTIONS для деталей.

()

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

Пример:

protocol ( tcp udp icmp )

результатом этого будут три правила:

... -p tcp ...
... -p udp ...
... -p icmp ...

Только значения могут буть 'засписочены', поэтому ты не сможешь сделать что-то похожее на это:

proto tcp ( ACCEPT LOG );

но ты можешь сделать так:

chain (INPUT OUTPUT FORWARD) proto (icmp udp tcp) DROP;

(что приведет к девяти правилам!)

Значения разделяются пробелами. Массив одновременно лево- и право-ассоциативный, в отличие от блока вложенности, который может быть только лево-ассоциативным.

#

Символ комментария. Все что следует за этим символом до конца строки - игнорируется.

`command`

Выполнить команду в shell и вставить вывод процесса. Смотри секцию backticks для деталей.

'string'

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

LOG log-prefix ' hey, this is my log prefix!';
"string"

Закавыченная строка (см. выше), но вызовы переменных через знак доллара остаются вычислимыми:

DNAT to "$myhost:$myport";

Ключевые слова

В предыдущей секции мы уже представили некоторые базовые ключевые слова, такие как "chain", "protocol" и "ACCEPT". Давайте исследуем их природу.

Здесь три вида ключевых слов:

  • location ключевые слова определяют где будет создано правило. Например: "table", "chain".
  • match ключевые слова сопоставляют все проходящие пакеты на соответствие условию. Текущее правило будет без эффекта если одно (или больше) сопоставление по критерию не пройдет. Пример: "proto", "daddr".
    За множеством критериев следует параметр: "proto tcp", "daddr 172.16.0.0./12".
  • target ключевые слова указывают что делать с пакетом. Пример: "ACCEPT", "REJECT", "jump".
    Многие цели описываются большим количеством ключевых слов для описания деталей: "REJECT reject-with icmp-net-unreachable".

Каждое правило состоит из location и target, плюс некоторое количество matches:

table filter                  # location
proto tcp dport (http https)  # match
ACCEPT;                       # target

Строго говоря, существует четвертый вид ключевых слов ferm (которые управляют внутренним поведением ferm), но они будут объяснены позже.

Параметры

Множество ключевых слов используют параметры. Они могут быть определены как константы, вызовы переменных или списки (массивы):

proto udp
saddr $TRUSTED_HOSTS;
proto tcp dport (http https ssh);
LOG log-prefix "funky wardriver alert: ";

Некоторые из них могут быть инвертированы (списки не могут):

proto !esp;
proto udp dport !domain;

Ключевые слова, которые не принимают параметров отрицаются префиксом '!':

proto tcp !syn;

Читай iptables(8) чтобы увидеть где может быть использован !.

Базовые ключевые слова

location keywords

  • domain [ip|ip6] - Устанавливает домен. "ip" значит "IPv4" (iptables) а "ip6" для поддержки IPv6, используя "ip6tables". Если ключевое слово не указано, будет использоваться значение из опции --domain или если и она не указана, то будет выбрано "ip", т.е. IPv4.

  • table [filter|nat|mangle] - Определяет в какую таблицу netfilter будет вставлено это правило: "filter" (default), "nat" или "mangle".

  • chain [chain-name] - Определяет в какую цепочку netfilter (в текущей таблице) это правило будет вставлено. Обычно в зависимости от таблицы предопределенны следующие имена цепочек "INPUT", "OUTPUT", "FORWARD", "PREROUTING", "POSTROUTING". Смотри документацию к netfilter для справки.

    Если указать здесь имя несуществующей цепочки, то ferm добавит правило в кастомную цепочку м таким именем.

  • policy [ACCEPT|DROP|...] - Определяет политику по умолчанию для текущей цепочки (только встроенные значения). Может быть одной из встроенных целей (ACCEPT, DROP, REJECT, ...). Пакет которому не подойдет ни одно правило в цепочке, будет обработан указанной политикой.

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

  • @subchain ["CHAIN-NAME"]{...} - Работает как обычный блок (без @subchain), за исключением того, что ferm перемещает правила внутри фигурных скобок в новую пользовательскую цепочку. Иия для этой цепочки будет выбрано автоматически ferm'ом.

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

    table filter chain INPUT {
      saddr (1.2.3.4 2.3.4.5 3.4.5.6 4.5.6.7 5.6.7.8) {
        proto tcp dport (http https ssh) ACCEPT;
        proto udp dport domain ACCEPT;
      }
    }
    

    Здесь будет сгенерировано 20 правил. Когда приходит пакет который не проходит saddr сопоставление, он тем не менее проверится через все 20 правил. С @subchain эта проверка пройдет единожды, как результат быстрая фильтрация и меньшая нагрузка на CPU:

    table filter chain INPUT {
      saddr (1.2.3.4 2.3.4.5 3.4.5.6 4.5.6.7 5.6.7.8) @subchain {
        proto tcp dport (http https ssh) ACCEPT;
        proto udp dport domain ACCEPT;
      }
    }
    

    Опционально можно задать имя для подцепочки:

    saddr (1.2.3.4 2.3.4.5 3.4.5.6) @subchain "foobar" {
      proto tcp dport (http https ssh) ACCEPT;
      proto udp dport domain ACCEPT;
    }
    

    Именем может быть любая закавыченная строковая константа или развернутое ferm выражение, такое как @cat("interface_", $iface) или @substr($var,0,20).

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

  • @gotosubchain ["CHAIN-NAME"]{...} - Работает как @subchain за искллючением того что вместот использования jump target используется goto target. Разницу между этими двумя таргетами смотри ниже.

  • @preserve - Сохранять существующие правила в текущей цепочке:

    chain (foo bar) @preserve;
    

    С этой опцией ferm загружает предыдущий набор правил используя iptables-save, выделяет все "preserved" цепочки и вставляет их в итоговый вывод.

    "Preserved" цепочки не должны изменяться ferm'ом: ни правила, ни политики.

Basic iptables match keywords

  • interface [interface-name] - Определяет имя интерфейса твоей внешней сетевой карты, как eth0 или dialup ppp1, или какого-либо другого девайса имя которого ты хочешь сопоставлять с проходящими пакетами. Это эквивалентно -i в iptables(8).
  • outerface [interface-name] - То же что и interface, только пакеты сопоставляются с исходящим интерфейсом, как в iptables(8).
  • protocol [protocol-name|protocol-number] - Сейчас ядро поддерживает TCP, UDP и ICMP или их соответствующие номера.
    Вместо protocol ты можешь также использовать сокращение proto.
  • saddr|daddr [address-spec] - Совпадение указанного адреса в адресе отправителя (saddr) или в адресе получателя (daddr).
    Пример:
    saddr 192.168.0.0/24 ACCEPT; # (identical to the next one:)
    saddr 192.168.0.0/255.255.255.0 ACCEPT;
    daddr my.domain.com ACCEPT;
    
  • fragment - Определяет что только фрагмент IP пакета будет заматчен. Когда пакеты больше чем максимальный размер с которым может справиться твоя система (это называется Maximum Transmission Unit или MTU), то они делятся на части и отправляются один за одним как одиночные пакеты. Смотри ifconfig(8) если хочешь узнать MTU своей системы (обычно по умолчанию это 1500 bytes).
    Фрагменты часто используются в DOS аттаках потому что нет пути поиска происхождения фрмагмента пакета.
  • sport|dport [port-spec] - Срабатывает на пакеты на указанный TCP или UDP порт. "sport" срабатывает на исходящий порт и "dport" срабатывает на конечный порт.
    Эта проверка может быть использована только после указания "protocol tcp" или "protocol udp", потому что только в этих двух протоколах на данный момент есть порты.
    И несколько примеров валидных портов/диапазонов:
    dport 80 ACCEPT;
    dport http ACCEPT;
    dport ssh:http ACCEPT;
    dport 0:1023 ACCEPT; # equivalent to :1023
    dport 1023:65535 ACCEPT;
    
  • syn - Указывает что SYN флаг, который используется для создания новых TCP соединений, должен быть в TCP пакете. Так ты можешь идентифицировать входящие соединения и принимать решение разрешать их или нет. Пакеты не имеющие такого флага обычно из уже существующих соединений, поэтому считается достаточно безопасным пропускать их.
  • module [module-name] - Загружает какой-либо iptables модуль. Множество модулей предоставляет много критериев. Мы вернемся к этому позже.
    Вместо module ты можешь также использовать сокращение mod

Basic target keywords

  • jump [custom-chain-name] - Перейти к кастомной цепочке. Если в кастомной цепочке нет походящего правила, netfilter вернется к следующему правилу в предыдущей цепочке.
  • goto [custom-chain-name] - Перейти к кастомной цепочке. Не похоже на jump, RETURN не будет продолжать обработку в этой цепочке, вместо этого продолжит в цепочке которая вызвала эту цепочку через jump.
  • ACCEPT - Допустить заматченный пакет.
  • DROP - Откинуть заматченный пакет без дальнейших уведомлений.
  • REJECT - Реджектить заматченные пакеты, то есть отправлять ICMP пакеты отправителю, в которых по умолчанию port-unreachable. Ты можешь определить иной ICMP тип.
    REJECT; # default to icmp-port-unreachable
    REJECT reject-with icmp-net-unreachable;
    
    Вводи "iptables -j REJECT -h" для справки.
  • RETURN - Закончить в текущей цепочке и вернуться к вызвавшей цепочке (если "jump [custom-chain-name]" использован)
  • NOP - Нет действий для всех.

ADDITIONAL KEYWORDS

Netfilter модульный. Модули погут предоставлять дополнительные критерии. Список модулей netfilter постоянно растет, а ferm пытается сохранить поддержку их всех.

iptables match modules

  • account - Учитывать трафик для всех хостов в определенной сети. Это один из модулей поиска совпадений, который уже ведет себя как цель, поэтому в основном тебе придется использовать цель NOP.
    mod account aname mynetwork aaddr 192.168.1.0/24 ashort NOP;
    
  • addrtype - Проверка типа адреса; любой: исходящй адрес или адрес назначения.
    mod addrtype src-type BROADCAST;
    mod addrtype dst-type LOCAL;
    
    Набери "iptables -m addrtype -h" для справки.
  • ah - Проверка SPI заголовка в AH пакете.
    mod ah ahspi 0x101;
    mod ah ahspi ! 0x200:0x2ff;
    
    Дополнительные аргументы для IPv6:
    mod ah ahlen 32 ACCEPT;
    mod ah ahlen !32 ACCEPT;
    mod ah ahres ACCEPT;
    
  • bpf - Матчинг с использованием Linux Socket Filter.
    mod bpf bytecode "4,48 0 0 9,21 0 1 6,6 0 0 1,6 0 0 0";
    
  • cgroup - Матчинг с использованием cgroupsv2 hierarchy или устаревшего net_cls cgroup.
    mod cgroup path ! example/path ACCEPT;
    
    Путь относителен корня cgroupsv2 hierarchy и сравнивается с начальной частью пути процесса в иерархии.
    mod cgroup cgroup 10:10 DROP;
    mod cgroup cgroup 1048592 DROP;
    
    Соответствует значению net_cls.classid установленному на процесс старым net_cls cgroup. Этот класс может быть определен как шестнадцатеричная major:minor пара (см. tc(8)), или как десятичное число, эти два правила эквивалентны.
  • comment - Добавляет комментарий к правилу, не больше 256 символов, комментарий не имеет эффекта на пакет. Отметь что это не то же что и ferm комментарии ('#'), этот будет показан в "iptables -L".
    mod comment comment "This is my comment." ACCEPT;
    
    "mod comment" можно не писать, ferm добавить автоматически.
  • condition - Срабатывает если значение в /proc/net/ipt_condition/NAME равно 1 (путь для ip6 /proc/net/ip6t_condition/NAME).
    mod condition condition (abc def) ACCEPT;
    mod condition condition !foo ACCEPT;
    
  • connbytes - Сопоставляет как много байт или пакетов было передано соединением до текущего момента, или среднее bytes per packet.
    mod connbytes connbytes 65536: connbytes-dir both connbytes-mode bytes ACCEPT;
    mod connbytes connbytes !1024:2048 connbytes-dir reply connbytes-mode packets ACCEPT;
    
    Валидные значения для connbytes-dir: original, reply, both; для connbytes-mode: packets, bytes, avgpkt.
  • connlabel - Модуль для проверки или добавления connlabel к соединению.
    mod connlabel label "name";
    mod connlabel label "name" set;
    
  • connlimit - Позволяет тебе ограничивать количество параллельных TCP соединений к серверу по клиентскому IP адресу (или блоку адресов).
    mod connlimit connlimit-above 4 REJECT;
    mod connlimit connlimit-above !4 ACCEPT;
    mod connlimit connlimit-above 4 connlimit-mask 24 REJECT;
    mod connlimit connlimit-upto 4 connlimit-saddr REJECT;
    mod connlimit connlimit-above 4 connlimit-daddr REJECT;
    
  • connmark - Проверка метки связанной с этим соединением, установленной CONNMARK'ом.
    mod connmark mark 64;
    mod connmark mark 6/7;
    
  • conntrack - Проверка информации от механизма определения состояния соединения.
    mod conntrack ctstate (ESTABLISHED RELATED);
    mod conntrack ctproto tcp;
    mod conntrack ctorigsrc 192.168.0.2;
    mod conntrack ctorigdst 1.2.3.0/24;
    mod conntrack ctorigsrcport 67;
    mod conntrack ctorigdstport 22;
    mod conntrack ctreplsrc 2.3.4.5;
    mod conntrack ctrepldst ! 3.4.5.6;
    mod conntrack ctstatus ASSURED;
    mod conntrack ctexpire 60;
    mod conntrack ctexpire 180:240;
    
    Введи "iptables -m conntrack -h" для справки.
  • cpu - Сопоставление CPU обрабатывающего это соединение.
    mod cpu cpu 0;
    
  • dccp - Проверка атрибутов специфичных для DCCP (Datagram Congestion Control Protocol). Этот модуль автоматически подгружается когда ты используешь "protocol dccp".
    proto dccp sport 1234 dport 2345 ACCEPT;
    proto dccp dccp-types (SYNCACK ACK) ACCEPT;
    proto dccp dccp-types !REQUEST DROP;
    proto dccp dccp-option 2 ACCEPT;
    
  • dscp - Сопоставление 6-битного DSCP поля с TOS полем.
    mod dscp dscp 11;
    mod dscp dscp-class AF41;
    
  • dst - Сравнение параметров в заголовке Destination Options (IPv6).
    mod dst dst-len 10;
    mod dst dst-opts (type1 type2 ...);
    
  • ecn - Сравнение ECN битов IPv4 TCP заголовков.
    mod ecn ecn-tcp-cwr;
    mod ecn ecn-tcp-ece;
    mod ecn ecn-ip-ect 2;
    
    Набери "iptables -m ecn -h" для подробной информации.
  • esp - Сравнение SPI заголовка в ESP пакете.
    mod esp espspi 0x101;
    mod esp espspi ! 0x200:0x2ff;
    
  • eui64 - "Этот модуль матчит EUI-64 часть автонастраиваемого IPv6 адреса без сохранения состояния. Он сравнивает EUI-64 полученный из MAC адреса в Ethernet фрейме с наименьшими 64 битами исходящего IPv6 адреса. Но "Universal/Local" биты не сравниваются. Этот модуль не проверяет другие фреймы канального уровня, а только валидные в PREROUTING, INPUT и FORWARD цепочках."
    mod eui64 ACCEPT;
    
  • fuzzy - "Этот модуль матчит пакеты которые входят в ограничение скорости основываясь на FLC."
    mod fuzzy lower-limit 10 upper-limit 20 ACCEPT;
    
  • geoip - Матчит пакеты основываясь на их геопозиции. (Нужно установить GeoDB.)
    mod geoip src-cc "CN,VN,KR,BH,BR,AR,TR,IN,HK" REJECT;
    mod geoip dst-cc "DE,FR,CH,AT" ACCEPT;
    
  • hbh - Матчит заголовок параметров Hop-by-Hop (ip6).
    mod hbh hbh-len 8 ACCEPT;
    mod hbh hbh-len !8 ACCEPT;
    mod hbh hbh-opts (1:4 2:8) ACCEPT;
    
  • hl - Матчит поле Hop Limit (ip6).
    mod hl hl-eq (8 10) ACCEPT;
    mod hl hl-eq !5 ACCEPT;
    mod hl hl-gt 15 ACCEPT;
    mod hl hl-lt 2 ACCEPT;
    
  • helper - Проверяет какой именно conntrack хелпер затрекал это соединение. Порт может быть указан через "-portnr".
    mod helper helper irc ACCEPT;
    mod helper helper ftp-21 ACCEPT;
    
  • icmp - Проверяет специфичные для ICMP аттрибуты. Этот модуль автоматически подгружается когда ты используешь "protocol icmp".
    proto icmp icmp-type echo-request ACCEPT;
    
    Эта опция может быть использована в ip6 домене, несмотря на то что в ip6tables она называется icmpv6.
    Используй "iptables -p icmp -h" чтобы получить список валидных ICMP типов.
  • iprange - Матчит диапазон IPv4 адресов.
    mod iprange src-range 192.168.2.0-192.168.3.255;
    mod iprange dst-range ! 192.168.6.0-192.168.6.255;
    
  • ipv4options - Проверяет в IPv4 заголовках такие опции как source routing, record route, timestamp and router-alert.
    mod ipv4options ssrr ACCEPT;
    mod ipv4options lsrr ACCEPT;
    mod ipv4options no-srr ACCEPT;
    mod ipv4options !rr ACCEPT;
    mod ipv4options !ts ACCEPT;
    mod ipv4options !ra ACCEPT;
    mod ipv4options !any-opt ACCEPT;
    
  • ip6header - Матчит заголовки расширений IPv6 (ip6).
    mod ipv6header header !(hop frag) ACCEPT;
    mod ipv6header header (auth dst) ACCEPT;
    
  • hashlimit - Похоже на 'mod limit', но добавляет способность добавления per-destination или per-port ограничений управляемых через hash таблицу.
    mod hashlimit  hashlimit 10/minute  hashlimit-burst 30/minute
      hashlimit-mode dstip  hashlimit-name foobar  ACCEPT;
    
    Возможные значения для hashlimit-mode: dstip dstport srcip srcport (или список нескольких из этих значений).
    Здесь больше возможных настроек, набери "iptables -m hashlimit -h" для просмотра документации.
  • ipvs - Сравнивает свойства IPVS подключения.
    mod ipvs ipvs ACCEPT; # packet belongs to an IPVS connection
    mod ipvs vproto tcp ACCEPT; # VIP protocol to match; by number or name, e.g. "tcp
    mod ipvs vaddr 1.2.3.4/24 ACCEPT; # VIP address to match
    mod ipvs vport http ACCEPT; # VIP port to match
    mod ipvs vdir ORIGINAL ACCEPT; # flow direction of packet
    mod ipvs vmethod GATE ACCEPT; # IPVS forwarding method used
    mod ipvs vportctl 80; # VIP port of the controlling connection to match
    
  • length - Проверяет длину пакета.
    mod length length 128; # exactly 128 bytes
    mod length length 512:768; # range
    mod length length ! 256; # negated
    
  • limit - Ограничивает скорость пакетов.
    mod limit limit 1/second;
    mod limit limit 15/minute limit-burst 10;
    
    Введи "iptables -m limit -h" для справки.
  • mac - Сравнивает исходящий MAC адрес.
    mod mac mac-source 01:23:45:67:89;
    
  • mark - Матчит пакеты основываясь на отметках netfilter mark. Здесь может быть 32 битное целое число между 0 и 4294967295.
    mod mark mark 42;
    
  • mh - Матчит заголовки мобильности (ip6).
    proto mh mh-type binding-update ACCEPT;
    
  • multiport - Матчит по набору исходящих или конечных портов (только UDP и TCP).
    mod multiport source-ports (https ftp);
    mod multiport destination-ports (mysql domain);
    
    Это правило имеет большое преимущество над "dport" и "sport": оно генерирует только одно правило для вплоть до 15 портов вместо одного правила на каждый порт.
    Как сокращение ты можешь использовать "sports" и "dports" (без "mod multiport"):
    sports (https ftp);
    dports (mysql domain);
    
  • nth - Матчит каждый n-ный пакет.
    mod nth every 3;
    mod nth counter 5 every 2;
    mod nth start 2 every 3;
    mod nth start 5 packet 2 every 6;
    
    Введи "iptables -m nth -h" для справки.
  • osf - Матчит пакеты в зависимости от ОС отправителя.
    mod osf genre Linux;
    mod osf ! genre FreeBSD ttl 1 log 1;
    
    Введи "iptables -m osf -h" для справки.
  • owner - Проверяет информацию о создателе пакета, а именно user id, group id, process id, session id и command name.
    mod owner uid-owner 0;
    mod owner gid-owner 1000;
    mod owner pid-owner 5432;
    mod owner sid-owner 6543;
    mod owner cmd-owner "sendmail";
    
    ("cmd-owner", "pid-owner" and "sid-owner" требуют специальных патчей для ядра, которые не включены в обычную поставку ядра Linux)
  • physdev - Матчит пакеты по девайсу с/на которые пакет пришел/ушел. Это полезно для bridge-интерфейсов.
    mod physdev physdev-in ppp1;
    mod physdev physdev-out eth2;
    mod physdev physdev-is-in;
    mod physdev physdev-is-out;
    mod physdev physdev-is-bridged;
    
  • pkttype - Проверяет тип пакета канального уровня.
    mod pkttype pkt-type unicast;
    mod pkttype pkt-type broadcast;
    mod pkttype pkt-type multicast;
    
  • policy - Проверяет IPsec политику которая была применена к пакету.
    mod policy dir out pol ipsec ACCEPT;
    mod policy strict reqid 23 spi 0x10 proto ah ACCEPT;
    mod policy mode tunnel tunnel-src 192.168.1.2 ACCEPT;
    mod policy mode tunnel tunnel-dst 192.168.2.1 ACCEPT;
    mod policy strict next reqid 24 spi 0x11 ACCEPT;
    
    Заметь что ключевое слово proto также используется как сокращенная версия для protocol (встроенные match module). Ты можешь исправить этот конфликт используя всегда длинное ключевое слово protocol.
  • psd - Детектит TCP/UDP скан портов.
    mod psd psd-weight-threshold 21 psd-delay-threshold 300
      psd-lo-ports-weight 3 psd-hi-ports-weight 1 DROP;
    
  • quota - Реализует сетевые квоты уменьшая счетчик байтов с каждым пакетом.
    mod quota quota 65536 ACCEPT;
    
  • random - Матчит случайный процент всех пакетов.
    mod random average 70;
    
  • realm - Матчит области маршрутизации. Полезно в окружениях использующих BGP.
    mod realm realm 3;
    
  • recent - Временно отмечат исходящие IP адреса.
    mod recent set;
    mod recent rcheck seconds 60;
    mod recent set rsource name "badguy";
    mod recent set rdest;
    mod recent rcheck rsource name "badguy" seconds 60;
    mod recent update seconds 120 hitcount 3 rttl;
    mod recent mask 255.255.255.0 reap;
    
    Этот модуль имеет конструкционный недостаток: несмотря на то что он реализован как match module, он имеет target-like поведение когда используется ключевое слово "set".
    http://snowman.net/projects/ipt_recent/
  • rpfilter - Проверяет, что ответ на пакет будет отправлен через тот же интерфейс, с которого он прибыл. Пакеты из loopback интерфейса всегда ограничиваются.
    mod rpfilter proto tcp loose RETURN;
    mod rpfilter validmark accept-local RETURN;
    mod rpfilter invert DROP;
    
    Этот модуль является предпочтительным способом выполнения фильтрации обратного пути для IPv6 и мощной альтернативой проверкам, контролируемым через sysctl net.ipv4.conf.*.rp_filter.
  • rt - Матчит IPv6 роутинг заголовки (ip6).
    mod rt rt-type 2 rt-len 20 ACCEPT;
    mod rt rt-type !2 rt-len !20 ACCEPT;
    mod rt rt-segsleft 2:3 ACCEPT;
    mod rt rt-segsleft !4:5 ACCEPT;
    mod rt rt-0-res rt-0-addrs (::1 ::2) rt-0-not-strict ACCEPT;
    
  • sctp - Проверят специфичные для SCTP (Stream Control Transmission Protocol) аттрибуты. Этот модуль автоматически подгружается когда ты используешь "protocol sctp".
    proto sctp sport 1234 dport 2345 ACCEPT;
    proto sctp chunk-types only DATA:Be ACCEPT;
    proto sctp chunk-types any (INIT INIT_ACK) ACCEPT;
    proto sctp chunk-types !all (HEARTBEAT) ACCEPT;
    
    Используй "iptables -p sctp -h" чтобы показать список валидных типов.
  • set - Сравнивает исходящий или конечный IP/Port/MAC с указанным набором.
    mod set set badguys src DROP;
    
    Смотри http://ipset.netfilter.org/ для большей информации.
  • state - Проверяет состояние соединения.
    mod state state INVALID DROP;
    mod state state (ESTABLISHED RELATED) ACCEPT;
    
    Введи "iptables -m state -h" для справки.
  • statistic - Преемник nth и random, на данный момент недокументирован в iptables(8) man page.
    mod statistic mode random probability 0.8 ACCEPT;
    mod statistic mode nth every 5 packet 0 DROP;
    
  • string - Сравнивает строку.
    mod string string "foo bar" ACCEPT;
    mod string algo kmp from 64 to 128 hex-string "deadbeef" ACCEPT;
    
  • tcp - Проверяет специфичные для TCP аттрибуты. Этот модуль автоматически подгружается когда ты используешь "protocol tcp".
    proto tcp sport 1234;
    proto tcp dport 2345;
    proto tcp tcp-flags (SYN ACK) SYN;
    proto tcp tcp-flags ! (SYN ACK) SYN;
    proto tcp tcp-flags ALL (RST ACK);
    proto tcp syn;
    proto tcp tcp-option 2;
    proto tcp mss 512;
    
    Набери "iptables -p tcp -h" для справки.
  • tcpmss - Проверяет поле TCP MSS в SYN или SYN/ACK пакетах.
    mod tcpmss mss 123 ACCEPT;
    mod tcpmss mss 234:567 ACCEPT;
    
  • time - Сравнивает время поступления пакета с указанными диапазонами.
    mod time timestart 12:00;
    mod time timestop 13:30;
    mod time timestart 22:00 timestop 07:00 contiguous;
    mod time days (Mon Wed Fri);
    mod time datestart 2005:01:01;
    mod time datestart 2005:01:01:23:59:59;
    mod time datestop 2005:04:01;
    mod time monthday (30 31);
    mod time weekdays (Wed Thu);
    mod time timestart 12:00;
    mod time timestart 12:00 kerneltz;
    
    Набери "iptables -m time -h" для справки.
  • tos - Матчит пакеты по указанному TOS значению.
    mod tos tos Minimize-Cost ACCEPT;
    mod tos tos !Normal-Service ACCEPT;
    
    Набери "iptables -m tos -h" для справки.
  • ttl - Матчит по TTL (time to live) полю в IP заголовке.
    mod ttl ttl-eq 12; # ttl equals
    mod ttl ttl-gt 10; # ttl greater than
    mod ttl ttl-lt 16; # ttl less than
    
  • u32 - Сравнивает сырые данные из пакета. Ты можешь указать больше чем один фильтр через список; они не развернутся в множество правил.
    mod u32 u32 '6&0xFF=1' ACCEPT;
    mod u32 u32 ('27&0x8f=7' '31=0x527c4833') DROP;
    
  • unclean - Матчит пакеты которые выглядят как бесформенные или необычные. Эта проверка не имеет дополнительных параметров.

iptables target modules

Следующие дополнительные цели доступны в ferm, при условии что ты включил их в своем ядре:

  • CHECKSUM - Считает чек-сумму пакета.
    CHECKSUM checksum-fill;
    
  • CLASSIFY - Устанавливат CBQ класс.
    CLASSIFY set-class 3:50;
    
  • CLUSTERIP - Конфигурирует простой кластер нод которые делят определенный IP и MAC адрес. Соединение статически доставляется между нодами.
    CLUSTERIP new hashmode sourceip clustermac 00:12:34:45:67:89
      total-nodes 4 local-node 2 hash-init 12345;
    
  • CONNMARK - Устанавливает netfilter отметки связанные с этим соединением.
    CONNMARK set-xmark 42/0xff;
    CONNMARK set-mark 42;
    CONNMARK save-mark;
    CONNMARK restore-mark;
    CONNMARK save-mark nfmask 0xff ctmask 0xff;
    CONNMARK save-mark mask 0x7fff;
    CONNMARK restore-mark mask 0x8000;
    CONNMARK and-mark 0x7;
    CONNMARK or-mark 0x4;
    CONNMARK xor-mark 0x7;
    CONNMARK and-mark 0x7;
    
  • CONNSECMARK - Этот модуль копирует маркировки безопасности из пакета на соединение (если не помечено), и из соединения возвращает пакеты (также, только если не помечены). Обычно используется в связи с SECMARK, он доступен только для таблицы mangle.
    CONNSECMARK save;
    CONNSECMARK restore;
    
  • DNAT to [ip-address|ip-range|ip-port-range] - Изменяет адрес назначения пакета.
    DNAT to 10.0.0.4;
    DNAT to 10.0.0.4:80;
    DNAT to 10.0.0.4:1024-2048;
    DNAT to 10.0.1.1-10.0.1.20;
    
  • DNPT - Предоставляет IPv6-to-IPv6 Трансляцию Сетевых Префиксов без сохранения состояния назначения.
    DNPT src-pfx 2001:42::/16 dst-pfx 2002:42::/16;
    
  • ECN - Позволяет выборочно работать вокруг известных черных дыр ECN. Доступно только в таблице mangle.
    ECN ecn-tcp-remove;
    
  • HL - Изменяет поле IPv6 Hop Limit (ip6/mangle).
    HL hl-set 5;
    HL hl-dec 2;
    HL hl-inc 1;
    
  • HMARK - Как MARK, т.е. устанавливает fwmark, но метка вычисляется из селектора пакетов хэширования по выбору.
    HMARK hmark-tuple "src" hmark-mod "1" hmark-offset "1"
      hmark-src-prefix 192.168.1.0/24 hmark-dst-prefix 192.168.2.0/24
      hmark-sport-mask 0x1234 hmark-dport-mask 0x2345
      hmark-spi-mask 0xdeadbeef hmark-proto-mask 0x42 hmark-rnd 0xcoffee;
    
  • IDLETIMER - Может быть использовано для идентификации когда интерфейс проставивает в определенный период времени.
    IDLETIMER timeout 60 label "foo";
    
  • IPV4OPTSSTRIP - Очищает все IP опции с пакета. Модуль не имеет опций.
    IPV4OPTSSTRIP;
    
  • JOOL - Передает пакеты для стэйтфул NAT64 трансляции через JOOL. JOOL должен быть установлен в системе и модуль ядра jool дожен быть загружен.
    JOOL instance "foo";
    
  • JOOL_SIIT - Передает пакеты для стэйтлес IP/ICMP трансляции (SIIT) через JOOL. JOOL должен быть установлен в системе и модуль ядра jool_siit дожен быть загружен.
    JOOL_SIIT instance "foo";
    
  • LED - Создает LED-триггер который может быть приаттачен к панели индикаторов, чтобы мигать или светить ими когда определенные пакеты проходят через систему.
    LED led-trigger-id "foo" led-delay 100 led-always-blink;
    
  • LOG - Логирует пакеты которые матчатся этим правилом в kernel log. Будь осторожен с лог флудингом. Отметь что это "non-terminating target", т.е. обход по правилам будет продолжен.
    LOG log-level warning log-prefix "Look at this: ";
    LOG log-tcp-sequence log-tcp-options;
    LOG log-ip-options;
    
  • MARK - Устанавливает netfilter маркировку для пакета (32 битное целое число между 0 и 4294967295):
    MARK set-mark 42;
    MARK set-xmark 7/3;
    MARK and-mark 31;
    MARK or-mark 1;
    MARK xor-mark 12;
    
  • MASQUERADE - Маскарадит заматченные пакеты. Опционально за ним следует порт или диапазон портов для iptables. Указывается как "123", "123-456" или "123:456". Параметр с диапазоном портов определяет через какие локальные порты должно проходить замаскараженое соединение.
    MASQUERADE;
    MASQUERADE to-ports 1234:2345;
    MASQUERADE to-ports 1234:2345 random;
    
  • MIRROR - Экспериментально/демонстрационная цель, которая меняет местами получателя и отправителя в IP заголовках.
    MIRROR;
    
  • NETMAP - Мапит целую сеть на другую сеть в nat таблице.
    NETMAP to 192.168.2.0/24;
    
  • NOTRACK - Отключает conntrack для всех пакетов которые матчатся этим правилом.
    proto tcp dport (135:139 445) NOTRACK;
    
  • RATEEST
    RATEEST rateest-name "foo" rateest-interval 60s rateest-ewmalog 100;
    
    proto tcp dport (135:139 445) NOTRACK;
    
  • NFLOG - Логирует пакеты по netlink; это наследник ULOG'a.
    NFLOG nflog-group 5 nflog-prefix "Look at this: ";
    NFLOG nflog-range 256;
    NFLOG nflog-threshold 10;
    
  • NFQUEUE - Очерединг, требует поддержку ядром nfnetlink_queue.
    proto tcp dport ftp NFQUEUE queue-num 20;
    
  • QUEUE - Очерединг, предок NFQUEUE. Все пакеты уходят в очередь 0.
    proto tcp dport ftp QUEUE;
    
  • REDIRECT to-ports [ports] - Прозрачное проксирование: изменяет IP назначения пакета на свой.
    proto tcp dport http REDIRECT to-ports 3128;
    proto tcp dport http REDIRECT to-ports 3128 random;
    
  • SAME - Похоже на SNAT, но клиент мапится на один и тот же исходящий IP для всех его подключений.
    SAME to 1.2.3.4-1.2.3.7;
    SAME to 1.2.3.8-1.2.3.15 nodst;
    SAME to 1.2.3.16-1.2.3.31 random;
    
  • SECMARK - Используется для маркирования пакета для подсистемы безопасности такой как SELinux. Это работает только в таблице mangle.
    SECMARK selctx "system_u:object_r:httpd_packet_t:s0";
    
  • SET [add-set|del-set] [setname] [flag(s)] - Добавляет IP в специальный список. См. http://ipset.netfilter.org/
    proto icmp icmp-type echo-request SET add-set badguys src;
    SET add-set "foo" timeout 60 exist;
    
  • SNAT to [ip-address|ip-range|ip-port-range] - Изменяет исходящий адрес пакета.
    SNAT to 1.2.3.4;
    SNAT to 1.2.3.4:20000-30000;
    SNAT to 1.2.3.4 random;
    
  • SNPT - Предоставляет IPv6-to-IPv6 трансляцию исходящих сетевых префиксов без сохранения состояния.
    SNPT src-pfx 2001:42::/16 dst-pfx 2002:42::/16;
    
  • SYNPROXY - Проксирование тройного рукопожатия в TCP: пусть файерволл обрабатывает тройное рукопожатие TCP и устанавливает соединение с сокетом сервера единожды для тех клиентов которые прошли стадию рукопожатия.
    SYNPROXY wscale 7 mss 1460 timestamp sack-perm
    
  • TCPMSS - Подменяет MSS значение в TCP SYN пакетах.
    TCPMSS set-mss 1400;
    TCPMSS clamp-mss-to-pmtu;
    
  • TCPOPTSTRIP - Лишает TCP пакет его TCP опций.
    TCPOPTSTRIP strip-options (option1 option2 ...);
    
  • TOS set-tos [value] - Устанавлиет TCP Type Of Service в указанное значение. Это будет использоваться любым планировщиком трафика, который захочет, в основном вашей собственной Linux-машиной, но, возможно, и больше. Оригинальные TOS-биты очищаются и перезаписываются.
    TOS set-tos Maximize-Throughput;
    TOS and-tos 7;
    TOS or-tos 1;
    TOS xor-tos 4;
    
    Введи "iptables -j TOS -h" для справки.
  • TTL - Изменяет заголовок TTL.
    TTL ttl-set 16;
    TTL ttl-dec 1; # decrease by 1
    TTL ttl-inc 4; # increase by 4
    
  • ULOG - Логирует пакеты пользовательской программой.
    ULOG ulog-nlgroup 5 ulog-prefix "Look at this: ";
    ULOG ulog-cprange 256;
    ULOG ulog-qthreshold 10;
    

ДРУГИЕ ДОМЕНЫ

Начиная с версии 2.0, ferm поддерживает не только ip и ip6, но также arp (ARP таблицы) и eb (ethernet bridging таблицы). Эти концепции аналогичны iptables.

Ключевые слова arptables

  • source-ip, destination-ip - Матчат исходящие или конечные IPv4 адреса. Похоже на saddr и daddr в ip домене.
  • source-mac, destination-mac - Матчат исходящие или конечные MAC адреса.
  • interface, outerface - Входной или выходной интерфейс.
  • h-length - Аппаратная длина пакета.
    chain INPUT h-length 64 ACCEPT;
    
  • opcode - Код операции, для справки смотри iptables(8).
    opcode 9 ACCEPT;
    
  • h-type - Аппаратный тип.
    h-type 1 ACCEPT;
    
  • proto-type - Тип протокола.
    proto-type 0x800 ACCEPT;
    
  • Mangling - Ключевые слова mangle-ip-s, mangle-ip-d, mangle-mac-s, mangle-mac-d, mangle-target могут быть использованы для изменения ARP. См. iptables(8) для справки.

Ключевые слова ebtables

  • proto - Матчит протокол которым создан этот фрейм, например IPv4 или PPP. Для просмотра списка, см. /etc/ethertypes.
  • interface, outerface - Физический входной или выходной интерфейс.
  • logical-in, logical-out - Логический bridge интерфейс.
  • saddr, daddr - Матчит исходный или конечный MAC адрес.
  • Match modules - Поддерживаются следующие модули: 802.3, arp, ip, mark_m, pkttype, stp, vlan, log.
  • Target extensions - Поддерживаются следующие расширения: arpreply, dnat, mark, redirect, snat.
    Пожалуйста отметь что здесь происходит конфликт между --mark из mark_m модуля и -j mark. Поскольку они оба сработают по ключевому слову mark, то мы решили эту проблему написанием имени цели в вернем регистре. Как и в других доменах. Следующий пример перезаписывает маркировку 1 на 2:
    mark 1 MARK 2;
    

ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ

Переменные

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

Чтобы указать переменную, напиши:

@def $DEV_INTERNET = eth0;
@def $PORTS = (http ftp);
@def $MORE_PORTS = ($PORTS 8080);

В настоящем ferm коде, переменные используются как параметры:

chain INPUT interface $DEV_INTERNET proto tcp dport $MORE_PORTS ACCEPT;

Заметь, что переменные могуть использоваться только в параметрах ("192.168.1.1", "http"); они не могут содержать ключевых слов как "proto" или "interface".

Переменные действительны только в текущем блоке:

@def $DEV_INTERNET = eth1;
chain INPUT {
    proto tcp {
        @def $DEV_INTERNET = ppp0;
        interface $DEV_INTERNET dport http ACCEPT;
    }
    interface $DEV_INTERNET DROP;
}

будет перобразован в:

chain INPUT {
    proto tcp {
        interface ppp0 dport http ACCEPT;
    }
    interface eth1 DROP;
}

"def $DEV_INTERNET = ppp0" валидно только в блоке "proto tcp"; родительский блок остается с "set $DEV_INTERNET = eth1".

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

Автоматические переменные

Некоторые переменные устанавливаются ferm'ом изнутри. Ferm скрипты могут использовать их просто как любые другие переменные.

  • $FILENAME - Имя конфигурационного файла относительно директории откуда был запущен ferm.
  • $FILEBNAME - Базовое имя конфигурационного файла.
  • $DIRNAME - Директория конфигурационного файла.
  • $DOMAIN - Текущий домен. Один из ip, ip6, arp, eb.
  • $TABLE - Текущая netfilter таблица.
  • $CHAIN - Текущая netfilter цепочка.
  • $LINE - Строка текущего скрипта. Это может быть использовано например так:
    @def &log($msg) = {
                 LOG log-prefix "rule=$msg:$LINE ";
    }
    .
    .
    .
    &log("log message");
    

Функции

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

@def &FOO() = proto (tcp udp) dport domain;
&FOO() ACCEPT;

@def &TCP_TUNNEL($port, $dest) = {
    table filter chain FORWARD interface ppp0 proto tcp dport $port daddr $dest outerface eth0 ACCEPT;
    table nat chain PREROUTING interface ppp0 proto tcp dport $port daddr 1.2.3.4 DNAT to $dest;
}

&TCP_TUNNEL(http, 192.168.1.33);
&TCP_TUNNEL(ftp, 192.168.1.30);
&TCP_TUNNEL((ssh smtp), 192.168.1.2);

Вызов функции, который содержит блок (как '{...}') должен быть последней командой в ferm правиле, например за ним должна следовать ';'. '$FOO()' не содержит блок и поэтому ты можешь написать 'ACCEPT' после ее вызова. Для обхода этого ты можешь реорганизовать ключевые слова:

@def &IPSEC() = { proto (esp ah); proto udp dport 500; }
chain INPUT ACCEPT &IPSEC();

Апострофы

С апострофами ты можешь использовать вывод внешних команд:

@def $DNSSERVERS = `grep nameserver /etc/resolv.conf | awk '{print $2}'`;
chain INPUT proto tcp saddr $DNSSERVERS ACCEPT;

Команды выполняются в shell (/bin/sh), просто как апострофы в Perl. Ferm не разворачивает никакие переменные в них.

Затем вывод помечается и сохраняется как ferm список (массив). Строки начинающиеся с '#' игнорируются; другие строки могут содержать любое количество значений разделенных пробелом.

Включения

Ключевое слово @include позволяет тебе включать внешние файлы:

@include 'vars.ferm';

Имя файла относительно к вызывающему файлу, например выражение выше включает /etc/ferm/vars.ferm когда включение происходит из /etc/ferm/ferm.conf.
Переменные и функции описанные во включенном файле остаются доступными в вызвавшем файле.

include работает в блоках:

chain INPUT {
    @include 'input.ferm';
}

Если ты укажешь директорию (с '/' на конце), все файлы из этой директории будут включены в алфавитном порядке:

@include 'ferm.d/';

Функция @glob может быть использована для разворачивания вайлдкардов:

@include @glob('*.include');

С пайп-символом на конце, ferm выполняет shell команду и парсит вывод:

@include "/root/generate_ferm_rules.sh $HOSTNAME|"

ferm прервется если код возврата не 0.

Условия

Ключевое слово @if предоставляет условное выражение:

@if $condition DROP;

Значение расценивается как true также как в Perl: ноль, пустой список, пустая строка это ложь, все остальное это истина. Примеры для истинных значений:

(a b); 1; 'foo'; (0 0)

Примеры для ложных значений:

(); 0; '0'; ''

Также здесь есть @else:

@if $condition DROP; @else REJECT;

Учитывай точку с запятой перед @else.

Можно использовать фигурные скобки перед @if и @else:

@if $condition {
    MARK set-mark 2;
    RETURN;
} @else {
    MARK set-mark 3;
}

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

Здесь нет @elsif, используй вместо этого @else @if.

Пример:

@def $have_ipv6 = `test -f /proc/net/ip6_tables_names && echo 1 || echo`;
@if $have_ipv6 {
    domain ip6 {
        # ....
    }
}

Хуки

Для запуска кастомных команд ты можешь устанавливать хуки:

@hook pre "echo 0 >/proc/sys/net/ipv4/conf/eth0/forwarding";
@hook post "echo 1 >/proc/sys/net/ipv4/conf/eth0/forwarding";
@hook flush "echo 0 >/proc/sys/net/ipv4/conf/eth0/forwarding";

Описанные команды выполняются используя shell. "pre" значит запустить команду до применения файерволл правил, а "post" значит запустить команду после. "flush" хук запускается после того как ferm зафлашит файерволл правила (опция --flush). Ты можешь установить любое количество хуков.

Встроенные функции

Здесь некоторые встроенные функции, которые ты можешь найти полезными.

@defined($name), @defined(&name)

Тестирует определена ли функция или переменная.

@def $a = 'foo';
@if @defined($a) good;
@if @not(@defined($a)) bad;
@if @defined(&funcname) good;

@eq(a,b)

Тестирует два значения на равенство. Например:

@if @eq($DOMAIN, ip6) DROP;

@ne(a,b)

Похоже на @eq, оно тестирует на неравенство.

@not(x)

Инвертирует логическое значение.

@resolve((hostname1 hostname2 ...), [type])

Обычно, хостнэймы резолвятся iptables'ом. Чтобы позволить ferm'у резолвить хостнэймы, используй функцию @resolve:

saddr @resolve(my.host.foo) proto tcp dport ssh ACCEPT;
saddr @resolve((another.host.foo third.host.foo)) proto tcp dport openvpn ACCEPT;
daddr @resolve(ipv6.google.com, AAAA) proto tcp dport http ACCEPT;

Отметь двойные скобки на второй строке: внутренняя пара создает список, в внешняя как разделитель параметров функции.

Второй параметр опционален и определяет тип DNS записи. По умолчанию это "A" для домена ip и "AAAA" для домена ip6.

Будь аккуратен с зарезолвленными хостнэймами в конфигурации файерволла. DNS запросы могут блокировать конфигурирование файерволла на долгое время, оставляя машину уязвимой, или они могут фэйлиться.

@cat(a, b, ...)

Конкатенирует все параметры в одну строку.

@join(separator, a, b, ...)

Объединяет все параметры в одну строку разделяя указанным разделителем.

@substr(expression, offset, length)

Извлекает подстроку из выражения и возвращает ее. Первый символ имеет отступ 0. Если OFFSET отрицательный, то отсчитывается настолько же далеко от конца строки.

@length(expression)

Возвращает длину выражения в символах.

@basename(path)

Возвращает базовое имя файла для указанного пути (File::Spec::splitpath).

@dirname(path)

Возвращает имя последней директории для указанного пути, предполагая что последний компонент это имя файла (File::Spec::splitpath).

@glob(path)

Разворачивает shell wildcard'ы в указанных путях (предполагается что они относительны к текущему скрипту). Возвращает список заматченных файлов. Эта функция полезна как параметр для @include.

@ipfilter(list)

Отфильтровывает IP адреса которые, очевидно, не подходят под текущий домен. Это полезно для создания общих переменных и правил для IPv4 и IPv6:

@def $TRUSTED_HOSTS = (192.168.0.40 2001:abcd:ef::40);

domain (ip ip6) chain INPUT {
    saddr @ipfilter($TRUSTED_HOSTS) proto tcp dport ssh ACCEPT;
}

РЕЦЕПТЫ

Директория ./examples/ содержит многочисленные ferm конфигурации, которые могут быть использованы для начала в новом файерволле. Эта секция содержит много примеров, рецептов и трюков.

Легкий проброс портов

Ferm функции делают рутинные задачи быстрыми и легкими:

@def &FORWARD_TCP($proto, $port, $dest) = {
    table filter chain FORWARD interface $DEV_WORLD outerface $DEV_DMZ daddr $dest proto $proto dport $port ACCEPT;
    table nat chain PREROUTING interface $DEV_WORLD daddr $HOST_STATIC proto $proto dport $port DNAT to $dest;
}

&FORWARD_TCP(tcp, http, 192.168.1.2);
&FORWARD_TCP(tcp, smtp, 192.168.1.3);
&FORWARD_TCP((tcp udp), domain, 192.168.1.4);

Удаленный ferm

Если удаленная машина не способна запустить ferm по каким-то причинам (может быть не имеется Perl), то ты можешь редактировать конфигурационный файл ferm на другом компьютере и дать ferm'у сгенерировать shell скрипт.

Пример для OpenWRT:

ferm --remote --shell mywrt/ferm.conf >mywrt/firewall.user
chmod +x mywrt/firewall.user
scp mywrt/firewall.user mywrt.local.net:/etc/
ssh mywrt.local.net /etc/firewall.user

ОПЦИИ

  • --noexec - Не выполнят iptables(8) команды, а пропускать их. С помощью этого ты можешь парсить свои данные, используй --lines для отображения вывода.
  • --flush - Очистить файерволл правила и установить политики всех цепочек в ACCEPT. ferm'у потребуется конфигурационный файл чтобы понять какие домены и таблицы пострадают.
  • --lines - Отображать строки которые были сгенерированы из правил. Они будут показаны перед тем как будут исполнены, поэтому если ты получишь сообщение об ошибке из iptables(8) итд, то ты сможешь увидеть какое правило вызвало ошибку.
  • --interactive - Применять правила и спрашивать подтверждение у пользователя. Отменяет предыдущий набор правил если не было пользовательского ответа в течение 30 секунд (см. ---timeout). Это полезно для удаленного администрирования файерволла: ты можешь тестировать правила без страха заблокировать себе доступ.
  • --timeout S - Если используется --interactive, то делает откат если в течение указанного количества секунд не было валидного пользовательского ответа. По умолчанию 30.
  • --help - Показывает краткий список доступных опций.
  • --version - Показывает номер версии программы.
  • --fast - Включает быстрый режим: ferm генерирует iptables-save(8) файл и устанавливает его через iptables-restore(8). Это намного быстрее, потому что по умолчанию ferm вызывает iptables(8) по одному разу на каждое правило.
    Быстрый режим включен по умолчанию начиная с ferm 2.0, и эта опция задепрекейчена.
  • --slow - Отключает быстрый режим, т.е. запускает iptables(8) для каждого правила и не использует iptables-restore(8).
  • --shell - Генерирует shell скрипт, который вызывает iptables-restore(8) и печатает. Заключает в себе --fast и --lines.
  • --remote - Генерирует правила для удаленной машины. Подразумевает --noexec и --lines. Может быть скомбинирован с --shell.
  • --domain {ip|ip6} - Обрабатывает только указанный домен и выбирает его как домен по умолчанию для правил где он не определен. Вывод ferm может быть пустым если домен не сконфигурирован во входном файле.
  • --def '$name=value' - Переопределяет переменные определенные в конфигрурационном файле.

СМОТРИ ТАКЖЕ

iptables(8)

ТРЕБОВАНИЯ

Операционная система

Linux 2.4 или новее, с поддержкой netfilter и всеми модулями которые используются твоими скриптами

Программное обеспечение

iptables и perl 5.6

БАГИ

Баги? Какие еще баги?
Если ты нашел баг, пожалуйста уведоми об этом на GitHub: https://github.com/MaxKellermann/ferm/issues

КОПИРАЙТ

Copyright 2001-2017 Max Kellermann max.kellermann@gmail.com, Auke Kok sofar@foo-projects.org and various other contributors.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

АВТОР

Max Kellermann max.kellermann@gmail.com, Auke Kok sofar@foo-projects.org