#!/bin/sh
# CVE-2026-98432 interim mitigation (Linux, nftables): drop inbound IPv4 TCP packets that carry IP options
# (IHL > 5) before the TCP stack sees them. Non-TCP packets (IGMP router-alert etc.) are untouched.
# Independent table => coexists with ufw / iptables-nft / docker / pve-firewall.
# Usage (root): ctg-cve-2026-98432 load | apply | verify.  Removal = `apt remove ctg-cve-2026-98432`
# (or `apt purge` too); once the distro kernel carries the fix, remove the package.
PATH=/usr/sbin:/sbin:/usr/bin:/bin
T=cve_2026_98432
RULES=/usr/lib/ctg-cve-2026-98432/rules.nft
UNIT=cve-2026-98432-mitigation.service
case "$1" in
load) # called by the unit; older nft without counter support gets the same rule without the counter
  if nft -c -f "$RULES" 2>/dev/null; then exec nft -f "$RULES"; fi
  sed 's/ drop comment/ drop comment/; s/ ip hdrlength > 5 counter drop/ ip hdrlength > 5 drop/; s/hdrlength > 5 counter drop/hdrlength > 5 drop/' "$RULES" > "/run/$T.nft" || exit 1
  nft -c -f "/run/$T.nft" || { echo "FAIL: syntax" >&2; exit 1; }
  nft -f "/run/$T.nft"; rc=$?; rm -f "/run/$T.nft"; exit $rc ;;
apply)
  [ "$(id -u)" = 0 ] || { echo "need root"; exit 2; }
  systemctl enable --now "$UNIT"; sh "$0" verify ;;
verify)
  ok=1
  out=$(nft list table inet $T 2>&1) || ok=0
  echo "$out" | grep -q 'ip hdrlength > 5' || ok=0
  echo "$out" | grep -q 'drop' || ok=0
  en=$(systemctl is-enabled "$UNIT" 2>/dev/null); [ "$en" = enabled ] || ok=0
  mig=$(cat /proc/sys/net/ipv4/tcp_migrate_req 2>/dev/null || echo n/a); { [ "$mig" = 0 ] || [ "$mig" = n/a ]; } || ok=0
  pk=$(echo "$out" | sed -n 's/.*counter packets \([0-9]*\).*/\1/p'); [ -n "$pk" ] || pk=n/a
  [ $ok = 1 ] && s=OK || s=FAIL
  echo "MITIGATION-$s host=$(hostname) kernel=$(uname -r) unit=$en migrate_req=$mig dropped_pkts=$pk"
  [ $ok = 1 ] ;;
*) echo "usage: $0 load|apply|verify"; exit 2 ;;
esac
