Avanti Indietro Indice

8. Connection tracking

8.1 Descrizione

Questo modulo è particolarmente interessante ed è una delle novità più importanti introdotte. Il suo ruolo è quello di tenere traccia delle connessioni stabilite e di indicare se un pacchetto appartiene o è relativo ad una di esse. Implementa quindi ciò che è comunemente definito "stateful firewall". Per connessioni si intendono impropriamente anche quelle UDP, ICMP che in realtà non prevedono un meccanismo di richiesta/conferma connessione ("three-way handshake").

Una volta caricato il modulo ip_conntrack.o appena viene stabilita una nuova connessione esso provvede a prendere nota delle informazioni più importanti (indirizzo sorgente, indirizzo destinazione, porta sorgente, porta destinazione ...) e a memorizzarle. E' in grado così per ogni pacchetto che giunge dalla rete o è generato dalla Linux box stessa di stabilire a quale delle seguenti categorie appartiene:

NEW

Pacchetti che cercano di stabilire una nuova (NEW) connessione

ESTABLISHED

Pacchetti appartenenti ad una connessione esistente e nota.

RELATED

Pacchetti relativi ad una connessione esistente ma di cui non ne fanno parte, potrebbero essere pacchetti ICMP di errore o altro.

INVALID

Pacchetti non appartenenti a connessioni note, quindi in genere da rifiutare..

Quindi è possibile interrogare il "connection tracking" per conoscere che tipo di pacchetto è stato ricevuto (NEW,ESTABLISHED,RELATED,INVALID) e decidere l'azione da intraprendere (ACCEPT,DROP,...).

A questo scopo è necessario specificare l'opzione 'm state --state' seguita da una o più degli stati appena descritti: NEW, ESTABLISHED, RELATED, INVALID. Esempio:

# --------------------------------------------------------------------------------
# Interroghiamo il "connection tracking" e se il pacchetto appartiene ad una
# connessione nota (ESTABLISHED) o è relativo (RELATED, es. ICMP error, ftp data, ...)
# allora lo accettiamo (-j ACCEPT) 
# --------------------------------------------------------------------------------
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# --------------------------------------------------------------------------------
# Altrimenti lo scartiamo (-j DROP)
# --------------------------------------------------------------------------------
iptables -A INPUT -j DROP

Questo tipo di implementazione consente di rendere più semplice la realizzazione di un firewall e inoltre garantisce un maggior controllo sui pacchetti UDP e ICMP. UDP infatti diversamente da TCP è connection less (senza connessione) ciò comporta l'impossibilità ad esempio di utilizzare l'opzione '--syn' e quindi di averne un completo controllo.

Naturalmente tenere traccia di tutte le connessioni, in particolare in caso di traffico notevole, può richiedere un maggior utilizzo di memoria e CPU, comunque in base a vari test condotti sembrano essere abbastanza contenuti. In caso si abbia a disposizione una banda larga e ci sia un traffico notevole da gestire la soluzione "classica", ossia che non utilizzi il connection tracking, garantisce in genere prestazioni migliori.

Se non si intende utilizzare il "connection tracking" allora è necessario non compilare il modulo ip_conntrack.o nel kernel o caricarlo con insmod, questo per evitare che tenga traccia delle connessioni inutilmente.

Il suo utilizzo è comunque obbligatorio se si intendono effettuare operazioni di NAT (masquerading, port forwarding ...) e può essere inoltre anche di aiuto per facilitare il filtraggio dei pacchetti.

In alcuni casi si ritiene che questo meccanismo possa essere vulnerabile ad alcuni attacchi tra cui quelli DoS, è sempre possibile però utilizzare delle regole di filtraggio prima di quella contenente l'opzione '-m state --state ESTABLISHED,RELATED' per migliorare la protezione. Alcuni problemi noti e perfezionamenti sono già stati realizzati e sono in fase di testing.

8.2 Opzioni

Non sono disponibili opzioni.

8.3 Esempi

Esempio 1


#!/bin/bash
# Esempio 1

