ipipou: lebih dari sekedar terowongan yang tidak terenkripsi

Apa yang kita katakan kepada Tuhan IPv6?

ipipou: lebih dari sekedar terowongan yang tidak terenkripsi
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:

  • bergaya, modis, awet muda WireGuard
  • multifungsi, seperti pisau Swiss, OpenVPN dan SSH
  • GRE tua dan tidak jahat
  • IPIP paling sederhana, cepat, dan sepenuhnya tidak terenkripsi
  • berkembang secara aktif JENEWA
  • banyak lainnya.

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", чтобы лишние пакеты не плодить и не портить производительность.

TCP

CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2; tail -1 "$CPULOG"

latensi ICMP

ping -c 10 SERVER_IP | tail -1

di server (berjalan bersamaan dengan klien):

UDP

CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"

TCP

CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"

Konfigurasi terowongan

ipipou
server
/etc/ipipou/server.conf:

server
number 0
fou-dev eth0
fou-local-port 10000
tunl-ip 172.28.0.0
auth-remote-pubkey-b64 eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-secret topsecret
auth-lifetime 3600
reply-on-auth-ok
verb 3

systemctl start ipipou@server

pelanggan
/etc/ipipou/client.conf:

client
number 0
fou-local @eth0
fou-remote SERVER_IP:10000
tunl-ip 172.28.0.1
# pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=
auth-secret topsecret
keepalive 27
verb 3

systemctl start ipipou@client

openvpn (tanpa enkripsi, dengan otentikasi)
server

openvpn --genkey --secret ovpn.key  # Затем надо передать ovpn.key клиенту
openvpn --dev tun1 --local SERVER_IP --port 2000 --ifconfig 172.16.17.1 172.16.17.2 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key

pelanggan

openvpn --dev tun1 --local LOCAL_IP --remote SERVER_IP --port 2000 --ifconfig 172.16.17.2 172.16.17.1 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key

openvpn (dengan enkripsi, otentikasi, melalui UDP, semuanya seperti yang diharapkan)
Dikonfigurasi menggunakan openvpn-kelola

penjaga kawat
server
/etc/wireguard/server.conf:

[Interface]
Address=172.31.192.1/18
ListenPort=51820
PrivateKey=aMAG31yjt85zsVC5hn5jMskuFdF8C/LFSRYnhRGSKUQ=
MTU=1440

[Peer]
PublicKey=LyhhEIjVQPVmr/sJNdSRqTjxibsfDZ15sDuhvAQ3hVM=
AllowedIPs=172.31.192.2/32

systemctl start wg-quick@server

pelanggan
/etc/wireguard/client.conf:

[Interface]
Address=172.31.192.2/18
PrivateKey=uCluH7q2Hip5lLRSsVHc38nGKUGpZIUwGO/7k+6Ye3I=
MTU=1440

[Peer]
PublicKey=DjJRmGvhl6DWuSf1fldxNRBvqa701c0Sc7OpRr4gPXk=
AllowedIPs=172.31.192.1/32
Endpoint=SERVER_IP:51820

systemctl start wg-quick@client

Temuan

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

ipipou: lebih dari sekedar terowongan yang tidak terenkripsi

ipipou: lebih dari sekedar terowongan yang tidak terenkripsi

saluran per 1 Gbps optimis

ipipou: lebih dari sekedar terowongan yang tidak terenkripsi

ipipou: lebih dari sekedar terowongan yang tidak terenkripsi

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.

Semoga IPv6 dan NetPrickle menyertai kita!

Sumber: www.habr.com

Tambah komentar