Inoltro porta remota SSH non riuscito


27

Follow-up: sembra che la rapida serie di disconnessioni che coincidono con alcuni mesi di funzionamento di ciascun server sia probabilmente casuale e servita a rivelare il problema reale. Il motivo per cui non è stato possibile riconnettersi è quasi certamente dovuto ai valori AliveInterval (risposta di kasperd). L'uso dell'opzione ExitOnForwardFailure dovrebbe consentire il timeout corretto prima di ricollegarsi, il che dovrebbe risolvere il problema nella maggior parte dei casi. Il suggerimento di MadHatter (il kill script) è probabilmente il modo migliore per assicurarsi che il tunnel possa riconnettersi anche se tutto il resto fallisce.

Ho un server (A) dietro un firewall che avvia un tunnel inverso su più porte verso un piccolo VPS DigitalOcean (B), così posso collegarmi ad A tramite l'indirizzo IP di B. Il tunnel ha funzionato costantemente per circa 3 mesi, ma è improvvisamente fallito quattro volte nelle ultime 24 ore. La stessa cosa è successa un po 'di tempo fa su un altro provider VPS: mesi di funzionamento perfetto, poi improvvisamente molteplici guasti rapidi.

Ho uno script sulla macchina A che esegue automaticamente il comando tunnel ( ssh -R *:X:localhost:X address_of_Bper ogni porta X) ma quando viene eseguito, diceWarning: remote port forwarding failed for listen port X .

Accedere /var/log/securea sshd sul server mostra questi errori:

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

La risoluzione richiede il riavvio del VPS. Fino ad allora, tutti i tentativi di riconnettersi danno il messaggio "port forwarding remoto fallito" e non funzioneranno. È arrivato al punto in cui il tunnel dura solo circa 4 ore prima di fermarsi.

Non è cambiato nulla sul VPS ed è una macchina monouso e monoutente che funge solo da endpoint del tunnel inverso. Funziona con OpenSSH_5.3p1 su CentOS 6.5. Sembra che sshd non stia chiudendo le porte quando finisce la connessione. Sono in perdita per spiegare perché, o perché sarebbe successo all'improvviso ora dopo mesi di operazioni quasi perfette.

Per chiarire, devo prima capire perché sshd si rifiuta di ascoltare sulle porte dopo il fallimento del tunnel, il che sembra essere causato da sshd che ha lasciato le porte aperte e non le ha mai chiuse. Questo sembra essere il problema principale. Non sono sicuro di cosa potrebbe comportare questo in questo modo dopo mesi di comportamento come mi aspetto (cioè chiudere immediatamente le porte e consentire allo script di riconnettersi).


Qual è la tua domanda? Come affrontare l'errore di associazione delle porte o come scoprire perché ssh sta morendo o qualcos'altro?
MadHatter supporta Monica

Devo capire perché sshd si rifiuta di aprire le porte sul VPS (errore di bind). L'errore di associazione delle porte sembra essere la radice del problema e tutto dovrebbe funzionare se sono in grado di risolverlo.
Justin Mrkva,

2
Per tutti i ritardatari, invece di creare manualmente uno script per mantenere aperta la connessione, utilizzare semplicemente autossh, che fa questo per te. serverfault.com/questions/598210/…
oligofren

Risposte:


28

Concordo con MadHatter che è probabile che si tratti di port forwarding da connessioni ssh defunte. Anche se il tuo attuale problema si rivela essere qualcos'altro, prima o poi puoi aspettarti di imbatterti in connessioni ssh defunte.

Esistono tre modi in cui possono verificarsi connessioni defunte:

  • Uno dei due endpoint è stato riavviato mentre l'altra estremità della connessione era completamente inattiva.
  • Uno dei due endpoint ha chiuso la connessione, ma nel momento in cui la connessione è stata chiusa, si è verificata un'interruzione temporanea della connessione. L'interruzione è durata alcuni minuti dopo la chiusura della connessione, quindi l'altra estremità non ha mai saputo della connessione chiusa.
  • La connessione è ancora completamente funzionale su entrambi gli endpoint della connessione ssh, ma qualcuno ha messo un dispositivo stateful da qualche parte tra loro, che ha scaduto la connessione a causa dell'ozio. Questo dispositivo con stato sarebbe un NAT o un firewall, il firewall che hai già citato è il principale sospettato.

Capire quale dei tre precedenti sta accadendo non è molto importante, perché esiste un metodo che affronterà tutti e tre. Questo è l'uso di messaggi keepalive.

Dovresti cercare la ClientAliveIntervalparola chiave sshd_confige l' ServerAliveIntervalintervallo per ssh_configo ~/.ssh/config.

L'esecuzione del sshcomando in un ciclo può funzionare correttamente. È consigliabile inserire anche una sospensione nel ciclo in modo tale da non finire per inondare il server quando la connessione per qualche motivo non riesce.

Se il client si riconnette prima che la connessione sia terminata sul server, è possibile trovarsi in una situazione in cui la nuova connessione ssh è attiva, ma non ha port forwarding. Per evitarlo, è necessario utilizzare la ExitOnForwardFailureparola chiave sul lato client.


Sto pensando che questo potrebbe essere il problema. In particolare, il mio script su A proverà a riconnettersi a B se il processo SSH termina (ovviamente poiché il messaggio di avviso non interrompe il processo SSH si blocca solo quando ciò accade, ma è un problema per un altro giorno). Ma se A tenta di riconnettersi troppo rapidamente a B, B potrebbe attendere che A si riconnetta. Probabilmente devo assicurarmi che B scada sempre prima che A si ricolleghi. Combinando questo con il suggerimento di MadHatter di uccidere i processi sshd prima di ricollegarsi, probabilmente coprirà il 95% dei casi possibili.
Justin Mrkva,

