欢迎关注:1,欢迎关注本博客,你可点击右手边的【QQ邮件订阅】订阅本博客!2,本博客推出江湖救急计划,主要为工作中遇到疑难杂症的兄弟提供远程技术支持和分析,如有需要,请在江湖救急计划页面给我留言!

PSH|RST同置位,系统应用共沉寂!

作者:易隐者 发布于:2014-2-7 14:34 Friday 分类:案例讨论

       年前一位技术兄弟维护的站点遇到异常流量,导致无法正常访问站点。其将捕获到的报文发给我,让我帮其分析一下大致是什么情况。年前杂事较多,未来得及写分析文档,年后将未完成的部分补充完全,放在此供各位兄弟讨论。

       我首先查看其TCP会话数较多(8500多个),而且大部分的TCP会话是219.140.167.122与X.X.254.18之间产生的,并且这些会话具有较为明显的流量特征,如下图所示: 

点击查看原图

       我们在报文 中任意查看其中一个TCP会话的交互报文,如下图: 

点击查看原图

       我们可以发现,其在完成三次握手之后,219.140.167.122主机与X.X.254.18发起了一个PSH、RST同时置一的报文,如下图:

点击查看原图

       这个报文的解码和follow TCP Stream显示其为一个http  get请求报文,如下: 

点击查看原图

       将其解码,如下: 

点击查看原图

        可见这是一个针对站点某个pdf文档进行访问的操作。

点击查看原图

        在这个TCP交互过程中,我们可发现服务器在收到这个PSH、RST位同时置一的get请求之后,并没有立即RST释放这个TCP连接,而是在72秒之后,服务器才向客户端发送RST报文释放该TCP连接。

        一般情况下,在收到RST报文之后,系统传输层会立即释放对应的TCP连接,为什么要等到72秒之后才发送RST报文呢?TCP协议栈在收到PSH,RST位同时置一的报文时,应该如何处理??

       Google百度均未找到相关的说明资料。

       我们不妨自己先大胆推测一下服务器在收到PSH、RST位同时置一的报文时时如何处理。
三种假设:
1,如果服务器先处理RST位,则服务器端会立即释放相关的TCP连接表信息。PSH位置一应该会失去应有的意义,传输层不会将客户端的应用字段递交给应用层处理。
2,如果服务器先处理PSH位,后处理RST位,则服务器将get请求提交应用层之后,释放TCP连接。服务器及时向应用层在处理完客户端的get请求之后,应用层向传输层提交应用层响应数据,这时,会发现在服务器传输层已有的TCP连接表信息中找不到对应的TCP连接,传输层向应用层报错,应用层放弃。
3,如果服务器先处理PSH位,忽略RST位,则服务器会将应用层的响应字段正常发送给客户端。

       我们再来仔细的看看上述报文交互的情况:

点击查看原图

       我们可以发现,服务器在72秒之后向客户端发送的RST报文其ACK位是置一的,ACK相对确认号是1,这说明这个RST报文发送出来的时候,服务器端的TCP连接表信息是正常的,并且传输层并未处理PSH、RST位置一的报文,否则ACK相对确认号应该是805而不是我们看到的1。

        我们再来看一下这个服务器发送的RST报文的解码,如下图所示: 

点击查看原图


        该报文TTL=64,可说明两点:

1,这个报文的确是服务器发送的,不会是第三方进行TCP会话劫持伪造发送的;

2,这个服务器可能是linux的服务器。

       上面的这些说明了什么呢?

       我个人认为,造成上述情况出现的原因是服务器过滤了RST位置一的报文!

       服务器要做到对TCP标识位进行过滤并不是一件难事,iptables就可以。iptables如下命令即可实现对RST位置一报文的过滤:
  iptables -A INPUT -p tcp --tcp-flags RST RST -j DROP

       服务器过滤了PSH/RST位置一的报文,它不管PSH是否置一,因此那个客户端发送给服务器的PSH/RST位置一的http get报文并未被服务器传输层收到,服务器传输层在等待了72秒未收到客户端的任何请求之后,主动RST释放了这个TCP连接。

       这些流量特征一致的TCP会话基本都是一样的,在三次握手建立TCP连接之后,向服务器发送PSH、RST位同时置一的http get请求报文,如下图所示:  

