ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

《网络排查案例课》

2022-08-15 11:33:58  阅读:160  来源: 互联网

标签:案例 报文 端口 网络 tcp 排查 TCP 连接


《网络排查案例课》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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有