nftables (Русский)

From ArchWiki
Jump to navigation Jump to search

Состояние перевода: На этой странице представлен перевод статьи nftables. Дата последней синхронизации: 3 мая 2021. Вы можете помочь синхронизировать перевод, если в английской версии произошли изменения.

nftables — проект netfilter, разработанный для замены существующего фреймворка {ip,ip6,arp,eb}tables. Предоставляет новую систему фильтрации пакетов, пользовательскую утилиту ntf, а также слой совместимости с {ip,ip6}tables. nftables использует существующие хуки, отслеживание соединений, очереди в пространстве пользователя и подсистему логирования netfilter.

nftables состоит из трёх основных частей: низкоуровневая реализация в ядре, библиотека libnl, которая обеспечивает netlink-взаимодействие, и пользовательский фронтенд nftables. Ядро предоставляет интерфейс настройки netlink, а также занимается runtime-выполнением наборов правил. Библиотека libnl содержит низкоуровневые функции для взаимодействия с ядром. Фронтенд nftables — то, с чем пользователь взаимодействует утилитой nft.

Подробную информацию о nftables можно найти на вики-странице проекта.

Установка

Установите пакет nftables или git-версию nftables-gitAUR.

Совет: Большинство фронтендов iptables не предлагают прямой или косвенной поддержки nftables, хотя подобная возможность предусмотрена [1]. firewalld — единственный графический фронтенд со встроенной поддержкой как iptables, так и nftables [2].

Использование

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

Все правила должны создаваться или загружаться утилитой nft. Подробнее о работе с ней см. раздел #Настройка.

Текущий набор правил можно узнать командой:

# nft list ruleset

Простой межсетевой экран

В пакет nftables входит простая и надёжная конфигурация экрана, сохранённая в файле /etc/nftables.conf.

Служба nftables.service загрузит эти правила при запуске или включении.

Настройка

Утилита nft выполняет большую часть обработки правил перед передачей их ядру. Правила объединяются в цепочки, которые, в свою очередь, входят в состав таблиц. В последующих разделах описано создание и модифицирование этих структур.

Прочитать правила из файла можно с помощью опции -f/--file:

# nft --file имя-файла

Обратите внимание, что уже загруженные на этот момент правила не будут при этом автоматически стёрты.

Полный список команд можно найти в руководстве nft(8).

Таблицы

Таблицы содержат #Цепочки. В отличие от iptables, в nftables отсутствуют встроенные таблицы. Количество таблиц и их имена определяется пользователем. Тем не менее, каждая таблица имеет только одно семейство адресации и применяется к пакетам только этого семейства. Таблицы могут относиться к одному из пяти семейств.

семейство nftables утилита iptables
ip iptables
ip6 ip6tables
inet iptables и ip6tables
arp arptables
bridge ebtables

ip (т.е. IPv4) — семейство по умолчанию; используется, если семейство не было указано.

Семейство inet объединяет протоколы IPv4 и IPv6, что позволяет унифицировать семейства ip и ip6 и упростить создание правил.

Описание остальных семейств адресации вы найдёте в руководстве nft(8) § ADDRESS FAMILIES.

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

Создание таблицы

Добавить новую таблицу:

# nft add table семейство таблица

Просмотр таблиц

Вывести список таблиц:

# nft list tables

Просмотр цепочек и правил в таблице

Вывести цепочки и правила выбранной таблицы:

# nft list table семейство таблица

Например, чтобы вывести на экран правила таблицы my_table семейства inet, выполните команду:

# nft list table inet my_table

Удаление таблицы

Удалить таблицу со всеми цепочками:

# nft delete table семейство таблица

Очистка таблицы

Стереть все правила в таблице:

# nft flush table семейство таблица

Цепочки

Цепочка содержит #Правила. В отличие от iptables, в nftables отсутствуют встроенные цепочки. Соответственно, если опрелённые типы или хуки фреймворка netfilter не задействованы ни в одной цепочке, то проходящие через эти цепочки пакеты обрабатываться не будут (в отличие от iptables).

Есть два типа цепочек. Базовая цепочка является точкой входа для пакетов из сетевого стека; в ней указывается хук. Обычная цепочка может использоваться в качестве цели перехода и используется для лучшей организации правил.

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

