Gentoo Logo

Disclaimer : La versione originale di questo articolo è stata pubblicata da IBM developerWorks ed è di proprietà di Westtech Information Services. Questo documento è una versione aggiornata dell'articolo originale, e contiene numerosi miglioramenti apportati dal Gentoo Linux Documentation team.
Questo documento non è mantenuto attivamente.


Progettazione di un firewall stateful per Linux 2.4

Indice:

1.  Riguardo questa guida

Questa guida fa per me?

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.

Riguardo l'autore

Per domande tecniche sul contenuto di questa guida, contattate l'autore Daniel Robbins all'indirizzo email drobbins@gentoo.org.

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.

2.  Primi passi

Definire l'obiettivo

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.

Ottenere gli strumenti

Prima di cominciare a progettare il firewall, dobbiamo fare due cose. Innanzi tutto bisogna essere sicuri che il comando iptables sia disponibile. Da root, digitate iptables e guardate se esiste. Se non esiste, allora prima bisogna installarlo. Ecco come:

Codice 2.1: Installare gli strumenti necessari

# emerge iptables

Configurazione del Kernel

Una volta installato, il comando iptables dovrebbe essere pronto all'uso, così come la sua pagina di manuale (man iptables). Bene, ora dobbiamo essere sicuri di avere le funzionalità necessarie all'interno del kernel. Questa guida presuppone che l'utente si compili il proprio kernel. Posizionatevi in /usr/src/linux e digitate make menuconfig o make xconfig: configureremo nel kernel alcune funzionalità di rete.

Nella sezione "Networking options", assicuratevi di aver abilitato le seguenti opzioni:

Codice 2.2: Opzioni del kernel necessarie

<*> 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 non dovete abilitare: la notifica esplicita di congestione. Lasciate questa opzione disabilitata:

Codice 2.3: Opzione da lasciare disabilitata

[ ]   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 :)

Basi per la configurazione del Firewall

Nel costruire il firewall, il comando iptables è nostro amico. È ciò che usiamo per interagire con le regole di filtraggio dei pacchetti all'interno del kernel. Useremo il comando iptables per creare nuove regole, elencare quelle esistenti, eliminarle ed impostare le politiche predefinite per la gestione dei pacchetti. Questo significa che per creare il firewall, inseriremo una serie di comandi iptables; ecco il primo a cui daremo un'occhiata (per favore non digitatelo ancora!)...

Codice 2.4: Cambiare la politica della catena a DROP

# 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.

Impostare una politica per la catena

Il comando iptables -P viene usato per impostare la politica predefinita per una catena di regole di filtraggio pacchetti. In questo esempio iptables -P viene usato per impostare la politica predefinita per la catena INPUT, una catena di regole nativa che viene applicata ad ogni pacchetto entrante. Impostando la politica predefinita a DROP, diciamo al kernel che ogni pacchetto che raggiunge la fine della catena di regole INPUT deve essere lasciato cadere ( cioè deve essere scartato). E, poiché non abbiamo aggiunto nessuna altra regola alla catena INPUT, tutti i pacchetti raggiungono la sua fine e quindi tutti i pacchetti vengono scartati.

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.

3.  Definire le regole

Un (piccolo) miglioramento

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ù:

Codice 3.1: Miglioriamo il nosro firewall estremo

# iptables -P INPUT DROP
# iptables -A INPUT -i ! eth1 -j ACCEPT

La seconda linea iptables -A aggiunge una nuova regola di filtraggio alla fine della catena INPUT. Dopo aver aggiunto questa linea, la catena INPUT consiste di un'unica regola e di una politica scarta-per-default. Diamo ora un'occhiata a cosa fa il nostro firewall semi-completo.

Seguire la catena INPUT

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.

Firewall tradizionali

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:

Codice 3.2: Accettare tutti i pacchetti http entranti

# 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.

Scocciature di un firewall tradizionale

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.

4.  Firewall stateful

Lo stato: le basi

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.

