《网络排查案例课》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,连接 From: https://www.cnblogs.com/AllenWoo/p/16587647.html