Download tramite Bash
by admin on Sep.24, 2011, under Linux, Networking
Nel post intitolato “Bash Socket Programming” avevo trattato l’argomento relativo alla possibilità, sotto bash e tramite i device /dev/tcp e /dev/udp, di aprire un socket e far passare dei dati attraverso di esso, affermando anche che in tal modo non è più necessario, ad esempio, avere a disposizione comandi come wget o curl o lynx per ottenere i dati da un server remoto.
Rivedendolo a distanza di tempo mi sono accorto che gli esempi a corredo non si estendevano ad includere una soluzione per una esigenza molto comune e pratica, cioè il download di files remoti via HTTP.
Qui invece, vi è l’esempio di come un socket tcp gestito tramite bash possa venire usato a tale scopo.
Ipotizziamo, per comodità, di trovarci a dover scaricare l’ultima release di Asterisk da una macchina, priva di qualsiasi browser, e sprovvista degli abituali tools finalizzati al download.
Quanto basta è solamente:
# (echo -e "GET /pub/telephony/asterisk/releases/asterisk-1.8.7.0.tar.gz HTTP/1.0rnrn" 1>&3 & cat 0<&3) 3<> /dev/tcp/downloads.asterisk.org/80 | (read i; while [ "$(echo $i | tr -d 'r')" != "" ]; do read i; done; cat) > asterisk-1.8.7.0.tar.gz
Appena lanciato il comando è possibile verificare da un altro terminale che è effettivamente stata stabilita una connessione al server specificato:
# netstat -t Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 silversurfer:46365 downloads.asterisk.:www ESTABLISHED
mentre il file specificato si sta generando nella directory corrente fino a raggiungere le dimensioni originali:
# ls -lrt -rw-r--r-- 1 myuser mygroup 27828568 2011-09-24 00:42 asterisk-1.8.7.0.tar.gz
successivamente potremo verificare che il file sia stato correttamente trasferito:
# sha1sum asterisk-1.8.7.0.tar.gz |grep "e28ad2f52a227acc7ec6d6952f3fd41baecd6292" e28ad2f52a227acc7ec6d6952f3fd41baecd6292 asterisk-1.8.7.0.tar.gz
Vediamo come opera il codice bash utilizzato per effettuane il download:
Per scaricare un file tramite HTTP, occorre connettersi al server, inviare una richiesta HTTP (in questo caso “GET / HTTP/1.0″) eventualmente seguita da qualsiasi altro HTTP headers sia opportuno specificare, e da una linea vuota. Il server HTTP dovrebbe replicare di conseguenza con uno status code e relativo significato (tipo “200 OK”), altri headers HTTP, una linea vuota, quindi il contenuto.
Sappiamo già che in bash, è possibile aprire network socket, tramite l’ interface virtuale /dev/tcp/<server>/<porta>. Infatti reindirizziamo la richiesta HTTP a /dev/tcp/downloads.asterisk.org/80 proprio per contattare il server downloads.asterisk.org sulla porta 80. Tuttavia, dato che ogni singola operazione su /dev/tcp crea una nuova connessione e infine la chiude, dobbiamo riuscire a mantenere la stessa connessione e da essa ottenere il contenuto desiderato.
Ciò si effettua creando una subshell, ed impostando il file descriptor 3 per leggere dal e scrivere sul socket:
# (echo -e "GET /pub/telephony/asterisk/releases/asterisk-1.8.7.0.tar.gz HTTP/1.0rnrn" 1>&3 & cat 0<&3) 3<> /dev/tcp/downloads.asterisk.org/80
I due comandi nella subshell vengono eseguiti in modo concorrente, pertanto il comando echo è seguito da un carattere di ampersand (&) per procedere in background, mentre il suo output viene rediretto al file descriptor 3 (1>&3). Viene usato read per leggere l’ input, tramite pipe, sempre dal file descriptor 3 (0<&3).
Ciò avviene all’interno di un loop che legge tutti gli headers HTTP fino a trovare una linea vuota, quindi il resto viene passato a cat, ed infine rediretto su file.


September 25th, 2011 on 8:44 pm
Grazie per portare una vena di competenza in un mondo dominato da fanboy apple e blogolamer che discutono di temi di gnome, davvero.