First version
This commit is contained in:
commit
243e92a9dd
84 files changed
+4012
No files matched your search
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/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
|
||||
Reference in new issue
Block a user