Introduzione ai firewall

Perché usare i firewall?

Il termine firewall usato per descrivere un filtro di rete deriva dal nome con cui vengono chiamate quelle barriere fisiche separatrici che impediscono al fuoco di diffondersi da un'area all'altra, usate ad esempio dai vigili del fuoco. I filtri di rete vengono chiamati firewall perchè il loro compito è similare: impedire, entro certi limiti, gli attacchi di cracker che possono carpire o distruggere i vostri dati o provocare attacchi tipo di rifiuto del servizio (Denial of Service, DoS), ossia cercano di sovraccaricare le risorse di elaborazione (riempire il disco, intasare la connessione internet, ecc.)

Occorre subito precisare che non è sufficiente avere un firewall, anche se ben configurato, per risolvere tutti i problemi di sicurezza, e né si può pensare che installare un firewall renda inutili i backup di sicurezza dei dati, che conviene sempre programmare opportunamente, indipendentemente da quanto sia ristretta la politica di sicurezza adottata, perché rappresentano l'unico modo di tutelarsi da guasti o distruzione dell'hardware. Similmente avere un firewall non basta a risolvere il problema dello spam, che sussiste tutte le volte che la vostra rete consente la ricezione delle email, o quello dei virus, per cui si rende ancora necessario usare del software anti-virus e tenerlo aggiornato per una migliore protezione. Il più alto livello di sicurezza consiste nell'impedire qualsiasi tipo di traffico di rete, bloccandolo completamente (o equivalentemente staccando la spina del cavo di rete). Ovviamente questo non è praticabile perché sarebbe inutile avere una connessione ad internet. Nel configurare un firewall si può partire con una regola che blocca tutto e poi inserire man mano le regole che servono a far passare tutto e solo il traffico che si desidera passi. Questo è un buon metodo per essere quanto più possibili restrittivi e lo adotteremo in seguito quando faremo un esempio di firewall software.

Nonostante i suoi limiti, il firewall può essere una componente molto importante per controllare l'utilizzo di una rete forzando una politica di sicurezza prestabilita.

Come caso limite, invece di un'intera rete, supponiamo di avere un unico server di cui si è amministratori e responsabili e che naturalmente si vuole proteggere dalle intrusioni. Supponiamo che su questo server siano stati configurati opportunamente i servizi di rete, restringendo l'accesso quando applicabile, usando quanto più possibile protocolli sicuri (es. ssh al posto di telnet e ftp) e che l'amministratore ci lavori e stia piuttosto attento a mantenere il software aggiornato e a prendere tutte le altre misure di controllo del sistema. Potreste pensare in tal caso di non aver bisogno di un firewall. Eppure potrebbe essere lo stesso utile configurare un firewall (meglio ancora se hardware) a protezione della macchina anche in questo caso in cui la macchina è gestita da un esperto di sicurezza informatica, perché il firewall garantisce un ulteriore livello di sicurezza del sistema, che i cracker devono scavalcare. La sicurezza non è mai troppa: sempre meglio avere più livelli di sicurezza che uno soltanto.

Viceversa per proteggere le macchine della vostra rete usate da utenti inesperti di sicurezza informatica, un firewall può rivelarsi molto utile. Se avete una rete con molti utenti, e quindi molti computer che condividono una o più connessioni ad internet a banda larga (ad es. una o più linee T1 o T3), potreste non riuscire a gestire la sicurezza di ogni singolo calcolatore, anche per il semplice fatto che avete troppi calcolatori da gestire. Alcuni calcolatori potrebbero essere portatili di eventuali ospiti o di proprietà dei dipendenti e quindi su questi non avete alcun controllo. Utenti inesperti potrebbero attivare programmi server sui loro calcolatori come server Web, FTP di posta elettronica o altro che sono facilmente vulnerabili perchè non correttamente configurati, oppure sono versioni che presentato bachi ben noti e facilmente sfruttabili dai cracker. Alcuni sistemi Windows per uso client di qualche anno fa (95, 98) sono molto poco sicuri, in quanto non hanno meccanismi di controllo di ciò che un utente può fare (i cosiddetti "permessi di utente"): sono sostanzialmente sistemi monoutente in cui si lavora sempre con i permessi dell'amministratore. Qui i virus e i worm possono fare grossi danni. Le nuove versioni (2000, XP) sono più sicure, specie se usate come utente non privilegiato per tutto il lavoro quotidiano e se solo voi o collaboratori di cui vi potete fidare conoscono le password di amministratore. In ogni caso comunque chi ha l'accesso fisico alla macchina potrebbe sostituire il sistema operativo.

In questa situazione che abbiamo descritto, senza un firewall che protegga l'intera rete (un firewall posto di guardia ad ogni punto di accesso verso l'esterno), un cracker esterno potrebbe facilmente guadagnare l'accesso ad una delle vostre macchine interne ed usarla come base per penetrare su ancora altre macchine della vostra rete interna (per esempio sui server che gestiscono i servizi e le informazioni più importanti e li mettono maggiormente a disposizione delle macchine interne anziché di quelle esterne) o di altre reti esterne, usandovi come ponte per una azione criminale ai danni di terzi (di cui rischiate di essere ingiustamente accusati). In questa situazione avere un firewall ben configurato e gestito rappresenta di sicuro una necessità irrinunciabile volendo garantire un pur minimo livello di sicurezza. Il firewall dovrebbe consentire solo a quei calcolatori gestiti da esperti della sicurezza di fornire servizi di rete verso l'esterno. Nel contempo dovreste venire in contro alle esigenze degli utenti, cercando di bilanciare quanto meglio possibile sicurezza e funzionalità della vostra rete. Ad esempio gli utenti vorrebbero poter essere in grado di scaricare la posta elettronica da casa o collegarsi al file server per poter lavorare. Ci sono due soluzioni principali per permettere agli utenti di usare da remoto la rete interna: la prima è affittare da una società di telecomunicazioni delle linee dedicate dalla casa dell'utente fino al router della rete interna (generalmente è costoso); la seconda è usare le linee telefoniche, che pure possono essere costose se intervengono chiamate interurbane. Una soluzione che è sicura e conveniente consiste nel creare una rete privata virtuale (VPN), appoggiandosi ad un provider che abbia molti POP sparsi sul territorio, in modo da evitare le chiamate interurbane. Poichè si utilizza la rete pubblica occorre codificare tutte le informazioni a livello IP, creando un tunnel sicuro per far viaggiare i dati attraverso internet.

Potreste anche scegliere di porre dietro un firewall tutti i vostri client e i server che devono fornire servizi solo per la vostra rete interna, mentre mettere a monte del firewall, ossia tra il firewall e la connessione ad internet (nella cosiddetta area demilitarizzata, o DMZ Delimitarized Zone), quei server che devono fornire servizi verso l'esterno (opportunamente configurati e controllati da voi!). In questo modo evitate l'overhead del packet filtering per questi server.

I campi di applicazione dei firewall sono i più svariati, dalle piccole alle grosse reti, sia che si tratta di reti connesse ad internet oppure di reti solo private. Ad esempio potete trovare utile un firewall anche per proteggere la vostra piccola rete domestica quando vi collegate ad internet, sia che il collegamento avvenga saltuariamente tramite modem analogico e normale linea telefonica, sia se avete una connessione a banda più larga e permanente, come DSL o tramite un modem per cavo. Naturalmente una connessione permamente o usata per molte ore al giorno è più soggetta ad essere oggetto di eventuali attacchi di cracker.

Cosa può controllare un firewall? Un firewall, che può essere sia un dispositivo hardware, oppure può essere implementato via software, può filtrare e controllare le informazioni che provengono da internet verso la vostra rete privata o singolo computer. Può anche filtrare e controllare quelle che escono dalla vostra rete privata verso internet, quindi in generale un firewall può filtrare in entrambi i sensi, ossia il filtraggio riguarda sia i pacchetti in uscita che in ingresso. Il packet filtering si attua specificando una serie di regole (rules) che rappresentano la configurazione del firewall: quando un pacchetto fa corrispondenza con una regola può essere scartato o inoltrato a seconda di quello che stabilisce la regola stessa.

Oltre al packet filtering, esiste un nuovo metodo di filtraggio più fine e sofisticato, detto stateful inspection, che può essere combinato insieme al packet filtering. Questo metodo consente di generare dinamicamente delle regole di filtraggio di tipo packet filter, che hanno un certo tempo di scadenza anziché essere statiche. Il principio è semplice: quando il firewall lascia passare alcuni pacchetti di richiesta provenienti dall'interno (essendo stato abilitato a fare ciò), nel contempo salva in un database alcune informazioni fondamentali riguardanti queste richieste. I pacchetti in entrata vengono poi confrontati con queste informazioni chiave, in modo che vengano accettati solo pacchetti in ingresso che rappresentano delle risposte alla richieste inviate dagli utenti, scartando quindi le pseudo-risposte non valide.

Spesso le funzionalità di un proxy server e quelle di un firewall vengono integrate in un'unico software; i proxy sono calcolatori che recuperano le informazioni da una connessione internet in vece dei loro client a cui poi le inviano (e viceversa i client fanno al proxy le richieste esterne e questo le rifà agli host sparsi su internet in loro vece), provvedendo una cache centralizzata per ridurre il carico sulle connessioni di rete verso l'esterno e aumentare la velocità di navigazione e una qualche forma di controllo di accesso (firewall più o meno evoluto incorporato nel proxy). Inoltre un proxy può fornire procedure di autenticazione più sicure di quelle di protocolli quali telnet e ftp che fanno passare le password in chiaro.

Si può persino impedire l'accesso a siti offensivi, controllandone il contenuto e confrontandolo con una lista di parole chiave. Naturalmente in questo modo si può bloccare anche del contenuto legittimo contenente una parola chiave. Effettuare il blocco in base agli indirizzi IP dei siti vietati non è raccomandabile in quanto questi possono venire riassegnati ad enti diversi ed è difficile tenerne aggiornata la lista che sarà probabilmente molto lunga, rischiando così di bloccare dei contenuti ritenuti leciti e facendo passare invece buona parte dei contenuti da ritenersi invece illeciti. Effettuare il blocco in base ai nomi host richiede la risoluzione dei nomi tramite il protocollo dei DNS. Un firewall molto efficiente posto a protezione di un'intera rete solitamente non opera a questo livello, mentre un firewall software potrebbe avere questa feature.

Un firewall hardware è certamente più sicuro di uno software e comunque non è molto costoso. Molti router posseggono funzionalità di filtraggio, combinando così le funzioni di un router e di un firewall in un unico componente. Ricordo che un router è una macchina che effettua il forwading dei pacchetti tra due o più reti, che possono adottare anche protocolli diversi, percui il router dovrà essere in grado di effettuare una conversione nel formato dei dati. I router sono un componente fondamentale di Internet, senza di questi Internet non potrebbe esistere come rete mondiale; infatti la rete Internet è la confederazione di molte reti, e i router sono quei dispositivi che consentono a tutte queste reti di comunicare tra loro. I router sono spesso dispositivi hardware dedicati, amministrabili tramite software opportuno, ma un qualsiasi host con software opportuno che abbia almeno una connessione per ciascuna rete tra cui si vuole effettuare il routing, può agire da router software.

Protocolli TCP/IP, indirizzi IP

