# TCP/IP、《关于TCP/IP协议伪造和丢弃ACK为TCP-in-TCP隧道提速的技术原理》

此技术最早应用于linker项目。源码参考

灵感来自于2025年8月27日,真是个好日子,我的生日。

在仔细对比了TCP协议后,进行了代码实现。于2025年8月29日,也是个好日子,七夕,大概下午吧,iperf3测试从15-20Mbps上升到了家庭带宽上限。

但我认为这100%属于一种hack方法,并不主流,也不符合网络协议标准,这破坏了TCP标准通信流程。所以,如果你能使用UDP隧道,那使用UDP是最好的办法。如果你有不得不使用TCP隧道的理由,又遇到了跟本文的一样的问题,那不妨一试。

接下来我会尽可能详细、完整的描述这一技术原理。

1、条件背景

  1. A、B连个远程设备之间使用tun虚拟网卡构建异地局域网,A 虚拟ip 10.18.18.A、B虚拟ip10.18.18.B
  2. A、B之间使用TCP隧道连接,服务器中转,服务器带宽500Mbps,A、B两边最小上传带宽50Mbps
  3. A、B使用TCP通信,比如访问网页,或其它基于TCP协议的服务
  4. 完整通信过程:tun(10.18.18.A)<—->socketA<—->服务器(socket1<–>socket2)<—->socketB<—->tun(10.18.18.B),从A网卡读取数据包通过socketA发往服务器socket1,服务器socket1收到数据通过socket2发往socketB,socketB收到数据后写入网卡B,完成一次数据发送,反之亦然

2、实际问题

在实际通信中,无论使用打洞隧道还是服务器中转隧道

  1. HTTP下载文件大多数时候都是远远达不到上传带宽峰值,仅有时候可以(应该是“捎带确认”的优化机制的原因)
  2. iperf3则无论如何都无法达到上传峰值,大概速率为10-20Mbps之间波动,同样的隧道,直接发送数据或使用端口转发方式通信时速率正常

3、表现猜测

经过Wireshark抓包,物理网卡上,隧道没有丢包,没有双重确认等问题。虚拟网卡上,窗口非常小。在仔细分析整个通信过程后,觉得伪造和丢弃ACK数据包非常的可行。

完整链路:(tun(10.18.18.A)<—->socketA<—->服务器(socket1<–>socket2)<—->socketB<—->tun(10.18.18.B)

  1. 默认情况下,A到B发送一个PSH+ACK数据包,将有以下过程
    • socketA–PSH+ACK–>socket1,socket1–ACK–>socketA
    • socket2--PSH+ACK–>socketB,socketB–ACK–>socket2
    • PSH+ACK到达B网卡后,B网卡会回复一条ACK,当然在隧道里被包装为PSH+ACK
    • socketB–PSH+ACK(ACK)–>socket2,socket2–ACK–>socketB
    • socket1–PSH+ACK(ACK)–>socketA,socketA–ACK–>socket1
  2. 如果丢弃回复的ACK,那A到B发送一个PSH+ACK数据包,将有以下过程
    • socketA–PSH+ACK–>socket1,socket1–ACK–>socketA
    • socket2--PSH+ACK–>socketB,socketB–ACK–>socket2

4、优化原理

有几个前提

  1. ACK包的序列号可以使用SYN+ACK的序列号+1得到
  2. ACK包的确认号为要确认的包的 序列号+荷载长度
  3. ACK包需要计算校验和,没有荷载数据

最大的挑战是,如何在不影响正常的TCP握手和挥手以及无需复杂的状态管理的情况下丢弃ACK包,以一个完整TCP连接流程为例

  1. A–>SYN–>B
  2. B–>SYN+ACK–>A,在B、A分别取出SYN+ACK包的序列号+1,得到新序列号,用四元组记录状态
    • B、(源IP,源端口,目标IP,目标端口):(新序列号丢包=true)
    • A、(源IP,源端口,目标IP,目标端口):(新序列号丢包=false),A还要给B回复一个ACK,先不丢包
  3. A–>ACK–>B,检查状态,发现丢包==false,原样发送,并设置丢包=true,丢弃以后的ACK
  4. A–>PSH+ACK–>B,数据包原样发送到B,从状态获取新序列号,伪造B到A的ACK包写入A网卡
  5. B–>ACK–>A,检查状态,发现丢包==true,直接丢包
  6. ……
  7. A–>FIN/RST–>B,发送方和接收方都删除状态,发送和收到RST时也删除
  8. B–>ACK–>A,没有状态,原样发送
  9. B–>FIN+ACK,原样发送
  10. A–>ACK–>B,没有状态,原样发送

大概流程图