Frage SSH-Remote-Port-Weiterleitung fehlgeschlagen


Nachverfolgen: Es sieht so aus, als ob die schnelle Reihe von Verbindungsunterbrechungen, die mit ein paar Monaten Laufzeit jedes Servers zusammenfallen, wahrscheinlich zufällig ist und nur dazu diente, das tatsächliche Problem aufzudecken. Der Grund dafür, dass die Verbindung nicht wiederhergestellt werden konnte, liegt mit Sicherheit an den AliveInterval-Werten (Kasperds Antwort). Wenn Sie die Option ExitOnForwardFailure verwenden, sollte das Zeitlimit ordnungsgemäß vor dem erneuten Herstellen der Verbindung auftreten, wodurch das Problem in den meisten Fällen behoben werden sollte. MadHatters Vorschlag (das Kill-Skript) ist wahrscheinlich der beste Weg, um sicherzustellen, dass der Tunnel die Verbindung wiederherstellen kann, selbst wenn alles andere fehlschlägt.

Ich habe einen Server (A) hinter einer Firewall, die einen Reverse-Tunnel an mehreren Ports zu einem kleinen DigitalOcean-VPS (B) initiiert, so dass ich mich über die IP-Adresse von B mit A verbinden kann. Der Tunnel arbeitet seit etwa 3 Monaten ununterbrochen, ist aber in den letzten 24 Stunden plötzlich vier Mal gescheitert. Das Gleiche passierte vor einiger Zeit bei einem anderen VPS-Anbieter - monatelange einwandfreie Funktion, dann plötzlich mehrere schnelle Ausfälle.

Ich habe ein Skript auf Maschine A, das den Tunnelbefehl automatisch ausführt (ssh -R *:X:localhost:X address_of_B für jeden Port X), aber wenn es ausgeführt wird, heißt es Warning: remote port forwarding failed for listen port X.

In den sshd gehen /var/log/secure Auf dem Server werden diese Fehler angezeigt:

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

Zum Lösen muss der VPS neu gestartet werden. Bis dahin geben alle Versuche, die Verbindung wiederherzustellen, die Meldung "Remote-Portweiterleitung fehlgeschlagen" und funktioniert nicht. Es ist jetzt zu dem Punkt, wo der Tunnel nur etwa 4 Stunden vor dem Anhalten dauert.

Auf dem VPS hat sich nichts geändert, und es handelt sich um einen Single-Use-Computer für einen einzelnen Benutzer, der nur als Reverse-Tunnel-Endpunkt dient. Es läuft OpenSSH_5.3p1 auf CentOS 6.5. Es scheint, dass sshd die Ports an seinem Ende nicht schließt, wenn die Verbindung verloren geht. Ich kann nicht erklären, warum, oder warum es nach Monaten fast perfekter Operation plötzlich passieren würde.

Um klarzustellen, muss ich zuerst herausfinden, warum sshd es ablehnt, nach dem Ausfall des Tunnels auf die Ports zu warten, was dadurch zu entstehen scheint, dass sshd die Ports offen lässt und sie niemals schließt. Das scheint das Hauptproblem zu sein. Ich bin mir nur nicht sicher, was es dazu bringen würde, sich so zu verhalten, nachdem ich mich monatelang so verhalten habe, wie ich es erwarte (d. H. Die Ports sofort schließen und dem Skript erlauben, sich wieder zu verbinden).


23
2018-05-15 14:37


Ursprung


Was ist deine Frage? Wie kann man den Port-Binding-Fehler beheben oder herausfinden, warum ssh stirbt oder noch etwas anderes? - MadHatter
Ich muss herausfinden, warum sshd sich weigert, die Häfen auf dem VPS zu öffnen (der Bindungsfehler). Der Portbindungsfehler scheint die Wurzel des Problems zu sein, und alles sollte funktionieren, wenn ich das lösen kann. - Justin Mrkva
Für alle Late Lurker, anstatt manuell ein Skript zu erstellen, um die Verbindung offen zu halten, verwenden Sie einfach stattdessen autossh, was dies für Sie tut. serverfault.com/questions/598210/ ... - oligofren


Antworten:


Ich stimme MadHatter zu, dass es sich wahrscheinlich um Port-Weiterleitungen von defekten ssh-Verbindungen handelt. Selbst wenn sich Ihr aktuelles Problem als etwas anderes herausstellt, können Sie damit rechnen, früher oder später auf solche nicht funktionierenden ssh-Verbindungen zu stoßen.

