#!/usr/bin/env bash set -euo pipefail BASE_BRIDGE_NAME=br-q BASE_TAP_NAME=tap-q randstr() { dd if=/dev/urandom count=1 bs=4 2>/dev/null | xxd -p -g 0 } default_route() { ip route | grep '^default' | sed -n 's/.*dev \([^ ]*\).*/\1/p' } find_next_subnet() { local i for i in {20..254}; do if ip route | grep -q "^172\.$i\."; then true else break fi done echo "172.$i" } create() { local next_subnet local bridge_name local dhcp_subnet local dhcp_range local tap_name local dnsmasq_pid next_subnet="$(find_next_subnet)" dhcp_subnet="$next_subnet.0.1/16" dhcp_range="$next_subnet.0.2,$next_subnet.255.254" bridge_name="$BASE_BRIDGE_NAME-$(randstr)" tap_name="$BASE_TAP_NAME-$(randstr)" echo > "$NET_CONF_FILE" ip link add name "$bridge_name" type bridge echo "bridge_name='$bridge_name'" >> "$NET_CONF_FILE" ip addr add "$dhcp_subnet" dev "$bridge_name" ip link set dev "$bridge_name" up ip tuntap add "$tap_name" mode tap echo "tap_name='$tap_name'" >> "$NET_CONF_FILE" ip link set "$tap_name" up ip link set dev "$tap_name" master "$bridge_name" dnsmasq -k --interface="$bridge_name" --bind-interface \ --dhcp-range="$dhcp_range" & dnsmasq_pid="$!" echo "dnsmasq_pid='$dnsmasq_pid'" >> "$NET_CONF_FILE" disown -h "$dnsmasq_pid" echo "nft_ruleset='$(nft -s list ruleset)'" >> "$NET_CONF_FILE" # dhcp nft add rule ip filter INPUT udp dport 67 accept nft add rule ip filter INPUT tcp dport 67 accept # dns nft add rule ip filter INPUT udp dport 53 accept nft add rule ip filter INPUT tcp dport 53 accept # scream nft add rule ip filter INPUT udp dport 4010 accept nft add rule ip filter INPUT tcp dport 4010 accept # forward bridge nft add rule ip filter FORWARD iifname "$bridge_name" \ counter packets 0 bytes 0 accept nft add rule ip filter FORWARD oifname "$bridge_name" \ counter packets 0 bytes 0 accept nft add rule ip nat POSTROUTING oifname "$(default_route)" \ counter masquerade } delete() { source "$NET_CONF_FILE" kill "$dnsmasq_pid" ip link del "$tap_name" ip link del "$bridge_name" nft flush ruleset nft -f - <<< "$nft_ruleset" rm "$NET_CONF_FILE" } if [[ -z "$NET_CONF_FILE" ]]; then echo Please specify the configuration file path \ with NET_CONF_FILE >&2 exit 1 fi if [[ "EUID" -ne 0 ]]; then echo "Please run as root" >&2 exit 2 fi "$@"