aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rwxr-xr-xslirp4netns.sh227
1 files changed, 227 insertions, 0 deletions
diff --git a/slirp4netns.sh b/slirp4netns.sh
new file mode 100755
index 0000000..f543e9b
--- /dev/null
+++ b/slirp4netns.sh
@@ -0,0 +1,227 @@
+#!/bin/sh -euf
+#
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# PASST - Plug A Simple Socket Transport
+# for qemu/UNIX domain socket mode
+#
+# PASTA - Pack A Subtle Tap Abstraction
+# for network namespace/tap device mode
+#
+# slirp4netns.sh - Compatibility wrapper for pasta, behaving like slirp4netns(1)
+#
+# WARNING: Draft quality, not really tested, --enable-sandbox not supported yet
+#
+# Copyright (c) 2021 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+PASTA_PID="$(mktemp)"
+PASTA_OPTS="-q --ipv4-only -a 10.0.2.0 -n 24 -g 10.0.2.2 -m 1500 --no-ndp --no-dhcpv6 --no-dhcp -P ${PASTA_PID}"
+
+# add() - Add single option to $PASTA_OPTS
+# $1: Option name, with or without argument
+add() {
+ PASTA_OPTS="${PASTA_OPTS} ${1}"
+}
+
+# drop() - Drop one option (without argument) from $PASTA_OPTS
+# $1: Option name
+drop() {
+ old_opts="${PASTA_OPTS}"; PASTA_OPTS=
+ for o in ${old_opts}; do [ "${o}" != "${1}" ] && add "${o}"; done
+}
+
+# sub() - Substitute option in $PASTA_OPTS, with or without argument
+# $1: Option name
+# $2: Option argument, can be empty
+sub() {
+ old_opts="${PASTA_OPTS}"; PASTA_OPTS=
+ next=0
+ for o in ${old_opts}; do
+ if [ ${next} -eq 1 ]; then
+ next=0; add "${1} ${2}"; shift; shift; continue
+ fi
+
+ for r in ${@}; do [ "${o}" = "${r}" ] && next=1 && break; done
+ [ "${next}" -eq 0 ] && add "${o}"
+ done
+}
+
+# xorshift() - pseudorandom permutation of 16-bit group
+# $1: 16-bit value to shuffle
+xorshift() {
+ # Adaptation of Xorshift algorithm from:
+ # Marsaglia, G. (2003). Xorshift RNGs.
+ # Journal of Statistical Software, 8(14), 1 - 6.
+ # doi:http://dx.doi.org/10.18637/jss.v008.i14
+ # with triplet (5, 3, 1), suitable for 16-bit ranges.
+ n=${1}
+ : $((n ^= n << 5))
+ : $((n ^= n >> 3))
+ : $((n ^= n << 1))
+ echo ${n}
+}
+
+# opt() - Validate single option from getopts
+# $1: Option type
+# $@: Variable names to assign to
+opt() {
+ case "${1}" in
+ u32)
+ if ! printf "%i" "${OPTARG}" >/dev/null 2>&1 || \
+ [ "${OPTARG}" -lt 0 ]; then
+ echo "${OPT} must be a non-negative integer"
+ usage
+ fi
+ eval ${2}="${OPTARG}"
+ ;;
+ mtu)
+ if ! printf "%i" "${OPTARG}" >/dev/null 2>&1 || \
+ [ "${OPTARG}" -lt 0 ] || [ "${OPTARG}" -ge 65522 ]; then
+ echo "MTU must be a positive integer (< 65522)"
+ usage
+ fi
+ eval ${2}="${OPTARG}"
+ ;;
+ str)
+ eval ${2}="${OPTARG}"
+ ;;
+ net4)
+ addr="${OPTARG%/*}"
+ mask="${OPTARG##*/}"
+
+ { [ -z "${mask}" ] || !printf "%i" "${mask}" >/dev/null 2>&1 \
+ || [ ${mask} -gt 32 ] || ${mask} -le 0 ]; } && usage
+
+ expr "${addr}" : \
+ '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' \
+ >/dev/null
+ [ $? -ne 0 ] && usage
+
+ ifs="${IFS}"; IFS='.'
+ for q in ${addr}; do [ ${q} -gt 255 ] && usage; done
+ IFS="${ifs}"
+
+ eval ${2}="${addr}"
+ eval ${3}="${mask}"
+ ;;
+ esac
+}
+
+# usage() - Print slirpnetns(1) usage and exit indicating failure
+# $1: Invalid option name, if any
+usage() {
+ [ ${#} -eq 1 ] && printf "s: invalid option -- '%s'\n" "${0}" "${1}"
+ cat << EOF
+Usage: ${0} [OPTION]... PID|PATH TAPNAME
+User-mode networking for unprivileged network namespaces.
+
+-c, --configure bring up the interface
+-e, --exit-fd=FD specify the FD for terminating slirp4netns
+-r, --ready-fd=FD specify the FD to write to when the network is configured
+-m, --mtu=MTU specify MTU (default=1500, max=65521)
+-6, --enable-ipv6 enable IPv6 (experimental)
+-a, --api-socket=PATH specify API socket path
+--cidr=CIDR specify network address CIDR (default=10.0.2.0/24)
+--disable-host-loopback prohibit connecting to 127.0.0.1:* on the host namespace
+--netns-type=TYPE specify network namespace type ([path|pid], default=pid)
+--userns-path=PATH specify user namespace path
+--enable-sandbox create a new mount namespace (and drop all caps except CAP_NET_BIND_SERVICE if running as the root)
+--enable-seccomp enable seccomp to limit syscalls (experimental)
+-h, --help show this help and exit
+-v, --version show version and exit
+EOF
+ exit 1
+}
+
+# version() - Print version
+version() {
+ echo "slirp4netns-like wrapper for pasta"
+ exit 0
+}
+
+# gen_addr6() - Generate pseudorandom IPv6 address, changes every second
+gen_addr6() {
+ printf "fd00"
+ n=$(($(xorshift $(date +%S)) % 65536))
+ for i in $(seq 2 8); do
+ printf ":%04x" ${n}
+ n=$(($(xorshift ${n}) % 65536))
+ done
+}
+
+# Default options
+v6=0
+get_pid=0
+MTU=1500
+A4="10.0.2.0"
+M4="255.255.255.0"
+no_map_gw=0
+EFD=0
+RFD=0
+
+while getopts ce:r:m:6a:hv-: OPT 2>/dev/null; do
+ if [ "${OPT}" = "-" ]; then
+ OPT="${OPTARG%%[= ]*}"
+ OPTARG="${OPTARG#${OPT}[= ]}"
+ fi
+ case "${OPT}" in
+ c | configure) add "--config-net" ;;
+ e | exit-fd) opt u32 EFD ;;
+ r | ready-fd) opt u32 RFD ;;
+ m | mtu) opt mtu MTU && sub -m ${MTU} ;;
+ 6 | enable-ipv6) V6=1 ;;
+ a | api-socket) opt str API ;;
+ cidr) opt net4 A4 M4 && sub -a ${A4} -n ${M4} ;;
+ disable-host-loopback) add "--no-map-gw" && no_map_gw=1 ;;
+ netns-type) : Autodetected ;;
+ userns-path) opt_str USERNS_NAME "${OPTARG}" ;;
+ enable-sandbox) : Not supported yet ;;
+ enable-seccomp) : Cannot be disabled ;;
+ h | help) usage "${0}" ;;
+ v | version) version ;;
+ ??*) usage "${0}" "${OPT}" ;;
+ ?) usage "${0}" ;;
+ esac
+done
+
+shift $((OPTIND - 1))
+[ ${#} -ne 2 ] && usage
+ns_spec="${1}"
+
+ifname="${2}"
+add "-I ${ifname}"
+
+if [ ${v6} -eq 1 ]; then
+ drop "--ipv4-only"
+ add "-a $(gen_addr6) -g fd00::2 -D fd00::3"
+fi
+
+./pasta ${PASTA_OPTS} ${ns_spec} 2>/dev/null && \
+ [ ${RFD} -ne 0 ] && echo "1" >&${RFD}
+
+trap "kill $(cat ${PASTA_PID}); rm ${PASTA_PID}" INT TERM
+
+cat << EOF
+sent tapfd=5 for ${ifname}
+received tapfd=5
+Starting slirp
+* MTU: ${MTU}
+* Network: ${A4}
+* Netmask: ${M4}
+* Gateway: 10.0.2.2
+* DNS: 10.0.2.3
+* Recommended IP: 10.0.2.100
+EOF
+
+if [ ${no_map_gw} -eq 0 ]; then
+ echo "WARNING: 127.0.0.1:* on the host is accessible as 10.0.2.2 (set --disable-host-loopback to prohibit connecting to 127.0.0.1:*)"
+fi
+
+if [ ${EFD} -ne 0 ]; then
+ dd count=1 of=/dev/null 2>/dev/null <&${EFD}
+else
+ while read a; do :; done
+fi
+
+exit 0