Per entrare nei dettagli del packet filtering occorre conoscere qualcosa riguardo la struttura dei pacchetti, secondo i protocolli standard di internet, quelli della famiglia TCP/IP. Questa vuole essere solo una introduzione senza alcuna pretesa di completezza. Spero tuttavia di essere chiaro ed aiutare a capire quello che avviene dietro la scena durante una comunicazione tra due computer attraverso una rete. I tre principali protocolli TCP/IP sono: IP (Internet Protocol) per il routing (livello di rete, o livello numero 3, della pila OSI, un modello teorico per strutturare i servizi di una rete in modo interoperabile), e TCP (Transmission Control Protocol) oppure UDP (User Datagram Protocol), entrambi per il livello di trasporto (4). La struttura dei pacchetti, a cui faremo riferimento in seguito, è la seguente:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of service|         Total length          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|        Identification         |Flags|     Fragment offset     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to live  |   Protocol    |        Header checksum        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Source address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Destination address                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Option + Padding                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig. Struttura di un pacchetto IP


 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Acknowledgment Number                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       |           |U|A|P|R|S|F|                               |
|  HL   | Reserved  |R|C|S|S|Y|I|          Window Size          |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Options + Padding                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig. Struttura di un pacchetto TCP


 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source port          |       Destination port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Length             |           Checksum            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig. Struttura di un pacchetto UDP



Tab. Riassunto del modello teorico OSI, esemplificato su internet e sulla più comune tecnologia LAN, Ethernet.
# livello descrizione apparecchiature o software protocolli o standard principali
1 physical È il livello fisico o della trasmissione binaria. Definisce la rappresentazione elettrica degli 0 e 1 binari, le massime distanze tra due nodi di uno stesso segmento di rete, la forma dei connettori, ecc.. hub Ethernet
2 datalink È il livello di accesso al mezzo di trasmissione. Individua e corregge gli errori che avvengono al livello 1. Usa tipicamente gli indirizzi MAC Ethernet per individuare ciascun host. I pacchetti di questo livello sono a lunghezza fissa e sono detti frame. switch Ethernet, ARP
3 network È il livello di rete. Si occupa del routing o instradamento dei pacchetti (IP), tramite le tabelle di routing e algoritmi di routing per la ricerca del miglior percorso. Usa tipicamente gli indirizzi IP di internet. router, sistema operativo IP
4 transport È il livello di trasporto che realizza la comunicazione host-to-host. Usa tipicamente pacchetti TCP o UDP di internet. È indipendente dalla topologia della rete e dai livelli sottostanti. TCP effettua il controllo di errore su tutto il pacchetto, non solo gli header, ma anche sui dati, e corregge gli errori richiedendo la ritrasmissione. Inoltre numera i pacchetti per preservarne l'ordine. UDP non fa niente di tutto questo, e lascia questi compiti a protocolli di livello superiore. sistema operativo TCP, UDP
5 sessione Controlla il dialogo, ovvero sincronizza e mantiene la comunicazione fra programmi applicativi che girano ciascuno sui due host che comunicano. sistema operativo (nessuno)
6 presentation È il livello della presentazione dei dati. Effettua le necessarie conversioni dei dati in un formato comune (set di caratteri, ordine nella rappresentazione binaria dei numeri, cifratura/decifratura) per consentire la comunicazione a sistemi differenti. sistema operativo rappresentazione big-endian detta anche network byte order
7 applicazione È il livello dei programmi applicativi. programmi utente HTTP, SMTP, DOMAIN (DNS protocol), FTP, TELNET

Questo modello OSI e gli esempi presentati vanno considerati come una classificazione concettuale. Nella pratica ad esempio spesso un router ha molte porte e vengono combinate le funzioni di un router e di uno switch in uno stesso dispositivo, mentre noi nel modello abbiamo considerato queste funzioni chiaramente distinte e assegnate a dispositivi separati. Oppure i livelli 6 e 7 non sono realmente completamente separati. Questo naturalmente non cambia niente su un piano concettuale. Uno dei vantaggi più importanti di questa strutturazione a livelli è che permette ai programmatori di scrivere applicazioni che operano sulla rete (livello 7) in modo indipendente dai livelli sottostanti. Questo è un grosso sollievo per il programmatore che si appoggia al sistema operativo o ad opportune librerie che fanno parte del sistema e non è costretto a supportare direttamente tutti i vari protocolli di trasporto e di routing, nonché quelli di basso livello dipendenti dal tipo di rete. Tipicamente il programmatore semplicemente sceglie se vuole usare TCP o UDP per la sua applicazione per Internet, evitando così molte delle altre complessità coinvolte.

Utilizzando per il trasporto TCP o UDP, il protocollo di livello 7 viene individuato da un cosiddetto numero di porta, che può essere lungo al più 16 bit per definizione. Questo implica che con i protocolli TCP/IP due host possono dialogare tramite al più 216-1=65535 diversi protocolli di più alto livello contemporaneamente (la porta numero 0 non è usata). Il file /etc/services(5) nei sistemi UNIX (come FreeBSD e Linux) contiene il database dei nomi dei servizi di internet in un formato testuale molto semplice: ogni riga rappresenta un servizio con al più tre campi di informazioni:

Un estratto di questo file e degli esempi di come si cerca nel database tramite grep(1):

#
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, most entries here have two entries
# even if the protocol doesn't support UDP operations.
#
# The latest IANA port assignments can be gotten from
#
#       http://www.iana.org/assignments/port-numbers
#
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
...
#
# WELL KNOWN PORT NUMBERS
#
...
ftp-data         20/tcp    #File Transfer [Default Data]
ftp-data         20/udp    #File Transfer [Default Data]
ftp              21/tcp    #File Transfer [Control]
ftp              21/udp    #File Transfer [Control]
...
telnet           23/tcp
telnet           23/udp
...
smtp             25/tcp    mail         #Simple Mail Transfer
smtp             25/udp    mail         #Simple Mail Transfer
...
domain           53/tcp    #Domain Name Server
domain           53/udp    #Domain Name Server
...
http             80/tcp    www www-http         #World Wide Web HTTP
http             80/udp    www www-http         #World Wide Web HTTP
...
$ grep -w 123 /etc/services 
ntp             123/tcp    #Network Time Protocol
ntp             123/udp    #Network Time Protocol
$ grep -w ^ssh /etc/services
ssh              22/tcp    #Secure Shell Login
ssh              22/udp    #Secure Shell Login

Fondamentale è il concetto di pacchetto (packet). I lunghi messaggi, ad esempio lunghe email o pagine web, vengono sempre divisi in pacchetti prima della trasmissione, ciascuno di una certa dimensione in byte. I pacchetti possono anche essere ricevuti non in ordine e seguire percorsi differenti sulla rete a seconda delle decisioni intelligenti dei router. Alla destinazione i driver della rete del sistema operativo riordinano i pacchetti nell'ordine giusto e quindi ricostruiscono l'intero messaggio in maniera trasparente alle applicazioni come se il packet switching non fosse avvenuto. Questo invece avviene a vari livelli (2,3,4).

