mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
580 lines
17 KiB
Bash
Executable File
580 lines
17 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
PROGRAM=$(basename $0)
|
|
COUNT="2"
|
|
COMMAND=""
|
|
BRNAME="tapbr0"
|
|
TAPNAME="tap"
|
|
TUNNAME=""
|
|
DEACTIVATE_IPV6=""
|
|
ENABLE_FORWARDING=0
|
|
BRIDGE_ADDRS=""
|
|
BRIDGE_ROUTES=""
|
|
DEFAULT_PREFIX_LEN=128
|
|
UPLINK=""
|
|
|
|
usage() {
|
|
echo "usage: ${PROGRAM} [arguments]" >&2
|
|
echo "" >&2
|
|
echo "Defaults:"
|
|
echo " If no option is given, -c is assumed" >&2
|
|
echo "" >&2
|
|
echo "Options:" >&2
|
|
echo " -c [<num>], --create [<num>]: Create <num> tap interfaces (default: 2)" >&2
|
|
echo " -d, --delete: Delete all interface" >&2
|
|
echo " -l <iface>, --list <iface>: If <iface> belongs to a bridge, list the bridge and" >&2
|
|
echo " all interfaces that belong to it. If <iface> does " >&2
|
|
echo " not belong to a bridge, just print <iface>." >&2
|
|
echo " -a <address>[/<prefix_len>], --address <address>[/<prefix_len>]:" >&2
|
|
echo " Address to add to the created bridge. Can be used" >&2
|
|
echo " multiple times." >&2
|
|
echo " -r <route>[/<prefix_len>] <next_hop>, --route <route>[/<prefix_len>] <next_hop>:" >&2
|
|
echo " Route to add to via the created bridge. Can be used" >&2
|
|
echo " multiple times." >&2
|
|
echo " -f, --forwarding Enable forwarding system-wide on creation and " >&2
|
|
echo " disable on deletion." >&2
|
|
echo " --tun [<name>] Create a single, unbridged TUN interface" >&2
|
|
echo " named <name>0 (default for <name>: tun)." >&2
|
|
echo " No bridge will be created in that case." >&2
|
|
echo " <name> will be ignored on OSX and FreeBSD." >&2
|
|
echo " -b <name>, --bridge <name>: Give name for the bridge (default: tapbr)" >&2
|
|
echo " -t <name>, --tap <name>: Name base for the tap interfaces; the" >&2
|
|
echo " generated names will be <name>x" >&2
|
|
echo " (default: tap; ignored on OSX and FreeBSD)" >&2
|
|
echo " -6, --deactivate-ipv6: Deactivate IPv6 for the interfaces and bridge" >&2
|
|
echo " (ignored on OSX and FreeBSD)" >&2
|
|
echo " -u, --uplink: Optional uplink interface" >&2
|
|
echo " (ignored on OSX and FreeBSD)" >&2
|
|
echo " -h, --help: Prints this text" >&2
|
|
}
|
|
|
|
unsupported_platform() {
|
|
echo "unsupported platform" >&2
|
|
echo "(currently supported \`uname -s\` 'Darwin', 'FreeBSD', and 'Linux')" >&2
|
|
}
|
|
|
|
update_uplink() {
|
|
if command -v dhclient > /dev/null; then
|
|
dhclient $1
|
|
else
|
|
echo "DHCP client \`dhclient\` not found." >&2
|
|
echo "Please reconfigure your DHCP client for interface $1" >&2
|
|
echo "to keep up-link's IPv4 connection." >&2
|
|
fi
|
|
}
|
|
|
|
activate_forwarding() {
|
|
if [ ${ENABLE_FORWARDING} -eq 1 ]; then
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
sysctl -w net.inet.ip.forwarding=1 || exit 1 ;;
|
|
Linux)
|
|
sysctl -w net.ipv6.conf.${BRNAME}.forwarding=1 || exit 1
|
|
if [ -z ${TUNNAME} ]; then
|
|
sysctl -w net.ipv6.conf.${BRNAME}.accept_ra=0 || exit 1
|
|
else
|
|
echo "Setting accept_ra=2 for all interfaces!" >&2
|
|
# See https://github.com/RIOT-OS/RIOT/issues/14689#issuecomment-668500682
|
|
for iface in $(ip link | grep -o "^[0-9]\+: [^:]\+" | cut -f2 -d' '); do
|
|
sysctl -w net.ipv6.conf.${iface}.accept_ra=2 || exit 1
|
|
done
|
|
fi
|
|
sysctl -w net.ipv6.conf.all.forwarding=1 || exit 1 ;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
add_ipv6_addrs() {
|
|
for a in ${BRIDGE_ADDRS}; do
|
|
address_addr=$(echo "${a}" | cut -d/ -f1)
|
|
prefix_len=$(echo "${a}" | cut -d/ -f2)
|
|
if [ "${a}" = "${prefix_len}" ]; then
|
|
# prefix length is not defined
|
|
prefix_len=${DEFAULT_PREFIX_LEN}
|
|
fi
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
ifconfig ${BRNAME} inet6 ${address_addr} prefixlen ${prefix_len} || exit 1
|
|
;;
|
|
Linux)
|
|
ip address add ${address_addr}/${prefix_len} dev ${BRNAME} || exit 1
|
|
;;
|
|
*) ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
add_ipv6_routes() {
|
|
for r in ${BRIDGE_ROUTES}; do
|
|
route=$(echo "${r}" | cut -d- -f1)
|
|
next_hop=$(echo "${r}" | cut -d- -f2)
|
|
route_prefix=$(echo "${route}" | cut -d/ -f1)
|
|
route_prefix_len=$(echo "${route}" | cut -d/ -f2)
|
|
if [ "${route}" = "${route_prefix_len}" ]; then
|
|
# prefix length is not defined
|
|
route_prefix_len=${DEFAULT_PREFIX_LEN}
|
|
fi
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
route -6n add ${route_prefix} -interface ${BRNAME} \
|
|
${next_hop} || exit 1
|
|
;;
|
|
Linux)
|
|
ip route add ${route_prefix}/${route_prefix_len} \
|
|
via ${next_hop} dev ${BRNAME} || exit 1
|
|
;;
|
|
*) ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
create_bridge() {
|
|
echo "creating bridge ${BRNAME}"
|
|
|
|
case "${PLATFORM}" in
|
|
FreeBSD)
|
|
kldload if_bridge # module might be already loaded => error
|
|
ifconfig ${BRNAME} create || exit 1 ;;
|
|
Linux)
|
|
ip link add name ${BRNAME} type bridge || exit 1
|
|
if [ -n "${UPLINK}" ]; then
|
|
echo "using uplink ${UPLINK}"
|
|
ip link set dev ${UPLINK} master ${BRNAME} || exit 1
|
|
fi
|
|
if [ -n "${DEACTIVATE_IPV6}" ]; then
|
|
echo 1 > /proc/sys/net/ipv6/conf/${BRNAME}/disable_ipv6 || exit 1
|
|
fi ;;
|
|
OSX)
|
|
ifconfig ${BRNAME} create || exit 1 ;;
|
|
*)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
up_bridge() {
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
ifconfig ${BRNAME} up || exit 1 ;;
|
|
Linux)
|
|
ip link set ${BRNAME} up || exit 1
|
|
|
|
# The bridge is now the new uplink
|
|
if [ -n "${UPLINK}" ]; then
|
|
update_uplink ${BRNAME}
|
|
fi ;;
|
|
*)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
deactivate_forwarding() {
|
|
if [ ${ENABLE_FORWARDING} -eq 1 ]; then
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
sysctl -w net.inet.ip.forwarding=0 || exit 1 ;;
|
|
Linux)
|
|
sysctl -w net.ipv6.conf.${BRNAME}.forwarding=0 || exit 1
|
|
if [ -z ${TUNNAME} ]; then
|
|
sysctl -w net.ipv6.conf.${BRNAME}.accept_ra=1 || exit 1
|
|
else
|
|
echo "Setting accept_ra=1 for all interfaces!" >&2
|
|
# See https://github.com/RIOT-OS/RIOT/issues/14689#issuecomment-668500682
|
|
for iface in $(ip link | grep -o "^[0-9]\+: [^:]\+" | cut -f2 -d' '); do
|
|
sysctl -w net.ipv6.conf.${iface}.accept_ra=1 || exit 1
|
|
done
|
|
fi
|
|
sysctl -w net.ipv6.conf.all.forwarding=0 || exit 1 ;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
del_ipv6_addrs() {
|
|
for a in ${BRIDGE_ADDRS}; do
|
|
address_addr=$(echo "${a}" | cut -d/ -f1)
|
|
prefix_len=$(echo "${a}" | cut -d/ -f2)
|
|
if [ "${a}" = "${prefix_len}" ]; then
|
|
# prefix length is not defined
|
|
prefix_len=${DEFAULT_PREFIX_LEN}
|
|
fi
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
ifconfig ${BRNAME} inet6 ${address_addr} prefixlen ${prefix_len} delete || exit 1
|
|
;;
|
|
Linux)
|
|
ip address delete ${address_addr}/${prefix_len} dev ${BRNAME} || exit 1
|
|
;;
|
|
*) ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
del_ipv6_routes() {
|
|
for r in ${BRIDGE_ROUTES}; do
|
|
route=$(echo "${r}" | cut -d- -f1)
|
|
next_hop=$(echo "${r}" | cut -d- -f2)
|
|
route_prefix=$(echo "${route}" | cut -d/ -f1)
|
|
route_prefix_len=$(echo "${route}" | cut -d/ -f2)
|
|
if [ "${route}" = "${route_prefix_len}" ]; then
|
|
# prefix length is not defined
|
|
route_prefix_len=${DEFAULT_PREFIX_LEN}
|
|
fi
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
route -6 delete ${route_prefix}/${route_prefix_len} \
|
|
-interface ${BRNAME} ${next_hop} || exit 1
|
|
;;
|
|
Linux)
|
|
ip route delete ${route_prefix}/${route_prefix_len} \
|
|
via ${next_hop} dev ${BRNAME} || exit 1
|
|
;;
|
|
*) ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
delete_iface() {
|
|
IFACE="$1"
|
|
echo "deleting ${IFACE}"
|
|
case "${PLATFORM}" in
|
|
FreeBSD|OSX)
|
|
ifconfig "${IFACE}" destroy ;;
|
|
Linux)
|
|
ip link delete "${IFACE}" ;;
|
|
*) ;;
|
|
esac
|
|
}
|
|
|
|
delete_bridge() {
|
|
case "${PLATFORM}" in
|
|
FreeBSD)
|
|
sysctl net.link.tap.user_open=0
|
|
for IF in $(ifconfig ${BRIDGE} | grep -oiE "member: .+ " | cut -d' ' -f2); do
|
|
delete_iface ${IF}
|
|
done
|
|
delete_iface ${BRNAME} || exit 1
|
|
kldunload if_tap # unloading might fail due to dependencies
|
|
kldunload if_bridge ;;
|
|
Linux)
|
|
for IF in $(ls /sys/class/net/${BRNAME}/brif); do
|
|
if [ "${IF}" != "${UPLINK}" ]; then
|
|
delete_iface ${IF}
|
|
fi
|
|
done
|
|
|
|
delete_iface ${BRNAME} || exit 1
|
|
|
|
# restore the old uplink
|
|
if [ -n "${UPLINK}" ]; then
|
|
update_uplink ${UPLINK}
|
|
fi ;;
|
|
OSX)
|
|
for IF in $(ifconfig ${BRIDGE} | grep -oiE "member: .+ " | cut -d' ' -f2); do
|
|
delete_iface ${IF}
|
|
done
|
|
delete_iface ${BRNAME} || exit 1 ;;
|
|
*)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
begin_iface() {
|
|
if [ -z "${TUNNAME}" ]; then
|
|
MODE="tun"
|
|
else
|
|
MODE="tap"
|
|
fi
|
|
case "${PLATFORM}" in
|
|
FreeBSD)
|
|
kldload if_${MODE} # module might be already loaded => error
|
|
sysctl net.link.${MODE}.user_open=1 ;;
|
|
*)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
create_iface() {
|
|
if [ -z "${TUNNAME}" ]; then
|
|
NAME="${TAPNAME}"
|
|
MODE="tap"
|
|
else
|
|
NAME="${TUNNAME}"
|
|
MODE="tun"
|
|
fi
|
|
case "${PLATFORM}" in
|
|
FreeBSD)
|
|
echo "creating ${NAME}${N}" || exit 1
|
|
ifconfig ${NAME}${N} create || exit 1
|
|
chown ${SUDO_USER} /dev/${MODE}${N} || exit 1
|
|
if [ -z "${TUNNAME}" ]; then
|
|
ifconfig ${BRNAME} addm ${NAME}${N} || exit 1
|
|
fi
|
|
ifconfig tap${N} up || exit 1 ;;
|
|
Linux)
|
|
echo "creating ${NAME}${N}"
|
|
ip tuntap add dev ${NAME}${N} mode ${MODE} user ${SUDO_USER} || exit 1
|
|
if [ -n "${DEACTIVATE_IPV6}" ]; then
|
|
echo 1 > /proc/sys/net/ipv6/conf/${NAME}${N}/disable_ipv6 || exit 1
|
|
fi
|
|
if [ -z "${TUNNAME}" ]; then
|
|
ip link set dev ${NAME}${N} master ${BRNAME} || exit 1
|
|
fi
|
|
ip link set ${NAME}${N} up || exit 1 ;;
|
|
OSX)
|
|
chown ${SUDO_USER} /dev/${NAME}${N} || exit 1
|
|
echo "start RIOT instance for ${NAME}${N} now and hit enter"
|
|
read
|
|
if [ -z "${TUNNAME}" ]; then
|
|
ifconfig ${BRNAME} addm ${NAME}${N} || exit 1
|
|
fi
|
|
ifconfig ${NAME}${N} up || exit 1 ;;
|
|
*)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
get_master() {
|
|
IFACE=$1
|
|
case "${PLATFORM}" in
|
|
Linux)
|
|
MASTER=$(ip link show ${IFACE} | grep -o "master \S\+" | cut -d' ' -f2)
|
|
;;
|
|
FreeBSD|OSX)
|
|
for IF in $(ifconfig | grep -oiE "^[a-z0-9_-]+"); do
|
|
if ifconfig $IF | grep -q "member: $IFACE"; then
|
|
MASTER=${IF}
|
|
break
|
|
fi
|
|
done
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
if [ -z "$MASTER" ]; then
|
|
# IFACE is its own master
|
|
echo "$IFACE"
|
|
else
|
|
echo "$MASTER"
|
|
fi
|
|
}
|
|
|
|
list_bridge() {
|
|
BRIDGE=$1
|
|
IFACES=0
|
|
echo -n "$BRIDGE:"
|
|
case "${PLATFORM}" in
|
|
Linux)
|
|
for IF in $(ls /sys/class/net/${BRIDGE}/brif 2> /dev/null); do
|
|
echo ""
|
|
echo -n "- $IF"
|
|
IFACES=$(( ${IFACES} + 1 ))
|
|
done
|
|
;;
|
|
FreeBSD|OSX)
|
|
for IF in $(ifconfig ${BRIDGE} | grep -oiE "member: .+ " | cut -d' ' -f2); do
|
|
echo ""
|
|
echo -n "- $IF"
|
|
IFACES=$(( ${IFACES} + 1 ))
|
|
done
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
if [ "${IFACES}" -eq 0 ]; then
|
|
echo " []"
|
|
else
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
while true ; do
|
|
case "$1" in
|
|
-6)
|
|
DEACTIVATE_IPV6=1
|
|
shift ;;
|
|
-a|--address)
|
|
# check if valid address + optional prefix length
|
|
if echo "$2" | grep -q "^[a-f0-9:]\+\(/[0-9]\+\)\?$"; then
|
|
BRIDGE_ADDRS="${BRIDGE_ADDRS} $2"
|
|
shift 2
|
|
else
|
|
usage
|
|
exit 2
|
|
fi ;;
|
|
-b|--bridge)
|
|
case "$2" in
|
|
"")
|
|
usage
|
|
exit 2 ;;
|
|
*)
|
|
BRNAME="$2"
|
|
shift 2 ;;
|
|
esac ;;
|
|
-c|--create)
|
|
if [ -n "${COMMAND}" ]; then
|
|
usage
|
|
exit 2
|
|
fi
|
|
COMMAND="create"
|
|
case "$2" in
|
|
"")
|
|
shift ;;
|
|
*[!0-9]*)
|
|
usage
|
|
exit 2;;
|
|
*)
|
|
COUNT="$2"
|
|
shift 2 ;;
|
|
esac ;;
|
|
-d|--delete)
|
|
if [ -n "${COMMAND}" ]; then
|
|
usage
|
|
exit 2
|
|
fi
|
|
COMMAND="delete"
|
|
shift ;;
|
|
-f|--forwarding)
|
|
ENABLE_FORWARDING=1
|
|
shift ;;
|
|
-l|--list)
|
|
if [ -n "${COMMAND}" ]; then
|
|
usage
|
|
exit 2
|
|
fi
|
|
COMMAND="list"
|
|
case "$2" in
|
|
"")
|
|
usage
|
|
exit 2 ;;
|
|
*)
|
|
BRNAME="$2"
|
|
shift 2 ;;
|
|
esac ;;
|
|
-h|--help)
|
|
usage
|
|
exit ;;
|
|
-r|--route)
|
|
# check if valid address + optional prefix length
|
|
if ! echo "$2" | grep -q "^[a-f0-9:]\+\(/[0-9]\+\)\?$"; then
|
|
usage
|
|
exit 2
|
|
fi
|
|
# check if valid next hop
|
|
if ! echo "$3" | grep -q "^[a-f0-9:]\+$"; then
|
|
usage
|
|
exit 2
|
|
fi
|
|
BRIDGE_ROUTES="${BRIDGE_ROUTES} $2-$3"
|
|
shift 3 ;;
|
|
-u|--uplink)
|
|
case "$2" in
|
|
"")
|
|
usage
|
|
exit 2 ;;
|
|
*)
|
|
UPLINK="$2"
|
|
shift 2 ;;
|
|
esac ;;
|
|
-t|--tap)
|
|
case "$2" in
|
|
"")
|
|
usage
|
|
exit 2 ;;
|
|
*)
|
|
TAPNAME="$2"
|
|
shift 2 ;;
|
|
esac ;;
|
|
--tun)
|
|
case "$2" in
|
|
"")
|
|
TUNNAME="tun"
|
|
shift 1 ;;
|
|
*)
|
|
TUNNAME="$2"
|
|
shift 2 ;;
|
|
esac ;;
|
|
"")
|
|
break ;;
|
|
*) usage
|
|
exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "${COMMAND}" ]; then
|
|
COMMAND="create"
|
|
fi
|
|
if [ -z "${SUDO_USER}" ] && [ "${COMMAND}" != "list" ]; then
|
|
echo 'Environment variable $SUDO_USER required; Please run with `sudo`'
|
|
exit 1
|
|
fi
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
PLATFORM="OSX"
|
|
if echo "$BRNAME" | grep -v -q "^bridge"; then
|
|
BRNAME=bridge42
|
|
fi
|
|
if [ -n "${TUNNAME}" ]; then
|
|
TUNNAME="tun"
|
|
fi
|
|
;;
|
|
FreeBSD)
|
|
PLATFORM="FreeBSD"
|
|
if echo "$BRNAME" | grep -v -q "^bridge"; then
|
|
BRNAME=bridge0
|
|
fi
|
|
if [ -n "${TUNNAME}" ]; then
|
|
TUNNAME="tun"
|
|
fi
|
|
;;
|
|
Linux)
|
|
PLATFORM="Linux" ;;
|
|
*)
|
|
unsupported_platform
|
|
exit 1 ;;
|
|
esac
|
|
|
|
if [ -n "${TUNNAME}" ]; then
|
|
echo "Only creating TUN interface ${TUNNAME}0 but no bridge"
|
|
COUNT=1
|
|
BRNAME="${TUNNAME}0"
|
|
fi
|
|
|
|
if [ "${COMMAND}" = 'create' ]; then
|
|
if [ -z "${TUNNAME}" ]; then
|
|
create_bridge || exit 1
|
|
fi
|
|
|
|
begin_iface || exit 1
|
|
|
|
for N in $(seq 0 "$((COUNT - 1))"); do
|
|
create_iface || exit 1
|
|
done
|
|
|
|
activate_forwarding || exit 1
|
|
if [ -z "${TUNNAME}" ]; then
|
|
up_bridge || exit 1
|
|
fi
|
|
add_ipv6_addrs || exit 1
|
|
add_ipv6_routes || exit 1
|
|
|
|
elif [ "${COMMAND}" = 'delete' ]; then
|
|
del_ipv6_routes || exit 1
|
|
del_ipv6_addrs || exit 1
|
|
deactivate_forwarding || exit 1
|
|
if [ -z "${TUNNAME}" ]; then
|
|
delete_bridge
|
|
else
|
|
for N in $(seq 0 "$((COUNT - 1))"); do
|
|
delete_iface "${TUNNAME}${N}"
|
|
done
|
|
fi
|
|
elif [ "${COMMAND}" = 'list' ]; then
|
|
list_bridge $(get_master "$BRNAME")
|
|
else
|
|
echo 'unknown command'
|
|
exit 1
|
|
fi
|
|
|
|
exit 0
|