nftables (Magyar)
Az nftables egy Netfilter projekt, amelynek célja a meglévő {ip,ip6,arp,eb}tables keretrendszer leváltása. Új csomagszűrő keretrendszert, egy új felhasználói térben futó segédprogramot (nft), valamint egy kompatibilitási réteget biztosít az {ip,ip6}tables számára. A netfilter meglévő automatikus műveletindítóit (hook-jait), kapcsolatkövető rendszerét, felhasználói térbeli várólista-komponensét és naplózási alrendszerét használja.
Három fő összetevőből áll: Egy kernelimplementációból, a libnl netlink kommunikációból és az nftables felhasználói térbeli előtétprogramból. A kernel egy netlink-beállítófelületet, valamint a szabálykészlet futásidejű kiértékelését biztosítja. A libnl a kernellel történő kommunikációhoz szükséges alacsony szintű függvényeket tartalmazza, az nftables előtétprogram pedig az a komponens, amellyel a felhasználó az nft segítségével kapcsolatba lép.
További információkért látogassa meg a hivatalos nftables wiki weboldalt.
Telepítés
Telepítse a felhasználói térben futtatható nftables segédprogram szoftvercsomagját.
Ha Önél fel van telepítve a számítógépre az iptables-legacy szoftvercsomag, akkor telepítse az iptables szoftvercsomagot, amely automatikusan eltávolítja az iptables-legacy szoftvercsomagot, és megakadályozza az nftables szoftvercsomaggal történő összeütközéseket.
iptables parancsok olyan implementációját biztosítja, amely ténylegesen létrehozza és végrehajtja az nftables szabályokat. Azonban a régi iptables-legacy segédprogramokkal létrehozott szabályok külön objektumok, és az iptables figyelmeztetni fogja Önt, amikor ezek jelen vannak a számítógépen.Frontend programok
- firewalld (firewall-cmd) — Szolgáltatás és parancssoros felhasználói felülettel is rendelkezik. Hálózati és tűzfalzónák beállítására, valamint a tűzfalszabályok megadására és azok beállítására szolgál.
- nft-blackhole — Szkriptfájl / szolgáltatásfájl az IP-címek nftables rendszerben történő blokkolására, országok és feketelisták alapján.
- ufw — Az ufw az Uncomplicated Firewall rövidítése, és egy netfilter alapú tűzfal kezelésére szolgáló program.
- reaction — Egy szolgáltatásfájl, amely a programok kimenetét vizsgálja ismétlődő minták után kutatva, és intézkedéseket tesz. A fail2ban könnyűsúlyú alternatívája.
Használat
Az nftables nem tesz különbséget a parancssorban létrehozott ideiglenes szabályok és a fájlból betöltött vagy fájlba mentett állandó szabályok között.
Minden szabályt az nft parancssori segédprogrammal kell létrehozni vagy betölteni a számítógép memóriájába.
A használattal kapcsolatban tekintse meg a #Beállítás című szakaszt.
A jelenlegi szabálykészlet a következőképpen jeleníthető meg:
# nft list ruleset
Az összes szabály eltávolítása, amely által a rendszer tűzfal nélkül fog maradni:
# nft flush ruleset
A szabálykészlet beolvasása a számítógép memóriájába a /etc/nftables.conf fájlból az nftables.service újraindításával történik.
Egyszerű tűzfal
Az nftables szoftvercsomag számítógépre történő feltelepítésekor egy egyszerű és biztonságos tűzfalbeállítással érkezik a számítógépre, amely a /etc/nftables.conf fájlban lesz eltárolva.
Tehát amikor az nftables.service el lesz indítva vagy engedélyezve lesz, a szabályokat az említett fájlból betölti a számítógép memóriájába.
Beállítás
Az nftables felhasználói térben lévő segédprogramja, az nft, a szabálykészletek nagy részének értékelését elvégzi, mielőtt a szabálykészleteket a kernelnek átadná. A szabályok láncokban vannak eltárolva, amelyek viszont táblákban vannak elhelyezve. A következő szakaszok bemutatják, hogy miként lehet létrehozni és módosítani ezeket a konstrukciókat.
A fájlból történő bemenet olvasása érdekében használja a -f/--file kapcsolót:
# nft --file fájlneve
Vegye figyelembe, hogy a már betöltött szabályok nem kerülnek automatikusan törlésre.
A teljes parancslistát megtekintheti az nft(8) man súgóban.
Táblák
A táblák tulajdonképpen tárolók a #Láncok, #Készletek és egyebek számára. Kizárólag ezek névterezésére, hatókörének meghatározására és rendszerezésére szolgálnak.
Nincsenek különleges vagy varázslatos táblanevek. Általában az programok a saját nevüket viselő táblákat hozzák létre (pl. a Firewalld létrehozza a firewalld táblát és csak a firewalld táblát módosítja), ezért érdemes lehet egy manuális úton, tehát kézzel létrehozandó táblát valami általános névvel ellátni, például firewall. (Itt egy példa).
Minden tábla többféle szabályt is tartalmazhat (pl. mind filter, mind nat), de kizárólag egyetlen családba tartozó csomagokra vonatkozik az alábbiak közül:
| nftables család | Egyenértékű iptables segédprogram |
|---|---|
ip (Ha kihagyjuk, akkor alapértelmezett.) |
iptables(8) |
ip6 |
ip6tables(8) |
inet |
Kombinált iptables(8) és ip6tables(8) |
arp |
arptables(8) |
bridge |
ebtables(8) |
Amennyiben Ön egy szabályt szeretne létrehozni, amely mind az IPv4 protokollra, mind az IPv6 protokollra vonatkozik, akkor használja az inet táblát. Az inet tábla lehetővé teszi az ip és az ip6 családok egyesítését, így egyszerűbbé téve a szabályok mindkettőre történő meghatározását.
Tekintse meg az nft(8) § ADDRESS FAMILIES man súgót a címcsoportok teljes leírásáért.
Alapvető parancsok
- Listing all tables
# nft list tables
- Adding a new table
# nft add table family_type table_name
create instead of add if you want the command to succeed even if the table already exists.- Listing all chains and rules of a table
# nft list table family_type table_name
For example, to list all the rules of the my_table table of the inet family:
# nft list table inet my_table
- Emptying a table (chains and rules)
# nft flush table family_type table_name
- Deleting a table
# nft delete table family_type table_name
destroy instead of delete if you want the command to succeed even if the table does not exist.Láncok
A chain is a collection of #Rules to be applied to packets.
Packets flow left to right in the traffic flow diagram; every time one reaches a "hook" (ingress, prerouting, input...), all "base" chains associated with that hook are processed.
(Thus, chains are implicitly ordered by hook type.)
The various properties and uses of chains, as well as how to manipulate them, are very well documented in the Configuring chains article on Netfilter's wiki.
Note however that the priority value of a chain orders it not only relative to other chains, but also relative to some of the kernel's processing, in particular connection tracking. The earlier a packet is dropped, the less work is wasted; but also, the less information about the packet is available.
Rules
Basics of rules' structure and related commands are described by Simple rule management on Netfilter's wiki.
Rules consist of expressions followed by statements.
The most common kind of statement is "verdict statements": accept, drop, queue, continue, return, jump chain_name, and goto chain_name. Other statements than verdict statements are possible; see nft(8) § STATEMENTS.
Expressions
There are various expressions available in nftables and, for the most part, coincide with their iptables counterparts. The most noticeable difference is that there are no generic or implicit matches. A generic match was one that was always available, such as --protocol or --source. Implicit matches were protocol-specific, such as --sport when a packet was determined to be TCP.
See also Building rules through expressions on the Netfilter wiki.
The following is an incomplete list of the matches available:
- meta (meta properties, e.g. interfaces)
- icmp (ICMP protocol)
- icmpv6 (ICMPv6 protocol)
- ip (IP protocol)
- ip6 (IPv6 protocol)
- tcp (TCP protocol)
- udp (UDP protocol)
- sctp (SCTP protocol)
- ct (connection tracking)
The following is an incomplete list of match arguments (for a more complete list, see nft(8)):
meta: iif <input interface INDEX> oif <output interface INDEX> iifname <input interface NAME> oifname <output interface NAME> icmp: type <icmp type> icmpv6: type <icmpv6 type> ip: protocol <protocol> daddr <destination address> saddr <source address> ip6: daddr <destination address> saddr <source address> tcp: dport <destination port> sport <source port> udp: dport <destination port> sport <source port> sctp: dport <destination port> sport <source port> ct: state <new | established | related | invalid>
In a way, iif and oif versus iifname and oifname are similar to static versus dynamic. Or the programming concept of definition versus declaration. Or to early binding versus delayed binding. See a use case and a link to further explanation.
Készletek
Sets are named or anonymous, and consist of one or more elements, separated by commas, enclosed by curly braces. Anonymous sets are embedded in rules and cannot be updated, you must delete and re-add the rule. E.g., you cannot just remove "http" from the dports set in the following:
# nft add rule ip6 filter input tcp dport {telnet, http, https} accept
Named sets can be updated, and can be typed and flagged. sshguard uses named sets for the IP addresses of blocked hosts.
table ip sshguard {
set attackers {
type ipv4_addr
flags interval
elements = { 1.2.3.4 }
}
To add or delete elements from the set, use:
# nft add element ip sshguard attackers { 5.6.7.8/32 }
# nft delete element ip sshguard attackers { 1.2.3.4/32 }
Note the type ipv4_addr can include a CIDR netmask (the /32 here is not necessary, but is included for completeness' sake). Note also, the set defined here by TABLE ip sshguard { SET attackers } is addressed as ip sshguard attackers.
NFTSet= in systemd.network(5) § [ADDRESS] SECTION OPTIONS for details and #Dynamic named sets using systemd-networkd for an example.Atomic reloading
Flush the current ruleset:
# echo "flush ruleset" > /tmp/nftables
Dump the current ruleset:
# nft -s list ruleset >> /tmp/nftables
Now you can edit /tmp/nftables and apply your changes with:
# nft -f /tmp/nftables
Examples
Workstation
/etc/nftables.conf
flush ruleset
table inet my_table {
set LANv4 {
type ipv4_addr
flags interval
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 }
}
set LANv6 {
type ipv6_addr
flags interval
elements = { fd00::/8, fe80::/10 }
}
chain my_input_lan {
udp sport 1900 udp dport >= 1024 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 accept comment "Accept Samba Workgroup browsing replies"
}
chain my_input {
type filter hook input priority filter; policy drop;
iif lo accept comment "Accept any localhost traffic"
ct state invalid drop comment "Drop invalid connections"
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)"
ct state { established, related } accept comment "Accept traffic originated from us"
meta l4proto { icmp, ipv6-icmp } 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"
ip6 saddr @LANv6 jump my_input_lan comment "Connections from private IP address ranges"
ip saddr @LANv4 jump my_input_lan comment "Connections from private IP address ranges"
counter comment "Count any other traffic"
}
chain my_forward {
type filter hook forward priority filter; policy drop;
# Drop everything forwarded to us. We do not forward. That is routers job.
}
chain my_output {
type filter hook output priority filter; policy accept;
# Accept every outbound connection
}
}
NFTSet= to get the network prefixes of a connection. See #Dynamic named sets using systemd-networkd.Server
/etc/nftables.conf
flush ruleset
table inet my_table {
set LANv4 {
type ipv4_addr
flags interval
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 }
}
set LANv6 {
type ipv6_addr
flags interval
elements = { fd00::/8, fe80::/10 }
}
chain my_input_lan {
meta l4proto { tcp, udp } th dport 2049 accept comment "Accept NFS"
udp dport netbios-ns accept comment "Accept NetBIOS Name Service (nmbd)"
udp dport netbios-dgm accept comment "Accept NetBIOS Datagram Service (nmbd)"
tcp dport netbios-ssn accept comment "Accept NetBIOS Session Service (smbd)"
tcp dport microsoft-ds accept comment "Accept Microsoft Directory Service (smbd)"
udp sport { bootpc, 4011 } udp dport { bootps, 4011 } accept comment "Accept PXE"
udp dport tftp accept comment "Accept TFTP"
}
chain my_input {
type filter hook input priority filter; policy drop;
iif lo accept comment "Accept any localhost traffic"
ct state invalid drop comment "Drop invalid connections"
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)"
ct state { established, related } accept comment "Accept traffic originated from us"
meta l4proto { icmp, ipv6-icmp } 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"
ip6 saddr @LANv6 jump my_input_lan comment "Connections from private IP address ranges"
ip saddr @LANv4 jump my_input_lan comment "Connections from private IP address ranges"
tcp dport ssh accept comment "Accept SSH on port 22"
tcp dport ipp accept comment "Accept IPP/IPPS on port 631"
meta l4proto { tcp, udp } th dport { http, https, 8008, 8080 } accept comment "Accept HTTP (ports 80, 443, 8008, 8080)"
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)"
}
chain my_forward {
type filter hook forward priority filter; policy drop;
# Drop everything forwarded to us. We do not forward. That is routers job.
}
chain my_output {
type filter hook output priority filter; policy accept;
# Accept every outbound connection
}
}
Limit rate
table inet my_table {
chain my_input {
type filter hook input priority filter; policy drop;
iif lo accept comment "Accept any localhost traffic"
ct state invalid drop comment "Drop invalid connections"
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)"
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 { icmp, ipv6-icmp } 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"
}
}
Jump
When using jumps in configuration file, it is necessary to define the target chain first. Otherwise one could end up with Error: Could not process rule: No such file or directory.
table inet my_table {
chain web {
tcp dport http accept
tcp dport 8080 accept
}
chain my_input {
type filter hook input priority filter;
ip saddr 10.0.2.0/24 jump web
drop
}
}
Different rules for different interfaces
If your box has more than one network interface, and you would like to use different rules for different interfaces, you may want to use a "dispatching" filter chain, and then interface-specific filter chains. For example, let us assume your box acts as a home router, you want to run a web server accessible over the LAN (interface enp3s0), but not from the public internet (interface enp2s0), you may want to consider a structure like this:
table inet my_table {
chain my_input { # this chain serves as a dispatcher
type filter hook input priority filter; policy drop;
iif lo accept comment "always accept loopback"
iifname enp2s0 jump my_input_public
iifname enp3s0 jump my_input_private
}
chain my_input_public { # rules applicable to public interface interface
ct state {established,related} accept
ct state invalid drop
udp dport bootpc accept
tcp dport bootpc accept
}
chain my_input_private {
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 port-unreachable comment "all other traffic"
}
chain my_output { # we let everything out
type filter hook output priority filter;
accept
}
}
Alternatively you could choose only one iifname statement, such as for the single upstream interface, and put the default rules for all other interfaces in one place, instead of dispatching for each interface.
Masquerading
nftables has a special keyword masquerade "where the source address is automagically set to the address of the output interface" (source). This is particularly useful for situations in which the IP address of the interface is unpredictable or unstable, such as the upstream interface of routers connecting to many ISPs. Without it, the Network Address Translation rules would have to be updated every time the IP address of the interface changed.
To use it:
- make sure masquerading is enabled in the kernel (true if you use the default kernel), otherwise during kernel configuration, set
CONFIG_NFT_MASQ=m. - the
masqueradekeyword can only be used in chains of typenat. - masquerading is a kind of source NAT, so only works in the output path.
Example for a machine with two interfaces: LAN connected to enp3s0, and public internet connected to enp2s0:
table inet my_nat {
chain my_masquerade {
type nat hook postrouting priority srcnat;
oifname "enp2s0" masquerade
}
}
Since the table type is inet both IPv4 and IPv6 packets will be masqueraded. If you want only ipv4 packets to be masqueraded (since extra adress space of IPv6 makes NAT not required) meta nfproto ipv4 expression can be used infront of oifname "enp2s0" or the table type can be changed to ip.
NAT with port forwarding
This example will masquerade traffic exiting through a WAN interface called eth0 and forward ports 22 and 80 to 10.0.0.2. You will need to set net.ipv4.ip_forward to 1 via sysctl.
table nat {
chain prerouting {
type nat hook prerouting priority dstnat;
iif eth0 tcp dport {22, 80} dnat to 10.0.0.2
}
chain postrouting {
type nat hook postrouting priority srcnat;
oif eth0 masquerade
}
}
Count new connections per IP
Use this snippet to count HTTPS connections:
/etc/nftables.conf
table inet filter {
set https {
type ipv4_addr;
flags dynamic;
size 65536;
timeout 60m;
}
chain input {
type filter hook input priority filter;
ct state new meta l4proto { tcp, udp } th dport 443 update @https { ip saddr counter }
}
}
To print the counters, run nft list set inet filter https.
Dynamic blackhole
Use this snippet to drop all HTTPS connections for 1 minute from a source IP (or /64 IPv6 range) that exceeds the limit of 10/second.
/etc/nftables.conf
table inet dev {
set blackhole_ipv4 {
type ipv4_addr;
flags dynamic, timeout;
size 65536;
}
set blackhole_ipv6 {
type ipv6_addr;
flags dynamic, timeout;
size 65536;
}
chain input {
type filter hook input priority filter; policy accept;
ct state new meta l4proto { tcp, udp } th dport 443 \
meter flood_ipv4 size 128000 { ip saddr timeout 10s limit rate over 10/second } \
add @blackhole_ipv4 { ip saddr timeout 1m }
ct state new meta l4proto { tcp, udp } th dport 443 \
meter flood_ipv6 size 128000 { ip6 saddr and ffff:ffff:ffff:ffff:: timeout 10s limit rate over 10/second } \
add @blackhole_ipv6 { ip6 saddr and ffff:ffff:ffff:ffff:: timeout 1m }
ip saddr @blackhole_ipv4 counter drop
ip6 saddr and ffff:ffff:ffff:ffff:: @blackhole_ipv6 counter drop
}
}
To print the blackholed IPs, run nft list set inet dev blackhole_ipvX.
Tippek és trükkök
Saving current rule set
The output of nft list ruleset command is a valid input file for it as well. Current rule set can be saved to file and later loaded back in.
# nft -s list ruleset | tee filename
nft list does not output variable definitions, if you had any in your original file they will be lost. Any variables used in rules will be replaced by their value.Simple stateful firewall
See Simple stateful firewall for more information.
Single machine
Flush the current ruleset:
# nft flush ruleset
Add a table:
# nft add table inet my_table
Add the input, forward, and output base chains. The policy for input and forward will be to drop. The policy for output will be to 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 ; }'
Add two regular chains that will be associated with tcp and udp:
# nft add chain inet my_table my_tcp_chain # nft add chain inet my_table my_udp_chain
Related and established traffic will be accepted:
# nft add rule inet my_table my_input ct state '{ related, established }' accept
All loopback interface traffic will be accepted:
# nft add rule inet my_table my_input iif lo accept
Drop any invalid traffic:
# nft add rule inet my_table my_input ct state invalid drop
Accept ICMP and IGMP:
# nft add rule inet my_table my_input meta l4proto '{ icmp, ipv6-icmp }' accept
# nft add rule inet my_table my_input ip protocol igmp accept
New udp traffic will jump to the UDP chain:
# nft add rule inet my_table my_input meta l4proto udp ct state new jump my_udp_chain
New tcp traffic will jump to the 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'
At this point you should decide what ports you want to open to incoming connections, which are handled by the TCP and UDP chains. For example to open connections for a web server add:
# nft add rule inet my_table my_tcp_chain tcp dport 80 accept
To accept HTTPS connections for a webserver on port 443:
# nft add rule inet my_table my_tcp_chain tcp dport 443 accept # nft add rule inet my_table my_udp_chain udp dport 443 accept
To accept SSH traffic on port 22:
# nft add rule inet my_table my_tcp_chain tcp dport 22 accept
To accept incoming DNS requests:
# 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
Be sure to make your changes permanent when satisfied.
Prevent brute-force attacks
Sshguard is program that can detect brute-force attacks and modify firewalls based on IP addresses it temporarily blacklists. See Sshguard#nftables on how to set up nftables to be used with it.
Logging traffic
You can log packets using the log action. The most simple rule to log all incoming traffic is:
# nft add rule inet filter input log
See nftables wiki for details.
Monitor
Listen to all events, report in native nft format.
# nft monitor
See nft(8) § MONITOR
Ruleset debugging trace temporary
meta nftrace set 1 ruleset packet tracing on/off. Use monitor trace command to watch traces.
In another shell "include" the file inside the interactive shell:
# nft -i nft> include "/root/nftables.trace"
Example, adjust to your needs:
/root/nftables.trace
add table ip temp-trace {comment "Temporary table!!"; flags owner;}
add chain ip temp-trace icmp-prerouting { type filter hook prerouting priority raw - 1 ; }
add rule ip temp-trace icmp-prerouting ip protocol icmp meta nftrace set 1
This file adds a temporary table (flags owner) so that it gets automatically removed, if the calling (process) interactive nft is closed. The Base Chain needs to be adjusted for your use case. You can create multiple chains and multiple rules with "meta nftrace set 1" "ip protocol icmp" is used just as an example and is not necessary. There are many ways to achieve a similar effect, the advantage is that by closing the interactive shell the previous state is automatically restored, and if an error is inside the file nothing gets executed.
See nftables wiki and a python tool automating the process and coloring.
Using iptables-nft
The older iptables language remains quite dominant in Linux documentation, and quite a few things still depend on iptables to run (such as Docker's networking). Although it's also perfectly workable to use legacy iptables and nftables at the same time, using iptables-nft's translation is preferred because:
- It puts everything in the same place, using the newer, more efficient, non-locking framework.
- It checks for conflicts.
There are two ways to use the old iptables language with nftables:
iptables-translateandiptables-restore-translate(idem forip6tables,ebtables, etc.) take iptable language and output nft language. They do not change running nft settings. See xtables-translate(8).
- For configuration you want to maintain later on, it's a good idea to use the
-translatetool and integrate the result code into your existing rules. For example, if you find something useful in simple stateful firewall or the wider Internet, you can translate them to put into your nft config.
iptablesandiptables-restore(again idem forip6tablesetc.) uses the above translation and put them into the running nft settings. It also offers statistics like regular iptables does. See xtables-nft(8).
- Those commands work reasonably well given what they have to work with. They should "just work" with simple usage, but occasionally you will need to step in and debug.
Dynamic named sets using systemd-networkd
systemd-networkd's connections can use the NFTSet= option to populate predefined named sets with host IP addresses, network prefixes and interface indexes. This allows to avoid hardcoding them in /etc/nftables.conf. The NFTSet= option is supported in [Address], [DHCPv4], [DHCPv6] and [IPv6AcceptRA] sections. See systemd.network(5) § [ADDRESS] SECTION OPTIONS.
For example, to process connections from a local network (where IP addresses are assigned via DHCP or SLAAC) in a separate my_input_lan chain:
/etc/nftables.conf
...
table inet my_table {
set eth_ipv4_prefix {
type ipv4_addr
flags interval
comment "Populated by systemd-networkd"
}
set eth_ipv6_prefix {
type ipv6_addr
flags interval
comment "Populated by systemd-networkd"
elements = { fe80::/10 }
}
set eth_ifindex {
type iface_index
comment "Populated by systemd-networkd"
}
...
chain my_input {
type filter hook input priority filter; policy drop;
iif @eth_ifindex ip6 saddr @eth_ipv6_prefix jump my_input_lan comment "Connections from LAN"
iif @eth_ifindex ip saddr @eth_ipv4_prefix jump my_input_lan comment "Connections from LAN"
}
...
}
/etc/systemd/network/my-network.network
... [DHCPv4] NFTSet=prefix:inet:my_table:eth_ipv4_prefix NFTSet=ifindex:inet:my_table:eth_ifindex [DHCPv6] NFTSet=prefix:inet:my_table:eth_ipv6_prefix NFTSet=ifindex:inet:my_table:eth_ifindex [IPv6AcceptRA] NFTSet=prefix:inet:my_table:eth_ipv6_prefix NFTSet=ifindex:inet:my_table:eth_ifindex ...
Hibaelhárítás
Working with Docker
- With the following setup, you will not be able to use protocols like
AF_BLUETOOTHinside containers even with--net host --privileged. - Rootless Docker containers already run in a separate network namespace. You may not need to do anything.
Using nftables can interfere with Docker networking (and probably other container runtimes as well). You can find various workarounds on the internet which either involve patching iptables rules and ensuring a defined service start order or disabling dockers iptables management completely which makes using docker very restrictive (think port forwarding or docker-compose).
A reliable method is letting docker run in a separate network namespace where it can do whatever it wants. It is probably best to not use iptables and instead use iptables-legacy to prevent docker from mixing nftables and iptables rules.
Use the following docker service drop-in file:
/etc/systemd/system/docker.service.d/netns.conf
[Service] PrivateNetwork=yes PrivateMounts=No # cleanup ExecStartPre=-nsenter -t 1 -n -- ip link delete docker0 # add veth ExecStartPre=nsenter -t 1 -n -- ip link add docker0 type veth peer name docker0_ns ExecStartPre=sh -c 'nsenter -t 1 -n -- ip link set docker0_ns netns "$$BASHPID" && true' ExecStartPre=ip link set docker0_ns name eth0 # bring host online ExecStartPre=nsenter -t 1 -n -- ip addr add 10.0.0.1/24 dev docker0 ExecStartPre=nsenter -t 1 -n -- ip link set docker0 up # bring ns online ExecStartPre=ip addr add 10.0.0.100/24 dev eth0 ExecStartPre=ip link set eth0 up ExecStartPre=ip route add default via 10.0.0.1 dev eth0
Adjust the 10.0.0.* IP addresses if they are not appropriate for your setup.
Enable IP forwarding and set-up NAT for docker0 with the following postrouting rule:
iifname docker0 oifname eth0 masquerade
Then, ensure that kernel IP forwarding is enabled.
Now you can setup a firewall and port forwarding for the docker0 interface using nftables without any interference.
További olvasnivaló a témában
- netfilter nftables wiki
- debian:nftables
- gentoo:nftables
- First release of nftables
- nftables quick howto
- The return of nftables
- What comes after ‘iptables’? Its successor, of course: `nftables`
- Gene's Tech Blog – additional nftables samples for workstation and firewall