Per-application network scoping for Linux: select an app once, launch it normally, and only that app's traffic is filtered or routed.
Alpha. Linux only. Kernel 5.13 or newer with cgroup v2 and nftables.
Arch Linux / CachyOS (after the AUR package is published):
yay -S netscope-bin
sudo systemctl enable --now netscoped
sudo usermod -aG netscope "$USER"Tarball and cargo install --git channels are documented in docs/install.md. Cargo installs binaries only; the systemd unit, sysusers file, and config come from the tarball or AUR. Full documentation: https://qiiks.github.io/netscope/.
sudo netscope --uid "$(id -u)" add blocked --exe /usr/bin/curl --filter drop
curl --max-time 3 https://example.com # fails
sudo netscope remove blockedRoute a selected app through a tunnel interface:
sudo netscope --uid "$(id -u)" add routed --exe /usr/bin/curl --route tun0Scope a Windows game launched through Wine or Proton by selecting the .exe:
sudo netscope --uid "$(id -u)" add game --wine /games/Game/Game.exe --filter dropUse --route tun0 in place of --filter drop to route the same target.
Or attach a running process by name, with no install path and no wrapper:
sudo netscope --uid "$(id -u)" add game --process Overwatch.exe --route tun0--process matches a process's comm or an argv basename, so Overwatch,
Overwatch.exe, and overwatch.exe are the same target. A running process is
attached on the next poll and its existing sockets are marked, so a restart is
not required. A new Wine/Proton launch is caught before the loader runs, so the
game's first socket is already scoped.
netscope status, netscope list, netscope doctor, and netscope support-bundle cover inspection and troubleshooting. No wrapper is required: native ELF apps are caught at exec, Windows PEs launched through Wine/Proton are caught when Wine opens the PE, name targets hold the Wine loader, and Steam apps are matched by app id.
Two programs can share one process without fighting over its cgroup:
sudo netscope --uid "$(id -u)" open --consumer exitlink --name overwatch --process Overwatch.exe --route tun0
sudo netscope --uid "$(id -u)" open --consumer dropship --process Overwatch.exe --filter allow \
--deny-cidr 34.142.0.0/16Both consumers get the same profile and cgroup. Each owns its own policy; the
last netscope close removes the scope. See shared scopes.
netscope-gui is a calm desktop inspector for the daemon: overview rates and links, scopes with
their claims and permissions, an Add scope flow, and a Doctor screen whose fix commands copy to
the clipboard. It opens peer holds by default, so closing the window releases them.
cargo build --release -p netscope-gui
./target/release/netscope-guiThe window reports a down daemon, retries every two seconds, and shows the exact
systemctl start netscoped or usermod -aG netscope hint. --demo and headless --snap
scenes exist for screenshots; normal launches never read demonstration data. See
the GUI documentation.
Two programs can share one process through the netscope-client
crate (cargo add netscope-client), or speak the daemon protocol directly from any language.
use netscope_client::{Client, Hold};
fn main() -> Result<(), netscope_client::ClientError> {
let mut client = Client::connect()?;
let scope = client.open_process("exitlink", "Overwatch.exe", 1000, Hold::Peer)?;
client.close_scope(&scope.profile, "exitlink")
}The daemon accepts newline-delimited JSON on
/run/netscope/control.sock. The full envelope, every operation, hold
semantics, and copy-pasteable Python, Go, C, and shell clients are in
Daemon protocol & SDK.
fanotifyholds anexecof a selected native inode — or the first open of a selected Windows PE by a Wine/Proton loader — until the daemon has moved the process into/sys/fs/cgroup/netscope/<profile>.- nftables matches
socket cgroupv2or the profile'ssocket markand applies a filter or a routing mark. - Route profiles set a dedicated routing table with a blackhole fallback. If the configured interface is down, traffic is dropped rather than leaking through the main table.
A name target also holds the Wine/Proton loader binaries and matches the launcher ancestry of the loader, so a new game launch is caught before its first socket. A polling fallback attaches already-running processes, Wine/Proton processes matched by command line, and Steam children. When a process is attached late, the daemon marks its existing sockets with the profile mark; the nftables rules match either the cgroup or that mark, so those sockets change route on the next packet without a restart.
netscoped runs as root and accepts control messages only over a root-owned Unix socket in the netscope group. It loads no kernel module and opens no network listener. See SECURITY.md and docs/security.md.
sudo netscope support-bundleThe bundle is written to /tmp, is root-only, and includes a review-before-upload warning. Attach it to a bug report after checking it.
Dual-licensed under MIT or Apache-2.0, at your option.