In nftables, what does the `inet` family mean when you write `table inet filter`, and what does it change compared with maintaining separate iptables and ip6tables rulesets?
answer
- families beyond ip and ip6
- one table, both address stacks
- chains registered on v4 and v6 hooks
- address matches stay family-specific
- icmp keyword is v4 only
basics
~20 sThe inet family is nftables' dual-stack address family: one table whose base chains are evaluated for both IPv4 and IPv6 packets. It replaces keeping two parallel rulesets, so each rule is written, reviewed and audited once.
solid answer
~60 sEvery nftables table is declared in an address family — `ip`, `ip6`, `inet`, `arp`, `bridge` or `netdev` — and the family decides which traffic its base chains see. `inet` is the dual-stack one: a chain in `table inet filter` is registered on both the IPv4 and IPv6 side of its hook, so a rule such as `tcp dport 22 accept` applies to both protocols from a single line. That is the direct answer to the old `iptables` plus `ip6tables` split, where two commands, two saved files and two review surfaces meant the IPv6 half routinely drifted or was never written at all — and a host that later picked up an IPv6 address was effectively unfirewalled on it. Family-specific matches still exist inside an inet table: `ip saddr` only ever matches IPv4 packets and `ip6 saddr` only IPv6, and you can branch a whole block with `meta nfproto ipv4`. The trap to remember is ICMP: `icmp` matches IPv4 only, so a default-drop inet chain must allow ICMPv6 explicitly or IPv6 neighbour discovery breaks.
code
bash · 7 linesnft add table inet filter
nft add chain inet filter input '{ type filter hook input priority filter; policy drop; }'
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input iif lo accept
nft add rule inet filter input tcp dport 22 accept
nft add rule inet filter input icmp type echo-request accept
nft add rule inet filter input icmpv6 type '{ echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert }' acceptgo deeper
Know the family is the first word of a table declaration and that inet means IPv4 and IPv6 in one place. Being able to say why that is better than two parallel rulesets is enough at this level.
Explain which matches are family-neutral (tcp dport, ct state, meta l4proto) and which are not (ip saddr, ip6 saddr, icmp, icmpv6), and show how meta nfproto branches a block for one protocol.
Treat the dual-stack gap as a real exposure: hosts pick up IPv6 by autoconfiguration, services bind to ::, and a v4-only ruleset leaves them open. Be able to audit a chain for rules that silently cover only one stack.
Own the standard: one inet ruleset per host class, reviewed as a single artefact, with any family-specific table justified. Weigh that against tooling and frontends that still emit v4-only rules, and decide how the estate converges.
## Families come first in nftables In nftables nothing exists outside a table, and no table exists outside an **address family**. The family is the first word of the declaration — `table inet filter`, `table ip nat`, `table netdev ingressfilter` — and it determines two things: which kind of traffic the table's base chains are able to see, and which match expressions are legal inside them. The families are: - `ip` — IPv4 traffic only. - `ip6` — IPv6 traffic only. - `inet` — IPv4 and IPv6 together. - `arp` — ARP traffic. - `bridge` — traffic traversing a bridge. - `netdev` — traffic at the device level, used for the `ingress` and `egress` hooks. ## What `inet` actually does A base chain in an `inet` table is registered on the IPv4 *and* the IPv6 version of the hook it names. One chain object, one ordered list of rules, evaluated for a packet of either protocol. Nothing is duplicated behind the scenes and nothing is translated — the same rules simply run for both. ```bash nft add table inet filter nft add chain inet filter input '{ type filter hook input priority filter; policy drop; }' nft add rule inet filter input ct state established,related accept nft add rule inet filter input iif lo accept nft add rule inet filter input tcp dport 22 accept ``` That SSH rule covers IPv4 and IPv6 SSH. Under the old tooling it would have been one `iptables -A INPUT ...` and one `ip6tables -A INPUT ...`. ## Which rules are protocol-neutral and which are not Most of what a host firewall does never mentions an address family at all: `tcp dport`, `udp dport`, `ct state`, `iif`/`oif`, `meta l4proto`, `meta mark`. Those are written once and are correct for both stacks. Address matches are not neutral, and this is legal and important inside an inet table: - `ip saddr 10.0.0.0/8` matches only IPv4 packets. Against an IPv6 packet it simply does not match — the ruleset still loads, the rule is just inert for that traffic. - `ip6 saddr fd00::/8` is the mirror case. - `meta nfproto ipv4` (or `ipv6`) lets you gate a whole block on the protocol when you want a section that applies to only one stack. - `ip protocol tcp` is an IPv4 header match; `meta l4proto tcp` is the family-neutral way to say the same thing and is what you want in an inet table. ## The ICMPv6 trap The single most common mistake with a dual-stack default-drop chain is allowing `icmp` and assuming ICMPv6 came along with it. It did not — `icmp` is the IPv4 keyword, ICMPv6 is matched with `icmpv6`. IPv6 depends on ICMPv6 for Neighbour Discovery, so dropping it does not merely block pings, it breaks on-link IPv6 connectivity in ways that look like a routing fault. A dual-stack chain needs something like: ```bash nft add rule inet filter input icmp type echo-request accept nft add rule inet filter input icmpv6 type '{ echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert }' accept ``` ## Why this matters operationally The security value is not aesthetic. With two separate rulesets, the IPv4 one gets written on day one and the IPv6 one gets written when someone remembers. Hosts acquire IPv6 addresses by autoconfiguration without anybody deciding to, and a service bound to `::` on such a host is exposed with no rules in front of it. A single inet ruleset removes that entire failure mode: there is one place to look, and `nft list ruleset` shows the complete picture for both protocols. ## What `inet` does not cover It is IPv4 plus IPv6 and nothing else. ARP filtering still belongs in an `arp` table, bridged-frame filtering in a `bridge` table, and device-level filtering in a `netdev` table. `inet` also does not mean "internet-facing" — the name is the socket-address-family convention, not a direction.
- Inside an inet table, what happens to an IPv6 packet when it reaches a rule that matches on `ip saddr`?Nothing special — the rule simply does not match, and evaluation continues with the next rule. `ip saddr` is an IPv4 header match, so it can never be true for an IPv6 packet. The ruleset still loads without error, which is exactly why a v4-only rule inside a dual-stack chain is easy to miss in review: it looks like protection and silently covers half the traffic.
- If everything can go in one inet table, when would you still declare an `ip` or `ip6` table?When the rule set genuinely only makes sense for one protocol — IPv4-only NAT for a legacy subnet, or an IPv6-specific block you want isolated and separately reloadable. Both are also useful during a migration, since a translated legacy ruleset lands in the `ip` family. Separate tables coexist fine: netfilter evaluates every base chain registered on a hook.
- How do you apply a block of rules to only IPv4 inside an inet chain without repeating the family match on every line?Match `meta nfproto ipv4` and jump to a regular chain holding the IPv4-specific rules. One test gates the whole block, the rules inside stay readable, and the same pattern with `meta nfproto ipv6` gives you the mirror section. It is clearer than sprinkling `ip`/`ip6` matches through a single flat list.
saying these in an interview costs you the question
- Thinks inet means the internet-facing or WAN side
- Says IPv6 still needs a separate ip6tables ruleset alongside
- Assumes the icmp keyword also matches ICMPv6
- Believes inet tables also filter ARP and bridged frames
- Claims ip saddr silently matches the equivalent IPv6 prefix