Es gibt drei Möglichkeiten, wie solche nicht funktionierenden Verbindungen auftreten können:

  • Einer der beiden Endpunkte wurde neu gestartet, während das andere Ende der Verbindung vollständig inaktiv war.
  • Einer der beiden Endpunkte hat die Verbindung geschlossen, aber zu dem Zeitpunkt, als die Verbindung geschlossen wurde, gab es einen temporären Ausfall der Verbindung. Der Ausfall dauerte einige Minuten, nachdem die Verbindung geschlossen wurde, und so wurde das andere Ende nie über die geschlossene Verbindung erfahren.
  • Die Verbindung ist an beiden Endpunkten der SSH-Verbindung immer noch voll funktionsfähig, aber jemand hat irgendwo zwischen ihnen ein zustandsbehaftetes Gerät platziert, das die Verbindung wegen Leerlaufs aussetzte. Dieses Stateful-Gerät wäre entweder ein NAT oder eine Firewall, die Firewall, die Sie bereits erwähnt haben, ist ein Hauptverdächtiger.

Herauszufinden, welches der drei oben genannten Dinge passiert, ist nicht sehr wichtig, weil es eine Methode gibt, die alle drei anspricht. Das ist die Verwendung von Keepalive-Nachrichten.

Du solltest in die ClientAliveInterval Stichwort für sshd_config und das ServerAliveInterval Intervall für ssh_config oder ~/.ssh/config.

Laufen der ssh Befehl in einer Schleife kann gut funktionieren. Es ist eine gute Idee, auch einen Schlaf in die Schleife einzufügen, damit Sie den Server nicht überschwemmen, wenn die Verbindung aus irgendeinem Grund fehlschlägt.

Wenn der Client die Verbindung erneut herstellt, bevor die Verbindung auf dem Server beendet wurde, können Sie in einer Situation landen, in der die neue SSH-Verbindung aktiv ist, aber keine Portweiterleitungen. Um dies zu vermeiden, müssen Sie die ExitOnForwardFailure Schlüsselwort auf der Client-Seite.


25
2018-05-15 15:14



Ich denke, das könnte das Problem sein. Insbesondere wird mein Skript auf A versuchen, sich wieder mit B zu verbinden, wenn der ssh-Prozess abstirbt (natürlich, da die Warnmeldung den ssh-Prozess nicht abbricht, hängt er einfach, wenn dies passiert, aber das ist ein Problem für einen anderen Tag). Wenn A versucht, sich zu schnell mit B zu verbinden, wartet B möglicherweise darauf, dass A die Verbindung wieder herstellt. Ich muss wahrscheinlich sicherstellen, dass B immer ausgeht, bevor A wieder verbindet. Kombiniert man dies mit MadHatters Vorschlag, die sshd-Prozesse vor der Wiederverbindung zu beenden, werden wahrscheinlich 95% der möglichen Fälle abgedeckt. - Justin Mrkva
Und wenn ich von der Warnmeldung spreche, die SSH nicht tötet, hat mich das zum Nachdenken gebracht ... und auf die Hilfeseiten geschaut. Stellt sich heraus -o ExitOnForwardFailure yes ist genau das, was ich brauchte. Das ist also eine Sache weniger, die ich herausfinden muss. Um zu denken, ich würde ein Python-Skript schreiben, um diese Warnmeldungen zu parsen. Das ist viel einfacher. : D - Justin Mrkva
Entschuldigung für das Vergessen ExitOnForwardFailure wenn ich meine Antwort schreibe. Ich habe es jetzt zur Antwort hinzugefügt. - kasperd
Kein Problem, und es war tatsächlich -o ExitOnForwardFailure=yes (beachte das Gleichheitszeichen). Wenn also irgendjemand darüber stolpert, kopieren und einfügen Sie nicht von meinem vorherigen Kommentar, es wird nicht funktionieren. : P - Justin Mrkva
Also habe ich den Server etwa 10 Stunden lang überwacht und es sieht so aus, als ob es gut läuft; Ich nehme an dieser Stelle an, dass diese Antwort richtig ist (ich bin ungefähr zu 99% sicher, basierend auf dem, was ich gesehen habe) und dass die Reihe der schnellen Verbindungsunterbrechungen zufällig mit Netzwerkproblemen zusammenhängt, die nur ein paar Monate später auftraten jeden Service starten. Danke an alle für Ihre Hilfe. ;) - Justin Mrkva


Sie können den Prozess finden, der den Port auf diesem Server bindet

sudo netstat -apn|grep -w X

Es scheint sehr wahrscheinlich zu sein, dass es halb tot ist sshd, aber warum sollten Sie Annahmen treffen, wenn Sie Daten haben können? Es ist auch eine gute Möglichkeit für ein Skript, eine PID zu finden, um Signal 9 zu senden, bevor der Tunnel wieder hochgefahren wird.


4
2018-05-15 14:53



