Короткий ответ
До nft flush ruleset снимите полный nft list ruleset в файл. Ищите policy drop, счётчики на drop-правилах, hook input/forward/output. Если крутится UFW — его цепочки ufw-*, правьте через ufw, не flush. Смена policy drop на accept «на минуту» оставляет дыру, если сессия оборвалась. Читайте counters: нулевые на вашем allow значат, что пакет не доходит до этой линии (другое правило выше или не тот hook).
Хост host.example (10.0.20.10).
Симптомы и как отличить
- UFW inactive, трафик всё равно drop — чистый nft/
iptables-nft; - UFW active — сначала UFW;
dmesg:nf_conntrack: table full, dropping packet;- SSH timeout при listen 22 — sshd vs filter.
| Hook | Когда |
|---|---|
| prerouting | DNAT, не filter accept |
| input | к локальным сокетам |
| forward | транзит (роутер/docker) |
| output | с самой машины |
Возможные причины
table inet filterpolicy drop без allow established.- Правило по
iifnameне тому NIC. - Только ip, клиент ipv6 (table ip vs inet).
- conntrack полный — drop новых.
- fail2ban nft set.
- Docker/ufw конфликт FORWARD.
- Админ сделал flush и потом частично восстановил.
Диагностика
sudo nft list ruleset
sudo nft list ruleset > /root/nft-$(date +%F).nft
systemctl is-active ufw nftables
sudo nft list tablesСчётчики (если rules с counter):
sudo nft list ruleset -a-a даёт handle — для nft delete rule … handle N.
Conntrack:
sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
sudo conntrack -C 2>/dev/null
dmesg -T | grep -i conntrack | tailТрассировка (осторожно на проде, коротко):
sudo nft add table inet diag
# не оставляйте trace надолгоПроще: tcpdump -ni ens3 port 5432 — пакеты на NIC есть? Если да, а сокет не принимает — filter/input. Если нет — маршрут/внешний FW.
Журнал nft log prefix:
journalctl -k | grep -i nft | tailРешение
Сценарий A. Нужен allow established + порт
Идея (если нет UFW, свой table): не копируйте вслепую, сверяйте с существующим:
ct state established,related accept
tcp dport 22 accept
tcp dport 5432 ip saddr 10.0.0.0/16 acceptВставка выше drop. Через nft insert rule inet filter input position 0 … только понимая position.
Сохраните:
sudo nft list ruleset > /etc/nftables.conf
sudo systemctl enable --now nftablesНа Ubuntu nftables.service грузит /etc/nftables.conf. Если UFW включён — не ведите второй параллельный filter.
Сценарий B. UFW + nft
Вернитесь в ufw. Ручные правки chain ufw-user-input перезапишутся ufw reload.
Сценарий C. conntrack full
sudo sysctl net.netfilter.nf_conntrack_max
# временное увеличение — после понимания, кто создаёт сессииИщите сканер, DNS amplification через NAT, слишком короткий timeout vs слишком длинный. Не max=10M «на всякий» без RAM.
Сценарий D. fail2ban set
sudo nft list set inet f2b-table addr-set-sshd 2>/dev/null
sudo fail2ban-client status sshdUnban свой IP, не flush всей таблицы.
Сценарий E. Нужен временный accept для теста
С консоли BMC, узкое правило source=ваш IP, не policy accept на input. Запишите revert в заявку.
Как читать counters и не спутать hook
Правило без counter не докажет hit. Для диагностики временно добавьте counter на drop и на allow порта, затем nft list ruleset. Рост drop при вашем nc = вы попали в это правило. Нулевой allow + нулевой drop = пакет не в этом hook (смотрите forward vs input).
Docker публикует DNAT в ip nat + filter forward. nft list table ip nat обязателен, если порт «открыт» в приложении внутри контейнера. UFW без DEFAULT_FORWARD_POLICY=ACCEPT и без правил docker режет published ports — это не баг sshd.
nf_conntrack_tcp_timeout_established по умолчанию дни; проблема чаще table full из-за коротких соединений (антискан, DNS). Смотрите conntrack -L | awk '{print $1}' | sort | uniq -c.
Сохранение /etc/nftables.conf без flush в начале файла при nft -f добавляет дубликаты правил. Типичный файл начинается с flush ruleset — на хосте с Docker это опасно. Либо UFW, либо свой набор с осторожным flush только своих table.
nft monitor trace включает трассировку каждого пакета — на 10G трафике это DoS самим собой. Для точечной проверки используйте meta nftrace set 1 на узком правиле source IP администратора, затем выключите.
IPv4-only table ip filter не видит IPv6. Dual-stack сервис слушает :: — клиент ходит в inet6, ваши ip-правила молчат, пакет принимается политикой другой table или наоборот drop в ip6. Всегда nft list tables целиком.
Состояние ct state invalid drop полезно, но ломает ASYMMETRIC routing. Если пакеты уходят одним путём, возвращаются другим — conntrack invalid. Это сеть, не «открыть порт».
Как проверить, что проблема устранена
sudo nft list ruleset | head
nc -vz 10.0.20.10 5432
ssh admin@10.0.20.10 true
sudo conntrack -CСчётчик allow-правила растёт при тесте. policy drop на input сохранён, если такова политика.
Если не помогло
- tcpdump пуст: апстрим, не nft.
- Только Docker:
iptables -t nat -L/nft nat, published ports. - Логи nft забили диск — journald + rate limit log rules.
Профилактика
- Один оркестратор FW: UFW или nftables.service + ansible.
- Бэкап ruleset в git.
- Мониторинг conntrack_count.
- Комментарии в правилах (
comment "pgsql lan").
FAQ
iptables-legacy vs nft?
iptables -V покажет nf_tables. Два стека сразу — классический способ «правило не сработало».
Чем inet лучше ip?
Один table для v4+v6. Не забудьте dport правила покрывают оба, если inet.
nft monitor?
Поток событий. Для учёбы, не круглосуточно без фильтра.
Можно ли policy accept на filter input в проде?
Только если есть явные drop и вы понимаете default. Secure-by-default — drop + allow.
Docker ставит свои chains при reboot
Да. Применяйте свои правила так, чтобы не конфликтовать, или документируйте порядок After=docker.