web-dev-qa-db-fra.com

Échec de la redirection du port distant SSH

Suivi: Il semble que la série rapide de déconnexions coïncidant avec quelques mois de fonctionnement de chaque serveur soit probablement une coïncidence et vient juste de révéler le problème réel. 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 au délai d'expiration de se produire correctement avant de se reconnecter, ce qui devrait résoudre le problème dans la plupart des cas. La suggestion de MadHatter (le script kill) 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 lance 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 régulièrement depuis environ 3 mois, mais a soudainement échoué quatre fois au cours des dernières 24 heures. La même chose s'est produite il y a quelque temps sur un autre fournisseur de VPS - des mois de fonctionnement parfait, puis soudainement plusieurs pannes rapides.

J'ai un script sur la machine A qui exécute automatiquement la commande 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 affiche 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. D'ici là, toutes les tentatives de reconnexion donneront le message "échec de la redirection de port distant" et ne fonctionneront pas. C'est maintenant au point où le tunnel ne dure que 4 heures environ avant de s'arrêter.

Rien n'a changé sur le VPS, et il s'agit d'une machine à 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 sur les ports après l'échec du tunnel, ce qui semble être dû au fait que sshd laisse les ports ouverts et ne les ferme jamais. Cela semble être le principal problème. Je ne suis tout simplement pas sûr de ce qui pourrait le faire se comporter de cette façon après des mois de comportement comme je m'y attendais (c'est-à-dire fermer les ports immédiatement et permettre au script de se reconnecter).

27
Justin Mrkva

Je suis d'accord avec MadHatter, qu'il s'agit probablement de redirection de port à partir de connexions ssh disparues. Même si votre problème actuel se révèle être autre chose, vous pouvez vous attendre à rencontrer de telles connexions ssh disparues tôt ou tard.

Il existe trois façons dont ces connexions disparues peuvent se produire:

  • L'un des deux points de terminaison 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 interruption temporaire de la connexion. La panne a duré quelques minutes après la fermeture de la connexion, et donc l'autre extrémité n'a jamais eu connaissance de la connexion fermée.
  • La connexion est toujours complètement fonctionnelle aux deux points de terminaison de la connexion ssh, mais quelqu'un a placé un périphérique avec état quelque part entre eux, ce qui a expiré la connexion en raison de l'oisiveté. Cet appareil avec état serait soit un NAT ou un pare-feu, le pare-feu que vous avez déjà mentionné est un suspect principal.

Déterminer lequel des trois ci-dessus se produit n'est pas très important, car il existe une méthode qui répondra aux trois. C'est l'utilisation de messages keepalive.

Vous devez rechercher le mot clé ClientAliveInterval pour sshd_config et l'intervalle ServerAliveInterval pour ssh_config ou ~/.ssh/config.

L'exécution de la commande ssh dans une boucle peut fonctionner correctement. C'est également une bonne idée d'insérer un sommeil dans la boucle afin de ne pas 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 mot clé ExitOnForwardFailure côté client.

29
kasperd

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 hypothèses quand vous pouvez 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éactiver le tunnel.

4
MadHatter

Pour moi, lorsqu'un tunnel ssh se déconnecte, il faut un certain temps pour que la connexion se réinitialise, de sorte que le processus ssh continue de se bloquer, me laissant sans tunnel actif et je ne sais pas pourquoi. Une solution de contournement consiste à mettre ssh en arrière-plan 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 la commande ssh fréquemment, par exemple dans un cron, ou, dans une boucle de votre script, par exemple, dans ce qui suit, nous exécutons la commande ssh 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
Stephen Quan

D'après mon expérience, ssh a une habitude un peu gênante de ne pas quitter proprement si "quelque chose" est toujours en cours d'exécution sur le système distant. Par exemple. a commencé en arrière-plan. Vous pouvez le reproduire 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 "while true"). Il se peut que quelque chose de similaire se produise - votre session a un processus "bloqué" qui est généré par ssh. Le port reste utilisé et ne peut donc pas être réutilisé par votre processus local.

1
Sobrique