其他分享
首页 > 其他分享> > 《网络排查案例课》

《网络排查案例课》

作者:互联网

《网络排查案例课》01 | 网络模型和工具:网络为什么要分层?

七层模型;四层 / 五层模型;五元组;四元组
===============================================
OSI 的七层模型,和 TCP/IP 的四层 / 五层模型
五元组:传输协议类型、源 IP、源端口、目的 IP、目的端口
四元组:源 IP、源端口、目的 IP、目的端口
七层模型;四层 / 五层模型;五元组;四元组

《网络排查案例课》02 | 抓包分析技术初探:你会用tcpdump和Wireshark吗?

《网络排查案例课》03 | 握手:TCP连接都是用TCP协议沟通的吗?

案例1:TCP 连接都是用 TCP 协议沟通的吗?(不是的,比如server端未监听某端口,那么会使用icmp type 3 返回端口不可达信息)
-----------------------------------------------------------------------
案例1:TCP 连接都是用 TCP 协议沟通的吗?(不是的,比如server端未监听某端口,那么会使用icmp type 3 返回端口不可达信息)
比如server端未监听某端口,那么会使用icmp type 3 返回端口不可达信息

server端要拒绝连接的话,会以下两种情形:
    1.静默丢包;
        客户端将会不明真相:a.静默丢包;b.去向丢包;c.回向丢包
    2.明确拒绝


$ sudo sysctl net.ipv4.tcp_syn_retries
net.ipv4.tcp_syn_retries = 6


Iptables -I INPUT -p tcp --dport 80 -j REJECT     #实验配置的这条规则
-A INPUT -p tcp -m tcp --dport 80 -j REJECT --reject-with icmp-port-unreachable     #自动补上了–reject-with icmp-port-unreachable
-A INPUT -p tcp -m tcp --dport 80 -j REJECT -–reject-with tcp-reset     #可以手动修改为tcp rst
案例1:TCP 连接都是用 TCP 协议沟通的吗?(不是的,比如server端未监听某端口,那么会使用icmp type 3 返回端口不可达信息)
案例2:Windows 服务器加域报 RPC service unavailable?;案例3:发送的数据还能超过接收窗口?
================================================================================
案例2:Windows 服务器加域报 RPC service unavailable?

使用netstat -antp 在客户端进行查看,发现客户端卡在SYN_SENT 状态,最终确认了使因为防火墙未放行端口,过滤了报文。

-----------------------------------------------------------------------
案例3:发送的数据还能超过接收窗口?

问题:wireshark中,Redis 服务告诉客户端它的接收窗口是 190 字节,但是客户端居然会发送 308 字节,大大超出了接收窗口
根因:抓包没有抓到3次握手的协商报文,wireshark无法对报文的窗口进行正确的解析

    TCP Options 的 Window Scale 字段只出现在TCP3次握手的协商阶段,它表示原始 Window 值的左移位数,最高可以左移 14 位。
    根因在于这次抓包没有抓到tcp协商过程,所以wireshark认为协商的窗口大写为65535字节;而实际的窗口大小应该是服务端通告的窗口190字节* Window Scale数值

    在分析抓包文件时,要注意是否连接的握手包被抓取到,没有握手包,这个 Window 值一般就不准。
