25.3.1 Packet filtering

Un firewall che effettua il packet filtering (filtraggio dei pacchetti) gestisce i pacchetti che lo attraversano in base ad opportune regole che si riferiscono ai protocolli di più basso livello del modello OSI, dal livello fisico fino a quello di trasporto.

Il meccanismo di firewalling sui sistemi GNU/Linux (dal kernel 2.4 in poi) è Netfilter2. Si tratta di un packet filter dotato di stateful inspection. Il packet filtering è implementato nel kernel, ma la parte relativa al filtraggio avviene tramite dei moduli: in questo modo il sistema di filtraggio risulta dinamicamente estensibile.

Poiché il meccanismo di firewalling è un’attività del kernel, per il suo funzionamento è necessario che il kernel sia stato opportunamente compilato e accompagnato dagli eventuali moduli necessari.

Per default un sistema GNU/Linux non permette ai pacchetti di transitare da un’interfaccia di rete ad un’altra, cioè non fa da router (ovvero non permette il forwarding dei pacchetti), ma questa caratteristica può essere abilitata facendo contenere ‘1’ al file /proc/sys/net/ipv4/ip_forward. Ciò può essere fatto con il comando seguente

# echo "1" > /proc/sys/net/ipv4/ip_forward
Questo va bene per IPv4, ma per la versione IPv6 è necessario inserire il valore ‘1’ nel file /proc/sys/net/ipv6/conf/all/forwarding, che, analogamente a quanto visto prima, può essere fatto con il comando seguente

# echo "1" > /proc/sys/net/ipv6/conf/all/forwarding
Poiché tale impostazione è relativa al filesystem virtuale /proc, non viene memorizzata sulla memoria i massa, pertanto se si desidera che tale impostazione sia attivata ad ogni avvio del sistema, è necessario impartire tale comando ogni volta che il sistema viene riavviato (magari per mezzo di un apposito script).

I pacchetti che transitano su Netfilter vengono esaminati, secondo un insieme di regole (rule) raggruppate in chain (catene o punti di controllo) assegnate a tabelle (table). Le regole determinano la politica di filtraggio dei pacchetti.

Ogni regola specifica una condizione ed un target (obiettivo), cioè l’azione che Netfilter deve intraprendere sul pacchetto in transito, quando questo soddisfa la condizione indicata dalla regola considerata.

Un pacchetto può essere destinato alla macchina che funge da firewall o ad un’altra macchina collegata in rete a quest’ultima. L’instradamento corretto del pacchetto è compito del meccanismo di routing (v. cap. 16).


pict
Figura 25.2: Schematizzazione del funzionamento di Netfilter.

Il funzionamento di Netfilter si basa sull’insieme di tabelle e chain illustrato in fig. 25.2; le tabelle e le chain predefinite sono elencate rispettivamente in tab. 25.1 e tab. 25.2. Si possono conunque definire altre chain per gestire in maniera più modulare le politiche di sicurezza, ovvero le regole di filtraggio dei pacchetti.


Tabella-|Descrizione-----------------------------------------|
filter--|tabella relativa al filtraggio-dei pacchetti (tabella di default).
nat    |tabella relativa al NAT. Viene consultata quando un pacchetto tenta
|     |di effettuare una nuova connessione.                    |
mangle  |tabella relativa alle direttive per l’alterazione di parti dei pacchetti
-------che passano dal firewall.------------------------------

Tabella 25.1: Tabelle utilizzate da Netfilter.


Chain------|Descrizione-----------------------------------------|
PREROUTING--|contiene-le-regole-relative-ai pacchetti che arrivano-in-ingresso al
|         |firewall.                                            |
FORWARD     |contieneleregolerelativeaipacchettichevengonoinoltratidalfirewall |
|         |verso altre interfacce di rete.                         |
INPUT       |cfiorntewieanlel (alei prergocoelessire llaoctaivlie). ai pacchetti che arrivano in ingresso al
OUTPUT      |contieneleregolerelativeaipacchettichevengonogeneratilocalmente |
|         |dal firewall.                                        |
POSTROUTING--contiene le regole-relative ai pacchetti che escono dal firewall.

Tabella 25.2: Chain predefinite di Netfilter.

La tabella mangle supporta le chain INPUT, FORWARD e POSTROUTING dal kernel 2.4.18.

