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
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
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
UPLINK="eth1"
ROUTER="yes"
NAT="1.2.3.4"
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
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
for x in ${INTERFACES}
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
if [ "$ROUTER" = "yes" ]
then
echo 1 > /proc/sys/net/ipv4/ip_forward
if [ "$NAT" = "dynamic" ]
then
echo "Enabling masquerading (dynamic ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE
elif [ "$NAT" != "" ]
then
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
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
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
UPLINK="eth1"
ROUTER="yes"
NAT="1.2.3.4"
INTERFACES="lo eth0 eth1"
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
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
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
for x in ${INTERFACES}
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
if [ "$ROUTER" = "yes" ]
then
echo 1 > /proc/sys/net/ipv4/ip_forward
if [ "$NAT" = "dynamic" ]
then
echo "Enabling masquerading (dynamic ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE
elif [ "$NAT" != "" ]
then
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
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.
|