Dentro al tracciamento della connessione (conntrack)

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 cat /proc/net/ip_conntrack. Anche senza aver configurato un firewall, la funzionalità conntrack di Linux lavora dietro le quinte, tenendo traccia delle connessioni alle quali sta partecipando la vostra macchina.

Lo stato di connessione NEW

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 ssh remote.host.com, il pacchetto iniziale o la raffica di pacchetti originati dalla vostra macchina e destinati a remote.host.com sono nello stato NEW. Tuttavia, appena ricevete anche solo un pacchetto di risposta da remote.host.com, ogni ulteriore pacchetto che spedite a remote.host.com come parte di questa connessione non è più considerato NEW. Un pacchetto viene quindi considerato NEW solamente quando è coinvolto nella creazione di una nuova connessione ed ancora non è stato ricevuto nulla dalla macchina remota (ovviamente nel contesto di questa connessione).

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.

Lo stato ESTABLISHED

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.

Lo stato RELATED

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).

Lo stato INVALID

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.

Aggiungere una regola basata sullo stato

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:

Codice 4.1: Aggiungere una regola stateful

# iptables -P INPUT DROP
# iptables -A INPUT -i ! eth1 -j ACCEPT
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Come funziona la regola

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 ssh remote.host.com, la nostra macchina invia un pacchetto all'esterno per instaurare la connessione. Questo pacchetto è nello stato NEW ed il firewall permette il suo ingresso, poiché stiamo bloccando solo i pacchetti in ingresso, non in uscita.

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.

Pacchetti NEW entranti

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ò.

Un firewall quasi perfetto

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.

Uno script base per il firewall

Ecco un semplice script che può essere usato per abilitare/disabilitare il nostro primo e basilare firewall per workstation:

Codice 4.2: Uno script base per il firewall

#!/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

Utilizzare lo script

Utilizzando questo script, potete disattivare il firewall digitando ./firewall stop e ripristinarlo con ./firewall start. Per disattivare il firewall, eliminiamo le regole dalla catena INPUT con un iptables -F INPUT e risistemiamo poi la politica INPUT predefinita con il comando iptables -P INPUT ACCEPT. Diamo ora un'occhiata ai miglioramenti che possiamo implementare. Dopo aver spiegato ogni miglioramento, illustrerò uno script per il firewall definitivo. Infine, personalizzeremo il nostro firewall per i server.

5.  Miglioramenti stateful

Disattivare esplicitamente l'ECN

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 /proc per disabilitare esplicitamente l'ECN come segue:

Codice 5.1: Disattivare esplicitamente l'ECN

if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
    echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi

Inoltrare

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:

Codice 5.2: Inoltrare

# echo 1 > /proc/sys/net/ipv4/ip_forward

Gestire il rifiuto di connessione

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:

Codice 5.3: Gestire il rifiuto di connessione

# 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).

Protezione dalla falsificazione della provenienza (spoofing)

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 /proc. Ecco come fare:

Codice 5.4: Protezione dallo spoofing

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.

Mascheramento IP

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:

Codice 5.5: Mascheramento

# 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.

SNAT

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:

Codice 5.6: SNAT

# 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.

Problemi con NAT

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.

Capire le tabelle

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 Risorse alla fine di questa guida).

Il nostro script migliorato

Ora che abbiamo scorso una lista di possibili miglioramenti, diamo un'occhiata ad uno script più flessibile per accendere/spegnere il firewall:

Codice 5.7: Il nostro script migliorato

#!/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

6.  Server stateful

Vedere le regole

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:

Codice 6.1: Vedere le regole

# 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:

Codice 6.2: Vedere le regole della tabella POSTROUTING

# 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

Pronti per il servizio

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.

HTTP stateful

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.

Esempio di HTTP stateful

Diamo un'occhiata al "cuore" del nostro firewall ed alle nuove regole che permettono le connessioni HTTP entranti:

Codice 6.3: Esempio di HTTP stateful

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.

Il nostro script finale per il firewall

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!)

Codice 6.4: Lo script finale per il firewall

#!/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

7.  Costruire un migliore firewall per server

Miglioramenti al server

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.

