前天晚上在家中,当我搭起熟悉的 ss
梯子时, 发现不可用了 T.T。登陆到控制台查看,发现国内的 IP 被 Block 了。问问身边朋友,也是一样的现象,听说是因为网络安全周?!看来只能寄希望于一周后能恢复吧 ….
昨天瞎逛,看到一个开源项目:udp2raw-tunnel,他实现的是将一个 IP 报文伪装成 TCP 报文,目的是穿过网络中 UDP 防火墙.
哈?!这难道是TCP-In-TCP
?这玩意儿不是不可用吗?
很早以前就有人说过了:
Why TCP Over TCP Is A Bad Idea
为了将问题描述地更清楚,我还是将隧道应用的组网画出来吧:
图中主机 A 和主机 D 通过隧道进行 End to End 的通信,而设备 B 对原始报文进行加密和封装,设备 C 做解封装和解密。当然 B 和 C 不一定是单独的设备,它们可以就集成在主机 A 和主机 D 中。
TCP-In-TCP
的问题是: 当隧道报文在网络中丢失时,B 上的 TCP 连接 <B-C> 显然会对报文进行重传,但要知道 A 上也有一个 TCP 连接<A-D>,所以 A 如果超时也会进行重传,而从整个网络的角度,这个重传是不必要的。但 A 不会理会,因为它是 TCP。
TCP 的设计原则是 下层协议和介质是不可靠的,所以我需要自己保证 。所以, TCP-In-TCP
这样的双保险完全是没有必要的。不仅没必要,还有可能造成网络中重传报文过多而拥塞。
不过也有研究说 TCP-In-TCP
在一定条件下可以提高网络的有效吞吐率:
论文在此 Understanding TCP over TCP: Effects of TCP Tunneling on End-to-End Throughput and Latency
还是差不多的拓扑:
论文中将传播延时 (propagation delay) 考虑进来了, 得出的结论是当 Ta 和 Tb 都比较大时,使用 TCP-In-TCP
隧道反而比不使用的有效吞吐量更大。为什么呢?原因也比较好解释:当 Ta 和 Tb 比较大时,显然在 A 视角里的 TCP 连接 <A-D> 的 RTT 会比 B 视角里的 <B-D> 大不少,那么如果隧道报文在网络中丢了,B 重传隧道报文,而 A 由于超时时间还没到,就不会重传原始报文。而如果不使用隧道,那么重传的任务就还是 A 的,显然 B 重传报文的传播延时要比 A 重传的大。
看上去有些道理,不过当网络条件实在不好,A 的超时时间也到达后,就还是会回到之前更糟糕的情况 ….
所以我还是认为 TCP-In-TCP
不是一个好主意..
那么, 本文开头提到的那个开源项目是怎么回事呢?仔细看了看它的介绍,又下载了它的代码。噢,原来它真的只是 伪装 成了 TCP 报文,实际上隧道报文的外层 TCP 封装都是在用户态自己填充的 TCP 首部,然后通过 raw socket
发送;而在接收端,同样使用 raw socket
(关于这个,详见我们忽略的 Socket 参数),所以报文会提前进入raw_local_deliver
上送,而不会由 TCP 去接收,这样也就没有了 TCP 状态机那一大堆复杂的东西。