La rete e l'instradamento dei pacchetti in Linux (cenni).
I pacchetti di rete percorrono il cuore del sistema operativo linux (kernel)
seguendo due possibili strade e attraversando alcuni punti specifici.
Un pacchetto in ingresso nel sistema deve essere ispezionato dal kernel per conoscerne la
destinazione: questa potrebbe essere locale (INPUT), oppure il pacchetto potrebbe essere
inoltrato verso un altro nodo della rete (FORWARD).
Per quanto riguarda invece i pacchetti generati localmente, ad esempio dalla nostra applicazione
browser web firefox, questi saranno destinati ad uscire (OUTPUT) dal nostro
sistema verso un computer remoto.
I pacchetti che raggiungono il nostro sistema possono attraversare la catena di INPUT oppure di
FORWARD, a seconda che sono destinati a noi oppure ad un altro computer.
I pacchetti generati dal nostro sistema, attraverseranno la catena di OUTPUT.
In ogni caso, i pacchetti che attraversano la catena di FORWARD (inoltro verso altre macchine)
non attraverseranno mai quella di OUTPUT o di INPUT.
Quindi all'arrivo di un pacchetto al nostro firewall linux, esso si trova ad un bivio: direzione INPUT
se il pacchetto e' per noi (ad esempio una risposta al nostro firefox contenente una pagina web), direzione
FORWARD se il pacchetto non contiene il nostro come indirizzo di destinazione (ad esempio un firewall di
instradamento di pacchetti (router) inoltra i pacchetti dei computer da esso protetti verso la
rete Internet esterna e ne redirige le risposte che ritornano indietro.
Solo nelle catene elencate fino ad ora è possibile effettuare il filtraggio
dei pacchetti di rete: INPUT, OUTPUT o FORWARD.
Questo significa che una regola di blocco sulla catena di INPUT blocca un pacchetto in arrivo e destinato
a noi, una regola sul FORWARD invece viene applicata a un pacchetto in arrivo ma non destinato a noi,
mentre una regola in OUTPUT blocca un pacchetto generato da una applicazione sul nostro sistema, e quindi
diretta verso un computer esterno.
Fino a questo punto le cose sono piuttosto semplici. A queste considerazioni tuttavia vanno aggiunte alcune
precisazioni.
Un firewall o filtro di pacchetti spesso non si limita a lasciare passare o meno il traffico attraverso di
esso. A volte è necessario che alcuni pacchetti in arrivo e destinati a una macchina X siano rediretti
verso un'altro computer Y. È il caso rappresentato ad esempio da un server web, che ospita le pagine di
un'università: esso di norma non viene installato sul computer di confine della rete, poich´ ivi
sarebbe esposto direttamente agli attacchi provenienti dalla grande Internet. Piuttosto il server web trova
spazio su una macchina interna alla rete, protetta dal firewall o anche da un indirizzo privato
(un indirizzo privato è appartenente ad una classe di indirizzi che non può essere raggiunta
dall'esterno di una rete privata). Allora un nodo della rete che volesse visitare il sito web
dell'università non potrebbe indirizzare il server web direttamente, poiché essendo l'indirizzo
di quest'ultimo privato, ma deve indirizzare quella macchina dell'università che risiede al confine della
rete interna e richiedere ad essa la pagina web. A questo punto, il computer firewall di confine non ha installato
il server web, tuttavia sa che quest'ultimo risiede presso la macchina Z della rete interna. A questo punto,
il firewall inoltra la richiesta verso la macchina Z (attraverso quindi la catena di FORWARD), e le risposte da
Z saranno naturalmente indirizzate al computer remoto che nel frattempo è rimasto in attesa del documento
web.
Apppare evidente quindi che il destino di un pacchetto in arrivo (INPUT oppure FORWARD) può
essere cambiato dopo il suo arrivo nel nostro sistema, ma prima del bivio INPUT/FORWARD.
Il punto in cui avviene questo cambiamento è il cosiddetto punto di PRE-ROUTING, cioè
prima dell'indirizzamento.
Affinché un pacchetto veda il proprio percorso cambiare nel punto di PRE-ROUTING, è necessario
che in quel punto il filtro di pacchetti modifichi il campo dell'indirizzo del pacchetto stesso:
è in PRE-ROUTING
che un pacchetto destinato alla macchina X viene reindirizzato ad una machina Y, oppure anche a noi stessi, o
ancora che un pacchetto destinato a noi (all'INPUT) sia inoltrato ad una macchina Z (quindi attraverso la catena
di FORWARD).
In modo del tutto analogo, un pacchetto che sta per lasciare la nostra macchina, può essere modificato
poco prima di uscire, ad esempio per farlo apparire come proveniente da una macchina diversa da quella dalla
quale è effettivamente stato generato. È il caso del lavoro svolto dal firewall quando deve
permettere ad una macchina interna alla rete privata (con indirizzo privato e quindi invisibile dall'esterno)
di accedere alla rete pubblica Internet. Questo tipo di lavoro viene svolto nel punto di POST-ROUTING.
La figura sottostante rappresenta il modello descritto finora.
Si osservi lo schema a blocchi piuttosto che i fumetti, che sono tratti da una figura atta a descrivere il
flusso del codice sorgente di IPFIRE-wall, che avviene in un'altra pagina.
Le operazioni di cui si è accennato nei punti di PRE e POST routing prendono il nome di operazioni
di NAT, ovvero Network Address Translation, traduzione degli indirizzi di rete. In effetti,
vengono proprio manipolati gli indirizzi di rete contenuti nei pacchetti per consentirne il corretto instradamento.
In particolare, la traduzione degli indirizzi può riguardare il cambiamento dell'indirizzo sorgente del
pacchetto (l'indirizzo della macchina che lo manda), oppure di quello destinazione (l'indirizzo verso cui è
diretto). Si parla quindi di NAT sorgente (SNAT) e destinazione (DNAT).
Il DNAT si esegue in PRE-ROUTING, per cambiare la destinazione del pacchetto, mentre il Source NAT si
esegue in POST-ROUTING, per cambiare l'indirizzo sorgente del pacchetto. In realtà con IPFIRE-wall
si può eseguire DNAT anche in OUTPUT, sotto particolari condizioni.
Il filtraggio dei pacchetti avviene invece nelle catene di INPUT, OUTPUT o FORWARD, e in tale contesto
essi non vengono manipolati, ma semplicemente accettati o scartati, a seconda della regola che li riguarda.
Regole di IPFIRE-wall e protocollo di rete TCP/IP
IPFIREwall può essere istruito per filtlrare pacchetti di rete
sulla base delle loro proprietà caratteristiche del protocollo di rete
internet TCP/IP (Transmission Control Protocol/Internet Protocol).
Identificazione di una macchina in rete e di un servizio al suo interno.
Per identificare un computer in rete, è necessario che a questo sia associato
un indirizzo univoco. Un indirizzo di rete è costituito da un numero di 32 bit, che
permette di assegnare quindi un totale di 2 alla 32 valori diversi. Una volta identificata
una particolare macchina nella rete, questa può avere in esecuzione più servizi:
è quindi necessario indicare a quale dei servizi disponibili siamo interessati.
Ad ogni servizio è associato un numero, detto numero di porta, o semplicemente
porta. Due servizi diversi saranno contraddistinti da due porte diverse.
Quindi la coppia indirizzo-porta è sufficiente a identificare un computer in
rete e, all'interno di esso, un particolare servizio in esecuzione.
Ad esempio, il servizio di recupero di pagine web è in ascolto sulla porta 80,
mentre il servizio di risoluzione dei nomi Internet sulla porta 53, o ancora il recupero
della posta elettronica avviene contattando un server in ascolto sulla porta 110 mentre
il deposito della posta in uscita viene effettuato su un server associato alla porta 25.
Questi costituiscono solo alcuni esempi di coppie servizio/porta, ma leggendo il file
/etc/services (si provi il comando cat /etc/services
da una shell
linux), se ne possono osservare molti altri.
Affidabilità della connessione di rete e servizi orientati alla connessione.
Il protocollo in uso per la trasmissione dei dati in rete è chiamato TCP/IP
(Protocollo di Controllo della Trasmissione / Protocollo Internet).
La parte IP rappresenta quella sezione di protocolli atta a gestire principalmente
l'instradamento dei pacchetti di rete da sorgente a destinazione, mentre la parte di controllo
(TCP) si preoccupa dell'affidabilità e della gestione della ritrasmissione
e del riordinamento dei pacchetti giunti corrotti o in ordine errato. Il controllo della
trasmissione fornisce vari livelli di affidabilità ed efficienza.
Ancora, si può dire che, in TCP/IP, TCP rappresenta il cosiddetto livello di
trasporto, mentre IP rappresenta il livello di rete.
Il livello di trasporto fornisce, come già accennato, diversi livelli di
affidabiità ed efficienza.
Due concetti sono fondamentali per caratterizzare un protocollo di trasporto: esso
può essere orientato o non orientato alla connessione,
affidabile o non affidabile.
Un altro protocollo spesso utilizzato nella comunicazione di rete è
quello ICMP, Internet Control Message Protocol, che appunto
viene utilizzato per scambiare messaggi di controllo.
Il programma ping rappresenta un esempio d'uso del protocollo
ICMP. Anche i firewall spesso rispondono tramite messaggi
ICMP qualora vogliano restituire qualche codice d'errore o la non disponibilità
di qualche servizio.
IPFIRE-wall supporta i protocolli TCP, UDP e
ICMP.
Una regola deve sempre indicare esplicitamente la direzione a
cui va applicata.
Secondo la trattazione sopra, le direzioni saranno quelle di ingresso (INPUT
), uscita (OUTPUT), inoltro (FORWARD),
pre-routing (PRE) o post-routing(POST).
I concetti rappresentati dalle direzioni sono stati illustrati poco sopra: i più
importanti sono costituiti dalle direzioni di ingresso, uscita e inoltro. Il lettore che non
avesse ancora chiaro i significati di pre e post-routing può tranquillamente
proseguire la trattazione, che non farà ulteriore riferimento ad essi; chi invece
non avesse compreso il significato di direzione di ingresso e uscita, rilegga attentamente
i paragrafi precedenti.
Al momento dell'aggiunta di una nuova regola è sempre bene specificare
il tipo di protocollo a cui pertiene.
Inoltre, possono essere specificati gli indirizzi sorgente e destinazione.
Gli indirizzi di rete vengono espressi nella forma decimale a punti: quattro numeri da
0 a 255 sono separati da un punto (notazione IP versione 4). Ad esempio, sono validi
indirizzi di rete IP
192.168.0.1
o 158.110.28.25.
IPFIRE-wall consente inoltre di specificare un intervallo di indirizzi, indicando
i due estremi, come ad esempio
192.168.1.0 -
192.168.1.254,
oppure utilizzando la notazione equivalente
192.168.1.0/23 o 192.168.1.0/255.255.254.0,
dove si può osservare la
coppia indirizzo/maschera di sottorete (si veda la bibliografia per gli approfondimenti).
Gli indirizzi di rete possono essere introdotti in IPFIRE-wall anche in
forma negata,
preponendo il carattere di negazione ! all'indirizzo che deve essere
negato. La direttiva "!192.168.0.2" significa ad esempio che l'indirizzo di rete
deve essere diverso da 192.168.0.2. Ancora, il carattere ! può
venire anteposto anche ad un intervallo, intendendo così che gli indirizzi al suo
interno sono esclusi dalla corrispondenza.
In modo del tutto analogo IPFIRE-wall consente di esprimere direttive riguardanti le
porte di una connessione. Il numero di porta è semplicemente
un intero minore di 65536 (la porta è un intero senza segno su 16 bit, e
quindi un numero di 16 bit può assumere un valore da zero a 65535, pari
a 2 elevato alla 16). Come per gli indirizzi, è possibile esprimere una singola
porta o un intervallo di porte, anche in forma negata.
IPFIRE-wall consente di determinare anche a quale interfaccia di rete va
applicata una regola: un computer connesso alla rete può possedere più
di un'interfaccia di rete e pertanto una regola si può applicare a tutte ovvero
a una sola delle presenti. Un caso comune è costituito da un PC con un
modem e una scheda di rete (ethernet): in tal caso i nomi
delle interfacce potrebbero essere ppp0, se il modem effettua una
connessione punto a punto Point to Point con il provider Internet remoto,
e eth0 per la scheda di rete ethernet.
La procedura di inserimento di una regola è guidata passo passo: per ogni
campo viene richiesto il valore desiderato dall'utente, che alla fine confermerà
o annullerà l'aggiunta della nuova prescrizione per il filtro dei pacchetti.
L'ultima fase della procedura chiede di dare un nome semplice (al più di venti
caratteri) alla regola, per consentirne il riconoscimento immediato al momento della
sua applicazione e visualizzazione sulla console dei messaggi di IPFIRE-wall.
Quando una nuova regola viene aggiunta, l'utente ha la facoltà di deciderne la
posizione: o in coda alle altre (e quindi il firewall la consulterà per ultima), come
predefinito, oppure in una particolare posizione a scelta.
Si osservi che questo passo richiede particolare attenzione: è sempre buona
norma conoscere approfonditamente le regole già presenti insieme con il loro
ordine e ricordare che quando una regola viene applicata con successo ad un
pacchetto di rete, la scansione della lista ha termine.
Questo significa che se la terza regola consente tutto il traffico
in uscita del protocollo TCP, è inutile inserire una regola
al quinto posto che permetta i pacchetti in uscita, di protocollo TCP e verso
la porta 80.
Se tuttavia le due regole sopra appaiono in ordine inverso,
il traffico TCP in uscita verso la porta 80 verrà permesso esplicitamente dalla
regola per la porta 80, mentre tutto il traffico in uscita, TCP, verso una porta diversa
dalla 80 verrà permesso dalla regola generica a seguire.
Si riporta infine un esempio di una regola così come viene salvata da IPFIRE-wall.
Anche se l'utente non dovrà mai preoccuparsi di scrivere a mano una regola,
essendo disponibile un'interfaccia interattiva, si può notare la chiarezza e la
semplicità delle direttive che costituiscono le politiche di gestione del filtro
di pacchetti.
RULE NAME=Telnet->192.168.0.2 POSITION=10 DIRECTION=OUTPUT OUTDEVICE=eth0 MYSRCADDR DSTADDR=192.168.0.2 PROTOCOL=6 DSTPORT=23 KEEP_STATE=YES
La prima riga dichiara l'inizio di una nuova regola della lista.
Il nome è costituito da una stringa qualsiasi scelta dall'utente per ricordare con facilità la regola.
Il terzo campo memorizza la posizione della regola nel firewall, mentre il quarto specifica la direzione.
La direttiva OUTDEVICE dice a IPFIRE-wall di applicare la regola ai pacchetti in uscita sull'interfaccia ethernet 0 (le interfacce hanno un numero che inizia dallo 0, non da 1).
La regola nell'esempio si applica ai pacchetti che hanno l'indirizzo di rete uguale al nostro indirizzo (il pacchetto cioè deve avere indirizzo sorgente pari all'indirizzo dell'interfaccia da cui esso esce), mentre il protocollo 6 rappresenta quello TCP (il protocollo UDP corrisponde al numero 17).
Infine, la regola si applica alle connessioni aventi come porta destinazione la numero 23 (corrispondente al servizio Telnet) ed è una regola di stato (si veda il paragrafo successivo).
Regole di stato.
Dalla trattazione svolta finora dovrebbe risultare chiaro che una comunicazione
via rete avviene tra due computer che devono dialogare tra loro conoscendo i rispettivi
indirizzi di rete. Non solo, all'arrivo di un pacchetto alla destinazione giusta, questo deve
anche essere consegnato all'applicazione corretta, in ascolto su una determinata porta.
Se ad esempio la macchina A con indirizzo 212.255.12.120 manda un pacchetto al server
web per scaricare una pagina al computer B 158.110.28.25, dovrà indirizzare
la richiesta all'applicativo server web, in ascolto sulla porta 80 TCP.
A questo punto, la macchina B risponderà alla macchina A conoscendo
l'indirizzo di rete di quest'ultima e alla porta aperta a sua volta dalla stessa macchina
A per identificare la connessione con il server web. Infatti anche il richiedente il servizio
deve aprire una porta affincé il server possa identificare il punto d'accesso
del destinatario a livello trasporto.
La situazione è quindi la seguente:
A: <212.255.12.120, porta 4096> -> B: <158.110.28.25, porta 80>
essendo A il mittente che inizia la connessione e B il destinatario, ed
essendo nel pacchetto nella direzione A -> B l'indirizzo di A (212.25...) quello sorgente
e quello di B (158.110...) quello destinazione (insieme alle rispettive porte).
Quando B risponde ad A, è evidente che il pacchetto da B ad A avrà
l'indirizzo di B, porta di B (80) come sorgente e l'indirizzo di A, porta 4096 come
destinazione.
Supponiamo dunque di avere installato IPFIRE-wall sul computer A: se noi inserissimo
una regola di permesso per i pacchetti in uscita verso l'indirizzo
destinazione 158.110.28.25, porta 80, certamente i pacchetti dal nostro PC A
uscirebbero verso B.
Ma questo è sufficiente affinché possiamo visualizzare la pagina web,
ovvero affinché la connessione sia stabilita?
Il lettore attento avrà già intuito il problema: i pacchetti di risposta da
B verso di noi (A) presentano l'indirizzo di B come sorgente, e quello di A come
destinazione, esattamente il caso opposto del nostro primo pacchetto in uscita da
A (sorgente), verso B (destinazione).
Di norma quindi, è necessaria una regola per lasciare
uscire un pacchetto verso
la destinazione, e una regola con i campi inversi per consentire le risposte.
In IPFIRE-wall, grazie alle regole di stato, è possibile
definire una regola per un pacchetto o un insieme di pacchetti verso una direzione,
e consentire il loro riconoscimento quando viaggiano nella direzione opposta :
è
sufficiente che la regola sia dichiarata di stato
(stateful).
In questo modo, oltre ad evitare di scrivere per ogni regola di permesso la sua
complementare, si risolve un ulteriore problema: in generale, se con una regola
si permette la comunicazione tra A e B e quella tra B ed A con la complementare,
si permette implicitamente che in ogni caso B possa mandare pacchetti ad A con
successo. Questo può non essere sempre auspicabile.
Qualora desiderassi contattare un sito web per leggere una pagina, potrei comunque
non volere che il sito web inizializzasse di sua spontanea volontà una connessione
verso il mio computer (in cerca di che cosa?).
Le regole di stato considerano che l'utente ha consentito che il primo pacchetto
che inizia la connessione sia uscito dal firewall e associano a
questa connessione una tabella, in modo tale che i pacchetti
di ritorno nella direzione opposta siano riconosciuti come correlati
al primo pacchetto.
Ad esempio siano N1:p1 indirizzo e porta associati al pc 1, N2 e p2 quelli associati al pc 2.
La regola di stato che consente
N1:p1 -> N2:p2
consentirà anche il traffico
N2:p2 -> N1:p1
almeno fintanto che le tabelle di stato non saranno andate in timeout dopo la fine della
connessione. Si osservi che, dopo lo scadere dei citati timeout, non saranno più
accettati pacchetti provenienti da N2:p2 (sorgente), poiché non c'è
alcuna regola che consenta N2:p2 come indirizzo e porta sorgente!
Si consiglia di prendere dimestichezza con le regole di stato e con il loro utilizzo
leggendo questa pagina.
Opzioni specifiche del protocollo TCP.
Essendo TCP un protocollo orientato alla connessione, esso memorizza nei suoi
pacchetti informazioni concernenti la connessione in alcuni campi detti
flag. Anche questi flag possono essere controllati da IPFIRE-wall.
Segue la lista dei campi che caratterizzano un pacchetto TCP e la loro spiegazione
in vista anche di un possibile utilizzo nel contesto di un filtro di pacchetti.
- SYN
- Il flag SYN viene utilizzato per instaurare una nuova connessione.
Quando un computer desidera iniziare una nuova connessione, esso invia un pacchetto con questo flag a uno (i flag sono costituiti da un solo bit e pertanto possono assumere solo i valori zero e uno). Al contempo, il flag ACK deve essere a zero. La risposta ad una nuova connessione accettata è caratterizzata da entrambi i flag SYN e ACK a uno. In pratica, SYN a uno denota un messaggio di tipo richiesta di connessione oppure connessione accettata.
Uno scenario interessante è costituito dalla presenza di regole di stato e da una regola che vieti esplicitamente i pacchetti con il flag SYN impostato e il flag ACK a zero. In questo caso, sarebbe possibile osservare colorati di rosso tutti i tentativi di creazione di una nuova connessione. - ACK
- In aggiunta alla funzione descritta sopra, il flag ACK indica che il campo acknowledgement number nel pacchetto TCP è valido. Se ACK vale zero, tale campo è ignorato.
- PSH
- Il flag PSH (Push) indica dati di tipo push. In questo modo, il al trasmettitore è richiesto di consegnare il pacchetto all'applicazione al momento d'arrivo, senza salvarlo prima in una memoria temporanea. Probabilmente, per ragioni di efficienza, il salvataggio in una memoria temporanea (buffer) sarebbe inevitabile.
- RST
- Il campo RST (Reset) viene utilizzato per riinizializzare una connessione divenuta instabile per un problema all'host o per qualche altro motivo. Viene anche adoperato per rifiutare un pacchetto TCP malformato o una nuova connessione. Se si riceve un reset, si è certi che da qualche parte si è verificato un problema.
- FIN
- Il flag FIN e' impostato al valore uno per chiudere una connessione e specifica che il trasmittente non ha altri dati da inviare.
- URG
- Il campo URG (Urgent pointer) indica che è presente uno scostamento (offset) in bytes, dal numero di sequenza, a partire dal quale il ricevente dovrebbe trovare dati urgenti. Per il significato dei numeri di sequenza, si veda la bibliografia.
Altri campi delle regole.
Dispositivo di rete
IPFIRE-wall può filtrare pacchetti anche in dipendenza del dispositivo di rete
dal quale essi sono in arrivo o in partenza.
Nella direzione di INPUT, PREROUTING o FORWARD si può specificare un
dispositivo d'ingresso, mentre in OUTPUT, POSTROUTING o ancora
in FORWARD è possibile indicare un dispositivo d'uscita.
Se nessun dispositivo di rete è presente in una regola, allora il kernel
non controllerà il nome del dispositivo coinvolto nel pacchetto considerato.
Diamo un nome ad una regola.
L'utente, al momento dell'inserimento di una nuova regola in IPFIRE-wall, può
assegnare a quest'ultima un semplice nome (di venti caratteri al massimo), che
verrà stampato dalla console quando un pacchetto corrisponde alla regola
stessa. Questo rende possibile all'utilizzatore ricordare facilmente la regola che
viene utilizzata, senza dover ispezionare attentamente tutti i campi tipici del
protocollo di rete per risalire al significato della norma applicata.
Il supporto per i nomi alle regole deve essere compilato in kernel
e nei moduli in
userspace . Si leggano le istruzioni per il
programma in userspace e per i moduli
del kernel (in inglese) per ulteriori informazioni.
BIBLIOGRAFIA.
Andrew S. Tanenbaum Reti di Computer (Computer Networks),
Terza edizione.