#!/bin/sh
# Esempio di /etc/ipfw.rules per un nodo Tutanum su FreeBSD (filtro di livello 2).
# Compito di ipfw qui: filtrare a livello ethernet, scartare i pacchetti con impronte TCP
# tipiche delle scansioni (anti OS fingerprint) e lasciare il resto del livello 3 a pf.
#
# ipfw esamina i frame ethernet solo con net.link.ether.ipfw=1 in /etc/sysctl.conf. Da
# quel momento ogni pacchetto passa dalle regole due volte, una come frame (layer2) e una
# come pacchetto IP (not layer2): ogni regola dice percio' a quale passaggio si applica.
#
# Note rispetto alle versioni precedenti di questo file:
#   - la sintassi "allow ether ..." non esiste in ipfw: il livello 2 si scrive con
#     "layer2", "mac" e "mac-type";
#   - rimossa la tabella per fail2ban: il nodo usa sshguard, che agisce su una tabella di pf;
#   - le opzioni TCP richiedono il protocollo tcp nella regola.

fwcmd="/sbin/ipfw -q"
ext_if="em0"

$fwcmd -f flush

# --- Tabelle che cambiano a sistema avviato ---
# Dal securelevel 2 FreeBSD 15 congela pf: niente regole nuove, niente indirizzi aggiunti alle
# tabelle, niente chiusura delle connessioni. Le tabelle di ipfw invece restano modificabili
# fino al livello 2 compreso, e ipfw esamina ogni pacchetto: un indirizzo inserito perde subito
# anche le connessioni gia' aperte. Il valore di ogni voce e' l'ora di inserimento (date +%s),
# che serve a farla scadere.
for t in quarantena esche 22 mai_bloccare; do
    $fwcmd table $t destroy 2>/dev/null
    $fwcmd table $t create type addr
done
# indirizzi da non bandire mai (guard di Tor, resolver, computer di amministrazione), uno per riga
[ -r /etc/ipfw.mai_bloccare ] && while read -r a; do
    case "$a" in ''|\#*) continue ;; esac
    $fwcmd table mai_bloccare add "$a"
done < /etc/ipfw.mai_bloccare

# Quarantena (EDR): la jail contenuta non parla piu' con nessuno
$fwcmd add 50 deny log ip from 'table(quarantena)' to any not layer2
$fwcmd add 51 deny log ip from any to 'table(quarantena)' not layer2
# sshguard (backend sshg-fw-ipfw, tabella 22): fuori dall'host
$fwcmd add 52 deny log ip from 'table(22)' to me not layer2
# Esche: chi ha toccato l'honeypot dall'esterno raggiunge ancora soltanto l'esca
$fwcmd add 53 allow tcp from 'table(esche)' to any 22,2222,2223 in via $ext_if not layer2
$fwcmd add 54 deny log ip from 'table(esche)' to any in via $ext_if not layer2

# --- Passaggio IP (not layer2) ---
# Loopback e interfaccia delle jail: il filtro tra le jail e' di pf
$fwcmd add 100 allow ip from any to any via lo0 not layer2
$fwcmd add 110 allow ip from any to any via lo1 not layer2

# Anti OS fingerprint: scarta le firme TCP tipiche delle scansioni, in ingresso
$fwcmd add 200 deny log tcp from any to any in via $ext_if tcpdatalen 0 tcpflags syn,!fin,!rst,!psh,!ack,!urg tcpoptions mss,window,sack,ts tcpwin 1 not layer2
$fwcmd add 210 deny log tcp from any to any in via $ext_if tcpdatalen 0 tcpflags syn,!fin,!rst,!psh,!ack,!urg tcpoptions mss,window,sack,ts tcpwin 63 not layer2
$fwcmd add 220 deny log tcp from any to any in via $ext_if tcpdatalen 0 tcpflags syn,!fin,!rst,!psh,!ack,!urg tcpoptions mss,window,ts tcpwin 4 not layer2
$fwcmd add 230 deny log tcp from any to any in via $ext_if tcpdatalen 0 tcpflags syn,!fin,!rst,!psh,!ack,!urg tcpoptions mss,window,sack,ts tcpwin 4 not layer2
$fwcmd add 240 deny log tcp from any to any in via $ext_if tcpdatalen 0 tcpflags syn,!fin,!rst,!psh,!ack,!urg tcpoptions mss,sack,ts tcpwin 512 not layer2

# Il resto del traffico IP passa a pf, che applica il default-deny
$fwcmd add 300 allow ip from any to any not layer2

# --- Passaggio ethernet (layer2) ---
$fwcmd add 1000 allow all from any to any layer2 mac-type arp   # ARP
$fwcmd add 1010 allow all from any to any layer2 mac-type ip    # IPv4: il filtro vero e' di pf
# IPv6, STP, LLDP e ogni altro tipo di frame cadono qui sotto.

# Esempi (disattivati) di filtro per indirizzi MAC: solo il router puo' parlare con il nodo
# (sintassi: mac <destinazione> <origine>)
#$fwcmd add 900 allow all from any to any layer2 mac any aa:bb:cc:dd:ee:ff via $ext_if   # dal router
#$fwcmd add 910 allow all from any to any layer2 mac aa:bb:cc:dd:ee:ff any via $ext_if   # verso il router
#$fwcmd add 920 deny log all from any to any layer2 via $ext_if

# Default-deny di livello 2
$fwcmd add 65000 deny log all from any to any layer2
