它建立在scapy(Scapy在Linux上本机运行,并且在大多数使用libpcap及其python包装器的Unix上运行)之上,它负责所有数据包的解析和构造。并实际处理发送和接收数据包。
有一个使用它在中获取网页的示例 examples/curl.py。这个例子使用ARP欺骗绕过内核的TCP堆栈,有时会导致它不工作。运行几次有时可以解决此问题。
sudo python examples/curl.py 10.0.4.4 example.com ens3310.4.4.4: 伪ip地址,example.com:访问域名,ens33:外网网卡
特征
- 可以连接到主机,发送数据包并以正确的顺序重组答复
- 将忽略乱序数据包
- 基本上,它适合于实现curl,但不适用于发送数据
缺少功能
- 一次发送多个数据包
- 重新发送丢弃的数据包
- 一次处理多个传入连接
- bind()根本没有经过严格测试,只是经过了单元测试。所以它可能不能严格好用。
难点
- 它需要以root用户身份运行,因为它需要使用原始套接字。
- TCP堆栈实际上不应该启动和停止。原则上,它实际上应该作为守护程序运行,但程序跑起来并非如此。
- 它需要绕过内核,因为通常那里的TCP堆栈将拦截所有传入的数据包并重置连接。因此,我们侦听虚假的IP地址并将免费的ARP发送到路由器。这就是为什么curl.py需要你的网络接口和伪IP地址的原因。
- Python所以慢。如果您在Wireshark中观看它,它会很有趣,它会备份发送ACK,然后在末尾发送ACK负载,并永久关闭连接。
- 有时ARP欺骗或嗅探无法正常工作。通常,运行5次,它将起作用。
一个实际案例:通过它可以(稍微)了解TCP
用Python编写了一个TCP堆栈是一次有趣的学习经历。
一年后,在工作中,有人在Slack上提到“嘿,我正在向NSQ发布消息,每次要花费40毫秒”。我已经开始考虑这个问题了一个星期了,没有去过任何地方。
背景知识:NSQ是发送消息的队列。发布消息的方式是在本地主机上发出HTTP请求。将HTTP请求发送到本地主机实际上不需要40毫秒。这看起来发生了严重错误。NSQ守护程序没有处于高CPU负载下,它没有使用大量内存,这似乎不是垃圾收集暂停。
然后想起了一周前读过的一篇文章“寻找性能-我们如何减少每个POST请求200ms的时间”(https://gocardless.com/blog/in-search-of-performance-how-we-shaved-200ms-off-every-post-request/)。在那篇文章中,他们讨论了为什么每个POST请求都需要200毫秒的额外时间。
延迟的ACK和TCP_NODELAY
Ruby的Net :: HTTP将POST请求拆分为两个TCP数据包-一个用于head头,另一个用于body。相比之下,如果将curl组合成一个小包,它们就会合并在一起。更糟的是,Net :: HTTP并未在打开的TCP套接字上设置TCP_NODELAY,因此它在发送第二个数据包之前等待第一个数据包的确认。此行为是Nagle算法的结果。
转到连接的另一端,HAProxy必须选择如何确认这两个数据包。在版本1.4.18(正在使用的版本)中,它选择使用TCP延迟确认。延迟的确认与Nagle的算法交互不良,并导致请求暂停,直到服务器达到其延迟的确认超时。
解开本段的内容。
- TCP是一种算法,可以在其中以包形式发送数据
- 他们的HTTP库以2个小数据包发送POST请求
之后,其余的TCP交换如下所示:
应用:嗨!这是数据包
HAProxy:
HA Proxy:
应用程序:
应用程序:
HAProxy:好吧,我很无聊。这是一个ack
应用程序:很好,这是第二个数据包!
HAProxy:在这里完成
那段时间,应用程序和HAProxy都被动地等待对方发送信息?那是额外的200毫秒。由于Nagle的算法,应用程序正在执行此操作;由于ACK延迟,应用程序正在这样做。
默认情况下,每个Linux系统上都会发生延迟的ACK 。因此,这不是极端情况或异常情况–如果您以多个TCP数据包发送数据,则可能会发生这种情况。
在其中我们成为巫师
对应用程序和BOOM进行了更改TCP_NODELAY。
所有40ms的延迟立即消失了。
我们是否应该完全停止使用延迟的ACK
真正的问题是ACK延迟。200毫秒的“ ACK延迟”计时器是一个坏主意,因为伯克利的某个人在1985年左右陷入了BSD,因为他们并没有真正理解该问题。延迟的ACK表示可以在200毫秒内收到应用程序级别的答复。TCP仍将继续使用延迟的ACK。
ACK既小巧又便宜,并且在实践中由延迟的ACK引起的问题可能比它们解决的问题严重得多。
不了解TCP就无法解决TCP问题
TCP确实是底层的,但是有时在现实生活中您会遇到一个错误,而该错误是由于TCP算法中的某些错误。因此,事实证明理解TCP很重要。
延迟的ACK / TCP_NODELAY交互特别糟糕–它可能会影响使用任何编程语言编写任何发出HTTP请求代码的任何人。
苹果的防火墙和MTU小包探测
MacOS支持pf(搜索OpenBSD pf)和ipfw防火墙,两者都可以做状态防火墙。
值得一提的是,Mac tcp堆栈大部分取自2001 FreeBSD,后来又添加了MPTCP,也许他们把mtu放在了路径mtu上,以探测最初导入后的变化,它是在syncache和syncookies之前进行的,并且肯定没有FreeBSD在过去20年中所做的任何其他主要可扩展性改进。防火墙代码的某些部分已损坏(或在过去的发行版中已损坏)。
话虽如此,苹果的TCP堆栈在iOS上比Android更好,因为苹果启用并调整了路径MTU探测,因此,如果MTU设置过大且ICMP被阻止的愚蠢网络中,iOS会很快发送较小的数据包,并且连接将正常工作,Android附带禁用了探测功能,因此它仅发送丢弃的大数据包,直到连接超时。