Zdalne przekazywanie portów SSH nie powiodło się

26

Dalsze działania: wygląda na to, że szybka seria rozłączeń zbiegająca się z kilkumiesięcznym uruchomieniem każdego serwera jest prawdopodobnie przypadkowa i służy jedynie ujawnieniu faktycznego problemu. Powodem, dla którego nie udało się ponownie połączyć, jest prawie na pewno wartość AliveInterval (odpowiedź kasperda). Użycie opcji ExitOnForwardFailure powinno pozwolić na prawidłowe przekroczenie limitu czasu przed ponownym połączeniem, co w większości przypadków powinno rozwiązać problem. Sugestia MadHattera (skrypt zabicia) jest prawdopodobnie najlepszym sposobem, aby upewnić się, że tunel może się ponownie połączyć, nawet jeśli wszystko inne zawiedzie.

Mam serwer (A) za zaporą ogniową, który inicjuje tunel zwrotny na kilku portach do małego DigitalOcean VPS (B), dzięki czemu mogę połączyć się z A za pośrednictwem adresu IP B. Tunel działał konsekwentnie przez około 3 miesiące, ale nagle zawiódł cztery razy w ciągu ostatnich 24 godzin. To samo zdarzyło się jakiś czas temu u innego dostawcy VPS - miesiące doskonałej pracy, a potem nagle wiele szybkich awarii.

Mam skrypt na komputerze A, który automatycznie wykonuje polecenie tunelowania ( ssh -R *:X:localhost:X address_of_Bdla każdego portu X), ale gdy się wykonuje, mówi Warning: remote port forwarding failed for listen port X.

Przechodzenie do sshd /var/log/securena serwerze pokazuje następujące błędy:

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

Rozwiązanie wymaga ponownego uruchomienia VPS. Do tego czasu wszystkie próby ponownego połączenia powodują wyświetlenie komunikatu „nieudane przekierowanie portu” i nie będą działać. Teraz jest tak, że tunel trwa tylko około 4 godzin przed zatrzymaniem.

Nic się nie zmieniło na VPS, a jest to maszyna do jednorazowego użytku dla jednego użytkownika, która służy tylko jako punkt końcowy tunelu zwrotnego. Działa z OpenSSH_5.3p1 na CentOS 6.5. Wygląda na to, że sshd nie zamyka portów na swoim końcu, gdy połączenie zostanie zerwane. Nie potrafię wyjaśnić, dlaczego lub dlaczego tak się stanie nagle po miesiącach prawie idealnej pracy.

Aby to wyjaśnić, najpierw muszę dowiedzieć się, dlaczego sshd odmawia nasłuchiwania portów po awarii tunelu, co wydaje się być spowodowane tym, że sshd pozostawia porty otwarte i nigdy ich nie zamyka. To wydaje się być głównym problemem. Po prostu nie jestem pewien, co spowodowałoby, że zachowałby się w ten sposób po miesiącach zachowań zgodnych z oczekiwaniami (tj. Natychmiastowym zamknięciu portów i umożliwieniu skryptu ponownego połączenia).

Justin Mrkva
źródło
Jakie jest Twoje pytanie? Jak rozwiązać błąd wiązania portu lub dowiedzieć się, dlaczego umiera ssh, czy coś jeszcze?
MadHatter obsługuje Monikę
Muszę dowiedzieć się, dlaczego sshd odmawia otwarcia portów VPS (błąd powiązania). Błąd wiązania portu wydaje się być przyczyną problemu i wszystko powinno działać, jeśli mogę to rozwiązać.
Justin Mrkva
2
W przypadku późnych czyhaczy zamiast ręcznego tworzenia skryptu, aby utrzymać połączenie otwarte, wystarczy użyć zamiast tego autossh, co robi to za Ciebie. serverfault.com/questions/598210/…
oligofren

Odpowiedzi:

27

Zgadzam się z MadHatter, że prawdopodobnie będą to przekierowania portów z niedziałających połączeń ssh. Nawet jeśli twój obecny problem okaże się czymś innym, możesz spodziewać się, że prędzej czy później natkniesz się na takie niedziałające połączenia ssh.