Il modello OSI (Open System Interconnection) è basato sul concetto di incapsulazione dei dati. Considerate la risposta di un server web, tipicamente contenente come dato una pagina web nel linguaggio HTML (notate che questo è un linguaggio, non un protocollo! Quindi non fa parte della pila OSI). Il software che agisce come server (tra i più usati l'Apache) vi aggiunge gli header del protocollo di livello 7 HTTP, che descrivono tra le tante altre cose l'esito della richiesta, il formato della risposta secondo lo standard MIME e il set di caratteri usato (header Content-Type). Poi interviene il protocollo di trasporto TCP di livello 4: questo aggiunge altre informazioni come il numero di porta sorgente (tipicamente la 80 per il servizio http, vedi sopra estratto di services(5)), il numero di porta destinazione (che corrisponde al numero di porta sorgente nei pacchetti di richiesta), il numero di sequenza di questo pacchetto (TCP pacchettizza la risposta come abbiamo detto), un checksum per il controllo degli errori, la lunghezza del pacchetto e alcuni altri dati. Poi sarà la volta di IP, che "imbusta" il pacchetto TCP e vi aggiunge alcune informazioni importanti per il routing, come l'indirizzo IP (un numero a 32 bit) dell'host sorgente e di quello di destinazione. Eventualmente qui può verificarsi una ulteriore frammentazione del pacchetto. Infine il pacchetto diventa uno o più frame Ethernet, supponendo che siete su questo tipo di rete (che comunque è il tipo di LAN più comune). La situazione complessiva mostra che i dati sono incapsulati dai protocolli del modello OSI, a partire da quelli superiori fino a finire a quelli inferiori, come in un gioco di scatole cinesi:

Ethernet
IP
TCP
HTTP
<html>
...
</html>
Fig. Come viene incapsulato un pezzo di codice HTML

Quando il pacchetto viene ricevuto, la scheda di rete ne scarta gli header Ethernet. Gli header IP e TCP vengono invece esaminati dal kernel. Infine il vostro browser interpreta gli header HTTP e acquisisce il carico utile, i dati, ossia il testo in formato HTML. Un altro bel po' di lavoro di parsing e rendering di questo formato e verrà visualizzata la pagina web sul vostro schermo.

Quanto può essere grande in byte un pacchetto IP? Minimo ogni pacchetto IP valido dovrà essere 21 byte, perché l'header deve essere almeno 20 byte e ci deve essere almeno 1 byte di dati. La dimensione massima (header+dati) è di 65535 byte. Questo numero deriva dal fatto che la dimensione deve essere indicata in byte nel campo "Total length" dell'header. Siccome questo campo è lungo 16 bit, potrà rappresentare i numeri interi senza segno compresi tra 0 e 216-1=65535. La lunghezza zero è chiaramente un valore illegale del campo "Total length" e non viene utilizzata. 65535 byte sono 64 kbyte-1, approssimando diciamo quasi 64 kbyte, essendo 1 kbyte definito come 1024 byte. Il campo IP di 4 bit IHL sta per "IP Header Length" ed indica la dimensione dell'header. Questa deve risultare sempre multipla di 32 bit, vale a dire di 32/8=4 byte. Quindi il valore di IHL va moltiplicato per 4 byte per ottenere la dimensione in byte dell'header, oppure per 32 per ottenerne la dimensione in bit. Poiché su 4 bit posso rappresentare i numeri interi senza segno tra 0 e 24-1=15, posso avere un header IP di dimensione massima pari a 15*4=60 byte, vale a dire 15*32=60*8=480 bit. Sottraendo dal valore del campo "Total length" il valore del campo IHL dopo averli espressi nella stessa unità di misura (bit o byte), si calcola la dimensione dei dati portati come carico utile dal pacchetto IP.

Un pacchetto IP su Internet tipicamente ne contiene uno TCP (oppure UDP), anche se potrebbe contenere altri tipi di protocolli di trasporto. Il campo Protocol dell'header IP indica il tipo di protocollo incapsulato da IP in 8 bit. Questo estratto dal file database /etc/protocols mostra i numeri dei protocolli di internet più comuni:

#
# Internet protocols
#
# $FreeBSD: src/etc/protocols,v 1.13.2.3 2002/02/27 03:39:00 dd Exp $
#       from: @(#)protocols     5.1 (Berkeley) 4/17/89
#
# See also http://www.iana.org/assignments/protocol-numbers
#
ip      0       IP              # internet protocol, pseudo protocol number
...
icmp    1       ICMP            # internet control message protocol
...
tcp     6       TCP             # transmission control protocol
...
udp     17      UDP             # user datagram protocol
...

Siccome come abbiamo visto il protocollo IP registra la dimensione totale del pacchetto e quella dell'header, permettendo di calcolare per semplice sottrazione la dimensione del pacchetto TCP che contiene, questa informazione non viene registrata in nessun campo nel pacchetto TCP, perché sarebbe ridondante e occuperebbe spazio in bit prezioso per inserire altre informazioni più utili, cioè non già presenti ai livelli inferiori. Il campo TCP HL (Header Length), detto anche Offset indica invece la lunghezza dell'header TCP, che come nel caso dell'header IP è variabile tra un massimo e un minimo. Anche questo valore è espresso in multipli di 32 bit (4 byte) esattamente come nel campo IHL di IP. Possiamo adesso calcolare la dimensione massima di un pacchetto TCP, come il massimo carico dei dati che un pacchetto IP può portare, cioè:

dimensione massima del pacchetto IP - dimensione minima dell'header IP
= 65535-20
= 65515 byte

Questa dimensione dipende quindi dal protocollo di rete su cui TCP si appoggia (tipicamente IP su internet). Tenendo conto che un header TCP minimo (quando non viene usato il campo delle opzioni) dovrà essere lungo 20 byte (come un header IP), la dimensione massima del carico utile (dati) trasportato da un singolo pacchetto TCP è 65515-20=65495 byte.

Per quanto riguarda UDP, ha un header di dimensione fissa pari ad 8 byte, in quanto non può contenere ulteriori opzioni. Tanto per riempire l'header arrivando a un multiplo di 32 bit (4 byte), è stato inserito il campo Length che indica la lunghezza complessiva del pacchetto UDP (header+dati) in byte. Sottraendo 8 da questo campo si ottiene la lunghezza dei dati.

Occorre osservare comunque che eventuali limiti dei protocolli di livello 2 riguardo la dimensione dei pacchetti non permettono di avere incapsulati pacchetti IP molto grossi. Un frame Ethernet ad esempio non può essere più grande di 1518 bytes.

Per quanto riguarda gli indirizzi IP di sorgente e destinazione presenti nell'header IP, questi sono lunghi 32 bit (4 byte) ciascuno. Questo significa che ci sono 232=4,294,967,296 indirizzi differenti. Sono più di 4 miliardi. Ogni macchina che vuole far parte di internet deve avere un indirizzo differente, ma come vedremo tra poco non tutti questi indirizzi possono essere usati come indirizzi di un host facente parte della grande rete. Questo secondo la versione 4 di IP (detta IPv4), che è ancora quella maggiormente impiegata al momento in cui scrivo. Ogni indirizzo IP va pensato diviso in due parti: la prima parte è un indirizzo di un'intera rete, mentre la restante indica un host (detto anche nodo) di quella rete. Poichè il sistema binario è prolisso e non è agevole, si può usare il sistema esadecimale per esprimere un indirizzo IP. Ogni cifra esadecimale corrisponde ad un gruppo di 4 cifre binarie, cosa che semplifica la traduzione da binario a esadecimale e viceversa: basta avere una tabella che indichi la corrispondenza tra le 16 cifre esadecimali e i numeri binari di 4 cifre (detti anche nibble o mezzo byte) che indicano la stessa quantità.


Tab. Tabella per la conversione semplificata binario<->esadecimale
cifra esadecimale numero binario
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
A 1010
B 1011
C 1100
D 1101
E 1110
F 1111
1010 0000   0110 0001   0001 1000   1011 1010
 A    0      6    1      1    8      B    A
   160         97          24          186
Fig. Vari modi equivalenti di esprimere uno stesso indirizzo IP

La notazione più usata, e capita dai programmi di utente, ad esempio i browser web, consiste nel fare una conversione indiretta in decimale prendendo le cifre binarie a gruppi di 8 (ottetti) o quelle esadecimali a gruppi di 2. Anziché usare degli spazi per separare i vari gruppi di cifre decimali ottenuti si usa il punto. Per l'esempio precedente si scrive:

160.97.24.186
e questa viene detta notazione decimale puntata.

La tabella seguente indica gli indirizzi IP che possono essere assegnati agli host e come vengono divisi in classi:


Tab. Le tre classi principali degli indirizzi IP
class A
net id first octet
host id last three octets
default netmask 255.0.0.0
first octet range 1-126 (00000001-01111110)
total host IP addresses (126-1+1)*(224-2)=2,130,706,178
class B
net id first two octets
host id last two octets
default netmask 255.255.0.0
first octet range 128-191 (10000000-10111111)
total host IP addresses (191-128+1)*28*(216-2)=1,073,709,056
class C
net id first three octets
host id last octet
default netmask 255.255.255.0
first octet range 192-223 (11000000-11011111)
total host IP addresses (223-192+1)*216*(28-2)=532,676,608

Ad esempio l'indirizzo 160.97.24.186, poiché il primo ottetto è nel range 128-191, è un indirizzo di classe B. I primi due ottetti, 160.97, rappresentano l'indirizzo della rete, mentre gli ultimi due restanti, 24.186, rappresentano l'indirizzo dell'host.

L'indirizzo 0.0.0.0 è riservato per indicare l'host stesso su cui viene utilizzato. L'indirizzo IP 255.255.255.255 viene invece usato per i broadcast, cioè per mandare un pacchetto a tutti i computer della rete a cui appartiene l'host su cui viene utilizzato. Esistono altre due classi, la D e la E che sono usate per il multicast e per scopi sperimentali. L'indirizzo IP 127.0.0.1 viene usato per l'interfaccia di loopback lo(4). Questa è una interfaccia di rete software. Tramite questa interfaccia virtuale un host può mandare messaggi solo a se stesso. Viene usata per testare o sviluppare software di rete anche su un calcolatore non connesso a nessuna rete, oppure per la comunicazione locale:

$ ifconfig lo0
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet 127.0.0.1 netmask 0xff000000 

Gli indirizzi IP vengono assegnati alle organizzazioni che vogliono connettersi alla rete internet da alcune autorità che ne assicurano l'unicità di assegnazione su base mondiale e mantengono una base di dati con tutte le informazioni riguardo la registrazione. Occorre pagare una tassa per mantenere l'assegnazione. Per maggiori informazioni consultate il sito della Registration Authority Italiana.

In passato alle maggiori organizzazioni veniva assegnato un intero pool di indirizzi di classe A, vale a dire 224-2, ovvero un pool di circa 224 indirizzi (più di sedici milioni). A causa di questo spreco, vista l'enorme espansione che ha la rete internet, gli indirizzi IP liberi hanno cominciato a scarseggiare. Onde evitare di rimanere in poco tempo senza indirizzi liberi per soddisfare le nuove richieste, da qualche tempo non viene più assegnata un'intera rete di classe A e nemmeno di classe B, ma solo parti degli indirizzi di queste classi, che vengono così condivise tra diverse organizzazioni, ciascuna con la propria rete. Quindi non è detto che una classe corrisponda ad una sola organizzazione.

Sorge spontanea una domanda: visto che una certa classe non corrisponde più ad una singola rete, ma può corrispondere a moltissime reti, come fanno queste reti a comunicare tra loro? O meglio, come fa il router che gestisce la connessione ad internet di ogni rete a sapere se un pacchetto che porta quel numero di rete condiviso è un pacchetto diretto ad una macchina locale, della stessa rete, oppure deve essere diretto verso un altra rete esterna?

Occorre che ciascuna rete specifichi una netmask (detta anche subnet mask o maschera di sottorete) diversa da quella di default della classe di appartenenza. Ad esempio supponiamo che vi sia stato assegnato l'indirizzo di classe B 173.21 ma che vi siano stato concesso di usare soltanto il pool di numeri disponibili per l'indirizzo 173.21.89 (in tutto 254 indirizzi di host differenti, numerati da 1 a 254). Ad un'altra organizzazione invece è stato concesso di usare il pool di numeri 173.21.90 (prendiamo solo due organizzazioni per semplicità).

Per indicare che il vostro numero di rete è formato dai primi 3 ottetti anziché dai primi 2, dovete specificare al router che la maschera della vostra rete è 255.255.255.0 invece di 255.255.0.0 e altrettando dovrà fare l'altra organizzazione che condivide parte della stessa classe B insieme a voi. In questo modo se ad esempio mandate un pacchetto con indirizzo IP sorgente 173.21.89.56 (host numero 56 della vostra rete) e indirizzo destinazione 173.21.90.87 (host numero 87 dell'altra rete), il router sa che la destinazione è su internet, in quanto fa l'and logico di ciascun indirizzo con la netmask 255.255.255.0 e trova due indirizzi di rete differenti (la rete 173.21.89 e la rete 173.21.90). Se usate erroneamente la netmask di default 255.255.0.0, avrete che gli indirizzi di rete ricavati dal router sarebbero 173.21 e 173.21, ossia il mittente e il destinatario stanno sulla stessa rete, il che è sbagliato. Per evitare errori di routing, occorre impostare la netmask corretta.

Ci sono due notazioni in uso per indicare la netmask. Quella che abbiamo visto è nello stile puntato di un indirizzo IP. L'altra consiste nell'indicare il numero di bit che devono essere settati pari ad 1 a partire dal bit più significativo. Si usa separare l'indicazione della netmask dall'indirizzo IP a cui si riferisce tramite uno slash, mentre si usano i due punti per separare l'indirizzo IP e la netmask quando entrambi sono in notazione dotted. La notazione con / può essere usata solo per le maschere che sono composte da una sequenza iniziale di 1 seguita da una sequenza finale di zero e quindi non è una notazione generale come quella dotted.

173.21.89.56/16
173.21.89.56:255.255.0.0

173.21.89.56/24
173.21.89.56:255.255.255.0

Un'altra soluzione che evita di dover richiedere molti indirizzi IP consiste nell'usare il range degli indirizzi privati per la maggior parte o tutti i calcolatori della propria rete in congiunzione con la tecnica del Network Address Translation (NAT), di solito usata solo per i client, ma niente vieta di usarla, con qualche limitazione anche per i server.

Per ciascuna delle tre classi di reti A,B,C, esistono infatti dei numeri di rete pluriuso, ossia un range di indirizzi IP appartenenti a quella classe che sono privati. Possono essere usati liberamente per reti private senza il vincolo dell'unicità in quanto host con tali indirizzi non fanno realmente parte di internet, o meglio non possono essere connessi direttamente alla rete. Anche la scelta della classe è arbitraria.


Tab. Indirizzi IP privati
class net ids total host IP addresses
A 10.0.0.0 224-2=16,777,214
B 172.16.0.0
.
.
172.31.0.0
(31-16+1)*(216-2)=1,048,544
C 192.168.0.0
.
.
192.168.255.0
(255-0+1)*(28-2)=65024

Altre misure per risparmiare indirizzi IP consistono nell'assegnazione dinamica. Solo un server ha bisogno di un indirizzo statico, vale a dire che cambi raramente. Se vi collegate ad un ISP con un comune modem, vi viene assegnato un indirizzo IP pubblico tra quelli che l'ISP ha acquisito. Questo indirizzo viene mantenuto durante tutta la sessione, finché non vi sconnettete. Ma la prossima volta che vi collegate con ogni probabilità vi sarà assegnato un indirizzo diverso. In questo modo l'ISP ha bisogno di un indirizzo IP per ogni modem che si collega e non per ciascun utente. Gli utenti infatti non si collegheranno tutti contemporaneamente e probabilmente non potrebbero se sono molti in quanto troverebbero la linea occupata.

Il nuovo standard IPv6 prevede molte feature in più e indirizzi di 128 bit contro i soli 32 bit di IPv4, è già supportato dalla quasi totalità del software (sistemi operativi e applicazioni, FreeBSD e Linux compresi), ma la transizione sarà lenta a causa dell'hardware che è meno facile e più costoso da adattare.

Un'altra questione è che è difficile ricordarsi o digitare correttamente gli indirizzi IP per un utente umano (si tratta di digitare numeri che per noi non hanno alcun senso ed è facile sbagliarsi; dovreste farlo per ciascun sito che vi interessa. Potreste costruirvi voi un elenco che metta in corrispondenza indirizzo IP con il nome del sito, magari gestendolo elettronicamente, ma potreste non avere l'elenco con voi e non lo potete accedere tramite Internet. Inoltre l'indirizzo IP di un sito che vi interessa potrebbe cambiare (ad es. perché il sito ha cambiato provider) e non sareste più in grado di ritrovarlo facilmente. Il problema viene risolto associando agli indirizzi IP dei server dei nomi di dominio molto più leggibili.

