[snippet] Misusing Linux policy based routing for firewalling

by Ciprian Dorin Craciun (https://volution.ro/ciprian) on 

Experimenting with Linux policy based routing, i.e. man ip-rule(8), as a stateless firewall substitute.

// permanent-link // Lobsters // HackerNews // index // RSS



While experimenting with my approach to "secure" computers, one of the key ingredients is reducing the attack surface as most as possible, and unfortunately, one big attack surface of any Linux-based deployment is the kernel itself. Thus, one of the first things I've done is to configure and recompile my own extremely stripped down version of the Linux kernel (based on the latest LTS branch).

Among the kernel features that were removed was also a very important security related subsystem, namely the Linux firewall netfilter (or iptables the old version, and nf_tables the new version).

Why remove the firewall subsystem when it's essential for security?

Because there have been quite a few vulnerabilities that have impacted the Linux firewall subsystem, many of them granting root access, either to a local unprivileged user, or worse, RCE (Remote Code Execution) to an external attacker.

Here are some links to the most recent vulnerabilities impacting the Linux firewall subsystem:


However, I still do want the ability to firewall inbound traffic, and especially outbound traffic, in and out of my "secure" computer.

But, without the Linux firewall subsystem, how could we achieve this?

However, none of these approaches give us the ability to restrict incoming traffic. It only allows us to restrict what local processes can listen to (thus inbound traffic) or connect to (thus outbound traffic).


Which brings me to my alternative solution: Linux policy based routing.

Unfortunately, policy based routing is meant for, as the name says, "routing", and not for "firewalling", thus, it's worth stressing the fact that I'm abusing this tool.

Foremost, we must understand that routing applies only to outbound traffic, not inbound, thus it applies only to packets that are generated locally, and must be sent to somewhere else via a network device. (It also applies to forwarded traffic, when our node behaves as a router.)

It is also worth noting that policy based routing is stateless, as opposed to stateful, meaning that it doesn't see connections (e.g. TCP), or related traffic (like Linux's contrack does for UDP), but instead just individual packets. Thus, any "firewalling" that we can do by using Linux policy based routing can't take into account flows.

And, as a final note, due to a feature called return path filtering present in the Linux kernel, if enabled, we actually also get inbound traffic filtering. In a few words, with sysctl -w 'net.ipv4.conf.all.rp_filter = 1', the kernel is instructed that before accepting and delivering a packet locally, to look if there is a route for a packet that has the source and destination addresses switched (thus the "return path" name), and if not to consider it as "martian", causing it to be dropped and logged, because it is not coming from an expected route.

Fore more details on Linux based policy routing, see the ip-rule man page or this article.


Finally, here are the snippets I've used in my initial experiment:


A few observations:


Have I sparked some new ideas?