ipipou: lebih dari sekedar terowongan yang tidak terenkripsi
Apa yang kita katakan kepada Tuhan IPv6?
Benar sekali, hari ini kami akan mengatakan hal yang sama kepada dewa enkripsi.
Di sini kita akan berbicara tentang terowongan IPv4 yang tidak terenkripsi, tetapi bukan tentang “lampu hangat”, tetapi tentang “LED” modern. Dan ada juga soket mentah yang berkedip di sini, dan pekerjaan sedang dilakukan dengan paket-paket di ruang pengguna.
Ada N protokol tunneling untuk setiap selera dan warna:
Tapi saya seorang programmer, jadi saya akan meningkatkan N hanya sedikit, dan menyerahkan pengembangan protokol sebenarnya kepada pengembang Kommersant.
Dalam satu yang belum lahir proyekApa yang saya lakukan sekarang adalah menjangkau host di belakang NAT dari luar. Menggunakan protokol dengan kriptografi dewasa untuk ini, saya tidak dapat menghilangkan perasaan bahwa ini seperti menembakkan burung pipit dari meriam. Karena terowongan ini sebagian besar digunakan hanya untuk menyodok lubang di NAT-e, lalu lintas internal biasanya juga dienkripsi, tetapi masih tenggelam dalam HTTPS.
Saat meneliti berbagai protokol tunneling, perhatian perfeksionis saya tertuju pada IPIP berulang kali karena overhead minimalnya. Namun ia memiliki satu setengah kelemahan signifikan untuk tugas saya:
itu membutuhkan IP publik di kedua sisi,
dan tidak ada otentikasi untuk Anda.
Oleh karena itu, orang perfeksionis didorong kembali ke sudut gelap tengkorak, atau dimanapun dia duduk di sana.
Dan suatu hari, saat membaca artikel tentang terowongan yang didukung secara asli di Linux saya menemukan FOU (Foo-over-UDP), mis. terserah, dibungkus dengan UDP. Sejauh ini, hanya IPIP dan GUE (Generic UDP Encapsulation) yang didukung.
“Inilah solusi terbaiknya! IPIP sederhana sudah cukup bagi saya.” - Saya pikir.
Ternyata pelurunya tidak sepenuhnya berwarna perak. Enkapsulasi dalam UDP memecahkan masalah pertama - Anda dapat terhubung ke klien di belakang NAT dari luar menggunakan koneksi yang sudah ada sebelumnya, tetapi di sini setengah dari kelemahan IPIP berikutnya berkembang dalam cahaya baru - di balik IP publik yang terlihat dan port klien siapa pun dari jaringan pribadi dapat bersembunyi (dalam IPIP murni, masalah ini tidak ada).
Untuk mengatasi masalah satu setengah ini, lahirlah utilitas ipipou. Ini mengimplementasikan mekanisme buatan sendiri untuk mengautentikasi host jarak jauh, tanpa mengganggu pengoperasian FOU kernel, yang akan memproses paket di ruang kernel dengan cepat dan efisien.
Kami tidak membutuhkan naskahmu!
Oke, jika Anda mengetahui port publik dan IP klien (misalnya, semua orang di belakangnya tidak pergi ke mana pun, NAT mencoba memetakan port 1-in-1), Anda dapat membuat terowongan IPIP-over-FOU dengan perintah berikut, tanpa skrip apa pun.
di server:
# Подгрузить модуль ядра FOU
modprobe fou
# Создать IPIP туннель с инкапсуляцией в FOU.
# Модуль ipip подгрузится автоматически.
ip link add name ipipou0 type ipip
remote 198.51.100.2 local 203.0.113.1
encap fou encap-sport 10000 encap-dport 20001
mode ipip dev eth0
# Добавить порт на котором будет слушать FOU для этого туннеля
ip fou add port 10000 ipproto 4 local 203.0.113.1 dev eth0
# Назначить IP адрес туннелю
ip address add 172.28.0.0 peer 172.28.0.1 dev ipipou0
# Поднять туннель
ip link set ipipou0 up
pada klien:
modprobe fou
ip link add name ipipou1 type ipip
remote 203.0.113.1 local 192.168.0.2
encap fou encap-sport 10001 encap-dport 10000 encap-csum
mode ipip dev eth0
# Опции local, peer, peer_port, dev могут не поддерживаться старыми ядрами, можно их опустить.
# peer и peer_port используются для создания соединения сразу при создании FOU-listener-а.
ip fou add port 10001 ipproto 4 local 192.168.0.2 peer 203.0.113.1 peer_port 10000 dev eth0
ip address add 172.28.0.1 peer 172.28.0.0 dev ipipou1
ip link set ipipou1 up
dimana
ipipou* — nama antarmuka jaringan terowongan lokal
203.0.113.1 — server IP publik
198.51.100.2 — IP publik klien
192.168.0.2 — IP klien ditetapkan ke antarmuka eth0
10001 — port klien lokal untuk FOU
20001 — port klien publik untuk FOU
10000 — port server publik untuk FOU
encap-csum — opsi untuk menambahkan checksum UDP ke paket UDP yang dienkapsulasi; dapat digantikan oleh noencap-csum, belum lagi, integritas sudah dikontrol oleh lapisan enkapsulasi luar (saat paket berada di dalam terowongan)
eth0 — antarmuka lokal tempat terowongan ipip akan diikat
172.28.0.1 — IP antarmuka terowongan klien (pribadi)
172.28.0.0 — Antarmuka server terowongan IP (pribadi)
Selama koneksi UDP masih hidup, terowongan akan berfungsi dengan baik, tetapi jika rusak, Anda akan beruntung - jika IP klien: port tetap sama - port akan hidup, jika diubah - port akan rusak.
Cara termudah untuk mengembalikan semuanya adalah dengan membongkar modul kernel: modprobe -r fou ipip
Bahkan jika otentikasi tidak diperlukan, IP dan port publik klien tidak selalu diketahui dan sering kali tidak dapat diprediksi atau bervariasi (tergantung pada jenis NAT). Jika Anda menghilangkan encap-dport di sisi server, terowongan tidak akan berfungsi, tidak cukup pintar untuk mengambil port koneksi jarak jauh. Dalam hal ini, ipipou juga dapat membantu, atau WireGuard dan sejenisnya dapat membantu Anda.
Bagaimana cara kerjanya?
Klien (yang biasanya berada di belakang NAT) membuka terowongan (seperti pada contoh di atas), dan mengirimkan paket otentikasi ke server sehingga mengkonfigurasi terowongan di sisinya. Tergantung pada pengaturannya, ini bisa berupa paket kosong (hanya agar server dapat melihat IP publik: port koneksi), atau dengan data yang dapat digunakan server untuk mengidentifikasi klien. Data dapat berupa frasa sandi sederhana dalam teks yang jelas (analogi dengan HTTP Basic Auth terlintas dalam pikiran) atau data yang dirancang khusus yang ditandatangani dengan kunci pribadi (mirip dengan HTTP Digest Auth hanya saja lebih kuat, lihat fungsinya client_auth dalam kode).
Di server (sisi dengan IP publik), ketika ipipou dimulai, ia membuat penangan antrian nfqueue dan mengkonfigurasi netfilter sehingga paket yang diperlukan dikirim ke tempat yang seharusnya: paket yang menginisialisasi koneksi ke antrian nfqueue, dan [hampir] sisanya langsung ke FOU pendengar.
Bagi yang belum tahu, nfqueue (atau NetfilterQueue) adalah hal khusus bagi amatir yang tidak tahu cara mengembangkan modul kernel, yang menggunakan netfilter (nftables/iptables) memungkinkan Anda mengarahkan paket jaringan ke ruang pengguna dan memprosesnya di sana menggunakan cara primitif yang ada: memodifikasi (opsional) dan mengembalikannya ke kernel, atau membuangnya.
Untuk beberapa bahasa pemrograman ada binding untuk bekerja dengan nfqueue, untuk bash tidak ada (heh, tidak mengherankan), saya harus menggunakan python: ipipou menggunakan Antrian Netfilter.
Jika kinerja tidak penting, dengan menggunakan hal ini Anda dapat dengan relatif cepat dan mudah menyusun logika Anda sendiri untuk bekerja dengan paket pada tingkat yang cukup rendah, misalnya, membuat protokol transfer data eksperimental, atau mengendalikan layanan lokal dan jarak jauh dengan perilaku non-standar.
Soket mentah bekerja sama dengan nfqueue, misalnya, ketika terowongan sudah dikonfigurasi dan FOU mendengarkan port yang diinginkan, Anda tidak akan dapat mengirim paket dari port yang sama dengan cara biasa - sibuk, tapi Anda dapat mengambil dan mengirim paket yang dibuat secara acak langsung ke antarmuka jaringan menggunakan soket mentah, meskipun membuat paket seperti itu memerlukan sedikit penyesuaian. Ini adalah bagaimana paket dengan otentikasi dibuat di ipipou.
Karena ipipou hanya memproses paket pertama dari koneksi (dan paket yang berhasil masuk ke antrian sebelum koneksi dibuat), kinerjanya hampir tidak menurun.
Segera setelah server ipipou menerima paket yang diautentikasi, sebuah terowongan dibuat dan semua paket berikutnya dalam koneksi sudah diproses oleh kernel yang melewati nfqueue. Jika koneksi gagal, maka paket pertama dari paket berikutnya akan dikirim ke antrian nfqueue, tergantung pada pengaturannya, jika itu bukan paket dengan otentikasi, tetapi dari IP dan port klien yang terakhir diingat, maka dapat diteruskan aktif atau dibuang. Jika paket yang diautentikasi berasal dari IP dan port baru, terowongan akan dikonfigurasi ulang untuk menggunakannya.
IPIP-over-FOU biasa memiliki masalah lain saat bekerja dengan NAT - tidak mungkin membuat dua terowongan IPIP yang dienkapsulasi dalam UDP dengan IP yang sama, karena modul FOU dan IPIP cukup terisolasi satu sama lain. Itu. sepasang klien di belakang IP publik yang sama tidak akan dapat terhubung secara bersamaan ke server yang sama dengan cara ini. Di masa depan, mungkin, ini akan diselesaikan di tingkat kernel, tetapi ini belum pasti. Sementara itu, masalah NAT dapat diselesaikan dengan NAT - jika kebetulan sepasang alamat IP sudah ditempati oleh terowongan lain, ipipou akan melakukan NAT dari IP publik ke IP privat alternatif, voila! - Anda dapat membuat terowongan hingga port habis.
Karena Tidak semua paket dalam koneksi ditandatangani, maka perlindungan sederhana ini rentan terhadap MITM, jadi jika ada penjahat yang mengintai di jalur antara klien dan server yang dapat mendengarkan lalu lintas dan memanipulasinya, dia dapat mengarahkan ulang paket yang diautentikasi melalui alamat lain dan buat terowongan dari host yang tidak tepercaya.
Jika ada yang punya ide tentang cara memperbaikinya sambil tetap menyisakan sebagian besar lalu lintas di inti, jangan ragu untuk angkat bicara.
Omong-omong, enkapsulasi dalam UDP telah terbukti sangat baik. Dibandingkan dengan enkapsulasi melalui IP, ini jauh lebih stabil dan seringkali lebih cepat meskipun ada tambahan overhead dari header UDP. Hal ini disebabkan oleh kenyataan bahwa sebagian besar host di Internet hanya bekerja dengan baik dengan tiga protokol paling populer: TCP, UDP, ICMP. Bagian yang berwujud dapat sepenuhnya membuang yang lainnya, atau memprosesnya lebih lambat, karena dioptimalkan hanya untuk ketiga hal tersebut.
Misalnya, inilah mengapa QUICK, yang menjadi dasar HTTP/3, dibuat di atas UDP, dan bukan di atas IP.
Cukup kata-kata, sekarang saatnya untuk melihat cara kerjanya di “dunia nyata”.
Pertarungan
Digunakan untuk meniru dunia nyata iperf3. Dalam hal tingkat kedekatan dengan kenyataan, ini kira-kira sama dengan meniru dunia nyata di Minecraft, tetapi untuk saat ini sudah cukup.
Peserta kompetisi:
referensi saluran utama
pahlawan artikel ini adalah ipipou
OpenVPN dengan otentikasi tetapi tanpa enkripsi
OpenVPN dalam mode semua-inklusif
WireGuard tanpa PresharedKey, dengan MTU=1440 (karena hanya IPv4)
Data teknis untuk Geeks Metrik diambil dengan perintah berikut:
pada klien:
UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2 -u -b 12M; tail -1 "$CPULOG"
# Где "-b 12M" это пропускная способность основного канала, делённая на число потоков "-P", чтобы лишние пакеты не плодить и не портить производительность.
Tanda jelek dan lembab
Beban CPU server tidak terlalu indikatif, karena... Ada banyak layanan lain yang berjalan di sana, terkadang menghabiskan sumber daya:
proto bandwidth[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps канал с микрокомпьютера (4 core) до VPS (1 core) через Атлантику
# pure
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latency min/avg/max/mdev = 198.838/198.997/199.360/0.372 ms
# ipipou
UDP 19.8 98.45 99.47
TCP 18.8 99.56 96.75
ICMP latency min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (auth only, no encryption)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latency min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (full encryption, auth, etc)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latency min/avg/max/mdev = 202.168/202.377/202.900/0.451 ms
# wireguard
UDP 19.3 91.60 94.78
TCP 17.2 96.76 92.87
ICMP latency min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms
## около-1Gbps канал между VPS Европы и США (1 core)
# pure
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latency min/avg/max/mdev = 106.867/106.994/107.126/0.066 ms
# ipipou
UDP 714 63.10 23.53
TCP 431 95.65 64.56
ICMP latency min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (auth only, no encryption)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latency min/avg/max/mdev = 107.191/107.334/107.559/0.116 ms
# wireguard
UDP 629 22.26 2.62
TCP 198 77.40 55.98
ICMP latency min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms
saluran 20Mbps
saluran per 1 Gbps optimis
Dalam semua kasus, kinerja ipipou cukup dekat dengan saluran dasar, dan itu luar biasa!
Terowongan openvpn yang tidak terenkripsi berperilaku cukup aneh dalam kedua kasus tersebut.
Jika ada yang akan mengujinya, akan menarik untuk mendengar tanggapannya.