点击查看原图

       客户端短时间内大量的这种报文,导致服务器的连接表骤增而在一定时间内难以释放,从而给服务器造成了DOS攻击的效果。

阅读全文>>

标签: TCP RST TTL get push DOS攻击 连接表 异常流量 HTTP PSH RST过滤 iptables PSH/RST位同时置一

评论(4) 引用(0) 浏览(107815)

wireshark过滤器使用注意事项

作者:易隐者 发布于:2013-4-26 15:23 Friday 分类:网络分析

       以前一直认为各个网络分析产品的过滤器工作机制应该都是一样的,今天在协助分析定位一个故障的时候,我使用wireshark进行分析,用HTTP作为过滤条件,想仅查看HTTP交互的报文,其过滤后显示的内容如下图所示:

点击查看原图

       单看上图的显示内容,我们很容易的认为,这就是纯粹的HTTP交互,但是未看见三次握手连接建立的过程,一开始我心里是有点疑惑,但是并未往心里去,后来在合作伙伴的提醒下,我再尝试使用TCP作为过滤条件,方才看到大量的SYN报文,如下图所示:

点击查看原图

         实在想不通,难道HTTP的三次握手过程不属于HTTP报文????不知道wireshark在这一块是如何设计和考虑的,总之个人认为这个设计不合常理。我们以后在使用wireshark过滤器的时候稍微注意一下,避免出现误解。

阅读全文>>

标签: TCP wireshark 过滤器 HTTP

评论(2) 引用(0) 浏览(6962)

别具匠心的HTTP应用层行为设计

作者:易隐者 发布于:2012-12-26 16:09 Wednesday 分类:网络分析

       今年的年初,有位兄弟在QQ跟我讨论一个较为少见的报文交互情况,我当时在看了具体的报文交互之后,对他说是某种HTTP探测机制,他则对我说有人认为是某种SACK的重传机制,记得我曾说过我会找时间好好研究一下这个交互的行为,后来的确也写了一些分析、画了一些图示,但是在未完成的情况下被耽搁了,直至最近才把这个翻出来,闲话少说,我们还是直奔主题,一起来看一下这个有意思的应用交互行为吧。

       这个报文交互过程如下:

点击查看原图

       其交互的数据流图如下: 

点击查看原图

       我们再来看一下其中几个重要报文的详细解码,首先看服务器的HTTP 200 OK响应报文的解码,如下图所示: 

点击查看原图

服务器响应报文解码(No128报文解码)

       这个服务器的响应报文,其应用字段长度为585字节,序列号为101871,最后两字节应用字段为Hex 0d0a,我们再来看一下客户端对这个服务器响应报文的确认报文的解码,如下图所示: 

点击查看原图

       从上图解码来看,这是一个最为常见的确认报文,确认号为102456(101871+585)。我们再看看服务器的重传报文解码,如下: 

点击查看原图

服务器后续重传报文解码(No132报文解码)

       我们能够清楚的看到,这个来自服务器的重传报文其应用字段为1字节,序列号为102454,应用字段为Hex 0d,通过序列号我们可以看出这个重传报文并不是No130应用响应报文的重传,而仅仅是重传了No130报文中倒数第二个字节的应用字段!我们再看看客户端对服务器这个重传报文(No132报文)进行确认的报文解码: 

点击查看原图

客户端对服务器这个重传报文(No132报文)进行确认的报文解码

       客户端确认号为102456,但是其SACK却显示为102454-102455!确认号大于块左边界、块右边界值,这是不符合SACK的相关规范的!

       我把这个交互过程制作一个更为清晰明了的图示如下: 

点击查看原图

       现在大家应该清楚这个交互的具体情况了,那么疑问来了:

1, 服务器端为何重传倒数第二个字节的应用字段?
2, 客户端在确认服务器的重传报文时,为何使用不规范的SACK?

       带着这两个疑问,我用自己的机器访问163网站,重现了这个交互过程如下: 

点击查看原图

       这个过程跟上面的交互过程几乎是一致的,我们就不再做详细的分析了,但是我们来仔细的查看一下客户端对服务器一字节应用字段重传的确认报文的解码: 

点击查看原图