Создание цепочки

Обычная цепочка

Добавить обычную цепочку цепочка в таблицу таблица:

# nft add chain семейство таблица цепочка

Например, чтобы добавить обычную цепочку my_tcp_chain к таблице my_table семейства адресации inet, выполните:

# nft add chain inet my_table my_tcp_chain
Базовая цепочка

Чтобы добавить базовую цепочку, укажите хук и значение приоритета:

# nft add chain семейство таблица цепочка '{ type тип hook хук priority приоритет ; }'

тип может принимать значения filter, route или nat.

Для семейств адресации IPv4/IPv6/Inet хук может принимать значения prerouting, input, forward, output или postrouting. Описание других возможных хуков вы найдёте в руководстве nft(8) § ADDRESS FAMILIES.

Параметр приоритет задаётся названием приоритета или его численным значением (подробнее см. nft(8) § CHAINS). Цепочки с более низкими значениями обрабатываются раньше. Значение приоритета может быть отрицательным [3].

Например, добавим базовую цепочку для фильтрации входящих пакетов:

# nft add chain inet my_table my_chain '{ type filter hook input priority 0; }'

Если заменить команду add на create в любом из правил выше, то цепочка тоже будет создана, но если цепочка с таким названием уже существует, то вы получите сообщение об ошибке.

Просмотр правил

Следующая команда выводит на экран все правила в цепочке:

# nft list chain семейство таблица цепочка

Например, следующая команда выведет правила цепочки my_output таблицы my_table семейства inet:

# nft list chain inet my_table my_output

Изменение цепочки

Для редактирования цепочки укажите её название и правила, которые нужно изменить:

# nft chain семейство таблица цепочка '{ [ type тип hook хук device устройство priority приоритет ; policy политика ; ] }'

Например, для изменения политики обработки входящих пакетов цепочки исходной таблицы с accept на drop выполните команду:

# nft chain inet my_table my_input '{ policy drop ; }'

Удаление цепочки

Удалить цепочку:

# nft delete chain семейство таблица цепочка

Цепочка должна быть пустой (не содержащей правил) и не должна быть целью перехода из другой цепочки.

Очистка цепочки

Стереть все правила в цепочке:

# nft flush chain семейство таблица цепочка

Правила

Правила конструируются из выражений (expressions) и операторов (statements) и содержатся внутри цепочек.

Добавление правила

Совет: Утилита iptables-translate поможет преобразовать правила iptables в формат nftables.

Добавить правило в цепочку:

# nft add rule семейство таблица цепочка handle маркер оператор

Правило будет прикреплено после маркер, который можно не указывать. Если маркер (handle) не задать, то правило добавится в конец цепочки.

Чтобы добавить правило перед определённой позицией, выполните

# nft insert rule семейство таблица цепочка handle маркер оператор

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

Выражения

Обычно оператор включает некоторое выражение для сравнения и вынесения решения. Решениями могут быть accept, drop, queue, continue, return, jump цепочка и goto цепочка. Возможны и другие операторы помимо решений, подробнее смотрите nft(8).

В nftables доступен ряд выражений, по большей части совпадающий с аналогичными в iptables. Наиболее важное отличие заключается в том, что здесь нет обобщённых или неявных параметров. Обобщённый параметр (generic match) обычно доступен для всех правил, например, параметры --protocol или --source. Неявные правила (implicit matches) относятся к конкретному протоколу, как параметр --sport для пакетов TCP.

Ниже представлен неполный список возможных параметров:

  • meta (метасущности, напр. интерфейсы)
  • icmp (протокол ICMP)
  • icmpv6 (протокол ICMPv6)
  • ip (протокол IP)
  • ip6 (протокол IPv6)
  • tcp (протокол TCP)
  • udp (протокол UDP)
  • sctp (протокол SCTP)
  • ct (отслеживание соединений)

Ниже приведён неполный список аргументов для параметров (подробнее см. nft(8)):

meta:
  oif <интерфейс-отправитель НОМЕР>
  iif <интерфейс-получатель НОМЕР>
  oifname <интерфейс-отправитель ИМЯ>
  iifname <интерфейс-получатель ИМЯ>

  (параметры oif и iif принимают строковые значения, которые конвертируются в номер)
  (параметры oifname и iifname более гибкие, но они медленнее из-за необходимости выполнять сравнение строк)