Netfilter è un meccanismo di firewalling dotato di stateful inspection dei pacchetti, reso possibile dal connection tracking, ovvero un meccanismo con il quale Netfilter tiene traccia dello stato delle connessioni. Tale ruolo è implementato da Conntrack che risiede nel kernel (oppure può essere caricato come modulo ip_conntrack) e consente di gestire gli stati elencati in tab. 25.3.
Stato--------|Descrizione-----------------------------------------|
NEW---------|indica-che il pacchetto`e-relativo ad-una-nuova connessione.---|
ESTABILISHED |indica che il pacchetto appartiene ad una connessione gi`a instaurata.
RELATED      |indica che il pacchetto si riferisce ad una connessione gi`a instaurata
|          |(ESTABILISHED) -ad es. un pacchetto ICMP  che segnala un er-|
|          |rcoronen deesllsiaon ceom`eu snuliclaazpioorntea T 2C1P maoilil fl fluusssosoddataiti a dvivi uennes suerlvlaerpForTtPa 2(l0a).
INVALID      |indica che non `e possibile identificare lo stato relativo alla comuni-
|          |cazione alla quale si riferisce il pacchetto (in genere `e una buona idea
SNAT         |sincadritacarech teuttl’iin id piracizczhoet ItPi d laelcu mii ctotemnutenicdaelzi poancec`ehe itnto quperestcoe sdetanttoem).ente
|          |ricevuto`e diverso da quello di destinazione del pacchetto in uscita.
DNAT         |indica che l’indirizzo IP del destinatario del pacchetto preceden-
|          |temente inviato `e diverso da quello del mittente del pacchetto
------------ricevuto.--------------------------------------------

Tabella 25.3: Stati su cui si basa Conntrack.

Poiché il conection tracking non funziona a dovere nel caso di frammentazione dei pacchetti, Conntrack, se attivato, provvede automaticamente a disabilitare la deframmentazione dei pacchetti.

La gestione del connection tracking viene effettuata nelle chain PREROUTING e OUTPUT della tabella nat.

Lo stato delle connessioni è consultabile attraverso il file /proc/net/ip_conntrack. Il suo contenuto ha la seguente sintassi

 
protocol proto_num exp_time status details  
dove

Nel caso di PAT implicito, le porte del mittente sono divise in tre classi: 0 - 511, 512 - 1023, 1024 - 65535. Una porta che appartiene ad una di tali classe sarà sempre mappata in un’altra appartenente alla stessa classe.

Le annotazioni vengono rimosse quando scade il loro exp_time, tranne quelle marcate come [ASSURED]. Queste vengono eliminate soltanto quando viene raggiunto il massimo numero di connessioni tracciabili. Tale valore dipende dalla quantità di memoria centrale presente sulla macchina (per macchine con 256 MB di RAM è 16376) ed è contenuto nel file /proc/sys/net/ipv4/ip_conntrack_max.

Netfilter è gestito con il comando iptables (man page iptables(8))3.

____________________________________________________________________

Comando: iptables
Path: /sbin/iptables

SINTASSI  
# iptables [-h | -v | {-t | --table} table] [command] [option] [match] [target]  
DESCRIPTION

____________________________________________________________________

Nel caso di firewall stateless è opportuno aprire in ingresso le porte al di sopra della 1024 in modo da poter ricevere i pacchetti di risposta ad eventuali pacchetti di richiesta che escono dal firewall. Questo non è necessario nel caso di firewall stateful in quanto si può permettere l’ingresso di pacchetti con porta di destinazione maggiore di 1024 soltanto per i pacchetti di risposta, senza essere obbligati ad aprire in ingresso tutte le porte sopra la 1024 a tutti i pacchetti.

[da completare ...]

La configurazione del firewall impostata per mezzo di iptables non viene memorizzata sul filesystem e quindi viene perduta al successivo riavvio del sistema. È comunque possibile creare uno script in cui inserire i comandi necessari alla configurazione desiderata del firewall in modo da lanciarlo in esecuzione durante la procedura di avvio del sistema.

Si può optare anche per il salvataggio delle impostazioni del firewall per mezzo degli appositi comandi iptables-save (man page iptables-save(8)) e iptables-restore (man page iptables-restore(8)) che servono, rispettivamente, per salvare le impostazioni correnti del firewall e per ripristinare il firewall con le informazioni precedentemente salvate. Le impostazioni vengono gestite in un formato leggermente diverso da quello utilizzato dalla linea di comando con iptables.

L’utilizzo di iptables-save e iptables-restore velocizza considerabilmente il salvataggio ed il caricamento di un consistente insieme di regole poiché il passaggio tra user-space e kernel-space (dove vanno a finire le regole) viene effettuato una volta soltanto e non regola per regola come avverrebbe utilizzando uno script con varie chiamate a iptables.

____________________________________________________________________

Comando: iptables-save
Path: /sbin/iptables-save

SINTASSI  
# iptables-save [-c] [-t table]  
DESCRIZIONE

____________________________________________________________________________________________________________________

Per default iptables-save visualizza l’output sullo standard output (terminale). Per salvare le impostazioni su un file si può utilizzare la redirezione, come nell’esempio seguente

# iptables-save -c > iptables.conf
che salva le impostazioni relative a tutte le tabelle ed i contatori nel file iptables.conf.

Di seguito è riportato un esempio dell’output di iptables-save.

# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*filter
:INPUT DROP [1:229]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Wed Apr 24 10:19:55 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*mangle
:PREROUTING ACCEPT [658:32445]
:INPUT ACCEPT [658:32445]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [891:68234]
:POSTROUTING ACCEPT [891:68234]
COMMIT
# Completed on Wed Apr 24 10:19:55 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*nat
:PREROUTING ACCEPT [1:229]
:POSTROUTING ACCEPT [3:450]
:OUTPUT ACCEPT [3:450]
                                                                        
                                                                        
-A POSTROUTING -o eth0 -j SNAT --to-source 195.233.192.1
COMMIT
# Completed on Wed Apr 24 10:19:55 2002
Le righe relative alle tabelle hanno la seguente sintassi

 
*table-name  
Le righe che specificano le regole sono del tipo

 
:chain-name chain-default-policy [packet-counter:byte-counter]  
Le direttive (regole) hanno la sintassi seguente

 
[[packet-counter:byte-counter]] rule  
dove rule è una regola come imparita con il comando iptables, tranne per il fatto che non riporta l’indicazione del comando iptables né quella della tabella di riferimento. La parte relativa ai contatori è presente soltanto se è stata specificata l’opzione -c.

Ogni dichiarazione di tabella viene conclusa dalla parola chiave COMMIT.

____________________________________________________________________

Comando: iptables-restore
Path: /sbin/iptables-restore

SINTASSI  
# iptables-restore [-c | --counters] [-n | --noflush]  
DESCRIZIONE

____________________________________________________________________________________________________________________

Poiché iptables-restore imposta il firewall con le direttive impostate tramite lo standard input (tastiera), si può utilizzare la redirezione per ripristinare le impostazioni salvate in un file, come nell’esempio seguente

# cat iptables.conf | iptables-restore -c
oppure

                                                                        
                                                                        
# iptables-restore -c < iptables.conf
che imposta il firewall ripristinando i contatori e le regole contenute nel file iptables.conf precedentemente creato con iptables-save.

La procedura di avvio del sistema, provvede ad impostare automaticamente il firewall con le regole contenute nel file /etc/sysconfig/iptables, tramite il comando iptables-restore.

Si noti che iptables-restore non gestisce il caricamento di regole con valori parametrizzati (es. l’indirizzo IP dinamico dell’interfaccia di rete) e per questo tipo di regole si deve ricorrere comunque ad uno script.

25.3.1.1 Esempi

Nell’ambito della sicurezza è una buona regola bloccare l’accesso a tutti i pacchetti (policy di default DROP) e aggiungere delle regole che premettano l’accesso soltanto per determinati pacchetti.

[da completare ...]

È consigliabile abilitare il filtraggio dei pacchetti tramite la routing policy in modo tale che il router stesso scarti i pacchetti che arrivano da un’interfaccia inaspettata. Ad esempio, se un pacchetto con indirizzo IP relativo alla rete privata arriva all’interfaccia esterna, questo viene scartato. Questo può essere fatto per l’interfaccia ppp0 con il seguente comando

# echo "1" > /proc/sys/net/ipv4/conf/ppp0/rp_filter
Uno script di esempio che inserisce messaggi nel log di sistema man mano che i pacchetti ICMP attraversano Netfilter è il seguente

#!/bin/bash
#
# rc.test-iptables - test script for iptables chains and tables.
#
# Copyright (C) 2001  Oskar Andreasson <blueflux@koffein.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
                                                                        
                                                                        
# along with this program or from the site that you downloaded it
# from; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA  02111-1307   USA
#
#
# Filter table, all chains
#
iptables -t filter -A INPUT -p icmp --icmp-type echo-request \
-j LOG --log-prefix="filter INPUT:"
iptables -t filter -A INPUT -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="filter INPUT:"
iptables -t filter -A OUTPUT -p icmp --icmp-type echo-request \
-j LOG --log-prefix="filter OUTPUT:"
iptables -t filter -A OUTPUT -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="filter OUTPUT:"
iptables -t filter -A FORWARD -p icmp --icmp-type echo-request \
-j LOG --log-prefix="filter FORWARD:"
iptables -t filter -A FORWARD -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="filter FORWARD:"
#
# NAT table, all chains except OUTPUT which don't work.
#
iptables -t nat -A PREROUTING -p icmp --icmp-type echo-request \
-j LOG --log-prefix="nat PREROUTING:"
iptables -t nat -A PREROUTING -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="nat PREROUTING:"
iptables -t nat -A POSTROUTING -p icmp --icmp-type echo-request \
-j LOG --log-prefix="nat POSTROUTING:"
iptables -t nat -A POSTROUTING -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="nat POSTROUTING:"
iptables -t nat -A OUTPUT -p icmp --icmp-type echo-request \
-j LOG --log-prefix="nat OUTPUT:"
iptables -t nat -A OUTPUT -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="nat OUTPUT:"
#
# Mangle table, all chains
#
iptables -t mangle -A PREROUTING -p icmp --icmp-type echo-request \
-j LOG --log-prefix="mangle PREROUTING:"
iptables -t mangle -A PREROUTING -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="mangle PREROUTING:"
iptables -t mangle -I FORWARD 1 -p icmp --icmp-type echo-request \
-j LOG --log-prefix="mangle FORWARD:"
iptables -t mangle -I FORWARD 1 -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="mangle FORWARD:"
iptables -t mangle -I INPUT 1 -p icmp --icmp-type echo-request \
-j LOG --log-prefix="mangle INPUT:"
iptables -t mangle -I INPUT 1 -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="mangle INPUT:"
iptables -t mangle -A OUTPUT -p icmp --icmp-type echo-request \
-j LOG --log-prefix="mangle OUTPUT:"
iptables -t mangle -A OUTPUT -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="mangle OUTPUT:"
iptables -t mangle -I POSTROUTING 1 -p icmp --icmp-type echo-request \
-j LOG --log-prefix="mangle POSTROUTING:"
iptables -t mangle -I POSTROUTING 1 -p icmp --icmp-type echo-reply \
-j LOG --log-prefix="mangle POSTROUTING:"
Gli utenti di un sistema GNU/Linux con l’accesso ad Internet attraverso una connessione dialup (modem), spesso desiderano che nessuno possa accedere dall’esterno al loro sitema. Di seguito c’è uno script che funziona in questo modo

#
# Inserisci i moduli del connection-tracking
# (non necessari se inclusi nel kernel)
#
insmod ip_conntrack
insmod ip_conntrack_ftp
#
# Crea una catena che blocchi le nuove connessioni,
# eccetto quelle provenienti dall'interno.
#
iptables -N blockchain
iptables -A blockchain -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A blockchain -m state --state NEW -i ! ppp0 -j ACCEPT
iptables -A blockchain -j DROP
#
# Dalle catene INPUT e FORWARD salta a questa catena
#
iptables -A INPUT -j blockchain
iptables -A FORWARD -j blockchain
Si può sentire la necessità di effettuare un NAT per le macchine presenti su una rete privata e poterle fare accedere ad Internet tramite un’unica connessione dialup effettuata dalla macchina che funge da gateway/firewall, tramite uno script analogo a quello seguente (che deve essere eseguito sulla macchina che funge da firewall)

# Abilita l'IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Carica il modulo NAT.
# (non necessario se incluso nel kernel)
modprobe iptable_nat
# NAT su ppp0 (la connessione dialup)
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
È evidente che le macchine sulla rete protetta dal firewall che effettua anche il NAT, devono avere come gateway di default una macchina della rete o il firewall stesso.4

Una cosa utile è quella di tracciare i tentativi di recapito di pacchetti “strani”, che può essere fatta, ad esempio, con il seguente script

                                                                        
                                                                        
iptables -N no-conns-from-ppp0
iptables -A no-conns-from-ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A no-conns-from-ppp0 -m state --state NEW -i ! ppp0 -j ACCEPT
iptables -A no-conns-from-ppp0 -i ppp0 -m limit -j LOG --log-prefix "Bad packet from ppp0:"
iptables -A no-conns-from-ppp0 -i ! ppp0 -m limit -j LOG --log-prefix "Bad packet not from ppp0:"
iptables -A no-conns-from-ppp0 -j DROP
iptables -A INPUT -j no-conns-from-ppp0
iptables -A FORWARD -j no-conns-from-ppp0
[da completare ...]