客户端对服务器重传报文进行确认的报文解码

       在这个解码中,我们看到,我的机器在对服务器的一字节重传报文进行确认时,并未使用SACK,而是正常的重传了对服务器应用响应报文的确认,这是一般情况下的正常处理。这也说明了服务器的这个“重传一字节应用字段”的行为并不会导致客户端的确认出现异常。只有系统处理差异才能够解释这种情况的发生:我使用的客户端是XP操作系统,而那位与我讨论的兄弟使用的是其他操作系统。不同的操作系统在遇到这种重传部分应用字段的报文时处理机制不一样导致了疑问2的出现,这种不合SACK规范的确认报文虽然不会对服务器造成交互的影响,但足以让我们产生困惑,因此,严格来说,那位与我讨论的兄弟所使用的端系统如此处理是异常的。

       如此我们解决了第二个疑问。

       而针对第一个疑问,问遍了google和baidu无果后,让我们一起来分析一下这种行为可能带来的好处和坏处。

       服务器在作出应用响应之后,在200ms左右未收到来自客户端的确认报文,则将倒数第二个字节的应用字段封装重传给客户端。

这样做的好处是在如下几种情况下会提高服务器与客户端的交互效率

1, 服务器发往客户端的应用响应报文在网络传输过程中被丢弃
       服务器的响应报文被丢弃,未到达客户端,在这种情况下,服务器的这个“200ms内未收到客户端ACK报文则重传一字节应用字段”的行为,避免了服务器端被动等待客户端确认报文到达直至重传定时器清零,服务器才可以重传报文,服务器通过这种行为主动探测客户端对服务器报文接收的情况,提高了交互的效率。 

点击查看原图

服务器应用响应报文被丢弃时的交互过程图示

2,客户端对服务器应用响应报文的确认在网络传输过程中被丢弃
       如果客户端对服务器应用响应报文的确认报文在到达服务器之前被丢弃了,那么,会出现服务器端等待客户端确认报文到达的情况,这是一个超时重传的等待时间,一般至少在数秒之间,而服务器的这个“200ms内未收到客户端ACK报文则重传一字节应用字段”的行为,可以在200ms左右主动发送“封装最后倒数第二个字节应用字段的重传报文”,这个报文到达客户端之后,客户端将重新发送确认报文,这减少了超时重传的等待时间,从而提高了交互的效率;

点击查看原图

客户端对服务器响应报文的确认被丢弃时交互过程的图示

坏处就是:与一般正常交互过程相比,可能会给网络多带来两个64字节的小包

       如果客户端正常收到了服务器的应用响应报文,只是客户端的ACK报文较慢(网络传输延时或者客户端的delay ack机制等)到达服务器,则服务器会发送这种带有一个应用字段的重传报文,而客户端在收到这个报文后,会对这个报文进行确认。

       而这个坏处相对于其带来的好处而言,实在不值一提,因此不得不说,这个HTTP应用行为的设计是别具匠心的!

       那么为什么是倒数第二个字节而不是倒数第一个字节、倒数第三个字节或者其他字节?理论上来说重传任何一个字节达到的效果都是一样的,只重传部分应用字段(一个字节)是为了节约网络带宽资源,或许程序设计者如此设计有一些特别的用处,但是这只能去问程序设计者本人了。

      另:我已将相关报文文件作为附件上传至此,有兴趣的兄弟姐妹可下载学习探讨,下载后解压即可使用wireshark直接打开查看。

阅读全文>>

附件下载:
别具匠心的HTTP应用行为设计-兄弟提供的原报文.zip 203.32KB
别具匠心的HTTP应用行为设计-我重现的报文1.zip 2.1KB
别具匠心的HTTP应用行为设计-我重现的报文2.zip 4.21KB

标签: sack 解码 重传 get delay ack HTTP 应用行为

评论(1) 引用(0) 浏览(78452)

HTTP chunked编码异常导致业务下载附件慢故障案例

作者:易隐者 发布于:2012-12-18 9:32 Tuesday 分类:案例讨论

故障现象

       某业务应用系统基于B/S架构开发,其应用页面打开正常,但是该应用在下载附件时,速度非常慢。

故障分析

       在下载附件很慢时,在服务器上捕获客户端与服务器业务交互的报文。其TCP会话交互的情况如下图所示: 