Capite subito che conviene che la lista dei nomi di dominio e gli indirizzi IP corrispondenti sia gestita in modo centralizzato. Nei primi tempi, quando internet era composta da pochi host, il Network Information Server manteneva e metteva a disposizione di tutti un file di testo che mappava i nomi host agli indirizzi IP. Ma c'era un problema: con l'espansione di Internet, questo file diventava sempre più grande e difficile da gestire; ognuno doveva farsi una copia una tantum e quindi c'erano molte copie in circolazione, tutte diverse tra loro e i server principali che ne distribuivano la versione ufficiale erano soggetti a sovraccarico per le troppe richieste. Nel 1983 venne elaborato un sistema gerarchico, distribuito e del tutto automatico, che risolse il problema: viene chiamato DNS (Domain Name System).

Cattura dei pacchetti di una sessione TCP con tcpdump

L'utility tcpdump(1) viene fornita col sistema base di FreeBSD e naturalmente è disponibile anche per Linux. Serve per catturare i pacchetti che transitano su una interfaccia di rete di tipo broadcast come Ethernet. Essa pone la scheda di rete in modalità promiscua. In questo modo la NIC legge anche quei frame Ethernet che portano un indirizzo MAC di destinazione diverso da quello della scheda stessa, e questi possono essere salvati su disco per poi essere analizzati con calma. Per catturare i pacchetti in FreeBSD occorre che l'utente che lancia tcpdump(1) abbia il permesso di lettura sul pseudo-dispositivo /dev/bpf* che corrisponde alla interfaccia da cui si vuole catturare. Solo il root può operare sui dispositivi bpf (Berkeley Packet Filter), a meno che non cambiate i permessi di questi file di dispositivo (non raccomandabile):

$ ls -l /dev/bpf*
crw-------  1 root  wheel   23,   0 Apr 26 18:54 /dev/bpf0
crw-------  1 root  wheel   23,   1 Apr 26 18:54 /dev/bpf1
crw-------  1 root  wheel   23,   2 Apr 26 18:54 /dev/bpf2
crw-------  1 root  wheel   23,   3 Apr 26 18:54 /dev/bpf3

Anche in Linux il modo più semplice di utilizzare tcpdump è di disporre dell'accesso di root.

Ho operato su una rete molto semplice, quella formata dal mio computer desktop, chiamato ninuzzo (192.168.1.1) e il mio portatile detto dolly (192.168.1.3), collegati tramite due NIC Ethernet ed un cavo UTP (Unshielded Twisted Pair, doppino non schermato) di tipo cross, che ad esempio potete farvi costruire in un negozio di materiale elettrico. Per cavi da maneggiare continuamente è consigliabile scegliere conduttori di tipo trefolato, cioè con conduttore non in rame pieno ma composto da tanti fili intrecciati. Il motivo è che hanno una maggiore resistenza meccanica. I conduttori in rame pieno invece sono più rigidi e quindi adatti per cablaggi fissi e potrebbero spezzarsi se deformati troppo e frequentemente.

Su ninuzzo gira il server web Apache, sulla porta standard 80. dolly agisce come client e tramite il comando fetch(1) di FreeBSD (ma potete usare anche un qualsiasi altro browser come lynx(1), mozilla o firefox oppure una utility come wget(1), tutti disponibili anche per Linux) richiede la pagina web indice dell'host ninuzzo, che è la seguente:

ant@dolly $ fetch http://ninuzzo/
Receiving fetch.out (147 bytes): 100%
147 bytes transferred in 0.0 seconds (455.80 kBps)
ant@dolly $ cat fetch.out
<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Hello page</title>
</head>
<body>
<p>Hello everybody!</p>
</body>
</html>

Prima di dare questo comando su dolly, ho attivato sul server ninuzzo il tcpdump(1), chiedendogli di salvare i pacchetti in formato binario su un file chiamato dump (altrimenti tpcdump(1) li elabora e li mostra su stdout):

root@ninuzzo # tcpdump -s0 -w dump
tcpdump: listening on ed0
^C
13 packets received by filter
0 packets dropped by kernel

Per default tcpdump(1) continua a catturare i pacchetti finché non viene interrotto da un segnale SIGINT, interattivamente generabile premendo il carattere di interruzione, per default control-C. tcpdump(1) intercetta questo segnale, finalizza la scrittura del file dati, stampa un resoconto del numero di pacchetti filtrati, che in questo caso coincide con quello dei pacchetti catturati e il numero di pacchetti persi (vedi descrizione opzione -s in seguito, comunque non ne ho perso nessuno in questo caso).

Sulla prima consolle virtuale appaiono dei messaggi che indicano in che modo si trova la scheda di rete:

ed0: promiscuous mode enabled
...
ed0: promiscuous mode disabled

In caso avete più interfacce di rete configurate usate l'opzione -i di tcpdump(1), seguita dal nome del file dispositivo dell'interfaccia. Se il parametro -i viene omesso tcpdump(1) seleziona l'interfaccia di numero minore tra quelle configurate e attive, fermando la ricerca nella lista delle interfacce non appena ne trova una (nel mio caso trova ed0 che è quella giusta e perciò ho omesso il parametro -i).

Potete usare il comando ifconfig(1) per visualizzare le informazioni su tutte le interfacce di rete disponibili nel sistema, con indicazione se sono configurate e come sono configurate. Ad esempio nel mio caso su ninuzzo ottengo:

ant@ninuzzo $ ifconfig 
ed0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
        ether 00:50:bf:4f:13:82
lp0: flags=8810<POINTOPOINT,SIMPLEX,MULTICAST> mtu 1500
ppp0: flags=8010<POINTOPOINT,MULTICAST> mtu 1500
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet 127.0.0.1 netmask 0xff000000 

ed0 è la prima interfaccia Ethernet. Ho una vecchia scheda Ethernet PCI da 10 Mbps:

ant@ninuzzo $ dmesg | grep ed0
ed0: <NE2000 PCI Ethernet (RealTek 8029)> port 0xe400-0xe41f irq 11 at device 10.0 on pci0
ed0: address 00:50:bf:4f:13:82, type NE2000 (16 bit) 

lp0 è l'interfaccia della porta parallela, che non è attiva. ppp0 è l'interfaccia della porta seriale che uso per connettermi ad internet tramite un comune modem analogico esterno; lo0 è il dispositivo di loopback descritto prima, che è configurato e attivo.

Se avessi due schede di rete che usano lo stesso driver ed, ad esempio stessa marca e modello, una sarebbe indicata con ed0 e l'altra con ed1. Il numero indica l'ordine con cui il kernel rileva la scheda durante il boot.

Notate le varie informazioni che riguardano ed0. UP significa che l'interfaccia è configurata e pronta a funzionare. inet 192.168.1.1 indica che all'interfaccia è stato assegnato l'indirizzo IP di Internet 192.168.1.1 (la mia piccola rete di soli due computer è la rete privata 192.168.1.0, di classe C). netmask 0xffffff00 indica la subnet mask in notazione esadecimale (notazioni equivalenti: 192.168.1.1/24, 255.255.255.0). broadcast 192.168.1.255 è appunto l'indirizzo di broadcast della mia rete. Il MAC address della mia scheda su ninuzzo è 00:50:bf:4f:13:82. Questo è unico al mondo. I primi tre byte indicano la ditta che ha costruito la scheda, gli ultime tre il numero seriale della scheda.

Per quanto riguarda l'opzione -s di tcpdump, questa indica quanti byte di dati catturare partendo dall'inizio di ogni pacchetto. Il valore di default in FreeBSD è 68 byte, che è un valore adeguato se si è interessati agli header dei protocolli IP, ICMP, TCP e UDP (in Linux invece il default è 0, quindi potrebbe essere omessa). Ricordate infatti che la massima lunghezza di un header TCP o IP è di 60 byte, la minima di 20. Poiché vogliamo catturare i pacchetti completi del carico dati, specifichiamo per -s il valore massimo di lunghezza di un frame Ethernet, oppure 0 che cattura i pacchetti interamente, indipendentemente dalla loro lunghezza, o meglio fino ad a 65535 byte (se i pacchetti catturati sono tanti e passano velocemente tcpdump potrebbe non farcela e perdere qualche pacchetto, ma non è il nostro caso poiché nella nostra rete ci sono solo due computer e abbiamo attivato una sola sessione TCP/IP con scambio di pochi pacchetti).

root@ninuzzo # ls -l dump 
-rw-r--r--  1 root  wheel  1581 Jul  3 16:12 dump
root@ninuzzo # file dump
dump: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)

Per trasformare il dump in un formato leggibile occorre usare l'opzione -r di tcpdump(1), che in tal caso non effettua alcuna lettura ed agisce da filtro per trasformare un formato binario in uno testuale. Quindi non occorre essere root:

ant@ninuzzo $ tcpdump -enx -r dump

L'opzione -e indica di stampare anche gli header dei protocolli di livello 2 data-link (link-level header). L'opzione -n indica di lasciare numerici gli indirizzi di host e i numeri di porta invece di convertirli in nomi. L'opzione -x indica di stampare in esadecimale il pacchetto (ma non viene incluso il link level header). Il formato è spiegato in tcpdump(1).

18:43:35.886469 0:e0:4b:39:5:e1 ff:ff:ff:ff:ff:ff 0806 60: arp who-has 192.168.1.1 (1:1:0:0:0:0) tell 192.168.1.3
             0001 0800 0604 0001 00e0 4b39 05e1 c0a8
             0103 0101 0000 0000 c0a8 0101 0000 0000
             0000 0000 0000 0000 0000 0000 0000
18:43:35.886602 0:50:bf:4f:13:82 0:e0:4b:39:5:e1 0806 60: arp reply 192.168.1.1 is-at 0:50:bf:4f:13:82
             0001 0800 0604 0002 0050 bf4f 1382 c0a8
             0101 00e0 4b39 05e1 c0a8 0103 0000 0000
             0000 0000 0000 0000 0000 0000 0000
18:43:35.886811 0:e0:4b:39:5:e1 0:50:bf:4f:13:82 0800 74: 192.168.1.3.1025 > 192.168.1.1.80: S 382635771:382635771(0) win 57344 <mss 1460,nop,wscale 0,nop,nop,timestamp 23643 0> (DF)
             4500 003c 000a 4000 4006 b75d c0a8 0103
             c0a8 0101 0401 0050 16ce 8efb 0000 0000
             a002 e000 e13c 0000 0204 05b4 0103 0300
             0101 080a 0000 5c5b 0000 0000
18:43:35.886991 0:50:bf:4f:13:82 0:e0:4b:39:5:e1 0800 74: 192.168.1.1.80 > 192.168.1.3.1025: S 1502088555:1502088555(0) ack 382635772 win 57344 <mss 1460,nop,wscale 0,nop,nop,timestamp 23202 23643> (DF)
             4500 003c 0006 4000 4006 b761 c0a8 0101
             c0a8 0103 0050 0401 5988 0d6b 16ce 8efc
             a012 e000 1f96 0000 0204 05b4 0103 0300
             0101 080a 0000 5aa2 0000 5c5b
18:43:35.887234 0:e0:4b:39:5:e1 0:50:bf:4f:13:82 0800 66: 192.168.1.3.1025 > 192.168.1.1.80: . ack 1 win 57920 <nop,nop,timestamp 23643 23202> (DF)
             4500 0034 000b 4000 4006 b764 c0a8 0103
             c0a8 0101 0401 0050 16ce 8efc 5988 0d6c
             8010 e240 491a 0000 0101 080a 0000 5c5b
             0000 5aa2
