Il y a un petit moment j'avais présenté une méthode pour envoyer
des mails à travers un tunnel SSH. Après un an de bons et loyaux services, j'en
arrive à vouloir étendre ce système bien pratique à un plus grand nombre de ports.
Alors VPN ? Ben non, encore ce bon vieux SSH mais utilisé d'une "nouvelle" manière.
Le besoin
Le besoin d'origine était de pouvoir, de mon portable et de n'importe où, envoyer un
mail de manière sécurisée. J'avais à l'époque joué avec la capacité de redirection de
ports de SSH. J'envoyais alors mon courrier sur le port 25 local et il était émis à
travers un tunnel chiffré sur le port 25 de mon serveur de courrier.
Mais récemment, j'ai été amené à étendre cette logique à d'autres services. Étant obligé
pendant un temps de passer par une connexion 3G, j'ai ainsi voulu appliquer le même
principe à la réception de mail (IMAP) mais aussi au chat (bitlbee & IRC) et au web. En
gros à tout mon trafic externe quoi.
Pour ceux qui se demanderait quel intérêt peut on avoir de s'enquiquiner de la sorte, une petite liste
non exhaustive des raisons :
-
Déjà pour accéder à des services sur une machine distante que l'on ne
souhaite pas ouvrir sur le net généralement par soucis de sécurité ET de
simplicité. C'est typiquement le cas de mon service SMTP. Passer par un tunnel me
permet d'envoyer du courrier comme si j'étais sur mon réseau local, de manière sûre et
sans problématique de sécurité supplémentaire.
-
Ensuite, pour ne plus se soucier d'emprunter des connexions douteuses. En effet en mode
"nomade", on est déjà content d'avoir un réseau, on ne va pas en plus faire le
difficile. Et pourtant, entre la 3G d'un opérateur qui porte une couleur comme marque
et qui pratique
le DPI à ses heures perdues, la connexion d'un hôtel dont tout les
routeurs ont admin/admin comme identifiant/mot de passe, la borne WIFI du voisin
imprudent qui ne l'est peut-être pas, il vaut mieux être un minimum méfiant. Avoir son
trafic ainsi chiffré est une véritable paix de l'esprit dans ce genre de situation.
-
Enfin simplement pour améliorer la qualité des connexions. On ne parle pas non plus de miracle, mais un
tunnel SSH dispose de deux caractéristiques bien pratiques. D'abord il est possible
d'activer la compression des données, ce qui dans certain cas est très significatif.
Un fichier texte (ex. un mail) se comprime à 30% de son volume initial... Ensuite le
tunnel dispose de mécanisme permettant de vérifier que la connexion est toujours
viable et permet même de récupérer sa connexion en cas de coupure (pas trop longue).
Autant de raisons qui font du tunnel chiffré un précieux outil. Reste maintenant à voir
comment généraliser la bidouille d'origine à tout le trafic sans pour autant passer par
un VPN pur et dur ou par une avalanche de TUN/TAP/iptables.
SOCKS
SOCKS est un protocole qui permet (en simplifié) à une application cliente
d'accéder aux ressources réseau d'une machine distante. Ainsi, au lieu d'accéder directement au
net, l'application cliente va uniquement causer au service SOCKS qui lui va parler au
net. Dans sa version 5 (RFC 1928) ce
protocole permet outre la transmission TCP, la transmission UDP, l'authentification, la
résolution des noms de domaine et la prise en charge d'IPv6.
Or il se trouve que dans sa grande générosité, SSH offre le protocole SOCKS V5. Une
application cliente va ainsi pouvoir parler SOCKS dans un port ouvert par SSH pour cet
usage, ce dernier va faire transiter les demandes par le tunnel SSH et ces dernières
seront "exécutées" sur la machine distante.
Pour tester cela en 10 secondes, rien du plus simple. Il vous faut une
machine distante accessible et bien évidemment connectée au net et un compte sur cette
machine. Si tel est le cas, dans un terminal, lancez la commande suivante
gaston$ssh -nvNT -C -D 1080 gaston@mon_serveur_distant
...
debug1: Local connections to LOCALHOST:1080 forwarded to remote address SOCKS:0
...
debug1: Entering interactive session
Voilà c'est gagné. Vous avez maintenant un service local SOCKS sur le port 1080 prêt à
discuter bout de net avec la machine distante.
On s'arrête un peu sur les arguments utilisés. -n indique juste qu'il n'y a
aucune saisie clavier à attendre de notre part (dit autrement /dev/null redirigé sur
stdin). -N pour signifier à SSH qu'il n'y a aucune commande à lancer, on ne
cherche qu'à créer un tunnel pour le proxy SOCKS. Et pour enfoncer le clou,
-T désactive toute allocation de pseudo terminal.
-D 1080, c'est la partie intéressante, on demande à SSH de créer un
service SOCKS sur le port local 1080. À partir de là, toute requête faite sur
le port 1080 de la machine locale, passera par le tunnel chiffré et sera
exécutée sur la machine distante.
-C va quant à lui activer la compression du trafic et
enfin -v est juste là pour rendre SSH plus bavard. Suivent enfin
le nom d'utilisateur à utiliser pour la connexion et le nom de la machine
distante.
Pour tester cela, prenez Iceweasel/Firefox et allez modifier les réglages
dans Édition ⇨ Préférences ⇨ Avancées ⇨ Réseau ⇨ Réglages pour cocher Configuration manuelle
du proxy. Dans le champs SOCKS host nous allons mettre
localhost et 1080 dans le champ Port. Cochez SOCKS
v5 puis validez. Il ne vous reste plus qu'à aller sur votre site préféré pour
voir SSH jacasser dans son terminal, votre trafic passe maintenant par le tunnel SSH.
Petite note pour ceux qui comme moi sont amoureux de VIM et qui utilisent donc forcement
le fantastique pentadactyl, il est
possible d'activer/désactiver le proxy en ajoutant ceci à votre
~/.pentadactylrc
command! -nargs=1 proxy :set! network.proxy.type=<args>
Ceci fait, un coup de :restart et vous pouvez activer le proxy par
:proxy 1 et le désactiver (et donc ne plus utiliser le tunnel) par
:proxy 0.
Script de contrôle du tunnel
Tout ceci est bien sympa, reste à le rendre fonctionnel à travers un script qui pourra
allumer, éteindre et vérifier l'état du tunnel. Dans la mesure où je suis un membre de
la secte "moins je touche au système et plus j'en ai dans mon dossier ~, mieux je me
porte, je crée ici un script qui sera exécutable sans droits particulier tout en
fonctionnant de manière très similaire aux scripts présents en /etc/init.d :
#! /bin/bash
# nom du service
name=tunnel
# paramétres
port=1080
user=gaston
host=machine_distante
# PID et logs
pid_file=~/.local/var/run/$name
log_file=~/.local/var/logs/$name.log
mkdir -p $(dirname $pid_file) $(dirname $log_file)
# Arrêt du service
function stop {
if [ -f $pid_file ] ; then
echo -n "Arrêt de $name..."
kill -9 $(cat $pid_file)
rm $pid_file
echo "OK"
fi
}
# Démarrage du service
function start {
stop
echo -n "Démarrage de $name..."
command="ssh -nvNT -C -D $port $user@$host"
($command &> $log_file) &
echo $! > $pid_file
until nc -zw30 localhost $port &> /dev/null ; do
echo -n "."
sleep 1
done
echo " OK"
}
# test
function check {
if nc -zw30 localhost $port &> /dev/null ; then
echo "actif"
return 0
else
echo "inactif"
return 1
fi
}
# commandes
case $1 in
"start")
start ;;
"stop")
stop ;;
"check")
check ; exit $? ;;
*)
echo "usage: $(basename $0) start|stop"
exit 1
esac
Ce script fonctionne donc comme les scripts de démarrage de service système
à la différence prés que le PID du processus SSH et ses logs sont stockés en
local, sur mon compte, dans les dossiers ~/.local/var/logs et
~/.local/var/run/.
Le tunnel se lance par un tunnel start,
s'arrête par un tunnel stop et son état peut être lu par un
tunnel check. Cette dernier commande me permet d'afficher l'état du
tunnel dans la barre d'info d'awesome ce qui est bien pratique.
Pour compléter le dispositif, vous pouvez configurer dans votre ~/.ssh/config
un temps au bout duquel SSH devra vérifier si le tunnel est encore fonctionnel. Bien
utile lorsque l'on passe par de la 3G.
Host *
ServerAliveInterval 5
~/.ssh/config
Ouvrir le tunnel à la connexion
Il est possible de pousser un cran plus loin l'automatisation en lançant automatiquement
le tunnel à la connexion et en le tuant à la déconnexion. En tout cas c'est possible
avec l'excellentissime wicd. Pour ceux qui ne connaîtrait pas cet outil,
c'est le gestionnaire de connexion le plus efficace pour qui construit un bureau
minimaliste. Il permet de gérer les connexions filaires, les connexions USB/RNIS (modem
3G via android), et les connexions WIFI de manière fiable et robuste, à travers une
interface en ligne de commande ou en ncurses (il y aussi une version graphique pour ceux
que cela amuse).
Wicd autorise la mise en place de scripts exécutés avant et après la connexion et la
déconnexion. Ces scripts ne sont malheureusement pas dans un dossier ~/.wicd
ce qui est bien triste mais dans le dossier /etc/wicd/scripts. Il suffit donc
de lancer le tunnel en ajoutant le code suivant dans /etc/wicd/scripts/postconnect/tunnel.sh
#! /bin/bash
sudo -u gaston /home/gaston/bin/tunnel start
/etc/wicd/scripts/postconnect/tunnel.sh
Le second script je vous laisse l'écrire, il se place dans
/etc/wicd/scripts/postdisconnect/tunnel.sh.
À partir de là, il suffit de lancer wicd-ncurses, de se connecter et hop, le
tunnel est actif.
Et les autres applications ?
La grande majorité des applications qui utilisent le net offrent un support pour SOCKS
v5. Une page bien pratique pour savoir comment faire est le manuel de configuration des
applications pour le réseau TOR.
Cependant pour toutes les autres applications qui ne savent pas utiliser un proxy SOCKS
(au hasard mutt), il existe une solution magique : proxychains
Proxychains est un superbe utilitaire qui va servir de lanceur pour les applications
réseau. Son fonctionnement consiste à intercepter les appels aux sockets pour les
rediriger sur le serveur mandataire qui va bien. Cela fonctionne très bien pour la
grande majorité des applications. Cela permet aussi d'utiliser le proxy sur des
applications qui prennent en charge SOCKS mais pour lesquels nous n'avons envie de nous
prendre la tête.
Proxychains est en standard dans les dépôts Debian (et sûrement dans celui d'autres
distribs). Pour l'installer vous devez donc lancer un sudo aptitude install
proxychains.
Lorsque c'est fait, prenez votre éditeur préféré et éditez
~/.proxychains/proxychains.conf :
strict_chain
quiet_mode
proxy_dns
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
socks5 127.0.0.1 1080
L'option strict_chain indique que les proxys doivent être chaînés dans
l'ordre de leur déclaration. En effet, l'outil est velu et ne porte pas ce drôle de nom
pour des prunes. Il permet en effet de chaîner toute une série de proxys les uns aux
autres. Mais dans notre cas seul un proxy sera déclaré, pas besoin donc d'aller plus loin.
quiet_mode demande gentiment à proxychains d'arrêter
de jacasser dans stdout. Mine de rien sans cela c'est assez pénible.
proxy_dns va quant à lui permettre de faire aussi passer les
requêtes DNS dans le tuyau du proxy. C'est un peu plus long mais ainsi tout
passe dans le tunnel sans écoute possible.
Je passe sur les quelques timeouts de bonne hygiène pour en venir à
l'essentiel, la déclaration de la liste des proxy qui dans notre cas ne
contiendra que socks5 127.0.0.1 1080, le service que nous avons
créé plus haut.
Il ne reste maintenant plus qu'à lancer une commande nécessitant l'accès au
réseau :
gaston$proxychains wget -O - http://artisan.karma-lab.net
Et c'est tout. Comme vous le voyez, c'est plutôt simple d'usage et cela fonctionne sur à
peu prés toutes les commandes (mutt, wget, telnet, etc). La seule application qui lui
dit "crotte" jusqu'ici c'est weechat qui dispose de toute façon d'une très bonne prise
en charge native de SOCKS.
Amélioration de la vérification du tunnel
Fort de notre connaissance de proxychains, nous pouvons améliorer le script d'ouverture
du tunnel pour ne pas simplement dire actif lors d'un tunnel check
mais de nous renvoyer plutôt la qualité du tunnel, ce qui est fort pratique.
Pour cela il nous suffit de modifier comme ceci
function check {
if nc -zw30 localhost $port &> /dev/null ; then
lattence=$(proxychains nmap -sP azuris.karma-lab.net|grep -Eo '[[:digit:]]+\\.[[:digit:]]+s' | tr -d 's')
echo $lattence
return 0
else
echo "inactif"
return 1
fi
}
Le principe est d'utiliser la commande nmap pour aller faire un ping sur le
serveur distant à travers le tunnel via proxychains. Une fois le ping reçu,
nmap fournit la latence exprimée en secondes que l'on n'a plus qu'à grepper.
Conclusion
Une fois de plus SSH s'impose en outil incontournable. Comme je le disais plus haut,
chez moi le tunnel SOCKS fait maintenant partie intégrante de mon "bureau", se lance
tout seul dés lors qu'une connexion sur le net est ouverte. Et comme tout
ceci ne repose que sur SSH et des scripts "userland", cela fonctionne de manière propre
et homogène sur toutes mes machines sans configuration (mon dossier home étant
synchronisé d'une machine à l'autre via unison).