web-dev-qa-db-fra.com

Comment puis-je tuer une session SSH avec arrière-plan/détachée?

J'utilise la synergie du programme avec un tunnel SSH

Cela fonctionne, je dois juste ouvrir une console et taper ces deux commandes:

ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost

parce que je suis paresseux, j'ai créé un script Bash qui est exécuté avec un clic de souris sur une icône: 

#!/bin/bash
ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
synergyc localhost

le Bash-Script ci-dessus fonctionne aussi, mais maintenant je veux aussi tuer la synergie et le tunnel ssh via un clic de souris, donc je dois sauvegarder les PID de synergie et ssh dans un fichier pour les tuer plus tard:

#!/bin/bash

mkdir -p /tmp/synergyPIDs || exit 1
rm -f /tmp/synergyPIDs/ssh || exit 1
rm -f /tmp/synergyPIDs/synergy || exit 1

[ ! -e /tmp/synergyPIDs/ssh ] || exit 1
[ ! -e /tmp/synergyPIDs/synergy ] || exit 1

ssh -f -N -L localhost:12345:otherHost:12345 otherUser@OtherHost
echo $! > /tmp/synergyPIDs/ssh
synergyc localhost
echo $! > /tmp/synergyPIDs/synergy

Mais les fichiers de ce script sont vides.

Comment puis-je obtenir les PID de SSH et de synergie?
(J'essaie d'éviter les combinaisons ps aux | grep ... | awk ... | sed ..., il doit y avoir un moyen plus simple.)

58
Skaarj

et bien je ne veux pas ajouter un & à la fin des commandes car la connexion mourra si la console est fermée ... alors je me suis retrouvé avec un ps-grep-awk-sed-combo

ssh -f -N -L localhost:12345:otherHost:12345   otherUser@otherHost
echo `ps aux | grep -F 'ssh -f -N -L localhost' | grep -v -F 'grep' | awk '{ print $2 }'` > /tmp/synergyPIDs/ssh
synergyc localhost
echo `ps aux | grep -F 'synergyc localhost' | grep -v -F 'grep' | awk '{ print $2 }'` > /tmp/synergyPIDs/synergy

(vous pouvez intégrer grep dans awk, mais je suis trop paresseux maintenant)

12
Skaarj

Résumé rapide: ne fonctionnera pas.

Ma première idée est que vous devez démarrer les processus en arrière-plan pour obtenir leurs PID avec $!.

Un motif comme

some_program &
some_pid=$!
wait $some_pid

peut faire ce dont vous avez besoin ... sauf qu'alors ssh ne sera plus au premier plan pour demander plus de mots de passe.

Eh bien, vous pourriez avoir besoin de quelque chose de différent après tout. ssh -f génère probablement un nouveau processus que votre shell ne peut jamais savoir de l'invoquer de toute façon. Idéalement, SSH lui-même offrirait un moyen d'écrire son PID dans un fichier.

72
ndim

Avec tout le respect que je dois aux utilisateurs de pgrep, pkill, ps | awk, etc., il existe un moyenmuchbetter.

Considérez que si vous utilisez ps -aux | grep ... pour trouver un processus, vous courez le risque d’une collision. Vous pouvez avoir un cas d'utilisation où cela est peu probable, mais en règle générale, ce n'est pas la voie à suivre.

SSH fournit un mécanisme de gestion et de contrôle des processus en arrière-plan. Mais comme beaucoup de choses SSH, c'est une fonctionnalité "avancée", et beaucoup de gens (il semble, d'après les autres réponses ici) ne sont pas conscients de son existence.

Dans mon propre cas d'utilisation, j'ai un poste de travail chez moi sur lequel je veux laisser un tunnel qui se connecte à un proxy HTTP sur le réseau interne de mon bureau et un autre qui me donne un accès rapide aux interfaces de gestion sur des serveurs co-localisés. . Voici comment créer les tunnels de base, initiés de chez vous:

$ ssh -fNT -L8888:proxyhost:8888 -R22222:localhost:22 officefirewall
$ ssh -fNT -L4431:www1:443 -L4432:www2:443 colocatedserver

Celles-ci provoquent ssh à l'arrière-plan, laissant les tunnels ouverts. Mais si le tunnel s'en va, je suis bloqué et si je veux le trouver, je dois analyser ma liste de processus et chez moi, j'ai le "bon" ssh (au cas où j'en aurais accidentellement lancé plusieurs similaire).

Si je souhaite gérer plusieurs connexions, j'utilise plutôt l'option ControlMaster config de SSH, ainsi que l'option de ligne de commande -O pour le contrôle. Par exemple, avec les éléments suivants dans mon fichier ~/.ssh/config,

Host officefirewall colocatedserver
    ControlMaster auto
    ControlPath ~/.ssh/cm_sockets/%r@%h:%p

les commandes ssh ci-dessus, une fois lancées, laisseront spoor dans ~/.ssh/cm_sockets/ qui peut ensuite fournir un accès au contrôle, par exemple:

