Kegagalan client-connect OpenVPN: apakah pembersihan saat disconnect dijamin?
Klien yang ditolak tidak membatalkan aturan firewall atau catatan yang sudah ditulis. Bandingkan kontrak callback dengan pembatalan yang harus dilakukan hook Anda sendiri.
Ketika skrip client-connect keluar dengan kode bukan nol, OpenVPN menolak klien, dan operator biasanya menganggap skrip client-disconnect yang sesuai akan merapikan semuanya. Sering kali skrip itu tidak pernah berjalan, karena pemrosesan disconnect bergantung pada apa yang berhasil diselesaikan tahap connect. Memperlakukan penolakan dan pembatalan sebagai satu mekanisme itulah yang mengubah login gagal menjadi aturan firewall bocor atau catatan yatim. Keduanya adalah dua kewajiban terpisah, dan hanya satu yang otomatis. Baca jalur keluar hook itu sendiri sebelum menyalahkan server karena meninggalkan status.
Keluar dengan kode bukan nol menolak klien; itu tidak membatalkan pekerjaan Anda
Status keluar client-connect adalah keputusan penerimaan. Nol berarti terima, apa pun selain itu berarti membongkar instans sebelum benar-benar terbentuk. Tidak ada apa pun dalam kontrak itu yang memeriksa apa yang sudah dilakukan skrip terhadap dunia luar. Jika skrip menambahkan aturan iptables, menulis baris, atau menaikkan penghitung, perubahan itu bertahan setelah penolakan.
Asimetri yang sama berlaku untuk plugin, di mana beberapa fungsi connect dapat berjalan untuk satu instans. Kegagalan berikutnya tidak membatalkan keberhasilan sebelumnya secara surut, dan fungsi sebelumnya tidak punya cara mengetahui bahwa fungsi saudara gagal.
Penolakan otomatis, pembersihan tidak
Panduan OpenVPN 2.6 mengaitkan pemrosesan client-disconnect dengan keberhasilan pemrosesan connect sebelumnya. Pengecualian terdokumentasi mencakup rantai berjenjang: jika satu langkah connect sudah mengembalikan keberhasilan, langkah disconnect yang sesuai tetap berjalan saat instans dibongkar, meskipun langkah connect berikutnya gagal. Pengecualian itu sempit dan bergantung pada berapa banyak callback yang dikonfigurasi, karena itu menguji satu skrip shell tidak memberi tahu apa pun tentang sebuah rantai.
Petakan konfigurasi sebenarnya sebelum merancang di sekitarnya: skrip mana, plugin mana, dan dalam urutan apa semuanya berjalan. Tabel di bawah mencantumkan apa yang ditinggalkan penyiapan setengah jadi.
| What the hook did before failing | What the client sees | What stays behind |
|---|---|---|
| Created a firewall entry | A rejection, with no tunnel | A rule matching an address nobody owns |
| Wrote a state row | A rejection, with no tunnel | A record of a session that never started |
| Allocated a tunnel address | A rejection, with no tunnel | An address marked busy until something releases it |
Setiap baris berakhir sama bagi klien dan berbeda bagi host. Klien tidak dapat mengetahui mana yang terjadi, jadi hook harus membatalkan apa yang dilakukannya sebelum mengembalikan status kegagalan.
Kompensasi di dalam skrip yang gagal
Validasi semua yang bisa sebelum menyentuh status bersama: bidang sertifikat, ketersediaan alamat, grup tempat klien berada. Penolakan termurah adalah yang terjadi sebelum alokasi apa pun. Begitu penyiapan mencakup beberapa operasi eksternal, catat mana yang selesai dan batalkan dalam urutan terbalik sebelum mengembalikan status kegagalan.
Kasus konkret: skrip membuat entri firewall per klien, lalu gagal menulis baris status yang mendeskripsikannya. Cabang yang gagal harus menghapus entri yang baru dibuatnya lalu keluar dengan kode bukan nol. Menunggu peristiwa disconnect yang mungkin tidak pernah dijadwalkan adalah cara sebuah aturan bertahan lebih lama daripada sesi yang dimaksudkan untuknya.
Buat kompensasi idempoten dan memiliki pemilik
Pembersihan harus aman dijalankan dua kali dan tepat tentang apa yang boleh dihapusnya. Peristiwa terlambat dari percobaan sebelumnya tidak boleh menghapus alokasi sesi yang lebih baru hanya karena keduanya berbagi nama umum atau alamat terowongan yang didaur ulang. Catat handle atau id operasi spesifik bersama sumber daya, dan hapus berdasarkan kunci itu alih-alih berdasarkan nama. Transaksi basis data hanya membantu untuk perubahan basis data itu sendiri; aturan firewall di luar batas itu memerlukan langkah kompensasi eksplisit.
Anggap proses dapat mati antara perubahan dan pembersihan, dan tambahkan rekonsiliator yang membandingkan status eksternal dengan daftar klien yang diterima sesuai jadwal.
Uji tiga jalur yang benar-benar berbeda
Latih tiga kasus: penolakan sebelum apa pun dialokasikan, penolakan setelah alokasi sebagian, dan sesi diterima normal yang berakhir kemudian. Ketiganya menghasilkan baris log berbeda dan residu berbeda. Periksa status eksternal setelah masing-masing, bukan hanya pesan kegagalan klien, karena kegagalan klien adalah hasil yang diharapkan pada dua dari tiga kasus.
Catat tahap hook, status keluar, dan apa yang dialokasikan atau dilepaskan, tanpa kredensial. Log hook yang menyebut sumber daya yang dibuatnya itulah yang membuat aturan bocor dapat ditemukan enam bulan kemudian.