Files
2026-10-15 20:44:05 -03:00

107 lines
4.5 KiB
Bash
Executable File

#!/bin/bash
# Installs the contest firewall without Ansible, on the booted contest image
# (Ubuntu 26.04, as in the ICPC image). Run it as root from this directory.
#
# sudo ./install_firewall.sh # install, the firewall starts at the next boot
# sudo ./install_firewall.sh --start # install and start it now
set -euo pipefail
cd "$(dirname "$0")"
if [ "$(id -u)" -ne 0 ]; then
echo "Run this script as root (sudo)." >&2
exit 1
fi
START=no
[ "${1:-}" = "--start" ] && START=yes
TIMEZONE=${TIMEZONE:-America/Moncton}
entries() {
sed -e 's/#.*//' -e 's/[[:space:]]//g' "$1" | grep -v '^$'
}
echo "Installing nftables, dig, chrony and the nginx stream module"
apt-get update
apt-get install -y nftables dnsutils chrony nginx libnginx-mod-stream dnsmasq-base
id contest-proxy >/dev/null 2>&1 || useradd --system --no-create-home --shell /usr/sbin/nologin contest-proxy
echo "Copying the lists, scripts and systemd units"
install -d -m 0755 /etc/contest-firewall
install -m 0644 allowed_domains.txt dns_servers.txt ntp_servers.txt files/contest-proxy.conf /etc/contest-firewall/
install -m 0500 files/firewall.sh files/refresh_rules.sh files/enable_firewall.sh files/disable_firewall.sh /
install -m 0755 test_firewall.sh /
install -m 0644 files/firewall.service files/refresh_rules.service files/refresh_rules.timer files/contest-proxy.service files/contest-dns.service /etc/systemd/system/
echo "Configuring DNS (systemd-resolved)"
dns_list=$(entries dns_servers.txt | tr '\n' ' ' | sed 's/ $//')
if grep -qE '^#?DNS=' /etc/systemd/resolved.conf; then
sed -i -E "s|^#?DNS=.*|DNS=${dns_list}|" /etc/systemd/resolved.conf
else
echo "DNS=${dns_list}" >> /etc/systemd/resolved.conf
fi
if grep -qE '^#?DNSStubListener=' /etc/systemd/resolved.conf; then
sed -i -E 's|^#?DNSStubListener=.*|DNSStubListener=no|' /etc/systemd/resolved.conf
else
echo "DNSStubListener=no" >> /etc/systemd/resolved.conf
fi
echo "Configuring NTP (chrony) and the timezone"
sed -i -E '/^# (BEGIN|END) CONTEST FIREWALL NTP SERVERS$/,/^# END CONTEST FIREWALL NTP SERVERS$/d' /etc/chrony/chrony.conf
sed -i -E '/^(pool|server)[[:space:]]/d' /etc/chrony/chrony.conf
{
echo "# BEGIN CONTEST FIREWALL NTP SERVERS"
for ntp in $(entries ntp_servers.txt); do
echo "pool ${ntp} iburst"
done
echo "# END CONTEST FIREWALL NTP SERVERS"
cat /etc/chrony/chrony.conf
} > /etc/chrony/chrony.conf.new
mv /etc/chrony/chrony.conf.new /etc/chrony/chrony.conf
# Ubuntu 26.04 adds NTS time sources that the firewall blocks, and chrony
# does not use the plain NTP servers while those sources are configured
if [ -f /etc/chrony/sources.d/ubuntu-ntp-pools.sources ]; then
mv /etc/chrony/sources.d/ubuntu-ntp-pools.sources /etc/chrony/sources.d/ubuntu-ntp-pools.sources.disabled
fi
# The contest machines may also run Windows, which keeps the hardware clock
# in local time: chrony must not write its time into that clock
sed -i -E '/^rtcsync/d' /etc/chrony/chrony.conf
grep -q '^makestep' /etc/chrony/chrony.conf || echo 'makestep 1 3' >> /etc/chrony/chrony.conf
# Fallback: time from the contest site if NTP does not work
install -m 0500 files/time/time_from_contest.sh /
install -m 0644 files/time/time_from_contest.service files/time/time_from_contest.timer /etc/systemd/system/
ln -sf "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime
echo "Blocking open.kattis.com"
grep -q 'open\.kattis\.com' /etc/hosts || printf '127.0.0.1\topen.kattis.com\n' >> /etc/hosts
# Firefox must send the real site name, which encrypted client hello (ECH) hides
POLICIES=/usr/lib/firefox/distribution/policies.json
if [ -f "$POLICIES" ]; then
echo "Turning off encrypted client hello in Firefox"
python3 - "$POLICIES" <<'PY'
import json, sys
path = sys.argv[1]
data = json.load(open(path))
prefs = data.setdefault("policies", {}).setdefault("Preferences", {})
for name in ("network.dns.echconfig.enabled", "network.dns.http3_echconfig.enabled"):
prefs[name] = {"Value": False, "Status": "locked"}
json.dump(data, open(path, "w"), indent=2)
PY
fi
echo "Restarting services"
systemctl restart systemd-resolved
systemctl enable chrony
systemctl restart chrony
timedatectl set-ntp true || true
systemctl daemon-reload
systemctl enable firewall.service refresh_rules.service refresh_rules.timer time_from_contest.timer
systemctl start refresh_rules.timer
if [ "$START" = yes ]; then
systemctl start firewall.service
/refresh_rules.sh
echo "Firewall installed and active."
else
echo "Firewall installed. It will start at the next boot (or run: sudo /enable_firewall.sh)."
fi