In breve: il firewall filter di RouterOS smista ogni pacchetto in una di tre chain: input (verso il router), forward (attraverso il router), output (dal router). In ogni chain le regole si leggono dall’alto in basso e la prima che corrisponde con un’azione come accept o drop chiude la partita; se nessuna corrisponde, il pacchetto passa. Per questo una regola nuova va sempre sopra il drop finale, mai sotto.

Che cosa sono le chain input, forward e output?

Sono tre liste di regole, una per ogni direzione che un pacchetto può prendere rispetto al router. Esistono di serie e non si possono cancellare.

  • input: pacchetti che entrano nel router e hanno come destinazione uno dei suoi indirizzi. WinBox, SSH, il ping al router, le richieste DNS al router, il traffico WireGuard verso il router;
  • forward: pacchetti che attraversano il router. Il PC della LAN che naviga, il port forward verso il server interno;
  • output: pacchetti che nascono nel router ed escono da un’interfaccia. Il ping lanciato dal terminale del router, le sue richieste NTP e DNS, le risposte che il router manda a WinBox.

Il punto che sfugge a molti: i pacchetti che attraversano il router non passano dalla chain input. Se vuoi impedire a un PC della LAN di raggiungere un sito, la regola va in forward. In input non la vedrà mai nessun pacchetto di quel PC diretto a internet.

Le regole si trovano in /ip firewall filter per IPv4 e in /ipv6 firewall filter per IPv6: due firewall separati, con le stesse tre chain. Puoi anche creare chain tue (basta scrivere un nome nuovo in chain=) e saltarci con action=jump; action=return lo riporta indietro.

In che ordine vengono lette le regole?

Dall’alto in basso, nell’ordine in cui le vedi con print. Il router confronta il pacchetto con la prima regola della chain; se non corrisponde passa alla seconda, e così via. Alla prima regola che corrisponde esegue l’azione e, se l’azione è terminale, smette di leggere quella chain.

Non conta quale regola hai scritto prima, conta dove sta. Una regola perfetta al posto sbagliato non serve a niente.

Quali azioni chiudono la partita e quali no?

Il manuale le divide così:

  • chiudono la chain: accept (il pacchetto passa, nessuna regola successiva lo vede), drop (scartato in silenzio), reject (scartato con una risposta ICMP, o un TCP reset con reject-with=tcp-reset), tarpit (tiene la connessione appesa);
  • proseguono alla regola successiva: log (scrive una riga nel log), passthrough (conta e basta), add-src-to-address-list e add-dst-to-address-list (annotano l’indirizzo in una lista);
  • spostano il pacchetto: jump lo manda in un’altra chain, return lo riporta a quella da cui è saltato.

Per questo il port knocking funziona: la regola che ti mette nella address list non apre niente, ti annota e lascia scendere il pacchetto fino al drop. Da fuori la porta sembra chiusa come le altre.

Cosa succede se nessuna regola corrisponde?

Il pacchetto viene accettato. La policy di default delle chain di RouterOS è accept, e non si cambia: se vuoi chiudere, la chiusura la scrivi tu, come ultima regola.

Ne segue che un router senza regole è un router aperto. Dopo un /system reset-configuration no-defaults=yes (reset didattico, vedi l’howto Hardening di base) il filter è vuoto e WinBox risponde a chiunque lo raggiunga.

Com’è fatto il firewall di fabbrica?

È un firewall “accetta quello che serve e scarta il resto” verso il router, e “lascia uscire, non lasciare entrare” verso la LAN. Su una routerboard con la configurazione di fabbrica trovi regole commentate defconf, in questo ordine (chain e commento):

input    defconf: accept established,related,untracked
input    defconf: drop invalid
input    defconf: accept ICMP
input    defconf: accept to local loopback (for CAPsMAN)
input    defconf: drop all not coming from LAN
forward  defconf: accept in ipsec policy
forward  defconf: accept out ipsec policy
forward  defconf: fasttrack
forward  defconf: accept established,related, untracked
forward  defconf: drop invalid
forward  defconf: drop all from WAN not DSTNATed

Lo schema è lo stesso nelle due chain: prima le risposte alle connessioni aperte, poi gli scarti sicuri e le eccezioni, infine il drop. Il CHR parte senza configurazione di fabbrica, quindi senza firewall.

La conseguenza pratica è una sola: ogni regola che aggiungi per il traffico da internet deve stare sopra drop all not coming from LAN. Sotto, quel pacchetto è già stato scartato.

Come metto una regola nel punto giusto?

Con place-before mentre la crei, oppure con move dopo. add mette la regola nuova in fondo alla lista, cioè sotto il drop: è l’errore più comune.

/ip firewall filter
add chain=input protocol=tcp dst-port=22 src-address=10.6.0.50 action=accept \
    comment="SSH dal PC del lab" \
    place-before=[find comment="defconf: drop all not coming from LAN"]

⚠️ Attenzione: 10.6.0.50 è il PC del mio laboratorio, sulla WAN 10.6.0.0/12 con gateway 10.0.0.1. Usa l’indirizzo della tua postazione; se hai dubbi sulla rete, controllala con l’IP calculator.

