· 7 min read ·

Little Snitch for Linux and the Unfinished Business of Per-Process Firewalling

Source: hackernews

Objective Development announced Little Snitch for Linux recently, and the Hacker News thread hit over 1300 points and 400 comments. That response is itself informative. It reflects years of pent-up demand for something that macOS users have taken for granted since 2002: a tool that intercepts outbound connections per application, asks you what to do, and remembers your answer.

For macOS users, Little Snitch is familiar infrastructure. It sits in the network stack, intercepts outbound connections before they complete, and surfaces an alert: “Firefox wants to connect to telemetry.mozilla.org.” You allow or deny. Rules accumulate. Over time you build an accurate picture of what your software is actually doing over the wire. The absence of this workflow on Linux, despite Linux being the dominant developer workstation and server platform, is not for lack of interest. It is a consequence of how the Linux kernel handles network traffic and process identity.

Why Per-Process Attribution Is Hard on Linux

The macOS version of Little Snitch, post-Big Sur, uses Apple’s Network Extensions framework and specifically the NEFilterDataProvider API. When a socket tries to connect, the kernel invokes a user-space system extension synchronously, passing it full information about the connecting application, including a process audit token that is cryptographically bound to the process identity. Process attribution is built into the interception mechanism at the design level.

Linux has no equivalent primitive. When a packet leaves a socket and enters the netfilter hooks, the process context is partially gone. The packet carries a UID from the socket’s sk->sk_uid, which gives you user-level identity, but not per-executable identity. Two applications running as the same user are indistinguishable at that layer. To know which specific binary sent a packet, you have to work backward from the socket inode through /proc.

This is the architectural gap that every per-process firewall on Linux has had to paper over.

How OpenSnitch Bridges the Gap

OpenSnitch is the most mature open-source equivalent for Linux. Its approach is instructive. An iptables rule redirects all outbound packets to a Netfilter Queue:

iptables -I OUTPUT -j NFQUEUE --queue-num 0

