nmap使用求助

nmap使用求助,第1张

Nmap是一款网络扫描和主机检测的非常有用的工具。Nmap是不局限于仅仅收集信息和枚举,同时可以用来作为一个漏洞探测器或安全扫描器。它可以适用于winodws,linux,mac等 *** 作系统
Nmap是一款非常强大的实用工具,可用于:检测活在网络上的主机(主机发现)检测主机上开放的端口(端口发现或枚举)检测到相应的端口(服务发现)的软件和版本检测 *** 作系统,硬件地址,以及软件版本检测脆弱性的漏洞(Nmap的脚本)Nmap是一个非常普遍的工具,它有命令行界面和图形用户界面。本人包括以下方面的内容:介绍Nmap扫描中的重要参数 *** 作系统检测Nmap使用教程Nmap使用不同的技术来执行扫描,包括:TCP的connect()扫描,TCP反向的ident扫描,FTP反d扫描等。所有这些扫描的类型有自己的优点和缺点,我们接下来将讨论这些问题。 Nmap的使用取决于目标主机,因为有一个简单的(基本)扫描和预先扫描之间的差异。我们需要使用一些先进的技术来绕过防火墙和入侵检测/防御系统,以获得正确的结果。下面是一些基本的命令和它们的用法的例子:扫描单一的一个主机,命令如下:
代码如下:
#nmap nxadmincom#nmap 19216812
扫描整个子网,命令如下:
代码如下:
#nmap 19216811/24
扫描多个目标,命令如下:
代码如下:
#nmap 19216812 19216815
扫描一个范围内的目标,如下:
代码如下:
#nmap 19216811-100 (扫描IP地址为19216811-1921681100内的所有主机)
如果你有一个ip地址列表,将这个保存为一个txt文件,和namp在同一目录下,扫描这个txt内的所有主机,命令如下:
代码如下:
#nmap -iL targettxt
如果你想看到你扫描的所有主机的列表,用以下命令:
代码如下:
#nmap -sL 19216811/24
扫描除过某一个ip外的所有子网主机,命令:
代码如下:
#nmap19216811/24-exclude19216811
扫描除过某一个文件中的ip外的子网主机命令
代码如下:
#nmap19216811/24-excludefilexxxtxt(xxxtxt中的文件将会从扫描的主机中排除)
扫描特定主机上的80,21,23端口,命令如下
代码如下:
#nmap-p80,21,2319216811
从上面我们已经了解了Nmap的基础知识,下面我们深入的探讨一下Nmap的扫描技术
Tcp SYN Scan (sS) 这是一个基本的扫描方式,它被称为半开放扫描,因为这种技术使得Nmap不需要通过完整的握手,就能获得远程主机的信息。Nmap发送SYN包到远程主机,但是它不会产生任何会话因此不会在目标主机上产生任何日志记录,因为没有形成会话。这个就是SYN扫描的优势如果Nmap命令中没有指出扫描类型,默认的就是Tcp SYN但是它需要root/administrator权限
代码如下:
#nmap -sS 19216811
Tcp connect() scan(sT)如果不选择SYN扫描,TCP connect()扫描就是默认的扫描模式不同于Tcp SYN扫描,Tcp connect()扫描需要完成三次握手,并且要求调用系统的connect()Tcp connect()扫描技术只适用于找出TCP和UDP端口
代码如下:
#nmap -sT 19216811
Udp scan(sU)顾名思义,这种扫描技术用来寻找目标主机打开的UDP端口它不需要发送任何的SYN包,因为这种技术是针对UDP端口的。UDP扫描发送UDP数据包到目标主机,并等待响应,如果返回ICMP不可达的错误消息,说明端口是关闭的,如果得到正确的适当的回应,说明端口是开放的
代码如下:
#nmap -sU 19216811
FINscan(sF)
有时候TcpSYN扫描不是最佳的扫描模式,因为有防火墙的存在目标主机有时候可能有IDS和IPS系统的存在,防火墙会阻止掉SYN数据包。发送一个设置了FIN标志的数据包并不需要完成TCP的握手
代码如下:
<a href="mailto:root@bt:~#nmap-sF19216818">root@bt:~#nmap-sF19216818</a></p> <p>StartingNmap551at2012-07-0819:21PKTNmapscanreportfor19216818Hostisup(0000026slatency)Notshown:999closedportsPORTSTATESERVICE111/tcpopen|filteredrpcbind
FIN扫描也不会在目标主机上创建日志(FIN扫描的优势之一)个类型的扫描都是具有差异性的,FIN扫描发送的包只包含FIN标识,NULL扫描不发送数据包上的任何字节,XMAS扫描发送FIN、PSH和URG标识的数据包
PINGScan(sP)
PING扫描不同于其它的扫描方式,因为它只用于找出主机是否是存在在网络中的它不是用来发现是否开放端口的PING扫描需要ROOT权限,如果用户没有ROOT权限,PING扫描将会使用connect()调用
代码如下:
#nmap-sP19216811
版本检测(sV)
版本检测是用来扫描目标主机和端口上运行的软件的版本它不同于其它的扫描技术,它不是用来扫描目标主机上开放的端口,不过它需要从开放的端口获取信息来判断软件的版本使用版本检测扫描之前需要先用TCPSYN扫描开放了哪些端口
代码如下:
#nmap-sV19216811
Idlescan(sL)
Idlescan是一种先进的扫描技术,它不是用你真实的主机Ip发送数据包,而是使用另外一个目标网络的主机发送数据包
代码如下:
#nmap-sL1921681619216811
Idlescan是一种理想的匿名扫描技术,通过目标网络中的19216816向主机19216811发送数据,来获取19216811开放的端口
有需要其它的扫描技术,如FTPbounce(FTP反d),fragmentationscan(碎片扫描),IPprotocolscan(IP协议扫描),以上讨论的是几种最主要的扫描方式
Nmap的OS检测(O)
Nmap最重要的特点之一是能够远程检测 *** 作系统和软件,Nmap的OS检测技术在渗透测试中用来了解远程主机的 *** 作系统和软件是非常有用的,通过获取的信息你可以知道已知的漏洞。Nmap有一个名为的nmap-OS-DB数据库,该数据库包含超过2600 *** 作系统的信息。Nmap把TCP和UDP数据包发送到目标机器上,然后检查结果和数据库对照。
代码如下:
InitiatingSYNStealthScanat10:21Scanninglocalhost(127001)[1000ports]Discoveredopenport111/tcpon127001CompletedSYNStealthScanat10:21,008selapsed(1000totalports)InitiatingOSdetection(try#1)againstlocalhost(127001)RetryingOSdetection(try#2)againstlocalhost(127001)
上面的例子清楚地表明,Nmap的首次发现开放的端口,然后发送数据包发现远程 *** 作系统。 *** 作系统检测参数是O(大写O)
Nmap的 *** 作系统指纹识别技术:
设备类型(路由器,工作组等)运行(运行的 *** 作系统) *** 作系统的详细信息( *** 作系统的名称和版本)网络距离(目标和攻击者之间的距离跳)
如果远程主机有防火墙,IDS和IPS系统,你可以使用-PN命令来确保不ping远程主机,因为有时候防火墙会组织掉ping请求-PN命令告诉Nmap不用ping远程主机。
代码如下:
#nmap-O-PN19216811/24
以上命令告诉发信主机远程主机是存活在网络上的,所以没有必要发送ping请求,使用-PN参数可以绕过PING命令,但是不影响主机的系统的发现
Nmap的 *** 作系统检测的基础是有开放和关闭的端口,如果OSscan无法检测到至少一个开放或者关闭的端口,会返回以下错误:
代码如下:
Warning:OSScanresultsmaybeunreliablebecausewecouldnotfindatleast1openand1closedport
OSScan的结果是不可靠的,因为没有发现至少一个开放或者关闭的端口
这种情况是非常不理想的,应该是远程主机做了针对 *** 作系统检测的防范。如果Nmap不能检测到远程 *** 作系统类型,那么就没有必要使用-osscan_limit检测。
想好通过Nmap准确的检测到远程 *** 作系统是比较困难的,需要使用到Nmap的猜测功能选项,–osscan-guess猜测认为最接近目标的匹配 *** 作系统类型。
代码如下:
#nmap-O--osscan-guess19216811
下面是扫描类型说明
-sTTCPconnect()扫描:这是最基本的TCP扫描方式。connect()是一种系统调用,由 *** 作系统提供,用来打开一个连接。如果目标端口有程序监听,connect()就会成功返回,否则这个端口是不可达的。这项技术最大的优点是,你勿需root权限。任何UNIX用户都可以自由使用这个系统调用。这种扫描很容易被检测到,在目标主机的日志中会记录大批的连接请求以及错误信息。
-sSTCP同步扫描(TCPSYN):因为不必全部打开一个TCP连接,所以这项技术通常称为半开扫描(half-open)。你可以发出一个TCP同步包(SYN),然后等待回应。如果对方返回SYN|ACK(响应)包就表示目标端口正在监听;如果返回RST数据包,就表示目标端口没有监听程序;如果收到一个SYN|ACK包,源主机就会马上发出一个RST(复位)数据包断开和目标主机的连接,这实际上有我们的 *** 作系统内核自动完成的。这项技术最大的好处是,很少有系统能够把这记入系统日志。不过,你需要root权限来定制SYN数据包。
-sF-sX-sN秘密FIN数据包扫描、圣诞树(XmasTree)、空(Null)扫描模式:即使SYN扫描都无法确定的情况下使用。一些防火墙和包过滤软件能够对发送到被限制端口的SYN数据包进行监视,而且有些程序比如synlogger和courtney能够检测那些扫描。这些高级的扫描方式可以逃过这些干扰。些扫描方式的理论依据是:关闭的端口需要对你的探测包回应RST包,而打开的端口必需忽略有问题的包(参考RFC793第64页)。FIN扫描使用暴露的FIN数据包来探测,而圣诞树扫描打开数据包的FIN、URG和PUSH标志。不幸的是,微软决定完全忽略这个标准,另起炉灶。所以这种扫描方式对Windows95/NT无效。不过,从另外的角度讲,可以使用这种方式来分别两种不同的平台。如果使用这种扫描方式可以发现打开的端口,你就可以确定目标注意运行的不是Windows系统。如果使用-sF、-sX或者-sN扫描显示所有的端口都是关闭的,而使用SYN扫描显示有打开的端口,你可以确定目标主机可能运行的是Windwos系统。现在这种方式没有什么太大的用处,因为nmap有内嵌的 *** 作系统检测功能。还有其它几个系统使用和windows同样的处理方式,包括Cisco、BSDI、HP/UX、MYS、IRIX。在应该抛弃数据包时,以上这些系统都会从打开的端口发出复位数据包。 
-sPping扫描:有时你只是想知道此时网络上哪些主机正在运行。通过向你指定的网络内的每个IP地址发送ICMPecho请求数据包,nmap就可以完成这项任务。如果主机正在运行就会作出响应。不幸的是,一些站点例如:microsoftcom阻塞ICMPecho请求数据包。然而,在默认的情况下nmap也能够向80端口发送TCPack包,如果你收到一个RST包,就表示主机正在运行。nmap使用的第三种技术是:发送一个SYN包,然后等待一个RST或者SYN/ACK包。对于非root用户,nmap使用connect()方法。在默认的情况下(root用户),nmap并行使用ICMP和ACK技术。注意,nmap在任何情况下都会进行ping扫描,只有目标主机处于运行状态,才会进行后续的扫描。如果你只是想知道目标主机是否运行,而不想进行其它扫描,才会用到这个选项。
-sUUDP扫描:如果你想知道在某台主机上提供哪些UDP(用户数据报协议,RFC768)服务,可以使用这种扫描方法。nmap首先向目标主机的每个端口发出一个0字节的UDP包,如果我们收到端口不可达的ICMP消息,端口就是关闭的,否则我们就假设它是打开的。有些人可能会想UDP扫描是没有什么意思的。但是,我经常会想到最近出现的solarisrpcbind缺陷。rpcbind隐藏在一个未公开的UDP端口上,这个端口号大于32770。所以即使端口111(portmap的众所周知端口号)被防火墙阻塞有关系。但是你能发现大于30000的哪个端口上有程序正在监听吗使用UDP扫描就能!cDcBackOrifice的后门程序就隐藏在Windows主机的一个可配置的UDP端口中。不考虑一些通常的安全缺陷,一些服务例如:snmp、tftp、NFS使用UDP协议。不幸的是,UDP扫描有时非常缓慢,因为大多数主机限制ICMP错误信息的比例(在RFC1812中的建议)。例如,在Linux内核中(在net/ipv4/icmph文件中)限制每4秒钟只能出现80条目标豢纱锏肾CMP消息,如果超过这个比例,就会给1/4秒钟的处罚。solaris的限制更加严格,每秒钟只允许出现大约2条ICMP不可达消息,这样,使扫描更加缓慢。nmap会检测这个限制的比例,减缓发送速度,而不是发送大量的将被目标主机丢弃的无用数据包。不过Micro$oft忽略了RFC1812的这个建议,不对这个比例做任何的限制。所以我们可以能够快速扫描运行Win95/NT的主机上的所有65K个端口。
-sAACK扫描:这项高级的扫描方法通常用来穿过防火墙的规则集。通常情况下,这有助于确定一个防火墙是功能比较完善的或者是一个简单的包过滤程序,只是阻塞进入的SYN包。这种扫描是向特定的端口发送ACK包(使用随机的应答/序列号)。如果返回一个RST包,这个端口就标记为unfiltered状态。如果什么都没有返回,或者返回一个不可达ICMP消息,这个端口就归入filtered类。注意,nmap通常不输出unfiltered的端口,所以在输出中通常不显示所有被探测的端口。显然,这种扫描方式不能找出处于打开状态的端口。
-sW对滑动窗口的扫描:这项高级扫描技术非常类似于ACK扫描,除了它有时可以检测到处于打开状态的端口,因为滑动窗口的大小是不规则的,有些 *** 作系统可以报告其大小。这些系统至少包括:某些版本的AIX、Amiga、BeOS、BSDI、Cray、Tru64UNIX、DG/UX、OpenVMS、DigitalUNIX、OpenBSD、OpenStep、QNX、Rhapsody、SunOS4x、Ultrix、VAX、VXWORKS。从nmap-hackers邮件3列表的文档中可以得到完整的列表。
-sRRPC扫描。这种方法和nmap的其它不同的端口扫描方法结合使用。选择所有处于打开状态的端口向它们发出SunRPC程序的NULL命令,以确定它们是否是RPC端口,如果是,就确定是哪种软件及其版本号。因此你能够获得防火墙的一些信息。诱饵扫描现在还不能和RPC扫描结合使用。
-bFTP反d攻击(bounceattack):FTP协议(RFC959)有一个很有意思的特征,它支持代理FTP连接。也就是说,我能够从evilcom连接到FTP服务器targetcom,并且可以要求这台FTP服务器为自己发送Internet上任何地方的文件!1985年,RFC959完成时,这个特征就能很好地工作了。然而,在今天的Internet中,我们不能让人们劫持FTP服务器,让它向Internet上的任意节点发送数据。如同Hobbit在1995年写的文章中所说的,这个协议"能够用来做投递虚拟的不可达邮件和新闻,进入各种站点的服务器,填满硬盘,跳过防火墙,以及其它的骚扰活动,而且很难进行追踪"。我们可以使用这个特征,在一台代理FTP服务器扫描TCP端口。因此,你需要连接到防火墙后面的一台FTP服务器,接着进行端口扫描。如果在这台FTP服务器中有可读写的目录,你还可以向目标端口任意发送数据(不过nmap不能为你做这些)。传递给-b功能选项的参数是你要作为代理的FTP服务器。语法格式为:-busername:password@server:port。除了server以外,其余都是可选的。如果你想知道什么服务器有这种缺陷,可以参考我在Phrack51发表的文章。还可以在nmap的站点得到这篇文章的最新版本。
通用选项这些内容不是必需的,但是很有用。
-P0在扫描之前,不必ping主机。有些网络的防火墙不允许ICMPecho请求穿过,使用这个选项可以对这些网络进行扫描。microsoftcom就是一个例子,因此在扫描这个站点时,你应该一直使用-P0或者-PT80选项。
-PT扫描之前,使用TCPping确定哪些主机正在运行。nmap不是通过发送ICMPecho请求包然后等待响应来实现这种功能,而是向目标网络(或者单一主机)发出TCPACK包然后等待回应。如果主机正在运行就会返回RST包。只有在目标网络/主机阻塞了ping包,而仍旧允许你对其进行扫描时,这个选项才有效。对于非root用户,我们使用connect()系统调用来实现这项功能。使用-PT来设定目标端口。默认的端口号是80,因为这个端口通常不会被过滤。
-PS对于root用户,这个选项让nmap使用SYN包而不是ACK包来对目标主机进行扫描。如果主机正在运行就返回一个RST包(或者一个SYN/ACK包)。
-PI设置这个选项,让nmap使用真正的ping(ICMPecho请求)来扫描目标主机是否正在运行。使用这个选项让nmap发现正在运行的主机的同时,nmap也会对你的直接子网广播地址进行观察。直接子网广播地址一些外部可达的IP地址,把外部的包转换为一个内向的IP广播包,向一个计算机子网发送。这些IP广播包应该删除,因为会造成拒绝服务攻击(例如smurf)。

最近准备自己动手部署测试kubernetes集群,注备写一个 hands on 的手册。突发奇想将 centos 原有的内核从310更新到了414版本,并执行一些常规的优化 *** 作。没有想到在修改了 sysctlconf 里面的一些参数,希望能对新的 kubernetes 性能有所帮助。

sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory

纳尼,没有tcp_tw_recycle这个参数了? 怎么回事。。。

netipv4tcp_tw_reuse = 0  表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭

netipv4tcp_tw_recycle = 0  表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭

netipv4tcp_fin_timeout = 60  表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间(可改为30,一般来说FIN-WAIT-2的连接也极少)

好像上面3个内核调整参数,都是很多 Linux 运维工程师的标配了,怎么我一升级内核就不行了? 自己狠下心来好好去的看了 kernel 的文档,Linux 从412内核版本开始移除了 tcp_tw_recycle 这个参数。 好嘛,小弟我手贱贱,升级到了414现在没有这个参数,只能硬着头皮去掉。

但是这个参数对 linux 系统回收大量 tcp timeout wait 有帮助, tcp_tw_recycle通常会和tcp_tw_reuse参数一起使用,用于解决服务器TIME_WAIT状态连接过多的问题 。 但是 kernel 为什么又要取消掉呢? 

简单来说就是,Linux会丢弃所有来自远端的timestramp时间戳小于上次记录的时间戳(由同一个远端发送的)的任何数据包。也就是说要使用该选项,则必须保证数据包的时间戳是单调递增的。同时从410内核开始,官方修改了时间戳的生成机制,所以导致  tcp_tw_recycle 和新时间戳机制工作在一起不那么友好,同时  tcp_tw_recycle 帮助也不那么的大。

此处的时间戳并不是我们通常意义上面的绝对时间,而是一个相对时间。很多情况下,我们是没法保证时间戳单调递增的,比如业务服务器之前部署了NAT,LVS等情况。相信很多小伙伴上班的公司大概率实用实用各种公有云,而各种公有云的 LVS 网关都是 FullNAT 。所以可能导致在高并发的情况下,莫名其妙的 TCP 建联不是那么顺畅或者丢连接。

而这也是很多优化文章中并没有提及的一点,大部分文章都是简单的推荐将netipv4tcp_tw_recycle设置为1,却忽略了该选项的局限性,最终造成严重的后果(比如我们之前就遇到过部署在nat后端的业务网站有的用户访问没有问题,但有的用户就是打不开网页)。

这次我们要关注的不是上半部分的 TCP 新建连接,而是下半部分的 TCP 断开连接。 别人老谈 TCP 3次握手,我就来谈 TCP 4次“挥手告别”。

在说 TCP 断开连接之前,我想先插入点内容。 就是 为什么要在 TCP 传输种引入 TIMEWAIT 这个概念。

第一个作用就是避免新连接接收到重复的数据包,由于使用了时间戳,重复的数据包会因为时间戳过期被丢弃。

第二个作用是确保远端不是处于LAST-ACK状态,如果ACK包丢失,远端没有成功获取到最后一个ACK包,则会重发FIN包。直到:

1放弃(连接断开)

2收到ACK包

3收到RST包

如果FIN包被及时接收到,并且本地端仍然是TIME-WAIT状态,那ACK包会被发送,此时就是正常的四次挥手流程。

如果TIME-WAIT的条目已经被新连接所复用,则新连接的SYN包会被忽略掉,并且会收到FIN包的重传,本地会回复一个RST包(因为此时本地连接为SYN-SENT状态),这会让远程端跳出LAST-ACK状态,最初的SYN包也会在1秒后重新发送,然后完成连接的建立,整个过程不会中断,只是有轻微的延迟。流程如下:
TIME_WAIT永远是出现在主动发送断开连接请求的一方(下文中我们称之为客户), 划重点:这一点面试的时候经常会被问到。 嘿嘿,这个可以做为面试官的杀手锏,上图逻辑保证好多人不知道。(我咋这么坏呢。。。)

客户在收到服务器端发送的FIN(表示"我们也要断开连接了")后发送ACK报文,并且进入TIME_WAIT状态,等待2MSL(MaximumSegmentLifetime 最大报文生存时间)。对于Linux,字段为TCP_TIMEWAIT_LEN硬编码为30秒,对于Windows为2分钟(可自行调整)。

说到 TCP_TIMEWAIT_LEN 这个我就多啰嗦几句,很多资深运维小伙伴,在早起为了加快 tcp timeout 的回收时间,经常会修改这个内核头文件中定义的宏数据,然后重编译内核。 说实话确实有一些用处,至少早起阿里很多基础平台的运维就是这么干的,至于其他大厂不得而知,这个仁者见仁吧。

    确保 TCP 连接在各种情况下,都能正常的关闭。我们的网络 IP 协议本身就是尽力而为的传输,所有传输的可靠性都是靠 TCP 协议栈来完成的。假如当 TCP 自身传输信令的过程中也出现了一些异常呢? 是不是我们 TCP 传输协议本身需要一定的容错机制。

又回到了上面说到的 IP 网络本身尽力而为的传输机制,并不保证数据包在底层传输的时候,接收方收到的数据包的数据顺序不一定是按照发送方的顺序,再加上数据传输延迟,就让上图的问题发生的情况成为了大概率事件。

TIME_WAIT占用的1分钟时间内,相同四元组(源地址,源端口,目标地址,目标端口)的连接无法创建,通常一个ip可以开启的端口为netipv4ip_local_port_range指定的32768-61000,如果TIME_WAIT状态过多,会导致无法创建新连接。

这个占用资源并不是很多,可以不用担心。 (现在服务器内存真心多,不怕。 如果你实用的虚拟机,而且还是短链接巨多,内存分配不那么充足的情况下,还要节省成本, 那就要当心咯)

1修改为长连接,代价较大,长连接对服务器性能有影响。

2增加可用端口范围(修改netipv4ip_local_port_range); 增加服务端口,比如采用80,81等多个端口提供服务; 增加客户端ip(适用于负载均衡,比如nginx,采用多个ip连接后端服务器); 增加服务端ip; 这些方式治标不治本,只能缓解问题。

3将netipv4tcp_max_tw_buckets设置为很小的值(默认是18000) 当TIME_WAIT连接数量达到给定的值时,所有的TIME_WAIT连接会被立刻清除,并打印警告信息。但这种粗暴的清理掉所有的连接,意味着有些连接并没有成功等待2MSL,就会造成通讯异常。

4修改TCP_TIMEWAIT_LEN值,减少等待时间,但这个需要修改内核并重新编译。(这个之前提过,有某个大厂的小伙伴之前这么做的,有效果,但是有其他负面情况,我没有做完整的评估,自己斟酌实用)

5打开tcp_tw_recycle和tcp_timestamps选项。

6打开tcp_tw_reuse和tcp_timestamps选项。

注意,注意,注意,重要的事情说三遍。 5和6之间只能选择一个,不能同时打开。

tcp_tw_recycle 选项在410内核之前还只是不适用于NAT/LB的情况(其他情况下,我们也非常不推荐开启该选项),但410内核后彻底没有了用武之地,并且在412内核中被移除

tcp_tw_reuse 选项仍然可用。在服务器上面,启用该选项对于连入的TCP连接来说不起作用,但是对于客户端(比如服务器上面某个服务以客户端形式运行,比如nginx反向代理)等是一个可以考虑的方案。

修改TCP_TIMEWAIT_LEN是非常不建议的行为。

本地传文件到linux服务器报connectionreset解决方法如下。
1、服务器端因某种原因关闭了Connection,而客户端依然在读写数据,此时服务器会返回复位标志RST。
2、客户端发送syn包(syn等于j)到服务器,并进入SYNSENT状态,等待服务器确认。
3、服务器收到syn包,并会确认客户的SYN(ack等于j加1),同时自己也发送一个SYN包(syn等于k),即SYN加ACK包,此时服务器进入SYNRECV状态。
4、客户端收到服务器的SYN加ACK包,向服务器发送确认包ACK(ack等于k加1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态。

最近使用 netty 过程中发现了几个比较细节的 Connection reset by peer 异常,做个笔记。

这个场景出现在用 Jedis ping 检测的场景,用完直接 close,服务端稳定出现 Connection reset by peer。

tcpdump 一下就很容易定位到问题所在,客户端收到 PONG 响应后直接发了一个 RST 包给服务端:

查看 Jedis 的源码发现 socket 有个比较特殊的配置 socketsetSoLinger(true, 0) 。

先看一下 man7/socket7 的解释:

坦白说不是很明白啥意思。。。

最终在 stackoverflow 上找到一个比较容易理解的解释:

简而言之,设置 SO_LINGER(0) 可以不进行四次挥手直接关闭 TCP 连接,在协议交互上就是直接发 RST 包,这样的好处是可以避免长时间处于 TIME_WAIT 状态,当然 TIME_WAIT 存在也是有原因的,大部分评论都不建议这样配置。

这个场景有点儿微妙,首先得理解一下 tcp 的两个队列。

这篇文章讲得比较清楚: SYN packet handling in the wild

accept 队列满通常是由于 netty boss 线程处理慢,特别是在容器化之后,服务刚启动的时候很容易出现 CPU 受限。

为了模拟这个现象,我写了个示例程序 shichaoyuan/netty-backlog-test ,设置 SO_BACKLOG 为 1,并且在 accept 第一个连接后设置 autoRead 为 false,也就是让 boss 线程不再继续 accept 连接。

启动第一个 Client,可以正常连接,发送 PING,接收 PONG。

启动第二个 Client,也可以正常连接,但是没有收到 PONG:

可见这个连接创建成功了,已经在 Accept Queue 里了,但是进程没有 accept,所以没有与进程绑定。

启动第三个 Client,也可以正常连接,也没有收到 PONG:

与第二个连接一样。

启动第四个 Client,也可以正常连接,但是在发送 PING 后出现 Connection reset by peer:

这个连接在服务端并没有进入 accept queue,处于 SYN_RECV 状态,并且很快就消失了(因为 accept queue 已经满了,无法转入 ESTABLISHED 状态)。

抓包看一下:

从客户端视角来看连接确实是建成功了,有一个比较特殊的地方在三次握手之后,服务端又向客户端发送了一个 [S],客户端回复了一个 [],这个交互看起来不影响连接。

服务端后来销毁了连接,而客户端还认为连接是 ESTABLISHED 的,发送 PING 消息,服务端自然得回复一个 RST。

PS:我在 Windows 10 的 WSL2 中实验这种场景是建连接超时,可能不同的 *** 作系统或 linux 版本对这个交互的过程处理不同,在此不进行进一步测试了。

以上,这个故事告诉我们判断连接是否可用,建成功之后应该发个心跳包测试一下。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/12789660.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-28
下一篇 2023-05-28

发表评论

登录后才能评论

评论列表(0条)

保存