# Supponiamo che PC1 appartenga ad una rete locale e che vogliamo renderla
# più sicura e protetta.
#
#   +---+      .
#   |PC1|------+
#   +---+      |
#              |
#              +---..... INTERNET
#   +---+      |
#   |   |------+
#   +---+      |
#              |
#              .

# --------------------------------------------------------------------------------
# Carichiamo i moduli necessari se non compilati nel kernel (es. ip_conntrack)
# --------------------------------------------------------------------------------
modprobe ip_conntrack
modprobe ipt_REJECT

# --------------------------------------------------------------------------------
# Svuotiamo le catene di tutte le regole
# --------------------------------------------------------------------------------
iptables -F

# --------------------------------------------------------------------------------
# OUTPUT 
# Accettiamo tutti i pacchetti riguardanti una connessione stabilita o relativa
# --------------------------------------------------------------------------------
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 

# --------------------------------------------------------------------------------
# I pacchetti di richiesta connessione o nuova connessione (NEW) accettati 
# sono solo quelli telnet,www, dns (tcp e udp)  
# Accettiamo inoltre anche i pacchetti in uscita dall'interfaccia lo
# (localhost)
# --------------------------------------------------------------------------------
iptables -A OUTPUT -o lo  -j ACCEPT
iptables -A OUTPUT -p tcp --dport telnet -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport domain -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport domain -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport www    -m state --state NEW -j ACCEPT

# --------------------------------------------------------------------------------
# tutto il resto è rifiutato
# --------------------------------------------------------------------------------
iptables -A OUTPUT -j REJECT

# --------------------------------------------------------------------------------
# FORWARD
# PC1 non è posto a protezione di una rete locale.
# --------------------------------------------------------------------------------
iptables -A FORWARD -j DROP

# --------------------------------------------------------------------------------
# INPUT - Accettiamo tutti i pacchetti che fanno parte di una connessione da 
# noi stabilita (ESTABLISHED) o che sono relativi (RELATED) come ad esempio 
# pacchetti ICMP di errore. 
# --------------------------------------------------------------------------------
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# --------------------------------------------------------------------------------
# il resto è scartato 
# --------------------------------------------------------------------------------
iptables -A INPUT -j DROP

Il connection tracking rende tutto molto più semplice, con ipchains sarebbe necessario utilizzare invece questo script:

#!/bin/bash
# Esempio 1

# Supponiamo che PC1 appartenga ad una rete locale e che vogliamo renderla
# più sicura e protetta.
#
#   +---+      .
#   |PC1|------+
#   +---+      |
#              |
#              +---..... INTERNET
#   +---+      |
#   |   |------+
#   +---+      |
#              |
#              .

# --------------------------------------------------------------------------------
# Svuotiamo le catene di tutte le regole
# --------------------------------------------------------------------------------
ipchains -F

# --------------------------------------------------------------------------------
# OUTPUT - Accettiamo telnet, www, dns
# Da questa macchina sarà consentito effettuare solo telnet e www
# --------------------------------------------------------------------------------
ipchains -A output -i lo -j ACCEPT
ipchains -A output -p tcp --dport telnet -j ACCEPT
ipchains -A output -p tcp --dport domain -j ACCEPT
ipchains -A output -p udp --dport domain -j ACCEPT
ipchains -A output -p tcp --dport www    -j ACCEPT
# --------------------------------------------------------------------------------
# tutto il resto è vietato
# --------------------------------------------------------------------------------
ipchains -A output -j REJECT

# --------------------------------------------------------------------------------
# FORWARD 
# PC1 non è posto a protezione di una rete locale.
# --------------------------------------------------------------------------------
ipchains -A forward -j REJECT

# --------------------------------------------------------------------------------
# INPUT - Accettiamo tutti i pacchetti protocollo tcp che non siano di
# richiesta connessione (pacchetti con flag SYN) e che non siano www, dns o
# telnet. Modo classico.
# --------------------------------------------------------------------------------
ipchains -A input -i lo -j ACCEPT
ipchains -A input -p tcp ! -y --sport telnet -j ACCEPT
ipchains -A input -p tcp ! -y --sport dns    -j ACCEPT
ipchains -A input -p udp      --sport dns    -j ACCEPT
ipchains -A input -p tcp ! -y --sport www    -j ACCEPT

