Questo documento contiene una breve panoramica sul nuovo codice di packet filtering dei kernel della serie 2.4.
Con questo documento non mi propongo né di entrare nei dettagli tecnici né di trattare in maniere esaustiva l'argomento (né, del resto, sarebbe possibile). Il mio intento è quello di darvi una breve introduzione sul packet filtering e condurvi passo per passo nella creazione di un firewall.
Nei kernel della serie 2.2 (in realtà dal 2.1.102) era incluso ipchains, che era un riscrittura del codice di firewalling IPv4 dei vecchi kernel (che a loro volta copiavano quello di BSD). Con iptables assistiamo ad una "rivoluzione" del codice, che è stato scritto ripartendo quasi da zero. Per quanto riguarda ipchains vi rimando ai vari HOWTO (ipchains HOWTO, Firewall-HOWTO, IP-Masquerading HOWTO) che potete trovare su www.pluto.linux.it, già tradotti in italiano.
IPTables rimane concettualmente vicino a ipchains, ma introduce anche diverse innovazioni; ad esempio, sono state create tre tabelle principali (nat, filter, mangle), mentre in ipchains avevamo a disposizione solo tre catene (INPUT, FORWARD, OUTPUT). La principale differenza dal vecchio ipchains è proprio questa: la possibilità di manipolare il pacchetto in diversi punti durante la sua "traversata" attraverso la nostra macchina. Vediamo in dettaglio le tre tabelle; la tabella filter è composta da tre catene predefinite identiche a quelle di ipchains: INPUT, OUTPUT, FORWARD, che controllano rispettivamente i pacchetti diretti verso l'userspace (ovvero i programmi), i pacchetti in uscita dall'userpsace e i pacchetti in transito; da queste tre catene potranno derivare tutte le altre catene definite dall'utente. La tabella nat viene consultata quando il kernel incontra un pacchetto che sta per creare una nuova connessione (pacchetti cosiddetti SYN); anche questa tabella ha tre catene: PREROUTING (per i pacchetti appena arrivati; come dice il nome viene consultata prima della "routing decision", ovvero l'analisi del pacchetto che determina se è indirizzato alla macchina stessa oppure se va forwardato ad un'altra macchina), OUTPUT (per i pacchetti in uscita generati localmente) e POSTROUTING (per i pacchetti che stanno per lasciare la macchina). La tabella mangle viene utilizzata per effettuare manipolazioni particolari sul pacchetto; e' provvista di due catene predefinite: PREROUTING e OUTPUT; la prima serve ad alterare i pacchetti in entrata prima della decisione di routing, la seconda interviene sui pacchetti locali in uscita prima della decisione di routing. Ogni regola inserita in una qualsiasi catena ha un "target", ovvero un'istruzione che indica la sorte del pacchetto che soddisfa quella regola; esistono quattro target fondamentali: ACCEPT (il pacchetto viene lasciato passare), DROP (il pacchetto viene scartato silenziosamente), QUEUE (il pacchetto viene accodato verso l'userspace), RETURN (blocca l'esame della catena e passa il controllo alla catena chiamante; se RETURN viene chiamato da una catena predefinita allora la sorte del pacchetto è determinata della policy della catena); non va trascurato il fatto che come target può essere specificata una catena definita dell'utente. Le tabelle nat e mangle hanno dei target speciali che consentono di alterare i pacchetti. Ho accennato alla policy di una catena; per capire cos'è bisogna comprendere il funzionamento della catena stessa: il pacchetto in esame viene confrontato con la prima regola; se corrisponde allora viene eseguito il target, altrimenti si passa alla seconda regola e così via; se nessuna delle regole è soddisfatta e il pacchetto è arrivato alla fine della catena allora la policy specifica come deve essere trattato il pacchetto. Le policy fondamentali sono ACCEPT e DROP.
Ok, adesso conosco (più o meno) come funziona un firewall, direte voi, ma perché dovrei volerne uno sulla mia macchina? Le ragioni principali sono 3: controllo, sicurezza, vigilanza.
Controllo: il mio firewall può permettere il traffico verso certi indirizzi o servizi e bloccarlo in altri casi; con un po' di pratica è possibile bloccare i banner pubblicitari sulle pagine :-). Naturalmente può essere usto per scopi più delicati, come il blocco di servizi e simili.
Sicurezza: quando vi connettete alla rete la vostra macchina è esposta ad ogni genere di abuso; si può utilizzare il firewall per impedire qualunque connessione alla propria linuxbox o concedere una visibilità parziale. Sfruttando le nuove caratteristiche di iptables è inoltre possibile proteggersi (o proteggere la propria rete casalinga) da alcuni tipo di DoS.
Vigilanza: il firewall può essere usato per vedere cosa entra/esce dalla vostra macchina e si possono ottenere informazioni relative al malfunzionamento di computer della propria rete.
Un firewall può essere impostato in decine di modi diversi, più o meno efficaci, ma comunque riconducibili a due grandi "linee di pensiero". Un metodo è quello di settare il firewalldel tipo "può passare tutto, tranne..."; l'altra soluzione adotta una filosofia del tipo "non può passare nulla, eccetto...", ed è questa che intendo trattare.
Prima di procedere all'impostazione del firewall vero e proprio è bene andare a sfruttare certe caratteristiche del kernel poco documentate ma comunque utilissime.
Una di queste è il SYN Cookie, che serve a proteggere, in una certa misura, da attacchi SYN Flood; durante questo tipo di attacco l'host viene bombardato da pacchetti SYN (ovvero che negoziano l'apertura di una connessione). Il sistema deve allocare risorse per ogni connessione e dovendo far fronte a migliaia di richieste al secondo arriva al collasso. Il kernel di linux è in grado di utilizzare un protocollo crittografato che permette agli utenti regolari di continuare la propria attività, anche se il computer è sotto attacco. Questo sistema è totalmente trasparente e non richiede alcuna modifica software nei computer con cui dialogate. Per essere utilizzabile il kernel deve essere compilato attivando l'opzione corrispondente; anche con un kernel ad hoc, il supporto non sarà attivo per default; il motivo è che su server sovraccarichi potrebbe impedire la connessione di utenti legittimi. Poiché state leggendo queste righe presumo che non dovrete configurare nessun server, quindi potete usare tranquillamente i SYN Cookie. Ora, supponendo che abbiate un kernel compilato con l'opzione adatta, passiamo ad abilitare questi SYN Cookie; per fare ciò dobbiamo agire sul file tcp_cookies, contenuto nella directory /proc/sys/net/ipv4/tcp, settando il suo contenuto a 1. Per fare questo si può utilizzare un qualunque editor di testo, oppure, più semplicemente, dare il comando:
echo 1 >
/proc/sys/net/ipv4/tcp_syncookies
Va tenuto in considerazione il fatto che la diretory /proc ed i file in essa contenuti sono "virtuali", ovvero servono come strumenti per manipolare alcune opzioni del kernel, ma queste modifiche svaniscono al primo riavvio.
Un'altra opzione che è bene attivare è il cosiddetto SAV - Source Address Verification. Questa opzione effettua una verifica a "ritroso" sull'indirizzo di provenienza del pacchetto (per i dettagli: RFC1812), filtrando i eventuali pacchetti spoofati.
Ci sono altre impostazioni che possono essere manipolate, ma quelle che ho descritto sono le principali; per un elenco completo potete consultare il file Documentation/networking/ip-sysctl.txt, nella directory dove avete installato i sources del kernel (in genere /usr/src/linux).
Adesso siamo pronti per passare al firewall vero e proprio; prima di tutto dobbiamo avare bene in mente quello che desideriamo fare, per evitare di trovarsi con uno script più volte rappezzato del quale non si seguono più i passaggi...
Noi ci proponiamo di sfruttare al meglio tutte le tabelle di iptables: nella tabella nat effettueremo dei primi controlli sulla sanità del pacchetto, e, se non soddisfa le regole, lo scartiamo. La policy delle catene INPUT e FORWARD (della tabella filter) sarà DROP, lasceremo cioè passare solo quello che compare esplicitamente nelle regole. L'ultima tabella (mangle) ci servirà per migliorare la qualità dei servizi che si intendono offrire; questa tabella non è indispensabile, infatti la maggior parte degli utenti non desidera che altre persone possano connetersi al proprio computer.
Cominciamo a dichiarare alcune variabili che ci serviranno nello script:
IPTAB=/usr/local/sbin/iptables
IP=`ifconfig ppp0 | grep inet | cut -d : -f 2 | cut -d\ -f
1`
La prima variabile ci evita di fare riferimento a iptables con il path completo ogni volta, la seconda contiene il nostro IP. Attenzioni agli apici (AltGr + ') e agli spazi!
Definiamo ora le policy della catena filter:
$IPTAB -P INPUT DROP
$IPTAB -P FORWARD DROP
$IPTAB -P OUTPUT ACCEPT
Avrete notato che uso la variabile IPTAB al posto del path completo; come ho detto prima permetterò tutto il traffico in uscita ma limiterò quello in entrata. Quando non indico esplicitamente il parametro -t iptables suppone che io stia lavorando sulla catena filter.
Andiamo adesso alla tabella nat:
$IPTAB -t nat -A PREROUTING -i ppp0 -s 127.0.0.0/8 -j
DROP
$IPTAB -t nat -A PREROUTING -i ppp0 -s 192.168.0.0/16
-j DROP
$IPTAB -t nat -A PREROUTING -i ppp0 -d ! $IP -j
DROP
### SPERIMENTALE ###
#$IPTAB -t nat -A PREROUTING -i ppp0 -m unclean -j
DROP
Vediamo cosa abbiamo fatto: con la prima istruzione scartiamo tutti i pacchetti che dicono di provenire da 127.x.x.x perché questi pacchetti dovrebbero viaggiare solo sull'interfaccia lo. La seconda elimina tutti quelli che dicono di provenire della rete locale; poiché sono nell'interfaccia ppp0 (il modem) sono sicuramente contraffatti. La terza istruzione scarta tutti i pacchetti che non sono diretti a noi; poiché un router non li invierebbe di certo a noi, questi pacchetti sono quantomeno sospetti ed è bene scartarli. L'ultima istruzione attiva un controllo sulla sanità del pacchetto, in modo da scartare pacchetti malformati che potrebbero mettere in crisi il nostro computer; la linea è commentata perché questa istruzione è considerata sperimentale e potrebbe scartare pacchetti che in realtà non sono dannosi. Per adesso io non ho incontrato alcun inconveniente, ma decidete voi se attivarla o meno.
$IPTAB -N ppp_in
$IPTAB -N services
Con queste due istruzioni abbiamo creato due catene che ci serviranno per migliorare la facilità di manutenzione del codice.
$IPTAB -A INPUT -i lo -j ACCEPT
$IPTAB -A INPUT -i ppp0 -j ppp_in
Con la prima istruzione abbiamo istruito iptables affinché lasci passare tutti i pacchetti local-to-local, ovvero quelli generati localmente con destinazione 127.0.0.1. La seconda dirotta tutti pacchetti provenienti dall'interfaccia ppp0 sulla catena ppp_in che abbiamo creato. (In realtà i pacchetti non vengono "dirottati", semplicemente il controllo viene passato alla catena ppp_in.)
Passiamo quindi alla catena ppp_in:
$IPTAB -A ppp_in -p icmp --icmp-type ! echo-request -j
ACCEPT
Questa linea indica che vogliamo far passare tutti i pacchetti ICMP (protocollo di controllo), tranne le "echo-request", ovvero i ping. Fate attenzione che siamo in una catena chiamata da input e quindi non verranno bloccati i ping i uscita; semplicemente un ping sul nostro ip non produrrà alcun risultato.
$IPTAB -A ppp_in -p tcp --dport 6000:6010 -j
DROP
$IPTAB -A ppp_in -p udp --dport 6000:6010 -j
DROP
$IPTAB -A ppp_in -p tcp --dport 7000:7010 -j
DROP
$IPTAB -A ppp_in -p udp --dport 7000:7010 -j
DROP
$IPTAB -A ppp_in -p tcp --dport 1:1024 -j
services
$IPTAB -A ppp_in -p udp --dport 1:1024 -j
services
Prima di spiegare queste istruzioni vorrei fare un "ripassino" sul protocolla tcp/ip; per stabilire una connessione si usa il "3-way handshake": il primo pc invia una richiesta di connessione verso una porta del server; il server a sua volta ci invia un pacchetto ACK per confermare l'apertura della comunicazione. A questo punto i dati possono fluire dal nostro pc al server, ma non viceversa; il server, quindi, subito dopo l'ACK ci invierà un pacchetto SYN verso una porta alta (> 1024); il nostro computer invierà la conferma e a quel punto sarà stata instaurata una comunicazione bidirezionale. Tornando al nostro script, la decisione di bloccare i pacchetti diretti verso le porte di X11 e Xfont Server nasce dal fatto che è relativamente semplice costruire un pacchetto diretto verso queste porte che sembra provenire da un server e da una porta legittima; questi pacchetti potrebbero interferire con il funzionamento di questi due servizi e quindi li blocchiamo. Le ultime due istruzioni indicano che per i pacchetti diretti verso le porte < 1024 il controllo viene passato alla catena services.
#DNS
$IPTAB -A ppp_in -p udp --sport 53 -j
ACCEPT
$IPTAB -A ppp_in -p tcp --sport 53 -j
ACCEPT
#smtp
$IPTAB -A ppp_in -p tcp --sport 25 -j
ACCEPT
#nntp
$IPTAB -A ppp_in -p tcp --sport 119 -j
ACCEPT
#telnet
$IPTAB -A ppp_in -p tcp --sport 23 -j
ACCEPT
#ftp (dati e linea di controllo)
$IPTAB -A ppp_in -p tcp --sport 20 -j
ACCEPT
$IPTAB -A ppp_in -p tcp --sport 21 -j
ACCEPT
#irc
$IPTAB -A ppp_in -p tcp --sport 6666:7000 -j
ACCEPT
$IPTAB -A ppp_in -p udp --sport 6666:7000 -j
ACCEPT
#napster
$IPTAB -A ppp_in -p tcp --sport 6699 -j
ACCEPT
$IPTAB -A ppp_in -p tcp --dport 6699 -j
ACCEPT
$IPTAB -A ppp_in -p tcp -s 64.24.141.18/24 -j
ACCEPT
#talk
$IPTAB -A ppp_in -p tcp --sport 518:519 -j
ACCEPT
$IPTAB -A ppp_in -p udp --sport 518:519 -j
ACCEPT
#http e https
$IPTAB -A ppp_in -p tcp -m multiport --source-port
80,443 -j ACCEPT
#pop3
$IPTAB -A ppp_in -p tcp --sport 110 -j
ACCEPT
#imap
$IPTAB -A ppp_in -p tcp -m multiport --source-port
143,220 -j ACCEPT
Queste istruzioni indicano cosa volgiamo far passare: DSN, posta in uscita, news, telnet in uscita, ftp, irc, napster, talk, navigazione web, server pop3, server imap2 e imap3. Questi sono in genere i servizi minimi che vorrete configurare. Fate attenzione a irc: io ho indicato le porte tra 6666 e 7000, se il vostro server usa porte diverse dovrete cambiare le istruzioni in relazione alle nuove porte. Nota per napster: alcuni utenti hanno impostato come porta di default una diversa dalla 6699 (che serve per i download); in questo caso il firewall bloccherà il download. L'unica soluzione è modificare al volo il firewall se si riscontrano problemi di questo tipo.
Torniamo alla catena services che avevamo lasciato in sospeso: per la maggior parte dei casi questa catena conterrà solo due istruzioni:
$IPTAB -A services -p tcp --dport 113 -j
REJECT
$IPTAB -A services -j DROP
Queste due regole indicano di scartare tutti i pacchetti diretti verso le porte basse. La prima indica che i pacchetti che sono diretti verso la porta 113 (auth) verranno scartati, ma l'host (in genere server irc) che li ha generati verrà avvisato che questo servizio non è disponibile. Questo per evitare che il server rimanga in attesa di una risposta che non arriverà mai, rallentando l'accesso al servizio. La seconda scarta tutto il resto senza dire nulla a nessuno. Se invece vogliamo lasciare aperti dei servizi bisognerà agire di conseguenza:
$IPTAB -A services -p tcp --dport 113 -j
REJECT
$IPTAB -A services -p tcp --dport 80 -j
ACCEPT
$IPTAB -A services -j DROP
ovvero: laciamo che il nostro web server locale sia accessibile anche dall'esterno. Potete aggiungere un'istruzione per tutti i servizi che volete rimangano visibili. Ricoradatevi sempre che l'istruzione di DROP deve essere l'ultima della catena.
Fino ad adesso abbiamo utilizzato istruzioni abbastanza semplici e compatibili (non tutte, a dire il vero) con il vecchio ipchains. In questa sezione verranno illustrate alcune regole che forniscono un ulteriore grado di protezione ma che funzionano solo con iptables e con le apposite opzioni compilate nel kernel (o come moduli).
$IPTAB -N conn_state
$IPTAB -N tcp_flags
Queste due tabelle serviranno rispettivamente per un controllo sullo stato della connessione e sui flags del pacchetto.
$IPTAB -A conn_state -m state --state INVALID -j
DROP
$IPTAB -A conn_state -m state --state
RELATED,ESTABLISHED -j ACCEPT
La prima istruzione prevede che i pacchetti che non appartengono a nessuna connessione e non sono dei SYN vengano immediatamente scartati. La seconda accetta subito i pacchetti le cui connessioni o sono già stabilite o che fanno riferimento a connessioni già stabilite. Per le nuove connessioni (pacchetti SYN) non viene preso alcun provvedimento: la decisione viene lasciata alla catena ppp_in.
La prossima catena verificherà i flags dei vari pacchetti per decidere se possano essere accettati oppure no. I flags sono degli speciali campi nell'header del pacchetto che servono a precisarne la funzione; quando facevo riferimento a «pacchetti SYN» in realtà intendevo dire «pacchetti con il flag SYN settato». Queste regole serviranno per proteggersi contro alcuni tipi di porscan, che usano particolari flags.
Nota: l'opzione --tcp-flags accetta due
parametri; il primo indica quali flags controllare, il secondo
quali dovranno essere settati. --tcp-flags ALL SYN
indica che dovranno essere controllati tutti i flags e solo il
SYN dovrà essere settato
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL FIN,URG,PSH
-j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL ALL -j
DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL
SYN,RST,ACK,FIN,URG -j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL NONE -j
DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags SYN,RST SYN,RST
-j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags SYN,FIN SYN,FIN
-j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags FIN FIN -j
DROP
La prima istruzione blocca gli scan Xmas tree di nmap; le due seguenti sono altre versioni del Xmas Tree; la quinta è per il Syn+Rst, mentre l'ultima blocca il classico Syn+Fin [Marco questa è per te ;-)].
L'ultima istruzione (contro gli scan FIN) è sensata solo se è presente anche la catena conn_state e se questa viene richiamata per prima.
Lo scan HalfSyn non viene bloccato dal firewall, ma è possibile integrare iptables e portsentry, in modo che quest'ultimo modifichi il primo in caso di scan. (Configurare portsentry)
Queste due catene dovranno essere inserite all'inizio della catena ppp_in con queste istruzioni:
$IPTAB -I ppp_in 1 -j conn_state
$IPTAB -I ppp_in 1 -j tcp_flags
A ben guardare l'inserimento della catena conn_state rende superflua la catena ppp_in. Infatti un normale utente non vorrà permettere connessioni sul proprio computer. I SYN di ritorno di una connessione tcp verranno riconosciuti come facienti parte di una connessione già avviata e fatti passare.
Tutto il firewall puè essere ridotto in questo modo:
$IPTAB -P INPUT DROP
$IPTAB -F
$IPTAB -X
$IPTAB -t nat -A PREROUTING -i ppp0 -s 127.0.0.0/8 -j
DROP
$IPTAB -t nat -A PREROUTING -i ppp0 -s 192.168.0.0/16
-j DROP
$IPTAB -t nat -A PREROUTING -i ppp0 -d ! $IP -j
DROP
### SPERIMENTALE ###
#$IPTAB -t nat -A PREROUTING -i ppp0 -m unclean -j
DROP
$IPTAB -N ppp_in
$IPTAB -N services
$IPTAB -N conn_state
$IPTAB -N flags
$IPTAB -N blocked
$IPTAB -A INPUT -i lo -j ACCEPT
$IPTAB -A INPUT -i ppp0 -j ppp_in
$IPTAB -A conn_state -m state --state INVALID -j
DROP
$IPTAB -A conn_state -m state --state
RELATED,ESTABLISHED -j ACCEPT
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL FIN,URG,PSH
-j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL ALL -j
DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL
SYN,RST,ACK,FIN,URG -j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags ALL NONE -j
DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags SYN,RST SYN,RST
-j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags SYN,FIN SYN,FIN
-j DROP
$IPTAB -A tcp_flags -p tcp --tcp-flags FIN FIN -j
DROP
$IPTAB -A services -j DROP
$IPTAB -A ppp_in -j blocked
$IPTAB -A ppp_in -j conn_state
$IPTAB -A ppp_in -j flags
$IPTAB -A ppp_in -p tcp --dport 1:1024 -j
services
$IPTAB -A ppp_in -p udp --dport 1:1024 -j
services
$IPTAB -A ppp_in -p icmp --icmp-type ! echo-request -j
ACCEPT
$IPTAB -A ppp_in -p tcp --sport 20 -j
ACCEPT
$IPTAB -A ppp_in -p tcp --dport 6699 -j
ACCEPT
Questo è ovviamente un firewall molto minimale, senza logging e difficilmente configurabile. Lo script avanzato che potete scaricare è invece più completo ed è configurabile tramite il file /etc/firewall.conf. Avviate il firewall senza alcun parametro ed otterrette una piccola guida su come configurarlo.
Ultimo aggiornamento: 09/10/2001
Copyright (C) 2000 Luca "Kronos" Tettamanti
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation;
with no Invariant Sections, with no Front-Cover Texts, and with
no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".