slirp4netns: user-mode networking for unprivileged network namespaces
User-mode networking for unprivileged network namespaces
At a glance
- What is it?
- slirp4netns gives a network namespace that an ordinary user created internet access by bridging its TAP device to a user-mode TCP/IP stack, which is what makes rootless container engines and rootless Kubernetes possible on Linux.
- Who is it for?
- slirp4netns is the right choice when you need networking for containers or namespaces that an unprivileged user created, on a host where veth pairs are unavailable to that user, and it is the piece that rootless Podman, Buildah, k3s and RootlessKit all lean on.
- Can I use it commercially?
- Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 20 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Unprivileged namespaces existed long before they were useful
Since Linux 3.8, an unprivileged user can create network namespaces together with user namespaces. The problem was that the feature was close to pointless in practice, because the obvious way to wire a namespace to the network, creating veth pairs across the host and the network namespace, still requires root privileges. The result was a namespace with no internet connection.
slirp4netns removes that requirement. It connects a network namespace to the internet in a completely unprivileged way, by connecting a TAP device inside the network namespace to the user-mode TCP/IP stack, the slirp implementation from libslirp. No kernel interface, no root, no bridge on the host.
The audience is therefore specific and quite large. The README lists the projects that build on it, and they divide into three groups. Kubernetes distributions include Usernetes and k3s, both via RootlessKit. Container engines include Podman, Buildah, ctnr via the slirp-cni-plugin, and Docker with Moby and containerd with nerdctl, both optionally via RootlessKit. And the tools layer contains RootlessKit, become-root and the slirp-cni-plugin itself.
That list is the strongest argument for the project. Almost every rootless container setup on Linux eventually needs a user-mode network path, and this is the component that provides it, which means its release cadence and its libslirp linkage are load bearing for a lot of other software.
A TAP device on one side, a user-mode stack on the other
The mechanism is worth understanding because it explains both the strengths and the limits of the approach.
On the inside of the namespace, slirp4netns creates a TAP device. From the namespace's point of view this is an ordinary network interface, with an address, a route and a MTU, and everything the container does with it looks like normal networking. The commands in the README show a TAP device named tap0 with the address 10.0.2.100/24, and a DNS server at 10.0.2.3, which are the familiar defaults of the classic user-mode network arrangement.
On the outside, there is no interface at all. The packets leaving the TAP device are handed to a TCP/IP stack running as an ordinary user-space process on the host, and that process performs the actual network traffic using the host's connectivity. libslirp is the library that implements the stack.
The consequence is that the data path is different in kind from kernel networking. Every packet is copied into user space, parsed there, and written back out. That is why the project ships a benchmarks directory and why the README has a Benchmarks section with an iperf3 case from the namespace to the host, and it is the reason to read that section before choosing this tool for a data heavy workload.
The other visible piece of the design is the sandbox. The repository has sandbox.c and sandbox.h, plus seccompfilter.c, seccompfilter.h, seccompfilter_rules.h and seccomparch.h, and the version output in the README shows a libseccomp version, so the host side process is deliberately restricted through seccomp filters rather than trusted blindly.
The three terminal walkthrough
The quick start in the README is a three part sequence, and the division into terminals is the part that surprises newcomers.
Terminal one creates the namespaces and records the process id so that the second process can attach to them:
(host)$ unshare --user --map-root-user --net --mount
(namespace)$ echo $$ > /tmp/pidTerminal two starts slirp4netns on the host against that pid, creating the tap0 device inside the namespace:
(host)$ slirp4netns --configure --mtu=65520 --disable-host-loopback $(cat /tmp/pid) tap0
starting slirp, MTU=65520
...The flags in that line do real work. --configure makes slirp4netns configure the TAP device itself, --mtu=65520 sets the interface MTU, and --disable-host-loopback stops the namespace from reaching services bound to the host's loopback address, which is the setting you want for isolation and the one you remove when you need to talk to a service on the host.
Terminal three goes back to the namespace and checks the interface, sets up name resolution and tries a request:
(namespace)$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
(namespace)$ mount --bind /tmp/resolv.conf /etc/resolv.conf
(namespace)$ curl https://example.comThe bind mount of the resolver file is the step people forget. Without it, name resolution inside the namespace keeps using whatever the host's resolver was, which usually does not answer for the names you want.
One more step may be needed before any of this works. If unshare fails, the README gives the sysctl workarounds known to be needed on Debian, Arch and old CentOS 7.x, which raise the limit on user namespaces and re-enable unprivileged user namespace cloning.
Host settings that decide whether unshare works at all
The fallback commands in the README are short but they are a deployment decision, not a detail. On the affected distributions, unshare fails unless the host allows a large number of user namespaces and permits cloning them for unprivileged users:
(host)$ sudo sh -c 'echo "user.max_user_namespaces=28633" >> /etc/sysctl.d/userns.conf'
(host)$ [ -f /proc/sys/kernel/unprivileged_userns_clone ] && sudo sh -c 'echo "kernel.unprivileged_userns_clone=1" >> /etc/sysctl.d/userns.conf'
(host)$ sudo sysctl --systemTwo things are worth flagging for an operations team. The first is that this is a host-wide change, applied through sysctl and therefore affecting every workload on the machine, and the second is that some distributions deliberately restrict unprivileged user namespaces for security reasons. A configuration change that raises the user namespace limit is a decision that belongs to whoever owns the host's security posture, and the README itself notes the affected distributions.
The second command only applies where the kernel exposes the unprivileged_userns_clone knob, and the file test in the command shows the intended pattern: check for the file, then write the setting only if it exists.
If that path is closed off on your hosts, slirp4netns will not help, because it solves the networking problem and not the namespace creation problem. That ordering is worth keeping in mind when a rootless setup fails at the first step rather than the second.
libslirp is now a separate version to track
The dependency story changed in a way that still catches people out, and the README explains it in the security advisories section.
Before the end of 2020, the vulnerabilities of QEMU/libslirp were collected in this repository, because slirp4netns releases prior to v1.0.0 were always statically linked with a specific version of libslirp. Starting with 2021, those vulnerabilities are no longer collected here, because slirp4netns version 1.0.0 and later can be linked with an arbitrary version of libslirp.
That moves part of your upgrade responsibility onto the distribution package. A packaged slirp4netns is linked against the libslirp your distribution ships, so a libslirp security fix reaches you when your distribution updates it, not when slirp4netns releases. The README points at the security advisories page for the project's own past advisories, and at the libslirp vulnerability list for the upstream ones.
The version output tells you what you actually have:
$ slirp4netns --version
slirp4netns version 1.1.8
commit: d361001f495417b880f20329121e3aa431a8f90f
libslirp: 4.4.0
SLIRP_CONFIG_VERSION_MAX: 3
libseccomp: 2.4.3Running that command is the fastest way to answer whether your install is old, which libslirp it is linked against, and which seccomp library it uses. The project also publishes statically linked binaries for x86_64, aarch64, armv7l, s390x, ppc64le and riscv64, which is the option when you want a known libslirp rather than the distribution's.
The maintenance table has not caught up with the 1.3.x releases
The README states a maintenance policy with a table of version lines and their status. The table marks the v1.2.x line as active, and lists v1.1.x as end of life as of May 2, 2022, v1.0.x as end of life as of June 2, 2020, v0.4.x as end of life as of September 30, 2020, v0.3.x as end of life as of March 31, 2020, v0.2.x as end of life as of August 30, 2019, and early versions before v0.2.x as end of life as of January 5, 2019.
Read that table against the release list and you notice a gap. The current releases are v1.3.6 on 2026-10-02, v1.3.5 on 2026-08-27 and v1.3.4 on 2026-05-26, and the v1.3.x line does not appear in the table at all, while the table still points at v1.2.x as the active line. The last push was on 2026-10-02, so work is landing on the master branch, but the documented policy table lags behind the version numbers people actually install.
The pattern of the three releases is also worth noting. v1.3.4, v1.3.5 and v1.3.6 landed roughly every three months, which is a steady but not fast cadence, and it means a production deployment should plan to pick up security relevant libslirp updates through the distribution package rather than by chasing tags here.
The licence is GPL-2.0, with a COPYING file at the top level of the repository, and the project keeps a MAINTAINERS file and a SECURITY_CONTACTS file. GPL-2.0 is the detail to note for an engineer linking this into a larger piece of software, since it carries copyleft obligations that a permissive licence would not.
Where slirp4netns is the wrong tool
Three cases stand out.
First, throughput. The data path runs through a user-mode TCP/IP stack rather than kernel interfaces, and the project ships benchmarks for exactly this reason. A network heavy workload, a large file transfer or a latency sensitive service inside a rootless container pays for that choice. The README has a Benchmarks section with an iperf3 case from the namespace to the host, and that section is the place to look before assuming the numbers are acceptable, because they are specific to the machine and the version.
Second, a host where you have root. If privileged containers are possible, veth pairs and bridge networking put the data path in the kernel and none of this applies. slirp4netns exists to work around the absence of privileges, and using it when privileges are available adds a moving part for nothing.
Third, an environment where unprivileged user namespaces are disabled or limited by policy. As noted above, slirp4netns does not create namespaces, it attaches networking to namespaces that already exist, so a host that blocks unshare blocks the whole approach no matter which networking tool you choose.
The realistic alternative is RootlessKit, which is listed in the README as a user of slirp4netns and is the usual entry point for a rootless container engine, since it sets up the user, mount and network namespaces and then delegates the networking. The difference in approach is that RootlessKit owns the namespace lifecycle and calls slirp4netns for you, while invoking slirp4netns directly gives you precise control over the flags, the MTU and the TAP device name. Another alternative is the slirp-cni-plugin, which presents the same user-mode network as a CNI plugin so that a Kubernetes or CNI aware runtime can request it declaratively. Between the three, a Kubernetes cluster should use the plugin path, an engineer experimenting with namespaces should call slirp4netns directly, and an application developer should let RootlessKit and the container engine handle it.
Editorial conclusion
slirp4netns is the right choice when you need networking for containers or namespaces that an unprivileged user created, on a host where veth pairs are unavailable to that user, and it is the piece that rootless Podman, Buildah, k3s and RootlessKit all lean on. It is the wrong tool for a throughput sensitive workload, because the path runs through a user-mode stack rather than kernel interfaces, and it is the wrong tool for a host where you simply have root and want kernel networking. Before you adopt it, check the linked libslirp version with slirp4netns --version, decide whether your distribution package is new enough, and confirm that the sysctl workarounds for unshare are acceptable on the hosts you target.
Frequently asked questions
What problem does slirp4netns solve?
Since Linux 3.8 unprivileged users can create network namespaces, but wiring them up with veth pairs still needs root. slirp4netns connects a TAP device in the namespace to a user-mode TCP/IP stack, giving the namespace internet access without privileges.
How do I install slirp4netns?
It is packaged on almost all Linux distributions, for example with `sudo apt-get install slirp4netns` on Debian and Ubuntu, and statically linked binaries are published for x86_64, aarch64, armv7l, s390x, ppc64le and riscv64. The README also points to an install from source section.
Which projects use slirp4netns?
The README lists Kubernetes distributions such as Usernetes and k3s, container engines including Podman, Buildah, ctnr, Docker with Moby and containerd with nerdctl, and tools including RootlessKit, become-root and the slirp-cni-plugin.
What does the --disable-host-loopback flag do in slirp4netns?
The README shows it in the start command alongside --configure and --mtu=65520. It prevents the namespace from reaching services bound to the host loopback address, which keeps the namespace isolated from the host.
How do I check which libslirp my slirp4netns is linked against?
Run slirp4netns --version, which prints the slirp4netns version, the commit, the libslirp version, SLIRP_CONFIG_VERSION_MAX and the libseccomp version. Since v1.0.0 the project can be linked with an arbitrary libslirp version, so this output is worth checking after a package upgrade.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rootless-containers-slirp4netns)Was this useful?