IP協議


IP協議是TCP/IP協議族的核心協議,也是socket網絡編程基礎之一。本章從兩個方面討論IP協議:

  1. IP頭部信息。IP頭部信息出現在每個IP數據報中,用於指定IP通信的源端IP地址、目的端IP地址,指導IP分片和重組,以及指定部分通信行為。
  2. IP數據報的路由和轉發。IP數據報的路由和轉發發生在除目標機器之為的所有主機和路由器上。它們決定數據報是否應該轉發以及如何轉發。

1、IP服務的特點

IP協議是TCP/IP協議族的動力,為上層協議提供無狀態、無連接、不可靠的服務。

  • 無狀態(stateless)是指IP通信雙方不同步傳輸數據的狀態信息,所有IP數據報的發生、傳輸和接收都是相互獨立、沒有上下文關系的。這種服務最大的缺點是無法處理亂序和重復的IP數據報。接收端的IP模塊只要收到完整的IP數據報(如果是IP分片的話,IP模塊會閑執行重組),就將其數據部分(TCP報文端、UDP數據包或者ICMP報文)上交給上層協議。那么在上層協議來看,這些數據可能是亂序的、重復的、面向連接的協議,比如TCP協議、能夠自己處理亂序 的、重復的報文段,它遞交給上層協議的內容絕對是有序的、正確的。IP數據報頭部提供了一個標志段用於唯一標志一個IP數據報,用來處理IP分片和重組,但不能用來知識接收順序。無狀態服務的有點很明顯:簡單、高效。無需為保證通信的狀態而分配一些內核資源嗎,也無需每次傳輸數據時都攜帶狀態信息。網絡中無狀態協議有UDP和HTTP等協議。
  • 無連接(connectionless)指IP通信雙方都不長久維持對方的任何信息。因此,上層協議每次發送數據的時候,都必須明確指定對方的IP地址。
  • 不可靠指IP協議不能保證IP數據報准確的到達接收端,它知識承諾盡最大努力(best effort)。很多情況都能導致IP數據報發送失敗。比如:某個中轉路由器發現IP數據報在網絡上存活的時間太長,則會將其丟棄,並返回一個ICMP錯誤信息(超時錯誤)給發送端。接收端發現收到的IP數據報不正確(通過校驗機制),也會將其丟棄,並返回一個ICMP錯誤信息(IP頭部參數錯誤)給發送端。無論哪種情況,發送端的Ip模塊一旦檢測到IP數據報發送失敗就通知上層協議發送失敗,而不會試圖重傳。以此,使用IP服務的上層協議(比如:TCP協議)需要自己實現數據確認、超時重傳等機制來達到可靠傳輸的目的。

2、IPv4頭部結構

