Little Snitch for Linux Help

Advanced Topics

This chapter explains the inner workings of Little Snitch for Linux for technically interested readers. Nothing here is required for everyday use, but it helps to understand what the product can and cannot do, and why.

Why Linux cannot do everything the macOS version does

Little Snitch hooks into the Linux network stack using eBPF, a mechanism that lets programs safely observe and intercept events inside the kernel. An eBPF program watches outgoing and incoming connections and feeds data to the daemon, which tracks statistics and serves the web UI.

eBPF is powerful but deliberately bounded. Before an eBPF program is loaded, the kernel's verifier statically analyzes it and rejects anything whose safety and termination it cannot prove. This imposes strict limits on program complexity and on storage:

This is the technical root of the statement in the Introduction: Little Snitch for Linux is built for privacy, not for hardening a system against a determined adversary.

Resolving IP addresses to names

The problem

Users want rules for domain names; everything else is obscure. But the filter works in the kernel, where only IP addresses are visible. Little Snitch must therefore reconstruct which name was used to look up a given IP address.

This reconstruction is fundamentally ambiguous. Many names can resolve to the same IP address. High traffic sites are typically hosted on content delivery networks. It is entirely possible (and even likely) that a tracking site and a computer magazine share the same address.

Two known techniques

There are two general techniques for recovering a name for an IP address:

  1. Temporal proximity of lookups. Watch DNS queries and responses. When a connection to an IP address is made, take the most recent DNS query that returned that address.
  2. Names carried inside the protocol. Many protocols include the remote host name in their data. Most importantly, TLS carries it in the SNI (Server Name Indication) header, and QUIC has an equivalent.

Both techniques are unreliable. A process may perform a lookup, cache the result, and connect much later. By then, the most recent lookup for that address may have been for a different name. Still, the name found this way is at least one valid name for the address. And this only works while DNS lookups are unencrypted. The SNI header, on the other hand, is entirely under control of the client. The client can send any name, as long as the server accepts it. And there are ongoing efforts to encrypt it (Encrypted Client Hello).

Little Snitch on macOS uses both techniques: it primarily reads the name from protocol headers, but validates it against recent DNS lookups. Little Snitch on Linux cannot inspect protocol headers, as explained above, so it relies on temporal proximity of DNS lookups only. This usually works very well, unless a DNS cache sits between the application and the visible network traffic, or DNS lookups are encrypted.

DNS visibility and systemd-resolved

On modern distributions, systemd-resolved commonly sits between applications and the network, and it can do both of the things that defeat lookup observation: caching and DNS encryption. The consequence: Little Snitch should observe the communication between the application and systemd-resolved, not the lookups systemd-resolved sends to the remote DNS server.

systemd-resolved offers applications two interfaces:

For best results, make sure applications use the UDP socket rather than the Unix domain socket. This is controlled by the hosts: line in /etc/nsswitch.conf. If that line contains the keyword resolve, glibc uses the nss-resolve module and talks to systemd-resolved over the Unix domain socket, invisibly to Little Snitch. Remove the resolve keyword (and any condition in brackets immediately following it) so that glibc falls back to classic DNS via /etc/resolv.conf, which on a systemd managed system points at 127.0.0.53. For example:

hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns

Name resolution behaves the same afterwards; the queries merely travel over the observable UDP socket instead of the hidden Unix domain socket.

Application level DNS encryption

Some applications, notably web browsers, offer their own DNS over HTTPS (or TLS or QUIC) setting. When enabled, the application sends encrypted queries directly to a remote resolver and Little Snitch sees no lookups at all from that application.

Our recommendation: disable DNS encryption in individual applications and enable it in systemd-resolved instead. Little Snitch then observes the plain queries between the application and systemd-resolved, while systemd-resolved encrypts the traffic that actually leaves your machine. As a welcome side effect, your entire system benefits from DNS encryption, not just the browser.

To enable encrypted DNS system wide, set DNSOverTLS=yes (or DNSOverTLS=opportunistic) in /etc/systemd/resolved.conf or a drop in file under /etc/systemd/resolved.conf.d/, and restart systemd-resolved. In browsers, look for the DNS over HTTPS or "secure DNS" setting and switch it to use the operating system's resolver.

Loopback answers

DNS responses containing loopback addresses (127.0.0.0/8, ::1) are discarded. Such answers usually come from blocking resolvers like Pi-hole, and names blocked there should not be attached to loopback traffic.

Process attribution: the parent chain

As described in Watching Your Connections, Little Snitch shows "parent via process" when a helper like curl makes a connection on behalf of another program. Here is how the parent is found.

Little Snitch walks the parent chain of the connecting process and tries to find "something interesting". If an interesting parent is found, the connection is displayed as "parent via process", and rules for this combination are matched. Rules for the parent alone are also matched. These apply to connections made by the parent directly or via any other process.

"Something interesting" is deliberately in quotes, because there is no crisp definition. Three refinements make the heuristic useful:

The app manager and shell lists are configured as glob patterns in executables.toml. See Advanced Configuration for how to override that file and the file itself for the syntax.

Executable normalization

Short of other identification criteria, executables are identified by their path in the file system. For most executables the path is fixed, but some contain a version number in a parent directory which changes with each upgrade, and some are mounted dynamically under a mount point whose name contains a unique identifier that changes on every start.

Rules should survive updates and restarts, and the connections view should not show a separate line for each version or incarnation of an application. Little Snitch therefore normalizes paths before matching rules or grouping entries.

Normalization converts the path into a glob pattern: the version number or unique identifier is replaced with *, the same style of pattern used by bash and other shells.

Which part of a path is a version number or unique identifier cannot be guessed reliably, it is configured in executables.toml. A normalization entry consists of:

One constraint deserves emphasis: the resulting glob pattern must itself be matched by the regular expression. This cannot be enforced or easily verified in code. It must be guaranteed by the person writing the pattern. When you add your own entries, double check this property.

If you write normalization patterns that could benefit other users, please consider sharing them with us.


Was this help page useful? Send feedback.
© 2016-2026 by Objective Development Software GmbH