1、前言

出于项目保密原因,本文所提及的IP地址并非真实IP地址,其余技术细节均与案例实际环境相同,供学习交流参考。

2、案例背景

我们前段时间接到项目现场工程师电话,对方称他们新上架了一台Linux服务器(操作系统为UOS),无法telnet到位于互联网上的一台短信分发服务器的8899端口。经过测试,运行Windows的设备在相同的网络甚至相同的IP地址下可以telnet,对方怀疑可能是UOS系统层面上的配置有些问题,或者是系统底层可能有bug。经过远程查看操作系统的各项配置和进程运行情况,确认操作系统不存在配置问题,也不太可能存在bug(因为没有出现其它故障,且其他项目没有相关bug工单),怀疑仍旧是网络层面存在某些安全策略阻止了Linux服务器的网络通信,而对方表示经过网络工程师排查,网络层面上的安全策略已经全部放开处于any any的状态,通过交流后,我们得到的一个大致的网络拓扑如下:

在本案例中,由于网络架构具体信息比较敏感,现场工程师不便透露给我们,但他们已经反复强调网络没有做策略,所以我们不用关心中间网络的IP地址是多少,况且中间的网络节点全部禁ping,无法进行路由追踪。再者从另一个角度上来说,网络层面做安全策略,即使是上升到针对于TCP或OSI参考模型的应用层,也应该是针对于网络协议而言而非操作系统类型,像本案例中,Windows可以通信而UOS无法通信,很明显不是由网络协议所引发的。

3、不同角度的故障分析测试得出完全相反的结论

前文说到,为了定位故障原因,现场工程师分别将运行Windows的设备和UOS的设备接入网络,先后配置相同的IP地址,看到的现象是Windows可以正常telnet但UOS无法telnet,由此得出将故障点定位到服务器的操作系统上
由于检查过操作系统配置不存在问题,而我们在进行故障测试时,是使用的不同的测试方法——将UOS设备分别接入用户网络和互联网直连进行telnet,看到的现象是同一台设备,在用户网络里无法telnet,而在互联网可以telnet建立通信,由此将故障定位在了网络层面上
和现场工程师再次进行沟通,确认所有网络节点中的安全设备只有网闸,其余路由交换设备没有做诸如acl(访问控制链表)之类的配置,由此,故障点的定位范围缩小至网闸部分,另外,Windows可以通信而UOS不能通信这样“奇特”的现象,也不能排除操作系统层面也会有影响。

4、通过wireshark抓包发现两种系统在TCP数据包上的差异

由于Linux和Windows发出的ICMP数据包存在差异,不同点在于Linux的ICMP包比Windows的多了时间戳的字段,因此需要考虑两者在TCP上是否也存在这样的差异。于是在UOS和Windows上分别安装了Wireshark进行抓包分析,的确发现UOS的TCP首包于Windows相比有三个参数是不同的,分别为TSval、TSecr和WS(Window Scale),相关差异如下图所示(上为UOS,下为Windows):

5、对TSval和TSecr参数的理解和移除测试

在TCP连接中,TSval和TSecr统称为TCP的时间戳参数(Time Stamp),其中TSval为本端发送到对端填写的时间数值,TSecr为对方接收到数据包后发送回复报文回显的时间数值,结合TCP报文结构,我们可以知道时间戳参数解决了TCP连接中通信延迟(RTT)测量序列号快速回绕两大问题。

5.1、通信延迟(RTT)测量

在没有时间戳参数的情况,对于从发出数据包到接受数据包这一段时间我们是不能很精确的确定的,由此我们无法得到这其中的网络延迟,而引入时间戳参数,通过时间戳参数的差值,我们可以很精确的计算出网络延迟。

5.2、TCP序列号回绕的理解和回绕的防止

在TCP数据包中结构中,有一个长度为32位的序列号字段,也就是我们通常所说的seq,因其长度为32位,数据量为232字节,因此经过换算后,一次TCP连接最大可以承担约4.29GB的数据传输,如下图所示:

32位seq会带来序列号回绕的现象,也就是说当seq的编号达到232时,这个编号将会返回到0,然后重新递增,这就是序列号回绕的现象。序列号回绕在通常情况下不会有太大的问题,但这个问题通常在超高速以太网(如万兆网络)中会非常明显,比如在万兆网络中,seq的数值从0到232的周期只有几秒种(因为数据量最大只有约4.29GB),假设某时刻,一个seq=400的数据包因链路延迟的原因需要进行重传且重传成功,此次交互将不会有问题,而如果在seq回绕后的下一周期中,上一周期因网络延迟而未到达的seq=400的数据包又恰好与下一周期的seq=400数据包同时到达,那么接收端将不知道应该接收哪个数据包,由此这样的二义性冲突会使得通信发生中断故障,如下图所示:

针对于上面的问题,引入时间戳参数可以防止TCP序列号回绕,原因在于TSval和TSecr是两个单调递增的变量,接收端在接收数据包时,会对TSval和TSecr两个数值进行比较,因此判断数据包的新旧,如果发生TCP序列号回绕,尽管从seq参数上已经无法判断数据包的新旧,但是从时间戳参数上,仍旧可以判断,并以此丢弃旧的数据包,保障通信正常。

