Firewall con due o piu` ADSL in bilanciamento

Questa configurazione serve a creare un firewall in grado di usare contemporanemente due (o piu`) ADSL per servire, con il NAT, una rete di client. Il carico del traffico generato dai client viene distribuito sulle due ADSL in percentuali stabilite in configurazione. Nel caso in cui una delle ADSL muoia, pero`, occorre necessariamente intervenire a mano per "disattivarla", a meno che non venga a mancare il link sulla NIC del firewall, nel qual caso il sistema si rende conto da solo che quel percorso e` morto, e smette di usarlo fino a che non torna il link.

Purtroppo per ottenere questo risultato occorre applicare una patch al kernel, perche` non facendolo succede che una parte del traffico nattato esce sull'interfaccia sbagliata (traffico su eth1 con l' ip di eth2 e viceversa). La patch inserisce un ulteriore meccanismo di controllo sullo stato delle connessioni nattate e su dove devono essere inoltrati i pacchetti.

Passo 1: ricompilare il kernel

Passo 2: configurare le interfacce

Questo firewall richiede necessariamente una interfaccia fisica (o al limite una vlan, ma non un alias) per ogni ADSL, quindi per un esempio con due ADSL servono come minimo tre interfacce (LAN, WAN1, WAN2). Configurare le interfacce normalmente in /etc/network/interfaces avendo cura di NON impostare un gateway predefinito in nessuna delle WAN. In questo modo la macchina parte senza un gateway impostato, quindi di default non va su internet.

Passo 3: configurare il routing

Configurare il routing sembra facile ma non lo e`. Occorre tenere conto del fatto che il nostro firewall puo` essere raggiunto da host che stanno su internet per mezzo di due linee diverse, con indirizzi IP diversi. E che potrebbe decidere di rispondere a chi l'ha chiamato usando il gateway sbagliato, ovvero quello collegato con l'altro dei due pubblici che ha. Nella mia testa sarebbe stato logico pensare che questo non succeda, ovvero mi viene da pensare che se ricevo una connessione da fuori verso il mio indirizzo ip pubblico numero uno, perche` mai dovrei rispondere con l' ip pubblico numero uno, ma via il gateway numero due? Siccome pero` pare (da prove fatte) che succeda, devo evitarlo. Per evitarlo, devo fare in modo che quando un pacchetto ha come indirizzo di mittente il mio ip pubblico uno, esca dal gateway connesso alla interfaccia uno e non dall'altro. Ovviamente lo stesso vale per il due. Si, lo so, piu` ci penso meno sta in piedi, pero` empiricamente e` cosi` che si comporta.

Quindi devo mettere assieme delle regole di routing che facciano queste cose:

Nel pensare a questa logica, ricordiamoci che il NAT in uscita (source NAT) e` fatto DOPO il routing, non prima. E che il NAT in entrata e` fatto invece PRIMA del routing.

Dobbiamo quindi creare uno script che configuri delle regole di routing e delle tabelle di routing. Diciamo per questo esempio che abbiamo due provider e una LAN. La configurazione e` cosi` fatta:

Prima di tutto, devo editare il file /etc/iproute2/rt_tables per inserire due alias comprensibili per le due routing tables che devo creare dopo, altrimenti le posso indicare per numero, ma e` scomodo e non capisco immediatamente chi e` chi. Quindi lo modifico aggiungendo in fondo una cosa tipo:

1 ProviderA
2 ProviderB

Fatto questo, devo creare uno script che imposti le regole di routing per ottenere quello che voglio. I comandi sono preceduti da una spiegazione del perche` sono stati fatti cosi`, occorre ovviamente fare uno script con i comandi senza le spiegazioni.

