Netfilter — the new firewall framework that will replace ipchains when the Linux 2.4 kernel ships — has been in development for nearly two years. The design has been public for most of that time but I have not read it carefully until this week.
This post is the read-up. The design is good. The implications for how Linux firewalling will evolve over the next decade are larger than I had appreciated.
What netfilter is
netfilter is two things, conceptually distinct:
A framework. A set of hook points inside the kernel's networking code where modules can register handlers. Five named hooks — PRE_ROUTING, LOCAL_IN, FORWARD, LOCAL_OUT, POST_ROUTING — covering every point at which a packet can be inspected, modified, or dropped. Modules register handlers for the hooks they care about; the kernel calls the handlers in priority order as packets traverse the stack.
A toolset. A collection of modules that use the framework to implement specific functionality. The headline module is iptables, which is the user-visible firewall tool that replaces ipchains. Other modules implement connection tracking, network address translation, packet logging, and so on.
The split between framework and toolset is the architectural decision that makes netfilter a long-term improvement rather than just a better firewall. Future modules can be added without modifying the framework. The framework is small enough to be auditable; the toolset can grow as needs emerge.
This is a meaningfully different design from ipchains, which had its functionality baked into the firewall code itself. Adding new functionality to ipchains required modifying the chains-and-rules code. Adding new functionality to netfilter requires writing a new module. The cost of innovation is much lower.
What iptables looks like
The user-visible tool, iptables, is similar in shape to ipchains but with notable refinements. The basic syntax:
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 192.0.2.0/24 -j ACCEPT
iptables -A INPUT -j DROP
This is recognisable. The chains have moved from lowercase input to uppercase INPUT; the syntax has been tightened. More substantially, several improvements over ipchains are visible immediately:
Connection tracking is integrated. A packet can be matched on its connection state — NEW, ESTABLISHED, RELATED, INVALID. This makes stateful firewalling — "allow established connections back in" — a single short rule rather than a complex set of permit-by-flag rules.
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
This one rule replaces about a dozen ipchains rules that approximated the same behaviour by examining TCP flags. It is also, structurally, correct — actual state tracking, not heuristic flag-checking.
Multiple tables for different concerns. netfilter separates filtering (the firewall decisions) from NAT (address translation) from mangling (packet modification) into separate tables. Each table has its own chains. The administrative model is cleaner; the rules for each concern do not interleave.
Modular match conditions. The -m flag loads a match module. There are modules for connection state, time of day, packet rate, packet length, source MAC address, mark values, and many more. Each is a small kernel module that can be loaded as needed. The set of match conditions is, in principle, unlimited; new conditions can be added without modifying iptables itself.
Modular targets. The same is true for the action — what to do with the matched packet. ACCEPT, DROP, REJECT, LOG, MASQUERADE, DNAT, SNAT, MARK, and others, with new ones available as modules.
The ergonomics are noticeably better than ipchains. Specific common patterns — "NAT this connection", "rate-limit these packets", "log dropped packets but not too verbosely" — are now expressible as short, idiomatic rule sets rather than patched-together compositions.
The architectural lesson
The deeper thing netfilter does is decouple the mechanism of packet matching from the policy it implements. The mechanism is a small framework. The policy is whatever modules are loaded and whatever rules are configured.
This is the same design pattern that has made other Linux subsystems extensible — VFS for filesystems, the LSM hooks coming in 2.4 for security policy, and so on. The pattern is general: build a small core that defines the extension points, then let modules implement actual functionality.
The consequences for Linux firewalling specifically:
The 2.4 kernel will have more capable firewalling than any other open-source operating system. OpenBSD's pf has its own design strengths but is less modular. FreeBSD's ipfw is older and less flexible. The functionality netfilter exposes is, for a single firewall config, deeper than what is available elsewhere.
Innovation will accelerate. The barrier to writing a new netfilter module is much lower than writing a new firewall feature was in 2.0. The next few years will see a stream of new match types, target types, and integration points.
The administrative complexity will grow. All of the above means more options. More options means more ways to misconfigure. The discipline of understanding what your rules actually do will become more important, not less, as the toolset grows.
The ipchains skill base will need to migrate. Operators who learned firewalling on ipchains will need to learn iptables syntax. The migration is not a one-line translation — the connection tracking changes the rule structure, the table-separation changes the configuration architecture. A rewrite is the right approach, not a syntactic conversion.
What I am going to do with this
For my own infrastructure, I will continue with ipchains until the 2.4 kernel is stable enough to deploy. The 2.4 development kernels are still rough; the production move is probably for late 2000 at earliest.
In parallel, I am rewriting my home firewall configuration in iptables syntax, using the development kernels in a test environment, to learn the tool before I have to use it in production. The exercise has already changed how I think about a few rules — connection tracking lets me express things more cleanly than ipchains, and the cleaner expressions are easier to audit.
I am also paying attention to the netfilter mailing list, where the development discussions happen. The community is active and generally civil; the design discussions are educational even when I do not have an opinion on the specific proposal. Reading mailing-list traffic of a project I respect is, in itself, a form of professional development.
A small note on what is not in netfilter
A short list of things netfilter does not do, which are sometimes assumed to be its job:
Application-layer firewalling. netfilter operates at IP and TCP/UDP layers. It cannot examine HTTP request contents, SQL queries, or anything above the transport layer. Application-layer protection requires a separate proxy (like Squid for HTTP) running in user space.
Cryptographic operations. netfilter does not handle SSL termination, IPSEC, VPNs, or any cryptographic protocol. Those are separate subsystems; netfilter integrates with them but does not implement them.
Distributed coordination. netfilter is per-host. Coordinating policy across multiple hosts — the kind of thing an ISP needs for DDoS response — requires additional infrastructure.
What netfilter is, is the kernel-side packet-filtering framework that lets each Linux box make local decisions about traffic flowing through it. That is a useful thing to have. The right tool for any specific job is rarely netfilter alone; it is netfilter as one component of a larger architecture.
More on this as the 2.4 release approaches. The transition is going to be the dominant Linux infrastructure event of the year. Worth being ready.