icmp:
  type <тип icmp>

icmpv6:
  type <тип icmpv6>

ip:
  protocol <протокол>
  daddr <адрес получателя>
  saddr <адрес отправителя>

ip6:
  daddr <адрес получателя>
  saddr <адрес отправителя>

tcp:
  dport <порт получателя>
  sport <порт отправителя>

udp:
  dport <порт получателя>
  sport <порт отправителя>

sctp:
  dport <порт получателя>
  sport <порт отправителя>

ct:
  state <new | established | related | invalid>

Удаление

Отдельные правила могут быть удалены только с помощью маркера. Команда nft --handle list выведет список маркеров.

Ниже приведён пример правила с маркером и команда для его удаления. Аргумент --numeric позволяет выводить IP-адреса в численном виде.

# nft --handle --numeric list chain inet my_table my_input
table inet my_table {
     chain my_input {
          type filter hook input priority 0;
          ip saddr 127.0.0.1 accept # handle 10
     }
}
# nft delete rule inet my_table my_input handle 10

Стирание всех цепочек таблицы выполняется командой nft flush table. Отдельные цепочки могут быть стёрты командами nft flush chain или nft delete rule.

# nft flush table таблица
# nft flush chain семейство таблица цепочка
# nft delete rule семейство таблица цепочка

Первая команда стирает все цепочки в ip-таблице таблица. Вторая очищает цепочку цепочка в таблице таблица семейства семейство. Третья удаляет все правила в цепочке цепочка в таблице таблица семейства семейство.

Множества

Множества бывают именованные и анонимные. Множество объявляется фигурными скобками, в которых перечислены разделённые запятыми элементы. Анонимные множества "встраиваются" в правило и не могут быть изменены отдельно от него. Если множество необходимо модифицировать, то придётся удалить правило целиком и добавить его заново. Так, не получится удалить "http" из множества dport'ов в следующем правиле:

# nft add rule ip6 filter input tcp dport {telnet, http, https} accept

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

table ip sshguard {
       set attackers {
               type ipv4_addr
               flags interval
               elements = { 1.2.3.4 }
       }

Команды для добавления и удаления элементов из множества:

# nft add element ip sshguard attackers { 5.6.7.8/32 }
# nft delete element ip sshguard attackers { 1.2.3.4/32 }

Если множество имеет тип ipv4_addr, то помимо адреса можно указать маску сети (маска "/32" в примере не обязательна, но указана для большей ясности). Обращение к множеству из примера выше ("TABLE ip sshguard { SET attackers }") производится по имени ip sshguard attackers.

Полная перезагрузка правил

Создать файл для новых правил:

# echo "flush ruleset" > /tmp/nftables 

Сбросить дамп правил в новый файл:

# nft -s list ruleset >> /tmp/nftables

Теперь можно редактировать файл /tmp/nftables, создавая и изменяя правила. Применить изменения можно командой:

# nft -f /tmp/nftables

Примеры

Рабочая станция

/etc/nftables.conf
flush ruleset

table inet filter {
	chain input {
		type filter hook input priority 0; policy drop;

		iif lo accept comment "Accept any localhost traffic"
		ct state invalid drop comment "Drop invalid connections"
		ct state established,related accept comment "Accept traffic originated from us"

		meta l4proto ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept comment "Accept ICMPv6"
		meta l4proto icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept comment "Accept ICMP"
		ip protocol igmp accept comment "Accept IGMP"

		udp dport mdns ip6 daddr ff02::fb accept comment "Accept mDNS"
		udp dport mdns ip daddr 224.0.0.251 accept comment "Accept mDNS"

		udp sport 1900 udp dport >= 1024 ip6 saddr { fd00::/8, fe80::/10 } meta pkttype unicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"
		udp sport 1900 udp dport >= 1024 ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } meta pkttype unicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"

		udp sport netbios-ns udp dport >= 1024 meta pkttype unicast ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept Samba Workgroup browsing replies"
		udp sport netbios-ns udp dport >= 1024 meta pkttype unicast ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept Samba Workgroup browsing replies"

		counter comment "Count any other traffic"
	}

	chain forward {
		type filter hook forward priority 0; policy drop;
	}

	chain output {
		type filter hook output priority 0; policy accept;
	}

}

