Logo PJ
Home
Arcade
Musica
FabLab
Linux
DreamBox
Giochi
 
   Introduzione   Perle   Programmi   SSH   SAMBA   Firewall   GPS   WIFI   Jukebox   PCcar 

Come configurare un firewall con iptables

Ho reinstallato da qualche giorno il server che gestisce la mia rete locale: erano quattro anni che gli era stato installato un Linux, non so più neanche quale versione (forse era una Red Hat 5.1), e a furia di aggiornarne i pacchetti era diventato un bordello; meglio a questo punto ripartire da zero, riconfigurando per bene tutti i programmi.

Una volta messi a posto i servizi essenziali (DNS, posta, Web, file server) devo ora sistemare il firewall. Tra le altre cose, sono passato al nuovo kernel 2.4: ormai lo ritengo sufficientemente maturo, anche se so che nei primi tempi dovrò stargli particolarmente dietro con gli aggiornamenti. La nuova versione del kernel ha tra le altre cose una gestione avanzata dei filtri di rete, quelli che stanno appunto alla base della creazione delle regole di un firewall: piuttosto che riadattare il mio vecchio script ho deciso quindi di ripartire anche in questo caso da zero.

Il primo suggerimento che vi do, almeno finché state sperimentando tutte le possibilità che vi vengono offerte, è quello di compilare le opzioni della sezione netfilter come moduli, in modo tale da poterli caricare e scaricare a piacimento, attivando quindi in maniera dinamica le opzioni che interessano. In questo modo poi se come nel mio caso disponete già di uno script che utilizza ipchains, e volete utilizzarlo in attesa di convertirlo a iptables, potete caricare il modulo ipchains e utilizzare in maniera quasi indolore la vecchia sintassi (i problemi sono più che altro legati al caricamento dei moduli wrapper per connessioni particolari come IRC e FTP). Nel momento in cui volete fare esperimenti con iptables rimuovete questo modulo dal sistema e caricate quelli nuovi.

Vediamo ora quindi quali sono le funzioni che mi interessano in un firewall e cosa sono riuscito ad ottenere:

  • Il server deve funzionare da gateway per tutta la rete locale: deve quindi gestire e rimappare correttamente i collegamenti TCP e UDP tra le macchine collegate alla LAN e le macchine su Internet.
  • Nel mentre le macchine della rete locale possono considerarsi fidate, devono essere filtrati tutti i tentativi di accesso dall'esterno a servizi che non voglio vengano utilizzati.
  • Devono essere in una qualche maniera controllati e filtrati anche eventuali tentativi di attacco più consistenti, quali scanport, flood e DoS in genere. Un ulteriore requisito potrebbe essere quello di bloccare temporaneamente l'accesso agli indirizzi da cui proviene l'attacco.
  • Voglio che sia disponibile dall'esterno l'accesso al servizio VNC di una macchina che sta all'interno della rete.
  • Tutti i tentativi di intrusione devono essere loggati, possibilmente in un database SQL cosicché sia possibile ricavarsi facilmente delle statistiche periodiche.

Armato di pazienza mi sono letto a fondo il testo Iptables tutorial che, come dice il titolo, spiega nel dettaglio il funzionamento dei filtri ed illustra alcuni esempi di firewall di diverse tipologie (con e senza DMZ, con e senza gateway, con server DHCP o modem ADSL) commentandoli nel dettaglio. Sono partito appunto dalla versione base dello script proposto per aggiungerci ciò di cui ho bisogno.

In pratica ho accolto l'idea di creare canali differenziati su cui far confluire il traffico dei pacchetti TCP, UDP e ICMP, in modo tale da alleggerire il carico della CPU e ottimizzare i tempi di reazione; nella sezione ICMP ho però aggiunto un paio di linee che controllano la lunghezza dei pacchetti di ping ricevuti: se eccedono la lunghezza standard (solitamente 84 byte, però il traceroute di Windows 2000 utilizza pacchetti lunghi 92 byte) vengono scartati, in maniera tale da bloccare primitivi tentativi di flood.

$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -m length \ --length 93: -m limit --limit 1/minute -j ULOG \ --ulog-nlgroup 1 --ulog-prefix "Ping flood: " $IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -m length \ --length 93: -j DROP

Sempre a proposito della lunghezza dei pacchetti e del traceroute ho aggiunto poi una regola nel controllo dei pacchetti UDP in arrivo per permettere l'accesso dei pacchetti dei traceroute: in pratica controllo se lunghezza e TTL corrispondono e se si tratta di una porta alta, nel qual caso accetto il pacchetto.

$IPTABLES -A udp_packets -p UDP -s 0/0 --destination-port 33000: -m length --length 38 -m ttl --ttl 2 -j ACCEPT

Ho aggiunto inoltre all'inizio della definizione del canale di input due linee che sfruttano il modulo esterno ipt_psd per individuare e loggare scansioni delle porte, scartando immediatamente i pacchetti in arrivo.

$IPTABLES -A INPUT -m psd -m limit --limit 1/minute -j \ ULOG --ulog-nlgroup 1 --ulog-prefix "Scanport: " $IPTABLES -A INPUT -m psd -j DROP

