ipipou:不仅仅是一个未加密的隧道

我们对IPv6上帝怎么说?



IPv6? 今天不行


诚然,对于加密之神,今天我们也要说同样的话。



在这里,它将是关于未加密的IPv4隧道的,而不是关于“暖灯”的,而是关于现代的“ LED”的。然后原始套接字在闪烁,并且在用户空间中使用了软件包。



每种口味和颜色都有N种隧穿协议:



  • 时尚,新潮,年轻的WireGuard
  • 多功能,如瑞士刀,OpenVPN和SSH
  • 老而不是邪恶的GRE
  • 最简单,最快,未加密的IPIP
  • 积极开发GENEVE
  • 很多其他的。


但是我是一名程序员,所以我只会将N增加一小部分,而将真正协议的开发留给b开发人员。



我目前正在进行的另一个未出生的项目中,我需要从外部与NAT后面的主机联系。为此,使用带有成人密码学的协议,我从来没有离开过像炮弹一样的感觉。因为 隧道大部分只用于戳NAT-e中的一个漏洞,内部流量通常也被加密,但是它们却被HTTPS淹没了。



在研究各种隧道协议时,由于其最小的开销,我内心的完美主义者不断地将注意力转向IPIP。但这对我的任务有一个重大的缺点:



  • 它需要双方的公共IP,
  • 并且没有身份验证给您。


因此,完美主义者被赶回头骨的黑暗角落,或者他坐在那里的任何地方。



有一次,在阅读有关Linux本机支持的隧道的文章时,我遇到了FOU(UDP上的Foo),即用UDP包装。到目前为止,其他任何功能仅支持IPIP和GUE(通用UDP封装)。



“这是银子弹!我和一个简单的IPIP引起了人们的注意。”我想。



实际上,子弹并非完全是银色的。 UDP中的封装解决了第一个问题-您可以使用预先建立的连接从外部连接到NAT后面的客户端,但是IPIP下一个缺点的一半以崭新的面貌出现-私有网络中的任何人都可以隐藏在可见的公共IP和客户端端口(采用纯IPIP)没有问题)。



为了解决这个一个半问题,ipipou实用程序诞生了它实现了一种用于对远程主机进行身份验证的自制机制,同时又不会破坏强大的FOU的工作,该FOU将快速有效地处理内核空间中的数据包。



不需要您的脚本!



好的,如果您知道客户端的公用端口和IP(例如,您自己的公用端口和IP,无论它们走到哪里,NAT都会尝试将端口一对一映射),则可以使用以下命令创建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 -客户端的公共IP
  • 192.168.0.2 -客户端IP分配给eth0接口
  • 10001 -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)就是这样一件特殊的事情为业余爱好者谁不知道如何开发内核模块,它通过网络过滤手段(nftables / iptables的)允许您对网络数据包重定向到用户空间和处理它们有原始的简易方法:修改(可选)并交还给内核,或者丢弃。



对于某些编程语言,存在用于nfqueue的绑定,对于bash没有(嘿,不足为奇),我不得不使用python:ipipou使用NetfilterQueue



如果性能不是很关键,则借助此功能,您可以相对快速,轻松地烹饪自己的逻辑,以便在相当低的水平上处理数据包,例如,雕刻实验数据传输协议或以非标准行为拖曳本地和远程服务。



原始套接字与nfqueue协同工作,例如,当已经配置了隧道并且FOU正在侦听所需的端口时,它将无法以通常的方式从同一端口发送数据包-它很忙,但是您可以将随机生成的数据包直接发射并发射到网络中接口使用原始套接字,尽管您将不得不多花一些时间来生成这样的数据包。这是在ipipou中创建具有身份验证的数据包的方式。



由于ipipou仅处理来自连接的第一个数据包(嗯,那些在建立连接之前设法泄漏到队列中的数据包),因此性能几乎不会受到影响。



ipipou服务器收到经过身份验证的数据包后,便会立即创建一个隧道,并且内核中已绕过nfqueue处理了连接中的所有后续数据包。如果连接不良,则下一个第一个数据包将被发送到nfqueue队列,具体取决于设置。如果它不是身份验证数据包,但来自最后记住的IP和客户端端口,则可以继续传递或丢弃它。如果经过身份验证的数据包来自新的IP和端口,则将隧道重新配置为使用它们。



通常的IPIP-over-FOU在使用NAT时还有另一个问题-您无法创建两个封装在UDP中且具有相同IP的IPIP隧道,因为FOU和IPIP模块彼此之间非常隔离。那些。在一个公共IP后面的一对客户端将无法以这种方式同时连接到同一服务器。将来,它可能会在内核级别解决,但这还不确定。同时,可以通过NAT解决NAT问题-如果碰巧一对隧道已经占用了一对IP地址,ipipou将从公共NAT过渡到另一个私有IP,瞧! -您可以创建隧道,直到端口用完为止。



因为并非连接中的所有数据包都经过签名,因此这样的简单保护很容易受到MITM的攻击,因此,如果在侦听和控制流量的客户端和服务器之间潜伏着小人,他可以通过另一个地址重定向经过身份验证的数据包并从不受信任的主机创建隧道...



如果有人对如何解决此问题有任何想法,同时又将大量流量留在了核心,请不要犹豫-大声说出来。



顺便说一句,UDP封装非常有效。与IP封装相比,尽管增加了UDP报头开销,但它更加稳定并且通常更快。这是由于以下事实:Internet上的大多数主机仅使用三种最流行的协议即可正常工作:TCP,UDP,ICMP。可感知的部分通常可以丢弃其他所有内容,或者处理得更慢,因为仅针对这三个部分进行了优化。



因此,例如,基于创建HTTP / 3的QUICK是通过UDP而不是通过IP创建的。



好吧,足够多的话了,是时候看看它在“现实世界”中如何工作了。



战斗



用于模拟现实世界iperf3就与现实的接近程度而言,这与在《我的世界》中模拟现实世界大致相同,但目前可以。



比赛包括:

  • 参考主频道
  • 本文的英雄是ipipou
  • 具有身份验证但不加密的OpenVPN
  • OpenVPN全包
  • WireGuard不带PresharedKey,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"




ipipou



/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 (c , , UDP, )

openvpn-manage



wireguard



/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




对于20 Mbps



20 Mbps时的带宽比较



20 Mbps时延的比较



通道,对于1乐观Gbps通道



1 Gbps带宽比较



CPU效率比较:Mbps / CPU_usage



在所有情况下,ipipou的性能都与基本通道非常接近,这太棒了!



在两种情况下,未加密的openvpn隧道的行为都非常奇怪。



如果有人要测试它,听到反馈将很有趣。



愿IPv6和NetPrickle与我们同在!



All Articles