本文主要是介绍TCP/IP详解 卷1:协议 学习笔记 第六章 ICMP:Internet控制报文协议,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
ICMP是IP层的组成部分,用来传递差错报文和其他需要注意的信息,它通常被更高层的协议(TCP、UDP)使用,一些ICMP报文把差错返回给用户进程。
类型字段可以有15个不同值,用来描述ICMP报文的类型。某些ICMP还使用代码字段的值进一步描述不同条件。
检验和字段覆盖整个ICMP报文。
上表中对ICMP的查询和差错进行了区分,在对差错报文进行响应时,永远不会产生另一份ICMP差错报文,如没有这个规则,可能会遇到一个差错产生另一个差错的情况,而差错再产生差错,从而无休止循环下去。
发送差错报文时,报文中始终包含产生错误的IP数据报的IP首部和该数据报数据字段的前8个字节,这样接收差错报文的模块就会把它与某个特定协议(IP数据报头中的协议字段)和用户进程(IP数据报前8个字节是TCP或UDP报文首部中的TCP或UDP端口号)联系起来。
下面的情况不会导致产生ICMP差错报文:
1.ICMP差错报文。
2.目的地址是广播地址的IP数据报。
3.作为链路层广播的数据报。
4.不是IP分片的第一片。
5.源地址不是单个主机的数据报,即源地址不能为零地址、环回地址、广播地址、多播地址。
以上规则是为了防止过去因允许广播分组响应产生ICMP差错报文所带来的广播风暴。
ICMP地址掩码请求报文用于无盘系统在引导过程中获取自己的子网掩码。系统广播它的ICMP请求报文(类似于无盘系统引导过程中使用RARP获取自己的IP地址)。
无盘系统获取自己子网掩码的另一个方法是BOOTP协议。
上图中的标识符和序列号字段由发送端任意选择设定,这些值会在应答中被返回,这样发送端可以匹配请求与应答。
编写一个简单的程序,它发送一份ICMP地址掩码请求报文,然后打印出所有应答:
上图中icmp地址掩码请求的目的地址是一个子网的广播地址。以上应答中,来自svr4的子网掩码是错误的,它返回了一个B类地址的掩码,好像子网不存在一样,这是因为svr4处理ICMP地址掩码请求过程存在差错。
向广播地址发送ICMP地址掩码请求时,目的网络的主机bsdi使用tcpdump命令的输出:
发送ICMP地址掩码请求的主机sun向自身所在网络广播时,它本身也能收到自身的ICMP应答,因为上例中广播也包括自身,当以太网驱动程序检测到目的地址是自身所在网络的后,就把分组送到网络上,同时传一份分组拷贝到环回接口。
之后如上图,bsdi以广播形式应答icmp地址掩码请求,而svr4只把应答传给请求主机,通常,应答地址必须是单播地址,除非请求的源IP地址是0.0.0.0,但本例不是这样,因此,把应答发送到广播地址是BSD/386的一个内部差错。
RFC规定,除非系统是地址掩码的授权代理,否则它不能发送地址掩码应答,为成为授权代理,必须进行特殊配置,但大多数主机在收到请求时都发送一个应答,有的应答还是错误的。
上图中,两种情况返回的接口的地址掩码对应的都是环回地址(A类地址127.0.0.1),发送给本机的IP数据报实际是送给环回接口,ICMP地址掩码应答必须是对应接口的子网掩码(因为多接口主机每个接口都有不同的子网掩码),以上两种情况下地址掩码请求都来自于环回接口。
ICMP时间戳请求允许系统向另一个系统查询当前时间,返回的建议值是自午夜开始计算的毫秒数。它获取的时间分辨率高,UNIX提供的rdata命令只能提供秒级分辨率。由于ICMP时间戳请求返回的时间是从午夜开始计算的,因此调用者必须通过其他方法获知当时的日期。
请求端填写发起时间戳,然后发送报文,接收系统收到时填写接收时间戳,发送应答时填写发送时间戳。但实现大多都将后两个字段设成相同值。
自写一个icmptime程序,它可以给某主机发送ICMP时间戳请求,并打印出应答:
上图中orig、recv、xmit分别表示发起时间戳、接收时间戳、发送时间戳。往返时间rtt是收到应答的时间值减去发送请求的时间值。difference值是接收到请求的时间值减去发送请求时的时间值(recv-orig)。
如果我们相信rtt值,并且相信rtt的一半用于请求报文的传输,另一半用于应答报文的传输,那么上例中,sun主机的时间比bsdi时间快,为了使本机时钟和查询主机时钟一致,我们可以调整本机时钟,方式是减少本机时间,减少值为difference-rtt/2的绝对值。
以上程序中,接受和发送时间戳最后一位总是0,这是由于SVR4在ICMP时间戳中不提供毫秒级分辨率,只提供10ms的分辨率。
路由器gateway(一个Cisco路由器)有一个有趣的现象,当系统返回一个非标准时间戳值时,gateway路由器就用32bit时间戳中的高位表示非标准时间戳,下图程序输出证明了这一点,在尖括号中打印出了接收和发送的时间戳值(在关闭高位之后),并且输出中去掉了difference值,因为时间戳的标准不同,不能简单加减计算,需要特定的算法:
比较sun主机和一个准确的系统时钟,一个NTP(网络时间协议)服务器:
其他获取时间和日期的方法:
1.使用daytime或time,前者返回人们可读格式的时间和日期,是一串ASCII字符;后者返回自UTC(1990.1.1 零时)到现在的秒数(rdate命令使用time程序)。
2.严格的计时器使用NTP(网络时间协议)。
3.开放软件基金会(OSF)的分布式计算环境(DCE)定义了分布式时间服务(DTS),提供计算机之间的时钟同步。
4.伯克利大学的UNIX系统提供守护程序timed,来同步局域网上的系统时钟。
ICMP端口不可达是ICMP的一种差错报文。
UDP若收到一份UDP数据报,而目的端口与某个正在使用的进程不相符,则UDP返回一个ICMP不可达报文。可用TFTP(Trivial File Transfer Protocol,简单文件传输协议)强制生成一个端口不可达报文。
TFTP服务器的公共端口号为69,大多TFTP客户程序允许使用connect命令指定一个不同端口号:
connect命令可指定要连接的主机和端口,之后用get命令来取文件,输入get后,一份UDP数据报就发送到connect命令指定的主机的端口上。tcpdump命令查看:
上图中第一行是发送UDP数据报到svr4前,先发送一份ARP请求来确定目的硬件地址。接着第二行返回了ARP应答。第三行才开始发送UDP数据报。
第四行显示ICMP端口不可达差错是立即返回的,但TFTP客户程序在5s后又发送了一份UDP数据报。
ICMP是主机间交换的,不用目的端口号,而每个UDP数据报都从一个特定端口发到另一个特定端口。
UDP后面的数字20表示UDP数据报中数据长度,上例中,20字节包括TFTP的2字节的操作代码,9字节的以空字符结束的文件名temp.foo,9字节的以空字符结尾的字符串netascii。
ICMP差错报文必须包括生成该差错报文的数据报的IP首部(包括可选项),还必须包括跟在该IP首部后面的前8个字节,上图中,跟在IP首部后面的前8个字节是UDP首部。
上图中的UDP首部中的内容含源端口号和目的端口号,就是由于目的端口号才产生了ICMP端口不可达差错报文,接收该差错报文的系统可根据源端口号把差错报文和发送端某个特定的用户进程关联。
导致差错的数据报中的IP首部要被送回的原因是,IP首部中包含了协议字段,使得ICMP可以知道如何解释后面的8个字节,上例中是UDP首部。TCP首部前8个字节中也包含源端口和目的端口。
上图中的未用的32bit在当代码为4(需要分片但置位了不分片位)时,路径MTU允许路由器把外出接口的MTU填在低16bit中。
TFTP在收到ICMP报文返回时还重发的原因是,BSD系统不把从插口(socket)接收到的ICMP报文中的UDP数据通知用户进程,除非该进程已经发送了一个connect命令给该插口。标准BSD TFTP客户程序并不发送connect命令,它永远不会收到ICMP差错报文的通知。
上例的超时重传算法已被RFC禁用,推荐的方法是指数退避方法,分别在0、5、15、35秒时重发报文。
上图中,传给用户进程的报文如果用户进程不存在时,报文会被丢弃;引号括起来的字符串是对应的UNIX差错。
发送一个ICMP差错总是将TOS(IP首部的服务类型字段)置为0。发送一个ICMP查询请求可以将TOS置为任何值,但是发送相应应答时必须将TOS置为相同的值。
使用netstat -s
命令可统计每个协议的数据。
这篇关于TCP/IP详解 卷1:协议 学习笔记 第六章 ICMP:Internet控制报文协议的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!