diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2021-10-14 13:07:32 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-10-14 13:20:34 +0200 |
commit | 2e6e29a7577a45c2723080d2acd1621df6402831 (patch) | |
tree | 539d2c2bac62c25be1035886c4f417d2660ee1a5 | |
parent | 3c6d24dd3021bb294a7aa182a95a9cb868ca6cb4 (diff) | |
download | passt-2e6e29a7577a45c2723080d2acd1621df6402831.tar passt-2e6e29a7577a45c2723080d2acd1621df6402831.tar.gz passt-2e6e29a7577a45c2723080d2acd1621df6402831.tar.bz2 passt-2e6e29a7577a45c2723080d2acd1621df6402831.tar.lz passt-2e6e29a7577a45c2723080d2acd1621df6402831.tar.xz passt-2e6e29a7577a45c2723080d2acd1621df6402831.tar.zst passt-2e6e29a7577a45c2723080d2acd1621df6402831.zip |
slirp4netns.sh: Introduce compatibility wrapper behaving like slirp4netns(1)
Warning: draft quality, not really tested, --enable-sandbox not
supported yet.
Example:
$ unshare -rUn
# echo $$
3130879
$ ./slirp4netns.sh -m 65520 -c 3130879 tap0
sent tapfd=5 for tap0
received tapfd=5
Starting slirp
* MTU: 65520
* Network: 10.0.2.0
* Netmask: 255.255.255.0
* Gateway: 10.0.2.2
* DNS: 10.0.2.3
* Recommended IP: 10.0.2.100
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:*)
# ip li sh
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
33: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 5e:9d:a0:c5:cf:67 brd ff:ff:ff:ff:ff:ff
# ip ad sh
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
33: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc pfifo_fast state UNKNOWN group default qlen 1000
link/ether 5e:9d:a0:c5:cf:67 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.0/24 scope global tap0
valid_lft forever preferred_lft forever
inet6 fe80::5c9d:a0ff:fec5:cf67/64 scope link
valid_lft forever preferred_lft forever
# ip ro sh
default via 10.0.2.2 dev tap0
10.0.2.0/24 dev tap0 proto kernel scope link src 10.0.2.0
root@epycfail:~# ip -6 ro sh
fe80::/64 dev tap0 proto kernel metric 256 pref medium
# iperf3 -c 10.0.2.2 -l1M
Connecting to host 10.0.2.2, port 5201
[ 5] local 10.0.2.0 port 43014 connected to 10.0.2.2 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 1.38 GBytes 11.8 Gbits/sec 0 9.96 MBytes
[ 5] 1.00-2.00 sec 1.59 GBytes 13.6 Gbits/sec 0 13.3 MBytes
[ 5] 2.00-3.00 sec 1.63 GBytes 14.0 Gbits/sec 0 13.3 MBytes
[ 5] 3.00-4.00 sec 1.78 GBytes 15.3 Gbits/sec 0 13.3 MBytes
[ 5] 4.00-5.00 sec 1.80 GBytes 15.5 Gbits/sec 0 15.8 MBytes
[ 5] 5.00-6.00 sec 1.69 GBytes 14.5 Gbits/sec 0 15.8 MBytes
[ 5] 6.00-7.00 sec 1.65 GBytes 14.2 Gbits/sec 0 15.8 MBytes
[ 5] 7.00-8.00 sec 1.68 GBytes 14.4 Gbits/sec 0 15.8 MBytes
[ 5] 8.00-9.00 sec 1.60 GBytes 13.7 Gbits/sec 0 15.8 MBytes
[ 5] 9.00-10.00 sec 1.66 GBytes 14.3 Gbits/sec 0 15.8 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 16.5 GBytes 14.1 Gbits/sec 0 sender
[ 5] 0.00-10.01 sec 16.4 GBytes 14.1 Gbits/sec receiver
iperf Done.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rwxr-xr-x | slirp4netns.sh | 227 |
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 |