当前位置: 首页 > article >正文

现代网络基础设施中的 TCP 握手之下

TCP 3 次握手

在最简单的形式中,TCP 三次握手很容易理解,并且有 大量在线材料都在讨论这个问题。(如果你能读懂 Chinease,你可以看看我之前的一篇文章。

然而,在实际中理解、练习和解决 TCP 问题 世界是另一回事。随着容器平台开始主宰世界,随着 以及 service-mesh 成为底层的下一个重大转变 网络基础设施,这些平台中的现代网络功能使 TCP 相关问题更加复杂。在传统观点中,这些问题 可能看起来相当奇怪。

本文将介绍其中两种情况。你看到时有什么想法 下面两张图片?

方案 1 的 TCP 流有问题

方案 2 的有问题的 TCP 流

1. 场景 1

1.1 现象:SYN -> SYN+ACK -> RST

客户端发起了与服务器的连接,服务器立即确认 (SYN+ACK),但客户端在收到此数据包时重置了它,并继续等待 用于来自服务器的下一个 SYN+ACK。经过多次 retransmit 和 reset, 连接终于超时了。

1.2 捕获

tcpdump 输出:

<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code>1 18:56:40.353352 IP 10.4.26.45.35582 <span style="color:#000000"><strong>></strong></span> 10.4.26.234.80: Flags <span style="color:#000000"><strong>[</strong></span>S],  <span style="color:#0086b3">seq </span>853654705, win 29200, length 0
2 18:56:40.353506 IP 10.4.26.11.80 <span style="color:#000000"><strong>></strong></span> 10.4.26.45.35582:  Flags <span style="color:#000000"><strong>[</strong></span>S.], <span style="color:#0086b3">seq </span>914414059, ack 853654706, win 28960, length 0
3 18:56:40.353521 IP 10.4.26.45.35582 <span style="color:#000000"><strong>></strong></span> 10.4.26.11.80:  Flags <span style="color:#000000"><strong>[</strong></span>R],  <span style="color:#0086b3">seq </span>853654706, win 0, length 0
4 18:56:41.395322 IP 10.4.26.45.35582 <span style="color:#000000"><strong>></strong></span> 10.4.26.234.80: Flags <span style="color:#000000"><strong>[</strong></span>S],  <span style="color:#0086b3">seq </span>853654705, win 29200, length 0
5 18:56:41.395441 IP 10.4.26.11.80 <span style="color:#000000"><strong>></strong></span> 10.4.26.45.35582:  Flags <span style="color:#000000"><strong>[</strong></span>S.], <span style="color:#0086b3">seq </span>930694343, ack 853654706, win 28960, length 0
6 18:56:41.395457 IP 10.4.26.45.35582 <span style="color:#000000"><strong>></strong></span> 10.4.26.11.80:  Flags <span style="color:#000000"><strong>[</strong></span>R],  <span style="color:#0086b3">seq </span>853654706, win 0, length 0
</code></span></span></span>

哪里

  • 客户:10.4.26.45
  • 服务器:,在端口提供 HTTP 服务10.4.26.23480

怎么了?在继续之前,请考虑一下这一点。

1.3 分析

让我们试着深入了解发生了什么:

  1. #1:客户端启动了与服务器的连接,使用src_port=35582,dst_port=80
  2. #2:服务器已确认 (SYN+ACK)
  3. #3:客户端重置服务器的 SYN+ACK 数据包
  4. #4:超时,客户端重传#1
  5. #5:服务器已确认(仍为 SYN+ACK)#4
  6. #6:客户端再次被拒绝 (, SYN+ACK)#5

此 TCP 流的时间序列在此处重新描述:

图 1.1 有问题的 TCP 流

乍一看,这似乎很奇怪,因为服务器确认了客户端的请求, 而 Client 端在收到后立即重置此数据包,然后一直等待 Next 来自服务器的 SYN+ACK(而不是关闭此连接尝试)。它 甚至在超时时重新传输第一个 SYN 数据包(注意到它使用与 do 相同的临时端口)。#4#1

1.4 根本原因

注意这一点:客户端假设服务器在 ,为什么 SYN+ACK 数据包 ( 和 ) 来自 ?通过一些调查, 我们发现:该服务器部署为 K8S ExternalIP Service,作为 VIP(ExternalIP)和 PodIP。10.4.26.234#2#410.4.26.1110.4.26.1110.4.26.234

1.4.1 简短的回答

客户端连接到服务器,目标 IP 为 server,但 server (实例)回复了其真实 IP (PodIP)。IP 不匹配使客户相信 SYN+ACK 数据包无效,因此拒绝了它们。

1.4.2 长答案

首先,我们位于 Cilium 驱动的 K8S 集群中。 Cilium 将生成 BPF 规则,以将流量负载均衡到此 VIP 添加到其所有后端 Pod 中。正常流量路径如图 1.1 所示:

图 1.2 客户端和服务器实例之间的正常数据流

  1. @Client:客户端向服务器发送流量VIP
  2. @ClientHost:Cilium 做 DNAT,把 VIP 改成它的 (backend 实例 IP)PodIP
  3. @ServerHost:路由到 IP 为PodIP
  4. @Server:服务器实例回复为自己的PodIP
  5. @ServerHost:将回复数据包路由到客户端主机
  6. @ClientHost:Cilium 进行 SNAT,将服务器的 schange 为 ,然后转发 到客户端实例的流量PodIPVIP
  7. @Client:客户端接收流量。从它自己的角度来看, received packet 只是前一个发送的 packet (两者都是 ),因此它接受该数据包。3 次握手完成。src_ipdst_ipVIP

客户端和服务器位于同一主机上时,会出现此问题,其中 的情况下,步骤 6 不是由 Cilium 实现的,如图 1.2 所示:

图 1.3 客户端和服务器位于同一主机上时的数据流

我们已经报告了这个问题,并确认了一个错误,请参阅此 问题了解更多详情。

2. 场景 2

2.1 现象:握手正常,传输数据时连接重置

客户端成功启动了与服务器的 TCP 连接(3 个数据包),但是,在 发送第一个数据包(总共第 4 个数据包),连接得到 由 Server 立即重置。

2.2 捕获

<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code>1 12:10:30.083284 IP 10.6.2.2.51136 <span style="color:#000000"><strong>></strong></span> 10.7.3.3.8080: Flags <span style="color:#000000"><strong>[</strong></span>S],  <span style="color:#0086b3">seq </span>1658620893, win 29200, length 0
2 12:10:30.083513 IP 10.6.3.3.8080 <span style="color:#000000"><strong>></strong></span> 10.7.2.2.51136: Flags <span style="color:#000000"><strong>[</strong></span>S.], <span style="color:#0086b3">seq </span>2918345428, ack 1658620894, win 28960, length 0
3 12:10:30.083612 IP 10.6.2.2.51136 <span style="color:#000000"><strong>></strong></span> 10.7.3.3.8080: Flags <span style="color:#000000"><strong>[</strong></span>.],  ack 1, win 229, length 0
4 12:10:30.083899 IP 10.6.2.2.51136 <span style="color:#000000"><strong>></strong></span> 10.7.3.3.8080: Flags <span style="color:#000000"><strong>[</strong></span>P.], <span style="color:#0086b3">seq </span>1:107, ack 1, win 229, length 106
5 12:10:30.084038 IP 10.6.3.3.8080 <span style="color:#000000"><strong>></strong></span> 10.7.2.2.51136: Flags <span style="color:#000000"><strong>[</strong></span>.],  ack 107, win 227, length 0
6 12:10:30.084251 IP 10.6.3.3.8080 <span style="color:#000000"><strong>></strong></span> 10.7.2.2.51136: Flags <span style="color:#000000"><strong>[</strong></span>R.], <span style="color:#0086b3">seq </span>1, ack 107, win 227, length 0
</code></span></span></span>

同样,在继续之前考虑这一点是值得的。

2.3 分析

  1. #1:客户端启动了与服务器的连接,src_port=51136,dst_port=8080
  2. #2:服务器已确认 (SYN+ACK)
  3. #3: 客户端已确认服务器,TCP 连接成功建立
  4. #4:客户端发送了一个字节数据包106
  5. #5: 服务器已确认#4
  6. #6:服务器在之后立即重置此连接#5

此 TCP 流的时间序列在此处重新描述:

图 2.1 有问题的 TCP 流的时间序列

2.4 根本原因

客户端看到一个如图 2.1 所示的拓扑:

图 2.2 两侧的客户端视图

它发起了一个连接,该连接被服务器成功接受,即 3 次握手完成,没有任何错误。但是在传输数据时, 服务器立即拒绝了此连接。因此,问题必须存在于 服务器端。

深入研究服务器端,我们发现一个 sidecar(具体来说是 envoy) 已注入到服务器端容器。如果你不熟悉这个 word,请参考 Istio 的一些介绍性文档。 简而言之,sidecar 充当服务器容器和 外面的世界:

  • 在 Ingress 方向上,它会拦截到 Server 的所有 Ingress 流量,做一些 处理,然后将允许的流量转发到 Server
  • 在 egress 方向上,它会拦截来自服务器的所有 egress 流量,再次执行 some 处理,并将允许的流量转发到外部世界。

流量拦截是通过 Istio 中的 iptables 规则实现的。 详细实现的解释在本文的范围之外, 但如果您有兴趣,可以参考附录 A 中的图表。

这就是魔力所在:客户端和 server 直接访问,但拆分为 2 个单独的连接

  1. 客户端和 sidecar 之间的连接
  2. Sidecar 和 Server 之间的连接

这两个连接是独立的握手,因此即使后者 失败,前者仍然可以成功。

图 2.3 双方的实际视图:一个中间人坐在客户端和服务器之间

这就是确切发生的情况:由于某些内部原因,服务器无法启动 错误,但 Client 和 sidecar 之间的连接已建立。什么时候 客户端开始发送数据包,sidecar 先 ack 接收,然后 将此转发到(失败的)服务器,但被拒绝。然后它意识到 后端服务不可用,因此关闭 (RST) 了 自身和 Client 端。

图 2.4 sidecar 和服务器之间的连接未建立

3. 结束语

在现代,底层网络基础设施越来越强大 且灵活,但代价是堆栈深度更深,并且构成更多 开发人员和维护人员的故障排除挑战。这不可避免 需要更深入地了解网络基础设施、虚拟化 技术、内核堆栈等。

4. 附录 A:Istio Sidecar 拦截

图 4.1 使用 iptables 规则的 Istio sidecar 拦截(入站)

对应的 iptables 规则:

<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#999988"><em># get the Pod netns</em></span>
<span style="color:#008080">$ </span>docker inspect <Container ID or Name> | <span style="color:#0086b3">grep</span> <span style="color:#dd1144">\"</span>Pid<span style="color:#dd1144">\"</span>
            <span style="color:#dd1144">"Pid"</span>: 82881,

<span style="color:#999988"><em># show iptables rules in Pod netns</em></span>
<span style="color:#008080">$ </span>nsenter <span style="color:#000080">-t</span> 82881 <span style="color:#000080">-n</span> iptables <span style="color:#000080">-t</span> nat <span style="color:#000080">-nvL</span>
Chain PREROUTING <span style="color:#000000"><strong>(</strong></span>policy ACCEPT 1725 packets, 104K bytes<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination
 2086  125K ISTIO_INBOUND  tcp  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0

Chain INPUT <span style="color:#000000"><strong>(</strong></span>policy ACCEPT 2087 packets, 125K bytes<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination

Chain OUTPUT <span style="color:#000000"><strong>(</strong></span>policy ACCEPT 465 packets, 29339 bytes<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination
  464 27840 ISTIO_OUTPUT  tcp  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0

Chain POSTROUTING <span style="color:#000000"><strong>(</strong></span>policy ACCEPT 498 packets, 31319 bytes<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination

Chain ISTIO_INBOUND <span style="color:#000000"><strong>(</strong></span>1 references<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination
  362 21720 ISTIO_IN_REDIRECT  tcp  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080

Chain ISTIO_IN_REDIRECT <span style="color:#000000"><strong>(</strong></span>1 references<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination
  362 21720 REDIRECT   tcp  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0            redir ports 15001

Chain ISTIO_OUTPUT <span style="color:#000000"><strong>(</strong></span>1 references<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination
    0     0 ISTIO_REDIRECT  all  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      lo      0.0.0.0/0           <span style="color:#000000"><strong>!</strong></span>127.0.0.1
  420 25200 RETURN     all  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0            owner UID match 1337
    0     0 RETURN     all  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0            owner GID match 1337
   11   660 RETURN     all  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            127.0.0.1
   33  1980 ISTIO_REDIRECT  all  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0

Chain ISTIO_REDIRECT <span style="color:#000000"><strong>(</strong></span>2 references<span style="color:#000000"><strong>)</strong></span>
 pkts bytes target     prot opt <span style="color:#000000"><strong>in     </strong></span>out     <span style="color:#0086b3">source               </span>destination
   33  1980 REDIRECT   tcp  <span style="color:#000080">--</span>  <span style="color:#000000"><strong>*</strong></span>      <span style="color:#000000"><strong>*</strong></span>       0.0.0.0/0            0.0.0.0/0            redir ports 15001</code></span></span></span>


http://www.kler.cn/a/461487.html

相关文章:

  • h5页面在安卓手机被软键盘弹起引起的bug
  • C# 服务应用研究
  • 《探寻真正开源的大模型:开启AI创新新纪元》
  • Docker--Docker Container(容器) 之 操作实例
  • Redis 发布订阅(Pub/Sub)机制详解
  • 无人机飞手培训机构大量新增,考取飞手证参军入伍还有优势吗?
  • 【092】基于51单片机水位控制系统【Proteus仿真+Keil程序+报告+原理图】
  • python文件操作相关(excel)
  • 构建代理 IP 池:方法与实践
  • 【YashanDB知识库】如何在备机节点上做备份和恢复
  • 学术主题研究相关10个ChatGPT提示词
  • 护眼屏幕灯市场格局正在重塑:书客屏幕挂灯如何成为办公新宠
  • 开源的Vue低代码表单设计器 form-create-designer v3.2.9 版本发布,新增10多种功能
  • mysql8 从C++源码角度看 客户端发送的sql信息 mysql服务端从网络读取到buff缓存中
  • 基于文生图模型的创新应用
  • 《量子AI:突破量子比特稳定性与容错性的关键瓶颈》
  • Cursor小试2.pdf转图片
  • Mac连接云服务器工具推荐
  • Unreal Engine 5 C++ Advanced Action RPG 三、四章笔记
  • 1177:奇数单增序列
  • vue中修改局部的elmentUI样式
  • Python将两个视频横向的拼接--视频效果对比
  • yolo数据集 - 2130张边坡排水沟堵塞数据集分享 - 无人机采集与数据增强处理
  • 计算机毕业设计Python深度学习美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js
  • KAFKA入门:原理架构解析
  • 自建私有云相册:Docker一键部署Immich,照片视频备份利器