tunnel ssh

30/11/2016

create a local unix socket to communicate with remote unix socket

ssh -L localsocket:remotesocket host

// -q réduit les logs, (semble pas necessaire)
// -N permet de ne pas executer de commande (par defaut c'est un shell qui est lancé)
// il ne faut pas mettre -N car sinon ssh ne serait pas kill en cas de crash de nodejs, un zombie va persister
// si on met -N, et qu'on envoie SIGHUP à ssh le tunnel va se fermer
// si on met -N et qu'on a spécifié une commande, par exemple "sleep 10" le tunnel va se lancer et attendre 10 secondes qu'une autre commande soit lancée.
// Le tunnel se fermera des qu'il n'y aura plus de commande ni de sleep en cours.
// -T permet de ne pas allouer de tty, (semble pas necessaire)
// -C permet de compresser, (semble pas necessaire)
// -n permet d'ignorer stdin, (nike tout à moins d'avoir activé N => donc pas cool)
// -f permet de passer le process en background (semble as necessaire + necessite de passer une commande)

A => B => C

Cette commande peut etre lancée sur A
elle se connecte sur B depuis A.
et ensuite depuis B, cela redirige le port local 2222 (sur A) vers C port 22
(autrement dit un write sur A:2222 est lu sur C:22)

A# ssh root@B -L 2222:C:22

Il suffit donc de faire cette première commande dans un terminal, puis de lancer celle-ci dans un autre terminal en parallèle,
toujours depuis A pour parler à C via B en sftp

A# sftp -oPort=2222 localhost

aspect securité :
Si vous aviez déjà fait une connexion a localhost depuis A par le passé. La clé ssh était déjà enregistrée dans known host et du coup vous aurez une alerte de sécurité, mais ça marche quand même.
Si quelqu'un tente de se connecter a A:2222 il tombera bien sur C:22
Donc le proxy B ne fait plus du tout office de proxy / pare-feu dans le sens ou il ne filtre plus les connections.
A mon sens cela reste cependant suffisament protégé car même dans ce cas une clé ssh ou un mot de passe pour accéder à C reste nécéssaire.

Bref, par exemple cette commande permet de lister des fichiers
echo 'ls' | sftp -oPort=2222 root@localhost

pour piloter tout ça depuis nodejs je suppose qu'il suffit de faire :

const { spawn } = require('child_process');

// créer le tunnel
let tunnel = spawn('ssh', ['-L', '2222:C:22', '-q', '-C', '-N', 'root@B']);

tunnel.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});
tunnel.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});
tunnel.on('close', (code) => {
  console.log(`tunnel closed with code ${code}`);
});
tunnel.on('error', (err) => {
  throw err;
});

await delay(3000);

// lancer des commandes sftp en utilisant le port localhost:2222
// via une lib nodejs ou directement le binaire sftp

// kill le tunnel
tunnel.kill('SIGHUP');

A <= B

On veut que A devienne accessible de l'extérieur (B est est le seul a etre accéssible de l'exterieur):
A est derrière un NAT
B est accessible par les deux
C est derrière un NAT ou pas
port forward sur B

AllowTcpForwarding yes

D'un coté on fait ça :

root@A:~# ssh -nNT -R 1103:localhost:22 root@B

De l'autre on fait ça :

root@C:# ssh root@B
root@B:# ssh root@localhost -p 1103

pour que le tunnel se relance tout seul en cas de plantage ou de pare feu chiant on peut mettre cette comamnde dans le cron :

@reboot autossh -M 10984 -N -f -o "PubkeyAuthentication=yes" -R 1103:localhost:22 root@B &