Tecniche di logging

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 --log-prefix che vi permette di specificare del testo che apparirà nei log di sistema al passaggio di un pacchetto. Ecco un esempio di regola di log:

Codice 7.1: Regola di log di esempio

#  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:

Codice 7.2: Limitare le scritture nei log

# iptables -A INPUT -m state --state INVALID -m limit --limit 5/minute -j LOG --log-prefix "INVALID STATE:"

Creare le vostre catene

iptables vi permette di creare delle catene personalizzate che possono essere specificate nelle vostre regole. Se volete imparare come fare ciò, spendete un po' di tempo col manuale di filtraggio pacchetti sulla home page del progetto netfilter/iptables (http://www.netfilter.org/).

Far rispettare le politiche di utilizzo della rete

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.

Altri aspetti di sicurezza

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.

8.  Risorse

tcpdump

In questa sezione, indicherò un po' di risorse che troverete utili per costruire il vostro firewall stateful personale. Cominciamo con uno strumento molto importante...

tcpdump è uno strumento essenziale per esplorare scambi di pacchetti ad un basso livello e verificare che il vostro firewall stia funzionando correttamente. Se non ce l'avete, installatelo. Se ce l'avete, incominciate ad usarlo.

netfilter.kernelnotes.org

Visitate la pagina del progetto iptables/netfilter (http://www.netfilter.org/). Su questo sito troverete un sacco di suggerimenti, il codice sorgente di iptables e le FAQ di netfilter. Anche le Eccellenti Guide di Rusty sono ottime, ed includono un manuale sui concetti basilari delle architetture di rete, uno su netfilter (iptables), uno sul NAT ed anche un manuale approfondito su netfilter destinato agli sviluppatori.

Pagine di manuale di iptables

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.

Manuale avanzato sull'instradamento (routing) ed il controllo del traffico su Linux

E' ora disponibile un manuale avanzato sull'instradamento (routing) ed il controllo del traffico su Linux. C'è un'ottima sezione che mostra come usare iptables per marcare i pacchetti ed utilizzare poi le funzionalità di routing di Linux per instradarli sulla base di queste marcature.

Nota: Questo manuale contiene dei riferimenti alla funzionalità per il controllo del traffico (qualità del servizio) in Linux, attraverso il nuovo comando tc. Questa nuova funzionalità, sebbene molto valida, è scarsamente documentata e cercare di immaginarsi tutti gli aspetti del controllo del traffico in Linux può risultare per ora un compito molto frustrante.

Mailing lists

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 la mailing list per gli utenti di netfilter.

Gli sviluppatori di netfilter/iptables che hanno domande, suggerimenti o contributi allo sviluppo di netfilter/iptables, possono invece contattare la mailing list per gli sviluppatori di netfilter.

A questi indirizzi potete anche navigare tra gli archivi delle varie mailing lists.

Building Internet Firewalls, Seconda Edizione

Nel Giugno 2000, O'Reilly ha pubblicato un libro eccellente -- Building Internet Firewalls, Seconda Edizione. E' un ottimo libro di riferimento, specialmente per quando volete configurare un firewall in modo da accettare (o rifiutare senza mezzi termini) un protocollo poco noto col quale non avete familiarità.

Bene, questo è tutto riguardo la lista delle risorse e la guida è terminata. Spero che vi sia stata d'aiuto ed attendo i vostri commenti.

Le vostre opinioni

Aspettiamo di avere le vostre opinioni su questa guida. Inoltre potete contattare direttamente l'autore, Daniel Robbins, all'indirizzo email drobbins@gentoo.org.



Stampa

Aggiornato il 13 gennaio 2012

La versione originale di questo documento è più recente ed è stata aggiornata il 9 ottobre 2005

Oggetto: Questa guida mostra come utilizzare netfilter per configurare un potente firewall stateful (cioè a filtraggio dinamico dei pacchetti) per Linux.

Daniel Robbins
Autore

Alessandro Candini
Traduttore

Donate to support our development efforts.

Copyright 2001-2014 Gentoo Foundation, Inc. Questions, Comments? Contact us.