Question Echec de la redirection de port distant SSH


Suivre: Il semble que la série de déconnexions rapides coïncidant avec quelques mois d’exécution de chaque serveur est probablement une coïncidence et ne fait que révéler le problème. La raison pour laquelle il n'a pas réussi à se reconnecter est presque certainement due aux valeurs AliveInterval (réponse de kasperd). L'utilisation de l'option ExitOnForwardFailure devrait permettre à la temporisation de se dérouler correctement avant la reconnexion, ce qui devrait résoudre le problème dans la plupart des cas. La suggestion de MadHatter (le script de suppression) est probablement le meilleur moyen de s'assurer que le tunnel peut se reconnecter même si tout le reste échoue.

J'ai un serveur (A) derrière un pare-feu qui initie un tunnel inverse sur plusieurs ports vers un petit VPS DigitalOcean (B) afin que je puisse me connecter à A via l'adresse IP de B. Le tunnel fonctionne de manière constante depuis environ 3 mois, mais a soudainement échoué à quatre reprises au cours des 24 dernières heures. La même chose s’est produite il ya quelque temps chez un autre fournisseur VPS: des mois de fonctionnement parfait, puis, tout à coup, de multiples défaillances rapides.

J'ai un script sur la machine A qui exécute automatiquement la commande de tunnel (ssh -R *:X:localhost:X address_of_B pour chaque port X) mais quand il s’exécute, il dit Warning: remote port forwarding failed for listen port X.

Entrer dans le sshd /var/log/secure sur le serveur montre ces erreurs:

bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X

La résolution nécessite le redémarrage du VPS. Jusque-là, toutes les tentatives de reconnexion donnent le message "Echec de la redirection du port distant" et ne fonctionneront pas. Nous en sommes maintenant au point où le tunnel ne dure que 4 heures environ avant de s’arrêter.

Rien n'a changé sur le SMV, et il s'agit d'un ordinateur à usage unique et à utilisateur unique qui ne sert que de point de terminaison de tunnel inverse. Il exécute OpenSSH_5.3p1 sur CentOS 6.5. Il semble que sshd ne ferme pas les ports de son côté lorsque la connexion est perdue. Je n'arrive pas à expliquer pourquoi, ou pourquoi cela se produirait soudainement après des mois de fonctionnement presque parfait.

Pour clarifier, je dois d’abord comprendre pourquoi sshd refuse d’écouter les ports après la défaillance du tunnel, ce qui semble être dû au fait que sshd a laissé les ports ouverts et ne les a jamais fermés. Cela semble être le problème principal. Je ne suis tout simplement pas sûr de ce qui le ferait se comporter après des mois de comportement conforme aux attentes (par exemple, fermer les ports immédiatement et permettre au script de se reconnecter).


23
2018-05-15 14:37


origine


Quelle est ta question? Comment résoudre l'erreur de liaison de port, ou comment savoir pourquoi ssh est en train de mourir, ou quelque chose d'autre? - MadHatter
Je dois comprendre pourquoi sshd refuse d'ouvrir les ports sur le VPS (erreur de liaison). L'erreur de liaison de port semble être la racine du problème, et tout devrait fonctionner si je suis capable de résoudre ce problème. - Justin Mrkva
Pour tous les utilisateurs tardifs, au lieu de créer manuellement un script pour maintenir la connexion ouverte, utilisez simplement autossh, qui le fait pour vous. serverfault.com/questions/598210/… - oligofren


Réponses:


Je conviens avec MadHatter qu'il est probable qu'il s'agisse de redirection de port à partir de connexions ssh disparues. Même si votre problème actuel s'avère être autre chose, vous pouvez vous attendre à rencontrer tôt ou tard de telles connexions ssh obsolètes.

