Bestimmen Sie den dynamisch zugewiesenen Port für OpenSSH RemoteForward

13

Frage (TL; DR)

-RWie 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 -XOption weiterzuleiten . Die zugewiesene X-Adresse wird in der Umgebungsvariablen gespeichert DISPLAYund 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_SERVERund PULSE_SERVERsind. 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_SERVERund PULSE_SERVERkorrekt.

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 0als Bindungsport für die Remote-Weiterleitung angegeben wird (die -ROption). 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, sshwird 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_SERVERund PULSE_SERVERauf dem Remote-Host zu speichern?


Sackgassen

Das einzig leichte, was ich finden konnte, war die Erhöhung der Ausführlichkeit der, sshdbis 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 sshdnicht 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, 55710und 6010; Tassen, Puls und X.

  • 6010wird als X-Port mit identifiziert DISPLAY.

  • 41273ist der Tassenport, weil lpstat -h localhost:41273 -azurückkehrt 0.
  • 55710ist der Impulsport, weil pactl -s localhost:55710 statzurückkehrt 0. (Es gibt sogar den Hostnamen meines Kunden aus!)

(Um die eingestellte Subtraktion I durchzuführen sort -uund die Ausgabe über die obigen Befehlszeilen zu speichern und commdie 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, 55710und 6010auf den gleichen sshdProzess. netstatgibt diese Informationen nicht an Nicht-Root-Benutzer weiter. Ich bekomme nur eine -in der PID/Program nameSpalte, in der ich lesen möchte 2339/54(in diesem speziellen Fall). So nah ...

Bananguin
quelle
fwiw, es ist genauer zu sagen, dass netstatIhnen die PID für Prozesse, die Sie nicht besitzen oder die Kernel-Space sind , nicht angezeigt wird . Zum Beispiel
Bratchley
Der robusteste Weg wäre, das sshd zu patchen ... Ein schneller und schmutziger Patch wäre nur ein paar Zeilen an der Stelle, an der der Server seinen lokalen Port vom Betriebssystem erhält und die Portnummer in eine Datei schreibt, den Namen vom Benutzer, dem Remote-Host und generiert Hafen. Angenommen, der Server kennt den Port auf der Clientseite, was nicht sicher, vielleicht sogar nicht wahrscheinlich ist (andernfalls wäre die Funktion bereits vorhanden).
Hyde
@ Hyde: genau. Der Remote-Server kennt die weitergeleiteten Ports nicht. Es werden nur wenige Listening-Sockets erstellt und Daten werden über die SSH-Verbindung weitergeleitet. Die lokalen Zielports sind nicht bekannt.
Bananguin

Antworten:

1

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:

  1. Übergeben Sie eine Umgebungsvariable vom Client an den Server und teilen Sie dem Server mit, wie er erkennen kann, wann Portinformationen verfügbar sind, und rufen Sie sie dann ab und verwenden Sie sie.
  2. Sobald Portinformationen verfügbar sind, kopieren Sie sie vom Client auf den Server, damit der Server sie abrufen kann (mithilfe von Teil 1 oben), und verwenden Sie sie

Beim Einrichten auf der Remote-Seite müssen Sie zunächst das Senden einer env-Variablen in der sshd- Konfiguration aktivieren :

sudo yourfavouriteeditor /etc/ssh/sshd_config

Suchen Sie eine Linie mit AcceptEnvund fügen Sie MY_PORT_FILEsie hinzu (oder fügen Sie die Linie unter dem rechten HostAbschnitt hinzu, falls noch keine vorhanden ist). Für mich wurde die Linie wie folgt:

AcceptEnv LANG LC_* MY_PORT_FILE

Denken Sie auch daran, sshd neu zu starten, damit dies wirksam wird.

Damit die folgenden Skripte funktionieren, sollten Sie dies auch mkdir ~/portfilesauf der Remote-Seite tun !


Dann auf lokaler Seite ein Skript-Snippet, das wird

  1. Erstellen Sie einen temporären Dateinamen für die stderr-Umleitung
  2. Verlassen Sie einen Hintergrundjob, um auf den Inhalt der Datei zu warten
  3. Übergeben Sie den Dateinamen als env-Variable an den Server, während Sie ssh stderr in die Datei umleiten
  4. Der Hintergrundjob kopiert die stderr-temporäre Datei mit separatem scp auf die Serverseite
  5. Der Hintergrundjob kopiert auch eine Flag-Datei auf den Server, um anzuzeigen, dass die stderr-Datei bereit ist

Das Skript-Snippet:

REMOTE=$USER@datserver

PORTFILE=`mktemp /tmp/sshdataserverports-$(hostname)-XXXXX`
test -e $PORTFILE && rm -v $PORTFILE

# EMPTYFLAG servers both as empty flag file for remote side,
# and safeguard for background job termination on this side
EMPTYFLAG=$PORTFILE-empty
cp /dev/null $EMPTYFLAG

# this variable has the file name sent over ssh connection
export MY_PORT_FILE=$(basename $PORTFILE)

# background job loop to wait for the temp file to have data
( while [ -f $EMPTYFLAG -a \! -s $PORTFILE ] ; do
     sleep 1 # check once per sec
  done
  sleep 1 # make sure temp file gets the port data

  # first copy temp file, ...
  scp  $PORTFILE $REMOTE:portfiles/$MY_PORT_FILE

  # ...then copy flag file telling temp file contents are up to date
  scp  $EMPTYFLAG $REMOTE:portfiles/$MY_PORT_FILE.flag
) &

# actual ssh terminal connection    
ssh -X -o "SendEnv MY_PORT_FILE" -R0:localhost:631 -R0:localhost:4713 $REMOTE 2> $PORTFILE

# remove files after connection is over
rm -v $PORTFILE $EMPTYFLAG

Dann ein Snippet für die Remote-Seite, geeignet für .bashrc :

# only do this if subdir has been created and env variable set
if [ -d ~/portfiles -a "$MY_PORT_FILE" ] ; then

       PORTFILE=~/portfiles/$(basename "$MY_PORT_FILE")
       FLAGFILE=$PORTFILE.flag
       # wait for FLAGFILE to get copied,
       # after which PORTFILE should be complete
       while [ \! -f "$FLAGFILE" ] ; do 
           echo "Waiting for $FLAGFILE..."
           sleep 1
       done

       # use quite exact regexps and head to make this robust
       export CUPS_SERVER=localhost:$(grep '^Allocated port [0-9]\+ .* localhost:631[[:space:]]*$' "$PORTFILE" | head -1 | cut -d" " -f3)
       export PULSE_SERVER=localhost:$(grep '^Allocated port [0-9]\+ .* localhost:4713[[:space:]]*$' "$PORTFILE" | head -1 | cut -d" " -f3)
       echo "Set CUPS_SERVER and PULSE_SERVER"

       # copied files served their purpose, and can be removed right away
       rm -v -- "$PORTFILE" "$FLAGFILE"
fi

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.

Hyde
quelle
Was natürlich erfordert, dass ich scpvon der entfernten Seite zur lokalen Seite kann, was ich nicht kann. Ich hatte einen ähnlichen Ansatz, aber ich würde sshihn nach dem Herstellen der Verbindung in den Hintergrund einbinden, dann diese Datei von lokal nach remote über senden scpund dann den sshClient 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 lokalen sshClients in solche Remote-Skripte scheint kein guter Ansatz zu sein.
Bananguin
Ah. Ich denke, Sie sollten nur die clientseitige scp Hintergrund : (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).
Hyde
@ Bananguin Neue Version fertig. Scheint für mich zu funktionieren, sollte also an Ihren Anwendungsfall anpassbar sein. Über "nette Herangehensweise", ja, aber ich denke nicht, dass hier wirklich eine nette Herangehensweise möglich ist. Die Informationen müssen irgendwie weitergegeben werden, und es wird immer ein Hack sein, es sei denn, Sie patchen sowohl den SSH-Client als auch den Server, um dies sauber über die einzelne Verbindung zu tun.
Hyde
Und ich denke immer mehr darüber nach, openssh zu patchen. Scheint keine große Sache zu sein. Die Informationen sind bereits verfügbar. Ich muss es nur an den Server senden. Wann immer der Server solche Informationen erhält, schreibt er sie an~/.ssh-${PID}-forwards
Bananguin
1

Ein Snippet für die lokale Seite, geeignet für .bashrc:

#!/bin/bash

user=$1
host=$2

sshr() {
# 1. connect, get dynamic port, disconnect  
port=`echo "exit" | ssh -R '*:0:127.0.0.1:52698' -t $1 2>&1 | grep 'Allocated port' | awk '/port/ {print $3;}'`
# 2. reconnect with this port and set remote variable
cmds="ssh -R $port:127.0.0.1:52698 -t $1 bash -c \"export RMATE_PORT=$port; bash\""
($cmds)
}

sshr $user@$host
ToxeH
quelle
0

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.shdas 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

mkfifo pipe
ssh -R "*:0:localhost:22" user@remotehost "~/getsshport.sh" 3>&1 1>&2 2>&3 < pipe | cat > pipe

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

#!/bin/sh
echo "Connection from $SSH_CLIENT"
while read line
do
    echo "$line" # echos everything sent back to the client
    echo "$line" | sed -n "s/Allocated port \([0-9]*\) for remote forward to \(.*\)\:\([0-9]*\).*/client port \3 is on local port \1/p" >> /tmp/allocatedports
done

Ich habe zuerst versucht, grepdie 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. catscheint 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 readZeile 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 macht

Das Weiterleiten des stderr von ssh in einen Befehl wie ~/getsshport.shwird bevorzugt, da ohne Angabe eines Befehls der Bannertext oder was auch immer in der Pipe enthalten ist, auf der Remote-Shell ausgeführt wird.

JesseMcL
quelle
nett. Ich fügte renice +10 $$; exec catvor dem hinzu done, um Ressourcen zu sparen.
Spongman
0

Dies ist eine knifflige, zusätzliche serverseitige Behandlung in Anlehnung an SSH_CONNECTIONoder DISPLAYwäre großartig, aber es ist nicht einfach hinzuzufügen: Ein Teil des Problems besteht darin, dass nur der sshClient 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 ;-)

  • clientseitig hinzufügen / ändern, SendEnvdamit wir einige Umgebungsvariablen nativ über ssh senden können (wahrscheinlich nicht standardmäßig)
  • Serverseitig hinzufügen / ändern AcceptEnv, um dasselbe zu akzeptieren (wahrscheinlich nicht standardmäßig aktiviert)
  • Überwachen Sie die sshClient-Stderr-Ausgabe mit einer dynamisch geladenen Bibliothek und aktualisieren Sie die SSH-Client-Umgebung während des Verbindungsaufbaus
  • Nehmen Sie die Umgebungsvariablen serverseitig im Profil- / Anmeldeskript auf

