0x0001
Perchè?

La prima cosa a cui tengo a precisare è la risposta alla domanda "Ma c'era proprio bisogno di questo documento con tutti i paper su iptables che ci sono in giro?".
In effetti, la risposta è, laconicamente, "No".
Ma poichè, sui newsgroup che frequento di più, continua ad esserci movimento per avere chiarimenti su determinate configurazioni di iptables, ho deciso di mettere il presente nero su bianco (anzi, il contrario), al fine di reindirizzare qui queste domande.
Prendetele un po' come delle FAQ non ufficiali, se volete.
Come avrete forse notato, sono l'unica parte di questo sito in lingua italiana, volutamente.
Sono tutt'altro che perfette e non affrontano iptables in profondità. Ma non sono fatte per questo, quanto per chiarire alcuni concetti nel modo più semplice possibile.
Per lo stesso motivo, viene evitata una buona parte della terminologia più tecnica.
Se avete consigli su come migliorarle, tuttavia, contattatemi.

0x0002
Teoria di base

Per capire il comportamento di iptables e il modo in cui le vostre regole dovranno essere costruite, è necessario per prima cosa capire quali sono le chain su cui dovrete agire e in quale ordine vengono attraversate. Evitiamo qui di prendere in considerazione attività di mangling e altro, ma ci limitiamo a parlare delle funzionalità di base, ovvero il filtering e il nat.
Quando parleremo di "firewall", ci riferiremo alla macchina stessa su cui stiamo configurando iptables.
Abbiamo 3 casi distinti da affrontare:
  1. Pacchetti originati dal firewall e diretti a qualcuno nel resto del mondo
  2. Pacchetti originati da qualcuno nel resto del mondo e diretti al firewall
  3. Pacchetti originati da qualcuno nel resto del mondo e diretti a qualcun altro, ma che si trovano a passare per il firewall
E' evidente che l'ultimo caso vale solo se stiamo gestendo del routing.

Rispettivamente, le chain di iptables attraversate saranno:
  1. OUTPUT -> POSTROUTING
  2. PREROUTING -> INPUT
  3. PREROUTING -> FORWARD -> POSTROUTING
Ognuna delle categorie citate prende in considerazione il traffico "origine" e non quello di risposta, che sarà ad esso inverso, ovvero l'inverso della 1 è la 2, l'inverso della 2 è la 1, l'inverso della 3 è sempre la 3 (anche se le interfacce di ingresso e uscita saranno ovviamente invertite).
Questo è di per sè ovvio, ma risulterà importante quando avrete a che fare con la macchina di state e con il NAT.

0x0003
Casi pratici

Data la natura poco didattica di questa pagina, non perderemo tempo a spiegare le funzioni di ogni singola possibilità offerta da iptables (questo è compito di altri papers meglio scritti, nonchè del man di iptables), ma inizieremo direttamente ad analizzare come usare le funzioni di base in casi pratici.
Verranno utilizzate le seguenti convenzioni:
$ext_dev è l'interfaccia esterna, non fidata, che va verso internet
$int_dev è l'interfaccia interna, fidata, che va alla rete interna

In questo esempio ipotizziamo di voler chiudere tutto sulla nostra macchina, lasciando la sola possibilità di accedere attraverso ssh (porta 22).
Palesemente, in questo caso non gestiamo in alcun modo la chain di FORWARD.
Per prima cosa porremo la policy della chain di INPUT a DROP, con
iptables -P INPUT DROP
poi accetteremo connessioni provenienti dall'esterno sulla porta 22
iptables -A INPUT -i $ext_dev -p tcp --dport 22 -j ACCEPT
Dato che non tocchiamo la chain di output, che resterà al valore predefinito (ACCEPT), non abbiamo necessità di specificare a questa di accettare il traffico di ritorno.
Se volessimo rendere disponibili altre porte, ci limiteremmo a replicare adeguatamente la seconda riga.
Si noti la necessità di esplicitare il protocollo: se non lo facessimo otterremmo un errore dovuto al fatto che il concetto di porta non è valido per tutti i protocolli, ma solamente per TCP e UDP.
Lo specifico solo perchè è errore comune.
Questo esempio è l'estensione del precedente. In questo caso abbiamo una macchina dedicata al ruolo di http proxy, con squid.
Vogliamo che la macchina sia raggiungibile sulla porta del proxy, e solo sulla rete interna. Inoltre vogliamo far sì che la macchina possa uscire solamente per le funzioni del proxy, potendo contattare solo le porte 80 e 443.
Per comodità faremo uso della macchina di state, concedendo l'accesso alle porte che dobbiamo tenere aperte specificando che lì accetteremo nuove "sessioni", e poi accettando il traffico conseguente a tali richieste in quanto già "stabilito".
Per prima cosa chiuderemo le chain di INPUT e OUTPUT.
iptables -P INPUT DROP
iptables -P OUTPUT DROP
Poi apriremo l'accesso alla porta di squid:
iptables -A INPUT -i $int_dev -p tcp --dport 3128 -m state --state NEW -j ACCEPT
Quindi consentiremo a squid di uscire a contattare chi deve:
iptables -A OUTPUT -o $ext_dev -p tcp --dport 80 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -o $ext_dev -p tcp --dport 443 -m state --state NEW -j ACCEPT
A questo punto abbiamo specificato quello che vogliamo accettare, ma rimane fuori tutto il traffico "di ritorno" generato da quanto finora specificato.
Lo accetteremo, semplicemente, con:
iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED -j ACCEPT
Si noti come non venga specificata alcuna relazione con alcun protocollo, porta o altro, ma solo il fatto di essere traffico "stabilito".
Queste regole consentono di passare solamente al traffico che sia già stato accettato come NEW.
Attenzione!!! Questa configurazione è assolutamente teorica e poco sensata: il proxy non sarebbe in grado di risolvere i nomi di dominio da contattare, poichè non abbiamo scritto nulla che consenta al firewall di contattare un dns. Tenetene conto.