Il existe trois manières de créer de telles connexions:

  • L'un des deux ordinateurs d'extrémité a été redémarré, tandis que l'autre extrémité de la connexion était complètement inactive.
  • L'un des deux points de terminaison a fermé la connexion, mais au moment où la connexion a été fermée, il y a eu une panne temporaire de la connexion. La panne a duré quelques minutes après la fermeture de la connexion. Ainsi, l’autre extrémité n’a jamais été informée de la connexion fermée.
  • La connexion est toujours complètement fonctionnelle aux deux extrémités de la connexion ssh, mais quelqu'un a placé un périphérique avec état entre eux, ce qui a entraîné un délai d'inactivité de la connexion. Ce périphérique avec état serait soit un NAT, soit un pare-feu, le pare-feu que vous avez déjà mentionné est le principal suspect.

Déterminer lequel de ces trois événements est en train de se produire n’est pas très important, car il existe une méthode qui les traitera tous les trois. C’est l’utilisation de messages keepalive.

Vous devriez regarder dans le ClientAliveInterval mot clé pour sshd_config et le ServerAliveInterval intervalle pour ssh_config ou ~/.ssh/config.

Lancer le ssh commande dans une boucle peut fonctionner correctement. Il est également judicieux d'insérer une veille dans la boucle afin d'éviter d'inonder le serveur lorsque la connexion échoue pour une raison quelconque.

Si le client se reconnecte avant la fin de la connexion sur le serveur, vous pouvez vous retrouver dans une situation où la nouvelle connexion ssh est active, mais sans redirection de port. Pour éviter cela, vous devez utiliser le ExitOnForwardFailure mot-clé côté client.


25
2018-05-15 15:14



Je pense que cela peut être le problème. En particulier, mon script sur A essaiera de se reconnecter à B si le processus ssh meurt (bien sûr, étant donné que le message d'avertissement ne tue pas le processus ssh, il se bloque lorsque cela se produit, mais c'est un problème pour un autre jour). Mais si A essaie de se reconnecter à B trop rapidement, il se peut que B attende que A se reconnecte. Je dois probablement m'assurer que B expire toujours avant que A se reconnecte. En combinant cela avec la suggestion de MadHatter de tuer les processus sshd avant de se reconnecter, cela couvrira probablement 95% des cas possibles. - Justin Mrkva
Et en parlant du message d’avertissement ne tuant pas SSH, cela m’a fait réfléchir ... et en regardant les pages de manuel. Il s'avère que -o ExitOnForwardFailure yes est exactement ce dont j'avais besoin. Donc, c'est une chose de moins que je dois comprendre. Pour penser, j'allais écrire un script Python pour analyser ces messages d'avertissement. C'est beaucoup plus simple. :RÉ - Justin Mrkva
Désolé d'avoir oublié ExitOnForwardFailure en écrivant ma réponse. Je l'ai ajouté à la réponse maintenant. - kasperd
Pas de problème, et c'était en fait -o ExitOnForwardFailure=yes (notez le signe égal). Donc, si quelqu'un rencontre cela, ne copiez et collez pas mon commentaire précédent, cela ne fonctionnera pas. : P - Justin Mrkva
J'ai donc surveillé le serveur pendant environ 10 heures et il semble que tout fonctionne bien. Je suppose à ce stade que cette réponse est correcte (je suis sûr à 99% sur la base de ce que j'ai vu) et que la série de déconnexions rapides était une coïncidence liée à des problèmes de réseau qui venaient de se produire quelques mois après à partir de chaque service. Merci à tous pour votre aide. ;) - Justin Mrkva


Vous pouvez trouver le processus qui lie le port sur ce serveur avec

sudo netstat -apn|grep -w X

Il semble très probable que ce soit le demi-défunt sshd, mais pourquoi faire des suppositions quand on peut avoir des données? C'est également un bon moyen pour un script de trouver un PID auquel envoyer le signal 9 avant d'essayer de rétablir le tunnel.


4
2018-05-15 14:53