18:43:35.887413 0:e0:4b:39:5:e1 0:50:bf:4f:13:82 0800 82: 192.168.1.3.1025 > 192.168.1.1.80: P 1:17(16) ack 1 win 57920 <nop,nop,timestamp 23643 23202> (DF)
             4500 0044 000c 4000 4006 b753 c0a8 0103
             c0a8 0101 0401 0050 16ce 8efc 5988 0d6c
             8018 e240 776b 0000 0101 080a 0000 5c5b
             0000 5aa2 4745 5420 2f20 4854 5450 2f31
             2e31 0d0a
18:43:35.983561 0:50:bf:4f:13:82 0:e0:4b:39:5:e1 0800 66: 192.168.1.1.80 > 192.168.1.3.1025: . ack 17 win 57920 <nop,nop,timestamp 23212 23643> (DF)
             4500 0034 0007 4000 4006 b768 c0a8 0101
             c0a8 0103 0050 0401 5988 0d6c 16ce 8f0c
             8010 e240 4900 0000 0101 080a 0000 5aac
             0000 5c5b
18:43:35.983908 0:e0:4b:39:5:e1 0:50:bf:4f:13:82 0800 134: 192.168.1.3.1025 > 192.168.1.1.80: P 17:85(68) ack 1 win 57920 <nop,nop,timestamp 23653 23212> (DF)
             4500 0078 000d 4000 4006 b71e c0a8 0103
             c0a8 0101 0401 0050 16ce 8f0c 5988 0d6c
             8018 e240 2b81 0000 0101 080a 0000 5c65
             0000 5aac 486f 7374 3a20 6e69 6e75 7a7a
             6f0d 0a55 7365 722d 4167 656e 743a 2066
             6574 6368 206c 6962 6665 7463 682f 322e
             300d 0a43 6f6e 6e65 6374 696f 6e3a 2063
             6c6f 7365 0d0a 0d0a
18:43:35.987400 0:50:bf:4f:13:82 0:e0:4b:39:5:e1 0800 469: 192.168.1.1.80 > 192.168.1.3.1025: P 1:404(403) ack 85 win 57920 <nop,nop,timestamp 23212 23653> (DF)
             4500 01c7 0008 4000 4006 b5d4 c0a8 0101
             c0a8 0103 0050 0401 5988 0d6c 16ce 8f50
             8018 e240 edeb 0000 0101 080a 0000 5aac
             0000 5c65 4854 5450 2f31 2e31 2032 3030
             204f 4b0d 0a44 6174 653a 2054 6875 2c20
             3033 204a 756c 2032 3030 3320 3136 3a34
             333a 3335 2047 4d54 0d0a 5365 7276 6572
             3a20 4170 6163 6865 2f31 2e33 2e32 3720
             2855 6e69 7829 2050 4850 2f34 2e33 2e31
             0d0a 4c61 7374 2d4d 6f64 6966 6965 643a
             2057 6564 2c20 3032 204a 756c 2032 3030
             3320 3230 3a30 313a 3037 2047 4d54 0d0a
             4554 6167 3a20 2232 6434 3031 2d39 332d
             3366 3033 3361 3033 220d 0a41 6363 6570
             742d 5261 6e67 6573 3a20 6279 7465 730d
             0a43 6f6e 7465 6e74 2d4c 656e 6774 683a
             2031 3437 0d0a 436f 6e6e 6563 7469 6f6e
             3a20 636c 6f73 650d 0a43 6f6e 7465 6e74
             2d54 7970 653a 2074 6578 742f 6874 6d6c
             0d0a 0d0a 3c21 444f 4354 5950 4520 6874
             6d6c 2050 5542 4c49 4320 222d 2f2f 4945
             5446 2f2f 4454 4420 4854 4d4c 2032 2e30
             2f2f 454e 223e 0a3c 6874 6d6c 3e0a 3c68
             6561 643e 0a3c 7469 746c 653e 4865 6c6c
             6f20 7061 6765 3c2f 7469 746c 653e 0a3c
             2f68 6561 643e 0a3c 626f 6479 3e0a 3c70
             3e48 656c 6c6f 2065 7665 7279 626f 6479
             213c 2f70 3e0a 3c2f 626f 6479 3e0a 3c2f
             6874 6d6c 3e0a 0a
18:43:35.987567 0:50:bf:4f:13:82 0:e0:4b:39:5:e1 0800 66: 192.168.1.1.80 > 192.168.1.3.1025: F 404:404(0) ack 85 win 57920 <nop,nop,timestamp 23212 23653> (DF)
             4500 0034 0009 4000 4006 b766 c0a8 0101
             c0a8 0103 0050 0401 5988 0eff 16ce 8f50
             8011 e240 471e 0000 0101 080a 0000 5aac
             0000 5c65
18:43:35.988005 0:e0:4b:39:5:e1 0:50:bf:4f:13:82 0800 66: 192.168.1.3.1025 > 192.168.1.1.80: . ack 405 win 57521 <nop,nop,timestamp 23653 23212> (DF)
             4500 0034 000e 4000 4006 b761 c0a8 0103
             c0a8 0101 0401 0050 16ce 8f50 5988 0f00
             8010 e0b1 48ad 0000 0101 080a 0000 5c65
             0000 5aac
18:43:35.991046 0:e0:4b:39:5:e1 0:50:bf:4f:13:82 0800 66: 192.168.1.3.1025 > 192.168.1.1.80: F 85:85(0) ack 405 win 57920 <nop,nop,timestamp 23653 23212> (DF)
             4500 0034 000f 4000 4006 b760 c0a8 0103
             c0a8 0101 0401 0050 16ce 8f50 5988 0f00
             8011 e240 471d 0000 0101 080a 0000 5c65
             0000 5aac
18:43:35.991123 0:50:bf:4f:13:82 0:e0:4b:39:5:e1 0800 66: 192.168.1.1.80 > 192.168.1.3.1025: . ack 86 win 57920 <nop,nop,timestamp 23212 23653> (DF)
             4500 0034 000a 4000 4006 b765 c0a8 0101
             c0a8 0103 0050 0401 5988 0f00 16ce 8f51
             8010 e240 471d 0000 0101 080a 0000 5aac
             0000 5c65

Se pensate che questo formato sia illegibile, potete aiutarvi con una versione di tcpdump(1) grafica, che si chiama tcpview(1) e va installata a parte. tcpview(1) sostituisce tcpdump(1), ed è certamente più facile da usare, ma potete anche usare tcpdump(1) per la cattura su file e poi caricare il file salvato in tcpview(1) ed analizzarlo più comodamente:

$ tcpview dump
Una schermata di tcpview
Fig. Il primo pacchetto catturato come visto tramite tcpview

Un'altra utility per stampare l'output di tcpdump(1) in formato più comprensibile è tcpshow(1). In particolare l'opzione -verbose produce un output prolisso, ma molto chiaro, in quanto di ogni campo viene sempre ripetuta la descrizione:

$ tcpshow -verbose <dump |less

---------------------------------------------------------------------------
Packet 1
    Timestamp:          18:43:35.886469
    Source Ethernet Address:    00:E0:4B:39:05:E1 (<unknown>)
    Destination Ethernet Address:   FF:FF:FF:FF:FF:FF (<unknown>)
    Encapsulated Protocol:      ARP
ARP Header
    Hardware Type:          Ethernet
    Protocol Type:          IP
    Hardware Address Length:    6 bytes
    Protocol Address Length:    4 bytes
    Operation:          ARP request
    Sender Hardware Address:    00:E0:4B:39:05:E1 (<unknown>)
    Sender IP Address:      192.168.1.3 (dolly)
    Target Hardware Address:    01:01:00:00:00:00 (<unknown>)
    Target IP Address:      192.168.1.1 (ninuzzo)

---------------------------------------------------------------------------
Packet 2
    Timestamp:          18:43:35.886602 (0.000133)
    Source Ethernet Address:    00:50:BF:4F:13:82 (<unknown>)
    Destination Ethernet Address:   00:E0:4B:39:05:E1 (<unknown>)
    Encapsulated Protocol:      ARP
ARP Header
    Hardware Type:          Ethernet
    Protocol Type:          IP
    Hardware Address Length:    6 bytes
    Protocol Address Length:    4 bytes
    Operation:          ARP response
    Sender Hardware Address:    00:50:BF:4F:13:82 (<unknown>)
    Sender IP Address:      192.168.1.1 (ninuzzo)
    Target Hardware Address:    00:E0:4B:39:05:E1 (<unknown>)
    Target IP Address:      192.168.1.3 (dolly)

---------------------------------------------------------------------------
Packet 3
    Timestamp:          18:43:35.886811 (0.000209)
    Source Ethernet Address:    00:E0:4B:39:05:E1 (<unknown>)
    Destination Ethernet Address:   00:50:BF:4F:13:82 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        60 bytes
    Identification:         0x000A
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB75D
    Source IP Address:      192.168.1.3 (dolly)
    Destination IP Address:     192.168.1.1 (ninuzzo)
TCP Header
    Source Port:            1025 (blackjack)
    Destination Port:       80 (http)
    Sequence Number:        0382635771
    Acknowledgement Number:     0000000000
    Header Length:          40 bytes (data=0)
    Flags:              URG=off, ACK=off, PSH=off
                    RST=off, SYN=on,  FIN=off
    Window Advertisement:       57344 bytes
    Checksum:           0xE13C
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>

---------------------------------------------------------------------------
Packet 4
    Timestamp:          18:43:35.886991 (0.000180)
    Source Ethernet Address:    00:50:BF:4F:13:82 (<unknown>)
    Destination Ethernet Address:   00:E0:4B:39:05:E1 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        60 bytes
    Identification:         0x0006
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB761
    Source IP Address:      192.168.1.1 (ninuzzo)
    Destination IP Address:     192.168.1.3 (dolly)
TCP Header
    Source Port:            80 (http)
    Destination Port:       1025 (blackjack)
    Sequence Number:        1502088555
    Acknowledgement Number:     0382635772
    Header Length:          40 bytes (data=0)
    Flags:              URG=off, ACK=on,  PSH=off
                    RST=off, SYN=on,  FIN=off
    Window Advertisement:       57344 bytes
    Checksum:           0x1F96
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>

---------------------------------------------------------------------------
Packet 5
    Timestamp:          18:43:35.887234 (0.000243)
    Source Ethernet Address:    00:E0:4B:39:05:E1 (<unknown>)
    Destination Ethernet Address:   00:50:BF:4F:13:82 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        52 bytes
    Identification:         0x000B
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB764
    Source IP Address:      192.168.1.3 (dolly)
    Destination IP Address:     192.168.1.1 (ninuzzo)
TCP Header
    Source Port:            1025 (blackjack)
    Destination Port:       80 (http)
    Sequence Number:        0382635772
    Acknowledgement Number:     1502088556
    Header Length:          32 bytes (data=0)
    Flags:              URG=off, ACK=on,  PSH=off
                    RST=off, SYN=off, FIN=off
    Window Advertisement:       57920 bytes
    Checksum:           0x491A
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>

---------------------------------------------------------------------------
Packet 6
    Timestamp:          18:43:35.887413 (0.000179)
    Source Ethernet Address:    00:E0:4B:39:05:E1 (<unknown>)
    Destination Ethernet Address:   00:50:BF:4F:13:82 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        68 bytes
    Identification:         0x000C
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB753
    Source IP Address:      192.168.1.3 (dolly)
    Destination IP Address:     192.168.1.1 (ninuzzo)
TCP Header
    Source Port:            1025 (blackjack)
    Destination Port:       80 (http)
    Sequence Number:        0382635772
    Acknowledgement Number:     1502088556
    Header Length:          32 bytes (data=16)
    Flags:              URG=off, ACK=on,  PSH=on
                    RST=off, SYN=off, FIN=off
    Window Advertisement:       57920 bytes
    Checksum:           0x776B
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    GET / HTTP/1.1.
    

