Codebase list slirp4netns / fresh-releases/upstream
Import upstream version 1.2.0 Debian Janitor 1 year, 11 months ago
52 changed file(s) with 2364 addition(s) and 987 deletion(s). Raw diff Collapse all Expand all
11 on: [push, pull_request]
22 jobs:
33 test-main:
4 runs-on: ubuntu-latest
4 runs-on: ubuntu-20.04
55 strategy:
66 matrix:
7 libslirp_commit: [master, v4.3.0, v4.2.0, v4.1.0]
7 libslirp_commit: [master, v4.7.0, v4.6.1, v4.1.0]
88 steps:
9 - uses: actions/checkout@v1
9 - uses: actions/checkout@v2
1010 - run: docker build -t slirp4netns-tests --build-arg LIBSLIRP_COMMIT -f Dockerfile.tests .
1111 env:
1212 LIBSLIRP_COMMIT: ${{ matrix.libslirp_commit }}
1313 - run: docker run --rm --privileged slirp4netns-tests
1414 test-build:
15 runs-on: ubuntu-latest
15 runs-on: ubuntu-20.04
1616 steps:
17 - uses: actions/checkout@v1
17 - uses: actions/checkout@v2
1818 - run: DOCKER_BUILDKIT=1 docker build -f Dockerfile.buildtests .
19 artifact:
20 runs-on: ubuntu-latest
19 test-centos7:
20 # vagrant is not installed on macOS 11 instances
21 runs-on: macos-10.15
22 env:
23 LIBSECCOMP_COMMIT: v2.3.3
24 LIBSLIRP_COMMIT: v4.1.0
25 BENCHMARK_IPERF3_DURATION: 3
2126 steps:
22 - uses: actions/checkout@v1
23 - run: DOCKER_BUILDKIT=1 docker build -o /tmp/artifact --target artifact -f Dockerfile.buildtests .
24 - run: (cd /tmp/artifact; sha256sum *)
25 - uses: actions/upload-artifact@v1
26 with:
27 name: slirp4netns-x86_64
28 path: /tmp/artifact/slirp4netns
27 - uses: actions/checkout@v2
28 - name: Setup CentOS 7 VM
29 run: |
30 vagrant up --provision --no-tty
31 cat > ./run-vagrant-tests <<'EOF'
32 exec vagrant ssh --no-tty -c "
33 export LIBSECCOMP_COMMIT=\"${LIBSECCOMP_COMMIT}\"
34 export LIBSLIRP_COMMIT=\"${LIBSLIRP_COMMIT}\"
35 export BENCHMARK_IPERF3_DURATION=\"${BENCHMARK_IPERF3_DURATION}\"
36 /src/build-and-test
37 "
38 EOF
39 - name: Build and test with Debian 10's version of libseccomp
40 run: sh ./run-vagrant-tests
41 - name: Build and test with Ubuntu 20.04's versions of libseccomp/libslirp
42 run: sh ./run-vagrant-tests
43 env:
44 LIBSECCOMP_COMMIT: v2.4.3
45 LIBSLIRP_COMMIT: v4.1.0
46 - name: Build and test with recent versions of libseccomp/libslirp
47 run: sh ./run-vagrant-tests
48 env:
49 LIBSECCOMP_COMMIT: v2.5.4
50 LIBSLIRP_COMMIT: v4.7.0
00 name: Release
11 on:
22 push:
3 tags:
4 - 'v*'
3 pull_request:
54
65 jobs:
76 release:
8 runs-on: ubuntu-latest
7 runs-on: ubuntu-20.04
98 steps:
10 - uses: actions/checkout@v1
11 - run: DOCKER_BUILDKIT=1 docker build -o /tmp/artifact --target artifact -f Dockerfile.buildtests .
12 - run: (cd /tmp/artifact; sha256sum *)
13 - uses: actions/create-release@v1
14 id: create_release
9 - uses: actions/checkout@v3
10 - uses: docker/setup-buildx-action@v1
11 - name: "Build binaries from Dockerfile.artifact"
12 run: docker buildx build -o /tmp --platform=amd64,arm64,arm,s390x,ppc64le,riscv64 -f Dockerfile.artifact .
13 - name: "Create /tmp/artifact"
14 run: |
15 mkdir -p /tmp/artifact
16 mv /tmp/linux_amd64/slirp4netns /tmp/artifact/slirp4netns-x86_64
17 mv /tmp/linux_arm64/slirp4netns /tmp/artifact/slirp4netns-aarch64
18 mv /tmp/linux_arm_v7/slirp4netns /tmp/artifact/slirp4netns-armv7l
19 mv /tmp/linux_s390x/slirp4netns /tmp/artifact/slirp4netns-s390x
20 mv /tmp/linux_ppc64le/slirp4netns /tmp/artifact/slirp4netns-ppc64le
21 mv /tmp/linux_riscv64/slirp4netns /tmp/artifact/slirp4netns-riscv64
22 - name: "SHA256SUMS"
23 run: (cd /tmp/artifact; sha256sum *) | tee /tmp/SHA256SUMS
24 - name: "The sha256sum of the SHA256SUMS file"
25 run: sha256sum /tmp/SHA256SUMS
26 - name: "Prepare the release note"
27 run: |
28 tag="${GITHUB_REF##*/}"
29 shasha=$(sha256sum /tmp/SHA256SUMS | awk '{print $1}')
30 libslirp_version=$(/tmp/artifact/slirp4netns-x86_64 -v | grep -oP '^libslirp: \K\S*')
31 libseccomp_version=$(/tmp/artifact/slirp4netns-x86_64 -v | grep -oP '^libseccomp: \K\S*')
32 ubuntu_version=$(grep -oP '^ARG UBUNTU_VERSION=\K\S*' Dockerfile.artifact)
33 cat << EOF | tee /tmp/release-note.txt
34 ${tag}
35
36 #### Changes
37 (To be documented)
38
39 #### Install
40 \`\`\`
41 curl -o slirp4netns --fail -L https://github.com/${{ github.repository }}/releases/download/${tag}/slirp4netns-\$(uname -m)
42 chmod +x slirp4netns
43 \`\`\`
44
45 #### About the binaries
46 The binaries are statically linked with libslirp ${libslirp_version} and libseccomp ${libseccomp_version} using Ubuntu ${ubuntu_version}.
47
48 The binaries were built automatically on GitHub Actions.
49 The build log is available for 90 days: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
50
51 The sha256sum of the SHA256SUMS file itself is \`${shasha}\` .
52 EOF
53 - name: "Create release"
54 if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
1555 env:
1656 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17 with:
18 tag_name: ${{ github.ref }}
19 release_name: ${{ github.ref }}
20 draft: true
21 - uses: actions/upload-release-asset@v1.0.1
22 env:
23 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 with:
25 upload_url: ${{ steps.create_release.outputs.upload_url }}
26 asset_path: /tmp/artifact/slirp4netns
27 asset_name: slirp4netns-x86_64
28 asset_content_type: application/octet-stream
57 run: |
58 tag="${GITHUB_REF##*/}"
59 asset_flags=()
60 for f in /tmp/artifact/* /tmp/SHA256SUMS; do asset_flags+=("-a" "$f"); done
61 hub release create "${asset_flags[@]}" -F /tmp/release-note.txt --draft "${tag}"
88 config.h
99 config.status
1010 INSTALL
11 /.vagrant
1112
1213 ################################################################################
1314 # https://github.com/github/gitignore/blob/c24cdc2175d7514d504d7f060a5d69675c8a9b50/Autotools.gitignore
5657 m4/ltoptions.m4
5758 m4/ltsugar.m4
5859 m4/ltversion.m4
59 m4/lt~obsolete.m4
60 m4/lt~obsolete.m4
0 ARG LIBSLIRP_COMMIT=v4.7.0
1 ARG UBUNTU_VERSION=22.04
2 ARG XX_VERSION=1.1.0
3
4 FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
5
6 FROM --platform=$BUILDPLATFORM ubuntu:${UBUNTU_VERSION} AS build-libslirp
7 ENV DEBIAN_FRONTEND=noninteractive
8 RUN apt-get update && apt-get install -y apt-utils automake autotools-dev make git ninja-build meson
9 RUN git clone https://git.qemu.org/libslirp.git /libslirp
10 WORKDIR /libslirp
11 ARG LIBSLIRP_COMMIT
12 RUN git pull && git checkout ${LIBSLIRP_COMMIT}
13 COPY --from=xx / /
14 ARG TARGETPLATFORM
15 RUN xx-apt-get install -y gcc libglib2.0-dev libcap-dev libseccomp-dev
16 COPY Dockerfile.artifact.d/meson-cross /meson-cross
17 RUN meson_setup_flags="--default-library=both" ; \
18 if xx-info is-cross; then meson_setup_flags="${meson_setup_flags} --cross-file=/meson-cross/$(xx-info) -Dprefix=/usr/local/$(xx-info)"; fi ; \
19 meson setup ${meson_setup_flags} build && ninja -C build install
20
21 FROM build-libslirp AS build
22 COPY . /src
23 WORKDIR /src
24 RUN ./autogen.sh && \
25 ./configure LDFLAGS="-static" --host=$(xx-info) && \
26 make && \
27 $(xx-info)-strip slirp4netns && \
28 xx-verify --static slirp4netns && \
29 cp -a slirp4netns /
30
31 FROM scratch
32 COPY --from=build /slirp4netns /slirp4netns
0 [binaries]
1 c = 'aarch64-linux-gnu-gcc'
2 cpp = 'aarch64-linux-gnu-g++'
3 ar = 'aarch64-linux-gnu-gcc-ar'
4 strip = 'aarch64-linux-gnu-strip'
5 pkgconfig = 'aarch64-linux-gnu-pkg-config'
6
7 [host_machine]
8 system = 'linux'
9 cpu_family = 'aarch64'
10 cpu = 'aarch64'
11 endian = 'little'
0 [binaries]
1 c = 'arm-linux-gnueabihf-gcc'
2 cpp = 'arm-linux-gnueabihf-g++'
3 ar = 'arm-linux-gnueabihf-gcc-ar'
4 strip = 'arm-linux-gnueabihf-strip'
5 pkgconfig = 'arm-linux-gnueabihf-pkg-config'
6
7 [host_machine]
8 system = 'linux'
9 cpu_family = 'arm'
10 cpu = 'armhf'
11 endian = 'little'
0 [binaries]
1 c = 'powerpc64le-linux-gnu-gcc'
2 cpp = 'powerpc64le-linux-gnu-g++'
3 ar = 'powerpc64le-linux-gnu-gcc-ar'
4 strip = 'powerpc64le-linux-gnu-strip'
5 pkgconfig = 'powerpc64le-linux-gnu-pkg-config'
6
7 [host_machine]
8 system = 'linux'
9 cpu_family = 'ppc64'
10 cpu = 'powerpc64le'
11 endian = 'little'
0 [binaries]
1 c = 'riscv64-linux-gnu-gcc'
2 cpp = 'riscv64-linux-gnu-g++'
3 ar = 'riscv64-linux-gnu-gcc-ar'
4 strip = 'riscv64-linux-gnu-strip'
5 pkgconfig = 'riscv64-linux-gnu-pkg-config'
6
7 [host_machine]
8 system = 'linux'
9 cpu_family = 'riscv64'
10 cpu = 'riscv64'
11 endian = 'little'
0 [binaries]
1 c = 's390x-linux-gnu-gcc'
2 cpp = 's390x-linux-gnu-g++'
3 ar = 's390x-linux-gnu-gcc-ar'
4 strip = 's390x-linux-gnu-strip'
5 pkgconfig = 's390x-linux-gnu-pkg-config'
6
7 [host_machine]
8 system = 'linux'
9 cpu_family = 's390x'
10 cpu = 's390x'
11 endian = 'big'
0 [binaries]
1 c = 'x86_64-linux-gnu-gcc'
2 cpp = 'x86_64-linux-gnu-g++'
3 ar = 'x86_64-linux-gnu-gcc-ar'
4 strip = 'x86_64-linux-gnu-strip'
5 pkgconfig = 'x86_64-linux-gnu-pkg-config'
6
7 [host_machine]
8 system = 'linux'
9 cpu_family = 'x86_64'
10 cpu = 'x86_64'
11 endian = 'little'
0 ARG LIBSLIRP_COMMIT=v4.3.0
0 ARG LIBSLIRP_COMMIT=v4.7.0
11
22 # Alpine
33 FROM alpine:3 AS buildtest-alpine3-static
4 RUN apk add --no-cache git build-base autoconf automake libtool linux-headers glib-dev glib-static libcap-static libcap-dev libseccomp-dev git meson
5 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
4 RUN apk add --no-cache git build-base autoconf automake libtool linux-headers glib-dev glib-static libcap-static libcap-dev libseccomp-dev libseccomp-static git meson
5 RUN git clone git://git.qemu.org/libslirp.git /libslirp
66 WORKDIR /libslirp
77 ARG LIBSLIRP_COMMIT
88 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both build && ninja -C build install
1212
1313 # Ubuntu
1414 FROM ubuntu:18.04 AS buildtest-ubuntu1804-common
15 ENV DEBIAN_FRONTEND=noninteractive
1516 RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
1617 RUN pip3 install meson
17 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
18 RUN git clone git://git.qemu.org/libslirp.git /libslirp
1819 WORKDIR /libslirp
1920 ARG LIBSLIRP_COMMIT
2021 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup build && ninja -C build install
2526 FROM buildtest-ubuntu1804-common AS buildtest-ubuntu1804-dynamic
2627 RUN ./configure && make && cp -f slirp4netns /
2728
28 # CentOS
29 FROM centos:7 AS buildtest-centos7-common
30 RUN yum install -y epel-release
31 RUN yum install -y autoconf automake gcc glib2-devel git make libcap-devel libseccomp-devel ninja-build python3-pip
32 RUN pip3 install meson
33 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
34 WORKDIR /libslirp
35 ARG LIBSLIRP_COMMIT
36 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both --prefix=/usr build && ninja-build -C build install
37 COPY . /src
38 WORKDIR /src
39 RUN ./autogen.sh
40
41 FROM buildtest-centos7-common AS buildtest-centos7-dynamic
42 RUN ./configure && make && cp -f slirp4netns /
43
44 FROM buildtest-centos7-common AS buildtest-centos7-static
45 RUN yum install -y glibc-static glib2-static
46 RUN yum-config-manager --add-repo=https://buildlogs.centos.org/centos/7/virt/x86_64/container && \
47 yum install --nogpgcheck -y libseccomp-static
48 RUN ./configure LDFLAGS="-static" && make && cp -f slirp4netns /
29 # CentOS 7 is no longer tested in this file.
30 # See Vagrantfile for CentOS 7 tests.
4931
5032 # openSUSE (dynamic only)
5133 FROM opensuse/leap:15 AS buildtest-opensuse15-common
5234 RUN zypper install -y --no-recommends autoconf automake gcc glib2-devel git make libcap-devel libseccomp-devel ninja python3-pip
5335 RUN pip3 install meson
54 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
36 RUN git clone git://git.qemu.org/libslirp.git /libslirp
5537 WORKDIR /libslirp
5638 ARG LIBSLIRP_COMMIT
5739 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both build && ninja -C build install
6244 FROM buildtest-opensuse15-common AS buildtest-opensuse15-dynamic
6345 RUN ./configure && make && cp -f slirp4netns /
6446
65 # artifact for GitHub actions
66 FROM scratch AS artifact
67 COPY --from=buildtest-centos7-static /slirp4netns /slirp4netns
68
6947 FROM scratch AS buildtest-final-stage
7048 COPY --from=buildtest-alpine3-static /slirp4netns /buildtest-alpine3-static
7149 COPY --from=buildtest-ubuntu1804-dynamic /slirp4netns /buildtest-ubuntu1804-dynamic
72 COPY --from=buildtest-centos7-dynamic /slirp4netns /buildtest-centos7-dynamic
73 COPY --from=buildtest-centos7-static /slirp4netns /buildtest-centos7-static
7450 COPY --from=buildtest-opensuse15-dynamic /slirp4netns /buildtest-opensuse15-dynamic
0 ARG LIBSLIRP_COMMIT=v4.3.0
0 ARG LIBSLIRP_COMMIT=v4.7.0
11
2 FROM ubuntu:18.04 AS build
2 FROM ubuntu:22.04 AS build
3 ENV DEBIAN_FRONTEND=noninteractive
34 RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
45 RUN pip3 install meson
5 RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
6 RUN git clone git://git.qemu.org/libslirp.git /libslirp
67 WORKDIR /libslirp
78 ARG LIBSLIRP_COMMIT
89 RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup build && ninja -C build install
1415
1516 FROM build AS test
1617 USER 0
17 RUN apt update && apt install -y git libtool iproute2 clang clang-format clang-tidy iputils-ping iperf3 nmap jq
18 RUN apt update && apt install -y git libtool iproute2 clang clang-format clang-tidy iputils-ping iperf3 ncat jq udhcpc
1819 USER 1000:1000
1920 CMD ["make", "ci"]
77 # An approver may approve PRs and ship releases without waiting for LGTMs from other approvers.
88 # However, the approver should try to get LGTMs from other approvers for significant changes.
99 #
10 # Release guide (since v0.4.3):
11 # 1. Bump up the version string to `vX.Y.Z` (or `vX.Y.Z-beta.W`) in `configure.ac`.
12 # 2. `git commit -a -s -m vX.Y.Z`
13 # 3. Bump up the version string to `vX.Y.Z+dev` (or `vX.Y.Z-beta.W`+dev) in `configure.ac`.
14 # 4. `git commit -a -s -m vX.Y.Z+dev`
15 # 5. Open a PR and merge it.
16 # 6. Create a tag `v.X.Y.Z` for the `vX.Y.Z` commit, and push the tag to the upstream: `git push upstream vX.Y.Z`
17 # 7. GitHub Actions automatically ships a draft release with a statically compiled binary: https://github.com/rootless-containers/slirp4netns/releases
18 # If it fails, check the GitHub Actions log: https://github.com/rootless-containers/slirp4netns/actions?query=workflow%3ARelease
19 # 8. Add release notes to the draft release and ship the release.
10 # Release guide (since v1.1.1):
11 # 1. Bump up the version string in `configure.ac` to `vX.Y.Z` (or `vX.Y.Z-beta.W`)
12 # 2. `git commit -a -s -m vX.Y.Z`
13 # 3. Bump up the version string to `vX.Y.Z+dev` (or `vX.Y.Z-beta.W+dev`)
14 # 4. `git commit -a -s -m vX.Y.Z+dev`
15 # 5. Open a PR and merge it.
16 # 6. Create a tag `v.X.Y.Z` for the `vX.Y.Z` commit, with a GPG sign: `git tag -s vX.Y.Z <commit>`
17 # 7. Push the tag to the upstream: `git push upstream vX.Y.Z`
18 # 8. GitHub Actions automatically ships a draft release with statically compiled binaries `slirp4netns-$(uname -m)` and `SHA256SUMS`: https://github.com/rootless-containers/slirp4netns/releases
19 # If it fails, check the GitHub Actions log: https://github.com/rootless-containers/slirp4netns/actions?query=workflow%3ARelease
20 # 9. Sign `SHA256SUMS`: `gpg --detach-sign -a SHA256SUMS`
21 # This command will create `SHA256SUMS.asc`. Make sure to use the same GPG key used for `git tag -s vX.Y.Z <commit>`.
22 # 10. Attach `SHA256SUMS.asc` and add release note texts to the draft release, and ship the release.
2023 [Org.Approvers]
2124 people = [
2225 "akihirosuda",
44 noinst_LIBRARIES = libparson.a
55
66 AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$(PATH)"
7 TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh
7 TESTS = tests/test-slirp4netns-api-socket.sh \
8 tests/test-slirp4netns-cidr.sh \
9 tests/test-slirp4netns-configure.sh \
10 tests/test-slirp4netns-dhcp.sh \
11 tests/test-slirp4netns-disable-dns.sh \
12 tests/test-slirp4netns-disable-host-loopback.sh \
13 tests/test-slirp4netns-exit-fd.sh \
14 tests/test-slirp4netns-macaddress.sh \
15 tests/test-slirp4netns-nspath.sh \
16 tests/test-slirp4netns-outbound-addr.sh \
17 tests/test-slirp4netns-ready-fd.sh \
18 tests/test-slirp4netns-sandbox.sh \
19 tests/test-slirp4netns-sandbox-no-unmount.sh \
20 tests/test-slirp4netns-seccomp.sh
821
922 EXTRA_DIST = \
1023 slirp4netns.1.md \
1427 slirp4netns.h \
1528 api.h \
1629 sandbox.h \
30 seccomparch.h \
1731 seccompfilter.h \
18 tests/slirp4netns-no-unmount.sh \
32 seccompfilter_rules.h \
1933 vendor/parson/LICENSE \
2034 vendor/parson/README.md \
2135 vendor/parson/parson.h
2236
2337 # define specific commit if git available or it was replaced during git-archive creation
24 COMMIT := $(shell V=6a7b16babc95b6a3056b33fb45b74a6f62262dd4 ; \
38 COMMIT := $(shell V=656041d45cfca7a4176f6b7eed9e4fe6c11e8383 ; \
2539 expr match "$$V" ormat: >/dev/null \
2640 && (cd "$$abs_srcdir" && [ -d .git ] && git describe --always --abbrev=0 --dirty --exclude=\* || echo unknown) \
2741 || echo "$$V" )
3852 generate-man:
3953 go-md2man -in slirp4netns.1.md -out slirp4netns.1
4054
41 CLANGTIDY = clang-tidy -warnings-as-errors='*'
55 # clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling is disabled because too nitpicky: https://github.com/rootless-containers/slirp4netns/issues/216
56 CLANGTIDY = clang-tidy -warnings-as-errors='*' --checks='-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling'
4257
4358 CLANGFORMAT = clang-format
4459
5267 $(CLANGFORMAT) -i $(slirp4netns_SOURCES)
5368
5469 benchmark:
55 benchmarks/benchmark-iperf3.sh
56 benchmarks/benchmark-iperf3-reverse.sh
70 "$(abs_srcdir)/benchmarks/benchmark-iperf3.sh"
71 "$(abs_srcdir)/benchmarks/benchmark-iperf3-reverse.sh"
5772
5873 ci:
5974 $(MAKE) indent
60 git diff --exit-code
75 git -C "$(abs_srcdir)" diff --exit-code
6176 # TODO: make sure ./vendor is synced with ./vendor.sh
6277 $(MAKE) lint
6378 $(MAKE) -j $(shell nproc) distcheck || ( find . -name test-suite.log | xargs cat; exit 1 )
00 # slirp4netns: User-mode networking for unprivileged network namespaces
11
22 slirp4netns provides user-mode networking ("slirp") for unprivileged network namespaces.
3
4 <!-- START doctoc generated TOC please keep comment here to allow auto update -->
5 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
6
7
8 - [Motivation](#motivation)
9 - [Projects using slirp4netns](#projects-using-slirp4netns)
10 - [Maintenance policy](#maintenance-policy)
11 - [Quick start](#quick-start)
12 - [Install](#install)
13 - [Usage](#usage)
14 - [Manual](#manual)
15 - [Benchmarks](#benchmarks)
16 - [iperf3 (netns -> host)](#iperf3-netns---host)
17 - [Install from source](#install-from-source)
18 - [Acknowledgement](#acknowledgement)
19 - [License](#license)
20
21 <!-- END doctoc generated TOC please keep comment here to allow auto update -->
322
423 ## Motivation
524
625 Starting with Linux 3.8, unprivileged users can create [`network_namespaces(7)`](http://man7.org/linux/man-pages/man7/network_namespaces.7.html) along with [`user_namespaces(7)`](http://man7.org/linux/man-pages/man7/user_namespaces.7.html).
726 However, unprivileged network namespaces had not been very useful, because creating [`veth(4)`](http://man7.org/linux/man-pages/man4/veth.4.html) pairs across the host and network namespaces still requires the root privileges. (i.e. No internet connection)
827
9 slirp4netns allows connecting a network namespace to the Internet in a completely unprivileged way, by connecting a TAP device in a network namespace to the usermode TCP/IP stack ("slirp").
28 slirp4netns allows connecting a network namespace to the Internet in a completely unprivileged way, by connecting a TAP device in a network namespace to the usermode TCP/IP stack (["slirp"](https://gitlab.freedesktop.org/slirp/libslirp)).
1029
1130 ## Projects using slirp4netns
1231
1938 * [Buildah](https://github.com/containers/buildah)
2039 * [ctnr](https://github.com/mgoltzsche/ctnr) (via slirp-cni-plugin)
2140 * [Docker & Moby](https://get.docker.com/rootless) (optionally, via RootlessKit)
41 * [containerd/nerdctl](https://github.com/containerd/nerdctl) (optionally, via RootlessKit)
2242
2343 Tools:
2444 * [RootlessKit](https://github.com/rootless-containers/rootlesskit)
2949
3050 Version | Status
3151 -------------------------------|------------------------------------------------------------------------
32 v1.0.x | :white_check_mark: Active
33 v0.4.x | :white_check_mark: Active (EOL: Sep 30, 2020)
34 v0.3.x | :warning: End of Life (Mar 31, 2020)
35 v0.2.x | :warning: End of Life (Aug 30, 2019)
36 Early versions prior to v0.2.x | :warning: End of Life (Jan 5, 2019)
52 v1.2.x | :white_check_mark: Active
53 v1.1.x | End of Life (May 2, 2022)
54 v1.0.x | End of Life (Jun 2, 2020)
55 v0.4.x | End of Life (Sep 30, 2020)
56 v0.3.x | End of Life (Mar 31, 2020)
57 v0.2.x | End of Life (Aug 30, 2019)
58 Early versions prior to v0.2.x | End of Life (Jan 5, 2019)
3759
3860 See https://github.com/rootless-containers/slirp4netns/releases for the releases.
3961
62 ### Security advisories
4063 See https://github.com/rootless-containers/slirp4netns/security/advisories for the past security advisories.
4164
65 :warning: We had been collecting [the vulnerabilities of QEMU/libslirp](https://www.cvedetails.com/product/57329/Libslirp-Project-Libslirp.html?vendor_id=20192) in this slirp4netns repo until the end of 2020,
66 as the slirp4netns releases prior to v1.0.0 were always statically linked with a specific version of QEMU/libslirp.
67 Starting with 2021, the vulnerabilities of libslirp are no longer collected in this slirp4netns repo, as slirp4netns >= v1.0.0 can be linked with an arbitrary version of libslirp.
68
69 <details>
70 <summary> Run <code>slirp4netns --version</code> to check the version of the linked libslirp. </summary>
71
72 <p>
73
74 ```console
75 $ slirp4netns --version
76 slirp4netns version 1.1.8
77 commit: d361001f495417b880f20329121e3aa431a8f90f
78 libslirp: 4.4.0
79 SLIRP_CONFIG_VERSION_MAX: 3
80 libseccomp: 2.4.3
81 ```
82
83 </p>
84
85 </details>
86
4287 ## Quick start
4388
44 ### Install from source
45
46 Build dependencies:
47 * `glib2-devel` (`libglib2.0-dev`)
48 * `libslirp-devel` >= 4.1 (`libslirp-dev`)
49 * `libcap-devel` (`libcap-dev`)
50 * `libseccomp-devel` (`libseccomp-dev`)
51
52 Install steps:
53
54 ```console
55 $ ./autogen.sh
56 $ ./configure --prefix=/usr
57 $ make
58 $ sudo make install
59 ```
60
61 * To build `slirp4netns` as a static binary, please run `./configure` with `LDFLAGS=-static`.
62 * If you set `--prefix` to `$HOME`, you don't need to run `make install` with `sudo`.
63
64 ### Install from binary
65
66 #### RHEL 8 & [Fedora (28 or later)](https://src.fedoraproject.org/rpms/slirp4netns):
67
68 ```console
69 $ sudo dnf install slirp4netns
70 ```
71
72 #### RHEL/CentOS 7.7
73
74 ```console
75 $ sudo yum install slirp4netns
76 ```
77
78 #### [RHEL/CentOS 7.6](https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/)
79
80 ```console
81 $ sudo curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
82 $ sudo yum install slirp4netns
83 ```
84
85 You might need to enable user namespaces manually:
86 ```console
87 $ sudo sh -c 'echo "user.max_user_namespaces=28633" > /etc/sysctl.d/userns.conf'
88 $ sudo sysctl -p /etc/sysctl.d/userns.conf
89 ```
90
91 #### [Arch Linux](https://www.archlinux.org/packages/community/x86_64/slirp4netns/):
92
93 ```console
94 $ sudo pacman -S slirp4netns
95 ```
96
97 You might need to enable user namespaces manually:
98 ```console
99 $ sudo sh -c "echo 1 > /proc/sys/kernel/unprivileged_userns_clone"
100 ```
101
102 #### [openSUSE Tumbleweed](https://build.opensuse.org/package/show/openSUSE%3AFactory/slirp4netns)
103
104 ```console
105 $ sudo zypper install slirp4netns
106 ```
107
108 #### [openSUSE Leap 15.0](https://build.opensuse.org/package/show/devel%3Akubic/slirp4netns)
109
110 ```console
111 $ sudo zypper addrepo --refresh http://download.opensuse.org/repositories/devel:/kubic/openSUSE_Leap_15.0/devel:kubic.repo
112 $ sudo zypper install slirp4netns
113 ```
114
115 #### [SUSE Linux Enterprise 15](https://build.opensuse.org/package/show/devel%3Akubic/slirp4netns)
116
117 ```console
118 $ sudo zypper addrepo --refresh http://download.opensuse.org/repositories/devel:/kubic/SLE_15/devel:kubic.repo
119 $ sudo zypper install slirp4netns
120 ```
121
122 #### [Debian GNU/Linux (10 or later)](https://packages.debian.org/buster/slirp4netns) & [Ubuntu (19.04 or later)](https://packages.ubuntu.com/disco/slirp4netns)
123
124 ```console
125 $ sudo apt install slirp4netns
126 ```
127
128 #### [NixOS](https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/networking/slirp4netns)
129
130 ```console
131 $ nix-env -i slirp4netns
132 ```
133
134 #### [Gentoo Linux](https://packages.gentoo.org/packages/app-emulation/slirp4netns)
135
136 ```console
137 $ sudo emerge app-emulation/slirp4netns
138 ```
139
140 #### [Slackware](https://git.slackbuilds.org/slackbuilds/tree/network/slirp4netns)
141
142 ```console
143 $ sudo sbopkg -i slirp4netns
144 ```
145
146 #### [Void Linux](https://github.com/void-linux/void-packages/tree/master/srcpkgs/slirp4netns)
147
148 ```console
149 $ sudo xbps-install slirp4netns
150 ```
89 ### Install
90
91 Statically linked binaries available for x86\_64, aarch64, armv7l, s390x, ppc64le, and riscv64: https://github.com/rootless-containers/slirp4netns/releases
92
93 Also available as a package on almost all Linux distributions:
94 * [RHEL/CentOS (since 7.7 and 8.0)](https://pkgs.org/search/?q=slirp4netns)
95 * [Fedora (since 28)](https://src.fedoraproject.org/rpms/slirp4netns)
96 * [Arch Linux](https://www.archlinux.org/packages/community/x86_64/slirp4netns/)
97 * [openSUSE (since Leap 15.0)](https://build.opensuse.org/package/show/openSUSE%3AFactory/slirp4netns)
98 * [SUSE Linux Enterprise (since 15)](https://build.opensuse.org/package/show/devel%3Akubic/slirp4netns)
99 * [Debian GNU/Linux (since 10.0)](https://packages.debian.org/buster/slirp4netns)
100 * [Ubuntu (since 19.04)](https://packages.ubuntu.com/search?keywords=slirp4netns)
101 * [NixOS](https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/networking/slirp4netns)
102 * [Gentoo Linux](https://packages.gentoo.org/packages/app-emulation/slirp4netns)
103 * [Slackware](https://git.slackbuilds.org/slackbuilds/tree/network/slirp4netns)
104 * [Void Linux](https://github.com/void-linux/void-packages/tree/master/srcpkgs/slirp4netns)
105 * [Alpine Linux (since 3.14)](https://pkgs.alpinelinux.org/packages?name=slirp4netns)
106
107 e.g.
108
109 ```console
110 $ sudo apt-get install slirp4netns
111 ```
112
113 To install slirp4netns from the source, see [Install from source](#install-from-source).
151114
152115 ### Usage
153116
154 Terminal 1: Create user/network/mount namespaces
155 ```console
156 $ unshare --user --map-root-user --net --mount
157 unshared$ echo $$ > /tmp/pid
158 ```
159
160 Terminal 2: Start slirp4netns
161 ```console
162 $ slirp4netns --configure --mtu=65520 --disable-host-loopback $(cat /tmp/pid) tap0
117 **Terminal 1**: Create user/network/mount namespaces
118
119 ```console
120 (host)$ unshare --user --map-root-user --net --mount
121 (namespace)$ echo $$ > /tmp/pid
122 ```
123
124 In this documentation, we use `(host)$` as the prompt of the host shell, `(namespace)$` as the prompt of the shell running in the namespaces.
125
126 If `unshare` fails, try the following commands (known to be needed on Debian, Arch, and old CentOS 7.X):
127
128 ```console
129 (host)$ sudo sh -c 'echo "user.max_user_namespaces=28633" >> /etc/sysctl.d/userns.conf'
130 (host)$ [ -f /proc/sys/kernel/unprivileged_userns_clone ] && sudo sh -c 'echo "kernel.unprivileged_userns_clone=1" >> /etc/sysctl.d/userns.conf'
131 (host)$ sudo sysctl --system
132 ```
133
134 **Terminal 2**: Start slirp4netns
135
136 ```console
137 (host)$ slirp4netns --configure --mtu=65520 --disable-host-loopback $(cat /tmp/pid) tap0
163138 starting slirp, MTU=65520
164139 ...
165140 ```
166141
167 Terminal 1: Make sure the `tap0` is configured and connected to the Internet
168 ```console
169 unshared$ ip a
142 **Terminal 1**: Make sure the `tap0` is configured and connected to the Internet
143
144 ```console
145 (namespace)$ ip a
170146 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
171147 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
172148 3: tap0: <BROADCAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
175151 valid_lft forever preferred_lft forever
176152 inet6 fe80::c028:cff:fe0e:2906/64 scope link
177153 valid_lft forever preferred_lft forever
178 unshared$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
179 unshared$ mount --bind /tmp/resolv.conf /etc/resolv.conf
180 unshared$ curl https://example.com
181 ```
182
183 See [`slirp4netns.1.md`](slirp4netns.1.md) for further information.
154 (namespace)$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
155 (namespace)$ mount --bind /tmp/resolv.conf /etc/resolv.conf
156 (namespace)$ curl https://example.com
157 ```
158
159 ## Manual
160
161 Manual: [`slirp4netns.1.md`](slirp4netns.1.md)
162
163 * [Description](./slirp4netns.1.md#description)
164 * [Options](./slirp4netns.1.md#options)
165 * [Example](./slirp4netns.1.md#example)
166 * [Routing ping packets](./slirp4netns.1.md#routing-ping-packets)
167 * [API socket](./slirp4netns.1.md#api-socket)
168 * [Defined namespace paths](./slirp4netns.1.md#defined-namespace-paths)
169 * [Outbound addresses](./slirp4netns.1.md#outbound-addresses)
170 * [Inter-namespace communication](./slirp4netns.1.md#inter-namespace-communication)
171 * [Inter-host communication](./slirp4netns.1.md#inter-host-communication)
172 * [Bugs](./slirp4netns.1.md#bugs)
184173
185174 ## Benchmarks
186175
196185
197186 slirp4netns is faster than [vde_plug](https://github.com/rd235/vdeplug_slirp) and [VPNKit](https://github.com/moby/vpnkit) because slirp4netns is optimized to avoid copying packets across the namespaces.
198187
199 The latest revision of slirp4netns is regularly benchmarked (`make benchmark`) on Travis: https://travis-ci.org/rootless-containers/slirp4netns
188 The latest revision of slirp4netns is regularly benchmarked (`make benchmark`) on [CI](https://github.com/rootless-containers/slirp4netns/actions?query=workflow%3AMain).
189
190 ## Install from source
191
192 Build dependencies (`apt-get`):
193
194 ```console
195 $ sudo apt-get install libglib2.0-dev libslirp-dev libcap-dev libseccomp-dev
196 ```
197
198 Build dependencies (`dnf`):
199
200 ```console
201 $ sudo dnf install glib2-devel libslirp-devel libcap-devel libseccomp-devel
202 ```
203
204 Installation steps:
205
206 ```console
207 $ ./autogen.sh
208 $ ./configure --prefix=/usr
209 $ make
210 $ sudo make install
211 ```
212
213 * [libslirp](https://gitlab.freedesktop.org/slirp/libslirp) needs to be v4.1.0 or later.
214 * To build `slirp4netns` as a static binary, run `./configure` with `LDFLAGS=-static`.
215 * If you set `--prefix` to `$HOME`, you don't need to run `make install` with `sudo`.
200216
201217 ## Acknowledgement
202218 See [`vendor/README.md`](./vendor/README.md).
0 Vagrant.configure("2") do |config|
1 require 'etc'
2 config.vm.provider "virtualbox" do |vbox|
3 vbox.cpus = [1, Etc.nprocessors].max
4 # Change VirtualBox itself's slirp CIDR so that it doesn't conflict with slirp4netns
5 vbox.customize ["modifyvm", :id, "--natnet1", "10.0.200.0/24"]
6 end
7 config.vm.box = "centos/7"
8 config.vm.synced_folder ".", "/vagrant", disabled: true
9 config.vm.synced_folder ".", "/src/slirp4netns", type: "rsync"
10 config.vm.provision "shell",
11 inline: <<~'SHELL'
12 set -xeu
13 sysctl user.max_user_namespaces=65536
14
15 yum install -y \
16 epel-release \
17 https://repo.ius.io/ius-release-el7.rpm
18
19 yum install -y \
20 autoconf automake make gcc gperf libtool \
21 git-core meson ninja-build \
22 glib2-devel libcap-devel \
23 git-core libtool iproute iputils iperf3 nmap jq
24
25 # TODO: install udhcpc (required by test-slirp4netns-dhcp.sh)
26
27 cd /src
28 chown vagrant .
29
30 su vagrant -c '
31 set -xeu
32
33 git clone --depth=1 --no-checkout https://github.com/seccomp/libseccomp
34 git -C ./libseccomp fetch --tags --depth=1
35
36 git clone --depth=1 --no-checkout git://git.qemu.org/libslirp.git
37 git -C ./libslirp fetch --tags --depth=1
38
39 touch ./build-and-test
40 chmod a+x ./build-and-test
41 '
42
43 cat > ./build-and-test <<'EOS'
44 #! /bin/sh
45 set -xeu
46 src_dir='/src'
47
48 prefix="${PREFIX:-${HOME}/prefix}"
49 build_root="${BUILD_ROOT:-${prefix}/build}"
50 rm -rf "${prefix}" "${build_root}"
51 mkdir -p "${build_root}"
52
53 export CFLAGS="-I${prefix}"
54 export LDFLAGS="-L${prefix} -Wl,-rpath,${prefix}/lib"
55 export PKG_CONFIG_PATH="${prefix}/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"
56
57 git -C "${src_dir}/libseccomp" fetch --depth=1 origin "${LIBSECCOMP_COMMIT:-v2.4.3}"
58 git -C "${src_dir}/libseccomp" checkout FETCH_HEAD
59 ( cd "${src_dir}/libseccomp" && ./autogen.sh )
60 mkdir "${build_root}/libseccomp"
61 pushd "${build_root}/libseccomp"
62 "${src_dir}/libseccomp/configure" --prefix="${prefix}"
63 make -j "$( nproc )" CFLAGS+="-I$( pwd )/include"
64 make install
65 popd
66
67 git -C "${src_dir}/libslirp" fetch --depth=1 origin "${LIBSLIRP_COMMIT:-v4.1.0}"
68 git -C "${src_dir}/libslirp" checkout FETCH_HEAD
69 mkdir "${build_root}/libslirp"
70 pushd "${build_root}/libslirp"
71 meson setup --prefix="${prefix}" --libdir=lib . "${src_dir}/libslirp"
72 ninja -C . install
73 popd
74
75 ( cd "${src_dir}/slirp4netns" && ./autogen.sh )
76 mkdir "${build_root}/slirp4netns"
77 pushd "${build_root}/slirp4netns"
78 "${src_dir}/slirp4netns/configure" --prefix="${prefix}"
79 make -j "$( nproc )"
80
81 make ci 'CLANGTIDY=echo skipping:' 'CLANGFORMAT=echo skipping:'
82 popd
83 EOS
84 SHELL
85 end
9393 static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx,
9494 JSON_Object *jo)
9595 {
96 int wrc = 0, slirprc = 0;
96 int wrc = 0;
9797 char idbuf[64];
9898 const char *proto_s = json_object_dotget_string(jo, "arguments.proto");
9999 const char *host_addr_s =
155155 free(fwd);
156156 goto finish;
157157 }
158 if ((slirprc = slirp_add_hostfwd(slirp, fwd->is_udp, fwd->host_addr,
159 fwd->host_port, fwd->guest_addr,
160 fwd->guest_port)) < 0) {
158 if (slirp_add_hostfwd(slirp, fwd->is_udp, fwd->host_addr, fwd->host_port,
159 fwd->guest_addr, fwd->guest_port) < 0) {
161160 const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
162161 "slirp_add_hostfwd failed\"}}";
163162 wrc = write(fd, err, strlen(err));
2929 }
3030 trap cleanup EXIT
3131
32 iperf3 -c 127.0.0.1 -p 15201 -t 60
32 iperf3 -c 127.0.0.1 -p 15201 -t "${BENCHMARK_IPERF3_DURATION:-60}"
2222 }
2323 trap cleanup EXIT
2424
25 nsenter --preserve-credentials -U -n --target=$child iperf3 -c 10.0.2.2 -t 60
25 nsenter --preserve-credentials -U -n --target=$child iperf3 -c 10.0.2.2 -t "${BENCHMARK_IPERF3_DURATION:-60}"
00 AC_PREREQ([2.69])
1 AC_INIT([slirp4netns], [1.0.1], [https://github.com/rootless-containers/slirp4netns/issues])
1 AC_INIT([slirp4netns], [1.2.0], [https://github.com/rootless-containers/slirp4netns/issues])
22 AC_CONFIG_SRCDIR([main.c])
33 AC_CONFIG_HEADERS([config.h])
44
55 AC_PROG_CC
66 AC_PROG_RANLIB
77
8 AM_INIT_AUTOMAKE([1.9 foreign subdir-objects])
8 AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
9 AM_PROG_AR
910
1011 AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h sys/socket.h sys/timeb.h unistd.h getopt.h])
1112
2829 AC_FUNC_FORK
2930 AC_FUNC_MALLOC
3031 AC_FUNC_REALLOC
31 AC_CHECK_FUNCS([atexit clock_gettime dup2 getopt_long inet_ntoa memmove memset mkdir regcomp rmdir socket strcasecmp strchr strdup strerror strstr strtol strtoul])
32 AC_CHECK_FUNCS([atexit clock_gettime dup2 getopt_long memmove memset mkdir regcomp rmdir socket strcasecmp strchr strdup strerror strstr strtol strtoul])
3233
3334 PKG_CHECK_MODULES(GLIB, glib-2.0)
3435 PKG_CHECK_MODULES(SLIRP, slirp >= 4.1.0)
+0
-148
hack/release.sh less more
0 #!/bin/bash
1 # release.sh: configurable signed-artefact release script
2 # Copyright (C) 2016-2019 SUSE LLC.
3 #
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8 set -Eeuo pipefail
9
10 ## --->
11 # Project-specific options and functions. In *theory* you shouldn't need to
12 # touch anything else in this script in order to use this elsewhere.
13 project="slirp4netns"
14 root="$(readlink -f "$(dirname "${BASH_SOURCE}")/..")"
15
16 # Make pushd and popd silent.
17 function pushd() { command pushd "$@" &>/dev/null ; }
18 function popd() { command popd "$@" &>/dev/null ; }
19
20 # These functions allow you to configure how the defaults are computed.
21 function get_arch() { uname -m ; }
22 function get_version() { echo '@VERSION@' | "$root/config.status" --file - ; }
23
24 # Any pre-configuration steps should be done here -- for instance ./configure.
25 function setup_project() {
26 pushd "$root"
27 [ -x ./configure ] || ./autogen.sh
28 ./configure LDFLAGS="-static" --prefix=/ --bindir=/bin
29 popd
30 }
31
32 # This function takes an output path as an argument, where the built
33 # (preferably static) binary should be placed.
34 function build_project() {
35 tmprootfs="$(mktemp -d --tmpdir "$project-build.XXXXXX")"
36
37 make -C "$root" clean all install DESTDIR="$tmprootfs"
38
39 mv "$tmprootfs/bin/slirp4netns" "$1"
40 rm -rf "$tmprootfs"
41 }
42 # End of the easy-to-configure portion.
43 ## <---
44
45 # Print usage information.
46 function usage() {
47 echo "usage: release.sh [-h] [-v <version>] [-c <commit>] [-o <output-dir>]" >&2
48 echo " [-H <hashcmd>] [-S <gpg-key>]" >&2
49 }
50
51 # Log something to stderr.
52 function log() {
53 echo "[*]" "$@" >&2
54 }
55
56 # Log something to stderr and then exit with 0.
57 function quit() {
58 log "$@"
59 exit 0
60 }
61
62 # Conduct a sanity-check to make sure that GPG provided with the given
63 # arguments can sign something. Inability to sign things is not a fatal error.
64 function gpg_cansign() {
65 gpg "$@" --clear-sign </dev/null >/dev/null
66 }
67
68 # When creating releases we need to build (ideally static) binaries, an archive
69 # of the current commit, and generate detached signatures for both.
70 keyid=""
71 version=""
72 arch=""
73 commit="HEAD"
74 hashcmd="sha256sum"
75 while getopts ":h:v:c:o:S:H:" opt; do
76 case "$opt" in
77 S)
78 keyid="$OPTARG"
79 ;;
80 c)
81 commit="$OPTARG"
82 ;;
83 o)
84 outputdir="$OPTARG"
85 ;;
86 v)
87 version="$OPTARG"
88 ;;
89 H)
90 hashcmd="$OPTARG"
91 ;;
92 h)
93 usage ; exit 0
94 ;;
95 \:)
96 echo "Missing argument: -$OPTARG" >&2
97 usage ; exit 1
98 ;;
99 \?)
100 echo "Invalid option: -$OPTARG" >&2
101 usage ; exit 1
102 ;;
103 esac
104 done
105
106 # Run project setup first...
107 ( set -x ; setup_project )
108
109 # Generate the defaults for version and so on *after* argument parsing and
110 # setup_project, to avoid calling get_version() needlessly.
111 version="${version:-$(get_version)}"
112 arch="${arch:-$(get_arch)}"
113 outputdir="${outputdir:-release/$version}"
114
115 log "[[ $project ]]"
116 log "version: $version"
117 log "commit: $commit"
118 log "output_dir: $outputdir"
119 log "key: ${keyid:-(default)}"
120 log "hash_cmd: $hashcmd"
121
122 # Make explicit what we're doing.
123 set -x
124
125 # Make the release directory.
126 rm -rf "$outputdir" && mkdir -p "$outputdir"
127
128 # Build project.
129 build_project "$outputdir/$project.$arch"
130
131 # Generate new archive.
132 git archive --format=tar --prefix="$project-$version/" "$commit" | xz > "$outputdir/$project.tar.xz"
133
134 # Generate sha256 checksums for both.
135 ( cd "$outputdir" ; "$hashcmd" "$project".{"$arch",tar.xz} > "$project.$hashcmd" ; )
136
137 # Set up the gpgflags.
138 gpgflags=()
139 [[ -z "$keyid" ]] || gpgflags+=("--default-key=$keyid")
140 gpg_cansign "${gpgflags[@]}" || quit "Could not find suitable GPG key, skipping signing step."
141
142 # Sign everything.
143 gpg "${gpgflags[@]}" --detach-sign --armor "$outputdir/$project.$arch"
144 gpg "${gpgflags[@]}" --detach-sign --armor "$outputdir/$project.tar.xz"
145 gpg "${gpgflags[@]}" --clear-sign --armor \
146 --output "$outputdir/$project.$hashcmd"{.tmp,} && \
147 mv "$outputdir/$project.$hashcmd"{.tmp,}
+426
-18
main.c less more
1010 #include <sys/ioctl.h>
1111 #include <sys/socket.h>
1212 #include <sys/types.h>
13 #include <sys/un.h>
1314 #include <sys/wait.h>
1415 #include <linux/if_tun.h>
1516 #include <arpa/inet.h>
2021 #include <regex.h>
2122 #include <libslirp.h>
2223 #include "slirp4netns.h"
24 #include <ifaddrs.h>
25 #include <seccomp.h>
2326
2427 #define DEFAULT_MTU (1500)
2528 #define DEFAULT_CIDR ("10.0.2.0/24")
2831 #define DEFAULT_VNAMESERVER_OFFSET (3) // 10.0.2.3
2932 #define DEFAULT_RECOMMENDED_VGUEST_OFFSET (100) // 10.0.2.100
3033 #define DEFAULT_NETNS_TYPE ("pid")
34 #define DEFAULT_TARGET_TYPE ("netns")
3135 #define NETWORK_PREFIX_MIN (1)
3236 // >=26 is not supported because the recommended guest IP is set to network addr
3337 // + 100 .
7882 {
7983 int fd;
8084 struct ifreq ifr;
85 if (tapname == NULL) {
86 fprintf(stderr, "tapname is NULL\n");
87 return -1;
88 }
8189 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
8290 perror("open(\"/dev/net/tun\")");
8391 return fd;
157165 return -1;
158166 }
159167
168 if (cfg->vmacaddress_len > 0) {
169 ifr.ifr_ifru.ifru_hwaddr = cfg->vmacaddress;
170 if (ioctl(sockfd, SIOCSIFHWADDR, &ifr) < 0) {
171 perror("cannot set MAC address");
172 return -1;
173 }
174 }
175
160176 sai->sin_family = AF_INET;
161177 sai->sin_port = 0;
162178 sai->sin_addr = cfg->recommended_vguest;
194210 return 0;
195211 }
196212
213 /* Child (--target-type=netns) */
197214 static int child(int sock, pid_t target_pid, bool do_config_network,
198215 const char *tapname, char *netns_path, char *userns_path,
199216 struct slirp4netns_config *cfg)
216233 fprintf(stderr, "sent tapfd=%d for %s\n", tapfd, tapname);
217234 close(sock);
218235 return 0;
236 }
237
238 /*
239 * Child (--target-type=bess)
240 *
241 * FIXME: We do not really need to fork the child for BESS mode
242 */
243 static int child_bess(int sock, const char *bess_socket)
244 {
245 int bess_listenfd = -1, bess_acceptfd = -1;
246 struct sockaddr_un bess_listenaddr, bess_acceptaddr;
247 socklen_t bess_acceptaddrlen = sizeof(struct sockaddr_un);
248 memset(&bess_acceptaddr, 0, sizeof(bess_acceptaddr));
249 memset(&bess_listenaddr, 0, sizeof(bess_listenaddr));
250
251 /* Listen on the BESS socket */
252 if ((bess_listenfd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1) {
253 perror("child_bess: socket");
254 goto error;
255 }
256 bess_listenaddr.sun_family = AF_UNIX;
257 if (bess_socket == NULL) {
258 fprintf(stderr, "the specified BESS socket path is NULL\n");
259 goto error;
260 }
261 if (strlen(bess_socket) >= sizeof(bess_listenaddr.sun_path)) {
262 fprintf(stderr, "the specified BESS socket path is too long (>= %lu)\n",
263 sizeof(bess_listenaddr.sun_path));
264 goto error;
265 }
266 strncpy(bess_listenaddr.sun_path, bess_socket,
267 sizeof(bess_listenaddr.sun_path) - 1);
268 unlink(bess_socket); /* avoid EADDRINUSE */
269 if (bind(bess_listenfd, (struct sockaddr *)&bess_listenaddr,
270 sizeof(bess_listenaddr)) < 0) {
271 perror("child_bess: bind");
272 goto error;
273 }
274 if (listen(bess_listenfd, 0) < 0) {
275 perror("child_bess: listen");
276 goto error;
277 }
278
279 /* Accept a connection, and send its connection to the parent */
280 fprintf(stderr, "Waiting for connection to %s\n", bess_socket);
281 if ((bess_acceptfd =
282 accept(bess_listenfd, (struct sockaddr *)&bess_acceptaddr,
283 &bess_acceptaddrlen)) < 0) {
284 perror("child_bess: accept");
285 goto error;
286 }
287 if (sendfd(sock, bess_acceptfd) < 0) {
288 goto error;
289 }
290 fprintf(stderr, "sent \"tapfd\"=%d (not really TAP) for %s\n",
291 bess_acceptfd, bess_socket);
292 close(sock);
293 close(bess_listenfd);
294 return 0;
295 error:
296 close(bess_acceptfd);
297 close(bess_listenfd);
298 close(sock);
299 return -1;
219300 }
220301
221302 static int recvfd(int sock)
254335 static int parent(int sock, int ready_fd, int exit_fd, const char *api_socket,
255336 struct slirp4netns_config *cfg, pid_t target_pid)
256337 {
338 char str[INET6_ADDRSTRLEN];
257339 int rc, tapfd;
340 struct in_addr vdhcp_end = {
341 #define NB_BOOTP_CLIENTS 16
342 /* NB_BOOTP_CLIENTS is hard-coded to 16 in libslirp:
343 https://gitlab.freedesktop.org/slirp/libslirp/-/issues/49 */
344 .s_addr = htonl(ntohl(cfg->vdhcp_start.s_addr) + NB_BOOTP_CLIENTS - 1),
345 #undef NB_BOOTP_CLIENTS
346 };
258347 if ((tapfd = recvfd(sock)) < 0) {
259348 return tapfd;
260349 }
262351 close(sock);
263352 printf("Starting slirp\n");
264353 printf("* MTU: %d\n", cfg->mtu);
265 printf("* Network: %s\n", inet_ntoa(cfg->vnetwork));
266 printf("* Netmask: %s\n", inet_ntoa(cfg->vnetmask));
267 printf("* Gateway: %s\n", inet_ntoa(cfg->vhost));
268 printf("* DNS: %s\n", inet_ntoa(cfg->vnameserver));
269 printf("* Recommended IP: %s\n", inet_ntoa(cfg->recommended_vguest));
354 printf("* Network: %s\n",
355 inet_ntop(AF_INET, &cfg->vnetwork, str, sizeof(str)));
356 printf("* Netmask: %s\n",
357 inet_ntop(AF_INET, &cfg->vnetmask, str, sizeof(str)));
358 printf("* Gateway: %s\n",
359 inet_ntop(AF_INET, &cfg->vhost, str, sizeof(str)));
360 printf("* DNS: %s\n",
361 inet_ntop(AF_INET, &cfg->vnameserver, str, sizeof(str)));
362 printf("* DHCP begin: %s\n",
363 inet_ntop(AF_INET, &cfg->vdhcp_start, str, sizeof(str)));
364 printf("* DHCP end: %s\n",
365 inet_ntop(AF_INET, &vdhcp_end, str, sizeof(str)));
366 printf("* Recommended IP: %s\n",
367 inet_ntop(AF_INET, &cfg->recommended_vguest, str, sizeof(str)));
270368 if (api_socket != NULL) {
271369 printf("* API Socket: %s\n", api_socket);
370 }
371 #if SLIRP_CONFIG_VERSION_MAX >= 2
372 if (cfg->enable_outbound_addr) {
373 printf(
374 "* Outbound IPv4: %s\n",
375 inet_ntop(AF_INET, &cfg->outbound_addr.sin_addr, str, sizeof(str)));
376 }
377 if (cfg->enable_outbound_addr6) {
378 if (inet_ntop(AF_INET6, &cfg->outbound_addr6.sin6_addr, str,
379 sizeof(str)) != NULL) {
380 printf("* Outbound IPv6: %s\n", str);
381 }
382 }
383 #endif
384 if (cfg->vmacaddress_len > 0) {
385 unsigned char *mac = (unsigned char *)cfg->vmacaddress.sa_data;
386 printf("* MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0],
387 mac[1], mac[2], mac[3], mac[4], mac[5]);
272388 }
273389 if (!cfg->disable_host_loopback) {
274390 printf(
275391 "WARNING: 127.0.0.1:* on the host is accessible as %s (set "
276392 "--disable-host-loopback to prohibit connecting to 127.0.0.1:*)\n",
277 inet_ntoa(cfg->vhost));
393 inet_ntop(AF_INET, &cfg->vhost, str, sizeof(str)));
278394 }
279395 if (cfg->enable_sandbox && geteuid() != 0) {
280396 if ((rc = nsenter(target_pid, NULL, NULL, true)) < 0) {
303419
304420 static void usage(const char *argv0)
305421 {
306 printf("Usage: %s [OPTION]... PID|PATH TAPNAME\n", argv0);
422 printf("Usage: %s [OPTION]... PID|PATH [TAPNAME]\n", argv0);
307423 printf("User-mode networking for unprivileged network namespaces.\n\n");
308424 printf("-c, --configure bring up the interface\n");
309425 printf("-e, --exit-fd=FD specify the FD for terminating "
331447 "caps except CAP_NET_BIND_SERVICE if running as the root)\n");
332448 printf("--enable-seccomp enable seccomp to limit syscalls "
333449 "(experimental)\n");
450 /* v1.1.0 */
451 #if SLIRP_CONFIG_VERSION_MAX >= 2
452 printf("--outbound-addr=IPv4 sets outbound ipv4 address to bound to "
453 "(experimental)\n");
454 printf("--outbound-addr6=IPv6 sets outbound ipv6 address to bound to "
455 "(experimental)\n");
456 #endif
457 #if SLIRP_CONFIG_VERSION_MAX >= 3
458 printf("--disable-dns disables 10.0.2.3 (or configured internal "
459 "ip) to host dns redirect (experimental)\n");
460 #endif
461 /* v1.1.9 */
462 printf("--macaddress=MAC specify the MAC address of the TAP (only "
463 "valid with -c)\n");
464 /* v1.2.0 */
465 printf("--target-type=TYPE specify the target type ([netns|bess], "
466 "default=%s)\n",
467 DEFAULT_TARGET_TYPE);
334468 /* others */
335469 printf("-h, --help show this help and exit\n");
336470 printf("-v, --version show version and exit\n");
339473 // version output is runc-compatible and machine-parsable
340474 static void version()
341475 {
476 const struct scmp_version *scmpv = seccomp_version();
342477 printf("slirp4netns version %s\n", VERSION ? VERSION : PACKAGE_VERSION);
343478 #ifdef COMMIT
344479 printf("commit: %s\n", COMMIT);
345480 #endif
346481 printf("libslirp: %s\n", slirp_version_string());
482 printf("SLIRP_CONFIG_VERSION_MAX: %d\n", SLIRP_CONFIG_VERSION_MAX);
483 if (scmpv != NULL) {
484 printf("libseccomp: %d.%d.%d\n", scmpv->major, scmpv->minor,
485 scmpv->micro);
486 /* Do not free scmpv */
487 }
347488 }
348489
349490 struct options {
350 pid_t target_pid; // argv[1]
351491 char *tapname; // argv[2]
352 bool do_config_network; // -c
353 int exit_fd; // -e
354 int ready_fd; // -r
355 unsigned int mtu; // -m
356 bool disable_host_loopback; // --disable-host-loopback
357492 char *cidr; // --cidr
358 bool enable_ipv6; // -6
359493 char *api_socket; // -a
360494 char *netns_type; // argv[1]
361495 char *netns_path; // --netns-path
362496 char *userns_path; // --userns-path
497 char *outbound_addr; // --outbound-addr
498 char *outbound_addr6; // --outbound-addr6
499 pid_t target_pid; // argv[1]
500 int exit_fd; // -e
501 int ready_fd; // -r
502 unsigned int mtu; // -m
503 bool do_config_network; // -c
504 bool disable_host_loopback; // --disable-host-loopback
505 bool enable_ipv6; // -6
363506 bool enable_sandbox; // --enable-sandbox
364507 bool enable_seccomp; // --enable-seccomp
508 bool disable_dns; // --disable-dns
509 char *macaddress; // --macaddress
510 char *target_type; // --target-type
511 char *bess_socket; // argv[1] (When --target-type="bess")
365512 };
366513
367514 static void options_init(struct options *options)
396543 if (options->userns_path != NULL) {
397544 free(options->userns_path);
398545 options->userns_path = NULL;
546 }
547 if (options->outbound_addr != NULL) {
548 free(options->outbound_addr);
549 options->outbound_addr = NULL;
550 }
551 if (options->outbound_addr6 != NULL) {
552 free(options->outbound_addr6);
553 options->outbound_addr6 = NULL;
554 }
555 if (options->macaddress != NULL) {
556 free(options->macaddress);
557 options->macaddress = NULL;
558 }
559 if (options->target_type != NULL) {
560 free(options->target_type);
561 options->target_type = NULL;
562 }
563 if (options->bess_socket != NULL) {
564 free(options->bess_socket);
565 options->bess_socket = NULL;
399566 }
400567 }
401568
410577 char *optarg_netns_type = NULL;
411578 char *optarg_userns_path = NULL;
412579 char *optarg_api_socket = NULL;
580 char *optarg_outbound_addr = NULL;
581 char *optarg_outbound_addr6 = NULL;
582 char *optarg_macaddress = NULL;
583 char *optarg_target_type = NULL;
413584 #define CIDR -42
414585 #define DISABLE_HOST_LOOPBACK -43
415586 #define NETNS_TYPE -44
416587 #define USERNS_PATH -45
417588 #define ENABLE_SANDBOX -46
418589 #define ENABLE_SECCOMP -47
590 #define OUTBOUND_ADDR -48
591 #define OUTBOUND_ADDR6 -49
592 #define DISABLE_DNS -50
593 #define MACADDRESS -51
594 #define TARGET_TYPE -52
419595 #define _DEPRECATED_NO_HOST_LOOPBACK \
420596 -10043 // deprecated in favor of disable-host-loopback
421597 #define _DEPRECATED_CREATE_SANDBOX \
437613 { "enable-seccomp", no_argument, NULL, ENABLE_SECCOMP },
438614 { "help", no_argument, NULL, 'h' },
439615 { "version", no_argument, NULL, 'v' },
616 { "outbound-addr", required_argument, NULL, OUTBOUND_ADDR },
617 { "outbound-addr6", required_argument, NULL, OUTBOUND_ADDR6 },
618 { "disable-dns", no_argument, NULL, DISABLE_DNS },
619 { "macaddress", required_argument, NULL, MACADDRESS },
620 { "target-type", required_argument, NULL, TARGET_TYPE },
440621 { 0, 0, 0, 0 },
441622 };
442623 options_init(options);
525706 version();
526707 exit(EXIT_SUCCESS);
527708 break;
709 case OUTBOUND_ADDR:
710 printf("WARNING: Support for --outbound-addr is experimental\n");
711 optarg_outbound_addr = optarg;
712 break;
713 case OUTBOUND_ADDR6:
714 printf("WARNING: Support for --outbound-addr6 is experimental\n");
715 optarg_outbound_addr6 = optarg;
716 break;
717 case DISABLE_DNS:
718 options->disable_dns = true;
719 break;
720 case MACADDRESS:
721 optarg_macaddress = optarg;
722 break;
723 case TARGET_TYPE:
724 optarg_target_type = optarg;
725 break;
528726 default:
529727 goto error;
530728 break;
541739 }
542740 if (optarg_api_socket != NULL) {
543741 options->api_socket = strdup(optarg_api_socket);
742 }
743 if (optarg_outbound_addr != NULL) {
744 options->outbound_addr = strdup(optarg_outbound_addr);
745 }
746 if (optarg_outbound_addr6 != NULL) {
747 options->outbound_addr6 = strdup(optarg_outbound_addr6);
748 }
749 if (optarg_macaddress != NULL) {
750 if (!options->do_config_network) {
751 fprintf(stderr, "--macaddr cannot be specified when --configure or "
752 "-c is not specified\n");
753 goto error;
754 } else {
755 options->macaddress = strdup(optarg_macaddress);
756 }
757 }
758 if (optarg_target_type != NULL) {
759 options->target_type = strdup(optarg_target_type);
544760 }
545761 #undef CIDR
546762 #undef DISABLE_HOST_LOOPBACK
549765 #undef _DEPRECATED_NO_HOST_LOOPBACK
550766 #undef ENABLE_SANDBOX
551767 #undef ENABLE_SECCOMP
768 #undef OUTBOUND_ADDR
769 #undef OUTBOUND_ADDR6
770 #undef DISABLE_DNS
771 #undef MACADDRESS
772 #undef TARGET_TYPE
773
774 /* BESS mode */
775 if (options->target_type != NULL &&
776 strcmp(options->target_type, "bess") == 0) {
777 if (argc - optind < 1) {
778 goto error;
779 }
780 if (argc - optind > 1) {
781 fprintf(stderr, "too many arguments\n");
782 goto error;
783 }
784 options->bess_socket = strdup(argv[optind]);
785 if (options->do_config_network) {
786 fprintf(stderr, "--configure conflicts with --target-type=bess\n");
787 goto error;
788 }
789 if (options->netns_type != NULL) {
790 fprintf(stderr, "--netns-type conflicts with --target-type=bess\n");
791 goto error;
792 }
793 if (options->userns_path != NULL) {
794 fprintf(stderr,
795 "--userns-path conflicts with --target-type=bess\n");
796 goto error;
797 }
798 printf("WARNING: BESS mode is experimental\n");
799 return;
800 }
801
802 /* NetNS mode*/
803 if (options->target_type != NULL &&
804 strcmp(options->target_type, "netns") != 0) {
805 fprintf(stderr, "--target-type must be either \"netns\" or \"bess\"\n");
806 goto error;
807 }
552808 if (argc - optind < 2) {
553809 goto error;
810 }
811 if (argc - optind > 2) {
812 // not an error, for preventing potential compatibility issue
813 printf("WARNING: too many arguments\n");
554814 }
555815 if (!options->netns_type ||
556816 strcmp(options->netns_type, DEFAULT_NETNS_TYPE) == 0) {
669929 return rc;
670930 }
671931
932 static int get_interface_addr(const char *interface, int af, void *addr)
933 {
934 struct ifaddrs *ifaddr, *ifa;
935 if (interface == NULL)
936 return -1;
937
938 if (getifaddrs(&ifaddr) == -1) {
939 fprintf(stderr, "getifaddrs failed to obtain interface addresses");
940 return -1;
941 }
942
943 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
944 if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL)
945 continue;
946 if (ifa->ifa_addr->sa_family == af) {
947 if (strcmp(ifa->ifa_name, interface) == 0) {
948 if (af == AF_INET) {
949 *(struct in_addr *)addr =
950 ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
951 } else {
952 *(struct in6_addr *)addr =
953 ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
954 }
955 return 0;
956 }
957 }
958 }
959 return -1;
960 }
961
962 /*
963 * Convert a MAC string (macaddr) to bytes (data).
964 * macaddr must be a null-terminated string in the format of
965 * xx:xx:xx:xx:xx:xx. The data buffer needs to be at least 6 bytes.
966 * Typically the data is put into sockaddr sa_data, which is 14 bytes.
967 */
968 static int slirp4netns_macaddr_hexstring_to_data(char *macaddr, char *data)
969 {
970 int temp;
971 char *macaddr_ptr;
972 char *data_ptr;
973 for (macaddr_ptr = macaddr, data_ptr = data;
974 macaddr_ptr != NULL && data_ptr < data + 6;
975 macaddr_ptr = strchr(macaddr_ptr, ':'), data_ptr++) {
976 if (macaddr_ptr != macaddr) {
977 macaddr_ptr++; // advance over the :
978 }
979 if (sscanf(macaddr_ptr, "%x", &temp) != 1 || temp < 0 || temp > 255) {
980 fprintf(stderr, "\"%s\" is an invalid MAC address.\n", macaddr);
981 return -1;
982 }
983 *data_ptr = temp;
984 }
985 if (macaddr_ptr != NULL) {
986 fprintf(stderr, "\"%s\" is an invalid MAC address. Is it too long?\n",
987 macaddr);
988 return -1;
989 }
990 return (int)(data_ptr - data);
991 }
992
672993 static int slirp4netns_config_from_options(struct slirp4netns_config *cfg,
673994 struct options *opt)
674995 {
6791000 if (rc < 0) {
6801001 goto finish;
6811002 }
682 cfg->enable_ipv6 = cfg->enable_ipv6;
1003 cfg->enable_ipv6 = opt->enable_ipv6;
6831004 cfg->disable_host_loopback = opt->disable_host_loopback;
6841005 cfg->enable_sandbox = opt->enable_sandbox;
6851006 cfg->enable_seccomp = opt->enable_seccomp;
1007
1008 #if SLIRP_CONFIG_VERSION_MAX >= 2
1009 cfg->enable_outbound_addr = false;
1010 cfg->enable_outbound_addr6 = false;
1011 #endif
1012
1013 if (opt->outbound_addr != NULL) {
1014 #if SLIRP_CONFIG_VERSION_MAX >= 2
1015 cfg->outbound_addr.sin_family = AF_INET;
1016 cfg->outbound_addr.sin_port = 0; // Any local port will do
1017 if (inet_pton(AF_INET, opt->outbound_addr,
1018 &cfg->outbound_addr.sin_addr) == 1) {
1019 cfg->enable_outbound_addr = true;
1020 } else {
1021 if (get_interface_addr(opt->outbound_addr, AF_INET,
1022 &cfg->outbound_addr.sin_addr) != 0) {
1023 fprintf(stderr, "outbound-addr has to be valid ipv4 address or "
1024 "interface name.");
1025 rc = -1;
1026 goto finish;
1027 }
1028 cfg->enable_outbound_addr = true;
1029 }
1030 #else
1031 fprintf(stderr, "slirp4netns has to be compiled against libslrip 4.2.0 "
1032 "or newer for --outbound-addr support.");
1033 rc = -1;
1034 goto finish;
1035 #endif
1036 }
1037 if (opt->outbound_addr6 != NULL) {
1038 #if SLIRP_CONFIG_VERSION_MAX >= 2
1039 cfg->outbound_addr6.sin6_family = AF_INET6;
1040 cfg->outbound_addr6.sin6_port = 0; // Any local port will do
1041 if (inet_pton(AF_INET6, opt->outbound_addr6,
1042 &cfg->outbound_addr6.sin6_addr) == 1) {
1043 cfg->enable_outbound_addr6 = true;
1044 } else {
1045 if (get_interface_addr(opt->outbound_addr, AF_INET6,
1046 &cfg->outbound_addr6.sin6_addr) != 0) {
1047 fprintf(stderr, "outbound-addr has to be valid ipv4 address or "
1048 "iterface name.");
1049 rc = -1;
1050 goto finish;
1051 }
1052 cfg->enable_outbound_addr6 = true;
1053 }
1054 #else
1055 fprintf(stderr, "slirp4netns has to be compiled against libslirp 4.2.0 "
1056 "or newer for --outbound-addr6 support.");
1057 rc = -1;
1058 goto finish;
1059 #endif
1060 }
1061
1062 #if SLIRP_CONFIG_VERSION_MAX >= 3
1063 cfg->disable_dns = opt->disable_dns;
1064 #else
1065 if (opt->disable_dns) {
1066 fprintf(stderr, "slirp4netns has to be compiled against libslirp 4.3.0 "
1067 "or newer for --disable-dns support.");
1068 rc = -1;
1069 goto finish;
1070 }
1071 #endif
1072
1073 cfg->vmacaddress_len = 0;
1074 memset(&cfg->vmacaddress, 0, sizeof(cfg->vmacaddress));
1075 if (opt->macaddress != NULL) {
1076 cfg->vmacaddress.sa_family = AF_LOCAL;
1077 int macaddr_len;
1078 if ((macaddr_len = slirp4netns_macaddr_hexstring_to_data(
1079 opt->macaddress, cfg->vmacaddress.sa_data)) < 0) {
1080 fprintf(stderr, "macaddress has to be a valid MAC address (hex "
1081 "string, 6 bytes, each byte separated by a ':').");
1082 rc = -1;
1083 goto finish;
1084 }
1085 cfg->vmacaddress_len = macaddr_len;
1086 }
6861087 finish:
6871088 return rc;
6881089 }
7111112 goto finish;
7121113 }
7131114 if (child_pid == 0) {
714 if (child(sv[1], options.target_pid, options.do_config_network,
715 options.tapname, options.netns_path, options.userns_path,
716 &slirp4netns_config) < 0) {
1115 int ret;
1116 if (options.target_type != NULL &&
1117 strcmp(options.target_type, "bess") == 0) {
1118 ret = child_bess(sv[1], options.bess_socket);
1119 } else {
1120 ret = child(sv[1], options.target_pid, options.do_config_network,
1121 options.tapname, options.netns_path,
1122 options.userns_path, &slirp4netns_config);
1123 }
1124 if (ret < 0) {
7171125 exit_status = EXIT_FAILURE;
7181126 goto finish;
7191127 }
0 /* SPDX-License-Identifier: LGPL-2.1+ */
1 #ifndef SLIRP4NETNS_SECCOMPARCH_H
2 #define SLIRP4NETNS_SECCOMPARCH_H
3
4 #include <stdint.h>
5 #include <seccomp.h>
6
7 /*
8 * seccomp_extra_archs derived from systemd seccomp_local_archs
9 * but does NOT contain native archs:
10 * https://github.com/systemd/systemd/blob/v245/src/shared/seccomp-util.c#L25-L95
11 * .
12 */
13 const uint32_t seccomp_extra_archs[] = {
14 #if defined(__x86_64__) && \
15 defined(__ILP32__) /* X32 ( https://en.wikipedia.org/wiki/X32_ABI ) */
16 SCMP_ARCH_X86, SCMP_ARCH_X86_64,
17 #elif defined(__x86_64__) && !defined(__ILP32__) /* X86_64 */
18 SCMP_ARCH_X86, SCMP_ARCH_X32,
19 #elif defined(__i386__) /* X86 */
20 /* NONE */
21 #elif defined(__aarch64__) /* AARCH64 */
22 SCMP_ARCH_ARM,
23 #elif defined(__arm__) /* ARM */
24 /* NONE */
25 #elif defined(__mips__) && __BYTE_ORDER == __BIG_ENDIAN && \
26 _MIPS_SIM == _MIPS_SIM_ABI32 /* MIPS */
27 SCMP_ARCH_MIPSEL,
28 #elif defined(__mips__) && __BYTE_ORDER == __LITTLE_ENDIAN && \
29 _MIPS_SIM == _MIPS_SIM_ABI32 /* MIPSEL */
30 SCMP_ARCH_MIPS,
31 #elif defined(__mips__) && __BYTE_ORDER == __BIG_ENDIAN && \
32 _MIPS_SIM == _MIPS_SIM_ABI64 /* MIPS64 */
33 SCMP_ARCH_MIPSEL, SCMP_ARCH_MIPS, SCMP_ARCH_MIPSEL64N32,
34 SCMP_ARCH_MIPS64N32, SCMP_ARCH_MIPSEL64,
35 #elif defined(__mips__) && __BYTE_ORDER == __LITTLE_ENDIAN && \
36 _MIPS_SIM == _MIPS_SIM_ABI64 /* MIPSEL64 */
37 SCMP_ARCH_MIPS, SCMP_ARCH_MIPSEL, SCMP_ARCH_MIPS64N32,
38 SCMP_ARCH_MIPSEL64N32, SCMP_ARCH_MIPS64,
39 #elif defined(__mips__) && __BYTE_ORDER == __BIG_ENDIAN && \
40 _MIPS_SIM == _MIPS_SIM_NABI32 /* MIPS64N32 */
41 SCMP_ARCH_MIPSEL, SCMP_ARCH_MIPS, SCMP_ARCH_MIPSEL64,
42 SCMP_ARCH_MIPS64, SCMP_ARCH_MIPSEL64N32,
43 #elif defined(__mips__) && __BYTE_ORDER == __LITTLE_ENDIAN && \
44 _MIPS_SIM == _MIPS_SIM_NABI32 /* MIPSEL64N32 */
45 SCMP_ARCH_MIPS, SCMP_ARCH_MIPSEL, SCMP_ARCH_MIPS64,
46 SCMP_ARCH_MIPSEL64, SCMP_ARCH_MIPS64N32,
47 #elif defined(__powerpc64__) && __BYTE_ORDER == __BIG_ENDIAN /* PPC64 */
48 SCMP_ARCH_PPC, SCMP_ARCH_PPC64LE,
49 #elif defined(__powerpc64__) && __BYTE_ORDER == __LITTLE_ENDIAN /* PPC64LE */
50 SCMP_ARCH_PPC, SCMP_ARCH_PPC64,
51 #elif defined(__powerpc__) /* PPC */
52 /* NONE */
53 #elif defined(__s390x__) /* S390X */
54 SCMP_ARCH_S390,
55 #elif defined(__s390__) /* S390 */
56 /* NONE */
57 #endif
58 (uint32_t)-1
59 };
60
61 /* seccomp_extra_archs_items can be 0 */
62 const int seccomp_extra_archs_items =
63 sizeof(seccomp_extra_archs) / sizeof(seccomp_extra_archs[0]) - 1;
64
65 #endif
00 /* SPDX-License-Identifier: GPL-2.0-or-later */
11 #define _GNU_SOURCE
22 #include <stdio.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <linux/seccomp.h>
6 #include <glib.h>
37 #include <seccomp.h>
8 #include "seccomparch.h"
9
10 #if defined(SCMP_ACT_KILL_PROCESS) && defined(SECCOMP_GET_ACTION_AVAIL) && \
11 defined(SECCOMP_RET_KILL_PROCESS)
12 #include <unistd.h>
13 #include <sys/syscall.h>
14
15 static uint32_t get_block_action()
16 {
17 const uint32_t action = SECCOMP_RET_KILL_PROCESS;
18 /* Syscall fails if either actions_avail or kill_process is not available */
19 if (syscall(__NR_seccomp, SECCOMP_GET_ACTION_AVAIL, 0, &action) == 0)
20 return SCMP_ACT_KILL_PROCESS;
21 return SCMP_ACT_KILL;
22 }
23 #else
24 static uint32_t get_block_action()
25 {
26 return SCMP_ACT_KILL;
27 }
28 #endif
29
30 static void add_block_rule(scmp_filter_ctx ctx, const char *name,
31 uint32_t block_action, GString *blocked,
32 GString *skipped_undefined, GString *skipped_failed)
33 {
34 int rc = -1, num = seccomp_syscall_resolve_name(name);
35 if (num == __NR_SCMP_ERROR) {
36 g_string_append_printf(skipped_undefined, " %s", name);
37 return;
38 }
39 if ((rc = seccomp_rule_add(ctx, block_action, num, 0)) != 0) {
40 g_string_append_printf(skipped_failed, " %s(%s)", name, strerror(-rc));
41 return;
42 }
43 g_string_append_printf(blocked, " %s", name);
44 }
445
546 int enable_seccomp()
647 {
7 int rc = -1;
48 int rc = -1, i;
49 uint32_t block_action = get_block_action();
50 GString *blocked = g_string_new(NULL);
51 GString *skipped_undefined = g_string_new(NULL);
52 GString *skipped_failed = g_string_new(NULL);
853 /* Allow everything by default and block dangerous syscalls explicitly,
954 * as it is hard to find the correct set of required syscalls */
1055 scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
1156 if (ctx == NULL)
1257 goto ret;
13 printf("seccomp: The following syscalls will be blocked by seccomp:");
14 #ifdef SCMP_ACT_KILL_PROCESS
15 #define BLOCK_ACTION SCMP_ACT_KILL_PROCESS
16 #else
17 #define BLOCK_ACTION SCMP_ACT_KILL
18 #endif
19 #define BLOCK(x) \
20 { \
21 rc = seccomp_rule_add(ctx, BLOCK_ACTION, SCMP_SYS(x), 0); \
22 if (rc < 0) \
23 goto ret; \
24 printf(" %s", #x); \
58 for (i = 0; i < seccomp_extra_archs_items; i++) {
59 uint32_t arch = seccomp_extra_archs[i];
60 rc = seccomp_arch_add(ctx, arch);
61 if (rc < 0 && rc != -EEXIST && rc != -EDOM) {
62 fprintf(stderr,
63 "seccomp: WARNING: can't add extra arch (i=%d): %s\n", i,
64 strerror(-rc));
65 }
2566 }
26 BLOCK(execve);
27 #ifdef __NR_execveat
28 BLOCK(execveat);
29 #else
30 fprintf(stderr,
31 "seccomp: can't block execevat because __NR_execveat was not "
32 "defined in the build environment\n");
33 #endif
34 /* ideally we should also block open() and openat() but required for
35 * resolv.conf */
36 BLOCK(open_by_handle_at);
37 BLOCK(ptrace);
38 BLOCK(prctl);
39 BLOCK(process_vm_readv);
40 BLOCK(process_vm_writev);
41 BLOCK(mount);
42 BLOCK(name_to_handle_at);
43 BLOCK(setns);
44 BLOCK(umount);
45 BLOCK(umount2);
46 BLOCK(unshare);
67 #define BLOCK(x) \
68 add_block_rule(ctx, #x, block_action, blocked, skipped_undefined, \
69 skipped_failed)
70 #include "seccompfilter_rules.h"
4771 #undef BLOCK
48 #undef BLOCK_ACTION
49 printf(".\n");
50 rc = seccomp_load(ctx);
72 if ((rc = seccomp_load(ctx)) != 0) {
73 fprintf(stderr, "seccomp: seccomp_load(): %s\n", strerror(-rc));
74 goto ret;
75 }
76 printf("seccomp: The following syscalls are blocked:%s\n", blocked->str);
77 if (skipped_undefined->len > 0) {
78 fprintf(stderr,
79 "seccomp: WARNING: the following syscalls are not defined "
80 "in libseccomp and cannot be "
81 "blocked:%s\n",
82 skipped_undefined->str);
83 }
84 if (skipped_failed->len > 0) {
85 fprintf(stderr,
86 "seccomp: WARNING: the following syscalls cannot be "
87 "blocked due to unexpected errors:%s\n",
88 skipped_failed->str);
89 }
5190 ret:
5291 seccomp_release(ctx);
92 g_string_free(blocked, TRUE);
93 g_string_free(skipped_undefined, TRUE);
94 g_string_free(skipped_failed, TRUE);
5395 return rc;
5496 }
0 /* SPDX-License-Identifier: GPL-2.0-or-later */
1
2 /* We do not need ifndef _XXX_H guard: https://github.com/rootless-containers/slirp4netns/pull/238#discussion_r530214521 */
3
4 #ifndef BLOCK
5 #error "Included in an unexpected way?"
6 #endif
7
8 /*
9 NOTE:
10 - Run `sudo systemd-analyze syscall-filter` to show list of syscall groups.
11 - Ideally we should also block open() and openat(), but these calls are required for opening resolv.conf
12 */
13
14 /* group: @default */
15 BLOCK(execve);
16
17 /* group: @debug */
18 BLOCK(lookup_dcookie);
19 BLOCK(pidfd_getfd);
20 BLOCK(ptrace);
21
22 /* group: @ipc */
23 BLOCK(process_vm_readv);
24 BLOCK(process_vm_writev);
25
26 /* group: @module*/
27 BLOCK(delete_module);
28 BLOCK(finit_module);
29 BLOCK(init_module);
30
31 /* group: @mount */
32 BLOCK(chroot);
33 BLOCK(fsconfig);
34 BLOCK(fsmount);
35 BLOCK(fsopen);
36 BLOCK(fspick);
37 BLOCK(mount);
38 BLOCK(move_mount);
39 BLOCK(open_tree);
40 BLOCK(pivot_root);
41 BLOCK(umount);
42 BLOCK(umount2);
43
44 /* group: @privileged */
45 BLOCK(open_by_handle_at);
46
47 /* group: @process */
48 BLOCK(execveat);
49 BLOCK(pidfd_open);
50 BLOCK(pidfd_send_signal);
51 BLOCK(prctl);
52 BLOCK(setns);
53 BLOCK(unshare);
54
55 /* group: @reboot */
56 BLOCK(kexec_file_load);
57 BLOCK(kexec_load);
58 BLOCK(reboot);
59
60 /* group: @system-service */
61 BLOCK(name_to_handle_at);
00 .nh
1 .TH SLIRP4NETNS 1 "March 2020" "Rootless Containers" "User Commands"
1 .TH SLIRP4NETNS 1 "January 2022" "Rootless Containers" "User Commands"
22
33 .SH NAME
44 .PP
77
88 .SH SYNOPSIS
99 .PP
10 slirp4netns [OPTION]... PID|PATH TAPNAME
10 slirp4netns [OPTION]... PID|PATH [TAPNAME]
1111
1212
1313 .SH DESCRIPTION
1515 slirp4netns provides user\-mode networking ("slirp") for network namespaces.
1616
1717 .PP
18 Unlike \fBveth\fP(4), slirp4netns does not require the root privileges on the host.
18 Unlike \fB\fCveth(4)\fR, slirp4netns does not require the root privileges on the host.
1919
2020 .PP
2121 Default configuration:
3030 .IP \(bu 2
3131 DNS: 10.0.2.3 (network address + 3)
3232 .IP \(bu 2
33 DHCP begin: 10.0.2.15 (network address + 15)
34 .IP \(bu 2
35 DHCP end: 10.0.2.30 (network address + 30)
36 .IP \(bu 2
3337 IPv6 CIDR: fd00::/64
3438 .IP \(bu 2
3539 IPv6 Gateway/Host: fd00::2
4145
4246 .SH OPTIONS
4347 .PP
44 \fB\-c\fP, \fB\-\-configure\fP
48 \fB\fC\-c\fR, \fB\fC\-\-configure\fR
4549 bring up the TAP interface. IP will be set to 10.0.2.100 (network address + 100) by default. IPv6 will be set to a random address.
46 Starting with v0.4.0, the loopback interface (\fBlo\fP) is brought up as well.
47
48 .PP
49 \fB\-e\fP, \fB\-\-exit\-fd=FD\fP
50 Starting with v0.4.0, the loopback interface (\fB\fClo\fR) is brought up as well.
51
52 .PP
53 \fB\fC\-e\fR, \fB\fC\-\-exit\-fd=FD\fR
5054 specify the FD for terminating slirp4netns.
51 When the FD is specified, slirp4netns exits when a \fBpoll(2)\fP event happens on the FD.
52
53 .PP
54 \fB\-r\fP, \fB\-\-ready\-fd=FD\fP
55 When the FD is specified, slirp4netns exits when a \fB\fCpoll(2)\fR event happens on the FD.
56
57 .PP
58 \fB\fC\-r\fR, \fB\fC\-\-ready\-fd=FD\fR
5559 specify the FD to write to when the initialization steps are finished.
56 When the FD is specified, slirp4netns writes \fB"1"\fP to the FD and close the FD.
57 Prior to v0.4.0, the FD was written after the network configuration (\fB\-c\fP)
58 but before the API socket configuration (\fB\-a\fP).
59
60 .PP
61 \fB\-m\fP, \fB\-\-mtu=MTU\fP (since v0.2.0)
60 When the FD is specified, slirp4netns writes \fB\fC"1"\fR to the FD and close the FD.
61 Prior to v0.4.0, the FD was written after the network configuration (\fB\fC\-c\fR)
62 but before the API socket configuration (\fB\fC\-a\fR).
63
64 .PP
65 \fB\fC\-m\fR, \fB\fC\-\-mtu=MTU\fR (since v0.2.0)
6266 specify MTU (max=65521).
6367
6468 .PP
65 \fB\-6\fP, \fB\-\-enable\-ipv6\fP (since v0.2.0, EXPERIMENTAL)
69 \fB\fC\-6\fR, \fB\fC\-\-enable\-ipv6\fR (since v0.2.0, EXPERIMENTAL)
6670 enable IPv6
6771
6872 .PP
69 \fB\-a\fP, \fB\-\-api\-socket\fP (since v0.3.0)
73 \fB\fC\-a\fR, \fB\fC\-\-api\-socket\fR (since v0.3.0)
7074 API socket path
7175
7276 .PP
73 \fB\-\-cidr\fP (since v0.3.0)
77 \fB\fC\-\-cidr\fR (since v0.3.0)
7478 specify CIDR, e.g. 10.0.2.0/24
7579
7680 .PP
77 \fB\-\-disable\-host\-loopback\fP (since v0.3.0)
81 \fB\fC\-\-disable\-host\-loopback\fR (since v0.3.0)
7882 prohibit connecting to 127.0.0.1:* on the host namespace
7983
8084 .PP
81 \fB\-\-netns\-type=TYPE\fP (since v0.4.0)
85 \fB\fC\-\-netns\-type=TYPE\fR (since v0.4.0)
8286 specify network namespace type ([path|pid], default=pid)
8387
8488 .PP
85 \fB\-\-userns\-path=PATH\fP (since v0.4.0)
89 \fB\fC\-\-userns\-path=PATH\fR (since v0.4.0)
8690 specify user namespace path
8791
8892 .PP
89 \fB\-\-enable\-sandbox\fP (since v0.4.0)
93 \fB\fC\-\-enable\-sandbox\fR (since v0.4.0)
9094 enter the user namespace and create a new mount namespace where only /etc and
9195 /run are mounted from the host.
9296
9397 .PP
94 Requires \fB/etc/resolv.conf\fP not to be a symlink to a file outside /etc and /run.
98 Requires \fB\fC/etc/resolv.conf\fR not to be a symlink to a file outside /etc and /run.
9599
96100 .PP
97101 When running as the root, the process does not enter the user namespace but all
98102 the capabilities except \fB\fCCAP\_NET\_BIND\_SERVICE\fR are dropped.
99103
100104 .PP
101 \fB\-\-enable\-seccomp\fP (since v0.4.0, EXPERIMENTAL)
102 enable \fBseccomp(2)\fP to limit syscalls.
103 Typically used in conjunction with \fB\-\-enable\-sandbox\fP\&.
104
105 .PP
106 \fB\-h\fP, \fB\-\-help\fP (since v0.2.0)
105 \fB\fC\-\-enable\-seccomp\fR (since v0.4.0, EXPERIMENTAL)
106 enable \fB\fCseccomp(2)\fR to limit syscalls.
107 Typically used in conjunction with \fB\fC\-\-enable\-sandbox\fR\&.
108
109 .PP
110 \fB\fC\-\-outbound\-addr=IPv4\fR (since v1.1.0, EXPERIMENTAL)
111 specify outbound ipv4 address slirp should bind to
112
113 .PP
114 \fB\fC\-\-outbound\-addr=INTERFACE\fR (since v1.1.0, EXPERIMENTAL)
115 specify outbound interface slirp should bind to (ipv4 traffic only)
116
117 .PP
118 \fB\fC\-\-outbound\-addr=IPv6\fR (since v1.1.0, EXPERIMENTAL)
119 specify outbound ipv6 address slirp should bind to
120
121 .PP
122 \fB\fC\-\-outbound\-addr6=INTERFACE\fR (since v1.1.0, EXPERIMENTAL)
123 specify outbound interface slirp should bind to (ipv6 traffic only)
124
125 .PP
126 \fB\fC\-\-disable\-dns\fR (since v1.1.0)
127 disable built\-in DNS (10.0.2.3 by default)
128
129 .PP
130 \fB\fC\-\-macaddress\fR (since v1.1.9)
131 specify MAC address of the TAP interface (only valid with \-c)
132
133 .PP
134 \fB\fC\-\-target\-type=TYPE\fR (since v1.2.0)
135 specify the target type ([netns|bess], default=netns).
136
137 .PP
138 The \fB\fCbess\fR mode (since v1.2.0, EXPERIMENTAL) is expected to be used with User Mode Linux.
139 The \fB\fCbess\fR mode conflicts with \fB\fC\-\-configure\fR, \fB\fC\-\-netns\-type\fR, and \fB\fC\-\-userns\-path\fR\&.
140
141 .PP
142 \fB\fC\-h\fR, \fB\fC\-\-help\fR (since v0.2.0)
107143 show help and exit
108144
109145 .PP
110 \fB\-v\fP, \fB\-\-version\fP (since v0.2.0)
146 \fB\fC\-v\fR, \fB\fC\-\-version\fR (since v0.2.0)
111147 show version and exit
112148
113149
114150 .SH EXAMPLE
115151 .PP
116 Terminal 1: Create user/network/mount namespaces
117
118 .PP
119 .RS
120
121 .nf
122 $ unshare \-\-user \-\-map\-root\-user \-\-net \-\-mount
123 unshared$ echo $$ > /tmp/pid
124
125 .fi
126 .RE
127
128 .PP
129 Terminal 2: Start slirp4netns
130
131 .PP
132 .RS
133
134 .nf
135 $ slirp4netns \-\-configure \-\-mtu=65520 $(cat /tmp/pid) tap0
152 \fBTerminal 1\fP: Create user/network/mount namespaces
153
154 .PP
155 .RS
156
157 .nf
158 (host)$ unshare \-\-user \-\-map\-root\-user \-\-net \-\-mount
159 (namespace)$ echo $$ > /tmp/pid
160
161 .fi
162 .RE
163
164 .PP
165 In this documentation, we use \fB\fC(host)$\fR as the prompt of the host shell, \fB\fC(namespace)$\fR as the prompt of the shell running in the namespaces.
166
167 .PP
168 If \fB\fCunshare\fR fails, try the following commands (known to be needed on Debian, Arch, and old CentOS 7.X):
169
170 .PP
171 .RS
172
173 .nf
174 (host)$ sudo sh \-c 'echo "user.max\_user\_namespaces=28633" >> /etc/sysctl.d/userns.conf'
175 (host)$ if [ \-f /proc/sys/kernel/unprivileged\_userns\_clone ]; then sudo sh \-c 'echo "kernel.unprivileged\_userns\_clone=1" >> /etc/sysctl.d/userns.conf'; fi
176 (host)$ sudo sysctl \-\-system
177
178 .fi
179 .RE
180
181 .PP
182 \fBTerminal 2\fP: Start slirp4netns
183
184 .PP
185 .RS
186
187 .nf
188 (host)$ slirp4netns \-\-configure \-\-mtu=65520 $(cat /tmp/pid) tap0
136189 starting slirp, MTU=65520
137190 ...
138191
140193 .RE
141194
142195 .PP
143 Terminal 1: Make sure \fBtap0\fP is configured and connected to the Internet
144
145 .PP
146 .RS
147
148 .nf
149 unshared$ ip a
196 \fBTerminal 1\fP: Make sure \fB\fCtap0\fR is configured and connected to the Internet
197
198 .PP
199 .RS
200
201 .nf
202 (namespace)$ ip a
150203 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
151204 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
152205 3: tap0: <BROADCAST,UP,LOWER\_UP> mtu 65520 qdisc fq\_codel state UNKNOWN group default qlen 1000
155208 valid\_lft forever preferred\_lft forever
156209 inet6 fe80::c028:cff:fe0e:2906/64 scope link
157210 valid\_lft forever preferred\_lft forever
158 unshared$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
159 unshared$ mount \-\-bind /tmp/resolv.conf /etc/resolv.conf
160 unshared$ curl https://example.com
161
162 .fi
163 .RE
164
165 .PP
166 Bind\-mounting \fB/etc/resolv.conf\fP is only needed when \fB/etc/resolv.conf\fP on
167 the host refers to loopback addresses (\fB127.0.0.X\fP, typically because of
168 \fBdnsmasq\fP(8) or \fBsystemd\-resolved.service\fP(8)) that cannot be accessed from
169 the namespace.
170
171 .PP
172 If your \fB/etc/resolv.conf\fP on the host is managed by \fBnetworkmanager\fP(8)
173 or \fBsystemd\-resolved.service\fP(8), you might need to mount a new filesystem on
174 \fB/etc\fP instead, so as to prevent the new \fB/etc/resolv.conf\fP from being
175 unmounted unexpectedly when \fB/etc/resolv.conf\fP on the host is regenerated.
176
177 .PP
178 .RS
179
180 .nf
181 unshared$ mkdir /tmp/a /tmp/b
182 unshared$ mount \-\-rbind /etc /tmp/a
183 unshared$ mount \-\-rbind /tmp/b /etc
184 unshared$ mkdir /etc/.ro
185 unshared$ mount \-\-move /tmp/a /etc/.ro
186 unshared$ cd /etc
187 unshared$ for f in .ro/*; do ln \-s $f $(basename $f); done
188 unshared$ rm resolv.conf
189 unshared$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
190 unshared$ curl https://example.com
211 (namespace)$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
212 (namespace)$ mount \-\-bind /tmp/resolv.conf /etc/resolv.conf
213 (namespace)$ curl https://example.com
214
215 .fi
216 .RE
217
218 .PP
219 Bind\-mounting \fB\fC/etc/resolv.conf\fR is only needed when \fB\fC/etc/resolv.conf\fR on
220 the host refers to loopback addresses (\fB\fC127.0.0.X\fR, typically \fB\fCdnsmasq(8)\fR
221 or \fB\fCsystemd\-resolved.service(8)\fR) that cannot be accessed from the namespace.
222
223 .PP
224 If your \fB\fC/etc/resolv.conf\fR on the host is managed by \fB\fCnetworkmanager(8)\fR
225 or \fB\fCsystemd\-resolved.service(8)\fR, you might need to mount a new filesystem on
226 \fB\fC/etc\fR instead, so as to prevent the new \fB\fC/etc/resolv.conf\fR from being
227 unmounted unexpectedly when \fB\fC/etc/resolv.conf\fR on the host is regenerated.
228
229 .PP
230 .RS
231
232 .nf
233 (namespace)$ mkdir /tmp/a /tmp/b
234 (namespace)$ mount \-\-rbind /etc /tmp/a
235 (namespace)$ mount \-\-rbind /tmp/b /etc
236 (namespace)$ mkdir /etc/.ro
237 (namespace)$ mount \-\-move /tmp/a /etc/.ro
238 (namespace)$ cd /etc
239 (namespace)$ for f in .ro/*; do ln \-s $f $(basename $f); done
240 (namespace)$ rm resolv.conf
241 (namespace)$ echo "nameserver 10.0.2.3" > resolv.conf
242 (namespace)$ curl https://example.com
243
244 .fi
245 .RE
246
247 .PP
248 These steps can be simplified with \fB\fCrootlesskit \-\-copy\-up=/etc\fR if \fB\fCrootlesskit\fR is installed:
249
250 .PP
251 .RS
252
253 .nf
254 (host)$ rootlesskit \-\-net=slirp4netns \-\-copy\-up=/etc bash
255 (namespace)$ cat /etc/resolv.conf
256 nameserver 10.0.2.3
191257
192258 .fi
193259 .RE
195261
196262 .SH ROUTING PING PACKETS
197263 .PP
198 To route ping packets, you need to set up \fBnet.ipv4.ping\_group\_range\fP properly
199 as the root.
264 To route ping packets, you may need to set up \fB\fCnet.ipv4.ping\_group\_range\fR properly as the root.
200265
201266 .PP
202267 e.g.
205270 .RS
206271
207272 .nf
208 $ sudo sh \-c "echo 0 2147483647 > /proc/sys/net/ipv4/ping\_group\_range"
273 (host)$ sudo sh \-c 'echo "net.ipv4.ping\_group\_range=0 2147483647" > /etc/sysctl.d/ping\_group\_range.conf'
274 (host)$ sudo sysctl \-\-system
209275
210276 .fi
211277 .RE
213279
214280 .SH FILTERING CONNECTIONS
215281 .PP
216 By default, ports listening on \fBINADDR\_LOOPBACK\fP (\fB127.0.0.1\fP) on the host are accessible from the child namespace via the gateway (default: \fB10.0.2.2\fP).
217 \fB\-\-disable\-host\-loopback\fP can be used to prohibit connecting to \fBINADDR\_LOOPBACK\fP on the host.
218
219 .PP
220 However, a host loopback address might be still accessible via the built\-in DNS (default: \fB10.0.2.3\fP) if \fB\fC/etc/resolv.conf\fR on the host refers to a loopback address.
282 By default, ports listening on \fB\fCINADDR\_LOOPBACK\fR (\fB\fC127.0.0.1\fR) on the host are accessible from the child namespace via the gateway (default: \fB\fC10.0.2.2\fR).
283 \fB\fC\-\-disable\-host\-loopback\fR can be used to prohibit connecting to \fB\fCINADDR\_LOOPBACK\fR on the host.
284
285 .PP
286 However, a host loopback address might be still accessible via the built\-in DNS (default: \fB\fC10.0.2.3\fR) if \fB\fC/etc/resolv.conf\fR on the host refers to a loopback address.
221287 You may want to set up iptables for limiting access to the built\-in DNS in such a case.
222288
223289 .PP
224290 .RS
225291
226292 .nf
227 unshared$ iptables \-A OUTPUT \-d 10.0.2.3 \-p udp \-\-dport 53 \-j ACCEPT
228 unshared$ iptables \-A OUTPUT \-d 10.0.2.3 \-j DROP
293 (host)$ nsenter \-t $(cat /tmp/pid) \-U \-\-preserve\-credentials \-n
294 (namespace)$ iptables \-A OUTPUT \-d 10.0.2.3 \-p udp \-\-dport 53 \-j ACCEPT
295 (namespace)$ iptables \-A OUTPUT \-d 10.0.2.3 \-j DROP
229296
230297 .fi
231298 .RE
239306 .RS
240307
241308 .nf
242 $ slirp4netns \-\-api\-socket /tmp/slirp4netns.sock ...
243
244 .fi
245 .RE
246
247 .PP
248 \fBadd\_hostfwd\fP: Expose a port (IPv4 only)
249
250 .PP
251 .RS
252
253 .nf
254 $ json='{"execute": "add\_hostfwd", "arguments": {"proto": "tcp", "host\_addr": "0.0.0.0", "host\_port": 8080, "guest\_addr": "10.0.2.100", "guest\_port": 80}}'
255 $ echo \-n $json | nc \-U /tmp/slirp4netns.sock
256 { "return": {"id": 42}}
257
258 .fi
259 .RE
260
261 .PP
262 If \fBhost\_addr\fP is not specified, then it defaults to "0.0.0.0".
263
264 .PP
265 If \fBguest\_addr\fP is not specified, then it will be set to the default address that corresponds to \-\-configure.
266
267 .PP
268 \fBlist\_hostfwd\fP: List exposed ports
269
270 .PP
271 .RS
272
273 .nf
274 $ json='{"execute": "list\_hostfwd"}'
275 $ echo \-n $json | nc \-U /tmp/slirp4netns.sock
276 { "return": {"entries": [{"id": 42, "proto": "tcp", "host\_addr": "0.0.0.0", "host\_port": 8080, "guest\_addr": "10.0.2.100", "guest\_port": 80}]}}
277
278 .fi
279 .RE
280
281 .PP
282 \fBremove\_hostfwd\fP: Remove an exposed port
283
284 .PP
285 .RS
286
287 .nf
288 $ json='{"execute": "remove\_hostfwd", "arguments": {"id": 42}}'
289 $ echo \-n $json | nc \-U /tmp/slirp4netns.sock
290 { "return": {}}
309 (host)$ slirp4netns \-\-api\-socket /tmp/slirp4netns.sock ...
310
311 .fi
312 .RE
313
314 .PP
315 \fB\fCadd\_hostfwd\fR: Expose a port (IPv4 only)
316
317 .PP
318 .RS
319
320 .nf
321 (namespace)$ json='{"execute": "add\_hostfwd", "arguments": {"proto": "tcp", "host\_addr": "0.0.0.0", "host\_port": 8080, "guest\_addr": "10.0.2.100", "guest\_port": 80}}'
322 (namespace)$ echo \-n $json | nc \-U /tmp/slirp4netns.sock
323 {"return": {"id": 42}}
324
325 .fi
326 .RE
327
328 .PP
329 If \fB\fChost\_addr\fR is not specified, then it defaults to "0.0.0.0".
330
331 .PP
332 If \fB\fCguest\_addr\fR is not specified, then it will be set to the default address that corresponds to \fB\fC\-\-configure\fR\&.
333
334 .PP
335 \fB\fClist\_hostfwd\fR: List exposed ports
336
337 .PP
338 .RS
339
340 .nf
341 (namespace)$ json='{"execute": "list\_hostfwd"}'
342 (namespace)$ echo \-n $json | nc \-U /tmp/slirp4netns.sock
343 {"return": {"entries": [{"id": 42, "proto": "tcp", "host\_addr": "0.0.0.0", "host\_port": 8080, "guest\_addr": "10.0.2.100", "guest\_port": 80}]}}
344
345 .fi
346 .RE
347
348 .PP
349 \fB\fCremove\_hostfwd\fR: Remove an exposed port
350
351 .PP
352 .RS
353
354 .nf
355 (namespace)$ json='{"execute": "remove\_hostfwd", "arguments": {"id": 42}}'
356 (namespace)$ echo \-n $json | nc \-U /tmp/slirp4netns.sock
357 {"return": {}}
291358
292359 .fi
293360 .RE
297364
298365 .RS
299366 .IP \(bu 2
300 Client needs to \fBshutdown(2)\fP the socket with \fBSHUT\_WR\fP after sending every request.
367 Client needs to \fB\fCshutdown(2)\fR the socket with \fB\fCSHUT\_WR\fR after sending every request.
301368 i.e. No support for keep\-alive and timeout.
302369 .IP \(bu 2
303370 slirp4netns "stops the world" during processing API requests.
304371 .IP \(bu 2
305372 A request must be less than 4096 bytes.
306373 .IP \(bu 2
307 JSON responses may contain \fBerror\fP instead of \fBreturn\fP\&.
374 JSON responses may contain \fB\fCerror\fR instead of \fB\fCreturn\fR\&.
308375
309376 .RE
310377
317384 .RS
318385
319386 .nf
320 $ slirp4netns \-\-netns\-type=path ... /path/to/netns tap0
321
322 .fi
323 .RE
324
325 .PP
326 Currently, the \fBnetns\-type=TYPE\fP argument supports \fBpath\fP or \fBpid\fP args with the default being \fBpid\fP\&.
327
328 .PP
329 Additionally, a \fB\-\-userns\-path=PATH\fP argument can be included to override any user namespace path defaults
330
331 .PP
332 .RS
333
334 .nf
335 $ slirp4netns \-\-netns\-type=path \-\-userns\-path=/path/to/userns /path/to/netns tap0
336
337 .fi
338 .RE
387 (host)$ slirp4netns \-\-netns\-type=path ... /path/to/netns tap0
388
389 .fi
390 .RE
391
392 .PP
393 Currently, the \fB\fCnetns\-type=TYPE\fR argument supports \fB\fCpath\fR or \fB\fCpid\fR args with the default being \fB\fCpid\fR\&.
394
395 .PP
396 Additionally, a \fB\fC\-\-userns\-path=PATH\fR argument can be included to override any user namespace path defaults
397
398 .PP
399 .RS
400
401 .nf
402 (host)$ slirp4netns \-\-netns\-type=path \-\-userns\-path=/path/to/userns /path/to/netns tap0
403
404 .fi
405 .RE
406
407
408 .SH OUTBOUND ADDRESSES
409 .PP
410 A user can defined preferred outbound ipv4 and ipv6 address in multi IP scenarios.
411
412 .PP
413 .RS
414
415 .nf
416 (host)$ slirp4netns \-\-outbound\-addr=10.2.2.10 \-\-outbound\-addr6=fe80::10 ...
417
418 .fi
419 .RE
420
421 .PP
422 Optionally you can use interface names instead of ip addresses.
423
424 .PP
425 .RS
426
427 .nf
428 (host)$ slirp4netns \-\-outbound\-addr=eth0 \-\-outbound\-addr6=eth0 ...
429
430 .fi
431 .RE
432
433
434 .SH INTER\-NAMESPACE COMMUNICATION
435 .PP
436 The easiest way to allow inter\-namespace communication is to nest network namespaces inside the slirp4netns's network namespace.
437
438 .PP
439 .RS
440
441 .nf
442 (host)$ nsenter \-t $(cat /tmp/pid) \-U \-\-preserve\-credentials \-n \-m
443 (namespace)$ mount \-t tmpfs none /run
444 (namespace)$ ip netns add foo
445 (namespace)$ ip netns add bar
446 (namespace)$ ip link add veth\-foo type veth peer name veth\-bar
447 (namespace)$ ip link set veth\-foo netns foo
448 (namespace)$ ip link set veth\-bar netns bar
449 (namespace)$ ip netns exec foo ip link set veth\-foo name eth0
450 (namespace)$ ip netns exec bar ip link set veth\-bar name eth0
451 (namespace)$ ip netns exec foo ip link set lo up
452 (namespace)$ ip netns exec bar ip link set lo up
453 (namespace)$ ip netns exec foo ip link set eth0 up
454 (namespace)$ ip netns exec bar ip link set eth0 up
455 (namespace)$ ip netns exec foo ip addr add 192.168.42.100/24 dev eth0
456 (namespace)$ ip netns exec bar ip addr add 192.168.42.101/24 dev eth0
457 (namespace)$ ip netns exec bar ping 192.168.42.100
458
459 .fi
460 .RE
461
462 .PP
463 However, this method does not work when you want to allow communication across multiple slirp4netns instances.
464 To allow communication across multiple slirp4netns instances, you need to combine another network stack such as
465 \fB\fCvde\_plug(1)\fR with slirp4netns.
466
467 .PP
468 .RS
469
470 .nf
471 (host)$ vde\_plug \-\-daemon switch:///tmp/switch null://
472 (host)$ nsenter \-t $(cat /tmp/pid\-instance0) \-U \-\-preserve\-credentials \-n
473 (namespace\-instance0)$ vde\_plug \-\-daemon vde:///tmp/switch tap://vde
474 (namespace\-instance0)$ ip link set vde up
475 (namespace\-instance0)$ ip addr add 192.168.42.100/24 dev vde
476 (namespace\-instance0)$ exit
477 (host)$ nsenter \-t $(cat /tmp/pid\-instance1) \-U \-\-preserve\-credentials \-n
478 (namespace\-instance1)$ vde\_plug \-\-daemon vde:///tmp/switch tap://vde
479 (namespace\-instance1)$ ip link set vde up
480 (namespace\-instance1)$ ip addr add 192.168.42.101/24 dev vde
481 (namespace\-instance1)$ ping 192.168.42.100
482
483 .fi
484 .RE
485
486
487 .SH INTER\-HOST COMMUNICATION
488 .PP
489 VXLAN is known to work.
490 See Usernetes project for the example of multi\-node rootless Kubernetes cluster with VXLAN: \fB\fChttps://github.com/rootless\-containers/usernetes\fR
491
492
493 .SH BESS MODE (FOR USER MODE LINUX)
494 .PP
495 slirp4netns (since v1.2.0) can be also used as a BESS\-compatible server to provide network connectivity to User Mode Linux.
496
497 .PP
498 \fBTerminal 1\fP: Start slirp4netns
499
500 .PP
501 .RS
502
503 .nf
504 (host)$ slirp4netns \-\-target\-type=bess /tmp/bess.sock
505
506 .fi
507 .RE
508
509 .PP
510 \fBTerminal 2\fP: Start User Mode Linux
511
512 .PP
513 .RS
514
515 .nf
516 (host)$ linux.uml vec0:transport=bess,dst=/tmp/bess.sock,depth=128,gro=1 root=/dev/root rootfstype=hostfs init=/bin/bash mem=2G
517 (UML)$ ip addr add 10.0.2.100/24 dev vec0
518 (UML)$ ip link set vec0 up
519 (UML)$ ip route add default via 10.0.2.2
520
521 .fi
522 .RE
523
524 .PP
525 Currently, only a single instance of User Mode Linux can be connected to the slirp4netns BESS server.
526
527 .PP
528 See also User Mode Linux documentation: \fB\fChttps://www.kernel.org/doc/html/latest/virt/uml/user\_mode\_linux\_howto\_v2.html#bess\-socket\-transport\fR
339529
340530
341531 .SH BUGS
342532 .PP
343 Kernel 4.20 bumped up the default value of \fB/proc/sys/net/ipv4/tcp\_rmem\fP from 87380 to 131072.
344 This is known to slow down slirp4netns port forwarding: \fBhttps://github.com/rootless\-containers/slirp4netns/issues/128\fP\&.
345
346 .PP
347 As a workaround, you can adjust the value of \fB/proc/sys/net/ipv4/tcp\_rmem\fP inside the namespace.
533 Kernel 4.20 bumped up the default value of \fB\fC/proc/sys/net/ipv4/tcp\_rmem\fR from 87380 to 131072.
534 This is known to slow down slirp4netns port forwarding: \fB\fChttps://github.com/rootless\-containers/slirp4netns/issues/128\fR\&.
535
536 .PP
537 As a workaround, you can adjust the value of \fB\fC/proc/sys/net/ipv4/tcp\_rmem\fR inside the namespace.
348538 No real root privilege is needed to modify the file since kernel 4.15.
349539
350540 .PP
351541 .RS
352542
353543 .nf
354 unshared$ c=$(cat /proc/sys/net/ipv4/tcp\_rmem); echo $c | sed \-e s/131072/87380/g > /proc/sys/net/ipv4/tcp\_rmem
544 (host)$ nsenter \-t $(cat /tmp/pid) \-U \-\-preserve\-credentials \-n \-m
545 (namespace)$ c=$(cat /proc/sys/net/ipv4/tcp\_rmem); echo $c | sed \-e s/131072/87380/g > /proc/sys/net/ipv4/tcp\_rmem
355546
356547 .fi
357548 .RE
359550
360551 .SH SEE ALSO
361552 .PP
362 \fBnetwork\_namespaces\fP(7), \fBuser\_namespaces\fP(7), \fBveth\fP(4)
553 \fB\fCnetwork\_namespaces(7)\fR, \fB\fCuser\_namespaces(7)\fR, \fB\fCveth(4)\fR
363554
364555
365556 .SH AVAILABILITY
366557 .PP
367 The slirp4netns command is available from \fBhttps://github.com/rootless\-containers/slirp4netns\fP under GNU GENERAL PUBLIC LICENSE Version 2 (or later).
558 The slirp4netns command is available from \fB\fChttps://github.com/rootless\-containers/slirp4netns\fR under GNU GENERAL PUBLIC LICENSE Version 2 (or later).
0 SLIRP4NETNS 1 "March 2020" "Rootless Containers" "User Commands"
0 SLIRP4NETNS 1 "January 2022" "Rootless Containers" "User Commands"
11 ==================================================
22
33 # NAME
66
77 # SYNOPSIS
88
9 slirp4netns [OPTION]... PID|PATH TAPNAME
9 slirp4netns [OPTION]... PID|PATH [TAPNAME]
1010
1111 # DESCRIPTION
1212
1313 slirp4netns provides user-mode networking ("slirp") for network namespaces.
1414
15 Unlike **veth**(4), slirp4netns does not require the root privileges on the host.
15 Unlike `veth(4)`, slirp4netns does not require the root privileges on the host.
1616
1717 Default configuration:
1818
2020 * CIDR: 10.0.2.0/24
2121 * Gateway/Host: 10.0.2.2 (network address + 2)
2222 * DNS: 10.0.2.3 (network address + 3)
23 * DHCP begin: 10.0.2.15 (network address + 15)
24 * DHCP end: 10.0.2.30 (network address + 30)
2325 * IPv6 CIDR: fd00::/64
2426 * IPv6 Gateway/Host: fd00::2
2527 * IPv6 DNS: fd00::3
2628
2729 # OPTIONS
2830
29 **-c**, **--configure**
31 `-c`, `--configure`
3032 bring up the TAP interface. IP will be set to 10.0.2.100 (network address + 100) by default. IPv6 will be set to a random address.
31 Starting with v0.4.0, the loopback interface (**lo**) is brought up as well.
32
33 **-e**, **--exit-fd=FD**
33 Starting with v0.4.0, the loopback interface (`lo`) is brought up as well.
34
35 `-e`, `--exit-fd=FD`
3436 specify the FD for terminating slirp4netns.
35 When the FD is specified, slirp4netns exits when a **poll(2)** event happens on the FD.
36
37 **-r**, **--ready-fd=FD**
37 When the FD is specified, slirp4netns exits when a `poll(2)` event happens on the FD.
38
39 `-r`, `--ready-fd=FD`
3840 specify the FD to write to when the initialization steps are finished.
39 When the FD is specified, slirp4netns writes **"1"** to the FD and close the FD.
40 Prior to v0.4.0, the FD was written after the network configuration (**-c**)
41 but before the API socket configuration (**-a**).
42
43 **-m**, **--mtu=MTU** (since v0.2.0)
41 When the FD is specified, slirp4netns writes `"1"` to the FD and close the FD.
42 Prior to v0.4.0, the FD was written after the network configuration (`-c`)
43 but before the API socket configuration (`-a`).
44
45 `-m`, `--mtu=MTU` (since v0.2.0)
4446 specify MTU (max=65521).
4547
46 **-6**, **--enable-ipv6** (since v0.2.0, EXPERIMENTAL)
48 `-6`, `--enable-ipv6` (since v0.2.0, EXPERIMENTAL)
4749 enable IPv6
4850
49 **-a**, **--api-socket** (since v0.3.0)
51 `-a`, `--api-socket` (since v0.3.0)
5052 API socket path
5153
52 **--cidr** (since v0.3.0)
54 `--cidr` (since v0.3.0)
5355 specify CIDR, e.g. 10.0.2.0/24
5456
55 **--disable-host-loopback** (since v0.3.0)
57 `--disable-host-loopback` (since v0.3.0)
5658 prohibit connecting to 127.0.0.1:\* on the host namespace
5759
58 **--netns-type=TYPE** (since v0.4.0)
60 `--netns-type=TYPE` (since v0.4.0)
5961 specify network namespace type ([path|pid], default=pid)
6062
61 **--userns-path=PATH** (since v0.4.0)
63 `--userns-path=PATH` (since v0.4.0)
6264 specify user namespace path
6365
64 **--enable-sandbox** (since v0.4.0)
66 `--enable-sandbox` (since v0.4.0)
6567 enter the user namespace and create a new mount namespace where only /etc and
6668 /run are mounted from the host.
6769
68 Requires **/etc/resolv.conf** not to be a symlink to a file outside /etc and /run.
70 Requires `/etc/resolv.conf` not to be a symlink to a file outside /etc and /run.
6971
7072 When running as the root, the process does not enter the user namespace but all
7173 the capabilities except `CAP_NET_BIND_SERVICE` are dropped.
7274
73 **--enable-seccomp** (since v0.4.0, EXPERIMENTAL)
74 enable **seccomp(2)** to limit syscalls.
75 Typically used in conjunction with **--enable-sandbox**.
76
77 **-h**, **--help** (since v0.2.0)
75 `--enable-seccomp` (since v0.4.0, EXPERIMENTAL)
76 enable `seccomp(2)` to limit syscalls.
77 Typically used in conjunction with `--enable-sandbox`.
78
79 `--outbound-addr=IPv4` (since v1.1.0, EXPERIMENTAL)
80 specify outbound ipv4 address slirp should bind to
81
82 `--outbound-addr=INTERFACE` (since v1.1.0, EXPERIMENTAL)
83 specify outbound interface slirp should bind to (ipv4 traffic only)
84
85 `--outbound-addr=IPv6` (since v1.1.0, EXPERIMENTAL)
86 specify outbound ipv6 address slirp should bind to
87
88 `--outbound-addr6=INTERFACE` (since v1.1.0, EXPERIMENTAL)
89 specify outbound interface slirp should bind to (ipv6 traffic only)
90
91 `--disable-dns` (since v1.1.0)
92 disable built-in DNS (10.0.2.3 by default)
93
94 `--macaddress` (since v1.1.9)
95 specify MAC address of the TAP interface (only valid with -c)
96
97 `--target-type=TYPE` (since v1.2.0)
98 specify the target type ([netns|bess], default=netns).
99
100 The `bess` mode (since v1.2.0, EXPERIMENTAL) is expected to be used with User Mode Linux.
101 The `bess` mode conflicts with `--configure`, `--netns-type`, and `--userns-path`.
102
103 `-h`, `--help` (since v0.2.0)
78104 show help and exit
79105
80 **-v**, **--version** (since v0.2.0)
106 `-v`, `--version` (since v0.2.0)
81107 show version and exit
82108
109
83110 # EXAMPLE
84111
85 Terminal 1: Create user/network/mount namespaces
86 ```console
87 $ unshare --user --map-root-user --net --mount
88 unshared$ echo $$ > /tmp/pid
89 ```
90
91 Terminal 2: Start slirp4netns
92 ```console
93 $ slirp4netns --configure --mtu=65520 $(cat /tmp/pid) tap0
112 **Terminal 1**: Create user/network/mount namespaces
113
114 ```console
115 (host)$ unshare --user --map-root-user --net --mount
116 (namespace)$ echo $$ > /tmp/pid
117 ```
118
119 In this documentation, we use `(host)$` as the prompt of the host shell, `(namespace)$` as the prompt of the shell running in the namespaces.
120
121 If `unshare` fails, try the following commands (known to be needed on Debian, Arch, and old CentOS 7.X):
122
123 ```console
124 (host)$ sudo sh -c 'echo "user.max_user_namespaces=28633" >> /etc/sysctl.d/userns.conf'
125 (host)$ if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then sudo sh -c 'echo "kernel.unprivileged_userns_clone=1" >> /etc/sysctl.d/userns.conf'; fi
126 (host)$ sudo sysctl --system
127 ```
128
129 **Terminal 2**: Start slirp4netns
130
131 ```console
132 (host)$ slirp4netns --configure --mtu=65520 $(cat /tmp/pid) tap0
94133 starting slirp, MTU=65520
95134 ...
96135 ```
97136
98 Terminal 1: Make sure **tap0** is configured and connected to the Internet
99 ```console
100 unshared$ ip a
137 **Terminal 1**: Make sure `tap0` is configured and connected to the Internet
138
139 ```console
140 (namespace)$ ip a
101141 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
102142 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
103143 3: tap0: <BROADCAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
106146 valid_lft forever preferred_lft forever
107147 inet6 fe80::c028:cff:fe0e:2906/64 scope link
108148 valid_lft forever preferred_lft forever
109 unshared$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
110 unshared$ mount --bind /tmp/resolv.conf /etc/resolv.conf
111 unshared$ curl https://example.com
112 ```
113
114 Bind-mounting **/etc/resolv.conf** is only needed when **/etc/resolv.conf** on
115 the host refers to loopback addresses (**127.0.0.X**, typically because of
116 **dnsmasq**(8) or **systemd-resolved.service**(8)) that cannot be accessed from
117 the namespace.
118
119 If your **/etc/resolv.conf** on the host is managed by **networkmanager**(8)
120 or **systemd-resolved.service**(8), you might need to mount a new filesystem on
121 **/etc** instead, so as to prevent the new **/etc/resolv.conf** from being
122 unmounted unexpectedly when **/etc/resolv.conf** on the host is regenerated.
123
124 ```console
125 unshared$ mkdir /tmp/a /tmp/b
126 unshared$ mount --rbind /etc /tmp/a
127 unshared$ mount --rbind /tmp/b /etc
128 unshared$ mkdir /etc/.ro
129 unshared$ mount --move /tmp/a /etc/.ro
130 unshared$ cd /etc
131 unshared$ for f in .ro/*; do ln -s $f $(basename $f); done
132 unshared$ rm resolv.conf
133 unshared$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
134 unshared$ curl https://example.com
149 (namespace)$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
150 (namespace)$ mount --bind /tmp/resolv.conf /etc/resolv.conf
151 (namespace)$ curl https://example.com
152 ```
153
154 Bind-mounting `/etc/resolv.conf` is only needed when `/etc/resolv.conf` on
155 the host refers to loopback addresses (`127.0.0.X`, typically `dnsmasq(8)`
156 or `systemd-resolved.service(8)`) that cannot be accessed from the namespace.
157
158 If your `/etc/resolv.conf` on the host is managed by `networkmanager(8)`
159 or `systemd-resolved.service(8)`, you might need to mount a new filesystem on
160 `/etc` instead, so as to prevent the new `/etc/resolv.conf` from being
161 unmounted unexpectedly when `/etc/resolv.conf` on the host is regenerated.
162
163 ```console
164 (namespace)$ mkdir /tmp/a /tmp/b
165 (namespace)$ mount --rbind /etc /tmp/a
166 (namespace)$ mount --rbind /tmp/b /etc
167 (namespace)$ mkdir /etc/.ro
168 (namespace)$ mount --move /tmp/a /etc/.ro
169 (namespace)$ cd /etc
170 (namespace)$ for f in .ro/*; do ln -s $f $(basename $f); done
171 (namespace)$ rm resolv.conf
172 (namespace)$ echo "nameserver 10.0.2.3" > resolv.conf
173 (namespace)$ curl https://example.com
174 ```
175
176 These steps can be simplified with `rootlesskit --copy-up=/etc` if `rootlesskit` is installed:
177 ```console
178 (host)$ rootlesskit --net=slirp4netns --copy-up=/etc bash
179 (namespace)$ cat /etc/resolv.conf
180 nameserver 10.0.2.3
135181 ```
136182
137183 # ROUTING PING PACKETS
138184
139 To route ping packets, you need to set up **net.ipv4.ping_group_range** properly
140 as the root.
185 To route ping packets, you may need to set up `net.ipv4.ping_group_range` properly as the root.
141186
142187 e.g.
143188 ```console
144 $ sudo sh -c "echo 0 2147483647 > /proc/sys/net/ipv4/ping_group_range"
189 (host)$ sudo sh -c 'echo "net.ipv4.ping_group_range=0 2147483647" > /etc/sysctl.d/ping_group_range.conf'
190 (host)$ sudo sysctl --system
145191 ```
146192
147193 # FILTERING CONNECTIONS
148194
149 By default, ports listening on **INADDR_LOOPBACK** (**127.0.0.1**) on the host are accessible from the child namespace via the gateway (default: **10.0.2.2**).
150 **--disable-host-loopback** can be used to prohibit connecting to **INADDR_LOOPBACK** on the host.
151
152 However, a host loopback address might be still accessible via the built-in DNS (default: **10.0.2.3**) if `/etc/resolv.conf` on the host refers to a loopback address.
195 By default, ports listening on `INADDR_LOOPBACK` (`127.0.0.1`) on the host are accessible from the child namespace via the gateway (default: `10.0.2.2`).
196 `--disable-host-loopback` can be used to prohibit connecting to `INADDR_LOOPBACK` on the host.
197
198 However, a host loopback address might be still accessible via the built-in DNS (default: `10.0.2.3`) if `/etc/resolv.conf` on the host refers to a loopback address.
153199 You may want to set up iptables for limiting access to the built-in DNS in such a case.
154200
155201 ```console
156 unshared$ iptables -A OUTPUT -d 10.0.2.3 -p udp --dport 53 -j ACCEPT
157 unshared$ iptables -A OUTPUT -d 10.0.2.3 -j DROP
202 (host)$ nsenter -t $(cat /tmp/pid) -U --preserve-credentials -n
203 (namespace)$ iptables -A OUTPUT -d 10.0.2.3 -p udp --dport 53 -j ACCEPT
204 (namespace)$ iptables -A OUTPUT -d 10.0.2.3 -j DROP
158205 ```
159206
160207 # API SOCKET
162209 slirp4netns can provide QMP-like API server over an UNIX socket file:
163210
164211 ```console
165 $ slirp4netns --api-socket /tmp/slirp4netns.sock ...
166 ```
167
168 **add_hostfwd**: Expose a port (IPv4 only)
169
170 ```console
171 $ json='{"execute": "add_hostfwd", "arguments": {"proto": "tcp", "host_addr": "0.0.0.0", "host_port": 8080, "guest_addr": "10.0.2.100", "guest_port": 80}}'
172 $ echo -n $json | nc -U /tmp/slirp4netns.sock
173 { "return": {"id": 42}}
174 ```
175
176 If **host_addr** is not specified, then it defaults to "0.0.0.0".
177
178 If **guest_addr** is not specified, then it will be set to the default address that corresponds to --configure.
179
180 **list_hostfwd**: List exposed ports
181
182 ```console
183 $ json='{"execute": "list_hostfwd"}'
184 $ echo -n $json | nc -U /tmp/slirp4netns.sock
185 { "return": {"entries": [{"id": 42, "proto": "tcp", "host_addr": "0.0.0.0", "host_port": 8080, "guest_addr": "10.0.2.100", "guest_port": 80}]}}
186 ```
187
188 **remove_hostfwd**: Remove an exposed port
189
190 ```console
191 $ json='{"execute": "remove_hostfwd", "arguments": {"id": 42}}'
192 $ echo -n $json | nc -U /tmp/slirp4netns.sock
193 { "return": {}}
212 (host)$ slirp4netns --api-socket /tmp/slirp4netns.sock ...
213 ```
214
215 `add_hostfwd`: Expose a port (IPv4 only)
216
217 ```console
218 (namespace)$ json='{"execute": "add_hostfwd", "arguments": {"proto": "tcp", "host_addr": "0.0.0.0", "host_port": 8080, "guest_addr": "10.0.2.100", "guest_port": 80}}'
219 (namespace)$ echo -n $json | nc -U /tmp/slirp4netns.sock
220 {"return": {"id": 42}}
221 ```
222
223 If `host_addr` is not specified, then it defaults to "0.0.0.0".
224
225 If `guest_addr` is not specified, then it will be set to the default address that corresponds to `--configure`.
226
227 `list_hostfwd`: List exposed ports
228
229 ```console
230 (namespace)$ json='{"execute": "list_hostfwd"}'
231 (namespace)$ echo -n $json | nc -U /tmp/slirp4netns.sock
232 {"return": {"entries": [{"id": 42, "proto": "tcp", "host_addr": "0.0.0.0", "host_port": 8080, "guest_addr": "10.0.2.100", "guest_port": 80}]}}
233 ```
234
235 `remove_hostfwd`: Remove an exposed port
236
237 ```console
238 (namespace)$ json='{"execute": "remove_hostfwd", "arguments": {"id": 42}}'
239 (namespace)$ echo -n $json | nc -U /tmp/slirp4netns.sock
240 {"return": {}}
194241 ```
195242
196243 Remarks:
197244
198 * Client needs to **shutdown(2)** the socket with **SHUT_WR** after sending every request.
245 * Client needs to `shutdown(2)` the socket with `SHUT_WR` after sending every request.
199246 i.e. No support for keep-alive and timeout.
200247 * slirp4netns "stops the world" during processing API requests.
201248 * A request must be less than 4096 bytes.
202 * JSON responses may contain **error** instead of **return**.
249 * JSON responses may contain `error` instead of `return`.
203250
204251 # DEFINED NAMESPACE PATHS
205252 A user can define a network namespace path as opposed to the default process ID:
206253
207254 ```console
208 $ slirp4netns --netns-type=path ... /path/to/netns tap0
209 ```
210 Currently, the **netns-type=TYPE** argument supports **path** or **pid** args with the default being **pid**.
211
212 Additionally, a **--userns-path=PATH** argument can be included to override any user namespace path defaults
213 ```console
214 $ slirp4netns --netns-type=path --userns-path=/path/to/userns /path/to/netns tap0
215 ```
255 (host)$ slirp4netns --netns-type=path ... /path/to/netns tap0
256 ```
257 Currently, the `netns-type=TYPE` argument supports `path` or `pid` args with the default being `pid`.
258
259 Additionally, a `--userns-path=PATH` argument can be included to override any user namespace path defaults
260 ```console
261 (host)$ slirp4netns --netns-type=path --userns-path=/path/to/userns /path/to/netns tap0
262 ```
263
264 # OUTBOUND ADDRESSES
265 A user can defined preferred outbound ipv4 and ipv6 address in multi IP scenarios.
266
267 ```console
268 (host)$ slirp4netns --outbound-addr=10.2.2.10 --outbound-addr6=fe80::10 ...
269 ```
270
271 Optionally you can use interface names instead of ip addresses.
272
273 ```console
274 (host)$ slirp4netns --outbound-addr=eth0 --outbound-addr6=eth0 ...
275 ```
276
277 # INTER-NAMESPACE COMMUNICATION
278
279 The easiest way to allow inter-namespace communication is to nest network namespaces inside the slirp4netns's network namespace.
280
281 ```console
282 (host)$ nsenter -t $(cat /tmp/pid) -U --preserve-credentials -n -m
283 (namespace)$ mount -t tmpfs none /run
284 (namespace)$ ip netns add foo
285 (namespace)$ ip netns add bar
286 (namespace)$ ip link add veth-foo type veth peer name veth-bar
287 (namespace)$ ip link set veth-foo netns foo
288 (namespace)$ ip link set veth-bar netns bar
289 (namespace)$ ip netns exec foo ip link set veth-foo name eth0
290 (namespace)$ ip netns exec bar ip link set veth-bar name eth0
291 (namespace)$ ip netns exec foo ip link set lo up
292 (namespace)$ ip netns exec bar ip link set lo up
293 (namespace)$ ip netns exec foo ip link set eth0 up
294 (namespace)$ ip netns exec bar ip link set eth0 up
295 (namespace)$ ip netns exec foo ip addr add 192.168.42.100/24 dev eth0
296 (namespace)$ ip netns exec bar ip addr add 192.168.42.101/24 dev eth0
297 (namespace)$ ip netns exec bar ping 192.168.42.100
298 ```
299
300 However, this method does not work when you want to allow communication across multiple slirp4netns instances.
301 To allow communication across multiple slirp4netns instances, you need to combine another network stack such as
302 `vde_plug(1)` with slirp4netns.
303
304 ```console
305 (host)$ vde_plug --daemon switch:///tmp/switch null://
306 (host)$ nsenter -t $(cat /tmp/pid-instance0) -U --preserve-credentials -n
307 (namespace-instance0)$ vde_plug --daemon vde:///tmp/switch tap://vde
308 (namespace-instance0)$ ip link set vde up
309 (namespace-instance0)$ ip addr add 192.168.42.100/24 dev vde
310 (namespace-instance0)$ exit
311 (host)$ nsenter -t $(cat /tmp/pid-instance1) -U --preserve-credentials -n
312 (namespace-instance1)$ vde_plug --daemon vde:///tmp/switch tap://vde
313 (namespace-instance1)$ ip link set vde up
314 (namespace-instance1)$ ip addr add 192.168.42.101/24 dev vde
315 (namespace-instance1)$ ping 192.168.42.100
316 ```
317
318 # INTER-HOST COMMUNICATION
319
320 VXLAN is known to work.
321 See Usernetes project for the example of multi-node rootless Kubernetes cluster with VXLAN: `https://github.com/rootless-containers/usernetes`
322
323 # BESS MODE (FOR USER MODE LINUX)
324 slirp4netns (since v1.2.0) can be also used as a BESS-compatible server to provide network connectivity to User Mode Linux.
325
326 **Terminal 1**: Start slirp4netns
327
328 ```console
329 (host)$ slirp4netns --target-type=bess /tmp/bess.sock
330 ```
331
332 **Terminal 2**: Start User Mode Linux
333
334 ```console
335 (host)$ linux.uml vec0:transport=bess,dst=/tmp/bess.sock,depth=128,gro=1 root=/dev/root rootfstype=hostfs init=/bin/bash mem=2G
336 (UML)$ ip addr add 10.0.2.100/24 dev vec0
337 (UML)$ ip link set vec0 up
338 (UML)$ ip route add default via 10.0.2.2
339 ```
340
341 Currently, only a single instance of User Mode Linux can be connected to the slirp4netns BESS server.
342
343 See also User Mode Linux documentation: `https://www.kernel.org/doc/html/latest/virt/uml/user_mode_linux_howto_v2.html#bess-socket-transport`
216344
217345 # BUGS
218346
219 Kernel 4.20 bumped up the default value of **/proc/sys/net/ipv4/tcp_rmem** from 87380 to 131072.
220 This is known to slow down slirp4netns port forwarding: **https://github.com/rootless-containers/slirp4netns/issues/128**.
221
222 As a workaround, you can adjust the value of **/proc/sys/net/ipv4/tcp_rmem** inside the namespace.
347 Kernel 4.20 bumped up the default value of `/proc/sys/net/ipv4/tcp_rmem` from 87380 to 131072.
348 This is known to slow down slirp4netns port forwarding: `https://github.com/rootless-containers/slirp4netns/issues/128`.
349
350 As a workaround, you can adjust the value of `/proc/sys/net/ipv4/tcp_rmem` inside the namespace.
223351 No real root privilege is needed to modify the file since kernel 4.15.
224352
225353 ```console
226 unshared$ c=$(cat /proc/sys/net/ipv4/tcp_rmem); echo $c | sed -e s/131072/87380/g > /proc/sys/net/ipv4/tcp_rmem
354 (host)$ nsenter -t $(cat /tmp/pid) -U --preserve-credentials -n -m
355 (namespace)$ c=$(cat /proc/sys/net/ipv4/tcp_rmem); echo $c | sed -e s/131072/87380/g > /proc/sys/net/ipv4/tcp_rmem
227356 ```
228357
229358 # SEE ALSO
230359
231 **network_namespaces**(7), **user_namespaces**(7), **veth**(4)
360 `network_namespaces(7)`, `user_namespaces(7)`, `veth(4)`
232361
233362 # AVAILABILITY
234363
235 The slirp4netns command is available from **https://github.com/rootless-containers/slirp4netns** under GNU GENERAL PUBLIC LICENSE Version 2 (or later).
364 The slirp4netns command is available from `https://github.com/rootless-containers/slirp4netns` under GNU GENERAL PUBLIC LICENSE Version 2 (or later).
274274 cfg.if_mtu = s4nn->mtu;
275275 cfg.if_mru = s4nn->mtu;
276276 cfg.disable_host_loopback = s4nn->disable_host_loopback;
277 #if SLIRP_CONFIG_VERSION_MAX >= 2
278 cfg.outbound_addr = NULL;
279 cfg.outbound_addr6 = NULL;
280 if (s4nn->enable_outbound_addr) {
281 cfg.version = 2;
282 cfg.outbound_addr = &s4nn->outbound_addr;
283 }
284 if (s4nn->enable_outbound_addr6) {
285 cfg.version = 2;
286 cfg.outbound_addr6 = &s4nn->outbound_addr6;
287 }
288 #endif
289 #if SLIRP_CONFIG_VERSION_MAX >= 3
290 if (s4nn->disable_dns) {
291 cfg.version = 3;
292 cfg.disable_dns = true;
293 }
294 #endif
277295 slirp = slirp_new(&cfg, &libslirp_cb, opaque);
278296 if (slirp == NULL) {
279297 fprintf(stderr, "slirp_new failed\n");
00 /* SPDX-License-Identifier: GPL-2.0-or-later */
11 #ifndef SLIRP4NETNS_H
2 # define SLIRP4NETNS_H
2 #define SLIRP4NETNS_H
33 #include <arpa/inet.h>
44
55 struct slirp4netns_config {
6 unsigned int mtu;
7 struct in_addr vnetwork; // 10.0.2.0
8 struct in_addr vnetmask; // 255.255.255.0
9 struct in_addr vhost; // 10.0.2.2
10 struct in_addr vdhcp_start; // 10.0.2.15
11 struct in_addr vnameserver; // 10.0.2.3
12 struct in_addr recommended_vguest; // 10.0.2.100 (slirp itself is unaware of vguest)
13 bool enable_ipv6;
14 bool disable_host_loopback;
15 bool enable_sandbox;
16 bool enable_seccomp;
6 unsigned int mtu;
7 struct in_addr vnetwork; // 10.0.2.0
8 struct in_addr vnetmask; // 255.255.255.0
9 struct in_addr vhost; // 10.0.2.2
10 struct in_addr vdhcp_start; // 10.0.2.15
11 struct in_addr vnameserver; // 10.0.2.3
12 struct in_addr
13 recommended_vguest; // 10.0.2.100 (slirp itself is unaware of vguest)
14 bool enable_ipv6;
15 bool disable_host_loopback;
16 bool enable_sandbox;
17 bool enable_seccomp;
18 #if SLIRP_CONFIG_VERSION_MAX >= 2
19 bool enable_outbound_addr;
20 struct sockaddr_in outbound_addr;
21 bool enable_outbound_addr6;
22 struct sockaddr_in6 outbound_addr6;
23 #endif
24 #if SLIRP_CONFIG_VERSION_MAX >= 3
25 bool disable_dns;
26 #endif
27 struct sockaddr vmacaddress; // MAC address of interface
28 int vmacaddress_len; // MAC address byte length
1729 };
18 int do_slirp(int tapfd, int readyfd, int exitfd, const char *api_socket, struct slirp4netns_config *cfg);
30 int do_slirp(int tapfd, int readyfd, int exitfd, const char *api_socket,
31 struct slirp4netns_config *cfg);
1932
2033 #endif
00 #!/bin/bash
11
2 # See https://www.gnu.org/software/automake/manual/html_node/Scripts_002dbased-Testsuites.html#Testsuite-progress-on-console
3 TEST_EXIT_CODE_SKIP=77
4
5 function nsenter_flags {
6 pid=$1
7 flags="--target=${pid}"
8 userns="$(readlink /proc/${pid}/ns/user)"
9 mntns="$(readlink /proc/${pid}/ns/mnt)"
10 netns="$(readlink /proc/${pid}/ns/net)"
11
12 self_userns="$(readlink /proc/self/ns/user)"
13 self_mntns="$(readlink /proc/self/ns/mnt)"
14 self_netns="$(readlink /proc/self/ns/net)"
15
16 if [ "${userns}" != "${self_userns}" ]; then
17 flags="$flags --preserve-credentials -U"
18 fi
19 if [ "${mntns}" != "${self_mntns}" ]; then
20 flags="$flags -m"
21 fi
22 if [ "${netns}" != "${self_netns}" ]; then
23 flags="$flags -n"
24 fi
25 echo "${flags}"
26 }
27
228 function wait_for_network_namespace {
3 # Wait that the namespace is ready.
4 COUNTER=0
5 while [ $COUNTER -lt 40 ]; do
6 if nsenter --preserve-credentials -U -n --target=$1 true; then
7 break
8 else
9 sleep 0.5
10 fi
11 let COUNTER=COUNTER+1
12 done
29 # Wait that the namespace is ready.
30 COUNTER=0
31 while [ $COUNTER -lt 40 ]; do
32 flags=$(nsenter_flags $1)
33 if $(echo $flags | grep -qvw -- -n); then
34 flags="$flags -n"
35 fi
36 if nsenter ${flags} true >/dev/null 2>&1; then
37 return 0
38 else
39 sleep 0.5
40 fi
41 let COUNTER=COUNTER+1
42 done
43 exit 1
1344 }
1445
1546 function wait_for_network_device {
16 # Wait that the device appears.
17 COUNTER=0
18 while [ $COUNTER -lt 40 ]; do
19 if nsenter --preserve-credentials -U -n --target=$1 ip addr show $2; then
20 break
21 else
22 sleep 0.5
23 fi
24 let COUNTER=COUNTER+1
25 done
47 # Wait that the device appears.
48 COUNTER=0
49 while [ $COUNTER -lt 40 ]; do
50 if nsenter $(nsenter_flags $1) ip addr show $2; then
51 return 0
52 else
53 sleep 0.5
54 fi
55 let COUNTER=COUNTER+1
56 done
57 exit 1
2658 }
2759
2860 function wait_process_exits {
29 COUNTER=0
30 while [ $COUNTER -lt 40 ]; do
31 if kill -0 $1; then
32 sleep 0.5
33 else
34 break
35 fi
36 let COUNTER=COUNTER+1
37 done
61 COUNTER=0
62 while [ $COUNTER -lt 40 ]; do
63 if kill -0 $1; then
64 sleep 0.5
65 else
66 return 0
67 fi
68 let COUNTER=COUNTER+1
69 done
70 exit 1
3871 }
3972
4073 function wait_for_ping_connectivity {
41 COUNTER=0
42 while [ $COUNTER -lt 40 ]; do
43 if nsenter --preserve-credentials -U -n --target=$1 ping -c 1 -w 1 $2; then
44 break
45 else
46 sleep 0.5
47 fi
48 let COUNTER=COUNTER+1
49 done
74 COUNTER=0
75 while [ $COUNTER -lt 40 ]; do
76 if nsenter $(nsenter_flags $1) ping -c 1 -w 1 $2; then
77 return 0
78 else
79 sleep 0.5
80 fi
81 let COUNTER=COUNTER+1
82 done
83 exit 1
84 }
85
86 function wait_for_connectivity {
87 COUNTER=0
88 while [ $COUNTER -lt 40 ]; do
89 if echo "wait_for_connectivity" | nsenter $(nsenter_flags $1) ncat -v $2 $3; then
90 return 0
91 else
92 sleep 0.5
93 fi
94 let COUNTER=COUNTER+1
95 done
96 exit 1
5097 }
5198
5299 function wait_for_file_content {
53 # Wait for a file to get the specified content.
54 COUNTER=0
55 while [ $COUNTER -lt 20 ]; do
56 if grep $1 $2; then
57 break
58 else
59 sleep 0.5
60 fi
61 let COUNTER=COUNTER+1
62 done
100 # Wait for a file to get the specified content.
101 COUNTER=0
102 while [ $COUNTER -lt 20 ]; do
103 if grep $1 $2; then
104 return 0
105 else
106 sleep 0.5
107 fi
108 let COUNTER=COUNTER+1
109 done
110 exit 1
63111 }
64112
65113 function expose_tcp() {
66 apisock=$1 hostport=$2 guestport=$3
67 json="{\"execute\": \"add_hostfwd\", \"arguments\": {\"proto\": \"tcp\", \"host_addr\": \"0.0.0.0\", \"host_port\": $hostport, \"guest_addr\": \"10.0.2.100\", \"guest_port\": $guestport}}"
68 echo -n $json | ncat -U $apisock
69 echo -n "{\"execute\": \"list_hostfwd\"}" | ncat -U $apisock
114 apisock=$1 hostport=$2 guestport=$3
115 json="{\"execute\": \"add_hostfwd\", \"arguments\": {\"proto\": \"tcp\", \"host_addr\": \"0.0.0.0\", \"host_port\": $hostport, \"guest_addr\": \"10.0.2.100\", \"guest_port\": $guestport}}"
116 echo -n $json | ncat -U $apisock
117 echo -n "{\"execute\": \"list_hostfwd\"}" | ncat -U $apisock
70118 }
+0
-29
tests/slirp4netns-no-unmount.sh less more
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5 # it is a part of test-slirp4netns.sh
6 # must run in a new mount namespace
7
8 mount -t tmpfs tmpfs /run
9 mkdir /run/foo
10 mount -t tmpfs tmpfs /run/foo
11 mount --make-rshared /run
12
13 unshare -n sleep infinity &
14 child=$!
15
16 wait_for_network_namespace $child
17
18 ./slirp4netns --enable-sandbox --netns-type=path /proc/$child/ns/net tun11 &
19 slirp_pid=$!
20
21 function cleanup {
22 kill -9 $child $slirp_pid
23 }
24 trap cleanup EXIT
25
26 wait_for_network_device $child tun11
27
28 findmnt /run/foo
1111 apisocket=${tmpdir}/slirp4netns.sock
1212 apisocketlongpath=${tmpdir}/slirp4netns-TOO-LONG-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.sock
1313
14 if slirp4netns -c $child --api-socket $apisocketlongpath tun11; then
15 echo "expected failure with apisocket path too long" >&2
16 kill -9 $child
17 rm -rf $tmpdir
18 exit 1
14 if slirp4netns -c $child --api-socket $apisocketlongpath tap11; then
15 echo "expected failure with apisocket path too long" >&2
16 kill -9 $child
17 rm -rf $tmpdir
18 exit 1
1919 fi
2020
21 slirp4netns -c $child --api-socket $apisocket tun11 &
21 slirp4netns -c $child --api-socket $apisocket tap11 &
2222 slirp_pid=$!
2323
24 wait_for_network_device $child tun11
24 wait_for_network_device $child tap11
2525
2626 function cleanup() {
2727 kill -9 $child $slirp_pid
88 wait_for_network_namespace $child
99
1010 set +e
11 result=$(slirp4netns -c --cidr 24 $child tun11 2>&1)
11 result=$(slirp4netns -c --cidr 24 $child tap11 2>&1)
1212 set -e
1313 echo $result | grep "invalid CIDR"
1414
1515 set +e
16 result=$(slirp4netns -c --cidr foo $child tun11 2>&1)
16 result=$(slirp4netns -c --cidr foo $child tap11 2>&1)
1717 set -e
1818 echo $result | grep "invalid CIDR"
1919
2020 set +e
21 result=$(slirp4netns -c --cidr 10.0.2.0 $child tun11 2>&1)
21 result=$(slirp4netns -c --cidr 10.0.2.0 $child tap11 2>&1)
2222 set -e
2323 echo $result | grep "invalid CIDR"
2424
2525 set +e
26 result=$(slirp4netns -c --cidr 10.0.2.100/24 $child tun11 2>&1)
26 result=$(slirp4netns -c --cidr 10.0.2.100/24 $child tap11 2>&1)
2727 set -e
2828 echo $result | grep "CIDR needs to be a network address like 10.0.2.0/24, not like 10.0.2.100/24"
2929
3030 set +e
31 result=$(slirp4netns -c --cidr 10.0.2.100/26 $child tun11 2>&1)
31 result=$(slirp4netns -c --cidr 10.0.2.100/26 $child tap11 2>&1)
3232 set -e
3333 echo $result | grep "prefix length needs to be 1-25"
3434
35 slirp4netns -c $child --cidr 10.0.135.128/25 tun11 &
35 slirp4netns -c $child --cidr 10.0.135.128/25 tap11 &
3636 slirp_pid=$!
3737
38 wait_for_network_device $child tun11
38 wait_for_network_device $child tap11
3939
4040 function cleanup {
41 kill -9 $child $slirp_pid
41 kill -9 $child $slirp_pid
4242 }
4343 trap cleanup EXIT
4444
45 ip=$(nsenter --preserve-credentials -U -n --target=$child ip -json a show dev tun11 | jq -r .[1].addr_info[0].local)
46 [[ $ip = 10.0.135.228 ]]
45 result="$(nsenter $(nsenter_flags $child) ip a show dev tap11)"
46 echo "$result" | grep -o '^\s*inet .*/' | grep -F 10.0.135.228
77
88 wait_for_network_namespace $child
99
10 slirp4netns -c $child tun11 &
10 slirp4netns -c $child tap11 &
1111 slirp_pid=$!
1212
13 wait_for_network_device $child tun11
13 wait_for_network_device $child tap11
1414
1515 function cleanup {
16 kill -9 $child $slirp_pid
16 kill -9 $child $slirp_pid
1717 }
1818 trap cleanup EXIT
1919
20 nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11
20 nsenter $(nsenter_flags $child) ip -a netconf | grep tap11
2121
22 nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep inet
22 nsenter $(nsenter_flags $child) ip addr show tap11 | grep inet
0 #!/bin/bash
1
2 # This test should pass with libslirp < 4.6.0 and libslirp >= 4.6.1,
3 # but should fail with libslirp == 4.6.0 .
4 # https://gitlab.freedesktop.org/slirp/libslirp/-/issues/48
5
6 set -xeuo pipefail
7
8 . $(dirname $0)/common.sh
9
10 if ! command -v udhcpc 2>&1; then
11 echo "udhcpc is missing, skipping the test"
12 exit "$TEST_EXIT_CODE_SKIP"
13 fi
14
15 unshare -r -n sleep infinity &
16 child=$!
17
18 wait_for_network_namespace $child
19
20 slirp4netns $child tap0 &
21 slirp_pid=$!
22
23 udhcpc_log=$(mktemp /tmp/slirp4netns-test-udhcpc.XXXXXXXXXX)
24
25 function cleanup {
26 kill -9 $child $slirp_pid
27 rm -f $udhcpc_log
28 }
29 trap cleanup EXIT
30
31 nsenter $(nsenter_flags $child) ip link set lo up
32 nsenter $(nsenter_flags $child) ip link set tap0 up
33 nsenter $(nsenter_flags $child) timeout 10s udhcpc -q -i tap0 -s /bin/true 2>&1 | tee $udhcpc_log
34 grep 10.0.2.15 $udhcpc_log
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5 SLIRP_CONFIG_VERSION_MAX=$(slirp4netns -v | grep "SLIRP_CONFIG_VERSION_MAX: " | sed 's#SLIRP_CONFIG_VERSION_MAX: \(\)##')
6
7 if [ "${SLIRP_CONFIG_VERSION_MAX:-0}" -lt 3 ]; then
8 printf "'--disable-dns' requires SLIRP_CONFIG_VERSION_MAX 3 or newer. Test skipped..."
9 exit "$TEST_EXIT_CODE_SKIP"
10 fi
11
12 port=53
13 unshare -r -n sleep infinity &
14 child=$!
15
16 wait_for_network_namespace $child
17
18 mtu=${MTU:=1500}
19 slirp4netns -c --mtu $mtu --disable-dns $child tap11 &
20 slirp_pid=$!
21
22 wait_for_network_device $child tap11
23 # ping to 10.0.2.2
24 wait_for_ping_connectivity $child 10.0.2.2
25
26 function cleanup() {
27 kill -9 $child $slirp_pid
28 }
29 trap cleanup EXIT
30
31 set +e
32 err=$(echo "should fail" | nsenter $(nsenter_flags $child) ncat -v 10.0.2.3 $port 2>&1)
33 set -e
34 echo $err | grep 'Connection timed out\|TIMEOUT'
1212 wait_for_network_namespace $child
1313
1414 mtu=${MTU:=1500}
15 slirp4netns -c --mtu $mtu --disable-host-loopback $child tun11 &
15 slirp4netns -c --mtu $mtu --disable-host-loopback $child tap11 &
1616 slirp_pid=$!
1717
18 wait_for_network_device $child tun11
18 wait_for_network_device $child tap11
1919 # ping to 10.0.2.2 is possible even with --disable-host-loopback
2020 wait_for_ping_connectivity $child 10.0.2.2
2121
2222 function cleanup {
23 kill -9 $nc_pid $child $slirp_pid
23 kill -9 $nc_pid $child $slirp_pid
2424 }
2525 trap cleanup EXIT
2626
2727 set +e
28 err=$(echo "should fail" | nsenter --preserve-credentials -U -n --target=$child ncat -v 10.0.2.2 $port 2>&1)
28 err=$(echo "should fail" | nsenter $(nsenter_flags $child) ncat -v 10.0.2.2 $port 2>&1)
2929 set -e
3030 echo $err | grep "Network is unreachable"
31
99
1010 touch keep_alive
1111
12 slirp4netns -e 10 $child tun11 10<(while test -e keep_alive; do sleep 0.1; done) &
12 slirp4netns -e 10 $child tap11 10<(while test -e keep_alive; do sleep 0.1; done) &
1313
1414 slirp_pid=$!
1515
1616 function cleanup {
17 set +xeuo pipefail
18 kill -9 $child $slirp_pid
19 rm -f keep_alive
17 set +xeuo pipefail
18 kill -9 $child $slirp_pid
19 rm -f keep_alive
2020 }
2121 trap cleanup EXIT
2222
2828 wait_process_exits $slirp_pid
2929
3030 if kill -0 $slirp_pid; then
31 exit 1
31 exit 1
3232 fi
3333
3434 exit 0
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4 MACADDRESS="0e:d4:18:d9:38:fb"
5
6 unshare -r -n sleep infinity &
7 child=$!
8
9 wait_for_network_namespace $child
10
11 function cleanup {
12 kill -9 $child $slirp_pid
13 }
14 trap cleanup EXIT
15
16 slirp4netns -c --macaddress $MACADDRESS $child tap11 &
17 slirp_pid=$!
18
19 wait_for_network_device $child tap11
20
21 result=$(nsenter $(nsenter_flags $child) ip addr show tap11 | grep -o "ether $MACADDRESS")
22
23 if [ -z "$result" ]; then
24 printf "expecting %s MAC address on the interface but didn't get it" "$MACADDRESS"
25 exit 1
26 fi
27
28 cleanup
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5 # Test --userns-path= --netns-type=path
6 unshare -r -n sleep infinity &
7 child=$!
8
9 wait_for_network_namespace $child
10
11 slirp4netns --userns-path=/proc/$child/ns/user --netns-type=path /proc/$child/ns/net tap11 &
12 slirp_pid=$!
13
14 function cleanup {
15 kill -9 $child $slirp_pid
16 }
17 trap cleanup EXIT
18
19 wait_for_network_device $child tap11
20
21 nsenter $(nsenter_flags $child) ip -a netconf | grep tap11
22 nsenter $(nsenter_flags $child) ip addr show tap11 | grep -v inet
23
24 kill -9 $child $slirp_pid
25
26 # Test --netns-type=path
27 unshare -r -n sleep infinity &
28 child=$!
29
30 wait_for_network_namespace $child
31
32 nsenter --preserve-credentials -U --target=$child slirp4netns --netns-type=path /proc/$child/ns/net tap11 &
33 slirp_pid=$!
34
35 wait_for_network_device $child tap11
36
37 nsenter $(nsenter_flags $child) ip -a netconf | grep tap11
38 nsenter $(nsenter_flags $child) ip addr show tap11 | grep -v inet
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5 SLIRP_CONFIG_VERSION_MAX=$(slirp4netns -v | grep "SLIRP_CONFIG_VERSION_MAX: " | sed 's#SLIRP_CONFIG_VERSION_MAX: \(\)##')
6
7 if [ "${SLIRP_CONFIG_VERSION_MAX:-0}" -lt 2 ]; then
8 printf "'--disable-dns' requires SLIRP_CONFIG_VERSION_MAX 2 or newer. Test skipped..."
9 exit "$TEST_EXIT_CODE_SKIP"
10 fi
11
12 IPv4_1="127.0.0.1"
13 IPv4_2=$(ip a | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p' | head -n 1)
14
15 # For future ipv6 tests
16 #IPv6_1="::1"
17 #IPv6_2=$(ip a | sed -En 's/::1\/128//;s/.*inet6 (addr:)?([^ ]*)\/.*$/\2/p' | head -n 1)
18
19 function cleanup() {
20 rm -rf ncat.log
21 kill -9 $child $slirp_pid || exit 0
22 }
23 trap cleanup EXIT
24
25 port=12122
26 mtu=${MTU:=1500}
27
28 IPs=("$IPv4_1" "$IPv4_2")
29 for ip in "${IPs[@]}"; do
30 ncat -l $port -v >ncat.log 2>&1 &
31 ncat1=$!
32
33 unshare -r -n sleep infinity &
34 child=$!
35
36 wait_for_network_namespace $child
37
38 slirp4netns -c --mtu $mtu --outbound-addr="$ip" $child tap11 &
39 slirp_pid=$!
40
41 wait_for_network_device $child tap11
42
43 wait_for_connectivity $child 10.0.2.2 $port
44
45 wait_process_exits $ncat1
46 if ! grep "$ip" ncat.log; then
47 printf "%s not found in ncat.log" "$ip"
48 exit 1
49 fi
50 cleanup
51 let port=port+1
52 done
99
1010 touch keep_alive
1111
12 slirp4netns -c -r 10 $child tun11 10>configured &
12 slirp4netns -c -r 10 $child tap11 10>configured &
1313 slirp_pid=$!
1414
1515 function cleanup {
16 set +xeuo pipefail
17 kill -9 $child $slirp_pid
18 rm -f configured keep_alive
16 set +xeuo pipefail
17 kill -9 $child $slirp_pid
18 rm -f configured keep_alive
1919 }
2020 trap cleanup EXIT
2121
22 wait_for_network_device $child tun11
22 wait_for_network_device $child tap11
2323
2424 wait_for_file_content 1 configured
2525
0 #!/bin/bash
1 set -xeuo pipefail
2
3 if [[ ! -v "CHILD" ]]; then
4 # reexec in a new mount namespace
5 export CHILD=1
6 exec unshare -rm "$0" "$@"
7 fi
8
9 . $(dirname $0)/common.sh
10
11 mount -t tmpfs tmpfs /run
12 mkdir /run/foo
13 mount -t tmpfs tmpfs /run/foo
14 mount --make-rshared /run
15
16 unshare -n sleep infinity &
17 child=$!
18
19 wait_for_network_namespace $child
20
21 slirp4netns --enable-sandbox --netns-type=path /proc/$child/ns/net tap11 &
22 slirp_pid=$!
23
24 function cleanup {
25 kill -9 $child $slirp_pid
26 }
27 trap cleanup EXIT
28
29 wait_for_network_device $child tap11
30
31 findmnt /run/foo
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5 unshare -r -n sleep infinity &
6 child=$!
7
8 wait_for_network_namespace $child
9
10 slirp4netns --ready-fd=3 --enable-sandbox $child tap11 3>ready.file &
11 slirp_pid=$!
12
13 # Wait that the sandbox is created
14 wait_for_file_content 1 ready.file
15 rm ready.file
16
17 # Check there are no capabilities left in slirp4netns
18 getpcaps $slirp_pid 2>&1 | tail -n1 >slirp.caps
19 grep cap_net_bind_service slirp.caps
20 grep -v cap_sys_admin slirp.caps
21 rm slirp.caps
22 test -e /proc/$slirp_pid/root/etc
23 test -e /proc/$slirp_pid/root/run
24 test \! -e /proc/$slirp_pid/root/home
25 test \! -e /proc/$slirp_pid/root/root
26 test \! -e /proc/$slirp_pid/root/var
27
28 function cleanup {
29 kill -9 $child $slirp_pid
30 }
31 trap cleanup EXIT
32
33 nsenter $(nsenter_flags $child) ip -a netconf | grep tap11
34 nsenter $(nsenter_flags $child) ip addr show tap11 | grep -v inet
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5 unshare -r -n sleep infinity &
6 child=$!
7
8 wait_for_network_namespace $child
9
10 slirp4netns -c --enable-seccomp --userns-path=/proc/$child/ns/user $child tap11 &
11 slirp_pid=$!
12
13 wait_for_network_device $child tap11
14
15 function cleanup {
16 kill -9 $child $slirp_pid
17 }
18 trap cleanup EXIT
19
20 nsenter $(nsenter_flags $child) ip -a netconf | grep tap11
21
22 nsenter $(nsenter_flags $child) ip addr show tap11 | grep inet
+0
-71
tests/test-slirp4netns.sh less more
0 #!/bin/bash
1 set -xeuo pipefail
2
3 . $(dirname $0)/common.sh
4
5
6 # Test --netns-type=pid
7 unshare -r -n sleep infinity &
8 child=$!
9
10 wait_for_network_namespace $child
11
12 slirp4netns --ready-fd=3 --enable-sandbox $child tun11 3>ready.file &
13 slirp_pid=$!
14
15 # Wait that the sandbox is created
16 wait_for_file_content 1 ready.file
17 rm ready.file
18
19 # Check there are no capabilities left in slirp4netns
20 getpcaps $slirp_pid 2>&1 | tail -n1 > slirp.caps
21 grep cap_net_bind_service slirp.caps
22 grep -v cap_sys_admin slirp.caps
23 rm slirp.caps
24 test -e /proc/$slirp_pid/root/etc
25 test -e /proc/$slirp_pid/root/run
26 test \! -e /proc/$slirp_pid/root/home
27 test \! -e /proc/$slirp_pid/root/root
28 test \! -e /proc/$slirp_pid/root/var
29
30 function cleanup {
31 kill -9 $child $slirp_pid
32 }
33 trap cleanup EXIT
34
35 nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11
36 nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep -v inet
37
38 kill -9 $child $slirp_pid
39
40 # Test --userns-path= --netns-type=path
41 unshare -r -n sleep infinity &
42 child=$!
43
44 wait_for_network_namespace $child
45
46 slirp4netns --userns-path=/proc/$child/ns/user --netns-type=path /proc/$child/ns/net tun11 &
47 slirp_pid=$!
48
49 wait_for_network_device $child tun11
50
51 nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11
52 nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep -v inet
53
54 kill -9 $child $slirp_pid
55
56 # Test --netns-type=path
57 unshare -r -n sleep infinity &
58 child=$!
59
60 wait_for_network_namespace $child
61
62 nsenter --preserve-credentials -U --target=$child slirp4netns --netns-type=path /proc/$child/ns/net tun11 &
63 slirp_pid=$!
64
65 wait_for_network_device $child tun11
66
67 nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11
68 nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep -v inet
69
70 unshare -rm $(readlink -f $(dirname $0)/slirp4netns-no-unmount.sh)
00 # DO NOT EDIT MANUALLY
11
22 Vendored components:
3 * parson: https://github.com/kgabis/parson.git (`70dc239f8f54c80bf58477b25435fd3dd3102804`)
3 * parson: https://github.com/kgabis/parson.git (`2d7b3ddf1280bf7f5ad82d26e09252240e7c4557`)
44
55 Please do not edit the contents under this directory manually.
66
00 MIT License
11
2 Copyright (c) 2012 - 2019 Krzysztof Gabis
2 Copyright (c) 2012 - 2021 Krzysztof Gabis
33
44 Permission is hereby granted, free of charge, to any person obtaining a copy
55 of this software and associated documentation files (the "Software"), to deal
00 ## About
1 Parson is a lighweight [json](http://json.org) library written in C.
1 Parson is a lightweight [json](http://json.org) library written in C.
22
33 ## Features
44 * Full JSON support
141141 Remember to follow parson's code style and write appropriate tests.
142142
143143 ## My other projects
144 * [ape](https://github.com/kgabis/ape) - simple programming language implemented in C library
144145 * [kgflags](https://github.com/kgabis/kgflags) - easy to use command-line flag parsing library
145146 * [agnes](https://github.com/kgabis/agnes) - header-only NES emulation library
146147
00 /*
11 SPDX-License-Identifier: MIT
22
3 Parson 1.0.2 ( http://kgabis.github.com/parson/ )
4 Copyright (c) 2012 - 2019 Krzysztof Gabis
3 Parson 1.1.3 ( http://kgabis.github.com/parson/ )
4 Copyright (c) 2012 - 2021 Krzysztof Gabis
55
66 Permission is hereby granted, free of charge, to any person obtaining a copy
77 of this software and associated documentation files (the "Software"), to deal
6767
6868 #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
6969
70 typedef struct json_string {
71 char *chars;
72 size_t length;
73 } JSON_String;
74
7075 /* Type definitions */
7176 typedef union json_value_value {
72 char *string;
77 JSON_String string;
7378 double number;
7479 JSON_Object *object;
7580 JSON_Array *array;
127132 static void json_array_free(JSON_Array *array);
128133
129134 /* JSON Value */
130 static JSON_Value * json_value_init_string_no_copy(char *string);
135 static JSON_Value * json_value_init_string_no_copy(char *string, size_t length);
136 static const JSON_String * json_value_get_string_desc(const JSON_Value *value);
131137
132138 /* Parser */
133139 static JSON_Status skip_quotes(const char **string);
134140 static int parse_utf16(const char **unprocessed, char **processed);
135 static char * process_string(const char *input, size_t len);
136 static char * get_quoted_string(const char **string);
141 static char * process_string(const char *input, size_t input_len, size_t *output_len);
142 static char * get_quoted_string(const char **string, size_t *output_string_len);
137143 static JSON_Value * parse_object_value(const char **string, size_t nesting);
138144 static JSON_Value * parse_array_value(const char **string, size_t nesting);
139145 static JSON_Value * parse_string_value(const char **string);
144150
145151 /* Serialization */
146152 static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf);
147 static int json_serialize_string(const char *string, char *buf);
153 static int json_serialize_string(const char *string, size_t len, char *buf);
148154 static int append_indent(char *buf, int level);
149155 static int append_string(char *buf, const char *string);
150156
151157 /* Various */
152158 static char * parson_strndup(const char *string, size_t n) {
159 /* We expect the caller has validated that 'n' fits within the input buffer. */
153160 char *output_string = (char*)parson_malloc(n + 1);
154161 if (!output_string) {
155162 return NULL;
535542 }
536543
537544 /* JSON Value */
538 static JSON_Value * json_value_init_string_no_copy(char *string) {
545 static JSON_Value * json_value_init_string_no_copy(char *string, size_t length) {
539546 JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
540547 if (!new_value) {
541548 return NULL;
542549 }
543550 new_value->parent = NULL;
544551 new_value->type = JSONString;
545 new_value->value.string = string;
552 new_value->value.string.chars = string;
553 new_value->value.string.length = length;
546554 return new_value;
547555 }
548556
616624
617625 /* Copies and processes passed string up to supplied length.
618626 Example: "\u006Corem ipsum" -> lorem ipsum */
619 static char* process_string(const char *input, size_t len) {
627 static char* process_string(const char *input, size_t input_len, size_t *output_len) {
620628 const char *input_ptr = input;
621 size_t initial_size = (len + 1) * sizeof(char);
629 size_t initial_size = (input_len + 1) * sizeof(char);
622630 size_t final_size = 0;
623631 char *output = NULL, *output_ptr = NULL, *resized_output = NULL;
624632 output = (char*)parson_malloc(initial_size);
626634 goto error;
627635 }
628636 output_ptr = output;
629 while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) {
637 while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < input_len) {
630638 if (*input_ptr == '\\') {
631639 input_ptr++;
632640 switch (*input_ptr) {
663671 goto error;
664672 }
665673 memcpy(resized_output, output, final_size);
674 *output_len = final_size - 1;
666675 parson_free(output);
667676 return resized_output;
668677 error:
672681
673682 /* Return processed contents of a string between quotes and
674683 skips passed argument to a matching quote. */
675 static char * get_quoted_string(const char **string) {
684 static char * get_quoted_string(const char **string, size_t *output_string_len) {
676685 const char *string_start = *string;
677 size_t string_len = 0;
686 size_t input_string_len = 0;
678687 JSON_Status status = skip_quotes(string);
679688 if (status != JSONSuccess) {
680689 return NULL;
681690 }
682 string_len = *string - string_start - 2; /* length without quotes */
683 return process_string(string_start + 1, string_len);
691 input_string_len = *string - string_start - 2; /* length without quotes */
692 return process_string(string_start + 1, input_string_len, output_string_len);
684693 }
685694
686695 static JSON_Value * parse_value(const char **string, size_t nesting) {
728737 return output_value;
729738 }
730739 while (**string != '\0') {
731 new_key = get_quoted_string(string);
732 if (new_key == NULL) {
740 size_t key_len = 0;
741 new_key = get_quoted_string(string, &key_len);
742 /* We do not support key names with embedded \0 chars */
743 if (new_key == NULL || key_len != strlen(new_key)) {
744 if (new_key) {
745 parson_free(new_key);
746 }
733747 json_value_free(output_value);
734748 return NULL;
735749 }
818832
819833 static JSON_Value * parse_string_value(const char **string) {
820834 JSON_Value *value = NULL;
821 char *new_string = get_quoted_string(string);
835 size_t new_string_len = 0;
836 char *new_string = get_quoted_string(string, &new_string_len);
822837 if (new_string == NULL) {
823838 return NULL;
824839 }
825 value = json_value_init_string_no_copy(new_string);
840 value = json_value_init_string_no_copy(new_string, new_string_len);
826841 if (value == NULL) {
827842 parson_free(new_string);
828843 return NULL;
848863 double number = 0;
849864 errno = 0;
850865 number = strtod(*string, &end);
851 if (errno || !is_decimal(*string, end - *string)) {
866 if (errno == ERANGE && (number == -HUGE_VAL || number == HUGE_VAL)) {
867 return NULL;
868 }
869 if ((errno && errno != ERANGE) || !is_decimal(*string, end - *string)) {
852870 return NULL;
853871 }
854872 *string = end;
884902 size_t i = 0, count = 0;
885903 double num = 0.0;
886904 int written = -1, written_total = 0;
905 size_t len = 0;
887906
888907 switch (json_value_get_type(value)) {
889908 case JSONArray:
933952 if (is_pretty) {
934953 APPEND_INDENT(level+1);
935954 }
936 written = json_serialize_string(key, buf);
955 /* We do not support key names with embedded \0 chars */
956 written = json_serialize_string(key, strlen(key), buf);
937957 if (written < 0) {
938958 return -1;
939959 }
945965 if (is_pretty) {
946966 APPEND_STRING(" ");
947967 }
948 temp_value = json_object_get_value(object, key);
968 temp_value = json_object_get_value_at(object, i);
949969 written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
950970 if (written < 0) {
951971 return -1;
971991 if (string == NULL) {
972992 return -1;
973993 }
974 written = json_serialize_string(string, buf);
994 len = json_value_get_string_len(value);
995 written = json_serialize_string(string, len, buf);
975996 if (written < 0) {
976997 return -1;
977998 }
10111032 }
10121033 }
10131034
1014 static int json_serialize_string(const char *string, char *buf) {
1015 size_t i = 0, len = strlen(string);
1035 static int json_serialize_string(const char *string, size_t len, char *buf) {
1036 size_t i = 0;
10161037 char c = '\0';
10171038 int written = -1, written_total = 0;
10181039 APPEND_STRING("\"");
11581179 return json_value_get_string(json_object_get_value(object, name));
11591180 }
11601181
1182 size_t json_object_get_string_len(const JSON_Object *object, const char *name) {
1183 return json_value_get_string_len(json_object_get_value(object, name));
1184 }
1185
11611186 double json_object_get_number(const JSON_Object *object, const char *name) {
11621187 return json_value_get_number(json_object_get_value(object, name));
11631188 }
11871212 return json_value_get_string(json_object_dotget_value(object, name));
11881213 }
11891214
1215 size_t json_object_dotget_string_len(const JSON_Object *object, const char *name) {
1216 return json_value_get_string_len(json_object_dotget_value(object, name));
1217 }
1218
11901219 double json_object_dotget_number(const JSON_Object *object, const char *name) {
11911220 return json_value_get_number(json_object_dotget_value(object, name));
11921221 }
12551284 return json_value_get_string(json_array_get_value(array, index));
12561285 }
12571286
1287 size_t json_array_get_string_len(const JSON_Array *array, size_t index) {
1288 return json_value_get_string_len(json_array_get_value(array, index));
1289 }
1290
12581291 double json_array_get_number(const JSON_Array *array, size_t index) {
12591292 return json_value_get_number(json_array_get_value(array, index));
12601293 }
12921325 return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
12931326 }
12941327
1328 static const JSON_String * json_value_get_string_desc(const JSON_Value *value) {
1329 return json_value_get_type(value) == JSONString ? &value->value.string : NULL;
1330 }
1331
12951332 const char * json_value_get_string(const JSON_Value *value) {
1296 return json_value_get_type(value) == JSONString ? value->value.string : NULL;
1333 const JSON_String *str = json_value_get_string_desc(value);
1334 return str ? str->chars : NULL;
1335 }
1336
1337 size_t json_value_get_string_len(const JSON_Value *value) {
1338 const JSON_String *str = json_value_get_string_desc(value);
1339 return str ? str->length : 0;
12971340 }
12981341
12991342 double json_value_get_number(const JSON_Value *value) {
13141357 json_object_free(value->value.object);
13151358 break;
13161359 case JSONString:
1317 parson_free(value->value.string);
1360 parson_free(value->value.string.chars);
13181361 break;
13191362 case JSONArray:
13201363 json_array_free(value->value.array);
13561399 }
13571400
13581401 JSON_Value * json_value_init_string(const char *string) {
1402 if (string == NULL) {
1403 return NULL;
1404 }
1405 return json_value_init_string_with_len(string, strlen(string));
1406 }
1407
1408 JSON_Value * json_value_init_string_with_len(const char *string, size_t length) {
13591409 char *copy = NULL;
13601410 JSON_Value *value;
1361 size_t string_len = 0;
13621411 if (string == NULL) {
13631412 return NULL;
13641413 }
1365 string_len = strlen(string);
1366 if (!is_valid_utf8(string, string_len)) {
1367 return NULL;
1368 }
1369 copy = parson_strndup(string, string_len);
1414 if (!is_valid_utf8(string, length)) {
1415 return NULL;
1416 }
1417 copy = parson_strndup(string, length);
13701418 if (copy == NULL) {
13711419 return NULL;
13721420 }
1373 value = json_value_init_string_no_copy(copy);
1421 value = json_value_init_string_no_copy(copy, length);
13741422 if (value == NULL) {
13751423 parson_free(copy);
13761424 }
14161464 JSON_Value * json_value_deep_copy(const JSON_Value *value) {
14171465 size_t i = 0;
14181466 JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL;
1419 const char *temp_string = NULL, *temp_key = NULL;
1467 const JSON_String *temp_string = NULL;
1468 const char *temp_key = NULL;
14201469 char *temp_string_copy = NULL;
14211470 JSON_Array *temp_array = NULL, *temp_array_copy = NULL;
14221471 JSON_Object *temp_object = NULL, *temp_object_copy = NULL;
14701519 case JSONNumber:
14711520 return json_value_init_number(json_value_get_number(value));
14721521 case JSONString:
1473 temp_string = json_value_get_string(value);
1522 temp_string = json_value_get_string_desc(value);
14741523 if (temp_string == NULL) {
14751524 return NULL;
14761525 }
1477 temp_string_copy = parson_strdup(temp_string);
1526 temp_string_copy = parson_strndup(temp_string->chars, temp_string->length);
14781527 if (temp_string_copy == NULL) {
14791528 return NULL;
14801529 }
1481 return_value = json_value_init_string_no_copy(temp_string_copy);
1530 return_value = json_value_init_string_no_copy(temp_string_copy, temp_string->length);
14821531 if (return_value == NULL) {
14831532 parson_free(temp_string_copy);
14841533 }
16501699 return JSONSuccess;
16511700 }
16521701
1702 JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len) {
1703 JSON_Value *value = json_value_init_string_with_len(string, len);
1704 if (value == NULL) {
1705 return JSONFailure;
1706 }
1707 if (json_array_replace_value(array, i, value) == JSONFailure) {
1708 json_value_free(value);
1709 return JSONFailure;
1710 }
1711 return JSONSuccess;
1712 }
1713
16531714 JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) {
16541715 JSON_Value *value = json_value_init_number(number);
16551716 if (value == NULL) {
17071768
17081769 JSON_Status json_array_append_string(JSON_Array *array, const char *string) {
17091770 JSON_Value *value = json_value_init_string(string);
1771 if (value == NULL) {
1772 return JSONFailure;
1773 }
1774 if (json_array_append_value(array, value) == JSONFailure) {
1775 json_value_free(value);
1776 return JSONFailure;
1777 }
1778 return JSONSuccess;
1779 }
1780
1781 JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len) {
1782 JSON_Value *value = json_value_init_string_with_len(string, len);
17101783 if (value == NULL) {
17111784 return JSONFailure;
17121785 }
17831856 return status;
17841857 }
17851858
1859 JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len) {
1860 JSON_Value *value = json_value_init_string_with_len(string, len);
1861 JSON_Status status = json_object_set_value(object, name, value);
1862 if (status == JSONFailure) {
1863 json_value_free(value);
1864 }
1865 return status;
1866 }
1867
17861868 JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) {
17871869 JSON_Value *value = json_value_init_number(number);
17881870 JSON_Status status = json_object_set_value(object, name, value);
18541936
18551937 JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) {
18561938 JSON_Value *value = json_value_init_string(string);
1939 if (value == NULL) {
1940 return JSONFailure;
1941 }
1942 if (json_object_dotset_value(object, name, value) == JSONFailure) {
1943 json_value_free(value);
1944 return JSONFailure;
1945 }
1946 return JSONSuccess;
1947 }
1948
1949 JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len) {
1950 JSON_Value *value = json_value_init_string_with_len(string, len);
18571951 if (value == NULL) {
18581952 return JSONFailure;
18591953 }
19842078 int json_value_equals(const JSON_Value *a, const JSON_Value *b) {
19852079 JSON_Object *a_object = NULL, *b_object = NULL;
19862080 JSON_Array *a_array = NULL, *b_array = NULL;
1987 const char *a_string = NULL, *b_string = NULL;
2081 const JSON_String *a_string = NULL, *b_string = NULL;
19882082 const char *key = NULL;
19892083 size_t a_count = 0, b_count = 0, i = 0;
19902084 JSON_Value_Type a_type, b_type;
20262120 }
20272121 return 1;
20282122 case JSONString:
2029 a_string = json_value_get_string(a);
2030 b_string = json_value_get_string(b);
2123 a_string = json_value_get_string_desc(a);
2124 b_string = json_value_get_string_desc(b);
20312125 if (a_string == NULL || b_string == NULL) {
20322126 return 0; /* shouldn't happen */
20332127 }
2034 return strcmp(a_string, b_string) == 0;
2128 return a_string->length == b_string->length &&
2129 memcmp(a_string->chars, b_string->chars, a_string->length) == 0;
20352130 case JSONBoolean:
20362131 return json_value_get_boolean(a) == json_value_get_boolean(b);
20372132 case JSONNumber:
20612156 return json_value_get_string(value);
20622157 }
20632158
2159 size_t json_string_len(const JSON_Value *value) {
2160 return json_value_get_string_len(value);
2161 }
2162
20642163 double json_number (const JSON_Value *value) {
20652164 return json_value_get_number(value);
20662165 }
00 /*
11 SPDX-License-Identifier: MIT
22
3 Parson 1.0.2 ( http://kgabis.github.com/parson/ )
4 Copyright (c) 2012 - 2019 Krzysztof Gabis
3 Parson 1.1.3 ( http://kgabis.github.com/parson/ )
4 Copyright (c) 2012 - 2021 Krzysztof Gabis
55
66 Permission is hereby granted, free of charge, to any person obtaining a copy
77 of this software and associated documentation files (the "Software"), to deal
113113 */
114114 JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
115115 const char * json_object_get_string (const JSON_Object *object, const char *name);
116 size_t json_object_get_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
116117 JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
117118 JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
118119 double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
124125 this way. */
125126 JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name);
126127 const char * json_object_dotget_string (const JSON_Object *object, const char *name);
128 size_t json_object_dotget_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
127129 JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
128130 JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
129131 double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
147149 * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
148150 JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
149151 JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
152 JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
150153 JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
151154 JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
152155 JSON_Status json_object_set_null(JSON_Object *object, const char *name);
155158 * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
156159 JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
157160 JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
161 JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
158162 JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
159163 JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
160164 JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
173177 */
174178 JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
175179 const char * json_array_get_string (const JSON_Array *array, size_t index);
180 size_t json_array_get_string_len(const JSON_Array *array, size_t index); /* doesn't account for last null character */
176181 JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
177182 JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
178183 double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
189194 * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
190195 JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
191196 JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
197 JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len); /* length shouldn't include last null character */
192198 JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
193199 JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
194200 JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
200206 * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
201207 JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
202208 JSON_Status json_array_append_string(JSON_Array *array, const char *string);
209 JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len); /* length shouldn't include last null character */
203210 JSON_Status json_array_append_number(JSON_Array *array, double number);
204211 JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
205212 JSON_Status json_array_append_null(JSON_Array *array);
210217 JSON_Value * json_value_init_object (void);
211218 JSON_Value * json_value_init_array (void);
212219 JSON_Value * json_value_init_string (const char *string); /* copies passed string */
220 JSON_Value * json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */
213221 JSON_Value * json_value_init_number (double number);
214222 JSON_Value * json_value_init_boolean(int boolean);
215223 JSON_Value * json_value_init_null (void);
220228 JSON_Object * json_value_get_object (const JSON_Value *value);
221229 JSON_Array * json_value_get_array (const JSON_Value *value);
222230 const char * json_value_get_string (const JSON_Value *value);
231 size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */
223232 double json_value_get_number (const JSON_Value *value);
224233 int json_value_get_boolean(const JSON_Value *value);
225234 JSON_Value * json_value_get_parent (const JSON_Value *value);
229238 JSON_Object * json_object (const JSON_Value *value);
230239 JSON_Array * json_array (const JSON_Value *value);
231240 const char * json_string (const JSON_Value *value);
241 size_t json_string_len(const JSON_Value *value); /* doesn't account for last null character */
232242 double json_number (const JSON_Value *value);
233243 int json_boolean(const JSON_Value *value);
234244
00 #!/bin/bash
11 set -eux -o pipefail
22
3 # Feb 21, 2020
4 PARSON_COMMIT=70dc239f8f54c80bf58477b25435fd3dd3102804
3 # v1.1.3 (May 26, 2021)
4 PARSON_COMMIT=2d7b3ddf1280bf7f5ad82d26e09252240e7c4557
55 PARSON_REPO=https://github.com/kgabis/parson.git
66
77 # prepare