Network Address Translation: un abominio
P.S: Scusatemi se non sono stato molto preciso in alcuni dettagli ma non sono proprio espertissimo, eventualmente mandatemi un feedback che aggiusto l’articolo.
Gli indirizzi IPv4 sono scarsi. Agli albori di internet 2^32 indirizzi possibili sembravano una infinità. Ad oggi la ICANN (la società no-profit che si occupa di gestire indirizzi e regole ufficiali di Internet) ha esaurito tutti i “blocchi” di indirizzi IP assegnabili alle autorità “regionali” delle varie zone del pianeta. Questo ed altri motivi hanno condotto alla creazione di un nuovo standard, IPv6, che permette l’utilizzo di 2^128 indirizzi, che per svariati motivi sono stati calcolati come sufficienti per parecchio tempo.
Il processo di migrazione, già iniziato ufficialmente nel 2008, proseguirà per alcuni anni probabilmente e già da tanti anni si utilizzano due tecniche per ovviare al problema che alcune persone ritengono comode, ma io voglio mostrarvi quanto siano brutte, intefficenti e contro gli standard.
Già dagli anni 90′ però molte persone si erano accorte di questo problema ed è stato inventato il NAT (Network Address Translation).
Il NAT puro consiste nella semplice traduzione di indirizzi IPv4 da una classe di indirizzi privati a una classe di indirizzi pubblici e viceversa.
Supponiamo ad esempio di avere un gateway/router con due interfacce: una verso Internet e una verso una rete locale LAN che utilizza indirizzi IPv4 privati. Supponiamo di avere 10 computer nella LAN e 10 indirizzi IP disponibili sul router. Il NAT ci permette di fare un assegnamento IP Pubblico <-> IP privato. Quindi modificando la configurazione del router (e non dei computer) possiamo cambiare gli indirizzi pubblici di ciascun computer.
Questo può essere utile in qualche caso, ad esempio se abbiamo molti computer, pochi dei quali sono però accesi contemporaneamente. Allora possiamo tenere meno indirizzi IP pubblici rispetto al numero di computer nella LAN e utilizzare gli indirizzi a rotazione. Utile ma neanche tanto.
Quello che oramai da anni e anni va invece molto più di moda è il NAPT (Network Address and Port Translation).
Il NAPT funziona in questo modo: supponiamo di avere una rete sempre con un router centrale che da un lato ha Internet e dall’altro una rete locale. Supponiamo adesso di avere un solo IP pubblico sul router e 10 computer nella rete locale. Come facciamo a far uscire i 10 computer su internet? Ammettiamo che ciascun computer vuole inviare/ricevere pacchetti TCP e UDP. Ciascun pacchetto TCP e UDP è caratterizzato da due numeri di “porta”, una porta sorgente ed una porta destinazione. La porta sorgente è un identificatore per capire da quale applicazione della macchina che invia il pacchetto si è originata la connessione, mentre la porta destinazione identifica il processo da contattare sulla macchina di destinazione, che provvederà a mandare le risposte alla porta sorgente del mittente.
Per riuscire a far funzionare tutto, il NAPT guarda la porta sorgente del pacchetto TCP che vuole instaurare la connessione verso un host di Internet e controlla le porte sorgenti libere relative all’indirizzo IP pubblico che ha a disposizione. Il router sceglie quindi una porta sorgente libera per il suo ip pubblico e in una tabella si segna: “il computer della rete locale con indirizzo ip privato x.y.z.w ha stabilito una connessione verso un host remoto e tutti i pacchetti con porta sorgente X che mi arrivano da lui devo sostituirli con la mia porta sorgente Y”. Ovviamente questo procedimento verrà fatto anche al contrario quando il router riceverà dei pacchetti di risposta. In questo modo l’accrocchio funziona e si riesce a utilizzare un solo indirizzo IPv4 per far collegare molti host in rete.
Il NAPT può anche essere effettuato mettendo più di un indirizzo IP sul router che utilizzamo, di modo da aumentare il numero di connessioni contemporanee, come vedremo dopo.
Sebbene questo sistema permetta in un certo senso di risolvere il problema della scarsità di indirizzi IPv4, molti nella comunità di Internet lo considerano un vero e proprio abominio. Ecco alcune delle obiezioni:
8 Motivi per cui il NAPT non andrebbe utilizzato:
- NAPT viola la più importante regola di stratificazione dei protocolli, secondo la quale un protocollo di livello k non dovrebbe fare nessuna assunzione riguardo a protocolli di livello k+1. Un router normalmente dovrebbe solo prendere i pacchetti IP che arrivano ed instradarli, invece con il NAPT deve anche andare a controllare il carico del pacchetto IP per verificare il numero di porta, cosa che non dovrebbe fare per le regole sulla stratificazione dei protocolli. Questo causa inoltre overhead non previsto su un apparato che dovrebbe solo instradare e invece deve iniziare anche a tenere traccia di tutte le connessioni che lo attraversano
- NAPT viola il modello gerarchico di IP, che afferma che ogni macchina collegata in rete è identificata in modo univoco a livello mondiale da un indirizzo IP. In certi casi questo può essere un vantaggio per il nostro anonimato, ma se stiamo parlando di rintracciabilità non è certamente una garanzia.
- I processi su Internet non sono obbligati ad utilizzare TCP e UDP. Se un utente dietro ad una NAT decide di utilizzare un diverso protocollo di livello 4 non potrà funzionare, perchè il NAPT si basa sull’idea di controllare i numeri di porta, che in alcuni protocolli di livello 4 potrebbero non esistere. ICMP, il protocollo per il controllo del funzionamento di IP e per la diagnostica di rete, non utilizza numeri di porta ed è stato necessario implementare nei router che fanno il NAPT dei particolari workaround per permettere di inviare e ricevere i pacchetti correttamente. Questo ovviamente è tutto altro carico sulle spalle del router. Non dimentichiamoci che ogni volta che aggiungiamo qualcosa da fare ai router, aumenta il carico di lavoro per ogni pacchetto e le linee potrebbero subire leggeri ritardi che aumentano la frequenza di congestioni. Questo potrebbe richiedere hardware più potente e quindi costi più alti! È un ragionamento tirato abbastanza per gli estremi, ma se il traffico è molto elevato questo è un overhead che pesa.
- Il numero di connessioni contemporanee diminuisce. Poichè il router del NAPT deve allocare una delle sue porte sorgente per ciascuna connessione, essendo le porte utilizzabili 2^16 (in realtà le prime 4096 sono riservate ad usi speciali), non possiamo avere più di 61440 connessioni contemporanee per ogni indirizzo IP pubblico utilizzato dal router. Possono sembrare una valanga ma se usiamo un solo ip per la rete di una azienda o una università e magari qualcuno inizia a fare port-scanning o altre brutte cose che consumano un sacco di connessioni, il router satura subito le porte libere. Se abbiamo 614 computer dietro il nat, ciascuno potrà fare circa 100 connessioni contemporanee, dopo di che il NAPT non ha più numeri di porta liberi. Allora dobbiamo tenerci un pool di indirizzi IP al posto di uno unico… Ma a questo punto aveva veramente senso fare il NAT se avevamo degli indirizzi? Se parliamo della rete di un ateneo sì, ma se parliamo di piccoli uffici forse no.
- NAPT trasforma Internet da una rete ad assenza di connessione, in un tipo di rete orientata alle connessioni, perchè il dispositivo NAPT deve conservare le informazioni relative ad ogni connessione che lo attraversa. Se un dispositivo NAPT si blocca e la sua tabella di mappatura si perde, tutte le sue connessioni TCP/UDP verranno distrutte. In assenza di NAPT, i guasti ai router non hanno effetto su TCP/UDP, perchè il processo di ritrasmissione si attiva dopo il timeout di alcuni secondi. State scaricando un file e qualcuno riavvia il router che effettua il NAPT per manutenzione? La connessione verrà persa perché il router dopo il riavvio non è in grado di effettuare di nuovo le traduzioni di porta e né il mittente né il destinatario si accorgeranno del problema, la connessione resta in uno stato di zombie… Con un normale router senza NAPT e una connessione TCP si sarebbe notato solo un lag di pochi secondi (il tempo di riavvio del router).
- Solitamente ogni host collegato su internet può effettuare delle connessioni a dei server, oppure esporre dei propri servizi alla rete e permettere ad altri di collegarvisi. Purtroppo con l’introduzione del NAPT, se ad esempio nella rete locale ci sono due host con server web sulla porta 80, non è possibile esporre entrambi quei servizi sullo stesso indirizzo sulla stessa porta 80, quindi l’unica soluzione possibile (quando viene manualmente abilitata con il così detto Port Forwarding), è di assegnare due porte distinte dell’indirizzo pubblico ai due servizi dietro al NAPT, quindi ad esempio la porta 80 per uno dei due server web e la porta 81 per l’altro. Così facendo ovviamente il servizi che i vari host della rete locale possono esporre si riduce notevolemente. Se poi teniamo conto che gli stessi numeri di porta devono anche essere usati come porte sorgenti per le connessioni in uscita, la situazione è sempre peggiore. (Anche) per colpa del NAPT, Internet sta diventando sempre più una rete quasi esclusivamente per “scaricare” contenuti, questo sarà un problema più “filosofico” che tecnico, ma secondo me il bello di Internet, fin dai primi giorni in cui esiste, è proprio la possibilità per chiunque di esporre un suo servizio a tutti, in qualunque parte del mondo, senza dover dipendere obbligatoriamente da terze parti per farne “hosting”.
- Molti protocolli a livello applicativo, tra cui DCC e il notissimo FTP (in modalità attiva) fanno uso degli indirizzi IP degli host da cui si originano le connessioni all’interno dei messaggi scambiati a livello applicativo per avvertire il server a cui si collegano di inviare i dati da scaricare su una certa porta del client. Il NAPT non sa nulla di tutto questo e il risultato è che questi protocolli non sono più in grado di funzionare perché i server FTP tentano di inviare i dati a porte sul router NAPT che non è a conoscenza di questa operazione in corso e non permette il passaggio. Su alcuni router sono stati implementati dei meccanismi per intercettare il traffico a livello applicativo di questi protocolli e sbloccare le porte in ingresso per mettergli di funzionare. Questo è ancora più grave del primo punto perché con questo problema il router non deve solo andare a vedere il livello protocollare 4, ma addirittura anche i dati sul livello 7. Questo genera un overhead esagerato sulle operazioni di cui deve tenere traccia il povero router. Se questo non vi basta ancora, forse dovreste leggere dei magheggi che si sono dovuti inventare i realizzatori di IPsec per riuscire a farlo funzionare con il NAPT. IPsec infatti si basa sull’idea di “firmare” o cifrare il contenuto di pacchetti IP in modo da renderli sicuri e con sorgente affidabile. Per raggiungere questo scopo viene preso tutto il contenuto del pacchetto IP e firmato digitalmente ad esempio. Peccato che con il NAPT dei campi che dovrebbero essere fissi (aka porte TCP e/o UDP) diventano mutabili e quindi la firma non sarà più valida. Per poi non parlare dei pacchetti cifrati con IPsec, che ovviamente non potranno normalmente varcare il NAPT dato che non c’è modo di leggerli per fare la traduzione di porte.
- Il NAPT non permette di mantenere connessioni aperte in stato idle. Spesso può capitare di dover tenere una connessione aperta dove non passa neanche un bit per ore o settimane. TCP supporta questa cosa senza problemi ma il NAPT avendo pochi numeri di porta sorgente a disposizione non può permettersi di “sprecarli” per connessioni che non fanno nulla, quindi quando non viene rilevata attività per un po’ di tempo in molte implementazioni di NAPT si è obbligati a cancellare dalla tabella del NAPT la connessione. La cosa peggiore di questa cosa è che (in alcune implementazioni) i due host credono di essere ancora collegati tra loro, perché il NAPT non avvisa nè mittente nè destinatario che ha cancellato la riga nella tabella, quindi il client che ha aperto la connessione non vedrà nessun dato arrivargli anche se il server ha tentato di inviarli senza ricevere risposta. Invece una connessione TCP sopra IP inattiva, senza un NAT di mezzo, può resistere a qualunque problema di rete. Possiamo spegnere router, cambiare linee di collegamento, cambiare instradamento per arrivare il router, possiamo mettere in standby l’host, tagliare le fibre ottiche nell’atlantico e ricollegarci via saltellite. Possiamo fare quel cavolo che ci pare, quando torneremo nella nostra connessione, se gli indirizzi IP degli endpoint non sono cambiati saremo ancora collegati e potremo ancora mandare dati nella stessa connessione, tutto grazie a TCP/IP. Viene spontaneo chiedersi: come si fa allora con il NAT a tenere aperte connessioni persistenti? Ci sono tanti metodi. Quello più ovvio è di inviare dei messaggi di ping, e relative risposte (pong) a livello applicativo “ogni tanto” (come fa IRC, websocket etc etc…). In alternativa è possibile utilizzare un workaround (TCP-Keepalive) per inviare dei pacchetti TCP vuoti ogni tanto all’interno della connessione, come segno di “attività” e per evitare che il NAPT cancelli la regola di traduzione.
Il mito del NAT come firewall
Non dobbiamo nascondere che molto spesso, il NAPT, per come funziona, viene sfruttato impropriamente come meccanismo di firewalling. Ad esempio immaginiamo una rete di una università. Vogliamo evitare che la gente accenda server SMTP per iniziare attività di spamming o altre cose simili, come evitare che gente possa esporre servizi su internet ma possa allo stesso tempo collegarsi? Beh facciamo un bel NAPT. Questa è una porcheria bella e buona, specialmente quando viene fatta su reti relativamente piccole dove ci possono essere abbastanza indirizzi pubblici per tutti senza problemi. Il NAPT non serve a quello, per bloccare le connessioni in ingresso si possono utilizzare regole di firewalling sui router per non permettere a host di Internet di stabilire connessioni verso la rete locale con una cosa del genere con iptables:
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -P FORWARD DROP
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT #Permettiamo a tutto di uscire dalla interfaccia della rete locale ad internet
iptables -A FORWARD -i eth0 -o eth1 -m state –state RELATED,ESTABLISHED -j ACCEPT
Con queste 4 righe in realtà comunque il router deve andare a tenere conto di alcuni dettagli sul livello 4, ma è sempre meglio di usare il NAPT, per gli altri motivi sopra citati.
Alcune persone provano una falsa sensazione di sicurezza stando dietro al proprio NAPT, pensando di essere al sicuro. In realtà si sbagliano di grosso.
- Su alcuni router “casalinghi” molto economici, dove viene implementato il NAPT, può succedere per vari motivi che quando arriva un pacchetto da internet, con IP sorgente spoofato (modificato da un attaccante) per essere nella classe degli indirizzi privati (ad esempio arriva un pacchetto UDP con sorgente 192.168.0.1), il router non si interessa del fatto che il pacchetto arriva dall’interfaccia “sbagliata” (cioè quella verso Internet e non quella della rete locale), ma invece lo guarda e lo instrada nella rete locale. Ovviamente poi le risposte non torneranno indietro all’attaccante, ma con questo metodo si può già iniziare a tentare qualche attacco. Se non sbaglio diversi anni fa con questo metodo si riusciva ad attaccare un sistema di RPC su Windows e quindi con una serie di meccanismi ad ottenere anche delle risposte e quindi attaccare completamente la macchina bucando il NAT.
- Su altri router, vengono abilitati dei moduli particolari (presenti anche come moduli di iptables per il kernel Linux) per permettere a FTP, DCC e altri protcolli citati prima di funzionare. Questo è certamente un bene ma espone anche dei problemi di sicurezza perché con attacchi particolari è possibile sfruttuare questi meccanismi per aprire arbitrariamente delle porte del NAPT verso una porta di un host della rete locale. Ad esempio preparando una particolare pagina web e facendola visitare ad un utente ignaro, è possibile instaurare una finta connessione IRC sopra HTTP e quindi fare una richiesta DCC e sbloccare una porta in ingresso. Questo metodo viene mostrato tra altre cose in questo video.
Filed under: informatica | 4 Comments
Tag:abominio, address, napt, nat, network, orrore, translation
Ho qualche dubbio sul punto 5: sia IP che UDP sono connectionless, a prescindere dal fatto che usi NAT o meno; l’unico modo in cui una connessione UDP venga distrutta dall’evento che citi è che proprio in quel momento stia passando il pacchetto… su TCP invece possiamo anche essere d’accordo.
Probabilmente il termine connectionless lì confonde un po’. È vero, UDP è già connectionless, quindi il fatto che il NAT possa far cadere la connessione è conforme al fatto che è appunto “connectionless”, poi UDP non necessita instaurazione iniziale della connessione e i pacchetti possono essere inviati senza numero di sequenza, mentre TCP necessita instaurazione della connessione e numero di sequenza e si aspetta che la connessione instaurata resti attiva anche se scoppiano dei router in mezzo, per il semplice fatto che TCP è sopra IP e quindi fin tanto che c’è qualcosa ad instradare i pacchetti IP lui funziona. Usando il NAT invece se salta il router del NAT salta la connessione, cosa che non dovrebbe succeedere perchè il servizio è connection-oriented.
Comunque anche se UDP è connectionless, ci si aspetta che, come per TCP, i pacchetti in qualche modo arrivino (con magari qualcuno perso) anche se salta uno dei router intermedi momentaneamente, invece a causa della traduzione della porta sorgente, se salta il router del nat saltano anche tutte le connessioni UDP in modo permanente, non è che perdo qualche pacchetto.. i due host non ricevono più dati da entrambi i lati della comunicazione.
Bè, ovviamente se uno usa UDP vorrebbe che i pacchetti arrivassero, ma allo stesso modo se usi UDP non hai la certezza che ciò accada per tutti i pacchetti, quindi il fatto che gli host non ricevano nulla è, sotto un certo punto di vista, previsto e lo sviluppatore che usa questo protocollo se lo deve aspettare.
UDP non è connectionless “un po’”, lo è “del tutto” 🙂
Sta poi allo sviluppatore, se vuole, aggiungere qualche garanzia di reliability al di sopra di questo protocollo.
Sì, capisco, comunque ti faccio un esempio stupido: RTP e SIP si appoggiano su udp, vengono entrambi usati per videoconferenze o trasmissione audio/video. È ovvio che in una telefonata te ne frega poco se perdi 1 pacchetto dati, è più importante la latenza e il jitter, quindi si è scelto di usare UDP per roba del genere.
Ma tra avere mezzo secondo di silenzio in una telefonata e vedersela invece terminare in faccia, però, c’è una bella differenza.
Se usi un NAT e riavvii il router ti salta la telefonata. Se usi un router “vero” che non fa nat, se riavvii il router (molto velocemente) avrai solo alcuni secondi di silenzio nella telefonata..