Сервер

/etc/nftables.conf
flush ruleset

table inet filter {
	chain input {
		type filter hook input priority 0; policy drop;

		iif lo accept comment "Accept any localhost traffic"
		ct state invalid drop comment "Drop invalid connections"
		ct state established,related accept comment "Accept traffic originated from us"

		meta l4proto ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept comment "Accept ICMPv6"
		meta l4proto icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept comment "Accept ICMP"
		ip protocol igmp accept comment "Accept IGMP"

		udp dport mdns ip6 daddr ff02::fb accept comment "Accept mDNS"
		udp dport mdns ip daddr 224.0.0.251 accept comment "Accept mDNS"

		tcp dport ssh accept comment "Accept SSH on port 22"

		tcp dport ipp accept comment "Accept IPP/IPPS on port 631"

		tcp dport { http, https, 8008, 8080 } accept comment "Accept HTTP (ports 80, 443, 8008, 8080)"

		meta l4proto { tcp, udp } th dport 2049 ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept NFS"
		meta l4proto { tcp, udp } th dport 2049 ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept NFS"

		udp dport netbios-ns ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept NetBIOS Name Service (nmbd)"
		udp dport netbios-ns ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept NetBIOS Name Service (nmbd)"
		udp dport netbios-dgm ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept NetBIOS Datagram Service (nmbd)"
		udp dport netbios-dgm ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept NetBIOS Datagram Service (nmbd)"
		tcp dport netbios-ssn ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept NetBIOS Session Service (smbd)"
		tcp dport netbios-ssn ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept NetBIOS Session Service (smbd)"
		tcp dport microsoft-ds ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept Microsoft Directory Service (smbd)"
		tcp dport microsoft-ds ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept Microsoft Directory Service (smbd)"

		udp sport bootpc udp dport bootps ip saddr 0.0.0.0 ip daddr 255.255.255.255 accept comment "Accept DHCPDISCOVER (for DHCP-Proxy)"
		udp sport { bootpc, 4011 } udp dport { bootps, 4011 } ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept PXE"
		udp dport tftp ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept TFTP"
		udp dport tftp ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept TFTP"

	}

	chain forward {
		type filter hook forward priority 0; policy drop;
	}

	chain output {
		type filter hook output priority 0; policy accept;
	}

}

Ограничение скорости передачи

table inet filter {
	chain input {
		type filter hook input priority 0; policy drop;

		iif lo accept comment "Accept any localhost traffic"
		ct state invalid drop comment "Drop invalid connections"

		meta l4proto icmp icmp type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
		meta l4proto ipv6-icmp icmpv6 type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"

		ct state established,related accept comment "Accept traffic originated from us"

		meta l4proto ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept comment "Accept ICMPv6"
		meta l4proto icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept comment "Accept ICMP"
		ip protocol igmp accept comment "Accept IGMP"

		tcp dport ssh ct state new limit rate 15/minute accept comment "Avoid brute force on SSH"

	}

}

Переход

Если вы используете переходы (jumps), то целевая цепочка должна быть описана до перехода. Иначе будет получена ошибка Error: Could not process rule: No such file or directory.

table inet filter {
    chain web {
        tcp dport http accept
        tcp dport 8080 accept
    }
    chain input {
        type filter hook input priority 0;
        ip saddr 10.0.2.0/24 jump web
        drop
    }
}

Несколько сетевых интерфейсов с разными правилами

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