Je me souviens d’avoir vérifié cela sur le fournisseur VPS précédent et j’ai confirmé que sshd était le processus qui écoutait ces ports. La prochaine fois que cela se produira, je vérifierai ici, mais comme le comportement et la configuration sont exactement les mêmes, je ne m'attends pas à ce que ce soit différent. - Justin Mrkva
Génial! Votre script qui rouvre le tunnel doit-il tuer le vieux tunnelier avant de tenter de le faire? - MadHatter
Il n'y a jamais plus d'un script de tunnel (sur A) en même temps, si c'est ce que vous dites. D'un autre côté, si vous voulez que le script exécute à distance une commande sur B pour supprimer les processus parasites ... ce n'est en fait pas une demi-mauvaise idée. Mais une préoccupation est de tuer à plusieurs reprises toutes les connexions SSH si j'essaie de déboguer. Si le script sur A tue toujours B en raison d'un problème, je ne peux pas être constamment renvoyé de B par le script A voyous. : P Je vais devoir tester pour m'assurer qu'il ne le fait pas. Mais comme je l'ai dit, ce n'est pas une mauvaise idée. ;) - Justin Mrkva
Je n'avais pas pensé qu'il y avait. Vous dites qu'il y a un script en cours d'exécution sur le serveur distant qui tente de créer un tunnel et échoue, en raison de l'erreur de liaison, et je suppose qu'il s'exécute uniquement lorsque vous en avez besoin (c'est-à-dire lorsque le tunnel existant n'est pas bon) parce que tu n'as pas dit le contraire. Tout ce que je suggère, c'est que cela élimine le processus spécifique qui maintient le port ouvert avant d'essayer de créer le nouveau tunnel. - MadHatter
Le script qui exécute ssh est uniquement sur le serveur A, le serveur B est un serveur simple et vanille sans script supplémentaire. Ce que je ferai probablement, c'est écrire un script de suppression à mettre sur le serveur B, puis l'appeler à distance depuis A s'il ne parvient pas à se connecter un certain nombre de fois de suite. De cette façon, il est moins susceptible d'interférer avec d'autres connexions SSH. Et je vais probablement avoir le journal du script de suppression à chaque exécution et quitter sans rien faire s'il est appelé trop souvent et trop rapidement. Personnellement, il semble prudent de limiter le nombre de scripts qui tuent sshd. : P - Justin Mrkva


Pour moi quand un ssh tunnel se déconnecte, il faut un certain temps pour que la connexion se réinitialise de sorte que le ssh processus continue à bloquer me laissant sans tunnels actifs et je ne sais pas pourquoi. Une solution de contournement consiste à mettre ssh dans le fond avec -f et pour générer de nouvelles connexions sans attendre la réinitialisation des anciennes connexions. le -o ExitOnForwardFailure=yes peut être utilisé pour limiter le nombre de nouveaux processus. le -o ServerAliveInterval=60 améliore la fiabilité de votre connexion actuelle.

Vous pouvez répéter le ssh commande souvent, disons, dans un cron, ou, dans une boucle de votre script, par exemple, nous lançons le ssh commande toutes les 3 minutes:

while (1)
do
    ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
    sleep 180
done

3
2017-07-27 00:29



une solution plus robuste utiliserait autossh - Marco Lavagnino
-o ExitOnForwardFailure=yes était ce que je cherchais, merci beaucoup! - vadipp


D'après mon expérience, ssh a l'habitude un peu fastidieuse de ne pas quitter proprement si «quelque chose» est toujours en cours d'exécution sur le système distant. Par exemple. commencé en arrière-plan. Vous pouvez reproduire ceci en:

ssh <server>
while true; do  sleep 60; done&
exit

Votre SSH se déconnectera, mais ne fermera pas réellement la session - jusqu'à ce que le processus distant se termine (ce qui ne sera pas le cas, car il s'agit d'une boucle 'tant que vraie'). Il se peut que quelque chose de similaire se produise - votre session a un processus bloqué qui est engendré par ssh. Le port reste en cours d'utilisation et ne peut donc pas être réutilisé par votre processus local.


1
2018-05-15 14:50



La commande SSH complète qui s’exécute sur la machine A est ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 & Donc, SSH n’exécute que le tunnel lui-même, en particulier à cause de l’option -N. Tout ce qui reste ouvert est fait sur le serveur distant B en utilisant sshd lui-même. - Justin Mrkva