最后兩小節我們來討論ICMP查詢報文—地址掩碼和時間戳查詢及應答。現在來分析一種ICMP差錯報文,即端口不可達報文,它是ICMP目的不可到達報文中的一種,以此來看一看ICMP差錯報文中所附加的信息。使用UDP(見第11章)來查看它。
UDP的規則之一是,如果收到一份UDP數據報而目的端口與某個正在使用的進程不相符,那么UDP返回一個ICMP不可達報文。可以用TFTP來強制生成一個端口不可達報文(TFTP將在第15章描述)。
對于TFTP服務器來說,UDP的公共端口號是69。但是大多數的TFTP客戶程序允許用connect命令來指定一個不同的端口號。這里,我們就用它來指定8888端口:

connect命令首先指定要連接的主機名及其端口號,接著用get命令來取文件。敲入get命令后,一份UDP數據報就發送到主機svr4上的8888端口。tcpdump命令引起的報文交換結果如圖6-8所示。

在UDP數據報送到svr4之前,要先發送一份ARP請求來確定它的硬件地址(第1行)。接著返回ARP應答(第2行),然后才發送UDP數據報(第3行)(在tcpdump的輸出中保留ARP請求和應答是為了提醒我們,這些報文交換可能在第一個IP數據報從一個主機發送到另一個主機之前是必需的。在本書以后的章節中,如果這些報文與討論的題目不相關,那么我們將省略它們)。
一個ICMP端口不可達差錯是立刻返回的(第4行)。但是,TFTP客戶程序看上去似乎忽略了這個ICMP報文,而在5秒鐘之后又發送了另一份UDP數據報(第5行)。在客戶程序放棄之前重發了三次。
注意,ICMP報文是在主機之間交換的,而不用目的端口號,而每個20字節的UDP數據報則是從一個特定端口(2924)發送到另一個特定端口(8888)。
跟在每個UDP后面的數字20指的是UDP數據報中的數據長度。在這個例子中, 20字節包括TFTP的2個字節的操作代碼,9個字節以空字符結束的文件名temp.foo,以及9個字節以空字符結束的字符串netascii(TFTP報文的詳細格式參見圖15-1)。
如果用-e選項運行同樣的例子,我們可以看到每個返回的ICMP端口不可達報文的完整長度。這里的長度為70字節,各字段分配如圖6-9所示。

ICMP的一個規則是,ICMP差錯報文(參見圖6-3的最后一列)必須包括生成該差錯報文的數據報IP首部(包含任何選項),還必須至少包括跟在該IP首部后面的前8個字節。在我們的例子中,跟在IP首部后面的前8個字節包含UDP的首部(見圖11-2)。
一個重要的事實是包含在UDP首部中的內容是源端口號和目的端口號。就是由于目的端口號(8888)才導致產生了ICMP端口不可達的差錯報文。接收ICMP的系統可以根據源端口號(2924)來把差錯報文與某個特定的用戶進程相關聯(在本例中是TFTP客戶程序)。
導致差錯的數據報中的IP首部要被送回的原因是因為IP首部中包含了協議字段,使得ICMP可以知道如何解釋后面的8個字節(在本例中是UDP首部)。如果我們來查看TCP首部(圖17-2),可以發現源端口和目的端口被包含在TCP首部的前8個字節中。
ICMP不可達報文的一般格式如圖6-10所示。

在圖6-3中,我們注意到有16種不同類型的ICMP不可達報文,代碼分別從0到15。ICMP端口不可達差錯代碼是3。另外,盡管圖6-10指出了在ICMP報文中的第二個32 bit字必須為0,但是當代碼為4時(“需要分片但設置了不分片比特”),路徑M T U發現機制(2.9節)卻允許路由器把外出接口的MTU填在這個32 bit字的低16 bit中。我們在11.6節中給出了一個這種差錯的例子。
盡管ICMP規則允許系統返回多于8個字節的產生差錯的IP數據報中的數據,但是大多數從伯克利派生出來的系統只返回8個字節。Solaris 2.2的ip_icmp_return_data_bytes選項默認條件下返回前6 4個字節(E.4節)。
**tcpdump時間系列**
在本書的后面章節中,我們還要以時間系列的格式給出tcpdump命令的輸出,如圖6 - 11所示。

