qemu-vm/net

104 lines
2.5 KiB
Bash
Executable file

#!/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
"$@"