IPv4頭部結構如下圖,其長度通常為20字節,除非含有可變長的選項部分。

  • 4位版本號(version)指定IP協議的版本,對IPv4來說,值=4。
  • 4位頭部長度(header length)標志該IP頭部有多少個32bit字(4字節)。英文4位最大能表示15,所以IP頭部最長位為60字節。
  • 8位服務類型(Type Of Service,TOS)包括一個3位的優先權限字段(現在已經被忽略),4位的TOS字段和1位保留字段(必須置0)。4位的TOS字段分別表示:最小延時、最大吞吐量、最高可靠性和最小費用。一種最多有一個能置為1,應用程序應該根據實際需求來設置它。比如像ssh和telent這樣的登錄程序需要的是最小延時的服務,而文件傳輸程序ftp則需要最大吞吐量的服務。
  • 16位總長度(total length)是指整個IP數據報的長度,以字節為單位,以此IP數據報的最大長度為65535字節。但由於MTU的限制,長度超過MTU的數據報將被分片傳輸,所以實際傳輸的IP數據報(或分片)的長度都遠遠沒有達到這個最大值。接下來的3個字段則描述了如何實現分片。
  • 16位標志(identification)唯一標志主機發送的每一個數據報。其初始值由系統隨機生成,每發送一個數據報,其值就加1。該值在數據分片時,被復制到每個分片中,因此同一個數據報的所有分片都具有相同的標識值。
  • 3位標識字段的第一位保留。第二位(Don't Fragement,DF)表示“禁止分片”。如果設置了這個位,IP模塊將不對數據報進行分片。在這種情況下,如果IP數據報長度超過MTU的話,IP模塊將丟棄該數據報並返回一個ICMP差錯報文。第三位(More Fragment,MF)表示“更多分片”。除數據報的最后一個分片外,其他分片都要把它置1。
  • 13位分片偏移(fragmentation offset)時分片相對原始IP數據報開始處(僅指數據部分)的偏移。實際的偏移值時該值左移3位(乘8)后得到的。由於這個原因,除了最后一個IP分片外,每個IP分片的數據部分的長度必須是8的整數倍(這樣才能保障后面的IP分片擁有一個合適的偏移值)。
  • 8位生存時間(Time To Live,TTL)是數據報到達目的地之前允許經過的路由器跳數。TTL值被發送端設置(常見的值是64).數據報在轉發過程中沒經過一個路由,該值就被路由器減1。當TTL值減為0時,路由器將丟棄數據報,並向源端發送一個ICMP差錯報文。TTL值可以防止數據報陷入路由循環。
  • 8位協議(protocol)用來區分上層協議。/etc/protocls文件定義了所有上層協議對應的protocol字段數值。其中,ICMP=1,TCP=6,UDP=17。/etc/protocols文件時RFC1700的一個子集。
  • 16位頭部校驗和(header checksum)由發送端填充,接收端對其使用CRC算法以檢驗IP數據報頭部(注意,僅檢驗頭部)在傳輸過程中是否損壞。
  • 32位源端IP地址和目的端IP地址用來標識數據報的發送端和接收端。一般情況下,這兩個地址在整個數據報的傳遞中保持不變,而不論它中間經過多少個中轉路由器。
  • 最后一個選項字段(option)是可變長的可選信息。這部分最多包含40字節,因為IP頭部最長是60個字節(包含前面討論的20個字節的固定部分)。可用的IP選項包括:
    • 記錄路由(record route),告訴數據報途徑的所有的路由器都將自己的IP地址填入IP頭部的選項部分,這個我們可以跟蹤數據報的傳遞路徑。
    • 時間戳(timestamp),告訴每個路由器都將數據報被轉發時的時間(或時間與IP地址對)填入IP頭部選項部分,這個就可以測量途徑路由之間的數據報傳輸的時間。
    • 松散源路由選擇(loose source routing),指定一個路由器IP地址列表,數據報發送過程中必須經過其中所有的路由器。
    • 嚴格源路由選擇(strict source routing),和松散源路由選擇類似,不過數據報只經過被指定的路由器。

3、分片

當Ip數據報的長度超過幀的MTU時,將被分片傳輸。分片可能發生在發送端,也可能發生在中轉路由器上,而且可能在傳輸過程中被多次分片,但只有在最終的目標機器上,這些分片才會被內核中的IP模塊重新組裝。

IP頭部中的如下三個字段給IP的分片和重組提供了足夠的信息:數據報標識、標志和片偏移。

一個數據報的每個分片都具有自己的IP頭部,它們具有相同的標識值,但具有不同的片偏移。並且除了最后一個分片外,其他分片都將設置MF標識。此外,每個分片的IP頭部的總長度字段將被設置為該分片的長度。

以太網的MTU是1500字節(可通過ifconfig或netstat命令查看),以此它攜帶的IP數據報的數據部分最多是1480字節(IP頭部占用20字節)。考慮用IP數據報封裝一個長度為1481字節的ICMP報文(包括8字節的ICMP頭部,所以其數據部分長度為1473字節),則該數據報在使用以太網傳輸時必須被分片,如下圖所示:

注意:

ICMP報文的頭部長度取決於報文的類型,其變化范圍很大。上圖以8字節為例,后面例子用到的ping程序使用的ICMP回顯和應答報文的頭部長度是8字節。

sudo tcpdump -ntv -i enp2s0 icmp
ping 192.168.6.16 -s 1473

tcpdump輸出一個IP數據報的兩個分片內容如下:

這兩個分片的標識值都是11816,說明它們是同一個IP數據報分片。第一個分片的片偏移值為0,而第二個則是1480。很顯然,第二個分片的偏移值是加上也是第一個分片的ICMP報文的長度。而一個分片設置了MF標識表示還有后續分片,所以tcpdump輸出“flags[+]”。而第二個分片則沒有設置任何標識,所以tcpdump輸出“flags[none]”。這兩個分片長度分片分別是1500字節和21字節,與IP分片示意圖描述的一致。

最后,IP層傳遞給數據鏈路層的數據可能是一個完整的Ip數據報,也可能是一個IP分片,它們統稱為IP分組(packet)。

4、IP路由

IP模塊工作流程:

IP協議的一個核心任務是數據報的路由,即決定發送數據報到目標機器的路徑。IP模塊的基本工作流程如下:

首先從右往左來分析上圖,當IP模塊接收到來自數據鏈路層的IP數據報時,首先對該數據報的頭部進行CRC校驗,確認無誤后就分析其頭部的具體信息。

  • 如果該IP數據報的頭部設置了源站選路選項(松散原路由選擇或嚴格源路由選擇),則IP模塊調用數據報轉發子模塊處理該數據。
  • 如果IP數據報頭部中的IP地址是本機的某個IP地址嗎,或者是廣播地址,即該數據報是發給本機的,則IP模塊就根據數據報頭部中的協議字段來決定將它派發給哪個上層應用(分用)。
  • 如果IP模塊發現這個數據報不是發送給本機的,則調用數據報轉發子模塊來處理該數據報。
  • 數據報轉發子模塊將首先檢測系統是否允許轉發。如不允許,IP模塊則將數據丟棄;如允許,數據報轉發子模塊將對該數據報執行一些操作,然后將它交給IP數據報輸出子模塊。

IP數據報應該發送到哪個下一跳路由(或者目標機器),以及經過哪個網卡來發送,就是IP路由過程(即上圖中“計算下一跳路由”子模塊)。IP模塊實現數據報路由的核心數據結構是路由表。這個表安裝數據報的目標IP地址分類,同一類型的IP數據報將被發往相同的下一跳路由器(或目標機器)。

IP輸出隊列中存放的是所有等待發送的IP數據報,其中除了需要轉發的IP數據報外,還包括封裝了本機上層數據(ICMP報文、TCP報文段和UDP數據報)的IP數據報。

IP路由策略:上圖中虛線箭頭顯示了路由表更新過程。這一過程是指通過路由協議或者route命令調整路由表,使之更適應最新的網絡拓撲結構。

路由機制:

路由表實例說明:

該路由表包括三項,每項都包含8個字段,如下所示:

  • 目標(Destination):目標網絡或主機
  • 網關(Gateway):網關地址,*表示目標與本機在同一個網絡,不要需要路由。
  • 子網掩碼(Genmask):網絡掩碼
  • 標識(Flags):路由項標志,常見有如下五種:
    • U:該路由項是活動的。
    • H:該路由項的目標是一台主機。
    • G:該路由項的目標是網關。
    • D:該路由項是由重定向生成的。
    • M:該路由項被重定向修改過。
  • 活躍點(Metric):路由距離,即到達指定網絡所需的中轉數。
  • 引用(Ref):路由項被引用的次數(Linux未使用)。
  • 使用(Use):該路由項被使用的次數。
  • 接口(Iface):該路由項對應的輸出網卡接口。

說明:

第一項的目標地址是default,即默認路由項。該路由項包含G標志,說明路由下一跳目標是網關,其地址為192.168.6.1。另一個路由項目標地址是192.168.6.0,它只本地局域網。該路由項網關地址為* ,說明數據報不需要路由中轉,可以直接發送到目標機器。

IP路由機制的工作步驟:

  1. 查找路由表中和數據報的目標IP地址完全匹配的主機IP地址。如果找到,則使用該路由項,沒有則轉步驟2。
  2. 查找路由表中和數據報的目標IP地址具有相同網絡ID的網絡IP地址,比如上圖中第三項。如果找到則使用該路由項,否則轉步驟3。
  3. 選擇默認路由項,這通常意為中數據報下一跳路由是網關。

因此,對於上圖而言,所有發送到IP地址為192.168.6.*的機器的IP數據報都可以直接發送到目標機器,而所有訪問因特網的請求都將通過網關來轉發(匹配默認路由項)

路由表更新:

sudo route add -host 192.168.1.109 dev enp1s0
sudo route del -net 192.168.1.0 netmask 255.255.255.0
sudo route del default
sudo route add default gw 192.168.1.109 dev enp1s0

第1行表示添加主機192.168.1.109對應的路由項。設置后,從本機發往109的IP數據報繳通過網卡enp1s0直接發送至目標機器的接收網卡。

第2行表示刪除網絡192.168.1.0對應的路由項。此時除了109機器外,本機無法訪問局域網內任何其他機器。

第3行表示刪除默認的路由項。這樣做的結果是無法訪問英特網。

第4行表示重新設置默認路由項,不過這次網關是機器109,而不是能直接訪問的因特網路由器。經過上述修改后路由表內容如下:

Destination         Gateway         Genmask       Flags     Metric     Ref     Use     Iface
ken-machine          *              255.255.255.255   UH        0       0      0      enp1s0
default             109-machine     0.0.0.0        UG        0       0      0      enp1s0  

新路由表中,第一個路由項是主機路由項,所以被設置了H標志。

通過route命令或其他工具手工修改路由表是靜態路由更新方式。但對於大型的路由器,通常通過BGP(Border Gateway Protocol,邊際網關協議)、RIP(Routing Information Protocol,路由信息協議)、OSPF等協議來發現路徑,並更新自己的路由表。這種更新方式是動態的、自動的。

5、IP轉發

不是發給本機的IP數據報將由數據報轉發子模塊來處理。路由器都能執行數據報的轉發操作,而主機一般只發送和接收數據報,因為主機上/proc/sys/net/ipv4/ip_forward內核參數默認為0。我們可通過修改其值來激活主機的數據報轉發功能。

echo 1 > /proc/sys/net/ipv4/ip_forward

對於允許IP數據報轉發的系統(主機或路由器),數據報轉發子模塊將對期望轉發的數據報執行如下操縱:

  1. 檢查數據報頭部信息的TTL值。如果TTL=0,則丟棄該數據報。
  2. 查看數據報頭部信息的嚴格源路由選項。如果該選項被設置,則檢測數據報的目標IP地址是不是本機的某個IP地址,如果不是,則發送一個ICMP源站選路失敗報文給發送端。
  3. 如果有必要,則給源端發送一個ICMP重定向報文,以告知它一個更合理的下一跳路由器。
  4. 將TTL值減1。
  5. 處理IP頭部選項。
  6. 如有必要,則執行IP分片操作。

6、重定向

ICMP重定向報文

格式如下:

ICMP報文頭部包含3個固定字段:8為類型、8為代碼和16為校驗和。ICMP重定向報文的類型值=5,代碼段有4個值可選,用來區分不同的重定向類型。主機重定向時,代碼值=1。

ICMP重定向的數據部分給接收方提供如下兩個信息:

  • 引起重定向的IP數據報的源端IP地址。
  • 應該使用的路由器IP地址。

接收主機根據這連個信息就可以斷定引起重定向的IP數據報應該使用哪個路由器來轉發,並且以此來更新路由表(通常是更新路由表緩沖,而不是直接更改路由表)。

/proc/sys/net/ipv4/conf/all/send_redirects內核參數指定是否允許發送ICMP重定向報文,而/proc/sys/net/ipv4/conf/all/accept_redirects內核參數則指定是否允許接收重定向報文。一般來說,主機只能接收ICMP重定向報文,而路由器只能發送ICMP重定向報文。

主機重定向應用舉例:

第4章中,我們把機器ken-machine網關設置為109-machine,第5章中又設置了109-machine的數據報轉發功能,因此機器ken-machine將通過109-machine來訪問因特網。比如在ken-machine執行ping命令:

$ ping www.baidu.com
PING www.a.shifen.com (119.75.217.56) 56(84) bytes of data.
From 109-machine(192.168.1.109): icmp_sep=1 Redirect Host(New nexthop:192.168.1.1) 64 bytes from 119.75.217.56: icmp_seq=1 ttl=54 time=6.78 ms

---------www.a.shifen.com ping statistics---------
1 packets transmitted ,1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 6.789/ 6.789/ 6.789/0.000 ms

從ping命令的輸出來看,109-machine給ken-machine發送了一個ICMP重定向報文,告訴它請通過192.168.1.1來訪問目標機器,因為這對於ken-machine來說是更合理的路由方式。當主機ken-machine收到這樣的ICMP重定向報文后,它將更新其路由表緩沖(使用命令 route -Cn查看),並使用新的路由方式來發送后續數據報。總結如下圖所示:

注:筆記來源《Linux高性能服務器編程》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM