Questa guida mostra come utilizzare netfilter per configurare un potente firewall stateful per Linux. Quello che serve è un sistema Linux con kernel 2.4: un pc portatile, una workstation, un router o un server possono fare tutti al caso nostro.
Dovreste essere abbastanza pratici con la terminologia di rete standard come indirizzi IP, numeri di porta per l'invio e la ricezione di dati, TCP, UDP, ICMP , ecc. Alla fine della guida, capirete come vengono costruiti i firewall stateful per Linux ed avrete diverse configurazioni d'esempio da poter utilizzare nei vostri progetti.
Per domande tecniche sul contenuto di questa guida, contattate l'autore Daniel
Robbins all'indirizzo email
Risiedente ad Albuquerque, New Mexico (U.S.A.), Daniel Robbins è stato il Presidente/Amministratore Delegato di Gentoo Technologies Inc., nonché il creatore di Gentoo Linux, un avanzata versione di Linux per PC, e di Portage, un sistema di porting di nuova generazione. Ha inoltre contribuito ai libri Macmillan Caldera OpenLinux Unleashed, SuSE Linux Unleashed e Samba Unleashed. Daniel si è occupato in qualche modo di informatica fin dalla seconda elementare , quando venne avvicinato per la prima volta al linguaggio di programmazione Logo e ad una dose di Pac Man potenzialmente dannosa. Probabilmente questo spiega perché abbia poi lavorato come Principale Artista Grafico alla SONY Electronic Publishing/Psygnosis. A Daniel piace passare il tempo libero con sua moglie, Mary, e con la sua nuova bimba, Hadassah.
In questa guida, costruiremo un firewall stateful per Linux. Il firewall potrà funzionare su un pc portatile, una workstation, un server o un router Linux; il suo compito principale sarà quello di lasciar passare solo certi tipi di traffico di rete. Per incrementare la sicurezza, configureremo il firewall in modo che faccia cadere o rifiuti le connessioni alle quali non siamo interessati o che possano rappresentare una minaccia.
Prima di cominciare a progettare il firewall, dobbiamo fare due cose. Innanzi
tutto bisogna essere sicuri che il comando
# emerge iptables
Una volta installato, il comando
Nella sezione "Networking options", assicuratevi di aver abilitato le seguenti opzioni:
<*> Packet socket [*] Network packet filtering (replaces ipchains) <*> Unix domain sockets [*] TCP/IP networking [*] IP: advanced router [*] IP: policy routing [*] IP: use netfilter MARK value as routing key [*] IP: fast network address translation [*] IP: use TOS value as routing key
In seguito, nel menu "IP: Netfilter Configuration ->" abilitate ogni opzione, in modo da attivare tutte le funzionalità di netfilter. Non useremo tutte le sue potenzialità, ma è buona cosa abilitarle così da riuscire a fare qualche altro esperimento successivamente.
C'è un'opzione sotto la categoria "Networking options" che
[ ] IP: TCP Explicit Congestion Notification support
Se questa opzione è abilitata, la vostra macchina Linux non riuscirà ad inoltrare le comunicazioni di rete oltre l'8% dell'estensione di Internet. Quando l'ECN è abilitato, qualche pacchetto spedito dalla vostra Linux box avrà il bit ECN settato; purtroppo, questo bit fa impazzire molti router Internet, quindi è molto importante che tale opzione sia disabilitata.
Ok, adesso che il kernel è configurato correttamente per le nostre esigenze, compilatelo, installatelo e riavviate la macchina. E' ora di cominciare a giocare con netfilter :)
Nel costruire il firewall, il comando
# iptables -P INPUT DROP
State osservando un firewall "quasi" perfetto. Se lanciate questo comando, sarete incredibilmente ben protetti contro ogni forma di attacco malevolo entrante. Questo perché il comando dice al kernel di eliminare tutti i pacchetti entranti. Nonostante questo firewall sia estremamente sicuro, questa configurazione è un po' sciocca. Ma prima di andare avanti, diamo un'occhiata approfondita a come questo comando fa ciò che fa.
Il comando
Di nuovo, questo comando da solo è completamente inutile. Però mostra un buon approccio alla configurazione del firewall. Cominceremo eliminando tutti i pacchetti e poi, gradualmente, apriremo il firewall a seconda delle nostre esigenze. Questo ci assicurerà che il firewall sia il più sicuro possibile.
Nel nostro esempio, supponiamo di progettare un firewall per una macchina con due interfacce di rete, eth0 ed eth1. La scheda di rete eth0 è connessa alla nostra LAN, mentre la scheda di rete eth1 è connessa al router DSL, ovvero alla connessione Internet. In questo caso, possiamo migliorare il nostro "firewall estremo" aggiungendo una linea in più:
# iptables -P INPUT DROP # iptables -A INPUT -i ! eth1 -j ACCEPT
La seconda linea
Quando un pacchetto entra da qualsiasi interfaccia (lo, eth0 o eth1), viene diretto alla catena INPUT e controllato dal codice di netfilter per vedere se rispetta la prima regola. Se la rispetta, il pacchetto viene accettato, e non viene eseguito nessun altro processamento. Se non la rispetta, viene applicata la politica predefinita della catena INPUT ed il pacchetto viene scartato.
Questa è l'idea di base. Nello specifico, la prima regola accetta tutti i pacchetti provenienti da eth0 e lo, permettendo immediatamente il loro ingresso. Ogni pacchetto proveniente da eth1 viene invece scartato. Quindi, se abilitassimo questo firewall sulla nostra macchina, essa riuscirebbe ad interagire con la LAN, ma sarebbe in pratica disconnessa da Internet. Diamo allora un'occhiata ad un paio di modi per abilitare il traffico Internet.
Ovviamente, affinché il nostro firewall sia utile, dobbiamo permettere a qualche pacchetto proveniente da Internet di raggiungere la nostra macchina, dopo averlo selezionato. Ci sono due approcci per aprire il nostro firewall in modo che sia utile: usando regole statiche oppure usando regole dinamiche, basate sullo stato dei pacchetti.
Come esempio proviamo a scaricare qualche pagina Web. Se vogliamo che la nostra macchina riesca a scaricare delle pagine Web da Internet, possiamo aggiungere una regola statica che venga sempre rispettata per ogni pacchetto http entrante, indipendentemente da dove provenga:
# iptables -A INPUT --sport 80 -j ACCEPT
Poiché tutto il traffico web standard passa attraverso la porta 80, questa regola permette efficacemente alla nostra macchina di scaricare pagine Web. Però questo approccio tradizionale, sebbene in alcuni casi accettabile, soffre di qualche problema.
Primo problema: sebbene la maggior parte del traffico web venga originato dalla porta 80, una minima parte no. Quindi, sebbene questa regola funzioni quasi sempre, in alcuni rari casi non sarebbe adatta. Ad esempio, magari vi é capitato di vedere URL come "http://www.foo.com:81". Un URL come questo punta ad un sito Web sulla porta 81 e non sull'80 e risulterebbe invisibile dietro al nostro attuale firewall. Tenere in considerazione tutti questi casi speciali, può trasformare velocemente un firewall abbastanza sicuro in un formaggio svizzero, riempiendo la catena INPUT con un sacco di regole per gestire sporadici siti Web stravaganti.
Ma il maggior problema di questa regola è legato alla sicurezza. E' certamente vero che solo al traffico orginato sulla porta 80 verrà permesso di attraversare il nostro firewall, ma la porta sorgente di un pacchetto non è qualcosa su cui abbiamo il controllo e può essere facilmente alterata da un intruso. Ad esempio, se un intruso sapesse come è progettato il nostro firewall, potrebbe scavalcarlo assicurandosi semplicemente che tutte le sue connessioni entranti vengano originate dalla porta 80 di una delle sue macchine! Poiché questa regola statica è così facile da scavalcare, é necessario un più sicuro approccio dinamico. Per fortuna, iptables ed il kernel 2.4 forniscono tutto il necessario per definire un filtraggio dinamico, basato sullo stato dei pacchetti.
Invece di aprire dei buchi nel nostro firewall, sulla base di caratteristiche statiche del protocollo, possiamo utilizzare la nuova funzionalità di Linux per il tracciamento della connessione in modo che il firewall prenda decisioni basate sullo stato dinamico di connessione dei pacchetti.Il tracciamento della connessione funziona associando ogni pacchetto ad un canale di comunicazione bidirezionale, o connessione.
Ad esempio, considerate cosa succede se usate telnet o ssh verso una macchina remota. Se osservate il traffico di rete a livello di pacchetto, tutto ciò che potrete vedere sarà un insieme di pacchetti che sfreccia da una macchina all'altra. In realtà, ad un livello più alto, questo scambio di pacchetti è un canale di comunicazione bidirezionale tra la vostra macchina e la macchina remota. I firewall tradizionali (ormai fuori moda) si limitano ad osservare i singoli pacchetti, senza capire che in realtà essi fanno parte di un insieme più grande, cioè di una connessione.
Ecco da dove viene la terminologia "tracciamento della connessione". La funzionalità conntrack di Linux può "osservare" le connessioni instaurate di più alto livello, riconoscendo la connessione ssh come una singola entità logica. Conntrack può anche riconoscere gli scambi di pacchetti UDP ed ICMP come "connessioni" logiche, sebbene sia UDP che ICMP siano per loro natura protocolli senza connessione; questo è di grande aiuto perché ci permette di usare conntrack per gestire anche gli scambi di pacchetti UDP ed ICMP.
Se avete riavviato e state già usando il vostro nuovo kernel con netfilter
abilitato, potete vedere la lista delle connessioni di rete attive sulla vostra
macchina digitando
Conntrack non si limita a riconoscere le connessioni, ma classifica anche ogni
pacchetto che si trova in uno dei quattro possibili stati di connesione. Il
primo stato di cui parleremo è lo stato NEW. Quando digitate
Ho descritto pacchetti NEW uscenti, ma è anche possibile (e comune) avere pacchetti NEW entranti. I pacchetti NEW entranti vengono originati generalmente da una macchina remota, e sono coinvolti nell'instaurazione di una connessione sulla vostra macchina. I pacchetti iniziali che il vostro Web server riceve come parte di una richiesta HTTP, vengono considerati pacchetti NEW entranti; tuttavia, una volta risposto ad anche un solo pacchetto NEW entrante, qualsiasi altro pacchetto ricevuto, collegato a questa particolare connessione, non si trova più nello stato NEW.
Una volta che la connessione ha osservato del traffico in entrambe le direzioni, i pacchetti successivi collegati ad essa vengono considerati in stato ENSTABLISHED. La distinzione tra NEW ed ENSTABLISHED è molto importante, come vedremo tra poco.
Il terzo stato di connessione è detto RELATED. I pacchetti RELATED sono quelli che iniziano una nuova connessione, ma sono in relazione ad un altra connessione già esistente. Lo stato RELATED può essere usato per regolare le connessioni che sono parte di un protocollo multi-connessione, come ftp, o come pacchetti di errore collegati a connessioni esistenti (come i pacchetti di errore ICMP collegati ad una connessione esistente).
Infine, ci sono i pacchetti INVALID: quelli che non possono essere classificati in una delle tre categorie descritte sopra. E' importante notare che se un pacchetto viene considerato INVALID, non viene automaticamente scartato; sta a voi inserire le regole appropriate ed impostare la catena delle politiche in modo da gestire correttamente questa situazione.
Ok, ora che abbiamo una buona infarinatura del tracciamento di connessione, diamo un'occhiata alle singole regole addizionali che trasformano il nostro firewall non-funzionale in qualcosa di abbastanza utile:
# iptables -P INPUT DROP # iptables -A INPUT -i ! eth1 -j ACCEPT # iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Questa sola regola, se inserita alla fine della catena INPUT, ci permetterà di
stabilire connessioni con macchine remote. Funziona come segue. Diciamo di
volerci connettere tramite ssh a remote.host.com. Dopo aver digitato
Quando otteniamo una risposta da remote.host.com, questa viene filtrata dalla nostra catena INPUT. Il pacchetto di risposta non soddisfa la prima regola (poiché arriva da eth1), quindi si sposta sulla regola successiva, che è anche l'ultima. Se la soddisfa, verrà accettato, altrimenti cadrà alla fine della catena INPUT e verrà applicata al pacchetto la politica predefinita (DROP). Ma quindi, questo pacchetto di risposta entrante viene accettato oppure no?
Risposta: viene accettato. Quando il kernel esamina questo pacchetto entrante, come prima cosa capisce che è parte di una connessione già esistente. Successivamente, il kernel deve decidere se questo è un pacchetto NEW o ENSTABLISHED. Poiché è un pacchetto entrante, controlla se questa connessione ha avuto del traffico uscente, trovandolo: esso consiste infatti nel pacchetto NEW spedito precedentemente. Perciò, questo pacchetto entrante viene marcato ENSTABLISHED, poiché ci sono stati altri paccheti ricevuti o spediti, associati a questa connessione.
Consideriamo ora cosa succederebbe se qualcuno provasse da una macchina remota a connettersi in ssh alla nostra. Il primo pacchetto ricevuto verrebbe classificato come NEW e, non soddisfacendo la regola uno, passerebbe alla regola due. Poiché questo pacchetto non si trova in stato ENSTABLISHED o RELATED, cadrebbe alla fine della catena INPUT dove verrebbe applicata la politica predefinita, cioè DROP. La richiesta di connessione ssh entrante verrebbe eliminata senza che da noi parta una risposta (o reset TPC) per notificare ciò.
Dunque, che tipo di firewall abbiamo costruito fino ad ora? Uno ottimo per il computer portatile o la workstation per cui non vogliamo nessuna connessione entrante dall'esterno, ma che ci permette di conneterci ai siti Internet. Riuscirete ad usare Netscape, Konqueror, ftp, ping, a fare ricerche DNS e molto altro. Ogni connessione che inizierete, ritornerà indietro attraverso il firewall. Però, ogni connessione non richiesta che cercherà di entrare da Internet verrà bloccata, a meno che non sia collegata ad una connessione già esistente che avete inizializzato voi. Fino a quando non avrete bisogno di fornire un servizio di rete all'esterno, questo è un firewall quasi perfetto.
Ecco un semplice script che può essere usato per abilitare/disabilitare il nostro primo e basilare firewall per workstation:
#!/bin/bash# Un basilare firewall stateful per una workstation o un laptop che non esegue nessun # servizio di rete come un server web, un server SMTP, un server ftp, eccetera. if [ "$1" = "start" ] then echo "Starting firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! eth1 -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT elif [ "$1" = "stop" ] then echo "Stopping firewall..." iptables -F INPUT iptables -P INPUT ACCEPT fi
Utilizzando questo script, potete disattivare il firewall digitando
Prima ho detto che è importante disabilitare la notifica esplicita di
congestione (ECN, Explicit Congestion Notification) in modo che le comunicazioni
su Internet funzionino correttamente. Nonostante abbiate disabilitato nel kernel
l'ECN su mio suggerimento, è possibile che in futuro vi dimentichiate di farlo.
Oppure, potreste passare lo script per il firewall a qualcuno che ha l'ECN
abilitato. Per questi motivi, è una buona idea usare l'interfaccia
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
Se state usando una macchina Linux come router, allora vorrete abilitare l'inoltro IP, che permetterà al kernel di accettare il passaggio di pacchetti tra eth0 ed eth1 e vice versa. Nel nostro esempio di configurazione, dove eth0 è connessa alla LAN ed eth1 è connessa ad Internet, abilitare l'inoltro IP è un passo necessario per permettere alla LAN di collegarsi ad Internet attraverso la nostra macchina Linux. Per abilitare l'inoltro IP, usate questa linea:
# echo 1 > /proc/sys/net/ipv4/ip_forward
Fin'ora abbiamo bloccato tutto il traffico non richiesto entrante da Internet. Sebbene questo sia un metodo efficace per impedire un'attività di rete non voluta, presenta qualche inconveniente. Il problema principale con questo approccio è che risulta facile per un intruso capire che stiamo eseguendo un firewall, poiché la nostra macchina non risponde con il reset TCP standard e con il messaggio ICMP "porta irraggiungibile": queste sono infatti le risposte che una macchina normale spedirebbe indietro per notificare un tentativo fallito di connessione ad un servizio inesistente.
Piuttosto che far scoprire a dei potenziali intrusi che stiamo eseguendo un firewall (dandogli quindi il suggerimento che magari abbiamo qualche servizio prezioso che loro non possono avere), sarebbe meglio far sembrare di non avere proprio nessun servizio da offrire. Aggiungendo le due righe seguenti alla fine della catena INPUT, raggiungeremo con successo questo obiettivo:
# iptables -A INPUT -p tcp -i eth1 -j REJECT --reject-with tcp-reset # iptables -A INPUT -p udp -i eth1 -j REJECT --reject-with icmp-port-unreachable
La prima regola si occupa di eliminare correttamente le connessioni TCP, mentre la seconda gestisce l'UDP. Instaurando queste due regole, diventa molto difficile per un intruso capire se stiamo eseguendo un firewall; si spera che questo convinca l'intruso ad abbandonare la nostra macchina e a cercare altri bersagli più vulnerabili.
Oltre a rendere il nostro firewall più "invisibile", queste regole eliminano anche il ritardo relativo alla connessione di certi server ftp ed irc. Questo ritardo è causato dal server stesso, il quale attua una ricerca dell'identità sulla vostra macchina (connettendosi alla porta 113), disconnettendosi eventualmente dopo circa 15 secondi. Ora, il nostro firewall restituisce un reset TCP immediatamente e la ricerca dell'identità cadrà immediatamente anch'essa, invece che ritentare per 15 secondi (durante i quali voi starete aspettando pazientemente una risposta dal server).
In diverse distribuzioni, quando le interfacce di rete vengono abilitate,
vengono aggiunte al sistema anche alcune vecchie regole di catene IP. Queste
speciali regole sono state aggiunte dai creatori della distribuzione per gestire
un problema chiamato spoofing, nel quale l'indirizzo sorgente all'interno dei
pacchetti è stato modificato in modo da contenere un valore non valido (un
qualcosa creato da script spiritosi). Sebbene possiamo creare regole iptables,
in modo da bloccare anche i pacchetti alterati, c'è un modo più facile. Oggi il
kernel ha l'abilità integrata di eliminare i pacchetti alterati; tutto quello
che bisogna fare è abilitarla tramite una semplice interfaccia
for x in lo eth0 eth1
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
Questo script di shell dirà al kernel di eliminare ogni pacchetto con provenienza alterata, sulle interfacce lo, eth0 ed eth1. Potete aggiungere queste linee al vostro script per il firewall o aggiungerle allo script che abilita le interfacce lo, eth0 ed eth1.
Il NAT (Network Address Translation - Traduzione degli Indirizzi di Rete) ed il mascheramento IP, sebbene non direttamente collegati ai firewall, vengono spesso usati assieme ad essi. Osserveremo ora due comuni configurazioni di NAT e mascheramento che potreste aver bisogno di utilizzare. La prima regola si occupa di situazioni nelle quali avete un collegamento ad Internet su una linea commutata (come ppp0) che usa un IP dinamico:
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
Se vi trovate in questa situazione, allora vorrete anche modificare i miei script per il firewall in modo che tutti i riferimenti ad eth1 (il nostro router DSL d'esempio) vengano cambiati in "ppp0". E va assolutamente bene aggiungere regole che si riferiscano ad una interfaccia "ppp0" che ancora non esiste. Appena ppp0 verrà abilitata, tutto funzionerà perfettamente. Assicuratevi anche di abilitare l'inoltro IP.
Se usate la DSL per connettervi ad Internet, probabilmente avrete una di due possibili configurazioni. Una possibilità è che il vostro router o modem DSL abbia il proprio indirizzo IP e faccia per voi la traduzione degli indirizzi di rete. Se siete in questa situazione, non avete bisogno che Linux si occupi del NAT poiché lo fa già il router.
Ma se volete avere più controllo sulla funzionalità NAT, dovete mettervi d'accordo con il vostro ISP sulla configurazione della vostra connessione DSL in modo che il router passi in modalità bridge. In modalità bridge, il vostro firewall diventerà ufficialmente parte della rete del vostro ISP ed il router inoltrerà trasparentemente il traffico IP avanti ed indietro tra l'ISP e la vostra macchina Linux senza far sapere a nessuno della sua esistenza. Esso non ha più un indirizzo IP; invece eth1 (nel nostro esempio) sfoggia il suo IP. Se qualcuno esegue un ping da Internet verso il vostro indirizzo IP, otterrà una risposta dalla vostra macchina Linux, non più dal vostro router.
Con questo tipo di impostazione, dovreste usare lo SNAT (Source Nat) al posto del mascheramento. Ecco la linea da aggiungere al vostro firewall:
# iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 1.2.3.4
In questo esempio, eth1 deve essere cambiata con l'interfaccia ethernet collegata direttamente al router DSL ed 1.2.3.4 deve diventare il vostro IP statico (l'IP della vostra interfaccia ethernet). Ricordatevi ancora una volta di abilitare l'inoltro IP.
Fortunatamente il NAT ed il mascheramento vanno d'accordo con i firewall. Quando scrivete le vostre regole di filtraggio, basta che ignoriate il fatto che state usando il NAT. Le vostre regole dovrebbero accettare, far cadere o rifiutare i pacchetti basandosi sui loro "reali" indirizzi di sorgente e destinazione. Il codice di filtraggio del firewall vede l'indirizzo sorgente di un pacchetto e l'indirizzo di destinazione finale. Questo va benissimo, perché permette al nostro firewall di continuare a funzionare correttamente anche se disabilitassimo temporaneamente il NAT o il mascheramento.
Negli esempi precedenti su NAT/mascheramento, abbiamo aggiunto regole ad una
catena, ma abbiamo anche fatto qualcosa di leggermente diverso. Notate l'opzione
"-t". Essa ci permette di specificare la tabella alla quale appartiene la nostra
catena. Se omessa, la tabella predefinita si chiama "filter". Quindi, tutti i
precedenti comandi non collegati al NAT, stavano modificando la catena INPUT che
è parte della tabella "filter". La tabella "filter" contiene tutte le regole
associate ai pacchetti accettati o rifiutati, mentre la tabella "nat" (come
potete immaginare) contiene le regole connesse alla traduzione degli indirizzi
di rete. Ci sono anche altre catene iptables predefinite, che sono descritte in
dettaglio nella pagina di manuale di iptables e nelle guide di Rusty (guardate
il collegamento nella sezione
Ora che abbiamo scorso una lista di possibili miglioramenti, diamo un'occhiata ad uno script più flessibile per accendere/spegnere il firewall:
#!/bin/bash# Un firewall stateful migliorato per una workstation, un computer portatile o un # router che non esegue nessun servizio di rete come server web, SMTP, ftp, eccetera. # Cambiate questa variabile col nome dell'interfaccia che vi fornisce l'"uplink" # (cioè la connessione ad Internet) UPLINK="eth1"# Se dovete configurare un router (e quindi volete inoltrare i pacchetti IP tra le # interfacce), impostate ROUTER="yes"; altrimenti ROUTER="no" ROUTER="yes"# Modificate la linea seguente con l'IP statico della vostra interfaccia collegata # ad Internet per lo SNAT statico o con "dynamic" se avete un IP dinamico. Se non avete # bisogno del NAT, impostate "" in modo da disabilitarlo. NAT="1.2.3.4"# Modificate la linea seguente in modo da listare tutte le vostre interfacce di rete, lo compresa INTERFACES="lo eth0 eth1" if [ "$1" = "start" ] then echo "Starting firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! ${UPLINK} -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable# Disabilitate esplicitamente l'ECN if [ -e /proc/sys/net/ipv4/tcp_ecn ] then echo 0 > /proc/sys/net/ipv4/tcp_ecn fi# Disabilitate lo spoofing su tutte le interfacce for x in ${INTERFACES} do echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter done if [ "$ROUTER" = "yes" ] then# Avendo un router di qualsiasi tipo, abilitate l'inoltro IP echo 1 > /proc/sys/net/ipv4/ip_forward if [ "$NAT" = "dynamic" ] then# Indirizzo IP dinamico, utilizzate il mascheramento echo "Enabling masquerading (dynamic ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE elif [ "$NAT" != "" ] then# Indirizzo IP statico, usate SNAT echo "Enabling SNAT (static ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP} fi fi elif [ "$1" = "stop" ] then echo "Stopping firewall..." iptables -F INPUT iptables -P INPUT ACCEPT# Disabilitate il NAT/mascheramento, se sono abilitati iptables -t nat -F POSTROUTING fi
Prima di cominciare a personalizzare il firewall in modo che possa essere usato su un server, bisogna che vi mostri come listare le sue regole attive. Per visualizzare le regole nella tabella filter della catena INPUT, digitate:
# iptables -v -L INPUT
L'opzione -v ci da un output verboso, in modo da poter vedere i pacchetti ed i bytes totali trasferiti per ogni regola. Possiamo guardare anche alla tabella nat POSTROUTING con il seguente comando:
# iptables -t nat -v -L POSTROUTING Chain POSTROUTING (policy ACCEPT 399 packets, 48418 bytes) pkts bytes target prot opt in out source destination 2728 170K SNAT all -- any eth1 anywhere anywhere to:215.218.215.2
Fino qui, il nostro firewall non permette a chiunque di collegarsi a dei servizi sulla nostra macchina, poiché accetta solamente pachetti entranti ENSTABLISHED o RELATED. Poiché esso elimina ogni pacchetto NEW entrante, qualsiasi tentativo di connessione viene rifiutato incondizionatamente. Però, permettendo selettivamente a del traffico entrante di oltrepassare il firewall, possiamo permettere ad un utente generico di collegarsi a dei nostri servizi specifici.
Nonostante ci possa andare bene accettare qualche connessione entrante, probabilmente non vorremmo accettarle tutte. Ha senso cominciare con una politica di "divieto automatico" (come quella che abbiamo ora) e cominciare a permettere l'accesso a quei servizi che vorremmo rendere disponibili. Ad esempio se stiamo eseguendo un server web, permetteremo l'ingresso di pacchetti NEW sulla nostra macchina, se hanno nell'intestazione il riferimento alla porta 80 (HTTP). Questo è tutto ciò che bisogna fare; una volta che abbiamo permesso l'ingresso ai pacchetti NEW, abbiamo dato il permesso di stabilire una connessione. Quando viene stabilita una connessione, entrano in azione le regole per l'ingresso dei pacchetti ESTABLISHED e RELATED, permettendo liberamente la connessione HTTP.
Diamo un'occhiata al "cuore" del nostro firewall ed alle nuove regole che permettono le connessioni HTTP entranti:
iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Seguono le nostre nuove regole
iptables -A INPUT -p tcp --dport http -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with
icmp-port-unreachable
Questa nuova regola permette l'ingresso ai pacchetti TCP NEW destinati alla porta 80 (HTTP) della nostra macchina. Notate la sua posizione. E' importante che si trovi prima delle regole di REJECT. Poiché iptables applicherà la prima regola rispettata, posizionarla dopo le linee di REJECT avrebbe come effetto la non esecuzione della regola stessa.
Diamo ora un'occhiata allo script finale per il firewall, il quale può essere usato su un computer portatile, una workstation, un router o un server (o una combinazione di questi!)
#!/bin/bash# Il nostro script completo per il firewall. Questo firewall può essere configurato # per un computer portatile, una workstation, un router o anche un server. :) # Cambiate questa variabile col nome dell'interfaccia che vi fornisce l'"uplink" # (cioè la connessione ad Internet) UPLINK="eth1"# Se dovete configurare un router (e quindi volete inoltrare i pacchetti IP tra le # interfacce), impostate ROUTER="yes"; altrimenti ROUTER="no" ROUTER="yes"# Modificate la linea seguente con l'IP statico della vostra interfaccia collegata # ad Internet per lo SNAT statico o con "dynamic" se avete un IP dinamico. Se non avete # bisogno del NAT, impostate "" in modo da disabilitarlo. NAT="1.2.3.4"# Modificate la linea seguente in modo da listare tutte le vostre interfacce di rete, lo compresa INTERFACES="lo eth0 eth1"# Modificate la seguente linea in modo che vengano listati i numeri assegnati o i # nomi simbolici (da /etc/services) di tutti i servizi che vorreste fornire ad un'utenza # generica. Se non volete attivo nessun servizio, impostatela a "" SERVICES="http ftp smtp ssh rsync" if [ "$1" = "start" ] then echo "Starting firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! ${UPLINK} -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT# Abilitate un accesso pubblico a certi servizi for x in ${SERVICES} do iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j ACCEPT done iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable# Disabilitate esplicitamente l'ECN if [ -e /proc/sys/net/ipv4/tcp_ecn ] then echo 0 > /proc/sys/net/ipv4/tcp_ecn fi# Disabilitate lo spoofing su tutte le interfacce for x in ${INTERFACES} do echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter done if [ "$ROUTER" = "yes" ] then# Avendo un router qualsiasi, abilitate l'inoltro IP echo 1 > /proc/sys/net/ipv4/ip_forward if [ "$NAT" = "dynamic" ] then# Indirizzo IP dinamico, utilizzate il mascheramento echo "Enabling masquerading (dynamic ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE elif [ "$NAT" != "" ] then# Indirizzo IP statico, usate SNAT echo "Enabling SNAT (static ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP} fi fi elif [ "$1" = "stop" ] then echo "Stopping firewall..." iptables -F INPUT iptables -P INPUT ACCEPT# Disabilitate il NAT/mascheramento, se sono abilitati iptables -t nat -F POSTROUTING fi
E' sempre possibile rendere un firewall un po' "migliore". Ovviamente, il significato di "migliore" varia a seconda delle nostre necessità. Lo script che abbiamo prodotto potrebbe soddisfare perfettamente le vostre, o magari avrete bisogno di fare qualche aggiustamento. Questa sezione ha lo scopo di essere una fonte di idee, mostrando modi di migliorare il vostro firewall stateful.
Fino ad ora non abbiamo discusso di logging, ovvero della registrazione
cronologica delle operazioni man mano che vengono eseguite. C'è una speciale
opzione chiamata LOG che vi permette di gestirlo. Assieme a LOG, c'è un'altra
opzione chiamata
# iptables -A INPUT -j LOG --log-prefix "bad input:"
Questa linea non dovrà essere aggiunta come prima regola della catena INPUT, altrimenti causerà il salvataggio di una riga di log per ogni pacchetto ricevuto! Aggiungetela invece più in basso nella catena INPUT, con lo scopo di registrare solo pacchetti strani ed altre anomalie.
Ecco una nota importante per l'opzione LOG. Normalmente, quando una regola viene soddisfatta, il pacchetto in oggetto può essere accettato, rifiutato o lasciato cadere, senza che altre regole vengano analizzate. Però, quando viene soddisfatta una regola di log, il pacchetto viene registrato. Esso non viene accettato, rifiutato o lasciato cadere, ma prosegue verso la regola successiva, oppure viene applicata la politica predefinita se la regola di log é l'ultima della catena.
L'opzione LOG può essere anche combinata con il modulo "limit" (descritto nel manuale di iptables), per minimizzare le righe di log duplicate. Ecco un esempio:
# iptables -A INPUT -m state --state INVALID -m limit --limit 5/minute -j LOG --log-prefix "INVALID STATE:"
I firewall sono strumenti molto potenti per chi vuole rinforzare le politiche di utilizzo della rete su una LAN aziendale o accademica. Potete controllare quali pacchetti inoltrare dalla vostra macchina aggiungendo regole ed impostando le politiche nella catena FORWARD. Aggiungendo regole alla catena OUTPUT potete anche controllare cosa succede ai pacchetti che vengono generati localmente, dagli utenti della macchina Linux stessa. iptables ha inoltre l'incredibile capacità di filtrare i pacchetti creati localmente, basandosi sul proprietario (tramite uid o gid). Per maggiori informazioni, cercate "owner" (proprietario) nella pagina di manuale di iptables.
Nel nostro firewall d'esempio abbiamo assunto che tutto il traffico interno alla LAN fosse affidabile e che dovesse essere controllato attentamente solo il traffico proveniente da Internet. A seconda della vostra rete, questa configurazione può fare al caso vostro o meno. Non c'è nulla che vi impedisca di configurare il firewall in modo da proteggervi anche dal traffico entrante della vostra LAN. Considerate altre "zone" della vostra rete che magari vorreste proteggere. Potrebbe anche essere appropriato configurare 2 separate "zone" di sicurezza all'interno della LAN, ognuna con le proprie politiche di sicurezza.
In questa sezione, indicherò un po' di risorse che troverete utili per costruire il vostro firewall stateful personale. Cominciamo con uno strumento molto importante...
Visitate la pagina del progetto iptables/netfilter
(
Per fortuna su Internet ci sono un sacco di buone risorse per netfilter; comunque, non dimenticatevi delle basi. La pagina di manuale di iptables è molto dettagliata ed è un brillante esempio di come una pagina di manuale dovrebbe essere. In realtà è anche una lettura piacevole.
E' ora disponibile un
Gli utenti che hanno domande su utilizzo, organizzazione o configurazione di
netfilter/iptables o chiunque voglia aiutare altri utenti condividendo la loro
conoscenza ed esperienza, possono contattare
Gli sviluppatori di netfilter/iptables che hanno domande, suggerimenti o
contributi allo sviluppo di netfilter/iptables, possono invece contattare
A questi indirizzi potete anche navigare tra gli archivi delle varie mailing lists.
Nel Giugno 2000, O'Reilly ha pubblicato un libro eccellente --
Bene, questo è tutto riguardo la lista delle risorse e la guida è terminata. Spero che vi sia stata d'aiuto ed attendo i vostri commenti.
Aspettiamo di avere le vostre opinioni su questa guida. Inoltre potete
contattare direttamente l'autore, Daniel Robbins, all'indirizzo email