# --------------------------------------------------------------------------------
# tutto il resto è vietato 
# --------------------------------------------------------------------------------
ipchains -A input -j DENY 

Esempio 2


#!/bin/bash
# Esempio 2

# Supponiamo che PC1 sia ora un vero e proprio firewall posto a protezione
# della rete locale. Accettiamo in questo caso tutte le richieste provenienti
# dalla rete locale.
#
#   +---+      .
#   |   |------+  eth0   ppp0
#   +---+      |  |       |
#              |  \ +---+ /
#              +----|PC1|----..... INTERNET
#   +---+      |    +---+ 
#   |   |------+   
#   +---+      |
#              |
#              .

# --------------------------------------------------------------------------------
# Carichiamo i moduli necessari se non compilati nel kernel (es. ip_conntrack, ip_conntrack_ftp)
# --------------------------------------------------------------------------------
modprobe ip_conntrack
modprobe ip_conntrack_ftp
# ...

# --------------------------------------------------------------------------------
# Svuotiamo le catene di tutte le regole
# --------------------------------------------------------------------------------
iptables -F

# --------------------------------------------------------------------------------
# OUTPUT - In questo caso non è di grosso interesse
# Possiamo comunque filtrare ciò che è generato dal FIREWALL e in uscita
# --------------------------------------------------------------------------------

# --------------------------------------------------------------------------------
# FORWARD
# PC1 ora è posto a protezione di una rete locale, quindi stabiliamo quali 
# pacchetti possono transitare e arrivare alla rete locale e quali
# provenienti dalla rete locale uscire verso internet
# --------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
# Tutti i pacchetti appartenenti ad una connessione nota o relativi sono accettati
# --------------------------------------------------------------------------------
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# --------------------------------------------------------------------------------
# Qualsiasi nuova connessione (NEW) richiesta da una macchina della rete
# locale verso internet, che quindi "entra" per l'interfaccia eth0, è accettata
# --------------------------------------------------------------------------------
iptables -A FORWARD ! -i ppp0 -m state --state NEW -j ACCEPT

# --------------------------------------------------------------------------------
# Tutto il resto è scartato
# --------------------------------------------------------------------------------
iptables -A FORWARD -j DROP


# --------------------------------------------------------------------------------
# INPUT 
# Qui stabiliamo quali pacchetti destinati esclusivamente al *firewall*, e 
# non alla rete locale, sono accettati. In questo esempio accettiamo solo i ping e 
# pacchetti provenienti dall'interfaccia lo.
# --------------------------------------------------------------------------------
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp --icmp-type ping -j ACCEPT

# --------------------------------------------------------------------------------
# resto scartato
# --------------------------------------------------------------------------------
iptables -A INPUT -j DROP

Esempio 3


#!/bin/bash
# Esempio 3

# Supponiamo che PC1 sia ora un vero e proprio firewall posto a protezione
# della rete locale. In questo caso restringiamo e accettiamo dalla rete locale 
# solo le richieste www, dns, telnet. Questo è solo un esempio e può essere 
# migliorato.
#
#   +---+      .
#   |   |------+  eth0   ppp0
#   +---+      |  |       |
#              |  \ +---+ /
#              +----|PC1|----..... INTERNET
#   +---+      |    +---+ 
#   |   |------+   
#   +---+      |
#              |
#              .

# --------------------------------------------------------------------------------
# Carichiamo i moduli necessari se non compilati nel kernel (es. ip_conntrack, ip_conntrack_ftp)
# --------------------------------------------------------------------------------
modprobe ip_conntrack
modprobe ip_conntrack_ftp
# ...

# --------------------------------------------------------------------------------
# Svuotiamo le catene di tutte le regole
# --------------------------------------------------------------------------------
iptables -F

# --------------------------------------------------------------------------------
# OUTPUT - In questo caso non è di grosso interesse
# Possiamo comunque filtrare ciò che è generato dal FIREWALL e in uscita
# --------------------------------------------------------------------------------

# --------------------------------------------------------------------------------
# FORWARD
# Tutti i pacchetti che arrivano da internet (interfaccia di ingresso: ppp0) 
# appartenenti ad una connessione nota o relativi sono accettati
# --------------------------------------------------------------------------------
iptables -A FORWARD -i ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# --------------------------------------------------------------------------------
# Altrimenti se i pacchetti sono arrivati dall'interfaccia eth0 e quindi 
# dalla LAN e nuovi o di richiesta connessione (NEW) accettiamo solo 
# www, domain, telnet e ping. Accettiamo infine i pacchetti che appartengono
# ad una connessione già stabilita (ESTABLISHED) o sono relativi. 
# --------------------------------------------------------------------------------
iptables -A FORWARD -i eth0 -p tcp   --dport www      -m state --state NEW -j ACCEPT
iptables -A FORWARD -i eth0 -p tcp   --dport domain   -m state --state NEW -j ACCEPT
iptables -A FORWARD -i eth0 -p udp   --dport domain   -m state --state NEW -j ACCEPT
iptables -A FORWARD -i eth0 -p tcp   --dport telnet   -m state --state NEW -j ACCEPT
iptables -A FORWARD -i eth0 -p icmp  --icmp-type ping -m state --state NEW -j ACCEPT  
iptables -A FORWARD -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# --------------------------------------------------------------------------------
# Tutto il resto è scartato
# --------------------------------------------------------------------------------
iptables -A FORWARD -j DROP


# --------------------------------------------------------------------------------
# INPUT 
# Qui stabiliamo quali pacchetti destinati esclusivamente al *firewall*, e 
# non alla rete locale, sono accettati. In questo esempio accettiamo solo i ping
# sia che provengano dalla rete locale che dalla rete internet (nota che qui non 
# si specificano -i e -o) oltre ai pacchetti provenienti dall'interfaccia lo.
# --------------------------------------------------------------------------------
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp --icmp-type ping -j ACCEPT

# --------------------------------------------------------------------------------
# resto scartato
# --------------------------------------------------------------------------------
iptables -A INPUT -j DROP

# ////////////////////////////////////////////////////////////////////////////////
# --------------------------------------------------------------------------------
# Impartendo il comando 'iptables -L -v' si ottiene il seguente risultato:
#
#Chain OUTPUT (policy ACCEPT)
#target     prot opt source               destination         
#[root@localhost netfilter]# iptables -L -v
#Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
# pkts bytes target     prot opt in     out     source        destination         
#    0     0 ACCEPT     icmp --  any    any     anywhere      anywhere    icmp echo-request 
#    0     0 DROP       all  --  any    any     anywhere      anywhere           
#
#Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
# pkts bytes target     prot opt in     out     source        destination         
#    0     0 ACCEPT     all  --  ppp0   any     anywhere      anywhere    state RELATED,ESTABLISHED 
#    0     0 ACCEPT     tcp  --  eth0   any     anywhere      anywhere    state NEW tcp dpt:www 
#    0     0 ACCEPT     tcp  --  eth0   any     anywhere      anywhere    state NEW tcp dpt:domain 
#    0     0 ACCEPT     udp  --  eth0   any     anywhere      anywhere    state NEW udp dpt:domain 
#    0     0 ACCEPT     tcp  --  eth0   any     anywhere      anywhere    state NEW tcp dpt:telnet 
#    0     0 ACCEPT     icmp --  eth0   any     anywhere      anywhere    state NEW icmp echo-request 
#    0     0 ACCEPT     all  --  eth0   any     anywhere      anywhere    state RELATED,ESTABLISHED 
#    0     0 DROP       all  --  any    any     anywhere      anywhere           
# --------------------------------------------------------------------------------
# ////////////////////////////////////////////////////////////////////////////////
 

Esempio 4

In particolare nell'HOWTO Packet Filtering è presente il seguente esempio adatto per chi si connette al proprio ISP da casa via modem.

 insmod ip_contrack
 insmod ip_contrack_ftp

 iptables -N block
 iptables -A block -m state --state ESTABLISHED, RELATED -j ACCEPT
 iptables -A block -m state --state NEW -i ! ppp0        -j ACCEPT
 iptables -A block -j DROP

 iptables -A INPUT   -j block
 iptables -A FORWARD -j block
  

Avanti Indietro Indice