The opensnitchd daemon receives the packet via libnetfilter_queue. It extracts the source IP and port, queries /proc/net/tcp (or /proc/net/tcp6) to find the socket inode, then scans /proc/*/fd/* across every running process looking for a symlink that matches that inode. That gives it the PID. From there it reads /proc/$pid/exe and /proc/$pid/cmdline to identify the process.

The resulting flow looks like this:

app calls connect()
  → packet hits netfilter OUTPUT chain
  → NFQUEUE rule sends packet to opensnitchd
  → daemon queries /proc/net/tcp for socket inode
  → daemon scans /proc/*/fd/* for matching inode
  → daemon reads /proc/$pid/exe
  → checks rules database
  → if no matching rule: sends gRPC alert to GUI
  → user responds in dialog
  → daemon issues NF_ACCEPT or NF_DROP verdict
  → kernel proceeds

This works in the common case. It has two genuine problems. First, it is racy. The interval between connect() and the packet reaching NFQUEUE is nonzero. By then the process might have called exec(), the socket might have been transferred to a different process via SCM_RIGHTS, or the /proc scan might race with process exit. In practice, the race usually does not matter, but it means the process attribution is not a security guarantee.

Second, NFQUEUE imposes a round-trip to userspace for every new connection verdict, which creates measurable latency on high-connection-rate workloads. For a developer workstation this is usually tolerable; for anything doing thousands of short-lived connections per second it is not.

OpenSnitch addressed both problems partially in the v1.5 series by adding optional eBPF probes that attach to kernel functions like tcp_connect and udpv6_sendmsg. Because these probes fire at the point where process context is fully available, they use bpf_get_current_pid_tgid() to maintain a BPF map of inode → pid in real time. The daemon consults this map instead of scanning /proc, which eliminates the scan latency and reduces the race window significantly.

The eBPF Path That Does It Right

The cleanest architectural solution to per-process network interception on Linux does not involve NFQUEUE at all. Two eBPF program types get you there.

BPF_PROG_TYPE_CGROUP_SOCK_ADDR programs attach to a cgroup and fire at connect() time, before the packet is constructed. They have full access to the calling task’s context and can return a non-zero value to deny the connection. Because they intercept at the syscall boundary, there is no race between process identity and packet existence.

BPF_PROG_TYPE_LSM programs, available since kernel 5.7 with CONFIG_BPF_LSM, hook into Linux Security Module attachment points including security_socket_connect. You get the calling process’s task struct, the destination address, and the ability to return -EPERM to block the call, all synchronously. This is the model that closest approximates what macOS’s Network Extensions framework provides: an interception point at the kernel’s policy enforcement layer where the process is unambiguously known.

For a practical minimum kernel version, you need roughly 5.8 to 5.10 for a complete enough eBPF feature set. That covers Debian 11, Ubuntu 20.04 LTS with HWE kernels, Fedora 33+, and anything newer. It is not an aggressive requirement in 2025.

The iptables owner module (-m owner --uid-owner) predates all of this and gives you UID-level granularity, which is not sufficient for distinguishing two applications running under the same user. cgroups-based classification with net_cls can get you per-process tagging, but it requires manually assigning processes to cgroups, which is operationally unreasonable for a desktop tool. eBPF is the right answer, and the kernel has had the pieces in place for a few years.

Portmaster Occupies a Different Niche

Portmaster from Safing is the other complete solution in this space. It intercepts first at the DNS layer, blocking connections before a TCP handshake even begins, and uses netfilter rules for the packet layer beneath that. It bundles a full DNS-over-HTTPS resolver. The free tier covers the core firewall functionality; the paid add-on is SPN, Safing’s own onion-routing network.

Portmaster is real software, actively maintained, with meaningful user adoption. But its scope is wider than a connection monitor. It is a privacy infrastructure suite built around an Electron UI, and its design reflects that. The DNS interception approach is powerful for blocking tracking domains en masse, but it means the product’s mental model is different from Little Snitch’s connection-alert-per-application workflow. They are solving related but distinct problems.

What Objective Development Is Actually Bringing

The value here is not a novel technical approach. The eBPF primitives exist. OpenSnitch has shipped an eBPF mode. What obdev brings is two decades of UX refinement around a workflow that Linux tools have never prioritized.

The macOS Little Snitch connection alert is well-designed. It appears quickly, displays the hostname and destination port clearly, shows you the process name and icon, defaults to a temporary decision until you have enough context to make a permanent one, and gets out of the way. The network monitor shows live per-application connection data on a map. Automatic Profile Switching applies different rule sets depending on which network you are on.

None of that is available on Linux in a polished form. OpenSnitch’s Qt-based GUI is functional but clearly shows its open-source origins. Portmaster’s Electron shell is heavy. Neither has had the sustained design investment that a commercial product with a paying customer base tends to generate.

The technical question left open by the announcement is how precisely the Linux version handles kernel interception. Given that obdev maintained a kernel extension for years on macOS before migrating carefully to Network Extensions, they have genuine experience reasoning about kernel-userspace interfaces. If they built the Linux version around BPF_PROG_TYPE_CGROUP_SOCK_ADDR or LSM hooks rather than NFQUEUE, that would be a meaningful architectural decision, not just a repackaging of what OpenSnitch already does.

The Gap This Fills

Linux desktops have treated network transparency as an optional concern for a long time. The tools available to a developer who wants to know what their text editor is phoning home are the same tools a network administrator would use: Wireshark, ss, lsof -i, strace. They are powerful and completely wrong for the use case. A per-application connection monitor that works for someone who just wants to audit their development environment is a different product category.

The HN thread’s enthusiasm reflects genuine unmet demand from developers who use Linux daily and have wanted exactly this. OpenSnitch fills the gap for users willing to configure iptables rules, write udev rules, and accept a rough GUI. Portmaster fills it for users who want DNS-level blocking bundled with a broader privacy tool. Little Snitch for Linux is positioning itself as the focused, well-finished option for the use case the macOS version has served well since the kernel extension days.

Whether it succeeds depends on pricing, distribution packaging, and how well the GUI integrates across GNOME, KDE, and the assorted tiling window manager setups that Linux developers actually run. The macOS version sits around $59 one-time. A similar price point would be reasonable for this audience. The appetite is clearly there; the question is execution.

Was this interesting?