Mosh, IRC, les multi-connections ssh et NAT

Retour accueil


Sur bebou nous avons un serveur IRC. J’aime bien avoir une fenêtre ouverte en continu sur le serveur afin de répondre rapidement aux copaines. L’objectif est :

Ne rien rater de ce qui se raconte sur IRC

À la création d’un compte, le serveur lance automatiquement une session tmux avec un client IRC dedans. De cette manière quand une personne quitte sa session, tmux continue à tourner, le client reste ouvert et ainsi elle ne passera à côté d’aucun message.

A l’usage c’est génial sauf que si vous utilisez ssh vous n’êtes pas sans savoir que c’est fragile. ssh fonctionne de telle manière à ce que la connexion saute au moindre souci. Vous avez perdu la wifi pendant une seconde ? Plus de connexion. Vous avez mis votre ordi en veille ? Plus de connexion. La session tmux permet de ne pas perdre l’état de la session sur laquelle vous étiez1 mais il faudra tout de même vous y reconnecter.

Ne jamais perdre sa connexion

C’est là qu’intervient mosh. Je ne vous fais pas la réclame complète, vous pouvez aller sur le site du projet directement. Ce qui nous intéresse ici est principalement la capacité de mosh à récupérer la connexion là où elle s’est arrêtée partout où avec ssh elle aurait ét morte pour de bon. On ouvre la session une fois au démarrage de son pc puis on l’oublie, elle sera toujours vivante. Second besoin satisfait.

Si vous en êtes là vous constaterez une chose : lancer une nouvelle commande ssh prend tout de même du temps. En effet, par défaut, le client ssh initie une nouvelle connexion pour chaque ouverture de session. Il faudra repasser par tout le système d’authentification à chaque fois, ce qui prend du temps. On pourrait penser qu’il est possible de réutiliser la connexion existante et ainsi s’économiser de précieuses secondes.

Réutiliser la connexion

Effectivement, c’est possible avec la configuration ssh suivante, à mettre dans son ~/.ssh/config :

Host *
ControlMaster auto
ControlPath  ~/.ssh/sh-%r@%h:%p
ControlPersist yes

La dernière ligne est essentielle si l’on utilise mosh. À la connexion mosh ouvre une connexion ssh pour échanger des clefs de chiffrement, la ferme instantanément puis ouvre une session mosh. ControlPersist yes permet de conserver le socket créé à cette occasion même après la fermeture de la connexion ssh.

Sécurité : avant d’adopter cette configuration demandez vous si cela vous expose à un risque que vous ne pouvez pas accepter. En effet si on la combine avec un agent ssh relaxe, du type à ne presque jamais demander le mot de passe des clefs ssh, c’est la porte ouverte à toute connexion du moment que l’on mette la main sur votre ordinateur. Pas forcément grave pour bebou mais certainement plus dans un cadre professionnel par exemple. Si vous voulez plus de sécurité vous pouvez jouer sur la valeur de ControlPersist afin d’avoir un timeout par exemple. Voir man ssh_config. Il est également possible d’avoir un script tiers qui désactive la clef dans votre agent ssh et/ou supprime le socket à la mise en veille de votre pc. Posez vous les bonnes questions et adoptez le bon niveau de sécurité.

Faire fonctionner ControlMaster et mosh ensemble vers un serveur NATé

On pourrait en avoir fini sauf que non ! Pour ouvrir une connection, mosh a besoin de connaître l’ip de la machine distante. Pour cela il existe plusieurs techniques. Celle par défaut de mosh, nommée “proxy”, utilise la ProxyCommand d’ssh pour récupérer le nom canonique de l’hôte distant et ainsi son ip. Malin. Sauf que, comme nous l’enseigne cette issue, la configuration ControlMaster désactive ProxyCommand. La personne qui développe mosh a retenu comme solution de forcer la désactivation de ControlMaster lors de la connexion ssh qui précède la connexion mosh avec un -S2. Certaines personnes voulant tout de même utiliser ControlMaster, deux autres techniques ne nécessitant pas ProxyCommand on été implémentées. L’une, local, consiste à vérifier des valeurs de variables d’environnement locales (à vous de les setup). L’autre, remote, profite de la première connexion ssh pour exécuter une commande donnant l’ip sur la machine distante, lit ce résultat et le passe au processus exécutant la commande mosh-client. Dans le code d’origine de mosh cette technique repose sur le contenu de la variable d’environnement $SSH_CONNECTION. Malheureusement sur un serveur NATé, tel que bebou, $SSH_CONNECTION contiendra l’ip locale du serveur et non pas l’ip du routeur derrière lequel il est. Pour récupérer la bonne ip il convient donc de modifier la commande shell lancée à distance pour une commande donnant la bonne ip, par exemple un curl vers https://ipinfo.io/ip. En l’occurrence dans la version que j’ai, on modifie la ligne 368 :

shell_quote ( '[ -n "$SSH_CONNECTION" ] && printf "\nMOSH SSH_CONNECTION %s\n" "$SSH_CONNECTION"' ) .

par :

shell_quote ( 'printf "\nMOSH SSH_CONNECTION c d %s e\n" "$(curl -sS http://ipinfo.io/ip)"' ) .

Si vous préférez une autre technique pour récupérer l’ip mettez ce que vous voulez à la place du curl. Après cette modification on pourra utiliser l’option --experimental-remote-ip=remote de mosh pour forcer l’utilisation de cette technique en lieu de celle qui désactive ControlMaster.

Le résultat de toute cette affaire : dès que l’on lance une session mosh, y compris vers un serveur NATé, un socket persistant est créé !


  1. et ce serait la première raison d’être des multiplexeurs type tmux et screen. Ayant découvert cette informatique à un moment où les connexions étaient déjà très fiables dans les grandes villes française je n’avais jamais perçu cet avantage là. Je pensais que c’était pour avoir plusieurs fenêtre sur un même terminal. 

  2. vous pouvez aller lire tout ça dans le script mosh en faisant un vim $(whereis mosh). C’est du perl et c’est lisible. Le -S est ligne 408 par exemple. On y voit la construction de la commande ssh qui sera lancée, avec la commande proxy contenant un %h permettant de récupérer le nom canonique de l’hôte.