Con un piccolo trucchetto ho reso invece invisibile il server durante la fase di forward, facendolo sparire anche dai traceroute. In pratica nella tabella mangle del canale di prerouting ho aggiunto una regola che incrementa di uno il TTL di tutti pacchetti in transito.

$IPTABLES -t mangle -A PREROUTING -j TTL --ttl-inc 1

Il passo successivo è stato quello di reindirizzare le porte 5800 e 5900, associate al server VNC, alla macchina che voglio sia amministrabile dall'esterno. Fate attenzione che non è sufficiente limitarsi ad inserire nella tabella di prerouting del nat la porta del server con l'indirizzo locale, ma occorre rendere accessibile tale porta dall'esterno e attivare il forward dal server alla porta della macchina all'interno della rete:

$IPTABLES -A tcp_packets -p TCP -s 0/0 --dport 5800 -j allowed $IPTABLES -A tcp_packets -p TCP -s 0/0 --dport 5900 -j allowed $IPTABLES -A FORWARD -p TCP -i $INET_IFACE -o $LAN_IFACE \ -d 192.168.4.7 --dport 5800 -j ACCEPT $IPTABLES -A FORWARD -p TCP -i $INET_IFACE -o $LAN_IFACE \ -d 192.168.4.7 --dport 5900 -j ACCEPT $IPTABLES -t nat -A PREROUTING -p tcp -d $INET_IP --dport 5800 \ -j DNAT --to 192.168.4.7:5800 $IPTABLES -t nat -A PREROUTING -p tcp -d $INET_IP --dport 5900 \ -j DNAT --to 192.168.4.7:5900

Come ultima cosa vediamo in che maniera sono riuscito a far registrare tutti i log del firewall in una tabella di MySQL. Come avrete notato negli esempi che vi ho inserito, io non utilizzo il target LOG bensì il più nuovo ULOG, che lavora in userspace e permette quindi, tramite un programma in continuo ascolto, di gestire tali informazioni nella maniera più disparata. Il programma da me utilizzato si chiama ulogd e permette di salvare il log in un formato molto simile a quello del log si sistema, in un formato più schematico, ma sopprattutto permette di importare tutte le informazioni in una tabella MySQL, presto anche Postgres. Tutto quello che occorre fare, a parte caricare il modulo per attivare il target ULOG, è di specificare nella regola di iptables il canale sul quale mandare tali informazioni (ne gestisce fino a 32), dopodiché bisogna configurare il demone affiché utilizzi lo stesso canale e possa utilizzare il database. Eccovi la mia configurazione:

nlgroup 1 logfile /var/log/ulogd.log loglevel 5 plugin /usr/lib/ulogd/ulogd_BASE.so mysqlhost localhost mysqldb Firewall mysqltable ulog mysqlpass ***** mysqluser ***** plugin /usr/lib/ulogd/ulogd_MYSQL.so

Nella versione 1.1 dello script ho aggiunto la possibilità di bloccare gli IP degli attaccanti per un periodo stabilito, impedendo quindi che possano accedere al sistema. Per fare questo utilizzo il target NETLINK, che richiede il caricamento di un modulo apposito, e un programmino scritto da me che accede al dispositivo /dev/netlink, legge i pacchetti in arrivo e ne blocca i mittenti. Allo script ho dovuto aggiungere le seguenti regole

$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -m length \ --length 85:9999 -j NETLINK --nldrop $IPTABLES -A INPUT -m psd -j NETLINK --nldrop

relative al filtro dei ping flood e dei portscan; il parametro --nldrop mi permette di scartare subito il pacchetto senza dover aggiungere una ulteriore regola. Quando il demone riceve un pacchetto dal dispositivo, si ricava il mittente e aggiunge dinamicamente al firewall una regola che scarta qualsiasi nuovo pacchetto originato da tale indirizzo; contemporaneamente utilizza il comando di sistema at per posticipare dell'intervallo di tempo voluto la regola che cancella quella precedentemente inserita. La sintassi del programma è molto intuitiva e permette di specificare il numero di minuti desiderato o il nome di un altro dispositivo.

Usage: BlockBadIP [-hvbds] [-m minutes] [-f device] [-p pidfile] -h This help. -v Show version. -b Force daemon into the background. -d Turn on debugging mode. -s Syslog blocked adresses. -m minutes Block bad IPs for specified minutes instead of 120. -f device Use specifed device instead of /dev/netlink. -p pidfile Write the daemon PID to this file.

Non tutti i moduli da me utilizzati fanno parte della distribuzione ufficiale del kernel, molti vengono aggiunti da una release all'altra una volta dichiarati stabili. Per inserirli quindi del proprio pinguino consiglio di utilizzare Patch-O-Matic, un sistema interattivo incluso nel pacchetto iptables che permette di scegliere quali patch inserire nel proprio kernel tra quelle ancora non presenti oppure aggiornate.

RIFERIMENTI

Vi pongo qui lo script di gestione del firewall nell'ultima versione da me realizzata, vi inserisco inoltre i link alla documentazione e ai programmi che ho utilizzato e citato nel documento.

Comments