Dies 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 die write()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 ...)

Host somehost
  user whatever
  SendEnv SSH_RFWD_*

Auf dem Server sshd_config(Root- / Verwaltungsänderung erforderlich)

AcceptEnv LC_* SSH_RFWD_*

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:

LD_PRELOAD=./rfwd.so ssh -R0:127.0.0.1:4713 -R0:localhost:631 somehost

Der Code:

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>

// gcc -Wall -shared  -ldl -Wl,-soname,rfwd -o rfwd.so rfwd.c

#define DEBUG 0
#define dfprintf(fmt, ...) \
    do { if (DEBUG) fprintf(stderr, "[%14s#%04d:%8s()] " fmt, \
          __FILE__, __LINE__, __func__,##__VA_ARGS__); } while (0)

typedef ssize_t write_fp(int fd, const void *buf, size_t count);
static write_fp *real_write;

void myinit(void) __attribute__((constructor));
void myinit(void)
{
    void *dl;
    dfprintf("It's alive!\n");
    if ((dl=dlopen(NULL,RTLD_NOW))) {
        real_write=dlsym(RTLD_NEXT,"write");
        if (!real_write) dfprintf("error: %s\n",dlerror());
        dfprintf("found %p write()\n", (void *)real_write);
    } else {
        dfprintf(stderr,"dlopen() failed\n");
    }
}

ssize_t write(int fd, const void *buf, size_t count)
{
     static int nenv=0;

     // debug1: Remote connections from 192.168.0.1:0 forwarded to local address 127.0.0.1:1000
     //  Allocated port 44284 for remote forward to 127.0.0.1:1000
     // debug1: All remote forwarding requests processed
     if ( (fd==2) && (!strncmp(buf,"Allocated port ",15)) ) {
         char envbuf1[256],envbuf2[256];
         unsigned int rport;
         char lspec[256];
         int rc;

         rc=sscanf(buf,"Allocated port %u for remote forward to %256s",
          &rport,lspec);

         if ( (rc==2) && (nenv<32) ) {
             snprintf(envbuf1,sizeof(envbuf1),"SSH_RFWD_%i",nenv++);
             snprintf(envbuf2,sizeof(envbuf2),"%u %s",rport,lspec);
             setenv(envbuf1,envbuf2,1);
             dfprintf("setenv(%s,%s,1)\n",envbuf1,envbuf2);
         }
     }
     return real_write(fd,buf,count);
}

(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 die ssh.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

for fwd in ${!SSH_RFWD_*}; do
    IFS=" :" read lport rip rport <<< ${!fwd}
    [[ $rport -eq "631" ]] && export CUPS_SERVER=localhost:$lport
    # ...
done

Vorsichtsmaßnahmen:

  • Es gibt nicht viele Fehler beim Überprüfen des Codes
  • Das Ändern der Umgebung kann Thread-bezogene Probleme verursachen. PAM verwendet Threads. Ich erwarte keine Probleme, aber ich habe das nicht getestet
  • sshDerzeit wird die vollständige Weiterleitung des Formulars * local: port: remote: port * nicht eindeutig protokolliert (bei Bedarf wäre ein weiteres Parsen von debug1Nachrichten mit ssh -verforderlich), dies ist jedoch für Ihren Anwendungsfall nicht erforderlich

Seltsamerweise scheint OpenSSH keine Mittel zu haben, um Informationen über Portweiterleitungen abzurufen.

Sie 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_LISTENERSlots, 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 globalen optionsStruktur zu sichern:

#include "readconf.h"
Options options;  /* extern */
[...]
snprintf(buf, sizeof buf, "Local forwards:\r\n");
buffer_append(&buffer, buf, strlen(buf));
for (i = 0; i < options.num_local_forwards; i++) {
     snprintf(buf, sizeof buf, "  #%d listen %s:%d connect %s:%d\r\n",i,
       options.local_forwards[i].listen_host,
       options.local_forwards[i].listen_port,
       options.local_forwards[i].connect_host,
       options.local_forwards[i].connect_port);
     buffer_append(&buffer, buf, strlen(buf));
}
snprintf(buf, sizeof buf, "Remote forwards:\r\n");
buffer_append(&buffer, buf, strlen(buf));
for (i = 0; i < options.num_remote_forwards; i++) {
     snprintf(buf, sizeof buf, "  #%d listen %s:%d connect %s:%d\r\n",i,
       options.remote_forwards[i].listen_host,
       options.remote_forwards[i].listen_port,
       options.remote_forwards[i].connect_host,
       options.remote_forwards[i].connect_port);
     buffer_append(&buffer, buf, strlen(buf));
}

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. loist 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.

mr@local:~$ ssh -R127.53.50.55:44284:127.0.0.1:44284 remote
[...]
mr@remote:~$ ss -atnp src 127.53.50.55
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port 
LISTEN     0      128            127.53.50.55:44284                    *:*    

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.

mr.spuratic
quelle