Qui abbiamo un firewall già configurato in qualche maniera (il come non ci interessa), e vogliamo far sì che sulla porta 80 dell'interfaccia pubblica (esterna) risponda in realtà un pc della rete interna, che definiremo $web_server.
NB: questa è una configurazione che pone seri problemi di sicurezza. Questo è un esempio, non un consiglio. Se lo fate e vi bucano la rete interna sono fatti vostri. Children, don't do this at home!!! ( Ho messo abbastanza avvertimenti? )
Il traffico che ci interessa è traffico che normalmente impatterebbe nella chain di INPUT.
Dato che è nostra intenzione girarlo ad una macchina interna, dovremo cambiare la destinazione del pacchetto tramite una regola di NAT.
Dato che poi dovremo farlo prima che il pacchetto arrivi alla chain di INPUT, ovviamente lo faremo in PREROUTING:
iptables -A PREROUTING -t nat -i $ext_dev -p tcp --dport 80 -j DNAT --to-destination $web_server
Dopo aver attraversato la chain di PREROUTING, quindi il pacchetto non ha più per destinazione il firewall, ma una macchina interna. Questo ha due implicazioni.
Per prima cosa, non andrà più ad attraversare la chain di INPUT, ma quella di FORWARD.
Per seconda cosa, non andrà da nessuna parte se non abiliteremo il forward tra le interfacce del firewall. Senza scendere nei particolari, si fa con un
echo "1" > /proc/sys/net/ipv4/ip_forward
Pertanto, consentiremo il transito di nuove sessioni indirizzate a $web_server provenienti dall'esterno e il relativo traffico di risposta:
iptables -A FORWARD -i $ext_dev -d $web_server -p tcp --dport 80 -m state --state NEW -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED -j ACCEPT
Una domanda che spesso affligge chi si pone di fronte ad iptables per la prima volta è: "c'è bisogno di specificare una regola che natti anche il traffico di ritorno?"
La risposta è "no, ci pensa netfilter a tracciare il tutto". Ovviamente sono esclusi casi di protocolli particolari che facciano uso di più sessioni su porte diverse, come ad esempio ftp (una risorsa che consiglio per capire ftp è questa ).

Per quanto questa configurazione sia in sè abbastanza assurda, pare lì fuori sia pieno di gente che la vuole.
Immaginiamo questo caso: abbiamo un webserver che ospita dei virtualhost, e, poichè ci vogliamo del male, lo abbiamo messo nella nostra LAN anzichè in DMZ.
Che accade? Che nel momento in cui cercate di raggiungere uno dei siti ivi ospitati, e interrogate un dns pubblico, questi risponde con l'ip pubblico del vostro webserver.
Al che il vostro client, ringalluzzito, cerca di contattarlo ma non ce la fa. Perchè? Semplice, se pensate a quello che sta accadendo:
Le soluzioni sono almeno 3, in ordine di "correttezza":
  1. Spostate quella macchina in DMZ
  2. Usate un dns interno per risolvere i virtualhost con gli ip privati
  3. Barbatruccate il firewall
Anche se è la via meno corretta, qui esamineremo come applicare la 3 (d'altra parte parliamo di iptables...).
Il problema è dato dal fatto che il webserver risponde direttamente al client senza passare dal firewall. La soluzione è obbligarlo a passare dal firewall.
Pertanto, per prima cosa applichiamo la regola di DNAT come al solito:
iptables -A PREROUTING -t nat -d $web_ext -p tcp --dport 80 -j DNAT --to-destination $web_int
A questo punto, provvediamo a far sì che quelle connessioni che ivi giungono proveniendo dall'interno vengano SNATtate per sembrare provenienti dal firewall:
iptables -A POSTROUTING -t nat -s $int_net -d $web_int -p tcp --dport 80 -j SNAT --to-source $fw
In questo modo la macchina interna risponderà sempre al firewall, permettendo così a netfilter di "correggere" la sessione di ritorno.
Ovviamente, ciò implica che vi scordate il logging degli ip interni, ma sono solo fatti vostri...

Attenzione ad un particolare: il pacchetti (sia della sessione di andata che di ritorno) saranno pacchetti in ingresso sulla interfaccia interna del router che verranno forwardati attraverso la stessa interfaccia interna.
Affinchè a questi sia pertanto concesso il transito, la chain di FORWARD deve presentare una abilitazione (implicita od esplicita) di questo tipo:
iptables -A FORWARD -i $int_dev -o $int_dev -j ACCEPT
Sta a voi, poi, scegliere se limitare la stessa ai protocolli e alle macchine che realmente dovranno fare uso di tali regole o no...


...continua

back to home