table inet filter {
  chain input { # эта цепочка выступает в качестве диспетчера
    type filter hook input priority 0;

    iif lo accept # доступ к петлевому интерфейсу всегда разрешён
    iifname enp2s0 jump input_enp2s0
    iifname enp3s0 jump input_enp3s0

    reject with icmpx type port-unreachable # отклонить трафик от остальных интерфейсов
  }
  chain input_enp2s0 { # правила для публичного интерфейса
    ct state {established,related} accept
    ct state invalid drop
    udp dport bootpc accept
    tcp dport bootpc accept
    reject with icmpx type port-unreachable # весь остальной трафик
  }
  chain input_enp3s0 { # правила для веб-сервера на LAN-интерфейсе
    ct state {established,related} accept
    ct state invalid drop
    udp dport bootpc accept
    tcp dport bootpc accept
    tcp port http accept
    tcp port https accept
    reject with icmpx type port-unreachable # весь остальной трафик
  }
  chain ouput { # все исходящие пакеты - разрешены
    type filter hook output priority 0;
    accept
  }
}

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

Маскарадинг

В nftables есть специальное ключевое слово masquerade, "позволяющее автоматически изменять адрес источника на адрес интерфейса-отправителя" [4]. Это особенно удобно в ситуациях, когда IP-адрес интерфейса непредсказуем или нестабилен — например, исходящий интерфейс маршрутизатора, подключённого к нескольким интернет-провайдерам. Маскарадинг позволяет не переписывать правила межсетевого экрана для трансляции сетевых адресов (NAT) при каждом изменении IP-адреса интерфейса.

Правила работы маскарадинга:

  • опция masquerading в ядре Linux должна быть включена (в стандартном ядре она включена по умолчанию); в противном случае задайте параметр ядра CONFIG_NFT_MASQ=m.
  • ключевое слово masquerade может использоваться только в цепочке типа nat.
  • masquerading является подвидом SNAT, поэтому работает только для исходящих пакетов.

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

table inet nat {
  chain masquerade {
    type nat hook postrouting priority 100;
    oifname "enp2s0" masquerade
  }
}

Поскольку таблица выше относится к типу inet, то маскарадингу подвергаются пакеты и IPv4, и IPv6. Чтобы ограничить маскарадинг только IPv4-пакетами (т.к. у IPv6 большое пространство адресов и NAT не требуется) либо добавьте выражение meta nfproto ipv4 перед oifname "enp2s0" masquerade, либо измените тип таблицы на ip.

NAT с пробросом портов

Ниже приведён пример проброса портов 22 и 80 на адрес ip-адрес_получателя. Необходимо предварительно с помощью sysctl установить параметры net.ipv4.ip_forward и net.ipv4.conf.wan_интерфейс.forwarding на 1.

table ip nat {
  chain prerouting {
    type nat hook prerouting priority -100;

    tcp dport { ssh, http } dnat to ip-адрес_получателя
  }

  chain postrouting {
    type nat hook postrouting priority 100;

    ip daddr ip-адрес_получателя masquerade
  }
}

Счётчик новых соединений

Следующий сниппет позволяет считать открытые HTTPS-соединения:

/etc/nftables.conf
table inet filter {
    set https {
        type ipv4_addr;
        flags dynamic;
        size 65536;
        timeout 60m;
    }

    chain input {
        type filter hook input priority 0
        ct state new tcp dport 443 update @https { ip saddr counter }
    }
}

Текущее значение счётчика можно вывести командой nft list set inet filter https.

Динамическая блокировка

Следующий сниппет позволяет в течение минуты отклонять все HTTPS-соединения от адресов, которые превысили лимит в 10 запросов на соединение в секунду:

/etc/nftables.conf
table inet dev {
    set blackhole {
        type ipv4_addr;
        flags dynamic, timeout;
        size 65536;
    }

    chain input {
        ct state new tcp dport 443 \
                meter flood size 128000 { ip saddr timeout 10s limit rate over 10/second } \
                add @blackhole { ip saddr timeout 1m }

        ip saddr @blackhole counter drop
    }
}

Для вывода заблокированных адресов выполните nft list set inet dev blackhole.

Советы и рекомендации

Сохранение текущего набора правил

Вывод команды nft list ruleset можно использовать в качестве входных данных для других команд. Текущий набор правил можно сохранить в файл, а позже — загрузить их из него.

# nft -s list ruleset | tee название_файла
Примечание: Команда nft list не выводит определения переменных. Если в файле /etc/nftables.conf есть какие-либо переменные, то в выводе команды вы их не увидите — все переменные будут заменены на значения.

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

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

Одиночная машина

Сотрите текущий набор правил:

# nft flush ruleset