---------------------------------------------------------------------------
Packet 7
    Timestamp:          18:43:35.983561 (0.096148)
    Source Ethernet Address:    00:50:BF:4F:13:82 (<unknown>)
    Destination Ethernet Address:   00:E0:4B:39:05:E1 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        52 bytes
    Identification:         0x0007
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB768
    Source IP Address:      192.168.1.1 (ninuzzo)
    Destination IP Address:     192.168.1.3 (dolly)
TCP Header
    Source Port:            80 (http)
    Destination Port:       1025 (blackjack)
    Sequence Number:        1502088556
    Acknowledgement Number:     0382635788
    Header Length:          32 bytes (data=0)
    Flags:              URG=off, ACK=on,  PSH=off
                    RST=off, SYN=off, FIN=off
    Window Advertisement:       57920 bytes
    Checksum:           0x4900
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>

---------------------------------------------------------------------------
Packet 8
    Timestamp:          18:43:35.983908 (0.000347)
    Source Ethernet Address:    00:E0:4B:39:05:E1 (<unknown>)
    Destination Ethernet Address:   00:50:BF:4F:13:82 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        120 bytes
    Identification:         0x000D
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB71E
    Source IP Address:      192.168.1.3 (dolly)
    Destination IP Address:     192.168.1.1 (ninuzzo)
TCP Header
    Source Port:            1025 (blackjack)
    Destination Port:       80 (http)
    Sequence Number:        0382635788
    Acknowledgement Number:     1502088556
    Header Length:          32 bytes (data=68)
    Flags:              URG=off, ACK=on,  PSH=on
                    RST=off, SYN=off, FIN=off
    Window Advertisement:       57920 bytes
    Checksum:           0x2B81
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    Host: ninuzzo.
    User-Agent: fetch libfetch/2.0.
    Connection: close.
    .
    

---------------------------------------------------------------------------
Packet 9
    Timestamp:          18:43:35.987400 (0.003492)
    Source Ethernet Address:    00:50:BF:4F:13:82 (<unknown>)
    Destination Ethernet Address:   00:E0:4B:39:05:E1 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        455 bytes
    Identification:         0x0008
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB5D4
    Source IP Address:      192.168.1.1 (ninuzzo)
    Destination IP Address:     192.168.1.3 (dolly)
TCP Header
    Source Port:            80 (http)
    Destination Port:       1025 (blackjack)
    Sequence Number:        1502088556
    Acknowledgement Number:     0382635856
    Header Length:          32 bytes (data=403)
    Flags:              URG=off, ACK=on,  PSH=on
                    RST=off, SYN=off, FIN=off
    Window Advertisement:       57920 bytes
    Checksum:           0xEDEB
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    HTTP/1.1 200 OK.
    Date: Thu, 03 Jul 2003 16:43:35 GMT.
    Server: Apache/1.3.27 (Unix) PHP/4.3.1.
    Last-Modified: Wed, 02 Jul 2003 20:01:07 GMT.
    ETag: "2d401-93-3f033a03".
    Accept-Ranges: bytes.
    Content-Length: 147.
    Connection: close.
    Content-Type: text/html.
    .
    <!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
    <html>
    <head>
    <title>Hello page</title>
    </head>
    <body>
    <p>Hello everybody!</p>
    </body>
    </html>
    
    

---------------------------------------------------------------------------
Packet 10
    Timestamp:          18:43:35.987567 (0.000167)
    Source Ethernet Address:    00:50:BF:4F:13:82 (<unknown>)
    Destination Ethernet Address:   00:E0:4B:39:05:E1 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        52 bytes
    Identification:         0x0009
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB766
    Source IP Address:      192.168.1.1 (ninuzzo)
    Destination IP Address:     192.168.1.3 (dolly)
TCP Header
    Source Port:            80 (http)
    Destination Port:       1025 (blackjack)
    Sequence Number:        1502088959
    Acknowledgement Number:     0382635856
    Header Length:          32 bytes (data=0)
    Flags:              URG=off, ACK=on,  PSH=off
                    RST=off, SYN=off, FIN=on
    Window Advertisement:       57920 bytes
    Checksum:           0x471E
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>

---------------------------------------------------------------------------
Packet 11
    Timestamp:          18:43:35.988005 (0.000438)
    Source Ethernet Address:    00:E0:4B:39:05:E1 (<unknown>)
    Destination Ethernet Address:   00:50:BF:4F:13:82 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        52 bytes
    Identification:         0x000E
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB761
    Source IP Address:      192.168.1.3 (dolly)
    Destination IP Address:     192.168.1.1 (ninuzzo)
TCP Header
    Source Port:            1025 (blackjack)
    Destination Port:       80 (http)
    Sequence Number:        0382635856
    Acknowledgement Number:     1502088960
    Header Length:          32 bytes (data=0)
    Flags:              URG=off, ACK=on,  PSH=off
                    RST=off, SYN=off, FIN=off
    Window Advertisement:       57521 bytes
    Checksum:           0x48AD
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>

---------------------------------------------------------------------------
Packet 12
    Timestamp:          18:43:35.991046 (0.003041)
    Source Ethernet Address:    00:E0:4B:39:05:E1 (<unknown>)
    Destination Ethernet Address:   00:50:BF:4F:13:82 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        52 bytes
    Identification:         0x000F
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB760
    Source IP Address:      192.168.1.3 (dolly)
    Destination IP Address:     192.168.1.1 (ninuzzo)
TCP Header
    Source Port:            1025 (blackjack)
    Destination Port:       80 (http)
    Sequence Number:        0382635856
    Acknowledgement Number:     1502088960
    Header Length:          32 bytes (data=0)
    Flags:              URG=off, ACK=on,  PSH=off
                    RST=off, SYN=off, FIN=on
    Window Advertisement:       57920 bytes
    Checksum:           0x471D
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>

---------------------------------------------------------------------------
Packet 13
    Timestamp:          18:43:35.991123 (0.000077)
    Source Ethernet Address:    00:50:BF:4F:13:82 (<unknown>)
    Destination Ethernet Address:   00:E0:4B:39:05:E1 (<unknown>)
    Encapsulated Protocol:      IP
IP Header
    Version:            4
    Header Length:          20 bytes
    Service Type:           0x00
    Datagram Length:        52 bytes
    Identification:         0x000A
    Flags:              MF=off, DF=on
    Fragment Offset:        0
    TTL:                64
    Encapsulated Protocol:      TCP
    Header Checksum:        0xB765
    Source IP Address:      192.168.1.1 (ninuzzo)
    Destination IP Address:     192.168.1.3 (dolly)
TCP Header
    Source Port:            80 (http)
    Destination Port:       1025 (blackjack)
    Sequence Number:        1502088960
    Acknowledgement Number:     0382635857
    Header Length:          32 bytes (data=0)
    Flags:              URG=off, ACK=on,  PSH=off
                    RST=off, SYN=off, FIN=off
    Window Advertisement:       57920 bytes
    Checksum:           0x471D
    Urgent Pointer:         0
    <Options not displayed>
TCP Data
    <No data>
---------------------------------------------------------------------------

Una volta presa confidenza con i vari campi potete usare il formato di default di tcpshow(1) che è più compatto:

$ tcpshow <dump

---------------------------------------------------------------------------
Packet 1
TIME:   18:43:35.886469
LINK:   00:E0:4B:39:05:E1 -> FF:FF:FF:FF:FF:FF type=ARP
ARP:    htype=Ethernet ptype=IP hlen=6 plen=4 op=request
    sender-MAC-addr=00:E0:4B:39:05:E1 sender-IP-address=dolly
    target-MAC-addr=01:01:00:00:00:00 target-IP-address=ninuzzo

---------------------------------------------------------------------------
Packet 2
TIME:   18:43:35.886602 (0.000133)
LINK:   00:50:BF:4F:13:82 -> 00:E0:4B:39:05:E1 type=ARP
ARP:    htype=Ethernet ptype=IP hlen=6 plen=4 op=response
    sender-MAC-addr=00:50:BF:4F:13:82 sender-IP-address=ninuzzo
    target-MAC-addr=00:E0:4B:39:05:E1 target-IP-address=dolly

---------------------------------------------------------------------------
Packet 3
TIME:   18:43:35.886811 (0.000209)
LINK:   00:E0:4B:39:05:E1 -> 00:50:BF:4F:13:82 type=IP
  IP:   dolly -> ninuzzo hlen=20 TOS=00 dgramlen=60 id=000A
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B75D
 TCP:   port blackjack -> http seq=0382635771 ack=0000000000
    hlen=40 (data=0) UAPRSF=000010 wnd=57344 cksum=E13C urg=0
DATA:   <No data>

---------------------------------------------------------------------------
Packet 4
TIME:   18:43:35.886991 (0.000180)
LINK:   00:50:BF:4F:13:82 -> 00:E0:4B:39:05:E1 type=IP
  IP:   ninuzzo -> dolly hlen=20 TOS=00 dgramlen=60 id=0006
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B761
 TCP:   port http -> blackjack seq=1502088555 ack=0382635772
    hlen=40 (data=0) UAPRSF=010010 wnd=57344 cksum=1F96 urg=0
DATA:   <No data>

---------------------------------------------------------------------------
Packet 5
TIME:   18:43:35.887234 (0.000243)
LINK:   00:E0:4B:39:05:E1 -> 00:50:BF:4F:13:82 type=IP
  IP:   dolly -> ninuzzo hlen=20 TOS=00 dgramlen=52 id=000B
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B764
 TCP:   port blackjack -> http seq=0382635772 ack=1502088556
    hlen=32 (data=0) UAPRSF=010000 wnd=57920 cksum=491A urg=0
DATA:   <No data>

---------------------------------------------------------------------------
Packet 6
TIME:   18:43:35.887413 (0.000179)
LINK:   00:E0:4B:39:05:E1 -> 00:50:BF:4F:13:82 type=IP
  IP:   dolly -> ninuzzo hlen=20 TOS=00 dgramlen=68 id=000C
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B753
 TCP:   port blackjack -> http seq=0382635772 ack=1502088556
    hlen=32 (data=16) UAPRSF=011000 wnd=57920 cksum=776B urg=0
DATA:   GET / HTTP/1.1.
    

---------------------------------------------------------------------------
Packet 7
TIME:   18:43:35.983561 (0.096148)
LINK:   00:50:BF:4F:13:82 -> 00:E0:4B:39:05:E1 type=IP
  IP:   ninuzzo -> dolly hlen=20 TOS=00 dgramlen=52 id=0007
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B768
 TCP:   port http -> blackjack seq=1502088556 ack=0382635788
    hlen=32 (data=0) UAPRSF=010000 wnd=57920 cksum=4900 urg=0
DATA:   <No data>

---------------------------------------------------------------------------
Packet 8
TIME:   18:43:35.983908 (0.000347)
LINK:   00:E0:4B:39:05:E1 -> 00:50:BF:4F:13:82 type=IP
  IP:   dolly -> ninuzzo hlen=20 TOS=00 dgramlen=120 id=000D
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B71E
 TCP:   port blackjack -> http seq=0382635788 ack=1502088556
    hlen=32 (data=68) UAPRSF=011000 wnd=57920 cksum=2B81 urg=0
DATA:   Host: ninuzzo.
    User-Agent: fetch libfetch/2.0.
    Connection: close.
    .
    

---------------------------------------------------------------------------
Packet 9
TIME:   18:43:35.987400 (0.003492)
LINK:   00:50:BF:4F:13:82 -> 00:E0:4B:39:05:E1 type=IP
  IP:   ninuzzo -> dolly hlen=20 TOS=00 dgramlen=455 id=0008
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B5D4
 TCP:   port http -> blackjack seq=1502088556 ack=0382635856
    hlen=32 (data=403) UAPRSF=011000 wnd=57920 cksum=EDEB urg=0