Ich erinnere mich, das auf dem vorherigen VPS-Provider überprüft zu haben, und ich bestätigte, dass sshd der Prozess war, der diese Ports abhört. Das nächste Mal, wenn es passiert, werde ich es hier überprüfen, aber da das Verhalten und das Setup genau gleich sind, erwarte ich nicht, dass es anders ist. - Justin Mrkva
Großartig, also muss dein Skript, das den Tunnel wieder öffnet, den alten Tunnler töten, bevor du versuchst, es zu tun. - MadHatter
Es gibt nie mehr als ein Tunnelskript (auf A), das sofort ausgeführt wird, wenn Sie das sagen. Auf der anderen Seite, wenn Sie wollen, dass das Skript remote einen Befehl auf B ausführt, um die streunenden Prozesse zu beenden ... ist das eigentlich keine schlechte Idee. Aber ein Problem besteht darin, immer wieder alle SSH-Verbindungen auszuschalten, wenn ich versuche, zu debuggen. Wenn das Skript auf A aufgrund eines Fehlers immer B tötet, kann ich nicht ständig von dem Rogue-A-Skript von B losgeworfen werden. : P Ich muss testen, um sicherzustellen, dass es das nicht tut. Aber wie gesagt, keine schlechte Idee. ;) - Justin Mrkva
Ich hatte nicht gedacht, dass es da war. Sie sagen, dass auf dem Remote-Server ein Skript ausgeführt wird, das versucht, einen Tunnel aufzurufen, und aufgrund des Bindungsfehlers fehlschlägt, und ich gehe davon aus, dass es nur ausgeführt wird, wenn Sie es benötigen (dh wenn der vorhandene Tunnel nicht gut ist). weil du nicht anders gesagt hast. Alles, was ich vorschlage, ist, dass es den spezifischen Prozess abbricht, der den Port offen hält, bevor er versucht, den neuen Tunnel zu öffnen. - MadHatter
Das Skript, auf dem ssh ausgeführt wird, ist nur auf Server A, Server B ist ein normaler Server ohne zusätzliche Skripts. Was ich wahrscheinlich tun werde, ist ein Kill-Skript schreiben, um auf Server B zu setzen, und dann remote von A anzurufen, wenn es eine bestimmte Anzahl von Malen hintereinander nicht verbindet. Auf diese Weise ist es weniger wahrscheinlich, dass andere SSH-Verbindungen gestört werden. Und ich werde wahrscheinlich das Kill-Skript jedes Mal, wenn es ausgeführt wird, protokollieren und beenden, ohne etwas zu tun, wenn es zu oft zu schnell aufgerufen wird. Persönlich scheint es, als würde jedes Script, das sshd tötet, ratenbegrenzend sein, wahrscheinlich vorsichtig. : P - Justin Mrkva


Für mich wenn a ssh tunnel disconnects es dauert eine Weile, bis die Verbindung zurückgesetzt wurde ssh Der Prozess blockiert weiter, so dass ich keine aktiven Tunnel habe und ich weiß nicht warum. Eine Umgehungslösung ist zu stellen ssh in den Hintergrund mit -f und um neue Verbindungen herzustellen, ohne auf das Zurücksetzen alter Verbindungen zu warten. Das -o ExitOnForwardFailure=yes kann verwendet werden, um die Anzahl neuer Prozesse zu begrenzen. Das -o ServerAliveInterval=60 verbessert die Zuverlässigkeit Ihrer aktuellen Verbindung.

Sie können das wiederholen ssh Befehl häufig, sagen wir, in einem cronOder, in einer Schleife in Ihrem Skript, zum Beispiel, im Folgenden, führen wir die ssh Befehl alle 3 Minuten:

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



eine viel robustere Lösung wäre die Verwendung autossh - Marco Lavagnino
-o ExitOnForwardFailure=yes war was ich suchte, vielen Dank! - vadipp


Meiner Erfahrung nach hat ssh eine leicht lästige Angewohnheit, nicht sauber zu beenden, wenn auf dem Remote-System noch 'etwas' läuft. Z.B. im Hintergrund gestartet. Sie können dies reproduzieren durch:

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

Ihr ssh wird sich abmelden, aber die Sitzung wird nicht geschlossen - bis der Remote-Prozess beendet wird (was nicht der Fall ist, weil es eine "while true" -Schleife ist). Es könnte etwas Ähnliches passieren - Ihre Sitzung hat einen "festgefahrenen" Prozess, der von ssh ausgelöst wird. Der Port wird weiterhin verwendet und kann daher nicht von Ihrem lokalen Prozess wiederverwendet werden.


1
2018-05-15 14:50



Der vollständige SSH-Befehl, der auf der A-Maschine ausgeführt wird, ist ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 & Es wird also nichts durch SSH ausgeführt, außer dem Tunnel selbst, insbesondere wegen der Option -N. Was immer offen gehalten wird, wird auf dem entfernten Server B unter Verwendung von sshd selbst ausgeführt. - Justin Mrkva