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:
- Pacchetti originati dal firewall e diretti a qualcuno nel resto
del mondo
- Pacchetti originati da qualcuno nel resto del mondo e diretti al
firewall
- 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:
- OUTPUT -> POSTROUTING
- PREROUTING -> INPUT
- 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
- caso 1: Proteggere il nostro
firewall dal mondo esterno
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.
- caso 2: Proteggere il mondo
esterno dal nostro firewall
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.
- caso 3: Ridirigere una porta
su una macchina interna
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 ).
- caso 4: Ridirigere una porta
su una macchina nella stessa rete del chiamante
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:
- il client invia un SYN all'ip pubblico ottenuto via dns (non può
sapere che lo ha lì accanto sotto mentite spoglie)
- il SYN cerca di uscire dal firewall, che, a seconda di come
è configurato (ovvero se fa -correttamente IMHO- o no un check
sull'interfaccia da cui il SYN lo ha ricevuto) lo DNATta oppure no. Se
non lo DNATta, è chiaro che non funziona nulla, poichè a
rispondere a quell'indirizzo ip è il firewall stesso. Se lo
NATta, invia il pacchetto al webserver di destinazione.
- il webserver destinatario si vede arrivare 'sto benedetto SYN con
mittente una macchina interna. Risponde pertanto con un SYN/ACK
direttamente ad essa
- il client, che ha inviato il SYN a un ip pubblico, vede arrivare
il SYN/ACK da un ip privato. Dato che non ha mai contattato
quest'ultimo, cestina il SYN/ACK e continua ad aspettare risposta
dall'ip pubblico.
Le soluzioni sono almeno 3, in ordine di "correttezza":
- Spostate quella macchina in DMZ
- Usate un dns interno per risolvere i virtualhost con gli ip privati
- 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