Vediamo un esempio pratico di configurazione di Iptables per un personal firewall, quindi da applicare su una macchina desktop che deve poter navigare e liberamente agire in Internet e che non deve esporre alcun servizio.
In un caso simile ci si deve concentrare sulle catene INPUT e FORWARD della tabella FILTER.
Configurazione essenziale
Una configurazione minima può essere molto semplice, l'output che segue è quello di iptables-save
, per utilizzarlo copiarlo in un file (es: /etc/firewall) e applicarlo con iptables-restore < /etc/firewall
).
In pratica:
- Di default si blocca il traffico in ingresso e destinato ad attraversa l'host
- Si lascia aperto il traffico in uscita dal proprio host
- Si permette in INPUT tutto il traffico di ritorno relativo a connessioni già esistenti
- Si permette il traffico sulla interfaccia di loopback, necessario per il buon funzionamento di alcuni programma di sistema:
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
COMMIT
Configurazione più elaborata
Un esempio più elaborato e con un controllo più stringente sul traffico può prevedere:
- Default DROP su tutte le catene
- Si permette in INPUT tutto il traffico di ritorno relativo a connessioni già esistenti
- Si permette il traffico sulla interfaccia di loopback (si interviene sia in INPUT che in OUTPUT)
- Si permette in uscita solo il traffico generato da applicativi usati dall'utente con UserID 501 (attenzione, questo limite potrebbe compromettere il funzionamento di alcun programmi non previsti, che magari girano come root (UID 0) o con altri utenti di sistema)
- Si permette l'aggiornamento del sistema (in questo esempio via http all'indirizzo arbitrario 213.215.144.242)
- Si loggano tutti i pacchetti, esclusi quelli di broadcast, droppati.
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m pkttype --pkt-type ! broadcast -j LOG --log-prefix "INPUT DROP: "
-A FORWARD -m pkttype --pkt-type ! broadcast -j LOG --log-prefix "FORWARD DROP: "
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -m owner --uid-owner 501 -j ACCEPT
-A OUTPUT -p tcp --dport 80 -d 213.215.144.242 -j ACCEPT
-A OUTPUT -m pkttype --pkt-type ! broadcast -j LOG --log-prefix "OUTPUT DROP: "
COMMIT
Analizziamo la configurazione di iptables per un server pubblico, che deve rendere accessibili dei servizi, con diversi livello di accesso, e che ha un firewall locale.
In questo caso si agisce sulle catene di INPUT e di OUTPUT della tabella FILTER.
Configurazione essenziale
Vediamo un esempio essenziale di una configurazione per un server web pubblico, che deve rendere accessibili a tutto il mondo le porte 80 e 443 e deve poter essere gestito da alcuni IP privilegiati.
La configurazione prevede:
- DROP di default su tutte le catene
- Si lascia aperto il traffico in uscita dal proprio host (OUTPUT) dopo aver sanitificato i pacchetti in uscita (--state)
- Si permette in INPUT tutto il traffico di ritorno relativo a connessioni già esistenti
- Si permette il traffico sulla interfaccia di loopback
- Si permette accesso, da tutta Internet, alle porte 80 e 443
- Si permette l'accesso via SSH (porta 22/TCP) da una arbitraria rete di amministrazione (es: 213.25.10.0/24)
- Si permette l'accesso FTP (porta 21/TCP + gestione del canale dati) da un arbitrario host di un webmaster (es: 143.20.12.7)
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -p tcp --dport 22 -s 213.25.10.0/24 -j ACCEPT
-A INPUT -p tcp --dport 21 -s 143.20.12.7 -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
COMMIT
Notare che per gestire correttamente il protocollo FTP è opportuno assicurarsi che venga caricato il modulo del kernel ip_conntrack_ftp. Se non viene fatto automaticamente dalla propria distribuzione, caricarlo, facendo eseguire durante la fase di boot (per esempio nel file /etc/rcd.d/rc.local
) il seguente comando:
modprobe ip_conntrack_ftp
Configurazione più elaborata
Un esempio più complesso di un simile sistema può prevedere:
- Default DROP su tutte le catene
- Si permette in INPUT tutto il traffico di ritorno relativo a connessioni già esistenti
- Si permette il traffico sulla interfaccia di loopback (si interviene sia in INPUT che in OUTPUT)
- Si permette in uscita solo il traffico di risposta al traffico in entrata permesso
- Si permette l'aggiornamento del sistema (in questo esempio via http all'indirizzo arbitrario 213.215.144.242)
- Si permette l'invio della posta tramite un unico smtp relay (in questo esempio con IP 213.15.44.22)
- Si loggano tutti i pacchetti di tipo unicast (escludendo quindi broadcast e multicast) con una syslog facility che ci permetta il logging su file separato
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -p tcp --dport 22 -s 213.25.10.0/24 -j ACCEPT
-A INPUT -p tcp --dport 21 -s 143.20.12.7 -j ACCEPT
-A INPUT -m pkttype --pkt-type unicast -j LOG --log-prefix "INPUT DROP: " --log-level 7
-A FORWARD -m pkttype --pkt-type unicast -j LOG --log-prefix "FORWARD DROP: " --log-level 7
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p tcp --sport 80 -j ACCEPT
-A OUTPUT -p tcp --sport 443 -j ACCEPT
-A OUTPUT -p tcp --sport 22 -d 213.25.10.0/24 -j ACCEPT
-A OUTPUT -p tcp --sport 21 -d 143.20.12.7 -j ACCEPT
-A OUTPUT -p tcp --dport 80 -d 213.215.144.242 -j ACCEPT
-A OUTPUT -p tcp --dport 25 -d 213.15.44.42 -j ACCEPT
-A OUTPUT -m pkttype --pkt-type unicast -j LOG --log-prefix "OUTPUT DROP: " --log-level 7
COMMIT
Per visualizzare il log su file separato è necessario configurare Syslog. Editare /etc/syslog.conf
(o analogo) e aggiungere una riga tipo:
kern.debug /var/log/firewall.log
.
Esempi di configurazioni particolari
Vediamo alcuni esempi che usano funzioni di iptables meno comuni e non sempre incluse nel kernel di una distribuzione.
- Aprire diverse porte con multiport
Se il nostro server deve esporre più porte può essere comodo il match multiport, che permette di definire più porte TCP o UDP in una singola regola.
Ad esempio per un server di posta completo di webmail, pop3, imap e corrispettivi SSL si può permette pubblico accesso con:
iptables -I INPUT -m multiport -p tcp --dport 25,80,110,143,443,993,995 -j ACCEPT
- Limitare rischi con tool di analisi log con owner
Spesso sul sistema vengono installati strumenti di analisi dei log, di qualsiasi tipo. Questi possono essere semplici programmi singoli o applicazioni più complesse, possono venire schedulati o eseguiti in background. Qualsiasi sia la loro natura, sono programmi che ricevono un input con il log da analizzare, che spesso contiene informazioni su attività generate dall'esterno. Log di server web, di firewall, di posta, per esempio, contengono dati che possono entro certi limiti essere manipolati direttamente da un potenziale intrusore, facendo richieste via HTTP anomale, inviando pacchetti invalidi ecc.
Spesso si sorvola sui potenziali rischi associati al parsing di log, soprattutto se questo viene fatto da programmi semplici e non particolarmente prudenti nel gestire i loro input e se magari vengono pure eseguiti con privilegi di root.
Si possono limitare gli effetti di potenziali vulnerabilità di questi strumenti anche via iptables, impedendo all'utente con cui sono eseguiti sul sistema di comunicare via rete.
Primariamente è opportuno che simili programmi vengano eseguiti con permessi non privilegiati, per cui se non già previsto , è opportuno fare in modo che tutti i log e dati che devono leggere e scrivere siano accessibili dall'utente con cui il programma gira.
Poi, si può usare il metodo di match "owner" con cui le iptables possono gestire il traffico a seconda dell'utente che lo ha generato (per logica questo match si applica solo alla catena di OUTPUT).
Ad esempio se il nostro programma di analisi dei log si chiama fwanalog e viene eseguito con utente logs, con UID 150, possiamo impedire che questo programma comunichi all'esterno (escludendo query DNS che potrebbe fare per reverse DNS lookup) con un comando tipo:
iptables -I OUTPUT -p udp --dport ! 53 -m owner --uid-owner 150 -j DROP
oppure, nei kernel dove è supportata questa estensione:
iptables -I OUTPUT -p udp --dport ! 53 -m owner --cmd-owner fwanalog -j DROP
Analizziamo quali possono essere le configurazioni di iptables per un firewall Linux adibito a default gateway di una rete locale in grado di nattare gli host interni e impedire accessi non autorizzati dall'esterno.
Configurazione essenziale
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -s 10.0.0.0/255.255.255.0 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A FORWARD -s 10.0.0.0/255.255.255.0 -i eth0 -j ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A POSTROUTING -s 10.0.0.0/255.255.255.0 -j MASQUERADE
COMMIT
In questo infobox verra' illustrato come configurare una linux box come transparent firewall.
Rispetto ad una configurazione in cui il firewall ruoti anche i pacchetti, in questa situazione il sistema si comporta come un bridge: esso si limita a passare i pacchetti da un'interfaccia all'altra secondo le regole di filtraggio definita, senza occuparsi del routing.
Una simile configurazione presenta il grande vantaggio di una maggiore semplicita' nel deploy. Posizionando il firewall inline, infatti, non sara' necessario apportare alcuna modifica alla configurazione della rete esistente o delle macchine. Il funzionamento del firewall sara' completamente trasparente. Inoltre non dovendosi occupare del routing dei pacchetti, le prestazioni del sistema dovrebbero essere superiori rispetto ad un firewall in "routing mode".
Nell'esempio illustrato e' presente una lan con indirizzo 192.168.1.0/24. Il router, avente indirizzo IP 192.168.1.1 e' collegato all'interfaccia esterna del firewall, mentre l'inside di quest'ultimo sara' connessa allo switch dove sono attestati i pc client.
Per potere utilizzare il sistema come firewall trasparente e' innanzitutto necessario configurare la macchina linux in modo che possa svolgere la funzione di bridge ethernet. Il tool utilizzato per la configurazione di questo aspetto e' brctl e puo' essere installato con il seguente comando:
apt-get install bridge-utils
Nell'esempio verra' configurato un bridge di nome br0 costituito dalle interfacce eth0 ed eth1. La creazione del bridge e l'aggiunta delle interfacce puo' venire effettuata con i seguenti comandi:
brctl addbr br0
brctl addif br0 eth0
brctl addif br0 eth1
Il supporto per il bridging ethernet dovrebbe essere gia' incluso all'interno del kernel, ed il relativo modulo venire caricato automaticamente all'esecuzione del comando brctl addbr br0
.
Per verificare l'aggiunta delle interfacce al bridge eseguire brctl show
:
bridge name bridge id STP enabled interfaces
br0 8000.00219b02b0d6 no eth0
eth1
Dall'output del comando si puo' notare come la configurazione dello spanning tree sia disabilitata. Avendo l'esempio di rete illustrata una struttura estremamente semplice e priva di loop non e' stato abilitato il protocollo in questione.
Una volta creato il bridge assicurarsi che le interfacce eth0 ed eth1 appartenenti allo stesso non abbiano alcun indirizzp ip assegnato:
ifconfig eth0 down
ifconfig eth0 0.0.0.0 up
ifconfing eth1 down
ifconfig eth1 0.0.0.0 up
Inoltre, per consentira un accesso remoto al firewall potrebbe essere opportuno configurare un indirizzo ip su una terza interfaccia (se disponibile) oppure assegnarlo direttamente al bridge. Si ipotizza di assegnare al bridge br0 l'indirizzo 192.168.1.3:
ifconfig br0 192.168.1.50 netmask 255.255.255.0 up
A questo punto la configurazione delle schede di rete e del bridge visualizzabili con il comando ifconfig dovrebbero risultare simile alla seguente:
br0 Link encap:Ethernet HWaddr 00:21:9b:02:b0:d6
inet addr:192.168.1.50 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::221:9bff:fe02:b0d6/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:65 errors:0 dropped:0 overruns:0 frame:0
TX packets:78 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:9800 (9.5 KiB) TX bytes:10319 (10.0 KiB)
eth0 Link encap:Ethernet HWaddr 00:21:9b:02:b0:d6
inet6 addr: fe80::221:9bff:fe02:b0d6/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2748 errors:0 dropped:3728821171 overruns:0 frame:0
TX packets:2925 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:319216 (311.7 KiB) TX bytes:3064216 (2.9 MiB)
Interrupt:219
eth1 Link encap:Ethernet HWaddr 00:48:54:60:c1:6b
inet6 addr: fe80::248:54ff:fe60:c16b/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:14365 errors:0 dropped:0 overruns:0 frame:0
TX packets:9394 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:19225516 (18.3 MiB) TX bytes:799834 (781.0 KiB)
Interrupt:21 Base address:0xae00
Per completare la configurazione del bridge e' infine necessario abilitare il forward dei pacchetti ip (echo 1 > /proc/sys/net/ipv4/ip_forward
) ed eventualmente impostare un default gateway in caso si voglia rendere raggiungibile l'ip di gestione anche al di fuori della rete 192.168.1.0/24.
La funzionalita' del firewall e' comunque indipendente dall'impostazione di un default gateway, ma potrebbe essere opportuno aggiungerlo, anche per consentire eventuali download degli update dai repository debian:
route add default gw 192.168.1.1
A questo punto dai client connessi allo switch dovrebbe essere possibile pingare il router ed altre reti poste oltre di esso. A fini di test e' possibile disabilitare una delle interfacce (ifconfig ethX down
per verificare come il traffico non attraversi piu' il bridge e di conseguenza non raggiunga il router e le reti da esso ruotate.
L'esempio di configurazione illustrato, non e' pero' permanente ed andrebbe perso al primo riavvio del sistema. Per rendere la configurazione permanente e' possibile editare il file /etc/network/interfaces in modo da eseguire automaticamente i comandi necessari:
#loopback
auto lo
iface lo inet loopback
#bridge br0
auto br0
iface br0 inet static
address 192.168.1.50
netmask 255.255.255.0
broadcast 192.168.1.255
network 192.168.1.0
gateway 192.168.1.1
pre-up ifconfig eth0 down
pre-up ifconfig eth1 down
pre-up brctl addbr br0
pre-up brctl addif br0 eth0
pre-up brctl addif br0 eth1
pre-up ifconfig eth0 up
pre-up ifconfig eth1 up
post-down ifconfig eth0 down
post-down ifconfig eth1 down
Con la configurazione illustrata sino a questo punto il sistema ha funzionalita' di bridge ethernet, ma non effettua ancora alcun tipo di filtraggio, lasciando passare tutto il traffico che riceve. A tal fine e' necessario configurare iptables specificando le opportune regole.
In questo caso, le regole piu' importanti riguarderanno probabilmente la catena FORWARD, ovvero quella relativa ai pacchetti che attraversino il firewall.
Inserendo le regole nella catena INPUT si andrannoo invece a discriminare solamente i pacchetti diretti al sistema stesso, ovvero all'indirizzo 192.168.1.50.
Un esempio di set di regole minimale e' il seguente che blocca tutti i pacchetti in transito ad eccezione delle richieste dns dalla subnet 192.168.1.0/24 verso l'indirizzo 172.16.105.3, le request dhcp e le risposte dal dhcp server 172.16.105.5 eil traffico diretto alle porte 80 e 8080 di un proxy http con ip 172.16.105.12.
Per il traffico in senso contrario non e' stato necessario inserire regole puntuali, in quanto verra' matchato dalla statefull inspection grazie alle regole con l'opzione -m state --state ESTABLISHED, RELATED
.
Sono state inoltre previste alcune regole sulle catene di input ed output per consentire l'accesso via ssh al firewall e la possibilita' di scaricare aggiornamenti tramite il protocollo http.
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -s 192.168.1.50 -p tcp -dport 80 -j ACCEPT
iptables -A OUTPUT -s 192.168.1.50 -p udp -dport 53 -d 172.16.105.3 -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -p udp --dport 67 -j ACCEPT
iptables -A FORWARD -p udp --dport 68 -s 172.16.105.5 -j ACCEPT
iptables -A FORWARD -p udp --dport 53 -s 192.168.1.0/24 -d 172.16.105.3 -j ACCEPT
iptables -A FORWARD -p tcp --dport 80 -s 192.168.1.0/24 -d 172.16.105.12 -j ACCEPT
iptables -A FORWARD -p tcp --dport 8080 -s 192.168.1.0/24 -d 172.16.105.12 -j ACCEPT
Anche in questo caso con il reboot del sistema si perderebbe la a configurazione delle regole di filtraggio. A tal fine e' possibile creare uno shellscript come il seguente da inserire nella struttura di init del sistema
#!/bin/sh
IPTABLES="/sbin/$IPTABLES"
######################
# start firewall
######################
start()
{
# caricamento moduli necessari
/sbin/insmod ip_tables > /dev/null 2> /dev/null
/sbin/insmod iptable_NAT > /dev/null 2> /dev/null
/sbin/insmod ip_conntrack > /dev/null 2> /dev/null
/sbin/insmod ipt_MASQUERADE > /dev/null 2> /dev/null
# flush regole
$IPTABLES -F INPUT > /dev/null
$IPTABLES -F OUTPUT > /dev/null
$IPTABLES -F FORWARD > /dev/null
$IPTABLES -t nat -F > /dev/null
# attivazione ip_forward
echo 1 > /proc/sys/net/ipv4/ip_forward
# regole filtraggio
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP
$IPTABLES -P OUTPUT DROP
$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A OUTPUT -o lo -j ACCEPT
$IPTABLES -A INPUT -p tcp --dport 22 -j ACCEPT
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -s 192.168.1.50 -p tcp -dport 80 -j ACCEPT
$IPTABLES -A OUTPUT -s 192.168.1.50 -p udp -dport 53 -d 172.16.105.3 -j ACCEPT
$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A FORWARD -p udp --dport 67 -j ACCEPT
$IPTABLES -A FORWARD -p udp --dport 68 -s 172.16.105.5 -j ACCEPT
$IPTABLES -A FORWARD -p udp --dport 53 -s 192.168.1.0/24 -d 172.16.105.3 -j ACCEPT
$IPTABLES -A FORWARD -p tcp --dport 80 -s 192.168.1.0/24 -d 172.16.105.12 -j ACCEPT
$IPTABLES -A FORWARD -p tcp --dport 8080 -s 192.168.1.0/24 -d 172.16.105.12 -j ACCEPT
}
#################
# stop firewall
#################
stop()
{
#Flush regole e policy in accept
$IPTABLES -F
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
$IPTABLES -t nat -F
$IPTABLES -t mangle -F
# Rimozione dei moduli necessari
/sbin/rmmod ip_conntrack > /dev/null 2> /dev/null
/sbin/rmmod ipt_MASQUERADE > /dev/null 2> /dev/null
/sbin/rmmod iptable_nat > /dev/null 2> /dev/null
#Disattivazione IP forwarding
echo 0 > /proc/sys/net/ipv4/ip_forward
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
$IPTABLES -L -v
;;
*)
echo "Usage: $0 {start | stop | status}"
exit 1
;;
esac
exit 0