時間隨著向下而遞增,在圖左邊的時間標記與tcpdump命令的輸出是相同的(見圖6-8)。
位于圖頂部的標記是通信雙方的主機名和端口號。需要指出的是,隨著頁面向下的y坐標軸與真正的時間值不是成比例的。當出現一個有意義的時間段時,在本例中是每5秒之間的重發,我們就在時間系列的兩側作上標記。當UDP或TCP數據正在被傳送時,我們用粗線的行來表示。
當ICMP報文返回時,為什么TFTP客戶程序還要繼續重發請求呢?這是由于網絡編程中的一個因素,即BSD系統不把從插口(socket)接收到的ICMP報文中的UDP數據通知用戶進程,除非該進程已經發送了一個connect命令給該插口。標準的BSD TFTP客戶程序并不發送connect命令,因此它永遠也不會收到I C M P差錯報文的通知。
這里需要注意的另一點是TFTP客戶程序所采用的不太好的超時重傳算法。它只是假定5秒是足夠的,因此每隔5秒就重傳一次,總共需要25秒鐘的時間。在后面我們將看到TCP有一個較好的超時重發算法。
TFTP客戶程序所采用的超時重傳算法已被RFC所禁用。不過,在作者所在子網上的三個系統以及Solaris 2.2仍然在使用它。AIX 3.2.2采用一種指數退避方法來設置超時值,分別在0、5、15和35秒時重發報文,這正是所推薦的方法。我們將在第21章更詳細地討論超時問題。
最后需要指出的是, ICMP報文是在發送UDP數據報3.5 ms后返回的,這與第7章我們所看到的P i n g應答的往返時間差不多。
- 第1章 概述
- 1.1 引言
- 1.2 分層
- 1.3 TCP/IP的分層
- 1.4 互聯網的地址
- 1.5 域名系統
- 1.6 封裝
- 1.7 分用
- 1.8 客戶-服務器模型
- 1.9 端口號
- 1.10 標準化過程
- 1.11 RFC
- 1.12 標準的簡單服務
- 1.13 互聯網
- 1.14 實現
- 1.15 應用編程接口
- 1.16 測試網絡
- 1.17 小結
- 第2章 鏈路層
- 2.1 引言
- 2.2 以太網和IEEE 802封裝
- 2.3 尾部封裝
- 2.4 SLIP:串行線路IP
- 2.5 壓縮的SLIP
- 2.6 PPP:點對點協議
- 2.7 環回接口
- 2.8 最大傳輸單元MTU
- 2.9 路徑MTU
- 2.10 串行線路吞吐量計算
- 2.11 小結
- 第3章 IP:網際協議
- 3.1 引言
- 3.2 IP首部
- 3.3 IP路由選擇
- 3.4 子網尋址
- 3.5 子網掩碼
- 3.6 特殊情況的IP地址
- 3.7 一個子網的例子
- 3.8 ifconfig命令
- 3.9 netstat命令
- 3.10 IP的未來
- 3.11 小結
- 第4章 ARP:地址解析協議
- 4.1 引言
- 4.2 一個例子
- 4.3 ARP高速緩存
- 4.4 ARP的分組格式
- 4.5 ARP舉例
- 4.5.1 一般的例子
- 4.5.2 對不存在主機的ARP請求
- 4.5.3 ARP高速緩存超時設置
- 4.6 ARP代理
- 4.7 免費ARP
- 4.8 arp命令
- 4.9 小結
- 第5章 RARP:逆地址解析協議
- 5.1 引言
- 5.2 RARP的分組格式
- 5.3 RARP舉例
- 5.4 RARP服務器的設計
- 5.4.1 作為用戶進程的RARP服務器
- 5.4.2 每個網絡有多個RARP服務器
- 5.5 小結
- 第6章 ICMP:Internet控制報文協議
- 6.1 引言
- 6.2 ICMP報文的類型
- 6.3 ICMP地址掩碼請求與應答
- 6.4 ICMP時間戳請求與應答
- 6.4.1 舉例
- 6.4.2 另一種方法
- 6.5 ICMP端口不可達差錯
- 6.6 ICMP報文的4.4BSD處理
- 6.7 小結
- 第7章 Ping程序
- 7.1 引言
- 7.2 Ping程序
- 7.2.1 LAN輸出
- 7.2.2 WAN輸出
- 7.2.3 線路SLIP鏈接
- 7.2.4 撥號SLIP鏈路
- 7.3 IP記錄路由選項
- 7.3.1 通常的例子
- 7.3.2 異常的輸出
- 7.4 IP時間戳選項
- 7.5 小結
- 第8章 Traceroute程序
- 8.1 引言
- 8.2 Traceroute程序的操作
- 8.3 局域網輸出
- 8.4 廣域網輸出
- 8.5 IP源站選路選項
- 8.5.1 寬松的源站選路的traceroute程序示例
- 8.5.2 嚴格的源站選路的traceroute程序示例
- 8.5.3 寬松的源站選路traceroute程序的往返路由
- 8.6 小結
- 第9章 IP選路
- 9.1 引言
- 9.2 選路的原理
- 9.2.1 簡單路由表
- 9.2.2 初始化路由表
- 9.2.3 較復雜的路由表
- 9.2.4 沒有到達目的地的路由
- 9.3 ICMP主機與網絡不可達差錯
- 9.4 轉發或不轉發
- 9.5 ICMP重定向差錯
- 9.5.1 一個例子
- 9.5.2 更多的細節
- 9.6 ICMP路由器發現報文
- 9.6.1 路由器操作
- 9.6.2 主機操作
- 9.6.3 實現
- 9.7 小結