案例2:Windows 服务器加域报 RPC service unavailable?;案例3:发送的数据还能超过接收窗口?
UDP 也有握手?(nc探测UDP端口,无响应则认为succeeded,该结果是不可信的!!!);服务器端的最大连接数
====================================================================================================================================
UDP 也有握手?
有些同学会有这个误解,可能是跟 nc 这个命令有关。
$ nc -v -w 2 47.94.129.219 22
Connection to 47.94.129.219 22 port [tcp/ssh] succeeded!
victor@victorebpf:~$ nc -v -w 2 47.94.129.219 -u 22
Connection to 47.94.129.219 22 port [udp/*] succeeded!      #UDP测试,显示successded
抓包发现UDP只有发包,那么nc怎么回显示succeeded呢?
    可能只是因为对端没有回复 ICMP port unreachable

当你下次用 nc 探测 UDP 端口,不通的结果是可信的,而能通(succeeded)的结果并不准确,只能作为参考!!!!!!

------------------------------------------------------------------------------------------------------------------------------------
服务器端最多65535个连接,确实是个误区,其实这个跟很多都有关系的,比如服务器端的CPU、内存、fd数以及连接的情况,fd数是前提。
一个连接会牵扯到服务端的接收缓冲区(net.ipv4.tcp_rmem)以及发送缓冲区(net.ipv4.tcp_wmem),一个空的TCP连接会消耗3.3KB左右的内存,如果发数据的话,一个连接占用的内存会更大。
所以理论上4GB的机器理论上支持的空TCP连接可以达到100W个。
此外数据经过内核协议栈的处理需要CPU,所以CPU的好坏也会影响连接数。
UDP 也有握手?(nc探测UDP端口,无响应则认为succeeded,该结果是不可信的!!!);服务器端的最大连接数

《网络排查案例课》04 | 挥手:Nginx日志报connection reset by peer是怎么回事?

突破应用层日志和网络报文的鸿沟:时间吻合;RST 行为吻合;URL 路径吻合。
--------------------------------------------------------------
在应用层和网络层之间搭建桥梁
    做网络排查的第一个要点:把应用层的信息,“翻译”成传输层和网络层的信息。

应用现象跟网络现象之间的鸿沟:你可能看得懂应用层的日志,但是不知道网络上具体发生了什么。
工具提示跟协议理解之间的鸿沟:你看得懂 Wireshark、tcpdump 这类工具的输出信息的含义,但就是无法真正地把它们跟你对协议的理解对应起来。
突破应用层日志和网络报文的鸿沟:时间吻合;RST 行为吻合;URL 路径吻合。
案例 1:connection reset by peer?;附赠nginx日志解读
===================================================================================================================
案例背景:
    客户反馈,他们的 Nginx 服务器上遇到了很多 connection reset by peer 的报错。
    客户的应用是一个普通的 Web 服务,架设在 Nginx 上,而他们的另外一组机器是作为客户端,去调用这个 Nginx 上面的 Web 服务。
    客户端---nginx---服务端

根因:client的POST,nginx已经回复HTTP 200;但client还是发送了RST 重置连接;问题回到了client侧,进一步排查的话,需要查看client侧的源码了

排查及分析思路:
    1.在客户端上进行抓包;
    2.使用wireshark进行RST报文的过滤,发现了大量的RST报文 "ip.addr eq 10.255.252.31 and tcp.flags.reset eq 1"
        任意选取了一个RST报文,发现该RST报文是次握手的第3个报文,所以实际上该tcp连接还未成功建立,那么应用层就还不知道该连接的存在,不会有该连接的日志了
        结论:该RST报文和nginx日志"connection reset by peer"无关
    3.继续更新wireshark过滤规则,锁定目标RST报文 "frame.time >="dec 01, 2015 15:49:48" and frame.time <="dec 01, 2015 15:49:49" and ip.addr eq 10.255.252.31 and tcp.flags.reset eq 1 and !(tcp.seq eq 1 or tcp.ack eq 1)"
        应用层日志和网络报文是存在鸿沟的,没有直接的关系,但是可以通过以下的方式进行判断
            锁定 TCP 流和某条日志的对应关系,主要三点原因:时间吻合;RST 行为吻合;URL 路径吻合。
    4.追踪该TCP流,发现client的POST,nginx已经回复HTTP 200;但client还是发送了RST 重置连接;问题回到了client侧,进一步排查的话,需要查看client侧的源码了

--------------------------------------------------------------------------------------
nginx日志
2015/12/01 15:49:48 [info] 20521#0: *55077498 recv() failed (104: Connection reset by peer) while sending to client, client: 10.255.252.31, server: manager.example.com, request: "POST /WebPageAlipay/weixin/notify_url.htm HTTP/1.1", upstream: "http:/10.4.36.207:8080/WebPageAlipay/weixin/notify_url.htm", host: "manager.example.com"
2015/12/01 15:49:54 [info] 20523#0: *55077722 recv() failed (104: Connection reset by peer) while sending to client, client: 10.255.252.31, server: manager.example.com, request: "POST /WebPageAlipay/app/notify_url.htm HTTP/1.1", upstream: "http:/10.4.36.207:8080/WebPageAlipay/app/notify_url.htm", host: "manager.example.com"
2015/12/01 15:49:54 [info] 20523#0: *55077710 recv() failed (104: Connection reset by peer) while sending to client, client: 10.255.252.31, server: manager.example.com, request: "POST /WebPageAlipay/app/notify_url.htm HTTP/1.1", upstream: "http:/10.4.36.207:8080/WebPageAlipay/app/notify_url.htm", host: "manager.example.com"
2015/12/01 15:49:58 [info] 20522#0: *55077946 recv() failed (104: Connection reset by peer) while sending to client, client: 10.255.252.31, server: manager.example.com, request: "POST /WebPageAlipay/app/notify_url.htm HTTP/1.1", upstream: "http:/10.4.36.207:8080/WebPageAlipay/app/notify_url.htm", host: "manager.example.com"
2015/12/01 15:49:58 [info] 20522#0: *55077965 recv() failed (104: Connection reset by peer) while sending to client, client: 10.255.252.31, server: manager.example.com, request: "POST /WebPageAlipay/app/notify_url.htm HTTP/1.1", upstream: "http:/10.4.36.207:8080/WebPageAlipay/app/notify_url.htm", host: "manager.example.com"

recv() failed:这里的 recv() 是一个系统调用,也就是 Linux 网络编程接口。它的作用呢,看字面就很容易理解,就是用来接收数据的。
104:这个数字也是跟系统调用有关的,它就是 recv() 调用出现异常时的一个状态码,这是操作系统给出的。在 Linux 系统里,104 对应的是 ECONNRESET,也正是一个 TCP 连接被 RST 报文异常关闭的情况。
upstream:在 Nginx 等反向代理软件的术语里,upstream 是指后端的服务器。
    客户端把请求发到 Nginx,Nginx 会把请求转发到 upstream,等后者回复 HTTP 响应后,Nginx 把这个响应回复给客户端。


在网络运维的视角上,我们更关注网络报文的流向,因为 HTTP 报文是从外部进来的,那么我们认为其上游(upstream)是客户端;
但是在应用的视角上,更关注的是数据的流向,一般来说 HTTP 数据是从内部往外发送的,那么在这种视角下,数据的上游(upstream)就是后端服务器了。
    Nginx、Envoy 都属于应用网关,所以在它们的术语里,upstream 指的是后端环节。这里没有对错之分,你只要知道并且遵照这个约定就好了。

--------------------------------------------------------------------------------------
2.使用wireshark进行RST报文的过滤,发现了大量的RST报文 "ip.addr eq 10.255.252.31 and tcp.flags.reset eq 1"
    任意选取了一个RST报文,发现该RST报文是次握手的第3个报文,所以实际上该tcp连接还未成功建立,那么应用层就还不知道该连接的存在,不会有该连接的日志了
    结论:该RST报文和nginx日志"connection reset by peer"无关


    客户端抓包
    ip.addr eq my_ip:过滤出源IP或者目的IP为my_ip的报文
    ip.src eq my_ip:过滤出源IP为my_ip的报文
    ip.dst eq my_ip:过滤出目的IP为my_ip的报文

    tcp.flags.reset eq 1

    ip.addr eq 10.255.252.31 and tcp.flags.reset eq 1
        在 Wirershark 窗口的右下角,就有符合过滤条件的RST报文个数,这里有 9122 个,占所有报文的 4%


    我们就要先了解应用程序是怎么跟内核的 TCP 协议栈交互的。一般来说,客户端发起连接,依次调用的是这几个系统调用:
        socket()
        connect()
    而服务端监听端口并提供服务,那么要依次调用的就是以下几个系统调用:
        socket()
        bind()
        listen()
        accept()


    抓包现象:client在3次握手的第3个包,直接回复了TCP RST,ACK

        服务端的用户空间程序要使用 TCP 连接,首先要获得上面最后一个接口,也就是 accept() 调用的返回。
        而 accept() 调用能成功返回的前提呢,是正常完成三次握手。
        这次失败的握手,也不会转化为一次有效的连接了,所以 Nginx 都不知道还存在过这么一次失败的握手。

        当然,在客户端日志里,是可以记录到这次握手失败的。这是因为,客户端是 TCP 连接的发起方,它调用 connect(),而 connect() 失败的话,其 ECONNRESET 返回码,还是可以通知给应用程序的。

        所以 3次握手的 RST,不是我们要找的那种“在连接建立后发生的 RST”。

--------------------------------------------------------------------------
3.更新wireshark过滤规则,锁定目标RST报文 "frame.time >="dec 01, 2015 15:49:48" and frame.time <="dec 01, 2015 15:49:49" and ip.addr eq 10.255.252.31 and tcp.flags.reset eq 1 and !(tcp.seq eq 1 or tcp.ack eq 1)"


frame.time >="dec 01, 2015 15:49:48" and frame.time <="dec 01, 2015 15:49:49" and ip.addr eq 10.255.252.31 and tcp.flags.reset eq 1 and !(tcp.seq eq 1 or tcp.ack eq 1)


应用层日志和网络报文是存在鸿沟的,没有直接的关系,但是可以通过以下的方式进行判断
    锁定 TCP 流和某条日志的对应关系,主要三点原因:时间吻合;RST 行为吻合;URL 路径吻合。

--------------------------------------------------------------------------
4.追踪该TCP流,发现client的POST,nginx已经回复HTTP 200;但client还是发送了RST 重置连接;问题回到了client侧,进一步排查的话,需要查看client侧的源码了

然后根据该RST报文找到了TCP会话,发现实际上nginx实际已经响应client的post请求,并回复了http 200;
    奇怪的是client却发送RST报文结束该连接



本案例通过规则最终锁定了与nginx错误日志匹配的数据包,追踪该TCP流,发现client的POST,nginx已经回复HTTP 200;但client还是发送了RST 重置连接;问题回到了client侧,进一步排查的话,需要查看client侧的源码了
避免这种 reset,需要客户端代码进行修复
    客户端用 RST 来断开连接并不妥当,需要从代码上找原因。比如客户端在 Receive Buffer 里还有数据未被读取的情况下,就调用了 close()。
        网络不稳定,或者防火墙来几个 RST,也都有可能导致类似的 connection reset by peer 的问题。
案例 1:connection reset by peer?;附赠nginx日志解读
案例 2:一个 FIN 就完成了 TCP 挥手?"ack搭车"
==========================================================================================
TCP 的挥手是任意一端都可以主动发起的。也就是说,挥手的发起权并不固定给客户端或者服务端。

仅仅只是展示了一个案例,看起来只有一个FIN
实际上另一个FIN是在POST请求中一起发出的。。。

同时因为ack搭车的关系,这个挥手只有3个报文

实际上 TCP 挥手可能不是表面上的四次报文,因为并包也就是 Piggybacking 的存在,它可能看起来是三次。
案例 2:一个 FIN 就完成了 TCP 挥手?"ack搭车"

 

 

 

 

 

 

 

 

 

 

 

 

 

1111

标签:案例,报文,端口,网络,tcp,排查,TCP,连接
来源: https://www.cnblogs.com/AllenWoo/p/16587647.html