ipv4包头
// IPv4 header in iphdr.h
ntypedef struct ip_hdr
{
unsigned char ip_verlen; // 4-bit IPv4 version
// 4-bit header length (in 32-bit words)
unsigned char ip_tos; // IP type of service
unsigned short ip_totallength; // Total length
unsigned short ip_id; // Unique identifier
unsigned short ip_offset; // Fragment offset field
unsigned char ip_ttl; // Time to live
unsigned char ip_protocol; // Protocol(TCP,UDP etc)
unsigned short ip_checksum; // IP checksum
unsigned int ip_srcaddr; // Source address
unsigned int ip_destaddr; // Source address
} IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR;
// IPv4 option header
ntypedef struct ipv4_option_hdr
{
unsigned char opt_code; // option type
unsigned char opt_len; // length of the option header
unsigned char opt_ptr; // offset into options
unsigned long opt_addr[9]; // list of IPv4 addresses
} IPV4_OPTION_HDR, *PIPV4_OPTION_HDR, FAR *LPIPV4_OPTION_HDR;
版本:4位长。记录了数据报对应的协议版本号。当前的IP协议有两个版本:IPV4 和IPV6。
IHL:4位长。代表头部的总长度,以32位为一个单位。
服务类型:8位长。使主机可以告诉子网它想要什么样的服务。如下图所示,服务类型域又分为了5个部分。优先权字段是标志优先级的;三个标志位分别代表延迟、吞吐量、可靠性。
总长:16位。指头部和数据的总长。最大长度是65535个字节。
标识:16位。通过它使目的主机判断新来的分段属于哪个分组,所有属于同一分组的分段包含同样的标识值。
DF:代表不要分段。它命令路由器不要将数据报分段,因为目的端不能重组分段。
MF:代表还有进一步的分段,用它来标志是否所有的分组都已到达。除了最后一个分段的所有分段都设置了这一位。
分段偏移:13位。标明分段在当前数据报的什么位置。
生命期:8位。用来限制分组生命周期的计数器。它在每个节点中都递减,而且当在一个路由器中排队时可以倍数递减。
协议:8位。说明将分组发送给那个传输进程,如TCP、UDP等。
头校验和:16位。仅用来校验头部。
源地址: 32位。产生IP数据报的源主机IP地址。
目的地址:32位。IP数据报的目的主机的IP地址。
可选项:是变长的。每个可选项用一个字节标明内容。有些可选项还跟有一字节的可选项长度字段,其后是一个或多个数据字节。现在已定义了安全性、严格的源路由选择、松的源路由选择、记录路由和时间标记五个可选项。但不是所有的路由器都支持全部5个可选项。
安全性选项说明了信息的安全程度。
ipv6头
// IPv6 protocol header
typedef struct ipv6_hdr
{
unsigned long ipv6_vertcflow; // 4-bit IPv6 version
// 8-bit traffic class
// 20-bit flow label
unsigned short ipv6_payloadlen; // payload length
unsigned char ipv6_nexthdr; // next header protocol value
unsigned char ipv6_hoplimit; // TTL
struct in6_addr ipv6_srcaddr; // Source address
struct in6_addr ipv6_destaddr; // Destination address
} IPV6_HDR, *PIPV6_HDR, FAR * LPIPV6_HDR;
// IPv6 fragment header
typedef struct ipv6_fragment_hdr
{
unsigned char ipv6_frag_nexthdr;
unsigned char ipv6_frag_reserved;
unsigned short ipv6_frag_offset;
unsigned long ipv6_frag_id;
} IPV6_FRAGMENT_HDR, *PIPV6_FRAGMENT_HDR, FAR * LPIPV6_FRAGMENT_HDR;
对比之下我们发现尽管这些头字段中有一些与 IPv6 头类似,但其中真正完全保持不变的只有第一个字段,即版本字段,因为在同一条线路上传输时,必须保证 IPv4和 IPv6 的兼容性。下一个字段,即包头长度,则与 IPv6 无关,因为 IPv6 头是固定长度,IPv4 中需要这个字段是因为它的包头可能在 20 字节到 40 字节间变化。服务类型字段与 IPv6 的流类别字段相似,但 TOS 的位置比该字段要靠后一些,而且在具体实现中也没有广泛应用。下一个字段是数据报长度,后来发展成了 IPv6 中的净荷长度。IPv6 的净荷长度中包含了扩展头,而 IPv4 数据报长度字段中则指明包含包头在内的整个数据报的长度。这样一来,在 IPv4 中,路由器可以通过将数据报长度减去包头长度来计算包的净荷长度,而在 IPv6 中则无须这种计算。
后面的三个字段是数据报 I D、分段标志和分段偏移值,它们都用于 IPv4 数据报的分段。 由于 IPv6 中由源结点取代中间路由器来进行分段,这些字段在 IPv6 中变得不重要,并被 IPv6 从包头中去掉了。而生存期字段,正如上面所述,变成了跳极限字段。生存期字段最初表示的是一个包穿越 Internet 时以秒为单位的存在时间的上限。如果生存期计数值变为0,该包将被丢弃。其原因是包可能会存在于循环路由中,如果没有方法让它消失,它可能会一直选路(或者直到网络崩溃为止)。在最初的规范中要求路由器根据转发包的时间与收到包的时间的差值(以秒为单位) 来减小生存期的值。在实际情况中,大部分路由器都设计为每次对该值减1,而不是计算路由器上真正的处理时间。
协议字段,如前所述,指出在 IPv4 包中封装的高层协议类型。各协议对应的数值在最新版本的 RFC (现在是 RFC 1700)中可以查到。这个字段后来发展成为 IPv6 中的下一个头字段,其中定义了下一个头是一个扩展头字段还是另一层的协议头。
由于如 TCP 和 UDP 等高层协议均计算头的校验和, IPv4 头校验显得有些多余,因此这个字段在 IPv6 中已消失。对于那些真的需要对内容进行身份验证的应用, IPv6 中提供了身份验证头。
IPv6 中仍然保留了 32 位的 IPv4 源地址和目的地址,但将它们扩展为 128 位。而I P选项字段则已经彻底消失,取而代之的是 IPv6 扩展头。
流标签(flow label): IPv4 通常被描述为无连接协议。就像任何一个包交换网络一样, I Pv4 设计为让每个包找到自己的路径以到达其目的地。每个包都分别处理,而结果是两个从相同数据源发往相同目的地的包可以采用完全不同的路由来穿越整个网络。这对于适应网络突发事件来说是个好办法,因为突发事件意味着任何一条路由都可能在任何时间出现故障,但只要两主机间存在某些路由则可以进行数据的交互。但是,这种方法的效率可能不太高,尤其是当包并不是孤立的,且实际上是两个通信系统间的业务流的一部分时。进一步考虑一个包流从一台主机发往另一主机时在它所经过的路径上将发生的事情:每个中间路由器对每个包的处理将导致在链路上轻微地增加延时。对于类似文件传输或终端仿真之类的大部分传统 Internet 应用,延时只会带来一点不方便而已,但对于一些提供互操作的音频和视频应用而言,即使只是增加一点点延时也会显著降低服务质量。对每个 IPv4 包均进行单独处理带来的另一个问题在于难以把特定的业务流指定到较低代价的链路上。例如,电子邮件的传输优先级不高,并且不是实时应用,但 IPv4 网络管理员却没有简单的办法来标识这些包,把它们传输到较低开销的 Internet 链路,并为实时应用保留较高开销的链路。IPv6 中定义的流的概念将有助于解决类似问题。IPv6 头字段中的流标签把单个包作为一系列源地址和目的地址相同的包流的一部分。同一个流中的所有包具有相同的流标签。
扩展头: IPv4 选项的问题在于改变了 IP 头的大小,因此更像一个“特例”,即需要特别的处理。路由器必须优化其性能,这意味着将为最普遍的包进行最佳性能的优化。这使得 IPv4 选项引发一个路由器把包含该选项的包搁置一边,等到有时间的时候再进行处理。IPv6 中实现的扩展头可以消灭或至少大量减少选项带来的对性能的冲击。通过把选项从IP 头中搬到净荷中,路由器可以像转发无选项包一样来转发包含选项的包。除了规定必须由每个转发路由器进行处理的逐跳选项之外, IPv6 包中的选项对于中间路由器而言是不可见的。
可用的选项:除了减少 IPv6 包转发时选项的影响外, IPv6 规范使得对于新的扩展和选项的定义变得更加简单。在需要的时候可能还会定义其他的选项和扩展。本节仅列出已定义的扩展,而对于扩展头和选项的使用暂不介绍
IPv6 定义了如下选项扩展:
• 逐跳选项头:此扩展头必须紧随在 IPv6 头之后。它包含包所经路径上的每个节点都必须检查的选项数据。由于它需要每个中间路由器进行处理,逐跳选项只有在绝对必要的时
候才会出现。到目前为止,已经定义了两个选项:巨型净荷选项和路由器提示选项。巨型净荷选项指明包的净荷长度超过 IPv6 的 16 位净荷长度字段。只要包的净荷超过 65535 字节(其中包括逐跳选项头),就必须包含该选项。如果节点不能转发该包,则必须回送 一个 ICMPv6 出错报文。路由器提示选项用来通知路由器, IPv6 数据报中的信息希望能够得到中间路由器的查看和处理,即使这个包是发给其他某个节点的(例如,包含带宽预留协议信息的控制数据报)。
• 选路头:此扩展头指明包在到达目的地途中将经过哪些节点。它包含包沿途经过的各节点的地址列表。IPv6 头的最初目的地址是路由头的一系列地址中的第一个地址,而不是包的最终目的地址。此地址对应的节点接收到该包之后,对 IPv6 头和选路头进行处理,并把包发送到选路头列表中的第二个地址。如此继续,直到包到达其最终目的地。
• 分段头:此扩展头包含一个分段偏移值、一个“更多段”标志和一个标识符字段。用于源节点对长度超出源端和目的端路径 MTU 的包进行分段。
• 目的地选项头:此扩展头代替了 IPv4 选项字段。目前,唯一定义的目的地选项是在需要时把选项填充为 64 位的整数倍。此扩展头可以用来携带由目的地节点检查的信息。
• 身份验证头( AH ):此扩展头提供了一种机制,对 IPv6 头、扩展头和净荷的某些部分进行加密的校验和的计算。
• 封装安全性净荷( ESP )头:这是最后一个扩展头,不进行加密。它指明剩余的净荷已经加密,并为已获得授权的目的节点提供足够的解密信息。
下面我们对比一下ICMPv4和ICMPv6:他们在头文件中的描述如下
// ICMPv4 header in iphdr.h
typedef struct icmp_hdr
{
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short icmp_checksum;
unsigned short icmp_id;
unsigned short icmp_sequence;
} ICMP_HDR, *PICMP_HDR, FAR *LPICMP_HDR;
// ICMPv6 header
typedef struct icmpv6_hdr
{
unsigned char icmp6_type;
unsigned char icmp6_code;
unsigned short icmp6_checksum;
} ICMPV6_HDR;
// ICMPv6 echo request body
typedef struct icmpv6_echo_request
{
unsigned short icmp6_echo_id;
unsigned short icmp6_echo_sequence;
} ICMPV6_ECHO_REQUEST;
可以看出ICMPv6并没有对ICMPv4的定义进行更改,只是将id和sequence独立出来作为另一个结构,当ICMP需要请求回送信息时将被填充