Istnieją trzy sposoby, w jakie mogą wystąpić takie niedziałające połączenia:

  • Jeden z dwóch punktów końcowych został ponownie uruchomiony, a drugi koniec połączenia był całkowicie bezczynny.
  • Jeden z dwóch punktów końcowych zamknął połączenie, ale w momencie, gdy połączenie zostało zamknięte, nastąpiło tymczasowe wyłączenie połączenia. Awaria trwała kilka minut po zamknięciu połączenia, dlatego drugi koniec nigdy nie dowiedział się o zamkniętym połączeniu.
  • Połączenie jest nadal w pełni funkcjonalne w obu punktach końcowych połączenia ssh, ale ktoś umieścił gdzieś między nimi stanowe urządzenie, które przekroczyło limit czasu połączenia z powodu bezczynności. To stanowe urządzenie może być NAT lub zaporą ogniową. Zapora, o której już wspomniałeś, jest głównym podejrzanym.

Ustalenie, które z powyższych trzech zdarzeń ma miejsce, nie jest bardzo ważne, ponieważ istnieje metoda, która zajmie się wszystkimi trzema. To jest użycie komunikatów podtrzymujących.

Powinieneś spojrzeć na ClientAliveIntervalsłowo kluczowe dla sshd_configi ServerAliveIntervalinterwał dla ssh_configlub ~/.ssh/config.

Uruchamianie sshpolecenia w pętli może działać poprawnie. Dobrym pomysłem jest wstawienie trybu uśpienia w pętlę, aby nie zalać serwera, gdy połączenie z jakiegoś powodu nie powiedzie się.

Jeśli klient ponownie się połączy przed zakończeniem połączenia na serwerze, możesz skończyć w sytuacji, gdy nowe połączenie ssh jest aktywne, ale nie ma przekierowania portów. Aby tego uniknąć, musisz użyć ExitOnForwardFailuresłowa kluczowego po stronie klienta.

kasperd
źródło
Myślę, że to może być problem. W szczególności mój skrypt na A spróbuje ponownie połączyć się z B, jeśli proces ssh umrze (oczywiście, ponieważ komunikat ostrzegawczy nie zabija procesu ssh, po prostu zawiesza się, gdy to nastąpi, ale to problem na inny dzień). Ale jeśli A zbyt szybko spróbuje ponownie połączyć się z B, B może oczekiwać na ponowne połączenie A. Prawdopodobnie muszę się upewnić, że B zawsze kończy limit czasu, zanim A ponownie się połączy. Połączenie tego z sugestią MadHattera dotyczącą zabicia procesów sshd przed ponownym połączeniem prawdopodobnie obejmie 95% możliwych przypadków.
Justin Mrkva
1
A mówiąc o ostrzeżeniu, że nie zabija SSH, to sprawiło, że pomyślałem ... i spojrzałem na strony. Okazuje się, że -o ExitOnForwardFailure yeswłaśnie tego potrzebowałem. Więc to jedna mniejsza rzecz, którą muszę zrozumieć. Pomyślałem, że zamierzam napisać skrypt w języku Python, aby przeanalizować te komunikaty ostrzegawcze. To jest o wiele prostsze. : D
Justin Mrkva
Przepraszamy za zapomnienie ExitOnForwardFailurepodczas pisania mojej odpowiedzi. Dodałem go teraz do odpowiedzi.
kasperd
4
Nie ma problemu i tak naprawdę było -o ExitOnForwardFailure=yes(zwróć uwagę na znak równości). Więc jeśli ktoś się z tym spotka, nie kopiuj i wklej z mojego poprzedniego komentarza, to nie zadziała. : P
Justin Mrkva
Więc monitoruję serwer przez około 10 godzin i wygląda na to, że działa dobrze; Zakładam w tym momencie, że ta odpowiedź jest poprawna (jestem w około 99% pewien na podstawie tego, co widziałem) i że seria szybkich rozłączeń była zbiegiem okoliczności związanym z problemami z siecią, które pojawiły się kilka miesięcy później uruchomienie każdej usługi. Dziękujemy wszystkim za pomoc. ;)
Justin Mrkva
4

Możesz znaleźć proces, który wiąże port na tym serwerze

sudo netstat -apn|grep -w X

Wydaje się bardzo prawdopodobne, że jest to na wpół nieużywane sshd, ale po co zakładać, kiedy można mieć dane? Jest to również dobry sposób, aby skrypt znalazł PID do wysłania sygnału 9 przed ponownym uruchomieniem tunelu.

