TCP连接的状态图
TCP建立连接的三次握手过程,以及关闭连接的四次握手过程
贴一个telnet建立连接,断开连接的使用wireshark捕获的packet截图。
1、建立连接协议(三次握手)
(1)客户 端发送一个带SYN标志的TCP报文到server。这是三次握手过程中的报文1。
(2) server端回应client的,这是三次握手中的第2个报文。这个报文同一时候带ACK标志和SYN标志。
因此它表示对刚才clientSYN报文的回应。同一时候又标志SYN给client,询问client是否准备好进行数据通 讯。
(3) 客户必须再次回应服务段一个ACK报文,这是报文段3。
2、连接终止协议(四次握手)
因为TCP连 接是全双工的,因此每一个方向都必须单独进行关闭。这原则是当一方完毕它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN仅仅意味着这一方向上没有数据流动。一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将运行主动关闭。而还有一方运行被动关闭。
(1) TCP客 户端发送一个FIN。用来关闭客户到server的数据传送(报文段4)。
(2) server收到这个FIN。它发回一个ACK,确认序号为收到的序号加1(报文段5)。
和SYN一样。一个FIN将占用一个序号。
(3) server关闭client的连接,发送一个FIN给client(报文段6)。
(4) 客户段发回ACK报文确认。并将确认序号设置为收到序号加1(报文段7)。
CLOSED: 这个没什么好说的了,表示初始状态。
LISTEN: 这个也是很easy理解的一个状态。表示server端的某个SOCKET处 于监听状态,能够接受连接了。
SYN_RCVD: 这个状态表示接受到了SYN报文。在正常情况下,这个状态是server端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态。非常短暂,基本上用netstat你是非常难看到这样的状态的,除非你特意写了一个client測试程序。有益将三次TCP握手过程中最后一个ACK报文不予发送。因此这样的状态时,当收到client的ACK报文 后,它会进入到ESTABLISHED状态。
SYN_SENT: 这个状态与SYN_RCVD遥想呼应。当clientSOCKET运行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。
SYN_SENT状态表示client已发送SYN报文。
ESTABLISHED:这个easy理解了,表示连接已经建立了。
FIN_WAIT_1: 这个状态要好好解释一下,事实上FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的差别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。
而当对方回应ACK报文后,则进入到FIN_WAIT_2状态。当然在实际的正常情况下,不管对方何种情况下,都应该立即回应ACK报文,所以FIN_WAIT_1状态通常是比較难见到的。而FIN_WAIT_2状态还有时经常能够用netstat看到。
FIN_WAIT_2:上面已经详解了这样的状态,实际上FIN_WAIT_2状态下的SOCKET。表示半连接,也即有一方要求close连接,但另外还告诉对方,我临时还有点数据须要传送给你,稍后再关闭连接。
TIME_WAIT: 表示收到了对方的FIN报文。并发送出了ACK报文,就等2MSL后就可以回到CLOSED可用状态了。假设FIN_WAIT_1状态下。收到了对方同一时候带FIN标志和ACK标志的报文时,能够直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
CLOSING: 这样的状态比較特殊。实际情况中应该是非常少见,属于一种比較罕见的例外状态。
正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同一时候收到)对方的ACK报文,再收到对方的FIN报文。
可是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。
什么情况下会出现此种情况呢?事实上细想一下。也不难得出结论:那就是假设两方差点儿在同一时候close一个SOCKET的话。那么就出现了两方同一时候发送FIN报文的情况,也即会出现CLOSING状态,表示两方都正在关闭SOCKET连接。
CLOSE_WAIT: 这样的状态的含义事实上是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方。此时则进入到CLOSE_WAIT状态。接下来呢。实际上你真正须要考虑的事情是察看你是否还有数据发送给对方,假设没有的话,那么你也就能够close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下。须要完毕的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比較easy好理解的。它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即能够进入到CLOSED可用状态了。
补充:
a. 默认情况下(不改变socket选项)。当你调用close( or closesocket,下面说close不再反复)时。假设发送缓冲中还有数据,TCP会继续把数据发送完。
b. 发送了FIN仅仅是表示这端不能继续发送数据(应用层不能再调用send发送),可是还能够接收数据。
c. 应用层怎样知道对端关闭?通常。在最简单的堵塞模型中,当你调用recv时,假设返回0,则表示对端关闭。在这个时候通常的做法就是也调用close,那么TCP层就发送FIN。继续完毕四次握手。
假设你不调用close,那么对端就会处于FIN_WAIT_2状态,而本端则会处于CLOSE_WAIT状态。这个能够写代码试试。
d. 在非常多时候。TCP连接的断开都会由TCP层自己主动进行。比如你CTRL+C终止你的程序,TCP连接依旧会正常关闭。你能够写代码试试。
1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是由于服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后。它能够把ACK和SYN(ACK起应答作用。而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它只表示对方没有数据发送给你了。但未必你所有的数据都所有发送给对方了。所以你能够未必会立即会关闭SOCKET,也即你可能还须要发送一些数据给对方之后,再发送FIN报文给对方来表示你允许如今能够关闭连接了。所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
2、 为什么TIME_WAIT状态还须要等2MSL后才干返回到CLOSED状态?
什么是2MSL?MSL即Maximum Segment Lifetime,也就是报文最大生存时间,引用《TCP/IP具体解释》中的话:“它(MSL)是不论什么报文段被丢弃前在网络内的最长时间。”那么。2MSL也就是这个时间的2倍,当TCP连接完毕四个报文段的交换时,主动关闭的一方将继续等待一定时间(2-4分钟),即使两端的应用程序结束。比如在上面的telnet程序client关闭后。使用netstat查看的结果:
C:\>netstat -na | find "172.29.21.25"
TCP 172.29.132.60:2795 172.29.21.25:23 TIME_WAIT
为什么须要这个2MSL呢,
第一,尽管两方都允许关闭连接了,并且握手的4个报文也都协调和发送完成,按理能够直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);可是由于我们必需要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会由于超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
第二。报文可能会被混淆。意思是说。其它时候的连接可能会被当作本次的连接。直接引用《The TCP/IP Guide》的说法:The second is to provide a “buffering period” between the end of this connection and any subsequent ones. If not for this period, it is possible that packets from different connections could be mixed,
creating confusion.
当某个连接的一端处于TIME_WAIT状态时。该连接将不能再被使用。其实,对于我们比較有现实意义的是,这个port将不能再被使用。某个port处于TIME_WAIT状态(其实应该是这个连接)时,这意味着这个TCP连接并没有断开(全然断开),那么。假设你bind这个port,就会失败。对于server而言,假设server突然crash掉了,那么它将无法在2MSL内又一次启动,由于bind会失败。解决问题的一个方法就是设置socket的SO_REUSEADDR选项。这个选项意味着你能够重用一个地址。
当建立一个TCP连接时。server端会继续用原有port监听,同一时候用这个port与client通信。
而client默认情况下会使用一个随机port与server端的监听port通信。
有时候,为了server端的安全性,我们须要对client进行验证,即限定某个IP某个特定port的client。
client能够使用bind来使用特定的port。
对于server端,当设置了SO_REUSEADDR选项时。它能够在2MSL内启动并listen成功。可是对于client。当使用bind并设置SO_REUSEADDR时,假设在2MSL内启动,尽管bind会成功,可是在windows平台上connect会失败。而在linux上则不存在这个问题。(我的实验平台:winxp,
ubuntu7.10)
要解决windows平台的这个问题,能够设置SO_LINGER选项。SO_LINGER选项决定调用close时TCP的行为。SO_LINGER涉及到linger结构体,假设设置结构体中l_onoff为非0。l_linger为0,那么调用close时TCP连接会立马断开。TCP不会将发送缓冲中未发送的数据发送,而是马上发送一个RST报文给对方。这个时候TCP连接(关闭时)就不会进入TIME_WAIT状态。
如你所见。这样做尽管攻克了问题。可是并不安全。通过以上方式设置SO_LINGER状态,等同于设置SO_DONTLINGER状态。
当TCP连接发生一些物理上的意外情况时,比如网线断开,linux上的TCP实现会依旧觉得该连接有效,而windows则会在一定时间后返回错误信息。
这似乎能够通过设置SO_KEEPALIVE选项来解决,只是不知道这个选项是否对于全部平台都有效。
3. 为什么不能用两次握手进行连接?
我们知道。3次握手完毕两个重要的功能。既要两方做好发送数据的准备工作(两方都知道彼此已准备好),也要同意两方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
如今把三次握手改成仅须要两次握手。死锁是可能发生的。
作为样例。考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发送了确认应答分组。依照两次握手的协定,S觉得连接已经成功地建立了,能够開始发送数据分组。但是,C在S的应答分组在传输中被丢失的情况下,将不知道S是否已准备好。不知道S建立什么样的序列号。C甚至怀疑S是否收到自己的连接请求分组。在这样的情况下,C觉得连接还未建立成功,将忽略S发来的不论什么数据分组,仅仅等待连接确认应答分组。而S在发出的分组超时后,反复发送相同的分组。这样就形成了死锁。
4、为何ISN是随机的
DoS攻击
DoS攻击、DDoS攻击和DRDoS攻击相信大家已经早有耳闻了吧!DoS是Denial of Service的简写就是拒绝服务,而DDoS就是Distributed Denial of Service的简写就是分布式拒绝服务,而DRDoS就是Distributed Reflection Denial of Service的简写,这是分布反射式拒绝服务的意思。
只是这3中攻击方法最厉害的还是DDoS,那个DRDoS攻击尽管是新近出的一种攻击方法。但它仅仅是DDoS攻击的变形,它的唯一不同就是不用占据大量的“肉鸡”。
这三种方法都是利用TCP三次握手的漏洞进行攻击的。所以对它们的防御办法都是差点儿相同的。
DoS攻击是最早出现的,它的攻击方法说白了就是单挑,是比谁的机器性能好、速度快。可是如今的科技飞速发展。一般的站点主机都有十几台主机,并且各个主机的处理能力、内存大小和网络速度都有飞速的发展,有的网络带宽甚至超过了千兆级别。
这样我们的一对一单挑式攻击就没有什么作用了。搞不好自己的机子就会死掉。
举个这种攻击样例,假如你的机器每秒可以发送10个攻击用的数据包,而被你攻击的机器(性能、网络带宽都是顶尖的)每秒可以接受并处理100攻击数据包,那样的话,你的攻击就什么用处都没有了,并且很有死机的可能。要知道。你若是发送这种1Vs1的攻击,你的机器的CPU占用率是90%以上的,你的机器要是配置不够高的话,那你就死定了。
只是,科技在发展,黑客的技术也在发展。正所谓道高一尺,魔高一仗。
经过无数次当机,黑客们最终又找到一种新的DoS攻击方法。这就是DDoS攻击。它的原理说白了就是群殴。用好多的机器对目标机器一起发动 DoS攻击。但这不是非常多黑客一起參与的,这样的攻击仅仅是由一名黑客来操作的。这名黑客不是拥有非常多机器,他是通过他的机器在网络上占据非常多的“肉鸡”,而且控制这些“肉鸡”来发动DDoS攻击,要不然怎么叫做分布式呢。还是刚才的那个样例,你的机器每秒能发送10攻击数据包,而被攻击的机器每秒可以接受100的数据包。这样你的攻击肯定不会起作用。而你再用10台或很多其它的机器来对被攻击目标的机器进行攻击的话,嘿嘿!结果我就不说了。
DRDoS分布反射式拒绝服务攻击这是DDoS攻击的变形,它与DDoS的不同之处就是DrDoS不须要在攻击之前占据大量的“肉鸡”。它的攻击原理和Smurf攻击原理相近,只是DRDoS是能够在广域网上进行的。而Smurf攻击是在局域网进行的。它的作用原理是基于广播地址与回应请求的。一台计算机向还有一台计算机发送一些特殊的数据包如ping请求时,会接到它的回应;假设向本网络的广播地址发送请求包,实际上会到达网络上全部的计算机,这时就会得到全部计算机的回应。
这些回应是须要被接收的计算机处理的,每处理一个就要占用一份系统资源,假设同一时候接到网络上全部计算机的回应,接收方的系统是有可能吃不消的。就象遭到了DDoS攻击一样。只是是没有人笨到自己攻击自己。只是这样的方法被黑客加以改进就具有非常大的威力了。
黑客向广播地址发送请求包。全部的计算机得到请求后,却不会把回应发到黑客那里,而是发到被攻击主机。这是由于黑客冒充了被攻击主机。黑客发送请求包所用的软件是能够伪造源地址的。接到伪造数据包的主机会依据源地址把回应发出去,这当然就是被攻击主机的地址。黑客同一时候还会把发送请求包的时间间隔减小,这样在短时间能发出大量的请求包,使被攻击主机接到从被欺骗计算机那里传来的洪水般的回应,就像遭到了DDoS攻击导致系统崩溃。骇客借助了网络中全部计算机来攻击受害者,而不须要事先去占据这些被欺骗的主机,这就是Smurf攻击。
而DRDoS攻击正是这个原理,黑客相同利用特殊的发包工具,首先把伪造了源地址的SYN连接请求包发送到那些被欺骗的计算机上,依据TCP三次握手的规则,这些计算机会向源IP发出SYN+ACK或RST包来响应这个请求。同Smurf攻击一样。黑客所发送的请求包的源IP地址是被攻击主机的地址,这样受欺骗的主机就都会把回应发到被攻击主机处,造成被攻击主机忙于处理这些回应而瘫痪。
解释:
SYN:(Synchronize sequence numbers)用来建立连接,在连接请求中,SYN=1,ACK=0。连接响应时,SYN=1。ACK=1。即。SYN和ACK来区分Connection Request和Connection Accepted。
RST:(Reset the connection)用于复位因某种原因引起出现的错误连接,也用来拒绝非法数据和请求。
假设接收到RST位时候,通常发生了某些错误。
ACK:(Acknowledgment field significant)置1时表示确认号(Acknowledgment Number)为合法。为0的时候表示数据段不包括确认信息,确认号被忽略。
设我们要准备建立连接。server正处于正常的接听状态。
第一步:我们也就是client发送一个带SYN位的请求,向server表示须要连接。如果请求包的序列号为10,那么则为:SYN=10,ACK=0。然后等待server的回应。
第二步:server接收到这种请求包后,查看是否在接听的是指定的port,假设不是就发送RST=1回应。拒绝建立连接。假设接收请求包,那么server发送确认回应。SYN为server的一个内码,假设为100。ACK位则是client的请求序号加1。本例中发送的数据是:SYN=100。ACK=11,用这种数据回应给我们。向我们表示,server连接已经准备好了,等待我们的确认。这时我们接收到回应后。分析得到的信息,准备发送确认连接信号到server。
第三步:我们发送确认建立连接的信息给server。确认信息的SYN位是server发送的ACK位。ACK位是server发送的SYN位加1。
即:SYN=11。ACK=101。
这样我们的连接就建立起来了。
DDoS到底怎样攻击?
眼下最流行也是最好用的攻击方法就是使用SYN-Flood进行攻击,SYN-Flood也就是SYN洪水攻击。SYN-Flood不会完毕TCP三次握手的第三步,也就是不发送确认连接的信息给server。这样,server无法完毕第三次握手,但server不会马上放弃。server会不停的重试并等待一定的时间后放弃这个未完毕的连接,这段时间叫做SYN timeout,这段时间大约30秒-2分钟左右。若是一个用户在连接时出现故障导致server的一个线程等待1分钟并非什么大不了的问题。可是若有人用特殊的软件大量模拟这样的情况。那后果就可想而知了。
一个server若是处理这些大量的半连接信息而消耗大量的系统资源和网络带宽。这样server就不会再有空余去处理普通用户的正常请求(由于客户的正常请求比率非常小)。这样这个server就无法工作了,这样的攻击就叫做:SYN-Flood攻击。
到眼下为止,进行DDoS攻击的防御还是比較困难的。首先,这样的攻击的特点是它利用了TCP/IP协议的漏洞。除非你不用TCP/IP,才有可能全然抵御住DDoS攻击。
只是这不等于我们就没有办法阻挡DDoS攻击,我们能够尽力来降低DDoS的攻击。
以下就是一些防御方法:
1.确保server的系统文件是最新的版本号。并及时更新系统补丁。
2.关闭不必要的服务。
3.限制同一时候打开的SYN半连接数目。
4.缩短SYN半连接的time out 时间。
5.正确设置防火墙
6.禁止对主机的非开放服务的訪问
7.限制特定IP地址的訪问
8.启用防火墙的防DDoS的属性
9.严格限制对外开放的server的向外訪问
10.执行port映射程序祸port扫描程序,要认真检查特权port和非特权port。
11.认真检查网络设备和主机/server系统的日志。仅仅要日志出现漏洞或是时间变更,那这台机器就可能遭到了攻击。
12.限制在防火墙外与网络文件共享。
这样会给黑客截取系统文件的机会,主机的信息暴露给黑客,无疑是给了对方入侵的机会。