Skip to content

Instantly share code, notes, and snippets.

@digitalsignalperson
Last active July 9, 2026 19:00
Show Gist options
  • Select an option

  • Save digitalsignalperson/c4c14a00572c0f4ee028a474b103a80b to your computer and use it in GitHub Desktop.

Select an option

Save digitalsignalperson/c4c14a00572c0f4ee028a474b103a80b to your computer and use it in GitHub Desktop.
Example use of slirp4netns with bubblewrap
#!/bin/bash
status=$(mktemp -u)
mkfifo $status
# TODO error if slirp4netns not installed
set -e
cleanup() {
echo "cleanup"
rm -f "$status"
[[ ! -z "$BWRAP_PID" ]] && kill "$SLIRP_PID" 2>/dev/null && echo "killed bwrap"
[[ ! -z "$SLIRP_PID" ]] && kill "$SLIRP_PID" 2>/dev/null && echo "killed slirp"
}
trap cleanup EXIT
exec 4<<< "nameserver 10.0.2.3"
3>$status \
bwrap \
--symlink usr/bin /bin \
--symlink usr/bin /sbin \
--symlink usr/lib /lib \
--symlink usr/lib64 /lib64 \
--ro-bind /usr/bin /usr/bin \
--ro-bind /usr/lib /usr/lib \
--ro-bind /usr/lib64 /usr/lib64 \
--ro-bind /usr/share /usr/share \
--ro-bind /etc/ssl /etc/ssl \
--ro-bind /etc/ca-certificates /etc/ca-certificates \
--ro-bind /etc/fonts /etc/fonts \
--tmpfs /tmp \
--proc /proc \
--dev /dev \
--dev-bind /dev/dri/renderD129 /dev/dri/renderD129 \
--dev-bind /dev/dri/card1 /dev/dri/card1 \
--ro-bind /sys/dev/char /sys/dev/char \
--ro-bind /sys/devices /sys/devices \
--dir "$XDG_RUNTIME_DIR" \
--ro-bind "$XDG_RUNTIME_DIR/wayland-0" "$XDG_RUNTIME_DIR/wayland-0" \
--ro-bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0" \
--ro-bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse" \
--unshare-all \
--die-with-parent \
--new-session \
--bind $HOME/Downloads $HOME/Downloads \
--chdir $HOME \
--ro-bind-data 4 /etc/resolv.conf \
--json-status-fd 3 \
-- chromium --force-dark-mode --class=Chromium-Extra --ozone-platform=wayland &
# -- konsole &
# --ro-bind /etc/resolv.conf /etc/resolv.conf \
# --dev-bind /dev/dri/renderD130 /dev/dri/renderD130 \
# --dev-bind /dev/dri/card2 /dev/dri/card2 \
# --dev-bind /dev/dri /dev/dri \
BWRAP_PID=$!
echo "bwrap pid $BWRAP_PID"
while true; do
if read -r line < $status; then
CHILD_PID=$(echo "$line" | jq -r '.["child-pid"]')
if [[ -n $CHILD_PID ]]; then
echo "child pid $CHILD_PID"
break
fi
fi
done
echo "child pid $CHILD_PID"
slirp4bwrap $CHILD_PID &
SLIRP_PID=$!
echo "slirp pid $SLIRP_PID"
wait $BWRAP_PID
BWRAP_EXIT_STATUS=$?
kill "$SLIRP_PID"
wait "$SLIRP_PID" 2>/dev/null
exit "$BWRAP_EXIT_STATUS"
#define _GNU_SOURCE
#include <sched.h>
#include <linux/nsfs.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int get_parent_ns(int pid, const char *ns_type) {
char path[256];
snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns_type);
int ns_fd = open(path, O_RDONLY | O_CLOEXEC);
if (ns_fd == -1) {
perror("open");
exit(1);
}
int parent_ns_fd = ioctl(ns_fd, NS_GET_USERNS, &parent_ns_fd);
if (parent_ns_fd == -1) {
perror("NS_GET_USERNS");
exit(1);
}
return parent_ns_fd;
}
int main(int argc, char *argv[]) {
if (argc != 2)
exit(1);
char *slirp_args[] = {
"/usr/bin/slirp4netns",
"--configure",
"--enable-sandbox",
"--userns-path=/proc/self/ns/user",
"--disable-host-loopback",
argv[1],
"tap0",
NULL
};
int pid = atoi(argv[1]);
int fd = get_parent_ns(pid, "net");
if (setns(fd, 0) == -1) {
perror("setns");
exit(1);
}
execvp(slirp_args[0], slirp_args);
perror("execvp");
exit(1);
}
@rarensu

rarensu commented Jul 9, 2026

Copy link
Copy Markdown

what in the heck is slirp4bwrap?

@digitalsignalperson

digitalsignalperson commented Jul 9, 2026

Copy link
Copy Markdown
Author

Whoops forgot that existed (updated gist). This is what I arrived at before with a small C wrapper... maybe there is a better way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment