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:
Pacchetti che cercano di stabilire una nuova (NEW) connessione
Pacchetti appartenenti ad una connessione esistente e nota.
Pacchetti relativi ad una connessione esistente ma di cui non ne fanno parte, potrebbero essere pacchetti ICMP di errore o altro.
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.
Non sono disponibili opzioni.
#!/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
#!/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
#!/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 # -------------------------------------------------------------------------------- # ////////////////////////////////////////////////////////////////////////////////
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