Per spostare una regola che c’è già, move prende la regola da spostare e quella davanti a cui metterla:

/ip firewall filter
move [find comment="SSH dal PC del lab"] [find comment="defconf: drop all not coming from LAN"]

Riferisciti alle regole con find e un commento, non con il numero. I numeri li assegna l’ultimo print della sessione: in un comando incollato, senza quel print, il numero può non esistere o indicare un’altra regola. In WinBox e WebFig l’ordine lo cambi trascinando la riga nella lista del Filter.

Cosa sono le regole con la D?

Sono regole dinamiche: le crea RouterOS da solo, non le hai scritte tu e non le salvi con la configurazione. Le vedi con la lettera D nei flag, mescolate alle tue nel print; con print where dynamic vedi solo quelle.

La più famosa è la prima riga del filter quando c’è una regola di fasttrack: special dummy rule to show fasttrack counters. Non filtra niente. Mostra quanti pacchetti stanno passando dalla corsia veloce del fasttrack, che salta il resto del firewall. Non la puoi spostare: un move … 0 finisce con cannot move builtin, come abbiamo visto nell’howto sul DoH. Invece add … place-before=0 funziona: in laboratorio la regola nuova è finita in cima e la dummy è scesa al secondo posto. E se togli la regola di fasttrack, la dummy resta lì fino al riavvio: non fa niente, non preoccuparti. Altre le aggiungono servizi come Kid Control.

Come capisco quale regola sta colpendo un pacchetto?

Dai contatori. Ogni regola conta i byte e i pacchetti che le corrispondono:

/ip firewall filter print stats
/ip firewall filter reset-counters-all

Il metodo è questo: azzeri i contatori, rifai la prova (il ping, la connessione WinBox, la pagina che non si apre), ristampi. La regola il cui contatore è salito è quella che ha deciso. Se sale il drop finale e non il tuo accept, il tuo accept è sotto, oppure non corrisponde a quello che pensi.

Perché si parte da established e related?

Perché la maggior parte dei pacchetti appartiene a connessioni già accettate, e conviene farli uscire dalla chain alla prima regola. Il connection tracking ricorda ogni connessione e dà a ogni pacchetto uno stato: new apre una connessione, established appartiene a una già vista, related è legato a una connessione esistente (un errore ICMP, i dati FTP), invalid non ha uno stato chiaro e va scartato, untracked ha saltato il tracking per una regola RAW.

Così le regole che decidono chi entra lavorano solo sui pacchetti new. Il registro delle connessioni merita una scheda a parte.

Quali sono gli errori tipici?

La regola aggiunta in fondo

Crei l’accept per la porta di gestione con un semplice add, la regola finisce sotto il drop finale, e il suo contatore resta a zero per sempre. Non è rotta: non la raggiunge nessuno. Il fix è un move o, meglio, il place-before fin dall’inizio.

L’accept troppo largo in cima

Un accept in-interface-list=LAN in forward, messo sopra tutto, fa passare anche quello che volevi bloccare più sotto: gli ospiti dell’hotspot verso il NAS, i PC verso i server DNS cifrati. Le regole di blocco specifiche vanno sopra quelle che accettano in modo generico.

Chiudersi fuori

Un drop in input scritto prima dell’accept per la tua postazione, e la sessione WinBox muore. Prima di toccare la chain input da remoto attiva il Safe Mode (pulsante Safe Mode in WinBox, Ctrl+X da terminale): se la connessione cade, il router annulla le modifiche da solo.

Per tutti i parametri delle regole c’è il manuale MikroTik: Filter.

Dove lo uso?

Provato in laboratorio su una routerboard con RouterOS 7.24.5 (stable): ordine delle regole defconf letto da /system default-configuration print; log, add-src-to-address-list e passthrough che proseguono (contatori); regola accept aggiunta sotto un drop che non serve a niente, poi spostata con move e find (la porta si apre); place-before; regola dummy del fasttrack con cannot move builtin e place-before=0; reset-counters-all.

Domande frequenti

Qual è la differenza tra la chain input e la chain forward?

La chain input vede i pacchetti destinati al router stesso, per esempio WinBox o SSH; la chain forward vede i pacchetti che attraversano il router, per esempio un PC della LAN che naviga.

Cosa fa RouterOS se nessuna regola del firewall corrisponde?

Accetta il pacchetto. La policy di default è accept: per chiudere una chain serve una regola drop esplicita in fondo.

Perché la mia regola accept non funziona?

Quasi sempre perché sta sotto una regola drop: le regole si leggono dall’alto in basso e la prima che corrisponde decide. Controlla con /ip firewall filter print stats quale contatore sale e sposta la regola con move o ricreala con place-before.

La regola log blocca il pacchetto?

No. log, passthrough e le azioni che aggiungono a una address list registrano o annotano e poi passano il pacchetto alla regola successiva. Chiudono la chain accept, drop, reject e tarpit.

Cos’è la regola dinamica in cima con i contatori del fasttrack?

È una regola finta che mostra quanto traffico passa dal fasttrack. Non filtra niente e non si può spostare.