Menyematkan satu program ke VPN di Linux terutama adalah masalah perutean, dan aturan firewall hanya memutuskan apa yang terjadi setelah rute dipilih. Jika Anda mencocokkan UID program di OUTPUT sebelum terowongan memiliki rute default, aturan itu justru menjatuhkan lalu lintas yang ingin Anda lindungi. Aturan yang sama juga tidak melihat proses resolver yang menjawab kueri DNS program. Urutkan dengan benar dan satu akun tanpa hak istimewa menjadi pemilih terowongan terpisah yang andal.

Beri akun rute sebelum putusan

Pencocokan pemilik menjawab satu pertanyaan: apakah soket lokal milik UID ini yang membangun paket? Ia tidak memilih antarmuka dan tidak dapat memindahkan lalu lintas yang sudah dikirim tabel utama lewat NIC fisik. Karena itu aturan UID tanpa rute yang cocok memblokir program alih-alih mengalihkannya.

Kirim akun melewati tabelnya sendiri lebih dulu, lalu biarkan firewall mengonfirmasi hasilnya. Ini bekerja pada host yang iproute2-nya memahami uidrange, yang ip rule help laporkan dalam satu baris. Tabel 100 menyimpan rute default lewat terowongan, dan aturan hanya mengirim UID 1000 ke tabel itu. Semua yang lain tetap di tabel utama dan terus memakai tautan fisik.

ip rule add uidrange 1000-1000 table 100
ip route add default dev tun0 table 100

Akun kedua yang membutuhkan terowongan lain mendapat tabel 101 dan aturannya sendiri, karena dua profil tidak bisa sama-sama memiliki rute default di tabel yang sama. Profil NetworkManager bersifat seluruh sistem, jadi bagian ini tetap manual, dan aturannya hilang saat reboot kecuali ada yang memulihkannya. Tulis tabel ke skrip boot di samping definisi terowongan agar penyambungan ulang tidak meninggalkan satu akun di jalur yang salah.

Mengapa pengecualian loopback membunuh terowongan

Sebagian besar versi aturan yang disalin menjatuhkan setiap paket yang tidak keluar lewat loopback. Terowongan bukan loopback, jadi bentuk itu juga menjatuhkan lalu lintas terowongan, dan hasilnya tampak seperti VPN mati, bukan kesalahan firewall.

Saat OUTPUT berjalan, kernel sudah memilih antarmuka keluar, jadi -o dibandingkan dengan jawaban rute, bukan dengan header paket. Pencocokan pemilik hanya diperiksa di OUTPUT dan POSTROUTING, dan paket yang diteruskan tidak membawa soket untuk dibacanya. Kombinasi itu berarti pengecualian harus menyebut antarmuka terowongan dan menegasikan pencocokan tersebut, bukan menegasikan loopback.

Loopback tetap berhak atas ACCEPT sendiri di atas DROP, karena paket DNS pertama dari program menuju stub lokal lewat lo. Letakkan kedua aturan dalam urutan ini dan akun mencapai stub, lalu terowongan, dan tidak ke mana pun lagi.

iptables -I OUTPUT 1 -o lo -m owner --uid-owner vpnapp -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner vpnapp ! -o tun0 -j DROP

IPv6 adalah kumpulan aturan terpisah, dan pasangan khusus v4 membiarkan ip6tables tidak tersentuh. Program yang memilih record AAAA kemudian akan keluar lewat tautan fisik tanpa pernah mencapai DROP. Cerminkan kedua aturan di ip6tables, atau nonaktifkan IPv6 pada host ketika terowongan tidak membawa alamat v6. Aturan yang ditambahkan dengan tangan juga hilang saat reboot, jadi simpan dengan netfilter-persistent save atau bangun ulang logika yang sama sebagai tabel nftables yang dimuat unit boot.

Jawaban DNS datang dari proses lain

Kueri program ke 127.0.0.53 melewati ACCEPT loopback, dan di situlah pencocokan UID berhenti. Resolver stub meneruskan ke atas dari akun layanannya sendiri, jadi aturan yang dikunci ke vpnapp tidak pernah melihat kueri kedua. Jika resolver memilih server LAN untuk tautan, jawaban kembali lewat NIC fisik sementara paket program sendiri tetap di terowongan. Hasil yang terlihat adalah terowongan yang berfungsi dengan nama rusak, atau nama yang dijawab server yang tidak Anda pilih.

Perbaiki resolusi nama pada tautan terowongan, bukan pada aplikasi. Beri profil terowongan server DNS dan domain perutean, lalu konfirmasi dengan resolvectl query dan resolvectl status tun0 bahwa resolver memakainya untuk nama yang penting. Di dalam ruang nama jaringan masalahnya hilang, karena resolver ruang nama hanya mengenal terowongan.

Periksa aturan dari akun itu sendiri

Tanyakan ke kernel rute apa yang didapat UID, lalu buat permintaan sebagai akun itu dan bandingkan alamat keluar dengan alamat akun Anda sendiri. Jika keduanya melaporkan alamat yang sama, aturan itu mencocokkan sesuatu selain lalu lintas yang Anda uji. Perintah pertama di bawah menunjukkan pencarian rute tanpa mengirim paket, yang memisahkan kesalahan perutean dari kesalahan firewall.

ip route get 1.1.1.1 uid 1000
sudo -u vpnapp curl -s https://ifconfig.co

Penghitung menunjukkan apakah sebuah aturan pernah terpicu. Jalankan iptables -vnL OUTPUT, baca jumlah paket di samping setiap aturan, dan anggap nol di samping DROP setelah lalu lintas nyata sebagai kesalahan pencocokan.

Lalu lintas yang diteruskan berada di luar desain ini. Kontainer atau VM di belakang jembatan tidak memiliki soket lokal milik vpnapp, jadi pencocokan pemilik tidak pernah terpicu dan paket itu mengikuti kebijakan FORWARD. Jika beban kerja itu harus dicakup, uji terpisah dan tulis kebijakan yang dikunci ke jembatan atau alamat kontainer. Desain bertahan ketika tabel, pengecualian antarmuka, resolver, dan aturan v6 semuanya menunjuk arah yang sama; lewati salah satunya dan akun bocor atau kehilangan konektivitas.

Artikel terkait