DATA:   HTTP/1.1 200 OK.
    Date: Thu, 03 Jul 2003 16:43:35 GMT.
    Server: Apache/1.3.27 (Unix) PHP/4.3.1.
    Last-Modified: Wed, 02 Jul 2003 20:01:07 GMT.
    ETag: "2d401-93-3f033a03".
    Accept-Ranges: bytes.
    Content-Length: 147.
    Connection: close.
    Content-Type: text/html.
    .
    <!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
    <html>
    <head>
    <title>Hello page</title>
    </head>
    <body>
    <p>Hello everybody!</p>
    </body>
    </html>
    
    

---------------------------------------------------------------------------
Packet 10
TIME:   18:43:35.987567 (0.000167)
LINK:   00:50:BF:4F:13:82 -> 00:E0:4B:39:05:E1 type=IP
  IP:   ninuzzo -> dolly hlen=20 TOS=00 dgramlen=52 id=0009
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B766
 TCP:   port http -> blackjack seq=1502088959 ack=0382635856
    hlen=32 (data=0) UAPRSF=010001 wnd=57920 cksum=471E urg=0
DATA:   <No data>

---------------------------------------------------------------------------
Packet 11
TIME:   18:43:35.988005 (0.000438)
LINK:   00:E0:4B:39:05:E1 -> 00:50:BF:4F:13:82 type=IP
  IP:   dolly -> ninuzzo hlen=20 TOS=00 dgramlen=52 id=000E
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B761
 TCP:   port blackjack -> http seq=0382635856 ack=1502088960
    hlen=32 (data=0) UAPRSF=010000 wnd=57521 cksum=48AD urg=0
DATA:   <No data>

---------------------------------------------------------------------------
Packet 12
TIME:   18:43:35.991046 (0.003041)
LINK:   00:E0:4B:39:05:E1 -> 00:50:BF:4F:13:82 type=IP
  IP:   dolly -> ninuzzo hlen=20 TOS=00 dgramlen=52 id=000F
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B760
 TCP:   port blackjack -> http seq=0382635856 ack=1502088960
    hlen=32 (data=0) UAPRSF=010001 wnd=57920 cksum=471D urg=0
DATA:   <No data>

---------------------------------------------------------------------------
Packet 13
TIME:   18:43:35.991123 (0.000077)
LINK:   00:50:BF:4F:13:82 -> 00:E0:4B:39:05:E1 type=IP
  IP:   ninuzzo -> dolly hlen=20 TOS=00 dgramlen=52 id=000A
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=B765
 TCP:   port http -> blackjack seq=1502088960 ack=0382635857
    hlen=32 (data=0) UAPRSF=010000 wnd=57920 cksum=471D urg=0
DATA:   <No data>
---------------------------------------------------------------------------

Scarica il file dump di questo esempio.

Notate che il protocollo TCP prevede una procedura di connessione che ha tre stati (three-way handshake), caratterizzati da precisi valori dei suoi bit di controllo. I passi sono i seguenti:

  1. Il chiamante (chi inizia la connessione) setta solo il bit SYN(chronize) nel primo pacchetto, che serve solo a tentare una connessione e non ha dati. Il campo acknowledgement vale 0, il campo sequence viene inizializzato dal chiamante ad un certo valore.
  2. Il destinatario risponde con un pacchetto che ha settati solo i due bit SYN e ACK, inizializza il proprio numero di sequenza di questa sessione, ovvero si sincronizza anche lui. Si setta anche l'ACK per indicare che il primo pacchetto è stato ricevuto. Il campo acknowledgement conterrà il valore di sequenza del primo pacchetto + 1. Anche questo pacchetto è privo di dati.
  3. Adesso il chiamante deve solo confermare con un pacchetto col solo bit ACK che ha ricevuto il pacchetto precedente dal destinatario. Il campo acknowledgement viene posto pari al numero di sequenza del pacchetto ricevuto dal destinatario + 1. Il campo sequence ha il valore che aveva al punto 1 + 1. Il pacchetto è privo di dati.

Il campo TCP di sequence rappresenta un numero che viene assegnato ad ogni pacchetto in modo da poter mettere in corrispondenza le richieste con le risposte, anche quando si gestiscono molte connessioni TCP differenti. Come vedete dal nostro esempio non è detto che venga incrementato sempre di 1. Osservate che i pacchetti possono anche avere lo stesso numero di sequenza e di ack (ad es. il pacchetto 5 e 6; questi due pacchetti potrebbero anche essere fusi in uno). L'incremento di un numero di sequenza può essere maggiore di 1.

Il campo TCP di acknowledgement rappresenta il numero di sequenza del prossimo pacchetto atteso dall'altro computer per la connessione TCP a cui il pacchetto si riferisce.

Nel nostro esempio i pacchetti numerati come 3,4,5 costituiscono la procedura di handshake di TCP. Osservateli attentamente per ritrovare quello che abbiamo detto.

Dovreste essere in grado di continuare l'analisi di tutti i pacchetti da soli. Notate la procedura usata per chiudere la connessione: in questo caso è il server che, dopo aver trasmesso tutti i dati della risposta HTTP, col pacchetto 10 setta il flag FIN chiedendo di chiudere la connessione (in generale entrambi i soggetti della comunicazione possono farlo). dolly risponde con un pacchetto di ack (il numero 11), per indicare che ha ricevuto il pacchetto 10. Poi manda un altro pacchetto, il 12, con lo stesso seq number e ack dell'11, ma con settati i bit A e F. Avendo settato il suo bit F, indica che è daccordo a chiudere la connessione. Con l'ultimo pacchetto, il numero 13, il server ninuzzo conferma col bit A che ha ricevuto il pacchetto 12 e a questo punto la sessione TCP termina.

Un altro aspetto da notare è che i pacchetti 6, 8 e 9 settano il bit PSH (o PUSH, abbreviato in P da tcpshow). Quando il campo PSH è off, per ragioni di efficienza, TCP opera la bufferizzazione dei dati ricevuti. Questo vuol dire che i dati vengono consegnati all'applicazione a blocchi di dimensione opportuna, piuttosto che così come arrivano pacchetto per pacchetto. La presenza del buffer in alcuni casi però può essere un problema ed impedire la corretta sincronizzazione tra client e server. Ad esempio se la richiesta GET del protocollo HTTP mandata dal client dolly al server ninuzzo tramite il pacchetto 6 venisse bufferizzata e il buffer non fosse mai consegnato al server web Apache su ninuzzo, in quanto non ha raggiunto una dimensione opportuna, si avrebbe uno stato di blocco. Infatti il client resterebbe in attesa del risultato della richiesta, risultato che non arriverebbe mai in quanto il server non ha mai ricevuto la richiesta! Quando il bit PSH è settato in un pacchetto fa sì che i dati trasmessi col pacchetto stesso vengano consegnati all'applicazione subito dopo che il pacchetto è stato ricevuto.

Questo dimostra come il protocollo TCP realizzi una connessione a due vie (duplex) con ottime proprietà: dal punto di vista delle applicazioni che usano TCP, i pacchetti arrivano nell'ordine in cui sono inviati e senza errori. Se invece usate UDP non c'è alcuna garanzia che i pacchetti arrivino nell'ordine sequenziale in cui sono mandati, possono arrivare in ordine diverso e nemmeno che arrivino, qualcuno potrebbe perdersi e il protocollo UDP non fa niente per recuperarlo. Se un pacchetto UDP arriva, sarà error-free (se viene usato il campo Checksum dell'header UDP possiamo stabilire se si sono verificati errori o meno). A differenza di TCP, UDP non prevede l'instaurarsi di una connessione (non ci sono i campi sequence e acknowledgement o i vari flag come ACK); i protocolli di ordine superiore basati su UDP se vogliono devono implementare un meccanismo di acknowledgement; una tecnica molto semplice è quella basata su un timeout: si continua ad inviare un pacchetto UDP finché non si riceve un altro pacchetto di acknowledge (sempre nel formato stabilito dal protocollo superiore) entro un certo tempo prefissato dall'invio del pacchetto.

