以太网头介绍(IP头、TCP头、UDP头)
文章目录QT 常用快捷键QT 常用快捷键Ctrl + Shitf +F 快捷键方式搜索,具体搜索选项可以根据自己需要选择
文章目录
一、以太网帧格式
-
以太网发布标准有哪些,是哪些机构发布的
1.1 MAC 地址头
- https://juejin.cn/post/7087218595159080968
MAC帧是数据帧的一种。而所谓数据帧,就是数据链路层的协议数据单元,它包括三部分:帧头,数据部分,帧尾。其中,帧头和帧尾包含一些必要的控制信息,比如同步信息、地址信息、差错控制信息等;数据部分则包含网络层传下来的数据,比如ip数据包。
目前,有四种不同格式的以太网帧在使用,它们分别是:
Ethernet II即DIX 2.0:Xerox与DEC、Intel在1982年制定的以太网标准帧格式。Cisco名称为:ARPA。
Ethernet 802.3 raw:Novell在1983年公布的专用以太网标准帧格式。Cisco名称为:Novell-Ether。
Ethernet 802.3 SAP:IEEE在1985年公布的Ethernet 802.3的SAP版本以太网帧格式。Cisco名称为:SAP。
Ethernet 802.3 SNAP:IEEE在1985年公布的Ethernet 802.3的SNAP版本以太网帧格式。Cisco名称为:SNAP。
Ethernet II和IEEE802.3的帧格式比较类似,主要的不同点在于前者定义的2字节为包类型,而后者定义的2字节为的长度;所幸的是,后者定义的有效长度值与前者定义的有效类型值无一相同,这样就容易区分两种帧格式了。如果值大于 1500(0x05DC),说明是以太网类型字段,EthernetII 帧格式。如果值小于等于1500,说明是长度字段,IEEE802.3 帧格式。因此类型字段值最小的是 0x0600。而长度最大为 1500。
/*数据帧定义,头14个字节,尾4个字节*/
typedef struct _MAC_FRAME_HEADER
{
char m_cDstMacAddress[6]; //目的mac地址
char m_cSrcMacAddress[6]; //源mac地址
short m_cType; //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp
}__attribute__((packed))MAC_FRAME_HEADER,*PMAC_FRAME_HEADER;
typedef struct _MAC_FRAME_TAIL
{
unsigned int m_sCheckSum; //数据帧尾校验和
}__attribute__((packed))MAC_FRAME_TAIL, *PMAC_FRAME_TAIL;
- 以太类帧型:占16个比特,表示协议类型。
- 0800:IP协议
- 0806:ARP 协议
- 86DD:IPv6
- 0000-05DC:IEEE 802.3
1.2 IP头结构的定义
- 固定头:20 个字节
- 变长头:20 + 额外最多40字节
/IP头定义,共20个字节/
typedef struct _IP_HEADER
{
char m_cVersionAndHeaderLen; //版本信息(前4位),头长度(后4位)
char m_cTypeOfService; // 服务类型8位
short m_sTotalLenOfPacket; //数据包长度
short m_sPacketID; //数据包标识
short m_sSliceinfo; //分片使用
char m_cTTL; //存活时间
char m_cTypeOfProtocol; //协议类型
short m_sCheckSum; //校验和
unsigned int m_uiSourIp; //源ip
unsigned int m_uiDestIp; //目的ip
} __attribute__((packed))IP_HEADER, *PIP_HEADER ;
IP 头字段说明:
- 版本(Version)字段:占4比特。用来表明IP协议实现的版本号,当前一般为IPv4,即0100。
- 首部长度(Internet Header Length,IHL)字段:占4比特。因为头部长度不固定(Option可选部分不固定),所以需要标识该分组的头部长度多少,用4bit表示,以4byte为单位,取值范围:5-15,即20(54)-60(154)byte(其他字段也是类似的计算方式,因为bit位是不够表示该字段的值)
- 服务类型(Type of Service ,TOS)字段:占8比特。其中前3比特为优先权子字段(Precedence,现已被忽略)。第8比特保留未用。第4至第7比特分别代表延迟、吞吐量、可靠性和花费。当它们取值为1时分别代表要求最小时延、最大吞吐量、最高可靠性和最小费用。这4比特的服务类型中只能置其中1比特为1。可以全为0,若全为0则表示一般服务。服务类型字段声明了数据报被网络系统传输时可以被怎样处理。例如:TELNET协议可能要求有最小的延迟,FTP协议(数据)可能要求有最大吞吐量,SNMP协议可能要求有最高可靠性,NNTP(Network News Transfer Protocol,网络新闻传输协议)可能要求最小费用,而ICMP协议可能无特殊要求(4比特全为0)。实际上,大部分主机会忽略这个字段,但一些动态路由协议如OSPF(Open Shortest Path First Protocol)、IS-IS(Intermediate System to Intermediate System Protocol)可以根据这些字段的值进行路由决策。RFC2474的ToS取消了IP precedence字段而使用了DSCP,QoS里有描述,给QoS用来打标签。TOS字段历史:
- 总长度:占16比特。指明整个数据报的长度(以字节为单位,含头长度)。最大长度为65535字节。可用总长度减去头部长度获得实际报文数据的长度,取值范围0-65535byte,链路只允许1500byte,所以一般都需要MTU分片 。
- 标志字段:占16比特。用来唯一地标识主机发送的每一份数据报。通常每发一份报文,它的值会加1。通常与标记字段和分片偏移字段一起用于IP报文的分片。当原始报文大小超过MTU,那么就必须将原始数据进行分片。每个被分片的报文大小不得超过MTU,而这个字段还将在同一原始文件被分片的报文上打上相同的标记,以便接收设备可以识别出属于同一个报文的分片,“类似于进程号”,有时候电信会用他来识别流量是否是同一台主机(因为做了PAT后源ip都是一样的,鸡贼!)
- 注意:Ethernet以太网跟802.3以太网有所区别,802.3是由IEEE指定的标准,比较复杂用的比较少,网卡一般两种都支持。IP数据包的MTU值在各种物理线路环境下对应的MTU取值:(注意:不包含帧头和尾)
- 标志位字段:占3比特。标志一份数据报是否要求分段。
- 第1位没有被使用。
- 第2位D是不分片位(DF),Do not fragment,顾名思义,不要分片,当DF位设置为1时,表示路由器不能对报文进行分片处理。
- 第3位M表示还有后继分片(MF),More fragment,多分片,当路由器对报分进行分片时,除了最后一个分片的MF位设置为0外,其他所有分片的MF位均设置1,以便接收者直到收到MF位为0的分片为止
- 段偏移字段:占13比特。如果一份数据报要求分段的话,此字段指明该段偏移距原始数据报开始的位置。
- 生存期(TTL:Time to Live)字段:占8比特。用来设置数据报最多可以经过的路由器数。由发送数据的源主机设置,通常为32、64(win7)、128、255(linux)等。每经过一个路由器,其值减1,直到0时该数据报被丢弃。
- 协议字段:占8比特。指明IP层所封装的上层协议类型,如ICMP(1)、IGMP(2) 、TCP(6)、UDP(17)等。
- 头部校验和字段:占16比特。内容是根据IP头部计算得到的校验和码。计算方法是:对头部中每个16比特进行二进制反码求和。(和ICMP、IGMP、TCP、UDP不同,IP不对头部后的数据进行校验)。
- 源IP地址、目标IP地址字段:各占32比特。用来标明发送IP数据报文的源主机地址和接收IP报文的目标主机地址。
- 可选项字段:占32比特。用来定义一些任选项:如记录路径、时间戳等。这些选项很少被使用,同时并不是所有主机和路由器都支持这些选项。可选项字段的长度必须是32比特的整数倍,如果不足,必须填充0以达到此长度要求。
1.2.2 抓包图示
1.3 TCP头结构定义
/*TCP头定义,共20个字节*/
typedef struct _TCP_HEADER
{
short m_sSourPort; // 源端口号16bit
short m_sDestPort; // 目的端口号16bit
unsigned int m_uiSequNum; // 序列号32bit
unsigned int m_uiAcknowledgeNum; // 确认号32bit
short m_sHeaderLenAndFlag; // 前4位:TCP头长度;中6位:保留;后6位:标志位
short m_sWindowSize; // 窗口大小16bit
short m_sCheckSum; // 检验和16bit
short m_surgentPointer; // 紧急数据偏移量16bit
}__attribute__((packed))TCP_HEADER, *PTCP_HEADER;
/*TCP头中的选项数据部分定义
kind = 1表示 无操作NOP,无后面的部分
kind = 2表示 maximum segment,后面的Length就是maximum segment选项的长度(以byte为单位,1+1+内容部分长度)
kind = 3表示 windows scale,后面的Length就是 windows scale选项的长度(以byte为单位,1+1+内容部分长度)
kind = 4表示 SACK permitted Length为2,没有内容部分
kind = 5表示这是一个SACK包 Length为2,没有内容部分
kind = 8表示时间戳,Length为10,含8个字节的时间戳
*/
typedef struct _TCP_OPTIONS
{
char m_ckind; //kind(8bit)
char m_cLength; //Length(8bit,整个选项的长度,包含前两部分)
char m_cContext[32]; //内容(如果有的话)
}__attribute__((packed))TCP_OPTIONS, *PTCP_OPTIONS;
-
源端口:源端口和IP地址的作用是标识报文的返回地址。
-
目的端口:端口指明接收方计算机上的应用程序接口。TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。
-
序号和确认号:是TCP可靠传输的关键部分。
- 序号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节一个序号。e.g.一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。
- 确认号,即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN报文的ACK标志位为0。
-
数据偏移/首部长度:4bits。由于首部可能含有可选项内容,因此TCP报头的长度是不确定的,报头不包含任何任选字段则长度为20字节,4位首部长度字段所能表示的最大值为1111,转化为10进制为15,15*32/8 = 60,故报头最大长度为60字节。首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。
-
保留:为将来定义新的用途保留,现在一般置0。
-
控制位:URG ACK PSH RST SYN FIN,共6个,每一个标志位表示一个控制功能。
- URG:紧急指针标志,为1时表示紧急指针有效,为0则忽略紧急指针。
- ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。
- PSH:push标志,为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
- RST:重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。
- SYN:同步序号,用于建立连接过程,在连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。
- FIN:finish标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流。
-
窗口:滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小时一个16bit字段,因而窗口大小最大为65535。
-
校验和:奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
-
紧急指针:只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
-
选项和填充:最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size),每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志为1的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。
-
数据部分: TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。
1.4 UDP头结构定义
/*UDP头定义,共8个字节*/
typedef struct _UDP_HEADER
{
unsigned short m_usSourPort; // 源端口号16bit
unsigned short m_usDestPort; // 目的端口号16bit
unsigned short m_usLength; // 数据包长度16bit
unsigned short m_usCheckSum; // 校验和16bit
}__attribute__((packed))UDP_HEADER, *PUDP_HEADER;
- 端口号:用来表示发送和接受进程。由于 IP层已经把I P数据报分配给TCP或UDP(根据I P首部中协议字段值),因此TCP端口号由TCP来查看,而 UDP端口号由UDP来查看。TCP端口号与UDP端口号是相互独立的。
- 长度:UDP长度字段指的是UDP首部和UDP数据的字节长度。该字段的最小值为 8字节(发送一份0字节的UDP数据报是 OK)
- 检验和:UDP检验和是一个端到端的检验和。它由发送端计算,然后由接收端验证。其目的是为了发现UDP首部和数据在发送端到接收端之间发生的任何改动。整个UDP报文头和UDP所带的数据的校验和(也包括伪报文头)。伪报文头不包括在真正的UDP报文头中,但是它可以保证UDP数据被正确的主机收到了。因在校验和中加入了伪头标,故ICMP除能防止单纯数据差错之外,对IP分组也具有保护作用。
二、wireshark TCP常见异常报文分析
2.1 Tcp Previous segment not captured
- Wireshark抓包 [Tcp Previous Segment Not captured][Tcp Out-Of-Order][Tcp Spurious Retransmissiion]
- wireshark TCP常见异常报文分析
Wireshark抓包时,除了TCP协议的三次握手建立连接、数据收发和四次握手断开连接外,还经常能看到如下几种不太常见的报文,具体包括:
1.Tcp Previous Segment Not captured
2.Tcp Out-Of-Order
3.Tcp Dup Ack 12345#1
4.Tcp Spurious Retransmissiion
5.Tcp Retransmission
其中1、2、3会相伴出现,3、4、5会相伴出现。
- 问题:乱序、丢包、重传
- 对应第一种情况是由于由于TCP数据被分块后,传输过程中经过不同的路径,到达目的端时乱序,出现后发而先至的情况,此时目的端会显示【Tcp Previous Segment Not captured】,并且用【Tcp Dup Ack 12345#1】对前一个包再次进行确认,先发而后至的包到达目的端时,会显示【Tcp Out-Of-Order】;
- 对应第二种情况是由于网络不稳定,源端发送数据后,目的端进行了确认,但源端并未在规定的时间内收到确认,所以会重新发送,目的端对重新发送的报文会显示为【Tcp Spurious Retransmissiion】,并且用【Tcp Dup Ack 12345#1】确认。
- 这两种情况出现属于正常情况,TCP的超时重传机制和乱序重排可以保证TCP的按序可靠传输。
第一种情况乱序
乱序与丢包
1、[TCP Previous segment not captured]
[TCP Previous segment not captured]报文指的是在TCP发送端传输过程中,该Seq前的报文缺失了。一般在网络拥塞的情况下,造成TCP报文乱序、丢包时,会出现该标志。
需要注意的是,[TCP Previous segment not captured]解析文字是wireshark添加的标记,并非TCP报文内容
例子:
流媒体服务器39.135.135.81,端口80,发送序号Seq=147154的包,长度Len=1360,那么下一个数据包序号应该为Seq=147154+1360=148514,可以看到客户端请求的也是Ack=148514。而服务器下一个包序号为Seq=149874,中间的包丢失了。
2、[TCP Out-Of-Order]
[TCP Out-Of-Order]指的是TCP发送端传输过程中报文乱序了。
例子:
继续上面的包分析,因为208142包序号为Seq=148514,而前一个序号为Seq=149874,故有此错误标志。
Seq=148514实际是208139包的响应,因为网络拥塞的情况下,TCP包不能按顺序到达,所以出现[TCP Previous segment not captured] 和 [TCP Out-Of-Order]标志。
3、[TCP dup ack XXX#X]
[TCP dup ack XXX#X]表示第几次重新请求某一个包,#前XXX表示第几个包(不是Seq),#后的X表示第几次请求。丢包或者乱序的情况下,会出现该标志。
例子:下图表示客户端一直请求101261的包。
2.3 TCP Window (TCP ZeroWindow 与 TCP window Full)
问题:
- 一直处于 TCP ZeroWindow 状态会怎样?
1、[TCP ZeroWindow]
作为接收方发出现的标志,表示接收缓冲区已经满了,此时发送方不能再发送数据,一般会做流控调整。接收窗口,也就是接收缓冲区win=xxx ,告诉对方接收窗口大小。
例子:
传输过程中,接收方TCP窗口满了,win=0,wireshark会打上[TCP ZeroWindow]标签。
TCP ZeroWindow 是因为缓存超过65536字节了吗
不完全正确。TCP ZeroWindow 是指接收方窗口大小为0,表示接收方暂时无法接收更多的数据。这可能是因为接收方的接收缓冲区已满,但不一定是因为缓存超过了65536字节。接收方窗口大小取决于接收方的可用缓冲区大小,这个大小是由接收方主机的操作系统决定的,并不一定固定为65536字节。
当接收方窗口为0时,发送方会停止发送数据,以避免数据堆积在网络中。一旦接收方的缓冲区有足够的空间,它会发送窗口更新通知给发送方,以便发送方可以继续发送数据。
需要注意的是,TCP ZeroWindow 并不一定意味着数据丢失,只是暂时的数据阻塞。一旦接收方的窗口大小恢复正常,数据传输就会继续进行。
2、[TCP window update]
当接收端接收窗口大小发生变化,可以接收数据了,则有该标志。
例子:
接收方消耗缓冲数据后,更新TCP窗口,,可以看到从win=0逐渐变大,这时wireshark会打上[TCP window update]标签。
3、[TCP window Full]
作为发送方的标识,当前发送包的大小已经超过了接收端窗口大小,wireshark会打上此标识,标识不能在发送。
例子:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)