Penerusan port jarak jauh SSH gagal

26

Tindak Lanjut: Sepertinya serangkaian pemutusan yang cepat bertepatan dengan beberapa bulan menjalankan setiap server mungkin kebetulan dan hanya berfungsi untuk mengungkapkan masalah yang sebenarnya. Alasan kegagalan untuk menyambung kembali hampir pasti karena nilai AliveInterval (jawaban kasperd). Menggunakan opsi ExitOnForwardFailure harus memungkinkan batas waktu terjadi dengan benar sebelum menghubungkan kembali, yang seharusnya memecahkan masalah dalam banyak kasus. Saran MadHatter (skrip kill) mungkin adalah cara terbaik untuk memastikan bahwa terowongan dapat terhubung kembali walaupun semuanya gagal.

Saya memiliki server (A) di belakang firewall yang memulai terowongan terbalik pada beberapa port ke DigitalOcean VPS (B) sehingga saya dapat terhubung ke A melalui alamat IP B. Terowongan telah bekerja secara konsisten selama sekitar 3 bulan, tetapi tiba-tiba gagal empat kali dalam 24 jam terakhir. Hal yang sama terjadi beberapa waktu lalu pada penyedia VPS lain - berbulan-bulan beroperasi dengan sempurna, lalu tiba-tiba mengalami beberapa kegagalan cepat.

Saya memiliki skrip pada mesin A yang secara otomatis menjalankan perintah tunnel ( ssh -R *:X:localhost:X address_of_Buntuk setiap port X) tetapi ketika dijalankan, katanya Warning: remote port forwarding failed for listen port X.

Masuk ke sshd /var/log/securedi server menunjukkan kesalahan ini:

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

Pemecahan membutuhkan reboot VPS. Sampai saat itu, semua upaya untuk menyambung kembali memberikan pesan "penerusan port jarak jauh gagal" dan tidak akan berfungsi. Sekarang ke titik di mana terowongan hanya berlangsung sekitar 4 jam sebelum berhenti.

Tidak ada yang berubah pada VPS, dan ini adalah mesin sekali pakai, pengguna tunggal yang hanya berfungsi sebagai titik akhir terowongan terbalik. Ini menjalankan OpenSSH_5.3p1 pada CentOS 6.5. Tampaknya sshd tidak menutup port pada akhirnya ketika koneksi terputus. Saya bingung menjelaskan mengapa, atau mengapa hal itu tiba-tiba terjadi sekarang setelah berbulan-bulan operasi yang hampir sempurna.

Untuk memperjelas, saya pertama-tama perlu mencari tahu mengapa sshd menolak untuk mendengarkan port setelah terowongan gagal, yang tampaknya disebabkan oleh sshd membiarkan port terbuka dan tidak pernah menutupnya. Itu tampaknya menjadi masalah utama. Saya hanya tidak yakin apa yang menyebabkannya berperilaku seperti ini setelah berbulan-bulan berperilaku seperti yang saya harapkan (yaitu segera menutup port dan memungkinkan skrip untuk menyambung kembali).

Justin Mrkva
sumber
Apa pertanyaan Anda? Bagaimana mengatasi kesalahan port binding, atau bagaimana mencari tahu mengapa ssh sekarat, atau sesuatu yang lain lagi?
MadHatter mendukung Monica
Saya perlu mencari tahu mengapa sshd menolak untuk membuka port pada VPS (kesalahan mengikat). Kesalahan pengikatan port tampaknya menjadi akar masalah, dan semuanya akan berfungsi jika saya dapat menyelesaikannya.
Justin Mrkva
2
Untuk lurkers yang terlambat, alih-alih membuat skrip secara manual untuk menjaga koneksi tetap terbuka, gunakan saja autossh, yang melakukan ini untuk Anda. serverfault.com/questions/598210/...
oligofren

Jawaban:

27

Saya setuju dengan MadHatter, bahwa kemungkinan port forwarding dari koneksi ssh yang mati. Bahkan jika masalah Anda saat ini ternyata menjadi sesuatu yang lain, Anda dapat berharap untuk mengalami koneksi ssh yang sudah mati cepat atau lambat.

