sshtunnel

SSH Tunneling e UDP over TCP

SSH tunneling

Il tunneling SSH (detto anche “port forwarding”) è una tecnica per incanalare una comunicazione TCP in una connessione SSH.
Il concetto è semplice: apro una connessione con un server SSH (ovviamente devo avere un account su quel server) e indico al software quali porte mettere in comunicazione attraverso questa connesione.
Ci sono 2 diverse modalità di indicare le porte: il “local” oppure il “remote” port-forwarding (in realtà ci sarebbe anche quello dinamico, ma non lo affronterò qui).

Local port forwarding

Viene forwardata una porta locale, mettendola in comunicazione con l’ indirizzo di destinazione:

ssh -Nf -L 1234:localhost:5678 utente@server.com -p 9999

dopo che la connessione avrà avuto successo, il traffico che attraverserà la porta 1234 della macchina locale sarà immesso nel tunnel, e all’ uscita del tunnel sul server SSH sarà messo in comunicazione con l’ indirizzo specificato: localhost:5678, ovvero il server SSH stesso, in questo semplice esempio.

Per verificarlo proviamo il seguente comando sulla macchina locale:

$ netstat -tunelp | grep 1234

tcp 0 0 127.0.0.1:1234 0.0.0.0:* LISTEN 1000 836150 3251/ssh

Remote port forwarding

In questo caso, la situazione è ribaltata: mi connetto con un server SSH, e indico quale porta sul server SSH sarà messa in comunicazione con un indirizzo specificato sul lato della macchina locale:

ssh -Nf -R 1234:localhost:5678 utente@server.com -p 9999

dopo che il tunnel SSH è aperto, la porta 1234 del server SSH sarà in comunicazione con l’ indirizzo localhost:5678 relativo alla macchina locale, ovvero la macchina locale stessa in questo esempio.

I parametri di SSH

  • -f manda ssh in background
  • -N dice a SSH che non sarà eseguito alcun comando, ma sarà soltanto aperta una connessione
  • -L e -R indicano il port-forwarding locale e remoto, rispettivamente
  • -p indica ad SSH la porta a cui connettersi al server
  • -g: nel caso di local port-forwarding permette la connessione alla porta locale da tutte le macchine della subnet locale
  • -g: nel caso di remote port-forwarding permette la connessione alla porta remota da tutte le macchine della subnet remota

UDP over TCP

Il tunneling SSH funziona solo per connessioni TCP.
Se vogliamo far passare il traffico UDP (ad esempio il traffico DNS) bisogna prima fare una “traduzione” da UDP a TCP, trasmettere attraverso il tunnel, ricevere dall’ altra parte il traffico TCP, e riportarlo in UDP.

Il tutto si può fare con gli strumenti di Linux; vediamo come, passo per passo.

Tunnel SSH

Apriamo semplicemente una connessione, come sopra: mettiamo in comunicazione la porta 1234 della macchina locale con la porta 5678 del server remoto.

Da TCP a UDP sul server

Concetto: il traffico TCP che il server riceve sulla porta 5678 deve essere tradotto in UDP ed inviato a destinazione, mentre il traffico UDP che il server riceve dalla destinazione deve essere tradotto in TCP e immesso nel tunnel nella porta 5678.

Costruiamo il comando analizzando ogni singolo frammento:

# ricevo il traffico TCP dalla porta 5678
nc -l -p 5678
# quello che ricevo (sullo stdout) lo invio come UDP, per esempio sulla porta 9999
nc -l -p 5678 | nc -u indirizzo.com 9999

Ora vediamo come trattare il percorso inverso: nell’ ultimo comando, il processo di destra della pipe riceve in stdin dei dati e li invia a indirizzo.com; lo stdout sarà la risposta che il processo riceve da indirizzo.com.
Allora dobbiamo inviare questa risposta al processo di sinistra della pipe: infatti questo ascolta i dati dal tunnel sulla 5678 e li manda in stdout; ma ciò che esso riceve in stdin sarà inviato nel tunnel attraverso la 5678 !
Poichè la pipe (unnamed pipe) consente il passaggio di dati solo da sinistra a destra, avremo bisogno di una FIFO (named pipe): infatti una FIFO mette in comunicazione i processi che sono ad essa collegati.
In definitiva avremo:

mkfifo /path/to/fifo
nc -l -p 5678 < /path/to/fifo | nc -u indirizzo.com 9999 > /path/to/fifo

Per comprendere il significato del comando, facciamo questa prova:

nc -l -p 9999 < /path/to/fifo | tee PIPE | nc google.it 80 | tee FIFO > /path/to/fifo

Il comando tee prende lo stdin e lo invia allo stdout dopo averlo scritto in un file indicato come argomento: ciò ci permette di vedere cosa passa nella prima pipe e nell’ ultimo reindirizzamento alla fifo.
Infatti, se andiamo a richiedere la pagina HTML alla URL localhost:9999

wget localhost:9999

avremo il file PIPE che conterrà:

GET / HTTP/1.1
User-Agent: Wget/1.13.4 (linux-gnu)
Accept: */*
Host: localhost:9999
Connection: Keep-Alive

e il file FIFO che conterrà la pagina HTML richiesta, ad esempio

HTTP/1.1 302 Found
Location: http://www.google.com/
Cache-Control: private
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Date: Wed, 28 Mar 2012 13:01:08 GMT
Server: sffe
Content-Length: 219
X-XSS-Protection: 1; mode=block

302 Moved
<h1>302 Moved</h1>
The document has moved
<a href="http://www.google.com/">here</a>.

Da UDP a TCP sulla macchina locale

Come nel punto precedente, utilizziamo una fifo e netcat, facendo però attenzione che il processo di sinistra tratta UDP, quello di destra TCP.

mkfifo /path/to/fifo
nc -u -l -p 53 < /path/to/fifo | nc localhost 1234 > /path/to/fifo

Ora il traffico UDP (bidirezionale !) sulla porta 53 della macchina locale arriverà ad indirizzo.com:9999 passando attraverso il tunnel dalla porta locale 1234 alla porta remota 5678 come traffico TCP.

Riferimenti

About these ads

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...