MadHatter obsługuje Monikę
źródło
Pamiętam, że sprawdziłem to na poprzednim dostawcy VPS i potwierdziłem, że sshd to proces nasłuchujący na tych portach. Następnym razem to się sprawdzi tutaj, ale ponieważ zachowanie i konfiguracja są dokładnie takie same, nie oczekuję, że będzie inaczej.
Justin Mrkva
Świetnie, więc skrypt, który ponownie otwiera tunel, zabije starego tunelu przed próbą zrobienia tego.
MadHatter obsługuje Monikę
Nigdy nie działa więcej niż jeden skrypt tunelu (na A) naraz, jeśli tak mówisz. Z drugiej strony, jeśli chcesz zdalnie wykonać skrypt na komendzie B, aby zabić zbłąkane procesy ... to nie jest wcale taki zły pomysł. Ale jedną z obaw jest wielokrotne przerywanie wszystkich połączeń SSH, jeśli próbuję debugować. Jeśli skrypt na A zawsze zabija B z powodu usterki, to nie mogę być ciągle wyrzucany z B przez nieuczciwy skrypt A. : P Będę musiał przetestować, aby upewnić się, że tego nie robi. Ale jak powiedziałem, nie jest to wcale taki zły pomysł. ;)
Justin Mrkva
Nie myślałem, że tam jest. Mówisz, że na zdalnym serwerze działa skrypt, który próbuje uruchomić tunel i kończy się niepowodzeniem z powodu błędu powiązania, i zakładam, że działa on tylko wtedy, gdy jest to potrzebne (tj. Gdy istniejący tunel nie jest dobry) ponieważ nie powiedziałeś inaczej. Wszystko, co sugeruję, to to, że zabija określony proces, który utrzymuje port otwarty, zanim spróbuje uruchomić nowy tunel.
MadHatter obsługuje Monikę
Skrypt z uruchomionym ssh znajduje się tylko na serwerze A, serwer B jest zwykłym serwerem waniliowym bez dodatkowych skryptów. To, co prawdopodobnie zrobię, to napisanie skryptu zabijania, aby umieścić na serwerze B, a następnie zdalne wywołanie go z A, jeśli nie uda się połączyć pewną liczbę razy z rzędu. W ten sposób mniej prawdopodobne jest zakłócanie innych połączeń SSH. I prawdopodobnie będę mieć dziennik skryptu zabijania za każdym razem, gdy zostanie uruchomiony i zakończy się bez robienia czegokolwiek, jeśli zostanie wywołany zbyt wiele razy zbyt szybko. Osobiście wydaje się, że ograniczenie skryptu, który zabija sshd, jest prawdopodobnie rozsądne. : P
Justin Mrkva
3

Dla mnie, gdy sshtunel się rozłącza, połączenie się resetuje, więc sshproces nadal blokuje się, pozostawiając mnie bez aktywnych tuneli i nie wiem dlaczego. Rozwiązaniem tego problemu jest umieszczenie sshw tle -fi tworzenie nowych połączeń bez czekania na zresetowanie starych połączeń. -o ExitOnForwardFailure=yesMogą być wykorzystane do LIMT liczby nowych procesów. -o ServerAliveInterval=60Poprawia niezawodność bieżącego połączenia.

Możesz powtarzać sshpolecenie często, powiedzmy, w cronpętli lub w pętli skryptu, na przykład w następujący sposób: uruchamiamy sshpolecenie co 3 minuty:

while (1)
do
    ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
    sleep 180
done
Stephen Quan
źródło
o wiele bardziej niezawodnym rozwiązaniem byłoby użycie autossh
Marco Lavagnino,
-o ExitOnForwardFailure=yesbyło to, czego szukałem, wielkie dzięki!
vadipp
1

Z mojego doświadczenia wynika, że ​​ssh ma trochę irytujący zwyczaj nie wychodzenia czysto, jeśli „coś” nadal działa na zdalnym systemie. Np. Zaczął się w tle. Możesz to odtworzyć poprzez:

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

Twój ssh wyloguje się, ale tak naprawdę nie zamknie sesji - dopóki proces zdalny nie zakończy się (czego nie zrobi, ponieważ jest to pętla „while true”). Może się zdarzyć, że dzieje się coś podobnego - twoja sesja ma zablokowany proces, który jest spawnowany przez ssh. Port pozostaje w użyciu i dlatego nie może zostać ponownie wykorzystany przez proces lokalny.

Sobrique
źródło
Kompletne polecenie SSH, które wykonuje się na maszynie A, ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 &więc nic nie jest wykonywane przez SSH poza samym tunelem, szczególnie z powodu opcji -N. Cokolwiek pozostaje otwarte, odbywa się na zdalnym serwerze B za pomocą samego sshd.
Justin Mrkva