Соглашения об именах в nftables могли ввести вас в заблуждение, полагая, что эта функция не существует.
Из вики nftables:
route, который используется для перенаправления пакетов, если какое-либо соответствующее поле заголовка IP или метка пакета изменены. Если вы знакомы с iptables, этот тип цепочки обеспечивает эквивалентную семантику для таблицы mangle, но только для выходного хука (для других хуков используйте вместо этого фильтр типов). Это поддерживается семействами таблиц ip и ip6.
Делая все это из контейнера LXC, используя ядро Debian Stretch 4.9.0-4-amd64 #1 SMP Debian 4.9.65-3 (2017-12-03)
, я сделаю uid 1001 единственным пользователем, способным подключиться к Интернет (здесь общедоступный DNS Google с использованием TCP):
# ip route
default via 10.0.3.1 dev eth0
10.0.3.0/24 dev eth0 proto kernel scope link src 10.0.3.66
# pkill -9 dhclient
# ip route del default
# ip route add default via 10.0.3.2 dev eth0 # 10.0.3.2 doesn't exist, but a default route is required for the routing code to trigger the fwmark rule at all, else there's a direct "Network is unreachable" with no packet generated.
# ip route add default via 10.0.3.1 table 10
# ip rule add fwmark 1 table 10
Каноническое название mangle ниже можно найти здесь (или /usr /share /doc ...). -150 это значение NF_IP_PRI_MANGLE
# nft add table ip mangle
# nft 'add chain ip mangle output { type route hook output priority -150; }'
# nft add rule ip mangle output skuid 1001 counter mark set 1
# id
uid=0(root) gid=0(root) groups=0(root)
# nc -v -n -z 8.8.8.8 53 # will timeout on ARP request to 10.0.3.2
nc: connect to 8.8.8.8 port 53 (tcp) failed: No route to host
# su - test
$ id
uid=1001(test) gid=1001(test) groupes=1001(test)
$ nc -v -n -z 8.8.8.8 53
Connection to 8.8.8.8 53 port [tcp/*] succeeded!
Последнее замечание Есть комментарий об использовании сетевого пространства имен для упрощения конфигурации, и я могу только согласиться: было бы сложнее привести этот пример без контейнера (с собственным сетевым пространством имен). Также, например, если есть команда suid root, использующая сеть, в зависимости от того, как она работает, она может инициировать метку или маршрут или нет.
ОБНОВЛЕНИЕ: некоторые пакеты, инициированные соединением пользователя, больше не принадлежат пользователю. Это может произойти для последнего ACK
подтверждающего пакет FIN
в конце соединения, и чаще всего это происходит для пакетов RST
, когда соединение преждевременно прерывается. Эти пакеты не будут соответствовать владельцу, поэтому не получат оценку, не будут перенаправлены, и это может привести к тайм-ауту в конце передачи. Чтобы избежать этого, это должно сочетаться с другими функциями, такими как ct mark set mark
метки ct /mark set ct mark
(эквивалент iptables
CONNMARK
). Более подробная информация о марках conntrack и аналогичных проблемах iptables и их решениях:
знак nftables и знак контратаки
Netfilter Connmark
Iptables: сопоставление исходящего трафика с conntrack и владельцем. Работает со странными каплями
Можно ли заставить отражение fwmark в ответных пакетах произвольного TCP?
пакеты iptables без uid
Тайм-ауты произошли в предыдущем "успешном" тесте с nc
выше, но поскольку команда вернулась, она не была видна без захвата сети. Тайм-ауты произошли на стороне равноправного сервера. Чтобы решить эту проблему, сохраните те же команды маршрутизации, но замените приведенные выше правила nft:
# nft add table ip mangle
# nft 'add chain ip mangle output { type route hook output priority -150; }'
# nft flush chain ip mangle output
# nft add rule ip mangle output mark set ct mark counter
# nft add rule ip mangle output mark ne 0 counter accept
# nft add rule ip mangle output skuid 1001 counter mark set 1
# nft add rule ip mangle output ct mark set mark counter
counter
просто для отладки.