我們要對 IPv6 之神說什麼?
是的,我們今天也對加密之神說同樣的話。
在這裡,我們將討論未加密的 IPv4 隧道,但不是「暖燈」隧道,而是現代「LED」隧道。 這裡還有閃爍的原始套接字,並且正在處理用戶空間中的資料包。
每種口味和顏色都有 N 種隧道協定:
但我是一名程式設計師,所以我只會將N增加一小部分,並將真正協議的開發留給Kommersant開發人員。
在一個未出生的
在研究各種隧道協定時,我內心的完美主義者的注意力一次又一次地被 IPIP 吸引,因為它的開銷最小。 但對於我的任務來說,它有一個半明顯的缺點:
- 它需要雙方的公共IP,
- 並且沒有對您進行身份驗證。
因此,完美主義者被趕回了頭骨的黑暗角落,或者他坐在那裡的任何地方。
然後有一天,當我閱讀有關的文章時
「這就是銀彈! 一個簡單的 IPIP 對我來說就足夠了。” - 我想。
事實上,子彈並不是完全銀色的。 UDP 封裝解決了第一個問題- 您可以使用預先建立的連接從外部連接到NAT 後面的客戶端,但是IPIP 的下一個缺點的一半在這裡以新的方式展現- 來自專用網路的任何人都可以隱藏在可見的後面公共IP和客戶端連接埠(在純IPIP中不存在此問題)。
為了解決這個半問題,實用程式誕生了
我們不需要你的劇本!
好的,如果您知道客戶端的公共連接埠和 IP(例如,它後面的每個人都不會去任何地方,NAT 嘗試映射連接埠 1-in-1),您可以使用以下命令建立 IPIP-over-FOU 隧道遵循命令,無需任何腳本。
在伺服器上:
# Подгрузить модуль ядра 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
在客戶端:
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
哪裡
ipipou*
— 本機隧道網路介面的名稱203.0.113.1
— 公用IP伺服器198.51.100.2
— 用戶端的公共IP192.168.0.2
— 指派給介面 eth0 的客戶端 IP10001
— FOU 的本機用戶端端口20001
— FOU 的公共用戶端端口10000
— FOU 的公共伺服器端口encap-csum
— 在封裝的 UDP 封包中新增 UDP 校驗和的選項; 可以替換為noencap-csum
更不用說,完整性已經由外部封裝層控制(當資料包位於隧道內部時)eth0
— ipip 隧道將綁定到的本地接口172.28.0.1
— 用戶端隧道介面的 IP(私有)172.28.0.0
— IP 隧道伺服器介面(專用)
只要 UDP 連線處於活動狀態,隧道就會處於工作狀態,但如果它中斷,您會很幸運 - 如果客戶端的 IP:連接埠保持不變 - 它將繼續存在,如果它們發生變化 - 它將中斷。
恢復一切最簡單的方法是卸載核心模組: modprobe -r fou ipip
即使不需要身份驗證,客戶端的公共 IP 和連接埠也並不總是已知,並且通常是不可預測的或可變的(取決於 NAT 類型)。 如果你省略 encap-dport
在伺服器端,隧道將不起作用,它不夠智能,無法佔用遠端連線連接埠。 在這種情況下,ipipou 也可以提供幫助,或者 WireGuard 和其他類似的工具可以幫助您。
它是如何工作的呢?
用戶端(通常位於 NAT 之後)開啟隧道(如上例所示),並向伺服器發送身份驗證封包,以便伺服器在其一側配置隧道。 根據設置,這可以是一個空資料包(只是為了讓伺服器可以看到公共 IP:連接埠),也可以是包含伺服器可以識別客戶端的資料。 資料可以是明文形式的簡單密碼(類似 HTTP Basic Auth),也可以是用私鑰簽署的專門設計的資料(類似 HTTP Digest Auth,只是更強,請參閱函數 client_auth
在代碼中)。
在伺服器(具有公共IP 的一側)上,當ipipou 啟動時,它會建立一個nfqueue 佇列處理程序並配置netfilter,以便將必要的封包傳送到它們應該傳送到的位置:初始化與nfqueue 佇列的連接的資料包,以及[幾乎]其餘的都直接發送給聽眾 FOU。
對於那些不了解的人來說,nfqueue(或NetfilterQueue)對於不知道如何開發核心模組的業餘愛好者來說是一個特殊的東西,它使用netfilter(nftables/iptables)允許您將網路封包重定向到使用者空間並在那裡處理它們原始的意思是:修改(可選)並將其傳回給內核,或丟棄它。
對於某些程式語言,有與 nfqueue 一起使用的綁定,對於 bash 則沒有(呵呵,這並不奇怪),我不得不使用 python:ipipou 使用
如果性能並不重要,那麼使用這個東西,您可以相對快速且輕鬆地構建自己的邏輯,以在相當低的級別上處理數據包,例如,創建實驗性數據傳輸協議,或以非標準行為控製本地和遠端服務。
原始套接字與 nfqueue 協同工作,例如,當隧道已配置並且 FOU 正在偵聽所需連接埠時,您將無法以通常的方式從相同連接埠發送資料包 - 它很忙,但是您可以使用原始套接字直接將隨機產生的資料包發送到網路接口,儘管產生這樣的資料包需要更多的修改。 這就是在 ipipou 中建立帶有身份驗證的資料包的方式。
由於 ipipou 僅處理來自連接的第一個資料包(以及在建立連接之前設法洩漏到佇列中的資料包),因此效能幾乎不會受到影響。
一旦 ipipou 伺服器收到經過驗證的封包,就會建立隧道,並且連接中的所有後續封包都已由核心繞過 nfqueue 進行處理。 如果連接失敗,那麼下一個的第一個資料包將發送到 nfqueue 佇列,根據設置,如果不是帶有身份驗證的資料包,而是從最後記住的 IP 和客戶端連接埠開始,則可以透過開啟或丟棄。 如果經過驗證的封包來自新的 IP 和端口,則會重新配置隧道以使用它們。
通常的 IPIP-over-FOU 在使用 NAT 時還有一個問題 - 不可能創建兩個封裝在具有相同 IP 的 UDP 中的 IPIP 隧道,因為 FOU 和 IPIP 模組彼此完全隔離。 那些。 透過這種方式,同一公用 IP 後面的一對客戶端將無法同時連接到同一台伺服器。 在未來,
因為並非連接中的所有資料包都經過簽名,那麼這種簡單的保護很容易受到MITM 的攻擊,因此,如果客戶端和伺服器之間的路徑上潛伏著一個可以偵聽流量並操縱流量的惡棍,他可以透過以下方式重新導向經過驗證的封包:另一個位址並從不受信任的主機建立隧道。
如果有人對如何解決此問題同時將大部分流量留在核心中的想法有任何想法,請毫不猶豫地說出來。
順便說一下,UDP 封裝已經很好地證明了自己。 與 IP 封裝相比,儘管 UDP 標頭有額外的開銷,但它更加穩定且更快。 這是因為 Internet 上的大多數主機只能使用三種最受歡迎的協定才能正常運作:TCP、UDP、ICMP。 有形部分可以完全丟棄其他所有內容,或者更慢地處理它,因為它只針對這三者進行了最佳化。
例如,這就是為什麼 HTTP/3 所基於的 QUICK 是在 UDP 之上創建的,而不是在 IP 之上創建的。
好了,話夠多了,是時候看看它在「現實世界」中是如何運作的了。
戰鬥
用於模擬現實世界 iperf3
。 就接近現實的程度而言,這與《我的世界》中模擬現實世界大致相同,但目前來說就可以了。
比賽參加者:
- 參考主通路
- 本文的主角是 ipipou
- OpenVPN 具有身份驗證但不加密
- OpenVPN全包模式
- 不含 PresharedKey 的 WireGuard,MTU=1440(因為僅限 IPv4)
極客技術數據
使用以下命令取得指標:
在客戶端:
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"
ICMP 延遲
ping -c 10 SERVER_IP | tail -1
在伺服器上(與客戶端同時運行):
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"
隧道配置
伊皮普
服務器
/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
顧客
/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(無加密,有驗證)
服務器
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
顧客
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(加密、驗證、透過 UDP,一切如預期)
配置使用
線衛
服務器
/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
顧客
/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
Результаты
潮濕醜陋的標誌
伺服器 CPU 負載不是很有指示性,因為... 還有許多其他服務在那裡運行,有時它們會消耗資源:
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
20Mbps頻道
每 1 樂觀 Gbps 的通道
在所有情況下,ipipou 的性能都非常接近基本通道,這非常棒!
在這兩種情況下,未加密的 openvpn 隧道的行為都非常奇怪。
如果有人要測試它,聽到回饋將會很有趣。
願 IPv6 和 NetPrickle 與我們同在!
來源: www.habr.com