Skip to main content
  1. Index/

iptables

iptables is the user-space command-line interface to the Linux kernel’s Netfilter packet filtering framework, the dominant firewall tool on Linux from its introduction in 2001 until nftables began replacing it in the mid-2010s. Netfilter inserts hook points at five positions in the kernel’s IPv4 (and separately IPv6, via ip6tables) packet processing path: PREROUTING (immediately after a packet arrives, before routing), INPUT (packets destined for the local host), FORWARD (packets being routed through the host), OUTPUT (packets generated by local processes), and POSTROUTING (after routing, before transmission). At each hook point, Netfilter calls into the active tables, each of which contains ordered chains of rules. A rule is a match condition (source IP, destination port, protocol, connection state, interface, packet mark, and many more via match extensions) paired with a target — the action to take if the rule matches: ACCEPT, DROP, REJECT, LOG, MASQUERADE, DNAT, SNAT, or a jump to a user-defined chain. Rules are evaluated in order; the first matching rule’s target is applied and evaluation stops (unless the target is LOG or another non-terminating target). If no rule matches, the chain’s policy (the default target) applies.

The four built-in tables serve distinct purposes. The filter table is the primary firewall: its INPUT, FORWARD, and OUTPUT chains are where ACCEPT and DROP rules live. The nat table handles Network Address Translation in PREROUTING (DNAT — rewriting destination addresses, as in port forwarding), OUTPUT (locally generated NAT), and POSTROUTING (SNAT/MASQUERADE — rewriting source addresses for outbound traffic from a private network). The mangle table modifies packet headers — TTL, TOS/DSCP bits, packet marks via --set-mark — and is present at all five hooks. The raw table, evaluated before connection tracking, is used to exempt specific traffic from Netfilter’s connection tracking with NOTRACK, reducing overhead for high-volume trusted flows. Connection tracking (conntrack) is the stateful inspection layer shared across all tables: it classifies each packet as NEW, ESTABLISHED, RELATED, or INVALID, allowing a single rule like -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT to permit all return traffic for established connections without enumerating every possible source. The iptables-save and iptables-restore commands serialise the complete ruleset to text for persistence and atomic bulk loading, since individual iptables rule commands are slow when applied one at a time to large rulesets.

iptables has two well-known operational limitations that drove the development of nftables. First, performance at scale: each rule is evaluated linearly; a ruleset with thousands of source IP ranges (common in Kubernetes, where kube-proxy historically wrote one rule per Service endpoint) causes measurable packet processing overhead because the kernel walks the list for every packet. In Kubernetes clusters with hundreds of Services and thousands of endpoints, this linear walk was a significant contributor to connection latency, driving the adoption of eBPF-based replacements like Cilium that bypass iptables entirely. Second, atomicity and API fragmentation: rules are added one at a time via individual kernel calls with no transactional semantics; ip6tables, arptables, and ebtables are separate tools with separate rulesets despite all sitting on Netfilter; and the user-space API is unwieldy for programmatic management. Despite these limitations, iptables remains universally present on Linux systems as the iptables-legacy backend or — on modern distributions — as a compatibility shim (iptables-nft) that translates iptables commands into nftables rules under the hood, allowing legacy tooling and Kubernetes components that emit iptables commands to function on systems that have fully transitioned to nftables.

Related

nftables

nftables is the successor to iptables within the Linux Netfilter framework, merged into the mainline kernel in 3.13 (2014) and now the default firewall backend on all major distributions — Debian 10+, Ubuntu 20.04+, RHEL 8+, Fedora 32+. It replaces not just iptables but the entire family of legacy Netfilter frontends: ip6tables (IPv6), arptables (ARP), and ebtables (Ethernet bridging) are all unified under a single nft command and a single kernel subsystem. The kernel component is a generic, protocol-independent packet classification engine; the protocol-specific logic (IPv4, IPv6, ARP, bridging) is expressed in user-space rule syntax rather than hardcoded in separate kernel modules. This unification eliminates the fragmented ruleset management of the iptables era, where a firewall with consistent IPv4/IPv6 and bridging policy required coordinating four separate tools with four separate rulesets and four separate persistence mechanisms.

WireGuard

WireGuard is a VPN protocol and implementation designed by Jason Donenfeld, merged into the Linux kernel in 5.6 (2020) and subsequently ported to Windows, macOS, iOS, Android, and BSD. Its defining characteristic is radical simplicity: the reference Linux kernel implementation is approximately 4,000 lines of code, compared to tens of thousands for IPsec’s XFRM subsystem and hundreds of thousands for OpenVPN. This simplicity is a deliberate security property — a smaller codebase has a smaller attack surface, is easier to audit, and is less likely to contain implementation vulnerabilities. WireGuard achieves this by making every design decision that allows optionality to be eliminated: there is no algorithm negotiation, no handshake negotiation, no cipher suite selection. The cryptographic suite is fixed: X25519 for key exchange, ChaCha20-Poly1305 for authenticated encryption, BLAKE2s for hashing and key derivation (via a custom HKDF-like construction), and Curve25519 for the static key pairs that identify peers. Peers are identified exclusively by their 32-byte Curve25519 public key, making WireGuard a public-key routed VPN: there are no usernames, passwords, certificates, or CAs; access control is entirely a function of which public keys are listed in each peer’s configuration.

eBPF (Extended Berkeley Packet Filter)

eBPF (Extended Berkeley Packet Filter) is a Linux kernel subsystem, its modern form dating to kernel 3.18 (2014), that allows user-authored programs to run inside the kernel with near-native performance, subject to safety guarantees enforced at load time by a verifier. The name is historical: the original BPF (Berkeley Packet Filter, 1992) was a narrow packet filtering mechanism for tools like tcpdump. eBPF extended the instruction set, registers, and capabilities far beyond packet filtering into a general-purpose in-kernel programmability platform. The central design constraint is that eBPF programs must be provably safe: they cannot crash the kernel, loop infinitely, or access memory out of bounds. The verifier statically analyses every program at load time, checking that all memory accesses are bounds-checked, all loops are bounded or unrolled, and all pointer dereferences are preceded by null checks. Only programs that pass verification are accepted; once accepted, the kernel JIT-compiles the eBPF bytecode to native machine code for the host architecture — x86-64, ARM64, RISC-V — so eBPF programs run at the same speed as compiled kernel code, not as an interpreter.