Ada tiga cara koneksi yang mati tersebut dapat terjadi:

  • Salah satu dari dua titik akhir di-boot ulang sementara ujung koneksi yang lain benar-benar menganggur.
  • Salah satu dari dua titik akhir menutup koneksi, tetapi pada saat koneksi ditutup, ada pemadaman sementara pada koneksi. Pemadaman berlangsung selama beberapa menit setelah koneksi ditutup, dan dengan demikian ujung lainnya tidak pernah belajar tentang koneksi yang ditutup.
  • Koneksi masih sepenuhnya berfungsi di kedua titik akhir koneksi ssh, tetapi seseorang telah meletakkan perangkat stateful di suatu tempat di antara mereka, yang batas waktu koneksi karena kemalasan. Perangkat stateful ini bisa berupa NAT atau firewall, firewall yang telah Anda sebutkan adalah tersangka utama.

Mencari tahu mana dari ketiga di atas yang terjadi tidak terlalu penting, karena ada metode, yang akan membahas ketiganya. Itu adalah penggunaan pesan keepalive.

Anda harus melihat ClientAliveIntervalkata kunci sshd_configdan ServerAliveIntervalinterval untuk ssh_configatau ~/.ssh/config.

Menjalankan sshperintah dalam satu lingkaran dapat bekerja dengan baik. Sebaiknya masukkan juga sleep dalam loop agar Anda tidak membanjiri server ketika koneksi karena suatu alasan gagal.

Jika klien terhubung kembali sebelum koneksi berakhir di server, Anda dapat berakhir dalam situasi di mana koneksi ssh baru hidup, tetapi tidak memiliki penerusan port. Untuk menghindari itu, Anda perlu menggunakan ExitOnForwardFailurekata kunci di sisi klien.

kasperd
sumber
Saya pikir ini mungkin masalahnya. Secara khusus, skrip saya pada A akan mencoba menyambung kembali ke B jika proses ssh mati (tentu saja karena pesan peringatan tidak membunuh proses ssh yang baru saja hang ketika ini terjadi, tapi itu masalah untuk hari lain). Tetapi jika A mencoba menghubungkan kembali ke B terlalu cepat, B mungkin sedang menunggu A untuk terhubung kembali. Saya mungkin perlu memastikan B selalu keluar sebelum A terhubung kembali. Menggabungkannya dengan saran MadHatter untuk membunuh proses sshd sebelum menghubungkan kembali mungkin akan mencakup 95% dari kemungkinan kasus.
Justin Mrkva
1
Dan berbicara tentang pesan peringatan tidak membunuh SSH, itu membuat saya berpikir ... dan melihat halaman manual. Ternyata -o ExitOnForwardFailure yesitulah yang saya butuhkan. Jadi itu satu hal yang kurang saya perlu mencari tahu. Untuk berpikir, saya akan menulis skrip Python untuk menguraikan pesan peringatan itu. Ini jauh lebih sederhana. : D
Justin Mrkva
Maaf karena lupa ExitOnForwardFailureketika menulis jawaban saya. Saya telah menambahkannya ke jawabannya sekarang.
kasperd
4
Tidak masalah, dan itu sebenarnya -o ExitOnForwardFailure=yes(perhatikan tanda sama dengan). Jadi, jika ada yang menemukan ini, jangan salin dan tempel dari komentar saya sebelumnya, itu tidak akan berfungsi. : P
Justin Mrkva
Jadi saya sudah memonitor server selama sekitar 10 jam dan sepertinya berjalan baik; Saya berasumsi pada titik ini bahwa jawaban ini benar (saya sekitar 99% yakin berdasarkan apa yang saya lihat) dan bahwa rangkaian pemutusan cepat adalah kebetulan terkait dengan masalah jaringan yang kebetulan muncul beberapa bulan setelah memulai setiap layanan. Terimakasih untuk semua orang atas bantuannya. ;)
Justin Mrkva
4

Anda dapat menemukan proses yang mengikat port pada server itu dengan

sudo netstat -apn|grep -w X

Tampaknya sangat mungkin setengah mati sshd, tetapi mengapa membuat asumsi ketika Anda dapat memiliki data? Ini juga merupakan cara yang bagus untuk sebuah skrip untuk menemukan PID untuk mengirim sinyal 9 sebelum mencoba mengangkat terowongan lagi.