Un problema di questa tecnica si verifica nello scenario seguente: il pacchetto di dati viene correttamente ricevuto, ma quello di ack atteso dal mittente viene ricevuto con errori o peggio viene del tutto perduto. Il mittente, non potendo essere sicuro che il pacchetto sia stato ricevuto, scaduto il timeout, lo rispedisce. Supponendo che anche questa seconda copia del pacchetto venga ricevuta correttamente, il destinatario si ritrova ora con due pacchetti identici. Per fortuna la soluzione è semplice: il destinatario deve essere in grado di accorgersi che si tratta di un duplicato (ad es. tramite il fatto che il numero di sequenza è lo stesso dell'ultimo pacchetto correttamente ricevuto e consegnato) e non passare il pacchetto al livello superiore.

Condizioni di filtro

In generale con un firewall potete filtrare in base a condizioni che riguardano:

Osservate che non c'è alcun legame stretto tra i protocolli di livello 7 e i numeri di porta; ad esempio anche se la porta predefinita per il servizio HTTP è la 80, potete far ascoltare il server (ad es. Apache) anche su qualsiasi altra porta non utilizzata per un altro servizio. L'unica differenza è che questo numero di porta andrà specificato negli URL, non essendo quello di default. Ad esempio se invece della 80 usate la porta 8000:

$ fetch -o local-index.html http://localhost:8000
Receiving local-index.html (147 bytes): 100%
147 bytes transferred in 0.0 seconds (188.66 kBps)

Esempio di firewall software con kernel FreeBSD

Il kernel di FreeBSD permette di implementare un firewall software di tipo packet filter e/o stateful inspection, con funzioni di accounting del traffico di rete (che noi per non complicare troppo non descriveremo). Il kernel non copre le funzioni di proxy, esistono molte altre applicazioni di terze parti che potete installare a parte a questo scopo (una è squid). Il modulo del kernel che svolge questa funzione è chiamato ipfw(4) (che ovviamente sta per IP firewall). L'interfaccia utente sul modulo ipfw(4) è implementata tramite il programma di controllo ipfw(8). Questa permette di definire le regole o ottenere la lista delle regole definite. Anche il kernel di Linux offre funzionalità simili, che non saranno descritte qui. Consultate il riferimento 4.

Faremo un esempio molto semplice di firewall per proteggere una singola macchina, senza combinare il firewalling con la tecnica del network address translation NAT. Il nostro firewall non opererà alcuna trasformazione negli header del pacchetto, deciderà solo se scartare o meno i pacchetti senza mai modificarli (semplice filtraggio). I dettagli sono relativi alla versione 5 di FreeBSD.

ipfw lavora su una lista di regole (detta anche catena di regole o rule chain). Ogni regola è numerata similmente ad una linea di codice del vecchio linguaggio BASIC. Per ogni pacchetto il codice del firewall software scandisce l'insieme di regole, alla ricerca di una regola che fa corrispondenza con i contenuti dell'header del pacchetto. Appena trovata la corrispondenza viene eseguita l'azione specificata con la regola. Ci limiteremo a descrivere le seguenti azioni:

action (alias) descrizione
unreach host scarta i pacchetti che fanno corrispondenza con questa regola, e tenta di avvertire il mittente di questo fatto, mandando un avviso di host non raggiungibile tramite il protocollo ICMP. Similmente unreach port significa porta non raggiungibile.
deny (drop) scarta il pacchetto, senza mandare al mittente alcun messaggio ICMP. In questo modo al sorgente sembrerà che il pacchetto non è mai arrivato a destinazione, senza capire perché.
allow (accept, pass, permit) fa passare il pacchetto come se il firewall non ci fosse.
Tab. Le tre azioni principali di ipfw

Per tutte queste tre azioni, la ricerca della rule da applicare viene terminata al primo match. La ricerca nelle regole avviene nell'ordine crescente in cui sono numerate, quindi l'ordine con cui si specificano le regole è molto importante.

Per abilitare il firewall durante la fase di boot del sistema, inserite questa linea in /etc/rc.conf:

firewall_enable="YES"

Se il kernel non contiene compilato il supporto per la costruzione di firewall con ipfw, verrà caricato tale supporto come modulo del kernel tramite il comando kldload ipfw dallo script di inizializzazione del servizio di firewalling /etc/rc.d/ipfw. Per semplicità non descriverò i dettagli di come compilare il supporto per ipfw nel kernel, e la configurazione di default che si può stabilire in questa fase (trovate tutto descritto nelle note per la configurazione del kernel in /usr/src/sys/conf/NOTES e nella manpage ipfw(4)).

Tramite l'utility sysctl(8) l'amministratore può controllare lo stato del kernel e in particolare i nomi delle variabili che riguardano il firewalling sono:

$ sysctl -aN | grep -w fw
net.inet.ip.fw.enable
net.inet.ip.fw.autoinc_step
net.inet.ip.fw.one_pass
net.inet.ip.fw.debug
net.inet.ip.fw.verbose
net.inet.ip.fw.verbose_limit
net.inet.ip.fw.dyn_buckets
net.inet.ip.fw.curr_dyn_buckets
net.inet.ip.fw.dyn_count
net.inet.ip.fw.dyn_max
net.inet.ip.fw.static_count
net.inet.ip.fw.dyn_ack_lifetime
net.inet.ip.fw.dyn_syn_lifetime
net.inet.ip.fw.dyn_fin_lifetime
net.inet.ip.fw.dyn_rst_lifetime
net.inet.ip.fw.dyn_udp_lifetime
net.inet.ip.fw.dyn_short_lifetime
net.inet.ip.fw.dyn_keepalive

Per impostare queste variabili automaticamente al boot a valori diversi da quelli di default consultare la manpage sysctl.conf(5). Alcune opzioni si possono settare anche come parametri in rc.conf(5). Ad esempio per abilitare il logging dei pacchetti attraverso syslogd(8), potete usare il comando di shell:

# sysctl net.inet.ip.fw.verbose=1
oppure appendere a sysctl.conf(5) la linea:
net.inet.ip.fw.verbose=1
o ancora aggiungere a rc.conf la riga:
firewall_logging="YES"

Un altro parametro da inserire nel file di configurazione globale del sistema /etc/rc.conf è firewall_type. Ci sono alcuni tipi di firewall predefiniti, molto facili da usare, supportati dallo script che configura le regole di firewalling al boot /etc/rc.firewall. I valori di firewall_type sono commentati appunto in /etc/rc.firewall:

############
# Define the firewall type in /etc/rc.conf.  Valid values are:
#   open     - will allow anyone in
#   client   - will try to protect just this machine
#   simple   - will try to protect a whole network
#   closed   - totally disables IP services except via lo0 interface
#   UNKNOWN  - disables the loading of firewall rules.
#   filename - will load the rules in the given filename (full path required)
#
# For ``client'' and ``simple'' the entries below should be customized
# appropriately.

Se invece volete creare le vostre regole, salvatele in un file di testo, ad esempio in /etc/ipfw.rules e specificate questo come valore del parametro firewall_type, in quanto in effetti avete creato un nuovo tipo di firewall.

State attenti a non chiudervi completamente, specialmente se state configurando il firewall via ssh invece che alla consolle, in quanto la politica di default di ipfw, cioè quando non avete alcuna line firewall_type in /etc/rc.conf è la seguente:

# ipfw list
65535 deny ip from any to any

Con questa sola regola (che porta il numero più alto possibile, 65535, quindi è posta nell'ultima posizione della lista) nessun pacchetto IP potrà mai entrare od uscire!

Descriverò la configurazione che si ottiene aggiungendo le due righe seguenti in rc.conf(5):

firewall_enable="YES"
firewall_type="client"

Prima di riavviare il sistema, editate rc.firewall, cambiando queste righe come opportuno per riflettere la configurazione di rete che avete:

# set these to your network and netmask and ip
net="192.0.2.0"
mask="255.255.255.0"
ip="192.0.2.1"

Nel mio caso, avendo fatto le prove sul computer ninuzzo già descritto prima a proposito dell'uso di tcpdump(1), ho i seguenti valori:

# set these to your network and netmask and ip
net="192.168.1.0"
mask="255.255.255.0"
ip="192.168.1.1"

Al prossimo boot vedrete, subito dopo l'inizializzazione delle interfacce di rete, nuovi messaggi da parte del kernel e degli script di avvio, simili ai seguenti:

ipfw2 initialized, divert disabled, rule-based forwarding disabled, default to d
eny, logging disabled
Flushed all rules.
00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
00400 allow ip from 192.168.1.1 to 192.168.1.0/24
00500 allow ip from 192.168.1.0/24 to 192.168.1.1
00600 allow tcp from any to any established
00700 allow ip from any to any frag
00800 allow tcp from any to 192.168.1.1 dst-port 25 setup
00900 allow tcp from 192.168.1.1 to any setup
01000 deny tcp from any to any setup
01100 allow udp from 192.168.1.1 to any dst-port 53 keep-state
01200 allow udp from 192.168.1.1 to any dst-port 123 keep-state
Firewall rules loaded, starting divert daemons:.
net.inet.ip.fw.enable: 1 -> 1

Potete rivedere le regole in ogni momento col seguente comando (dato da root):

# ipfw list
00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
00400 allow ip from 192.168.1.1 to 192.168.1.0/24
00500 allow ip from 192.168.1.0/24 to 192.168.1.1
00600 allow tcp from any to any established
00700 allow ip from any to any frag
00800 allow tcp from any to 192.168.1.1 dst-port 25 setup
00900 allow tcp from 192.168.1.1 to any setup
01000 deny tcp from any to any setup
01100 allow udp from 192.168.1.1 to any dst-port 53 keep-state
01200 allow udp from 192.168.1.1 to any dst-port 123 keep-state
65535 deny ip from any to any

Il formato (non generale per semplicità) di tutte queste regole è di questo tipo:

rule: index action protocol addresses [option]

Tab. I valori del campo protocol usati nell'esempio di firewall per proteggere una sola macchina
protocol significato in una rule
all, ip qualsiasi protocollo IP, ovvero qualsiasi tipo di pacchetto IP
tcp corrisponde ad un pacchetto TCP
udp fa corrispondenza con un pacchetto udp

Il formato (ancora semplificando, vedere ipfw(8) per i dettagli) del campo address e dei suoi sottocampi è questo:

address: from src to dst
src and dst: ip-address [port]
ip-address: any | numeric-ip | addr/masklen

Tab. Significato delle opzioni usate nell'esempio di firewall
option significato
established Fa corrispondenza con i pacchetti TCP che hanno impostato il bit RST oppure ACK.
frag Fa fare corrispondenza alla regola a quei pacchetti che sono frammenti e non sono il primo frammento di un datagramma IP (come fa a sapere che non si tratta del primo frammento? Il campo IP Offset, che indica la posizione dei dati del frammento nel pacchetto IP originale è diverso da zero per tutti gli altri frammenti di un datagramma tranne il primo). Perché questa regola è necessaria? Perché i pacchetti che fanno match grazie a questa opzione, non possono fare match con delle regole che ispezionano i dati di header TCP o UDP, in quanto l'header TCP o UDP sarà tipicamente presente solo nel primo frammento.
keep-state È questa opzione che permette di implementare la logica con stati. Se la regola che ha questa opzione fa corrispondenza con un pacchetto, il firewall creerà una regola dinamica, il cui comportamento di default è quello di permettere la comunicazione bidirezionale solo tra i due IP e le due porte sorgente e destinazione del pacchetto che ha fatto match. Le regole dinamiche hanno un tempo di vita (lifetime) limitato (controllato dalle variabili di sysctl(8)). Tuttavia il timeout viene reimpostato ogni volta che un pacchetto fa match con la regola dinamica e questo meccanismo permette di allungare i tempi di vita finché necessario. Il set delle regole dinamiche viene controllato appena si incontra la prima regola statica che ha questa opzione keep-state, oppure l'opzione limit o check-state. Questo meccanismo delle regole dinamiche permette di aprire il firewall su domanda solo a traffico legittimo.
setup Fa corrispondenza con i pacchetti TCP che hanno impostato il bit SYN ma non il bit ACK. Questi sono i pacchetti della fase 1 della procedura di handshake a 3 fasi di TCP.
via specifica l'interfaccia allo scopo di fare corrispondenza solo con i pacchetti che provengono da questa interfaccia; per default le regole si applicano a tutte le interfacce.
00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
Queste regole sono le più appropriate per l'interfaccia virtuale di loopback.
00400 allow ip from 192.168.1.1 to 192.168.1.0/24
Abilita tutto il traffico in uscita dal mio computer a qualsiasi altro host della mia rete LAN.
00500 allow ip from 192.168.1.0/24 to 192.168.1.1
Questa regola fa passare qualsiasi tipo di traffico proveniente da un IP della mia rete LAN 192.168.1. verso l'IP del mio computer con firewall 192.168.1.1, ossia abilito tutto il traffico in entrata dalla mia stessa LAN.
00600 allow tcp from any to any established
Questa regola fa passare il traffico di tipo TCP se la fase di setup della connessione è stata già effettuata con successo.
00700 allow ip from any to any frag
Fa passare i pacchetti IP frammentati.
00800 allow tcp from any to 192.168.1.1 dst-port 25 setup
Permette a chiunque di iniziare una connessione TCP per recapitare la posta elettronica all'host 192.168.1.1. Se sul vostro host non è in ascolto sulla porta 25 un MTA (ad es. sendmail(8), exim(8), qmail, ecc.), commentate il comando che aggiunge questa linea in /etc/rc.firewall
00900 allow tcp from 192.168.1.1 to any setup
Permette di iniziare connessioni TCP solo in uscita.
01000 deny tcp from any to any setup
Disabilita il setup di tutte le altre connessioni TCP.
01100 allow udp from 192.168.1.1 to any dst-port 53 keep-state
Solitamente per interrogare un DNS si usa UDP e non TCP. Ricordate che UDP è un protocollo senza stato, e quindi non può creare una connessione virtuale. Questa regola permette di iniziare una connessione udp sulla porta 53 (quella del servizio dns) a qualsiasi server DNS (volendo potreste restringere ulteriormente inserendo gli ip dei server DNS della vostra rete). Se iniziate una connessione ad un DNS verrà installata una regola dinamica per consentire alla risposta di passare attraverso il firewall.
01200 allow udp from 192.168.1.1 to any dst-port 123 keep-state
Questa regola è del tutto simile alla precedente. Permette di fare delle query NTP (Network Time Protocol) per sincronizzare il proprio orologio con quello di qualsiasi servente NTP del mondo.
65535 deny ip from any to any
Se nessuna altra regola con numero inferiore ha fatto corrispondenza, questa regola scarta il pacchetto. Questa regola ha il numero indice più elevato possibile, cioè è sempre l'ultima e viene detta regola di default.

Notate infine che le regole vengono applicate sia ai pacchetti in entrata che in uscita. Il parametro (o opzione) in fa sì che una regola sia applicata solo ai pacchetti in entrata, mentre il suo inverso out la applica solo ai pacchetti in uscita. Per default è come se ci fossero specificate entrambe (in out).

Approfondimenti:

  1. FreeBSD Handbook, Firewalls
  2. Manpage firewall(7) in FreeBSD
  3. Appunti di informatica libera, Introduzione ai concetti di firewall e di NAT/PAT
  4. Kernel Linux 2.4 e 2.6: firewall
  5. protocols.com