Lo script risultante, tutto assieme e senza commenti, e` questo:

ip rule add from 1.0.0.2 table ProviderA
ip rule add from 2.0.0.2 table ProviderB

ip route add 1.0.0.0/29 dev eth1 src 1.0.0.2 table ProviderA
ip route add default via 1.0.0.1 table ProviderA
ip route add 10.0.0.0/24 dev eth0 table ProviderA
ip route add 2.0.0.0/29 dev eth2 table ProviderA
ip route add 127.0.0.0/8 dev lo table ProviderA

ip route add 2.0.0.0/29 dev eth2 src 2.0.0.2 table ProviderB
ip route add default via 2.0.0.1 table ProviderB
ip route add 10.0.0.0/24 dev eth0 table ProviderB
ip route add 1.0.0.0/29 dev eth1 table ProviderB
ip route add 127.0.0.0/8 dev lo table ProviderB

ip route add default scope global nexthop via 1.0.0.1 dev eth1 weight 1 nexthop via 2.0.0.1 dev eth2 weight 1

Passo 4: regole di firewll per il nat

Nel firewall, dobbiamo tenere conto che abbiamo due interfacce pubbliche, quindi ricordiamoci di applicare eventuali blocchi a tutte e due le interfacce. Per configurare correttamente il NAT in uscita dovremo definire due regole, che verranno applicate al traffico uscente a seconda di quale interfaccia avra` imboccato. Ricordiamo che il nat uscente (SNAT) avviene DOPO il routing. Il traffico che esce via eth1 (provider A) viene nattato con l' ip assegnato all'interfaccia stessa. Lo stesso vale per eth2 (provider B )

iptables -t nat -A POSTROUTING -o eth1  -j SNAT -s 10.0.0.0/24 --to-source 1.0.0.2
iptables -t nat -A POSTROUTING -o eth2  -j SNAT -s 10.0.0.0/24 --to-source 2.0.0.2

Se vogliamo fare NAT in ingresso, verso una macchina della LAN o della DMZ, dovremo farlo su tutte e due le interfacce, anche in questo caso, sempre se vogliamo che la macchina interna sia raggiungibile a tutti e due gli ip pubblici. Un caso del genere e` valido per esempio per un mail server, che ha senso che sia raggiungibile a mezzo di tutte e due le linee, in modo da pubblicare due MX e avere ridondanza della connessione.

Un esempio di NAT in ingresso e` questo:

iptables -t nat -A PREROUTING -i eth1  -p tcp --dport 25 -j DNAT --to 10.0.0.100
iptables -t nat -A PREROUTING -i eth2  -p tcp --dport 25 -j DNAT --to 10.0.0.101

NOTA: Dal momento che fuori ho due interfacce, per evitare che si possa creare confusione (il traffico che entra da una interfaccia riceve risposte attraverso l'altra per colpa del NAT che natta sull'indirizzo sbagliato) allora assegno due NAT diversi (a due indirizzi privati diversi) a seconda se il traffico entra dall'una o dall'altra ADSL. Questi due indirizzi sono alias della stessa NIC sul mail server, in modo che di fatto per tutto il processo di NAT il mail server sia visto come due macchine distinte. Siccome il mail server risponde usando come source addresso lo stesso indirizzo al quale ha ricevuto il traffico, i pacchetti in uscita saranno mandati via per la stessa interfaccia da cui sono entrati. Non so se esista un modo per evitare di dare due indirizzi alla macchina interna.

Debug e verifica

Se si hanno comportamenti buffi, o comunque si vuole capire se non ci siamo persi pezzi per strada, possiamo innanzitutto salvarci tutte le regole di routing prima di fare tutto questo lavoro, quando cioe` usiamo ancora un singolo gateway. Per farlo, possiamo salvare l'output dei comandi:

ip rule
ip route show table local
ip route show table main

Dopo aver modificato tutto quanto, possiamo ridare gli stessi comandi, aggiungendo pero` anche un ip rule show table <nometabella> per ognuna delle routing tables aggiuntive che abbiamo creato, ovvero quelle che sono menzionate nell'output del comando ip rule. Cosi` possiamo renderci conto per esempio di abbiamo fatto casino nelle tabelle predefinite, local e main, e se ci sono errori palesi nelle altre.

Un altro utile comando e` ip route flush cache che pulisce la cache del routing e quindi rende realmente attive le modifiche che avete fatto, le quali altrimenti potrebbero essere "nascoste" dietro un comportamento che era in cache prima che le applicaste.

Per provare a capire "cosa succederebbe se", ovvero "cosa succede se un pacchetto fatto cosi` e cosa` passa dalla macchina?" potete usare il comando ip route get con tutti i parametri del caso. Suggerisco di leggere il man di "ip" e cercare "get" per capire quali sono le possibilita` di interrogazione con il comando get. L'output del comando "get" riporta la regola di routing che viene applicata al pacchetto con le caratteristiche indicate nei parametri della get. Purtroppo non ci mostra esattamente quale sequenza di decisioni viene presa dal kernel per arrivare al risultato mostrato.

LinuxDebian/MultiPathRouting (last edited 2013-02-04 14:08:20 by Kurgan)