点击查看原图

       我们首先分析客户端与服务器三次握手建立连接的情况,查看客户端、服务器协商的MSS值是否正常,我们首先查看客户端SYN报文,其TCP MSS协商为1460,如下图所示: 

点击查看原图

       接下来查看服务器SYN/ACK报文,其TCP MSS也为1460,如下图所示: 

点击查看原图

       这说明双方协商的MSS值不存在问题,另服务器对客户端的get请求的第一个应用响应报文长度为248B,如下图所示: 

点击查看原图

       这也充分说明业务服务器在给客户端发送报文时并不是一直只能发送9字节的报文。那么是什么原因导致业务服务器突然之间只能每次发送9字节的应用层数据呢?

       我们注意到服务器给客户端的第一个HTTP应用响应报文,如下图所示: 

点击查看原图

        其Transfer-Enconding是chunked

        HTTP为什么会使用chunked传输编码?我直接引用《HTTP1.1中CHUNKED编码解析》一文中的描述来说明:一般HTTP通信时,会使用Content-Length头信息性来通知用户代理(通常意义上是浏览器)服务器发送的文档内容长度,该头信息定义于HTTP1.0协议RFC  1945  10.4章节中。浏览器接收到此头信息后,接受完Content-Length中定义的长度字节后开始解析页面,但如果服务端有部分数据延迟发送吗,则会出现浏览器白屏,造成比较糟糕的用户体验。
        解决方案是在HTTP1.1协议中,RFC  2616中14.41章节中定义的Transfer-Encoding: chunked的头信息,chunked编码定义在3.6.1中,所有HTTP1.1 应用都支持此使用trunked编码动态的提供body内容的长度的方式。进行Chunked编码传输的HTTP数据要在消息头部设置:Transfer-Encoding: chunked表示Content Body将用chunked编码传输内容。根据定义,浏览器不需要等到内容字节全部下载完成,只要接收到一个chunked块就可解析页面.并且可以下载html中定义的页面内容,包括js,css,image等。”

        “Chunked编码一般使用若干个chunk串连而成,最后由一个标明长度为0的chunk标示结束。每个chunk分为头部和正文两部分,头部内容指定下一段正文的字符总数(非零开头的十六进制的数字)和数量单位(一般不写,表示字节).正文部分就是指定长度的实际内容,两部分之间用回车换行(CRLF)隔开。在最后一个长度为0的chunk中的内容是称为footer的内容,是一些附加的Header信息(通常可以直接忽略)。”

       《HTTP1.1中CHUNKED编码解析》一文中使用了下图作为chunked解码的示意: 

点击查看原图

       通过这张示意图,我们可以清晰的了解到,chunked解码主要由2块组成,一块为指定数据块长度,以\r\n回车换行作为结束符,另一块为实际的应用数据,也以\r\n回车换行作为结束符。
       知道了chunked解码的组成,我们再来看看业务服务器给客户端发送的应用层长度仅9字节的报文解码: 

点击查看原图

       根据这9个字节的应用字段解码,我们将其十六进制换算为正常的十进制,如下表所示:

点击查看原图

        我们根据上图即可解码服务器发往客户端的chunked编码报文,其意义为:
1,指明长度为0001,即为1字节;
2,该报文真正的应用数据仅为1字节的“R”!

       服务器每次仅传输一个字节给客户端!其报文的有效载荷率仅为:   1/63=0.015873015873015873015873015873016!
       如果客户端下载一个1MB大小的附件,服务器端将产生1*1024*1024=1048576个报文,如果客户端每个报文都确认的话,一个下载将产生1048576次交互,即使往返时间RTT值非常小,再乘以1048576的基数之后,也将是个难以接收的数值。
       如此,我们终于明白下载附件慢的原因了。

分析结论

       此为业务服务器HTTP chunked编码传输时,自己指定的数据块长度值太小(为1字节)导致的故障。

参考文档

1,《HTTP1.1中CHUNKED编码解析》
2,RFC 2616《超文本传输协议》

阅读全文>>

标签: 疑难故障 MSS RTT 往返时间 HTTP chunked编码 交互次数

评论(3) 引用(0) 浏览(9388)

Powered by 易隐者 基于emlog 皖ICP备12002343号-1