1)版本号:占用4位二进制数,表示该IP数据报使用的IP协议版本。目前Internet中使用的主要是TCP/IP协议族中版本号为4的IP协议。
2)头长度:占用4位二进制位,此域指出整个报头的长度(包括选项),该长度是以32位二进制数为一个计数单位的,接收端通过此域可以计算出报头在何处结束及从何处开始读数据。普通IP数据报(没有任何选项)该字段的值是5(即20个字节的长度)。
3)服务类型(TOS、type of service):占用8位二进制位,用于规定本数据报的处理方式。
4)总长度:占用16位二进制位,总长度字段是指整个IP数据报的长度(报头区+数据区),以字节为单位。利用头部长度字段和总长度字段就可以计算出IP数据报中数据内容的起始位置和长度。由于该字段长度为16位二进制数,因此理论上IP数据报最长可达65536个字节(事实上受物理网络的限制,要比这个数值小很多)。
5)生存时间(TTL,time to live):占用8位二进制位,它指定了数据报可以在网络中传输的最长时间。实际应用中把生存时间字段设置成了数据报可以经过的最大路由器数。TTL的初始值由源主机设置(通常为32、64、128或256),一旦经过一个处理它的路由器,它的值就减1。当该字段为0时,数据报就丢弃,并发送ICMP报文通知源主机,因此可以防止进入一个循环回路时,数据报无休止地传输下去。
6)上层协议标识(Protocol):占用8位二进制位,IP协议可以承载各种上层协议,目标端根据协议标识就可以把收到的IP数据报送到TCP或UDP等处理此报文的上层协议了。
7)校验和:占用16位二进制数,用于协议头数据有效性的校验,可以保证IP报头区在传输时的正确性和完整性。
8)源地址:占用32位二进制数,表示发送端IP地址。
9)目的地址:占用32位二进制数,表述目的端IP地址。
1)MTU:链路层的特性决定了数据帧的最大长度。
2)分片:
场景:
同一个网络上的两台主机之间通信时,该网络的MTU值是确定的,不存在分片问题。分片问题一般只存在于具有不同MTU值的互联网中。
定义:
把一个数据报为了适合网络传输而分成多个数据报的过程称为分片,被分片后的各个IP数据报可能经过不同的路径到达目标主机。
3)标志
DF: 0=可以分片 1=不可以分片,出错时发送ICMP
MF: 0=最后一个分片 1=还有更多的分片在后面
4)片偏移
占13位。片偏移指出:较长的分组在分片后,某片在原分组中的相对位置。也就是说,相对于用户数据字段的起点,该片
从何处开始。片偏移以8个字节为偏移单位。也就是说,每个分片的长度一定是8字节(64位)的整数倍。
目标计算机在处理这些分片报文的时候,会把先到的分片报文缓存起来,然后一直等待后续的分片报文,这个过程会消耗掉一部分内存,以及一些IP协议栈的数据结构。如果攻击者给目标计算机只发送一片分片报文,而不发送所有的分片报文,这样攻击者计算机便会一直等待(直到一个内部计时器到时),如果攻击者发送了大量的分片报文,就会消耗掉目标计算机的资源,而导致不能相应正常的IP报文,这也是一种DOS攻击。
所提供的服务:进程到进程的通信,基于字节流的,面向连接的,全双工的可靠的通信服务
第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
为什么是三次握手?
一句话,主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。
如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。
如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。
)1 为什么TIME_WAIT状态停留时间:2MSL?
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
)2 为什么建立连接是三次握手,关闭连接确是四次挥手呢?
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。
1)SYNACK定时器
TCP服务器在收到SYN请求后发送SYN|ACK响应,然后等待对端的ACK到来以完成三次握手。如果没有收到ACK,TCP应该重传SYN|ACK,这个功能由SYN-ACK定时器完成。
2)重传定时器
为了控制丢失的报文段或丢弃的报文段,也就是对报文段确认的等待时间。当TCP发送报文段时,就创建这个特定报文段的重传计时器,可能发生两种情况:若在计时器超时之前收到对报文段的确认,则撤销计时器;若在收到对特定报文段的确认之前计时器超时,则重传该报文,并把计时器复位。
3)保活计时器:keeplive timer
每当服务器收到客户的信息,就将keeplive timer复位,超时通常设置2小时,若服务器超过2小时还没有收到来自客户的信息,就发送探测报文段,若发送了10个探测报文段(没75秒发送一个)还没收到响应,则终止连接。
4)延迟ACK定时器
TCP延迟确认定时器是指在一个TCP连接中,当一方收到另一端的数据之后,并不是立马返回ACK进行确认。而是等待200ms(在linux-2.6.38内核实现中应该是40ms),如果这段时间内有新的数据要发往对方,本地将ACK和数据封装在一个数据包中一起发送,称作捎带确认机制。超时后即使没有新数据的话也要将ACK发给对方。
5)坚持计时器:persistent timer
专门为对付零窗口通知而设立的,解决ACK的丢失可能造成的死锁问题。
6)TIME_WAIT定时器:2MSL
1)功能:
1、保证数据的可靠传递:未确认的数据必须被发送方缓存起来
2、保证数据的有序传输:乱序的数据必须被接收方缓存起来
3、提供End-to-End的流控机制:发送方发送太快就必须阻塞等待
TCP并不是每一个报文段都会回复ACK的,可能会对两个报文段发送一个ACK,也可能会对多个报文段发送1个ACK【累计ACK】,比如说发送方有1/2/3 3个报文段,先发送了2,3 两个报文段,但是接收方期望收到1报文段,这个时候2,3报文段就只能放在缓存中等待报文1的空洞被填上,如果报文1,一直不来,报文2/3也将被丢弃,如果报文1来了,那么会发送一个ACK对这3个报文进行一次确认。
一个例子来说明一下滑动窗口的原理:
假设32~45 这些数据,是上层Application发送给TCP的,TCP将其分成四个Segment来发往internet
seg1 32~34 seg3 35~36 seg3 37~41 seg4 42~45 这四个片段,依次发送出去,此时假设接收端之接收到了seg1 seg2 seg4
此时接收端的行为是回复一个ACK包说明已经接收到了32~36的数据,并将seg4进行缓存(保证顺序,产生一个保存seg3 的hole)
发送端收到ACK之后,就会将32~36的数据包从发送并没有确认切到发送已经确认,提出窗口,这个时候窗口向右移动
假设接收端通告的Window Size仍然不变,此时窗口右移,产生一些新的空位,这些是接收端允许发送的范畴
对于丢失的seg3,如果超过一定时间,TCP就会重新传送(重传机制),重传成功会seg3 seg4一块被确认,不成功,seg4也将被丢弃
就是不断重复着上述的过程,随着窗口不断滑动,将真个数据流发送到接收端,实际上接收端的Window Size通告也是会变化的,接收端根据这个值来确定何时及发送多少数据,从对数据流进行流控。原理图如下图所示:
2)症状及改进算法(Nagle算法、Clark算法)
症状:
如果我们的应用程序一次产生1个字节的数据,而这个1个字节数据又以网络数据包的形式发送到远端服务器,那么就很容易导致网络由于太多的数据包而过载。比如,当用户使用Telnet连接到远程服务器时,每一次击键操作就会产生1个字节数据,进而发送出去一个数据包,所以,在典型情况下,传送一个只拥有1个字节有效数据的数据包,却要发费40个字节长包头(即ip头20字节+tcp头20字节)的额外开销,这种有效载荷(payload)利用率极其低下的情况被统称之为愚蠢窗口症候群(Silly Window Syndrome)
Nagle算法的改进在于(针对发送端):如果发送端欲多次发送包含少量字符的数据包(一般情况下,后面统一称长度小于MSS的数据包为小包,与此相对,称长度等于MSS的数据包为大包,为了某些对比说明,还有中包,即长度比小包长,但又不足一个MSS的包),则发送端会先将第一个小包发送出去,而将后面到达的少量字符数据都缓存起来而不立即发送,直到收到接收端对前一个数据包报文段的ACK确认、或当前字符属于紧急数据,或者积攒到了一定数量的数据(比如缓存的字符数据已经达到数据包报文段的最大长度)等多种情况才将其组成一个较大的数据包发送出去
Nagle算法步骤:
1、发送端把从应用层收到的第一个数据发送出去。
2、发送完第一个后,发送端缓冲数据并等待,直到:a 收到上一次的确认 ;b 积累到MSS大小的数据。
3、重复步骤2。
Clark算法(针对接收端)
Clark解决方法是只要有数据到达就发送确认,但宣布的窗口大小为零,直到或者缓存空间已能放入具有最大长度的报文段,或者缓存空间的一半已经空了。
Nagle算法与CORK算法区别:
Nagle算法的初衷:避免发送大量的小包,防止小包泛滥于网络,理想情况下,对于一个TCP连接而言,网络上每次只能一个小包存在。它更多的是端到端意义上的优化。
CORK算法的初衷:提高网络利用率,理想情况下,完全避免发送小包,仅仅发送满包以及不得不发的小包。
Nagle算法和CORK算法着眼点不一样,Nagle算法主要避免网络因为太多的小包(协议头的比例非常之大)而拥塞,而CORK算法则是为了提高网络的利用率,使得总体上协议头占用的比例尽可能的小。
为什么需要拥塞控制?
1、流控只简单地表明了接收方的处理能力,并不能代表中间网络的处理能力。
2、如果一开始把流控窗口内的数据全部发送出去。中间路由器可能一时处理不了如此多的突发流量
路由器处理不及时—>缓冲数据—>时延增大—>重传数据—>导致更多的数据处理不及时。
1)拥塞窗口
门限值:
实际发送窗口W=min(cwnd, rwnd)
如果接收方慢,W=rwnd
如果网络慢,那么W=cwnd
2)慢启动
慢启动的算法如下(cwnd全称Congestion Window):
1)连接建好的开始先初始化cwnd = 1,表明可以传一个MSS大小的数据。
2)每当收到一个ACK,cwnd++; 呈线性上升
3)每当过了一个RTT,cwnd = cwnd*2; 呈指数让升
4)还有一个ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”
3)拥塞避免
当cwnd >= ssthresh时,就会进入“拥塞避免算法”。一般来说ssthresh的值是65535,单位是字节,当cwnd达到这个值时后,算法如下:
1)收到一个ACK时,cwnd = cwnd + 1/cwnd
2)当每过一个RTT时,cwnd = cwnd + 1
这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。很明显,是一个线性上升的算法。
4)快重传
如果连续收到3个或以上的重复ACK,那么很有可能是有数据包丢失了
当收到3个重复ACK时的措施:
1、ssthresh=min(cwnd/2, 2)
2、cwnd=ssthresh+3
3、如果再收到重复的ACK,cwnd+=1MSS
4、如果收到新数据的ACK,那么cwnd=ssthresh,重新进入加法增大的过程
5)快恢复
1. 当发送发连续接收到三个确认时,就执行乘法减小算法,把慢启动开始门限(ssthresh)减半,但是接下来并不执行慢开始算法。
2. 此时不执行慢启动算法,而是把cwnd设置为ssthresh的一半, 然后执行拥塞避免算法,使拥塞窗口缓慢增大。
6)BIC算法
思想:二分搜索
算法步骤:
1、如果发生丢包的时候,窗口的大小是W1,那么要保持线路满载却不丢包,实际的窗口最大值应该在W1以下;
2、如果检测到发生丢包,并且已经将窗口乘性减到了W2,那么实际的窗口值应该在W2以上。
因此,在TCP快速恢复阶段过去之后,便开始在W2~W1这个区间内进行二分搜索,寻找窗口的实际最大值。于是定义W1为Wmax,定义W2为Wmin。每收到一个ACK的时候,便将窗口设置到Wmax和Wmin的中点,一直持续到接近Wmax。
3、当超过wmax之后,进入新的wmax探测过程。 超越Wmax之后,如何找到新的Wmax呢?也非常简单!既然度过了Wmax都没有丢包,说明新的Wmax还没有达到,此时BIC采取了一种非常简单直接的方法:按照逼近Wmax的路径倒回去,即采用与之对称的方案。
7)CUBIC算法
beta决定了整个曲线对称范围围成区域的高度,而k则控制了从起始窗口到达丢包窗口的时间,由于k与C成反比,那么C越大,则探测到最大窗口的时间越短,反之则越久。
特征:
提供给应用发送不可靠报文的选项,通常用于多播
无需连接的概念,提供快速的数据发送
没有流控和拥塞控制
应用:
TFTP、SNMP、DHCP、DNS、RIP、RTP
-i 参数指定监听网口
-c 参数指定监听的数据包数量
-s 参数指定监听数据包大小
-w 参数指定监听数据包写入文件
-n:对地址以数字方式显式,否则显式为主机名,也就是说-n选项不做主机名解析。
-nn:除了-n的作用外,还把端口显示为数值,否则显示端口服务名。
-X:输出包的头部数据,会以16进制和ASCII两种方式同时输出。
-XX:输出包的头部数据,会以16进制和ASCII两种方式同时输出,更详细。
-v:当分析和打印的时候,产生详细的输出。
-vv:产生比-v更详细的输出。
-vvv:产生比-vv更详细的输出。
tcpdump 支持的表达式:
否 : ! 或 not
与 : && 或 and
或 : || 或 or
协议 header 过滤规则:
proto[x:y] : 从第 x 个位置开始取 y 字节, ip[2:2] 表示取 IP 首部中的第 3,4 字节(x 从 0 开始计算);
proto[x:y] & z = 0 : proto[x:y] 的结果和 z 进行 与 运算, 匹配最终结果为 0的报文;
操作符包括: >, <, >=, <=, =, !=
UDP 过滤规则:
udp[0:2] source port
udp[2:2] destination port
udp[4:2] datagram length
udp[6:2] UDP checksum
1、如果要监听某几台主机数据包 例如10.10.10.10、20.20.20.20、30.30.30.30
tcpdump host 10.10.10.10 and \(20.20.20.20 or 30.30.30.30\)
2、如果想要获取主机210.27.48.1除了和主机210.27.48.2之外所有主机通信的ip包
tcpdump ip host 210.27.48.1 and ! 210.27.48.2
3、如果获取10.10.10.10:80发出去的数据包
tcpdump -i eth0 src host 10.10.10.10 and src port 80
4、如果获取发往10.10.10.10:80的数据包
tcpdump -i eth0 dst host 10.10.10.10 and dst port 80
5、只抓取syn包
tcpdump -i eth0 tcp[13]==2
6、只抓取fin包
tcpdump -i eth2 tcp[13]==1
7、只抓取synack包
tcpdump -i eth2 tcp[13]==18
8、抓取10.10.10.10:80的syn、synack包
tcpdump -i eth2 tcp[13]==2 or tcp[13]==18 and port 80 and host 10.10.10.10
实践内容:ping百度域名,将百度作为远程服务器,模拟实践过程如下
第一步:
ping www.baidu.com
第二步:拿到远程服务器IP
即:112.80.248.73
第三步:打开另一个终端,输入:
sudo tcpdump -S host 49.123.79.83 and 112.80.248.73 //49.123.79.83是本地IP,即:客户端IP