Menandai lalu lintas dari satu cgroup adalah bagian yang mudah. Tiga keputusan terpisah harus selaras sebelum satu aplikasi keluar melalui antarmuka fisik sementara semua yang lain tetap di dalam terowongan: soket mana yang termasuk pengecualian, pencarian rute mana yang dipicu oleh tanda tersebut, dan alamat sumber mana yang dibawa paket saat keluar. Sebagian besar upaya yang gagal benar pada yang pertama, setengah benar pada yang kedua, dan tidak pernah memeriksa yang ketiga.

Tiga keputusan, bukan satu

Klasifikasi menjawab siapa yang dikecualikan. Perutean menjawab ke mana paket bertanda pergi. Pemilihan alamat sumber menjawab apa yang akan dilihat ujung jauh dan ke mana balasan harus kembali.

Hal-hal ini gagal secara terpisah. Sebuah paket dapat diklasifikasikan, dirutekan ulang ke antarmuka fisik, dan tetap membawa alamat privat yang tidak dapat dikembalikan oleh router hulu mana pun, yang menghasilkan timeout yang tampak persis seperti blokir firewall. Tidak ada dalam langkah klasifikasi yang memperingatkan Anda tentang itu. Tidak ada dalam langkah perutean juga.

Urutannya juga penting. Klasifikasi terjadi saat paket dibuat, perutean terjadi setelahnya, dan penerjemahan terjadi pada titik keluar.

Jika Anda tidak dapat menyebutkan tahap mana yang rusak, Anda tidak sedang melakukan debugging, Anda sedang menata ulang aturan dan berharap.

Cocokkan cgroup yang masih ada besok

nftables dapat menguji keanggotaan cgroup v2 sebuah soket, yang benar-benar berguna karena mengikuti prosesnya, bukan tujuannya. Masalahnya adalah pengenalnya. Aplikasi desktop yang diluncurkan dari menu sering berada dalam scope sementara yang namanya berubah pada peluncuran berikutnya.

nft list ruleset
systemctl status session.slice 2>/dev/null
cat /proc/self/cgroup

Menyalin nama scope dari satu sesi dan mengodekannya secara keras menghasilkan aturan yang berfungsi hari ini dan diam-diam berhenti cocok besok. Tempatkan aplikasi dalam konteks eksekusi yang stabil dan disengaja, seperti scope atau unit khusus yang Anda kendalikan, lalu cocokkan itu. Aturan tersebut kemudian bertahan melalui reboot dan pembaruan paket. Itu juga menjadi sesuatu yang dapat dipahami rekan kerja tanpa riwayat sesi Anda.

Juga berhati-hatilah tentang mekanisme mana yang Anda gunakan. Klasifikasi net_cls cgroup v1 dan pencocokan soket cgroup v2 adalah hal yang berbeda, dan bidang dengan nama serupa dalam dokumentasi tidak membuatnya dapat dipertukarkan.

Rantai route adalah yang memicu pencarian kedua

Untuk lalu lintas yang dihasilkan secara lokal, tipe chain menentukan apakah ada yang terjadi setelah tanda ditetapkan. Chain output bertipe filter dapat menandai paket dan kernel akan terus menggunakan rute yang sudah dipilihnya. Chain bertipe route adalah mekanisme yang meminta pencarian baru.

table inet bypass {
  chain mark {
    type route hook output priority mangle; policy accept;
    socket cgroupv2 level 2 "app.slice" meta mark set 0x1 comment "app bypass"
  }
}
ip rule add fwmark 0x1 lookup 200
ip route add default via 203.0.113.1 dev wlan0 table 200

Tanda tersebut kemudian memerlukan aturan kebijakan yang mengirimkannya ke tabel, dan tabel itu harus lengkap: rute default, tujuan lokal yang masih dibutuhkan aplikasi, dan gateway hulu yang benar-benar menjawab.

Pilih nilai tanda secara sengaja. WireGuard menggunakan fwmark-nya sendiri untuk lalu lintas transport luar, dan kebetulan memakai nomor yang sama dapat mengganggu pengecualian perutean terowongan itu sendiri dengan cara yang sulit didiagnosis.

Alamat sumber tidak mengikuti rute

Soket yang telah memilih alamat sumber untuk jalur terowongan tetap mempertahankan alamat itu setelah rute diubah. Tidak ada dalam perubahan rute yang menulis ulangnya, itulah sebabnya paket keluar dari antarmuka fisik dengan sumber privat yang tidak dapat dikembalikan oleh jaringan hulu.

Gejala yang terlihat adalah aplikasi yang tampaknya mengirim data dan tidak pernah menerima jawaban, dan log firewall yang tidak menunjukkan apa pun karena paketnya tidak pernah kembali.

Perbaikan sempitnya adalah aturan penerjemahan alamat sumber yang dibatasi pada tanda aplikasi itu dan antarmuka keluaran aslinya, diintegrasikan dengan NAT yang sudah ada, bukan menggantikannya:

table inet bypass {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    meta mark 0x1 oifname "wlan0" masquerade
  }
}

Terjemahkan pengecualian itu dan tidak yang lain. Aturan masquerade menyeluruh memperbaiki gejalanya dan menghancurkan kemampuan Anda untuk mengetahui lalu lintas mana yang mengambil jalur mana. Cocokkan pada tanda, antarmuka keluaran asli, dan jika bisa, alamat aplikasi itu sendiri. Aturan yang luas mudah ditulis dan hampir mustahil diaudit nanti.

Apa yang masih lolos dari pengecualian

Resolusi nama mungkin berasal dari proses resolver terpisah di cgroup yang berbeda, jadi mengklasifikasikan soket peramban tidak mengklasifikasikan pencariannya. Jika kueri resolver tetap di dalam terowongan sementara koneksinya keluar di luarnya, jawaban split-horizon dapat tidak cocok dengan jalurnya. Ketidakcocokan itu menghasilkan kegagalan yang tampak seperti bug DNS padahal bukan.

Proses anak mewarisi cgroup pada sebagian besar penyiapan, tetapi helper yang memindahkan dirinya ke scope sendiri tidak. Periksa daripada berasumsi, terutama untuk apa pun yang mengeksekusi ulang dirinya.

Terakhir, putuskan apa yang harus terjadi ketika terowongan mati. Pengecualian yang diam-diam menjadi bypass penuh adalah postur keamanan yang berbeda dari yang gagal tertutup, dan hanya salah satunya yang Anda maksud.

Artikel terkait