$ ssh -O check officefirewall
Master running (pid=23980)
$ ssh -O exit officefirewall
Exit request sent.
$ ssh -O check officefirewall
Control socket connect(/home/ghoti/.ssh/cm_socket/[email protected]:22): No such file or directory

Et à ce stade, le tunnel (et le contrôle de la session SSH) a disparu sans qu'il soit nécessaire d'utiliser un marteau (kill, killall, pkill, etc.).

Cela ramène à votre cas d'utilisation ...

Vous établissez le tunnel par lequel vous voulez que syngergyc communique avec syngergys sur le port TCP 12345. Pour cela, je procéderais comme suit.

Ajoutez une entrée à votre fichier ~/.ssh/config:

Host otherHosttunnel
    HostName otherHost
    User otherUser
    LocalForward 12345 otherHost:12345
    RequestTTY no
    ExitOnForwardFailure yes
    ControlMaster auto
    ControlPath ~/.ssh/cm_sockets/%r@%h:%p

Notez que l'option -L de la ligne de commande est gérée avec le mot clé LocalForward et que les lignes Control {Master, Path} sont incluses pour vous assurer que vous avez le contrôle après l'établissement du tunnel.

Ensuite, vous pouvez modifier votre script bash en quelque chose comme ceci:

#!/bin/bash

if ! ssh -f -N otherHosttunnel; then
    echo "ERROR: couldn't start tunnel." >&2
    exit 1
else
    synergyc localhost
    ssh -O exit otherHosttunnel
fi

L'option -f sert d'arrière-plan au tunnel, laissant un socket sur votre chemin d'accès ControlPath pour fermer le tunnel ultérieurement. Si ssh échoue (ce qui peut être dû à une erreur réseau ou à ExitOnForwardFailure), il n'est pas nécessaire de quitter le tunnel, mais s'il n'échoue pas (else), Synergyc est lancé, puis le tunnel est fermé.

Vous voudrez peut-être également vérifier si l'option SSH LocalCommand peut être utilisée pour lancer synergyc à partir de la droite de votre fichier de configuration ssh.

53
ghoti

je viens de trouver ce fil et je voulais mentionner l'utilitaire Linux "pidof":

$ pidof init
1
21
zrathen

Vous pouvez utiliser lsof pour afficher le pid du processus écoutant le port 12345 sur localhost:

lsof -t -i @localhost:12345 -sTCP:listen

Exemples:

PID=$(lsof -t -i @localhost:12345 -sTCP:listen)
lsof -t -i @localhost:12345 -sTCP:listen >/dev/null && echo "Port in use"
15
Atle

Vous pouvez supprimer le -f, ce qui le fait exécuter en arrière-plan, puis avec eval et le forcer vous-même à l'arrière-plan. 

Vous pouvez alors récupérer la pid. Assurez-vous de mettre le & dans l'instruction eval.

eval "ssh -N -L localhost:12345:otherHost:12345 otherUser@OtherHost & " 
tunnelpid=$!
9
l0k3y3

C'est plus un cas spécial pour synergyc (et la plupart des autres programmes qui essaient de se démoniser). Utiliser $! fonctionnerait, sauf que synergyc fait un appel système clone () pendant l'exécution qui lui donnera un nouveau PID différent de celui que bash pensait l'avoir. Si vous voulez contourner cela pour pouvoir utiliser $ !, vous pouvez dire à synergyc de rester dans le premier plan, puis de l’arrière-plan.

synergyc -f -n mydesktop remoteip &
synergypid=$!

synergyc fait également quelques autres choses, comme le redémarrage automatique, que vous pouvez désactiver si vous essayez de le gérer.

4
deltaray

Une autre option consiste à utiliser pgrep pour trouver le PID du processus ssh le plus récent.

ssh -fNTL 8073:localhost:873 otherUser@OtherHost
tunnelPID=$(pgrep -n -x ssh)
synergyc localhost
kill -HUP $tunnelPID
3
Lenny

Vous pouvez rechercher le processus ssh lié à votre port local en utilisant cette ligne:

netstat -tpln | grep 127\.0\.0\.1:12345 | awk '{print $7}' | sed 's#/.*##'

Il renvoie le PID du processus utilisant le port 12345/TCP sur localhost. Il n'est donc pas nécessaire de filtrer tous les résultats ssh de ps.

Si vous avez juste besoin de vérifier, si ce port est lié, utilisez:

netstat -tln | grep 127\.0\.0\.1:12345 >/dev/null 2>&1

Renvoie 1 si aucun lien n'est lié ou 0 si quelqu'un écoute ce port.

2
foo

Sur la base de la très bonne réponse de @ghoti, voici un script plus simple (à tester) utilisant les prises de contrôle SSH sans nécessiter de configuration supplémentaire:

#!/bin/bash
if ssh -fN -MS /tmp/mysocket -L localhost:12345:otherHost:12345 otherUser@otherHost; then
    synergyc localhost
    ssh -S /tmp/mysocket -O exit otherHost
fi

synergyc ne sera démarré que si le tunnel a été établi avec succès et sera fermé dès le retour de synergyc .

0
doak