Introduzione
Se registrassimo tutto il traffico che arriva o attraversa la nostra connessione ad internet rimarremmo stupiti dalla incredibile quantità di "contatti" che si realizza. La rete è letteralmente spazzata da flussi di pacchetti IP. Molti sono dovuti a nostre attività coscienti, ma la maggior parte è riferita ad attività che ci sono ignote: pacchetti ICMP, richieste di connessione per servizi che non abbiamo, o che non sappiamo che sono in funzione, port scanning, nostre applicazioni che colloquiano con l'esterno, ecc.
Qualunque computer collegato ad Internet dovrebbe essere protetto da intrusioni esterne.
Per fare ciò si usano i cosiddetti "firewall".
Un firewall non è altro che un filtro posto su una connessione di rete e che discrimina ciò che può passare e ciò che non deve passare.
Una soluzione sono i firewall hardware, cioè macchine dedicate a questa funzione, magari abbinata a quella di router ADSL. Ma non sempre questa soluzione è praticabile, vuoi per i costi, vuoi perchè se non sono di alta qualità hanno configurazioni piuttosto rigide che potrebbero non esserci sufficienti.
L'altra soluzione consiste nell'usare come firewall il computer connesso ad internet. Uno schema piuttosto usuale può essere il seguente:
Dove "PC 1", "PC 2", ecc. sono altri computer collegati ad una rete interna e che si connettono ad Internet tramite il primo. Questo schema ricorre spesso nelle configurazioni casalinghe o in quelle di piccoli uffici forniti di connessione ADSL con IP dinamico.
Se almeno il computer connesso al modem ha un sistema operativo Linux è possibile configurare un potente firewall , NetFilter-IPtables.
In questo articolo vedremo, per linee generali, il funzionamento di NetFilter-IPtables, e un esempio di uso pratico.
Caratteristiche
Kernel space - User space
Mentre altri sistemi operativi, come ad esempio Windows, usano per le funzioni di firewall software che lavora esclusivamente a livello utente, alla pari di ogni altra applicazione, Linux divide le funzioni di configurazione che sono svolte a livello utente, tramite l'applicativo "IPtables", dalle funzioni di packet filtering che sono svolte dal kernel stesso (ovvero dal sistema operativo direttamente), tramite il networking layer "NetFilter".
Questa scelta consente a Linux di beneficiare di prestazioni ottimali, alla pari di un firewall hardware, e di una grande flessibilità. Non è un caso che molti apparati dedicati usino distribuzioni Linux appositamente assemblate.
Firewall statefull e stateless
Oltre a ciò NetFilter-IPtables implementano un firewall "statefull", ovvero che è in grado di tenere traccia di una connessione, e della "storia" di una serie di pacchetti; mentre i firewall "stateless" considerano ogni pacchetto come a se stante e quindi diviene problematico impostare delle regole di filtraggio "intelligenti".
Installazione
Come abbiamo detto il sistema NetFilter-IPtables ha due componenti: una parte che fa parte del kernel, ed una costituita dagli applicativi della famiglia "iptables".
Per quanto riguarda la parte kernel, in genere tutte le distribuzioni escono con kernel compilati con i moduli necessari per il funzionamento di NetFilter-IPtables. Nel caso così non fosse o vogliamo usare un kernel ricompilato dovremo impostare le giuste opzioni. Per cui dopo avere decompresso i sorgenti ed essere entrati nella directory "linux-<versione>" digitiamo:
# make menuconfig
o se preferiamo un interfaccia grafica:
# make xconfig
oppure
# make gconfig
impostiamo tutte le opzioni necessarie al nostro sistema, o carichiamo il file di configurazione della nostra distribuzione e poi andiamo navighiamo nei menu:
Device Drivers -> Networking support -> Networking option ->
Network Packet Filtering -> IP: Netfilter Configuration
arriveremo ad avere una schermata con queste opzioni:
selezionamole tutte come moduli (<M>), laddove possibile, altrimenti inseriamole direttamente nel kernel ([*]). Fatto ciò procediamo con la compilazione e l'istallazione del nuovo kernel e dei moduli.
Per quanto riguarda "iptables", basterà scaricare ed istallare il pacchetto per la nostra distribuzione, oppure andare su http://www.iptables.org scaricare il tarball, scompattarlo, e dopo essere entrati nella directory digitare:
# make KERNEL_DIR=<directory dove stanno i sorgenti del kernel>
# make install KERNEL_DIR=<directory dove stanno i sorgenti del kernel>
Verranno istallati, oltre ad una serie di librerie, tre eseguibili:
iptables
L'eseguibile principale che presiede alla configurazione delle regole di filtraggio. Può essere usato direttamente con questa sintassi:
# /sbin/iptables <regola> <azione>
ma di fatto viene sempre usato tramite script bash che implementano tutte le regole in modo ordinato e facilmente manutenibile.
iptables-save
Una volta configurato correttamente il firewall, consente di salvare le regole scelte in un file di testo particolare, adatto per essere letto dalla utility "iptables-restore". Si usa con questa sintassi:
# /sbin/iptables-save > /etc/<file di salvataggio delle regole>
In genere viene usato direttamente da linea di comando quando, come
detto, abbiamo trovato delle regole che ci soddisfano.
iptables-restore
Viene usato per ripristinare le regole conservate
nell'apposito file. In genere viene inserito negli script di init
o di startup, per ripristinare le regole dopo un riavvio, ad esempio:
# /sbin/iptables-restore < /etc/<file di salvataggio delle regole>
Struttura
Iptables, a differenza del suo predecessore, Ipchains, basa la sua struttura su tre tabelle:
filter
Si tratta della tabella che contiene le regole di filtraggio,
cioè di decisione sul passaggio o meno di un pacchetto. Ha tre catene
(chains) predefinite:
INPUT
Tramite le regole di questa catena viene decisa l'autorizzazione
o meno all'accesso nel sistema in cui è istallato il firewall
dei pacchetti provenienti dall'esterno, cioè da internet o dalla stessa
LAN.
OUTPUT
Tramite le regole di questa catena viene consentita o meno
l'uscita dal sistema in cui è istallato il firewall dei pacchetti
prodotti da esso stesso.
FORWARD
Questa catena si occupa dei pacchetti in transito attraverso
il sistema in cui è istallato il firewall, ad esempio da internet
alla LAN e viceversa.
nat
Questa tabella (Network Address Traslation) è fondamentale in
tutti i casi in cui sia necessario modificare gli indirizzi dei pacchetti.
In pratica Netfilter può modificare l'indirizzo IP sorgente o di destinazione
dei pacchetti, mantenendo la memoria di questa operazione, per scopi
che vedremo in seguito. Ha due catene:
PREROUTING
qui vengono processati i pacchetti appena prima di entrare nella rete, e si può modificare l'indirizzo di destinazione.
POSTROUTING
qui vengono processati i pacchetti appena prima che lascino la rete in uscita e viene modificato l'indirizzo sorgente.
OUTPUT
catena con funzioni simili al postrouting, ma utilizzata sui pacchetti che nascono all'interno del sistema in cui è istallato il firewall.
mangle
Questa tabella è particolare, in quanto serve a effettuare delle modifiche molto specializzate ai pacchetti. Non verrà trattata in questo articolo in quanto il suo uso fuorisce dagli obiettivi dello stesso.
Sintassi di base
iptables [-t <tabella>] -<Comando> <catena> <regole> [<opzioni>] -j <target>
[-t tabella]
Tramite il flag -t si indica la tabella alla quale ci stiamo riferendo,
se viene omesso ci si riferisce a "filter". Possibili valori:
- filter
- nat
- mangle
-Comando
I comandi possibili sono:
-A catena regola
inserisci la regola che segue in coda alle altre
nella catena indicata.
-D catena x
cancella la regola numero "x" della catena indicata.
-I catena x
inserisci la regola alla posizione "x" della
catena indicata.
-R catena x nuova-regola
sostituisci la regola posta alla posizione
"x" con quella nuova.
-L catena
mostra le regole settate per la catena indicata, se è
omessa le mostra tutte.
-F catena
cancella tutte le regole per la catena indicata, se è
omessa cancella le regole di tutte le catene della tabella indicata.
-Z catena
azzera i contatori della catena indicata.
-N catena
crea la catena indicata. Serve per creare catene personalizzate.
-X catena
cancella la catena indicata. Si applica solo alle catene
create dall'utente.
-P catena target
setta la "policy", cioè la scelta di default,
della catena indicata. Questa scelta si applicherà a tutti i pacchetti
che siano sfuggiti a tutte le regole precedenti nella catena. Il significato
di "target" è spiegato dopo. I target possibili sono:
ACCEPT
i pacchetti che non corrispondono ad alcuna regola vengono
accettati.
DROP
i pacchetti che non corrispondono ad alcuna regola vengono
scartati senza risposta.
catena
Va indicata una delle catene elencate nel paragrafo "struttura".
La catena indicata deve essere coerente con la tabella scelta.
-j target
Tramite il flag -j viene decisa la sorta del pacchetto che corrisponde
alla regola. Possibili valori sono:
ACCEPT
i pacchetti che corrispondono alla regola vengono accettati.
DROP
i pacchetti che corrispondono alla regola vengono distrutti
senza risposta.
RETURN
i pacchetti che corrispondono alla regola, se ci si trova
in una catena creata dall'utente, vengono rimandati alla catena chiamante,
se ci si trova in una catena di sistema (input, output, ecc.) il pacchetto
segue la sorte indicata dalla policy di default.
QUEUE
i pacchetti che corrispondono alla regola vengono inviati
in "user space", cioè a qualche applicazione in attesa, altrimenti
vengono scartati. Per usufruire di questa possibilità il kernel deve
essere predisposto.
LOG
le intestazioni del pacchetto che corrisponde alla regola vengono
inserite in un file di log. In genere in /var/log/kern.log
Oltre a questi target di base, sempre utilizzabili, ve ne sono altri
per usi particolari. Alcuni li vedremo in seguito.
In questo articolo vedremo le regole e le opzioni necessarie per filtrare il traffico di rete.
Per chiarezza riportiamo la sintassi di base:
iptables [-t <tabella>] -<Comando> <catena> <regole> [<opzioni>] -j <target>
In pratica le "regole" ci dicono quando il pacchetto viene riconosciuto e deve subire la sorte stabilita con -j. Quindi si tratta di espressioni che ci consentono di discriminare tra un pacchetto ed un altro. Facciamo subito un esempio. Dopo approfondiremo il significato delle varie "regole".
Con:
iptables -A INPUT -p ALL -s 127.0.0.1 -i eth0 -j DROP
stiamo indicando la seguente configurazione:
iptables
Caro iptables configurami un filtro con regola come segue...
[-t filter]
Avendo omesso l'indicazione della tabella ci stiamo
riferendo a "filter".
-A INPUT
considera i pacchetti in ingresso.
... inizio regole ...
-p ALL
di qualunque protocollo: TCP, UDP, ICMP.
-s 127.0.0.1
che hanno indirizzo sorgente 127.0.0.1.
-i eth0
che si presentano in ingresso sulla prima interfaccia di
rete ethernet.
... fine regole ...
-j DROP
distruggili senza esitazione.
Una regola come quella appena vista serve per scartare i pacchetti in ingresso su una interfaccia che è esterna (eth0), ma che hanno indirizzo sorgente interno (127.0.0.1), sintomo evidente di maldestro spoofing (attacco portato tramite l'alterazione dell'indirizzo sorgente di un pacchetto).
Ora che è più chiaro di cosa stiamo parlando vediamo i principali
flag utilizzati per impostare delle regole.
Flag
Per prima cosa diciamo che è possibile quasi sempre invertire il significato
di un flag tramite il segno "!", quindi, riprendendo
l'esempio di prima, se avessimo scritto:
... -s ! 127.0.0.1 ...
avrebbe significato che la regola si applicava a qualunque indirizzo
sorgente diverso da 127.0.0.1.
-p protocollo
serve ad indicare a quale protocollo ci si riferisce.
Se non viene settato o si setta -p ALL ci riferiamo a qualuque
protocollo. I protocolli riconosciuti sono TCP, UDP e ICMP. Questo
flag ha una natura molto simile a -m, che vedremo in seguito,
in quanto carica dei moduli ulteriori.
-s indirizzo sorgente[/netmask]
indica l'indirizzo sorgente
a cui ci si riferisce, se è settata anche la netmask il riferimento
varrà per qualunque indirizzo del segmento di rete indicato. Ad esempio
10.0.0.0/255.255.255.0 indicherà gli indirizzi da 10.0.0.1 a 10.0.0.255.
È possibile usare per definire il segmento di rete interessato anche
la notazione numerica semplice, per cui /255.255.255.0 equivarrà a
/24. Infine per indicare l'indirizzo sorgente è possibile usare anche
un hostname, ma ciò ha un senso solo se la risoluzione di tale
hostname avviene in locale tramite file /etc/hosts, altrimenti se
IPtables si deve rivolgere per ogni pacchetto a un server DNS, avremo
un drammatico decadimento delle prestazioni, oltre ad introdurre problemi
di sicurezza, stante la debolezza del protocollo DNS. Se questo flag
non è settato o è settato a -s 0/0 vuol dire che ci riferiamo
a qualunque indirizzo sorgente.
-d indirizzo destinazione[/netmask]
indica l'indirizzo di
destinazione a cui ci si riferisce. Per il resto valgono le stesse
considerazione fatte per -s.
-i nome interfaccia
viene indicata l'interfaccia di rete di ingresso
a cui si riferisce la regola, ad esempio: eth0 (prima scheda
di rete), ppp0 (prima connessione modem), ecc. Si può usare solo
in relazione alle seguenti catene: INPUT, FORWARD, PREROUTING.
-o nome interfaccia
viene indicata l'interfaccia di rete di uscita
a cui si riferisce la regola, ad esempio: eth0 (prima scheda
di rete), ppp0 (prima connessione modem), ecc. Si può usare solo
in relazione alle seguenti catene: OUTPUT, FORWARD, POSTROUTING.
-f
consente di riferirsi ai pacchetti successivi al primo, in caso
di pacchetti frammentati. La frammentazione dei pacchetti si verifica
quando un blocco di dati da inviare eccede il MTU (Maximum Trasfert
Unit = massima dimensione di un singolo pacchetto inviabile) di un
qualunque segmento di rete attraversato.
-m nome modulo
consente il caricamento di moduli ulteriori per
compiti particolari e sofisticati. Quasi tutti i moduli disponibili
hanno propri flag di configurazione. Nel prossimo paragrafo li analizzeremo.
Moduli
Ricordo che i moduli si caricano tramite la sintassi:
iptables ... -m <nome modulo> -<opzioni modulo> ...
Per conoscere le opzioni disponibili per un modulo basta digitare:
iptables -m <nome modulo> -h
Verranno stampate le opzioni principali di IPtables ed in fondo quelle
del modulo.
Vediamo ora i principali:
tcp
scrivere "-m tcp" equivale a "-p tcp". A parte ciò,
questo modulo dice a IPtables che stiamo trattando il protocollo TCP.
Consente l'uso delle seguenti opzioni:
-sport porta[:porta]
si può impostare la porta, o l'intervallo
di porte sorgenti, ad esempio "-sport 80" oppure "-sport
1:1024", se non viene settato significa che intendiamo "qualunque
porta sorgente".
-dport porta[:porta]
si può impostare la porta, o l'intervallo
di porte di destinazione, ad esempio "-dport 80" oppure
"-dport 1:1024", se non viene settato significa che
intendiamo "qualunque porta di destinazione".
-tcp-flags flag_da_esaminare flag_settati
tramite questa opzione
si passa come primo argomento una lista, separata da virgole, dei
flags che devono essere esaminati, tramite il secondo la lista, separata
da virgole, dei flag che devono essere settati come attivi. Ad esempio
se io scrivo:
iptables -A INPUT -p tcp -tcp-flags SYN,ACK,FIN,RST SYN -j ACCEPT
la regola accetterà i pacchetti TCP aventi flag SYN attivo, e i flag
ACK, FIN, RST non attivi.
-syn
verranno riconosciuti i pacchetti TCP aventi flag SYN attivo
e flags ACK e FIN non attivi.
udp
scrivere "-m udp" equivale a "-p udp". A parte ciò,
questo modulo dice a IPtables che stiamo trattando il protocollo UDP.
Consente l'uso delle seguenti opzioni:
-sport porta[:porta]
per l'uso di questi flag vedi il modulo
tcp.
-dport porta[:porta]
per l'uso di questi flag vedi il modulo
tcp.
icmp
anche in questo caso crivere "-m icmp" equivale a "-p
icmp". A parte ciò, questo modulo dice a IPtables che stiamo trattando
il protocollo ICMP. Consente l'uso della seguente opzione:
-icmp-type nome o numero tipo
in questo modo si possono indicare
esattamente i tipi di pacchetto icmp interessati dalla regola. I tipi
si possono indicare o con un nome esteso, ricavabile dalla lista prodotta
dal comando:
iptables -m icmp -h
oppure tramite il codice numerico type/code ricavabile dalla
seguente tabella:
quindi, ad esempio, se vogliamo che la regola riguardardi i pacchetti
icmp echo request, scriveremo:
-m icmp -icmp-type echo-request
oppure
-m icmp -icmp-type 8/0
mac
tramite questo flag è possibile indicare l'interfaccia di rete
di input tramite il suo indirizzo hardware (mac address), invece di
utilizzare l'indirizzo IP o il nome dell'host. Può essere usato solo
con le catene INPUT FORWARD e PREROUTING. Accetta la seguente opzione:
-mac-source indirizzo hardware
gli indirizzi hardware (mac address)
si esprimono tramite 6 cifre esadecimali di 8 bit separati da ":",
cioè: XX:XX:XX:XX:XX:XX, tale indirizzo è ricavabile sui
sistemi UNIX tramite il comando ifconfig, ad esempio:
[shishii@marco iptables]$ /sbin/ifconfig
eth0 Link encap:Ethernet HWaddr 00:04:76:9B:89:21
L'uso dell'indirizzo hardware aumenta notevolmente la sicurezza, in
quanto è molto meno soggetto alle tecniche di spoofing (falsificazione
dell'indirizzo IP sorgente).
limit
tramite questo flag è possibile impostare dei limiti al numero
di applicazioni della regola in cui è inserito. È molto usato in
combinazione con il target -j LOG per evitare la crescita
incontrollata dei files di log. Accetta le seguenti opzioni:
-limit
Questa opzione permette di specificare il numero confronti
che devono essere effettuati in certo periodo di tempo. È possibile
specificare il numero di confronti (x) da effettuare per secondo 'x/s',
per minuto '/m', per ora '/h', per giorno '/d'.
-limit-burst
Questa opzione permette di specificare il numero di
pacchetti che devono essere verificati la prima volta, e quanti ne
devono essere recuperati se ad ogni scadenza non sono pervenuti dei
nuovi. Quindi se specifichiamo un limite di 1 pacchetto al minuto
con burst di 5 la prima volta saranno verificati 5 pacchetti, poi
uno solo ogni minuto. Inoltre per ogni minuto che non si ricevono
pacchetti ne sarà recuperato uno dal burst. Questa regola si scrive:
-m limit -limit 1/m -limit-burst 5
state
questo flag consente di discriminare lo "stato" di un
pacchetto. Qui si evidenzia la differenza fatta, nella prima parte
di questo articolo, tra firewall "stateless" e firewall
"statefull". Solo in riferimento a questi ultimi ha senso
il concetto di "stato" di un pacchetto. In altre parole, grazie
al mantenimento di una cache, e ad una elaborazione "intelligente"
dei dati in possesso, IPtables è in grado di capire, ad esempio, se
un pacchetto appartiene ad una connessione preesistente. L'unica opzione
accettata consente di selezionare gli "stati" che ci interessano:
-state stato
gli stati selezionabili sono:
- NEW se il pacchetto crea una nuova connessione.
- ESTABILISHED se il pacchetto appartiene ad una connessione preesistente.
- RELATED se il pacchetto è correlato, ma non è parte di una
connessione preesistente, ad esempio un ICMP che segnala un errore di connessione. - INVALID se non è stato possibile identificare un pacchetto.
È possibile selezionare più stati separati da una virgola, ad esempio:
-m state -state ESTABILISHED,RELATED
length
questo flag consente di verificare la lunghezza in byte di
un pacchetto. Sintassi:
-m length -length x[:y]
se si setta solo (x) la lunghezza verificata sarà fissa, se si setta
solo (x:) il range andrà dal valore x all'infinito, se si setta (x:y)
il range sarà quello compreso tra i due valori.
Target estesi
Come detto nella prima parte dell'articolo i target più comuni sono:
ACCEPT, DROP, RETURN, QUEUE, LOG, ora approfondiremo le estensioni
di LOG ed altri possibili target di uso più particolare.
-j LOG
Come detto questo target consente di "loggare" i pacchetti che
corrispondono alla regola, inoltre è bene notare che l'esame non finisce
con questo target, ma prosegue alle regole successive. Accetta varie
opzioni, le più usate sono:
-log-level valore
consente di impostare il livello di dettaglio
dei log, in accordo con quanto previsto dal servizio di logging di
sistema "syslogd". Vedere anche la pagina "man
syslog.conf". I valori si possono esprimere tramite un numero
da 0 a 7 o con un nome: debug, info, notice, warning, err, crit,
alert, emerg.
-log-prefix stringa
consente di impostare una stringa che funga
da banner per l'inserimento dei dati nei log in modo da riconoscerli
più facilmente, ad esempio se io setto:
-j LOG -log-level NOTICE -log-prefix "Prima regola "
otterrò dei log di questo tipo:
Apr 9 17:55:33 cobalt kernel: Prima regola IN=eth0
OUT= MAC=00:10:e0:00:f5:60:00:30:0a:0b:5a:d2:08:00
...
-j SNAT
Questo target è utilizzabile solo nella tabella NAT e nella catena
POSTROUTING e serve ad alterare l'indirizzo sorgente di un pacchetto
in uscita. Si usa, ad esempio, quando un host della rete interna,
dotato di IP non pubblico, deve connettersi ad un host su internet.
In tal caso il firewall cambierà l'IP interno, con quello pubblico
assegnato dal provider. Si usa in caso di possesso di IP pubblico
fisso, altrimenti si dovrà usare il target MASQUERADE che vedremo
dopo. Si usa tramite la seguente opzione:
-to-source indirizzo-IP[:port]
questa opzione indica quale indirizzo IP e numero di porta sorgente deve risultare nel pacchetto
in uscita.
-j DNAT
Questo target è utilizzabile solo nella tabella NAT e nelle catene
PREROUTING e OUTPUT, serve ad alterare l'indirizzo di destinazione
di un pacchetto in entrata. Si usa, ad esempio, per implementare un
servizio di proxy trasparente, cioè di cui la rete interna non si
rende conto. Si usa tramite la seguente opzione:
-to-destination indirizzo-IP[:port]
questa opzione indica quale indirizzo IP e numero di porta di destinazione deve risultare nel pacchetto in uscita.
-j MASQUERADE
Questo target è utilizzabile solo nella tabella NAT e nelle catena POSTROUTING ed è necessario quando ci si vuole collegare dall'interno di una LAN verso Internet e si dispone di una connessione senza IP fisso, tipo dial-up, che è il caso della maggior parte degli utenti. Questo target sostitusce l'indirizzo IP pubblico della connessione, qualunque esso sia, all'indirizzo sorgente dei pacchetti che provengono dall'interno della LAN e che non sarebbero validi su internet.
Configurazioni "on the fly" del kernel
Linux consente di modificate "on the fly", cioè senza riavvio, alcuni parametri del kernel. Ciò è possibile tramite il filesystem virtuale "proc". Questa caratteristica ci viene in aiuto per migliorare le prestazioni del firewall e la sua sicurezza.
Prestazioni
In genere su piattaforma Intel il sistema alloca di default un buffer per la scheda di rete di 64K. Questo valore è ottimale per gli usi ordinari, ma potrebbe essere insufficiente se si deve gestire un firewall, per cui è il caso di aumentarlo.
Per sapere le dimensioni del buffer realmente allocate digitate:
cat /proc/sys/net/core/rmem_default
cat /proc/sys/net/core/wmem_default
cat /proc/sys/net/core/rmem_max
cat /proc/sys/net/core/wmem_max
Viene consigliato da alcuni esperti di portare i valori di questi
buffer a 256K in caso di rete a 10Mbit, a 512K in caso di rete più
veloce, per cui basterà digitare:
echo 524288 > /proc/sys/net/core/rmem_default
echo 524288 > /proc/sys/net/core/wmem_default
echo 524288 > /proc/sys/net/core/rmem_max
echo 524288 > /proc/sys/net/core/wmem_max
Sicurezza
Alcuni impostazioni di default del kernel Linux lasciano spazio a possibili
attacchi. Ovviamente ciò non avviene perchè i responsabili dello sviluppo
del kernel ignorano tali problemi, ma perchè alcuni servizi potrebbero
non funzionare con opzioni più restrittive. Dato però l'assunto di
partenza, cioè la gestione di una piccola rete, non avremo questi
problemi e potremo proteggere maggiormente il firewall. Seguono alcune
proposte:
Per non risponde ai ping inviati all'indirizzo broadcast della rete:
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
Per non accettare pacchetti ICMP di route redirection:
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
Per attivare una protezione contro attacchi spoofing:
echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
Per loggare in /var/log/messages i pacchetti malformati e scartarli
automaticamente
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
Con ciò abbiamo concluso questa seconda parte. Nella prossima vedremo due esempi concreti di configurazione di un firewall.
Come preannunciato nei precedenti articoli, in questa ultima parte vedremo due esempio pratici per applicare subito sul nostro Linux le nozioni apprese.
Il primo esempio è calibrato sullo schema più semplice che ci sia, cioè un singolo computer collegato ad internet tramite connessione dial-up o ADSL, che non fornisce servizi all'esterno, ma che ha attivi alcuni servizi server (apache, mysql, ecc.) per studio o uso interno.
Il secondo esempio prende in considerazione un caso più complicato, e cioè la protezione di una piccola rete, il cui schema è quello indicato dalla figura 1 nella prima parte di questo articolo.
Il modo migliore per effettuare la configurazione di IPtables è creare degli script "bash" (cioè scritti nel linguaggio proprio della shell più diffusa) con i comandi necessari, i vantaggi sono che se può creare più di uno per svariate situazioni, e che per riconfigurare IPtables basterà eseguirli.
La politica generale che sarà seguita è quella della prudenza, per cui si inizierà chiudendo tutto il traffico in entrata e in uscita e poi aprendo ciò che ci serve. Questo potrà dare luogo a qualche problema con qualche servizio o applicazione, ma sarà sufficiente, in caso si sospetti che ciò derivi da IPtables, disattivare il firewall momentaneamente per fare le verifiche necessarie.
I numeri di riga servono solo da riferimento e non devono essere copiati in un eventuale script.
Ad ogni modo, a scopo prudenziale, inseriamo qui sotto uno script che una volta lanciato annulla qualunque impostazionio a IPtables, per evitare che commettendo un errore vi troviate con il networking del computer bloccato, il significato delle istruzioni vi sarà chiaro alla fine dell'articolo:
#!/bin/bash
# script per reimpostare IPtables
IPT="/sbin/iptables"
$IPT -F
$IPT -t nat -F
$IPT -t mangle -F
$IPT -X
$IPT -t nat -X
$IPT -t mangle -X
$IPT -P INPUT ACCEPT
$IPT -P FORWARD ACCEPT
$IPT -P OUTPUT ACCEPT
$IPT -t nat -P PREROUTING ACCEPT
$IPT -t nat -P POSTROUTING ACCEPT
$IPT -t nat -P OUTPUT ACCEPT
$IPT -t mangle -P PREROUTING ACCEPT
$IPT -t mangle -P OUTPUT ACCEPT
echo "Cancellate tutte le regole IPtables"
Primo esempio
1 #!/bin/bash
la prima riga, detta "shebang", è necessaria per l'esecuzione
dello script, indica il path dell'inteprete bash.
Impostiamo ora alcune variabili:
2 IPT="/sbin/iptables"
Path dell'eseguibile IPtables
3 IF="ppp0"
la riga 3 indica il nome dell'interfaccia di rete che ci collega ad
internet, è individuabile tramite l'utility "ifconfig"
4 LO="127.0.0.1"
la riga 4 indica l'indirizzo di loopack, cioè interno alla stessa
macchina su cui si sta operando. È sempre questo (127.0.0.1) per
convenzione internazionale su qualunque sistema, persino... Windows!
5 /sbin/modprobe <nome modulo>
Quando si istalla IPtables in genere vengono anche aggiornati i files
di configurazione che sono preposti al caricamento dei moduli del
kernel necessari per il suo funzionamento. Può tuttavia accadere che
alcuni non vengano caricati, per ovviare a ciò è possibile procedere
inserendo nello script il comando "/sbin/modprobe <nome
modulo>". Segue la lista di moduli necessaria per lo script che
stiamo trattando:
- [ip_tables]
- [iptable_filter]
- [iptable_nat]
- [iptable_mangle]
- [ip_conntrack]
- [ipt_state]
- [ipt_limit]
6 echo 524288 > /proc/sys/net/core/rmem_default
7 echo 524288 > /proc/sys/net/core/rmem_max
8 echo 524288 > /proc/sys/net/core/wmem_default
9 echo 524288 > /proc/sys/net/core/wmem_max
10 echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
11 echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
12 echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
13 echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
14 echo 1 > /proc/sys/net/ipv4/tcp_syncookies
15 echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
16 echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
Nella seconda parte di questo articolo è stata illustrata la possibilità
di effettuare alcuni impostazioni al volo del kernel per migliorare prestazioni
e sicurezza, con le righe da 9 a 16 applichiamo quanto spiegato.
17 echo 0 > /proc/sys/net/ipv4/ip_forward
disabilitiamo il forwarding dei pacchetti (cioè l'indirizzamento di
pacchetti provenienti dall'esterno, ad altre macchine) in quanto nel
nostro esempio non ci serve.
18 $IPT -t filter -F
19 $IPT -t mangle -F
20 $IPT -t nat -F
21 $IPT -t filter -X
22 $IPT -t nat -X
23 $IPT -t mangle -X
per evitare problemi è sempre bene azzerare tutti i impostazioni di IPtables
precedenti, comunque fossero stati effettuati. le righe 18-20 svuotano
le tre tabelle e le righe 20-22 le cancellano.
24 $IPT -P INPUT DROP
25 $IPT -P FORWARD DROP
26 $IPT -P OUTPUT DROP
le righe 24-26 sono assolutamente decisive. Infatti stiamo fissando
il destino di tutti i pacchetti che NON corrispondono ad
alcuna regola. In questo caso la regola settata è di scartare qualunque
pacchetto che non decidiamo di accettare esplicitamente.
Può sembrare un atteggiamento un pò eccessivo, ed in effetti all'inizio
può creare qualche difficoltà, in quanto qualche applicazione che
ci interessa potrebbe smettere di funzionare. Ma tutto ciò ha due
grossi vantaggi: primo, acquisiamo una sicurezza molto maggiore, in
quanto non può succedere che ci dimentichiamo una porta aperta, oppure
che un'applicazione o servizio sconosciuto aprano falle di cui non
conosciamo l'esistenza. Secondo, in questo modo avremo la possibilità
di renderci effettivamente conto di cosa fanno alcune applicazioni.
Facciamo un esempio.
Ammettiamo che, dopo avere avviato IPtables, l'applicazione "Y"
smetta di funzionare correttamente, è possibile che avesse bisogno
di accedere ad una porta che ora gli è interdetta. Per prima cosa
annullate tutti i impostazioni tramite lo script pubblicato all'inizio
di questa parte dell'articolo, lanciate di nuovo "Y", poi eseguite
il seguente comando:
netstat -taunp | grep Y
ammettiamo che riceviate:
tcp 0 0 <vostro IP>:33000 <IP remoto>:22 ESTABLISHED 1911/Y
vorrebbe dire che l'applicazione "Y" ha bisogno di utilizzare
la porta 33000 per accedere all'esterno, per cui, per risolvere il
problema, vi basterà effettuare gli opportuni impostazioni che vedremo
dopo alla riga 31.
27 $IPT -A INPUT -p ALL -s $LO -i $IF -m limit -limit 3/minute -limit-burst 3 -j LOG -log-level NOTICE -log-prefix "Local spoof: "
28 $IPT -A INPUT -p ALL -s $LO -i $IF -j DROP
29 $IPT -A INPUT -p ALL -i lo -j ACCEPT
tramite la riga 27 logghiamo qualunque pacchetto (-p ALL) che giunge
all'interfaccia internet (-i $IF), e che ha come IP 127.0.0.1, cosa
impossibile e quindi sintomo di attacco. Nei log troveremo queste
stringhe tramite il prefisso "Local spoof: ".
La riga 28 scarta i pacchetti suddetti dopo averli loggati.
La 29 accetta tutto il traffico "locale".
30 $IPT -A INPUT -m state -state RELATED,ESTABLISHED -j ACCEPT
Tramite questa fondamentale regola possiamo navigare su internet.
Consentiamo a dei pacchetti provenienti dall'esterno, come sono quelli
che contengono le pagine web da noi richieste, di attraversare il
firewall, impedendo l'ingresso agli altri, infatti accettiamo solo
i pacchetti che appartengono a connessioni da noi richieste (ESTABILISHED)
o queste correlate (RELATED).
31 $IPT -A INPUT -dport 33000 -m state -state NEW,RELATED,ESTABLISHED -j ACCEPT
la regola 31 ci serve per risolvere il problema che avevamo prospettato
sopra, cioè la necessità di garantire il funzionamento dell'applicazione
"Y" che doveva accettare connessioni sulla porta 33000.
32 $IPT -A OUTPUT -m state -state NEW,RELATED,ESTABLISHED -j ACCEPT
la riga 32 ci consente di collegarci all'esterno richiedendo una connessione.
33 $IPT -A INPUT -p icmp -m icmp -icmp-type 8 -m length -length 93: -m limit -limit 3/minute -limit-burst 3 -j LOG -log-level NOTICE -log-prefix "ICMP flood "
34 $IPT -A INPUT -p icmp -m icmp -icmp-type 8 -m length -length 93: -j DROP
tramite le righe 33 e 34 ci difendiamo da un eventuale attacco tramite
un flood di pacchetti ICMP fuori taglia, infatti, per gli usi leciti
un pacchetto ICMP non deve avere una dimensione superiore a 93 bytes.
Per cui se ne troviamo uno lo logghiamo e lo scartiamo.
35 $IPT -A INPUT -p ICMP -s 0/0 -m icmp -icmp-type 3 -j ACCEPT
36 $IPT -A INPUT -p ICMP -s 0/0 -m icmp -icmp-type 8 -j ACCEPT
37 $IPT -A INPUT -p ICMP -s 0/0 -m icmp -icmp-type 11 -j ACCEPT
con le linee 35-37 accettiamo alcuni tipi di pacchetti ICMP che possono
essere utili.
38 $IPT -A INPUT -m limit -limit 3/minute -limit-burst 3 -j LOG -log-level NOTICE -log-prefix "InputChain "
39 $IPT -A OUTPUT -m limit -limit 3/minute -limit-burst 3 -j LOG -log-level NOTICE -log-prefix "OutputChain "
40 $IPT -A FORWARD -m limit -limit 3/minute -limit-burst 3 -j LOG -log-level NOTICE -log-prefix "ForwardChain "
tramite queste tre ultime regole logghiamo tutti i pacchetti NON
accettati e che verranno scartati. Se la cosa non ci interessa basta
cancellare le tre righe.
Secondo esempio
Come detto, in questo esempio prendiamo in considerazione un firewall
su un computer che separa e collega una piccola rete ad internet,
tramite connessione ADSL.
sono necessari questi ulteriori moduli del kernel:
- [ip_nat_ftp]
- [ipt_MASQUERADE]
- [ipt_tcpmss]
Riutilizzeremo lo script visto sopra inserendo delle nuove righe,
quindi, ad esempio, la riga 31-1 e la 31-2, andranno inserite tra
la 31 e la 32. Le altre rimangono invariate.
4-1 INTRANET="10.0.0.0/255.255.255.0"
4-2 ETH="eth0"
impostiamo due ulteriori variabili per indicare l'indirizzo della nostra
rete interna (4-1) e il nome della interfaccia di rete interna (4-2).
29-1 $IPT -A INPUT -p ALL -s $INTRANET -i $ETH -j ACCEPT
29-2 $IPT -A INPUT -p ALL -s $INTRANET -i $IF -m limit -limit 3/minute -limit-burst 3 -j LOG -log-level NOTICE -log-prefix "External spoof: "
29-3 $IPT -A INPUT -p ALL -s $INTRANET -i $IF -j DROP
la riga 29-1 accetta tutto il traffico destinato al computer del firewall
proveniente dalla LAN interna.
la 29-2 e la 29-3 loggano ed eliminano il traffico che ha IP appartenente
alla rete interna e arrivano sull'interfaccia esterna, sintomo di
attacco tramite spoofing.
37-1 $IPT -A FORWARD -m tcp -tcp-flags SYN,RST SYN -j TCPMSS -clamp-mss-to-pmtu
questa regola è necessaria per garantire che la nostra rete possa
comunicare senza problemi tramite tutte le connessioni ADSL, regolando
in maniera prudente la grandezza dei pacchetti TCP generati.
37-2 $IPT -A FORWARD -i $IF -m state -state RELATED,ESTABLISHED -j ACCEPT
37-3 $IPT -A FORWARD -i $ETH -m state -state NEW,RELATED,ESTABLISHED -j ACCEPT
le righe 37-2 e 37-3 servono a consentire alla rete interna di colloquiare
con l'esterno, stabilendo connessioni, mentre dall'esterno potranno
giungere solo le risposte.
37-4 $IPT -t nat -A POSTROUTING -s $INTRANET -o $IF -j MASQUERADE
questa regola è quella che effettua il "mascheramento" dei pacchetti
che sono destinati o partono dalla LAN interna. Facciamo un esempio
(vedasi Fig. 1 nella prima parte dell'articolo).
Poniamo che abbiamo la situazione illustrata dalla figura 1 che trovate
nella prima parte dell'articolo, e che il computer della LAN interna
"PC 1", dotato di IP 10.0.0.1, vuole collegarsi al server web
www.html.it con IP 212.110.13.99.
Invierà un pacchetto con richiesta di connessione attraverso il firewall
che è posto sulla macchina con IP 10.0.0.100.
Originariamente il pacchetto avrebbe come IP sorgente 10.0.0.1 e come
IP di destinazione 212.110.13.99. Il web server non potrebbe rispondere
alla richiesta perchè 10.0.0.1 è un IP riservato alle reti private.
Per evitare ciò il firewall modificherà l'indirizzo sorgente del pacchetto
sostituendo a 10.0.0.1 l'IP pubblico assegnato 151.123.23.4, inoltre
ricorderà che la richiesta di connessione per il web server 212.110.13.99
proveniva da "PC 1".
Quando giungerà il pacchetto di risposta, che avrà IP sorgente 212.110.13.99
e IP di destinazione 151.123.23.4, modificherà quest'ultimo in 10.0.0.1
e lo inoltrerà a "PC 1".
37-5 echo 1 > /proc/sys/net/ipv4/ip_forward
infine riabilitiamo il "forwarding", cioè la capacità di fare
da ponte tra due computer.
Ricordo che il codice di questo secondo esempio va "inserito",
come spiegato, nel primo.
Conclusioni
Abbiamo solo sfiorato la superficie di IPtables, in quanto si tratta
di un sistema assolutamente completo e flessibile, e in alcuni aspetti
estremamente complesso. Per comprenderlo fino in fondo bisogna avere
delle ottime conoscenze di networking, ma, allo stesso tempo, è abbastanza
intelligente da consentirne l'uso anche da parte di non esperti.
Usatelo e vivrete più sereni.