154 lines
4.5 KiB
Bash
Executable File
154 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SUBNET=""
|
|
OPEN_TO_ALL="no"
|
|
DRY_RUN="no"
|
|
|
|
log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
|
warn() { printf '\033[1;33m==>\033[0m %s\n' "$*" >&2; }
|
|
fail() { printf '\033[1;31m==>\033[0m %s\n' "$*" >&2; exit 1; }
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
PiStation host firewall setup
|
|
|
|
sudo ./infra/firewall.sh [options]
|
|
|
|
Opens the ports LiveKit needs. The web and API containers publish their ports
|
|
through Docker, which writes its own rules and is not affected by the host
|
|
firewall. LiveKit runs on the host network, so it is.
|
|
|
|
Options
|
|
--subnet <cidr> Allow only this network, defaults to the LAN behind your default route
|
|
--open-to-all Allow from any address instead of a single network
|
|
--dry-run Print the commands without running them
|
|
--help Show this message
|
|
USAGE
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--subnet) SUBNET="${2:-}"; shift 2 ;;
|
|
--subnet=*) SUBNET="${1#*=}"; shift ;;
|
|
--open-to-all) OPEN_TO_ALL="yes"; shift ;;
|
|
--dry-run) DRY_RUN="yes"; shift ;;
|
|
--help|-h) usage; exit 0 ;;
|
|
*) fail "unknown option: $1" ;;
|
|
esac
|
|
done
|
|
|
|
PORTS_TCP=(7880 7881)
|
|
PORTS_UDP=(3478)
|
|
RANGE_UDP_START=50000
|
|
RANGE_UDP_END=50100
|
|
|
|
detect_subnet() {
|
|
local interface
|
|
interface="$(ip route show default 2>/dev/null | awk '/default/ {print $5; exit}')"
|
|
[[ -n "$interface" ]] || return 1
|
|
ip -o -f inet route show scope link dev "$interface" 2>/dev/null | awk '{print $1; exit}'
|
|
}
|
|
|
|
run() {
|
|
if [[ "$DRY_RUN" == "yes" ]]; then
|
|
printf ' %s\n' "$*"
|
|
else
|
|
"$@" >/dev/null
|
|
fi
|
|
}
|
|
|
|
if [[ "$OPEN_TO_ALL" == "no" && -z "$SUBNET" ]]; then
|
|
SUBNET="$(detect_subnet || true)"
|
|
[[ -n "$SUBNET" ]] || fail "could not work out your LAN subnet, pass --subnet or --open-to-all"
|
|
fi
|
|
|
|
if [[ "$DRY_RUN" == "no" && $EUID -ne 0 ]]; then
|
|
fail "run this with sudo, or pass --dry-run to see what it would do"
|
|
fi
|
|
|
|
apply_ufw() {
|
|
if [[ "$OPEN_TO_ALL" == "yes" ]]; then
|
|
for port in "${PORTS_TCP[@]}"; do
|
|
run ufw allow "${port}/tcp"
|
|
done
|
|
for port in "${PORTS_UDP[@]}"; do
|
|
run ufw allow "${port}/udp"
|
|
done
|
|
run ufw allow "${RANGE_UDP_START}:${RANGE_UDP_END}/udp"
|
|
return
|
|
fi
|
|
|
|
for port in "${PORTS_TCP[@]}"; do
|
|
run ufw allow from "$SUBNET" to any port "$port" proto tcp
|
|
done
|
|
for port in "${PORTS_UDP[@]}"; do
|
|
run ufw allow from "$SUBNET" to any port "$port" proto udp
|
|
done
|
|
run ufw allow from "$SUBNET" to any port "${RANGE_UDP_START}:${RANGE_UDP_END}" proto udp
|
|
}
|
|
|
|
apply_firewalld() {
|
|
if [[ "$OPEN_TO_ALL" == "yes" ]]; then
|
|
for port in "${PORTS_TCP[@]}"; do
|
|
run firewall-cmd --permanent "--add-port=${port}/tcp"
|
|
done
|
|
for port in "${PORTS_UDP[@]}"; do
|
|
run firewall-cmd --permanent "--add-port=${port}/udp"
|
|
done
|
|
run firewall-cmd --permanent "--add-port=${RANGE_UDP_START}-${RANGE_UDP_END}/udp"
|
|
else
|
|
for port in "${PORTS_TCP[@]}"; do
|
|
run firewall-cmd --permanent "--add-rich-rule=rule family=ipv4 source address=${SUBNET} port port=${port} protocol=tcp accept"
|
|
done
|
|
for port in "${PORTS_UDP[@]}"; do
|
|
run firewall-cmd --permanent "--add-rich-rule=rule family=ipv4 source address=${SUBNET} port port=${port} protocol=udp accept"
|
|
done
|
|
run firewall-cmd --permanent "--add-rich-rule=rule family=ipv4 source address=${SUBNET} port port=${RANGE_UDP_START}-${RANGE_UDP_END} protocol=udp accept"
|
|
fi
|
|
run firewall-cmd --reload
|
|
}
|
|
|
|
print_manual() {
|
|
cat <<MANUAL
|
|
No supported firewall front end was found. If you are running nftables or
|
|
iptables directly, allow these from ${SUBNET:-any address}:
|
|
|
|
tcp ${PORTS_TCP[*]}
|
|
udp ${PORTS_UDP[*]}
|
|
udp ${RANGE_UDP_START}-${RANGE_UDP_END}
|
|
MANUAL
|
|
}
|
|
|
|
if command -v ufw >/dev/null 2>&1; then
|
|
BACKEND="ufw"
|
|
elif command -v firewall-cmd >/dev/null 2>&1; then
|
|
BACKEND="firewalld"
|
|
else
|
|
BACKEND="none"
|
|
fi
|
|
|
|
if [[ "$BACKEND" == "ufw" && $EUID -eq 0 ]] && ! ufw status 2>/dev/null | grep -q "^Status: active"; then
|
|
warn "ufw is installed but not active, the rules will apply once you run: ufw enable"
|
|
fi
|
|
|
|
if [[ "$OPEN_TO_ALL" == "yes" ]]; then
|
|
log "opening LiveKit ports to any address"
|
|
else
|
|
log "opening LiveKit ports to $SUBNET"
|
|
fi
|
|
|
|
case "$BACKEND" in
|
|
ufw) apply_ufw ;;
|
|
firewalld) apply_firewalld ;;
|
|
none) print_manual; exit 0 ;;
|
|
esac
|
|
|
|
log "done via $BACKEND"
|
|
echo
|
|
echo " tcp 7880 LiveKit signalling, the websocket browsers connect to"
|
|
echo " tcp 7881 LiveKit media over TCP, used where UDP is blocked"
|
|
echo " udp 3478 TURN relay"
|
|
echo " udp 50000-50100 LiveKit media, the normal path for audio and video"
|
|
echo
|