Добавьте таблицу:

# nft add table inet my_table

Добавьте базовые цепочки input, forward и output. Политика для входящих и пересылаемых пакетов должна быть drop. Политика для исходящих пакетов — accept.

# nft add chain inet my_table my_input '{ type filter hook input priority 0 ; policy drop ; }'
# nft add chain inet my_table my_forward '{ type filter hook forward priority 0 ; policy drop ; }'
# nft add chain inet my_table my_output '{ type filter hook output priority 0 ; policy accept ; }'

Добавьте две обычные цепочки, которые будут обрабатывать пакеты протоколов TCP и UDP:

# nft add chain inet my_table my_tcp_chain
# nft add chain inet my_table my_udp_chain

Разрешите related и established трафик:

# nft add rule inet my_table my_input ct state related,established accept

Разрешите трафик на петлевой интерфейс:

# nft add rule inet my_table my_input iif lo accept

Заблокируйте invalid трафик:

# nft add rule inet my_table my_input ct state invalid drop

Разрешите пакеты ICMP и IGMP:

# nft add rule inet my_table my_input meta l4proto ipv6-icmp icmpv6 type '{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report }' accept
# nft add rule inet my_table my_input meta l4proto icmp icmp type '{ destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem }' accept
# nft add rule inet my_table my_input ip protocol igmp accept

Новый UDP-трафик будет передаваться цепочке my_udp_chain:

# nft add rule inet my_table my_input meta l4proto udp ct state new jump my_udp_chain

Новый TCP-трафик будет передаваться цепочке my_tcp_chain:

# nft add rule inet my_table my_input 'meta l4proto tcp tcp flags & (fin|syn|rst|ack) == syn ct state new jump my_tcp_chain'

Заблокировать весь трафик, который не обрабатывается другими правилами:

# nft add rule inet my_table my_input meta l4proto udp reject
# nft add rule inet my_table my_input meta l4proto tcp reject with tcp reset
# nft add rule inet my_table my_input counter reject with icmpx type port-unreachable

В этом месте необходимо выбрать, какие порты будут оставаться открытыми для входящих соединений, обрабатываемых цепочками my_tcp_chain и my_udp_chain. Например, открыть соединения для веб-сервера:

# nft add rule inet my_table my_tcp_chain tcp dport 80 accept

Разрешить HTTPS-соединения для веб-сервера на порте 443:

# nft add rule inet my_table my_tcp_chain tcp dport 443 accept

Разрешить SSH-трафик на порт 22:

# nft add rule inet my_table my_tcp_chain tcp dport 22 accept

Разрешить входящие DNS-запросы:

# nft add rule inet my_table my_tcp_chain tcp dport 53 accept
# nft add rule inet my_table my_udp_chain udp dport 53 accept

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

Предотвращение атак перебором

Sshguard может обнаруживать атаки перебором и модифицировать сетевые экраны, временно помещая IP-адреса в чёрный список. Описание настройки nftables для работы с sshguard можно найти в статье Sshguard#nftables.

Журналирование трафика

Действие log позволяет вести журнал пакетов. Простейшее правило для сохранения информации обо всём поступающем трафике:

# nft add rule inet filter input log

Подробнее см. nftables wiki.

Решение проблем

Работа с Docker

nftables может создавать помехи сетевой работе контейнеров Docker (возможно, и другим средствам виртуализации тоже). В частности, политика drop цепочки forward блокирует пакеты, источником которых является docker. Если вы не хотите удалять эту цепочку, то сделайте следующее:

  1. Установите пакет iptables-nft; он содержит iptables-совместимый интерфейс nftables, который docker сможет использовать.
  2. Модифицируйте цепочку forward таблицы inet:
    chain forward {
      type filter hook forward priority security; policy drop;
      mark 1 accept
    }
    
  3. Добавьте цепочку DOCKER-USER в таблицу ip filter, чтобы помечать (mark) пакеты docker:
    table ip filter {
      chain DOCKER-USER {
        mark set 1
      }
    }
    

Теперь сгенерированные контейнером docker пакеты будут маркироваться и пересылаться дальше, поскольку docker уже их отфильтровал (цепочка forward в docker использует политику drop).

Смотрите также