MadHatter mendukung Monica
sumber
Saya ingat memeriksa itu pada penyedia VPS sebelumnya, dan saya mengkonfirmasi bahwa sshd adalah proses mendengarkan port tersebut. Lain kali hal itu terjadi saya akan memeriksanya di sini, tetapi karena perilaku dan pengaturannya persis sama, saya tidak berharap itu menjadi berbeda.
Justin Mrkva
Bagus, jadi buat skrip Anda yang membuka kembali terowongan untuk membunuh tunneller lama sebelum mencoba melakukannya.
MadHatter mendukung Monica
Tidak pernah ada lebih dari satu skrip terowongan (pada A) yang berjalan sekaligus, jika itu yang Anda katakan. Di sisi lain, jika Anda bermaksud membuat skrip dari jarak jauh mengeksekusi perintah pada B untuk membunuh proses yang menyimpang ... itu sebenarnya bukan ide yang buruk setengah. Tetapi satu kekhawatiran berulang kali mematikan semua koneksi SSH jika saya mencoba untuk debug. Jika skrip pada A selalu membunuh B karena kesalahan, maka saya tidak bisa terus-menerus ditendang oleh B oleh skrip A yang nakal. : P Saya harus menguji untuk memastikan itu tidak melakukan itu. Tapi seperti yang saya katakan, bukan ide yang buruk. ;)
Justin Mrkva
Saya tidak mengira ada. Anda mengatakan ada skrip yang berjalan di server jauh yang mencoba memunculkan sebuah terowongan dan gagal, karena kesalahan pengikatan, dan saya menganggap itu hanya berjalan ketika Anda membutuhkannya (yaitu, ketika terowongan yang ada tidak baik) karena Anda belum mengatakan sebaliknya. Yang saya sarankan hanyalah mematikan proses spesifik yang menahan port terbuka sebelum mencoba membuka terowongan baru.
MadHatter mendukung Monica
Skrip yang menjalankan ssh hanya pada server A, server B adalah server vanilla biasa tanpa skrip tambahan. Apa yang mungkin akan saya lakukan adalah menulis skrip kill untuk diletakkan di server B, kemudian memanggilnya dari jarak jauh jika gagal menghubungkan beberapa kali berturut-turut. Dengan begitu kemungkinan kecil akan mengganggu koneksi SSH lainnya. Dan saya mungkin akan meminta log skrip kill setiap kali dijalankan dan keluar tanpa melakukan apa-apa jika dipanggil terlalu banyak terlalu cepat. Secara pribadi, sepertinya membatasi setiap skrip yang membunuh sshd mungkin lebih bijaksana. : P
Justin Mrkva
3

Bagi saya ketika sebuah sshterowongan terputus diperlukan beberapa saat untuk koneksi untuk mengatur ulang sehingga sshproses terus memblokir meninggalkan saya tanpa terowongan aktif dan saya tidak tahu mengapa. Solusi penyelesaiannya adalah dengan sshmenggunakan -fdan untuk menelurkan koneksi baru tanpa menunggu koneksi lama diatur ulang. The -o ExitOnForwardFailure=yesdapat digunakan untuk limt jumlah proses baru. The -o ServerAliveInterval=60meningkatkan keandalan koneksi yang sekarang.

Anda dapat mengulangi sshperintah itu berulang kali, katakanlah, dalam a cron, atau, dalam satu loop dalam skrip Anda, misalnya, berikut ini, kami menjalankan sshperintah setiap 3 menit:

while (1)
do
    ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
    sleep 180
done
Stephen Quan
sumber
solusi yang lebih kuat akan menggunakan autossh
Marco Lavagnino
-o ExitOnForwardFailure=yesadalah apa yang saya cari, terima kasih banyak!
vadipp
1

Dalam pengalaman saya ssh memiliki kebiasaan yang agak menjengkelkan untuk tidak keluar dengan bersih jika 'sesuatu' masih berjalan pada sistem jarak jauh. Misalnya dimulai di latar belakang. Anda dapat mereproduksi ini dengan:

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

Ssh Anda akan keluar, tetapi tidak akan benar-benar menutup sesi - sampai proses jarak jauh keluar (yang tidak akan, karena itu adalah 'sementara benar' loop). Mungkin hal serupa terjadi - sesi Anda mengalami proses 'macet' yang dihasilkan oleh ssh. Port tetap digunakan, dan karena itu tidak dapat digunakan kembali oleh proses lokal Anda.

Sobrique
sumber
Perintah SSH lengkap yang dijalankan pada mesin A adalah ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 &sehingga tidak ada yang dieksekusi oleh SSH kecuali terowongan itu sendiri, khususnya karena opsi -N. Apa pun yang disimpan terbuka sedang dilakukan pada server jauh B menggunakan sshd itu sendiri.
Justin Mrkva