Per-App Firewalling on Linux Is Genuinely Hard, and Little Snitch Is About to Find Out
Source: lobsters
Objective Development announced Little Snitch for Linux, and the response online ranged from enthusiasm to mild surprise that it took this long. Little Snitch has been the gold standard for per-application network monitoring on macOS since roughly 2002. Bringing it to Linux is not a port in the conventional sense. The two platforms have fundamentally different answers to the question of how a process’s network activity gets intercepted, attributed, and acted upon, and those differences go all the way down to the kernel.
Understanding what Objective Development had to build requires understanding what they had on macOS to begin with, and then reckoning with how little Linux offers in comparison.
What Little Snitch Does on macOS
On macOS, Little Snitch hooks into the Network Extension framework, specifically the NEFilterDataProvider and NEFilterControlProvider APIs Apple introduced as a replacement for kernel extensions in macOS Catalina. The NEFilterDataProvider runs as a system extension in user space, but with privileges that let it intercept outbound and inbound TCP/UDP flows before they complete. It receives rich metadata about each flow: the source process path, bundle identifier, code-signing identity, destination hostname (resolved from the DNS query that preceded the connection), destination IP, and port.
The critical word there is “pause.” The kernel will hold a connection attempt open while the filter decides what to do with it. If no rule matches, Little Snitch can pop up a dialog asking the user to allow or deny the connection, and the kernel waits for that verdict before proceeding or refusing the TCP handshake. This blocking behavior is built into the NEFilter API contract.
Before Catalina, Little Snitch used a Network Kernel Extension, a socket filter kext that ran directly in kernel space. Apple deprecated kexts and then, with Apple Silicon, blocked them entirely for new installs. Objective Development spent years migrating to Network Extensions, and the resulting architecture is still capable of everything the kext version could do.
Code-signing identity is particularly important here. A rule that says “allow Safari” is bound to Safari’s bundle ID and signing certificate, not just its filesystem path. You cannot rename a different binary to Safari and inherit its network permissions. That’s a property macOS provides for free.
The Linux Problem
Linux has no equivalent to NEFilterDataProvider. The kernel does not natively associate a network flow with the process that initiated it in a way that’s cleanly hookable from user space.
The conventional approach, used by OpenSnitch for years, is to combine Netfilter’s NFQUEUE with procfs polling. NFQUEUE lets a user-space daemon receive packets from the kernel and issue verdicts on them. The daemon receives a packet, checks /proc/net/tcp or /proc/net/udp to find the socket inode for that connection, then walks /proc/<pid>/fd/ to find which process owns that inode. It applies the matching rule, or prompts the user, and sends the verdict back to the kernel.
This works, but it has problems. The procfs lookup is a race: the process could have exited between the packet arriving and the lookup completing. High-frequency connections generate substantial overhead. The approach is inherently polling-adjacent rather than event-driven.
More recent versions of OpenSnitch have moved toward eBPF probes attached to the connect() and sendmsg() syscalls, which gives synchronous, per-call visibility without the procfs race. The eBPF program runs in the kernel context where the PID and process comm are available directly. This is architecturally cleaner, though it requires a kernel recent enough to support the relevant program types and map types, which in practice means Linux 5.x at minimum for anything sophisticated.
Portmaster, from Safing, takes a similar eBPF-forward approach combined with a custom DNS resolver. By routing all DNS traffic through a local resolver, Portmaster can enforce domain-based rules rather than just IP-based ones, which is essential for anything beyond basic allow/deny by address. It also has the most polished desktop UI of any existing Linux per-app firewall, built in Go with an Electron-based frontend.
The eBPF Path
The modern Linux mechanism that makes per-application firewalling tractable is eBPF, specifically the cgroup-level socket hooks introduced progressively through the 4.x and 5.x kernel series. Programs of type BPF_PROG_TYPE_CGROUP_SKB and socket operations programs (BPF_PROG_TYPE_SOCK_OPS) can be attached to a cgroup and intercept connections made by any process in that cgroup.
If every application runs in its own cgroup, which is increasingly true on systemd-based desktops where systemd assigns each user session and user-launched application to a cgroup slice, you get per-application hook points for free. The cgroup/connect4 and cgroup/connect6 hook types let you intercept TCP connection attempts synchronously at the connect() call, which is the closest Linux gets to NEFilter’s flow interception.
The blocking behavior, the ability to hold a connection while prompting the user, requires either denying the connection immediately and letting the application retry (which breaks many apps), or using a queuing mechanism like NFQUEUE for the initial connection while the eBPF layer handles attribution. Neither is as clean as Apple’s NEFilter blocking API, but both are workable.
Hostname-based rules require DNS interception, almost universally handled by running a local DNS proxy that all system DNS traffic routes through. This is what Portmaster does, and it’s likely what any serious Linux implementation needs.
What Objective Development Brings
The existing Linux tools are functional, but they are clearly developer-first projects. OpenSnitch’s UI is a Qt application that looks roughly like something from 2012. Portmaster is more polished but still carries the unmistakable aesthetic of a startup trying to make security software approachable.
What Objective Development has built over two decades on macOS is not just a firewall. It’s a product with a carefully considered rule model, a research assistant that identifies known processes and destinations, profile-based rules that switch based on network context, a live traffic map that’s genuinely useful for understanding what your machine is doing, and an alert dialog that presents the right information without overwhelming a non-expert user. That design maturity is what’s actually being ported.
The binary identity problem is harder on Linux. macOS’s code-signing infrastructure gives Little Snitch a tamper-evident way to identify a process. On Linux, the best available option is path and inode, which an attacker or a misconfigured install script can easily confuse. Some approaches use hash verification at rule creation time, but there’s no OS-level equivalent to Apple’s notarization or bundle ID semantics. Objective Development will have to decide how much to lean on path-based identity and how to communicate that limitation to users.
What This Means for the Ecosystem
OpenSnitch and Portmaster have done the hard work of proving that per-application firewalling on Linux is possible and that there’s a real user base for it. Little Snitch entering that space is not a displacement threat to those projects; it’s a validation. A commercial product with Objective Development’s track record choosing to invest in a Linux version signals that the audience is large enough and the problem is solvable enough to be worth it.
The more interesting question is what happens to Linux’s underlying infrastructure for this use case. eBPF has made per-application network visibility dramatically more accessible than it was five years ago. The BPF LSM hooks added in Linux 5.7 extend this to security-policy enforcement. The pieces are there; they’re just not assembled into a coherent, stable API the way Apple’s Network Extension framework is.
If Objective Development ships a polished Little Snitch for Linux, and if it works reliably across major distributions, it will set a de facto bar for what per-application network transparency looks like on the desktop. That’s a useful thing to have, regardless of which tool you end up using.