5.3、在Linux系统层面上移除时间戳参数

Windows系统中,TCP默认是不带时间戳参数的,并且就抓包情况来看,由于Windows通信正常,我们在Linux系统上通过关闭时间戳参数的方式来查看是否与其有关。通过在/etc/sysctl.conf文件中添加“net.ipv4.tcp_timestamps=0”,成功去除了TSval和TSecr两个参数,然后分别接入用户网络和互联网进行测试,故障现象依旧,说明造成通信故障的原因与时间戳参数无关。

6、窗口缩放选项(Window Scale)理解和移除测试

6.1、窗口缩放选项的理解

在关闭时间戳参数后,Windows和UOS之间的直接的差异就只剩下窗口缩放选项(WS)不同了,其中Windows的WS值为256,而UOS为128
通过查看TCP报文结构,我们可以看到TCP头部包含一个长度为16位的窗口大小(Window Size,在wireshark的数据包中表示为Win)字段。

在全球网络建设初期,由于带宽都很小,因此TCP协议将Window Size长度定为16位,也就是TCP报文的窗口大小最大为65535字节,但随着网络的发展,65535字节的窗口大小成为网络性能的瓶颈。针对于这个问题的解决方式是,独立与Window Size字段之外,扩展出一个TCP选项(TCP Option)来声明这个TCP报文真正的窗口大小,以达到将Window Scale从16位扩充到32位的目的,下图为Windows设备接入用户网络后数据包的TCP选项情况:

结合上图来看,UOS的WS值为128,因此TCP Option的Window Scale会显示为7,因为27=128,而对于窗口缩放选项是如何将Window Size由16位扩展到32位,则可以用下图来解释:

由图可知,Window Size的扩充是将二进制位向左移相应位数得到,上图移动了8位,对应的WS值为256,而32896*256=8421376,它的意义在于,扩充前本端服务器一次只能接受32896字节的数据量,扩充后则可以接收8421376字节的数据量。

6.2、窗口缩放选项的移除测试

经过查找相关资料,在Linux操作系统层面,只能选择将TCP窗口缩放选项开启或者关闭,无法修改其具体数值,我们将Window Scale关闭进行测试,具体操作为,将操作系统切换至root用户后,输入“echo “0” > /proc/sys/net/ipv4/tcp_window_scaling”即可关闭。关闭TCP窗口缩放选项后进行telnet测试,发现无论是在用户网络还是直接接入互联网,TCP都会连接失败,说明WS参数会对TCP的通信造成影响。从另一个角度看,当UOS的WS值为128时,接入互联网可以正常连接,但用户网络不行,说明另一部分原因还是和用户网络内的网闸有关系,我们因此可以推断,该网闸和TCP中的WS值存在某种关联。

7、网闸

在网络工程中,网闸一种安全设备,通常部署于网络边界,用于网络和网络之间相互隔离,并且这样的隔离是物理隔离,这是网闸和防火墙相比最本质的区别
网闸怎样做到物理隔离的?通常情况下,大部分网闸都是采用的“1+2模式”,即“两个独立运行的主机+一个交换隔离矩阵”,如下图所示:

在网闸中,主机1和主机2相互独立运行没有关联,交换隔离矩阵负责将所有连接的网络协议进行物理剥离。举个例子,某时刻网络A中的某个主机向网络B发起一个TCP连接,这个TCP连接首先到达网闸主机1,然后网闸主机1将这个TCP连接转发到交换隔离矩阵,交换隔离矩阵接收到TCP连接后,将TCP连接中的网络协议和数据无差别进行剥离,转换成纯粹的类xml文件,然后关闭和网闸主机1的连接,检查安全策略是否允许这些类xml文件通过,如果可以通过,则建立和网闸主机2的连接,重新构建网络协议和TCP连接,将类xml文件转换为对应的网络协议和数据,发往网闸主机2,最终由网闸主机2发往网络B。相关过程如下图所示:

换言之,在交换隔离矩阵内,没有所谓网络协议的概念,只有纯文件的转发,且主机1和主机2不会同时和交换隔离矩阵建立连接,以此达到物理隔离的效果。从理解的角度出发,这十分类似于轮船在水电站过闸门

8、故障定位和可能的故障原因

为最后确定相关的故障主因不是由UOS操作系统引起,我们将UOS换成了ubuntu进行测试,也出现了相同的现象,可以确定的是,基于ubuntu的衍生版本,如优麒麟(Ukylin)等操作系统,也无法通过该网闸和短信服务器建立TCP连接。由此,故障的定位基本可以定位于网闸一侧。由于网闸具体的底层工作原理均为网闸厂商的商业机密,我们只能在这里推测可能的故障原因,因为网闸无一例外会将网络协议进行重新构建,所以我们推测经过网闸重新构建后,单个数据包传送的数据量大于Linux系统最大窗口大小(64240*128)而又小于Windows系统的最大窗口大小(64240*256),导致Linux系统无法被接收,而Windows系统可以被接收到

更多推荐

【案例分析】Linux和Windows在TCP数据包上的差异+网闸兼容问题引发的TCP连接失败故障分析