1
E parlare del messaggio di avvertimento che non uccide SSH, mi ha fatto pensare ... e guardare le pagine man. Si scopre che -o ExitOnForwardFailure yesè esattamente quello di cui avevo bisogno. Quindi è una cosa in meno che devo capire. Pensando, stavo per scrivere uno script Python per analizzare quei messaggi di avviso. Questo è molto più semplice. : D
Justin Mrkva,

Ci scusiamo per aver dimenticato di ExitOnForwardFailureaver scritto la mia risposta. L'ho aggiunto alla risposta ora.
Kasperd,

4
Nessun problema, ed è stato effettivamente -o ExitOnForwardFailure=yes(notare il segno di uguale). Quindi, se qualcuno si imbatte in questo, non copiare e incollare dal mio commento precedente, non funzionerà. : P
Justin Mrkva,

Quindi ho monitorato il server per circa 10 ore e sembra che funzioni bene; Sto assumendo a questo punto che questa risposta sia corretta (sono sicuro di circa il 99% in base a quello che ho visto) e che la serie di disconnessioni rapide era una coincidenza relativa a problemi di rete che si sono verificati pochi mesi dopo avviare ogni servizio. Grazie a tutti per il vostro aiuto. ;)
Justin Mrkva,

4

Puoi trovare il processo che sta vincolando la porta su quel server

sudo netstat -apn|grep -w X

Sembra molto probabile che sia il mezzo defunto sshd, ma perché fare ipotesi quando si possono avere dati? È anche un buon modo per uno script di trovare un PID a cui inviare il segnale 9 prima di provare a richiamare nuovamente il tunnel.


Ricordo di averlo verificato sul precedente provider VPS e ho confermato che sshd era il processo che ascoltava quelle porte. La prossima volta che succede lo controllerò qui, ma poiché il comportamento e l'installazione sono esattamente gli stessi, non mi aspetto che sia diverso.
Justin Mrkva,

Fantastico, quindi fai in modo che la tua sceneggiatura che riapra il tunnel uccida il vecchio tunneller prima di provare a farlo.
MadHatter supporta Monica

Non c'è mai più di uno script tunnel (su A) in esecuzione contemporaneamente, se è quello che stai dicendo. D'altra parte, se vuoi dire che lo script esegua in remoto un comando su B per uccidere i processi vaganti ... non è in realtà una mezza cattiva idea. Ma una preoccupazione è uccidere ripetutamente tutte le connessioni SSH se sto cercando di eseguire il debug. Se la sceneggiatura su A uccide sempre B a causa di un problema tecnico, allora non posso essere costantemente espulso da B dalla sceneggiatura A canaglia. : P Dovrò fare un test per assicurarmi che non lo faccia. Ma come ho detto, non una mezza cattiva idea. ;)
Justin Mrkva,

Non avevo pensato che ci fosse. Dici che c'è uno script in esecuzione sul server remoto che tenta di aprire un tunnel e fallisce, a causa dell'errore di bind, e presumo che funzioni solo quando ne hai bisogno (cioè, quando il tunnel esistente non va bene) perché non hai detto diversamente. Tutto ciò che sto suggerendo è che uccide il processo specifico che tiene aperta la porta prima che tenti di aprire il nuovo tunnel.
MadHatter supporta Monica

Lo script che esegue ssh è solo sul server A, il server B è un semplice server vanilla senza script aggiuntivi. Quello che probabilmente farò è scrivere uno script kill da mettere sul server B, quindi chiamarlo in remoto da A se non riesce a connettersi un certo numero di volte di seguito. In questo modo è meno probabile che interferisca con altre connessioni SSH. E probabilmente avrò il registro degli script di uccisione ogni volta che viene eseguito ed esce senza fare nulla se viene chiamato troppe volte troppo in fretta. Personalmente, sembra che limitare la velocità di qualsiasi script che uccida sshd sia probabilmente prudente. : P
Justin Mrkva,

3

Per me quando un sshtunnel si disconnette ci vuole un po 'di tempo per ripristinare la connessione, quindi il sshprocesso continua a bloccarsi lasciandomi senza tunnel attivi e non so perché. Una soluzione alternativa è quella di mettere sshin background -fe generare nuove connessioni senza attendere il ripristino delle vecchie connessioni. La -o ExitOnForwardFailure=yespuò essere utilizzato per limt il numero di nuovi processi. Il -o ServerAliveInterval=60migliora l'affidabilità della connessione corrente.

Puoi ripetere il sshcomando frequentemente, ad esempio, in un cron, o, in un ciclo nel tuo script, ad esempio, nel seguito, eseguiamo il sshcomando ogni 3 minuti:

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

un modo più solido sarebbe usare l' autossh
Marco Lavagnino,

-o ExitOnForwardFailure=yesera quello che stavo cercando, grazie mille!
vadipp,

1

Nella mia esperienza ssh ha l'abitudine leggermente fastidiosa di non uscire in modo pulito se "qualcosa" è ancora in esecuzione sul sistema remoto. Ad esempio, è iniziato in background. Puoi riprodurlo come segue:

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

Il tuo ssh si disconnetterà, ma in realtà non chiuderà la sessione - fino a quando il processo remoto non verrà chiuso (cosa che non avverrà, perché è un ciclo 'while true'). Potrebbe succedere qualcosa di simile: la tua sessione ha un processo "bloccato" generato da ssh. La porta rimane in uso e pertanto non può essere riutilizzata dal processo locale.


Il comando SSH completo che viene eseguito sulla macchina A è ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 &quindi non c'è nulla che venga eseguito da SSH tranne il tunnel stesso, in particolare a causa dell'opzione -N. Qualunque cosa venga mantenuta aperta viene eseguita sul server remoto B usando sshd stesso.
Justin Mrkva,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.