Frage (TL; DR)
-R
Wie kann ein Skript auf dem Remotecomputer (z. B. von .bashrc
) bestimmen, welche Ports von OpenSSH ausgewählt wurden, wenn Ports dynamisch für die Remoteweiterleitung zugewiesen werden (auch als Option bezeichnet) ?
Hintergrund
Ich verwende OpenSSH (an beiden Enden), um eine Verbindung zu unserem zentralen Server herzustellen, den ich mit mehreren anderen Benutzern teile. Für meine Remote-Sitzung (vorerst) möchte ich X, Tassen und Pulseaudio weiterleiten.
Am trivialsten ist es, X mit dieser -X
Option weiterzuleiten . Die zugewiesene X-Adresse wird in der Umgebungsvariablen gespeichert DISPLAY
und daraus kann ich in den meisten Fällen sowieso den entsprechenden TCP-Port ermitteln. Aber das brauche ich kaum, denn Xlib ehrt DISPLAY
.
Ich brauche einen ähnlichen Mechanismus für Tassen und Pulseaudio. Die Grundlagen für beide Dienste existieren, in Form der Umgebungsvariablen CUPS_SERVER
und PULSE_SERVER
sind. Hier sind Anwendungsbeispiele:
ssh -X -R12345:localhost:631 -R54321:localhost:4713 datserver
export CUPS_SERVER=localhost:12345
lowriter #and I can print using my local printer
lpr -P default -o Duplex=DuplexNoTumble minutes.pdf #printing through the tunnel
lpr -H localhost:631 -P default -o Duplex=DuplexNoTumble minutes.pdf #printing remotely
mpg123 mp3s/van_halen/jump.mp3 #annoy co-workers
PULSE_SERVER=localhost:54321 mpg123 mp3s/van_halen/jump.mp3 #listen to music through the tunnel
Das Problem setzt CUPS_SERVER
und PULSE_SERVER
korrekt.
Wir verwenden häufig Portweiterleitungen, daher benötige ich dynamische Portzuweisungen. Statische Portzuweisungen sind keine Option.
OpenSSH verfügt über einen Mechanismus für die dynamische Portzuweisung auf dem Remote-Server, indem 0
als Bindungsport für die Remote-Weiterleitung angegeben wird (die -R
Option). Mit dem folgenden Befehl weist OpenSSH dynamisch Ports für Cups und Impulsweiterleitungen zu.
ssh -X -R0:localhost:631 -R0:localhost:4713 datserver
Wenn ich diesen Befehl verwende, ssh
wird Folgendes gedruckt STDERR
:
Allocated port 55710 for remote forward to 127.0.0.1:4713
Allocated port 41273 for remote forward to 127.0.0.1:631
Da sind die Informationen, die ich will! Letztendlich möchte ich generieren:
export CUPS_SERVER=localhost:41273
export PULSE_SERVER=localhost:55710
Die Nachrichten "Zugeordneter Port ..." werden jedoch auf meinem lokalen Computer erstellt und an diesen gesendet STDERR
, auf den ich auf dem Remotecomputer nicht zugreifen kann. Seltsamerweise scheint OpenSSH keine Mittel zu haben, um Informationen über Portweiterleitungen abzurufen.
Wie rufe ich diese Informationen ab, um sie in ein Shell-Skript einzufügen, um sie angemessen festzulegen CUPS_SERVER
und PULSE_SERVER
auf dem Remote-Host zu speichern?
Sackgassen
Das einzig leichte, was ich finden konnte, war die Erhöhung der Ausführlichkeit der, sshd
bis diese Informationen aus den Protokollen gelesen werden können. Dies ist nicht praktikabel, da diese Informationen viel mehr Informationen enthalten, als für Nicht-Root-Benutzer sinnvoll sind.
Ich habe darüber nachgedacht, OpenSSH zu patchen, um eine zusätzliche Escape-Sequenz zu unterstützen, die eine schöne Darstellung der internen Struktur druckt permitted_opens
, aber selbst wenn ich das möchte, kann ich immer noch kein Skript auf die Client-Escape-Sequenzen von der Serverseite aus ausführen.
Es muss einen besseren Weg geben
Der folgende Ansatz scheint sehr instabil zu sein und ist auf eine solche SSH-Sitzung pro Benutzer beschränkt. Ich benötige jedoch mindestens zwei gleichzeitige Sitzungen und noch mehr Benutzer. Aber ich habe es versucht ...
Wenn die Sterne richtig ausgerichtet sind und ein oder zwei Hühner geopfert haben, kann ich die Tatsache missbrauchen, dass sie sshd
nicht als mein Benutzer gestartet wurde, sondern nach erfolgreicher Anmeldung die Berechtigungen aufhebt, um dies zu tun:
Holen Sie sich eine Liste der Portnummern für alle Abhörbuchsen, die meinem Benutzer gehören
netstat -tlpen | grep ${UID} | sed -e 's/^.*:\([0-9]\+\) .*$/\1/'
Holen Sie sich eine Liste der Portnummern für alle Abhörbuchsen, die zu Prozessen gehören, die mein Benutzer gestartet hat
lsof -u ${UID} 2>/dev/null | grep LISTEN | sed -e 's/.*:\([0-9]\+\) (LISTEN).*$/\1/'
Alle Ports, die sich im ersten Satz, aber nicht im zweiten Satz befinden, sind mit hoher Wahrscheinlichkeit meine Weiterleitungsports, und tatsächlich werden die Erträge der Sätze abgezogen
41273
,55710
und6010
; Tassen, Puls und X.6010
wird als X-Port mit identifiziertDISPLAY
.41273
ist der Tassenport, weillpstat -h localhost:41273 -a
zurückkehrt0
.55710
ist der Impulsport, weilpactl -s localhost:55710 stat
zurückkehrt0
. (Es gibt sogar den Hostnamen meines Kunden aus!)
(Um die eingestellte Subtraktion I durchzuführen sort -u
und die Ausgabe über die obigen Befehlszeilen zu speichern und comm
die Substraktion durchzuführen.)
Mit Pulseaudio kann ich den Client identifizieren. In jeder Hinsicht kann dies als Anker für die Trennung von SSH-Sitzungen dienen, die getrennt werden müssen. Allerdings habe ich nicht gefunden , einen Weg zu binden 41273
, 55710
und 6010
auf den gleichen sshd
Prozess. netstat
gibt diese Informationen nicht an Nicht-Root-Benutzer weiter. Ich bekomme nur eine -
in der PID/Program name
Spalte, in der ich lesen möchte 2339/54
(in diesem speziellen Fall). So nah ...
quelle
netstat
Ihnen die PID für Prozesse, die Sie nicht besitzen oder die Kernel-Space sind , nicht angezeigt wird . Zum BeispielAntworten:
Nehmen Sie zwei (siehe Verlauf für eine Version, die scp von der Serverseite aus ausführt und etwas einfacher ist), dies sollte es tun. Das Wesentliche dabei ist:
Beim Einrichten auf der Remote-Seite müssen Sie zunächst das Senden einer env-Variablen in der sshd- Konfiguration aktivieren :
Suchen Sie eine Linie mit
AcceptEnv
und fügen SieMY_PORT_FILE
sie hinzu (oder fügen Sie die Linie unter dem rechtenHost
Abschnitt hinzu, falls noch keine vorhanden ist). Für mich wurde die Linie wie folgt:Denken Sie auch daran, sshd neu zu starten, damit dies wirksam wird.
Damit die folgenden Skripte funktionieren, sollten Sie dies auch
mkdir ~/portfiles
auf der Remote-Seite tun !Dann auf lokaler Seite ein Skript-Snippet, das wird
Das Skript-Snippet:
Dann ein Snippet für die Remote-Seite, geeignet für .bashrc :
Hinweis : Der obige Code ist natürlich nicht sehr gründlich getestet und kann alle Arten von Fehlern, Kopier- und Einfügefehlern usw. enthalten. Jeder, der ihn besser verwendet, versteht ihn auch. Die Verwendung erfolgt auf eigenes Risiko! Ich habe es nur mit der localhost-Verbindung getestet und es hat in meiner Testumgebung für mich funktioniert. YMMV.
quelle
scp
von der entfernten Seite zur lokalen Seite kann, was ich nicht kann. Ich hatte einen ähnlichen Ansatz, aber ich würdessh
ihn nach dem Herstellen der Verbindung in den Hintergrund einbinden, dann diese Datei von lokal nach remote über sendenscp
und dann denssh
Client in den Vordergrund ziehen und ein Skript auf der Remote-Seite ausführen. Ich habe nicht herausgefunden, wie man lokale und entfernte Prozesse gut hinterlegt und in den Vordergrund stellt. Das Umschließen und Integrieren des lokalenssh
Clients in solche Remote-Skripte scheint kein guter Ansatz zu sein.(while [ ... ] ; do sleep 1 ; done ; scp ... )&
. Warten Sie dann im Vordergrund im Server.bashrc
(vorausgesetzt, der Client sendet die richtige env-Variable), bis die Datei angezeigt wird. Ich werde die Antwort später nach einigen Tests aktualisieren (wahrscheinlich keine Zeit bis morgen).~/.ssh-${PID}-forwards
Ein Snippet für die lokale Seite, geeignet für .bashrc:
quelle
Ich habe das gleiche erreicht, indem ich auf dem lokalen Client eine Pipe erstellt und dann stderr auf die Pipe umgeleitet habe, die auch auf die Eingabe von ssh umgeleitet wird. Es sind nicht mehrere SSH-Verbindungen erforderlich, um einen freien bekannten Port anzunehmen, der ausfallen könnte. Auf diese Weise werden das Anmeldebanner und der Text "Zugeordneter Port ### ..." an den Remote-Host umgeleitet.
Ich habe ein einfaches Skript auf dem Host,
getsshport.sh
das auf dem Remote-Host ausgeführt wird, das die umgeleiteten Eingaben liest und den Port analysiert. Solange dieses Skript nicht endet, bleibt die SSH-Remote-Weiterleitung geöffnet.lokale Seite
3>&1 1>&2 2>&3
ist ein kleiner Trick, um stderr und stdout zu tauschen, damit stderr an cat weitergeleitet wird und die gesamte normale Ausgabe von ssh auf stderr angezeigt wird.Remote-Seite ~ / getsshport.sh
Ich habe zuerst versucht,
grep
die Nachricht "Zugewiesener Port" auf der lokalen Seite abzurufen, bevor ich sie über ssh gesendet habe, aber anscheinend blockiert ssh das Warten auf das Öffnen der Pipe auf stdin. grep öffnet die Pipe nicht zum Schreiben, bis es etwas erhält, also blockiert dies im Grunde genommen.cat
scheint jedoch nicht dasselbe Verhalten zu haben und öffnet die Pipe zum Schreiben sofort, sodass ssh die Verbindung öffnen kann.Dies ist das gleiche Problem auf der Remote-Seite, und warum
read
Zeile für Zeile statt nur grep von stdin - andernfalls wird "/ tmp / assignports" erst ausgeschrieben, wenn der SSH-Tunnel geschlossen wird, was den gesamten Zweck zunichte machtDas Weiterleiten des stderr von ssh in einen Befehl wie
~/getsshport.sh
wird bevorzugt, da ohne Angabe eines Befehls der Bannertext oder was auch immer in der Pipe enthalten ist, auf der Remote-Shell ausgeführt wird.quelle
renice +10 $$; exec cat
vor dem hinzudone
, um Ressourcen zu sparen.Dies ist eine knifflige, zusätzliche serverseitige Behandlung in Anlehnung an
SSH_CONNECTION
oderDISPLAY
wäre großartig, aber es ist nicht einfach hinzuzufügen: Ein Teil des Problems besteht darin, dass nur derssh
Client das lokale Ziel kennt, das das Anforderungspaket (an den Server) enthält nur die entfernte Adresse und den Port.Die anderen Antworten hier haben verschiedene unpretty Lösungen, um diese Client-Seite zu erfassen und an den Server zu senden. Hier ist ein alternativer Ansatz, der ehrlich gesagt nicht viel hübscher ist, aber zumindest diese hässliche Party wird auf der Kundenseite gehalten ;-)
SendEnv
damit wir einige Umgebungsvariablen nativ über ssh senden können (wahrscheinlich nicht standardmäßig)AcceptEnv
, um dasselbe zu akzeptieren (wahrscheinlich nicht standardmäßig aktiviert)ssh
Client-Stderr-Ausgabe mit einer dynamisch geladenen Bibliothek und aktualisieren Sie die SSH-Client-Umgebung während des VerbindungsaufbausDies funktioniert (zum Glück ohnehin vorerst), da die Remote-Weiterleitungen eingerichtet und aufgezeichnet werden, bevor die Umgebung ausgetauscht wird (bestätigen mit
ssh -vv ...
). Die dynamisch geladene Bibliothek muss diewrite()
libc-Funktion erfassen (ssh_confirm_remote_forward()
→logit()
→do_log()
→write()
). Das Umleiten oder Umschließen von Funktionen in einer ELF-Binärdatei (ohne Neukompilieren) ist um Größenordnungen komplexer als das gleiche für eine Funktion in einer dynamischen Bibliothek.Auf dem Client
.ssh/config
(oder der Befehlszeile-o SendEnv ...
)Auf dem Server
sshd_config
(Root- / Verwaltungsänderung erforderlich)Dieser Ansatz funktioniert für Linux-Clients und erfordert nichts Besonderes auf dem Server. Er sollte für andere * nix mit einigen geringfügigen Änderungen funktionieren. Funktioniert von mindestens OpenSSH 5.8p1 bis 7.5p1.
Kompilieren mit
gcc -Wall -shared -ldl -Wl,-soname,rfwd -o rfwd.so rfwd.c
Aufrufen mit:Der Code:
(Es gibt einige Glibc-Bärenfallen im Zusammenhang mit der Symbolversionierung bei diesem Ansatz, aber
write()
dieses Problem tritt nicht auf.)Wenn Sie sich mutig fühlen, können Sie den
setenv()
zugehörigen Code in diessh.c
ssh_confirm_remote_forward()
Rückruffunktion patchen .Dadurch werden Umgebungsvariablen mit dem Namen festgelegt
SSH_RFWD_nnn
. Überprüfen Sie diese in Ihrem Profil, z. B. inbash
Vorsichtsmaßnahmen:
ssh
Derzeit wird die vollständige Weiterleitung des Formulars * local: port: remote: port * nicht eindeutig protokolliert (bei Bedarf wäre ein weiteres Parsen vondebug1
Nachrichten mitssh -v
erforderlich), dies ist jedoch für Ihren Anwendungsfall nicht erforderlichSie können dies (teilweise) interaktiv mit dem Escape tun.
~#
Seltsamerweise überspringt die Implementierung Kanäle, die gerade abhören, listet nur offene (dh TCP ESTABLISHED) Kanäle auf und druckt auf keinen Fall die nützlichen Felder. Sehenchannels.c
channel_open_message()
Sie können diese Funktion Patch , um die Details zu drucken
SSH_CHANNEL_PORT_LISTENER
Slots, aber das bekommt man nur die lokalen Umleitungen ( Kanäle sind nicht das gleiche wie tatsächlich vorwärts ). Sie können es auch patchen, um die beiden Weiterleitungstabellen aus der globalenoptions
Struktur zu sichern:Dies funktioniert einwandfrei, obwohl es keine "programmatische" Lösung ist, mit der Einschränkung, dass der Client-Code die Liste nicht aktualisiert (noch ist er in der Quelle als XXX gekennzeichnet), wenn Sie Weiterleitungen im laufenden Betrieb hinzufügen / entfernen (
~C
)Wenn die Server Linux sind, haben Sie eine weitere Option, die ich im Allgemeinen verwende, allerdings eher für die lokale Weiterleitung als für die Remote-Weiterleitung.
lo
ist 127.0.0.1/8, unter Linux können Sie transparent an jede Adresse in 127/8 binden , sodass Sie feste Ports verwenden können, wenn Sie eindeutige 127.xyz-Adressen verwenden, z.Dies unterliegt der Bindung von privilegierten Ports <1024. OpenSSH unterstützt keine Linux-Funktionen und verfügt auf den meisten Plattformen über eine fest codierte UID-Prüfung.
Mit Bedacht ausgewählte Oktette (in meinem Fall ASCII-Ordnungsmnemonik) helfen dabei, das Chaos am Ende des Tages zu entwirren.
quelle