DHCP協定分析以及相關實驗
DHCP (Dynamic Host Configuration Protocol )協定的探讨與分析
最近在工作中遇到了連接配接外網的交換機在<code>IPv6</code>位址條件下從營運商自動擷取的<code>DNS</code>位址與本機手動輸入配置的<code>IPv4</code>位址下的<code>DNS</code>發生沖突的問題,這個問題在實際的生産網上會帶來業務的中斷和不穩定,在進入到生産環境中的本地終端發送給資料中心的網絡流量會因為<code>IPv4</code> 和 <code>IPv6</code> 下的<code>DNS</code>沖突而導緻無法正确的發送流量。
在終端中,預設的<code>IPv6</code> 的優先級會大于<code>IPv4</code>的優先級,這樣就會帶來沖突問題,解決的問題就是将連接配接外網的網絡線從與連接配接内網的交換機中斷開即可以解決。下邊的圖檔說明了該問題的發生的場景:
從上邊的圖看出,業務終端連接配接着“本地業務網核心交換機”來擷取和轉發網絡流量到資料中心生産網絡中的伺服器,在正常的條件下,“本地業務網核心交換機”和“本地營運商交換機”是不能通過網絡跳線連接配接在一起并配置到同一個<code>Vlan</code>中的。在本次問題中,因為“本地營運商交換機”和“本地業務網核心交換機”連接配接在了同一個<code>Vlan</code>,導緻了業務終端的業務流量從資料中心生産網絡來源的不穩定,而造成了業務不穩定。
在這個解決問題的過程中,有<code>DHCP</code>和<code>ARP</code>在實際網絡環境下的運用場景和背景模糊不清的問題,故而撰寫這篇部落格來複習和鞏固<code>DHCP</code>協定。
網絡是非常複雜且抽象的,網絡中的硬體裝置比如 路由器、交換機、集線器、網線、網卡、網橋共同組成了核心網絡,在硬體裝置上流通的網絡流量,做到怎麼去引導網絡流量正确得流向到正确的網絡裝置上,需要<code>TCP/IP</code> 協定作為網絡流量的核心協定。
但是如果一個網絡管理者想要正确地讓<code>TCP/IP</code>協定正确運作,需要給網絡中的主機和路由器配置一些關鍵資訊,比如說接口的<code>IP</code>位址。我們可以輕易地在電腦上輸入 <code>ipconfig</code> 指令去顯示目前網絡裝置的網絡位址資訊,那麼這個位址到底是怎麼被配置設定到目前的裝置上的?
對于一個網絡裝置(終端)的核心<code>IP</code>資訊主要有: <code>IP位址</code>、<code>子網路遮罩</code> 和 <code>DNS伺服器位址</code>。
而擷取網絡裝置的 <code>TCP/IP</code>資訊主要有這幾個方面:
手動配置 - 通過終端上的配置界面根據業務的要求進行手動配置。
動态擷取 - 例如 <code>windows</code> 上的手動配置選項上的動态擷取選項。
特定的算法進行計算。
一般來說,對于伺服器端的采用<code>手動配置方式</code>來适應業務的核心需求,對于用戶端比如連接配接網絡拓撲上的個人終端那麼采用<code>動态擷取方式</code>來擷取相關資訊。
原因有以下幾個方面:
用戶端與伺服器端的互動會更加頻繁,并且用戶端可能會在網絡中發生遷移。
伺服器端的配置服務要求用戶端的網絡一定必須是固定的。
在這個場景下,用戶端需要從伺服器端動态地擷取伺服器端的資訊并配置到本地中,這個時候 <code>DHCP</code>就派上了用場。在本文中,主機 == 用戶端,即任何需要從網絡中擷取位址的裝置( 不包括 網絡中的路由器),請差別開這個方面的概念。伺服器 = 服務端,有時候并不一定是一個獨立的裝置,而是一個應用程式(在大多數條件下),希望能将這些方面的概念差別出來。
DHCP,從英文的含義來說,Dynamic Host Configuration Protocol,是用來動态地配置主機的相關狀态,從<code>DHCP</code>的發展來說,<code>DHCP</code>是繼承于<code>BOOTP</code> 協定 ( Bootstrap Protocol ),後者在設計協定的過程中僅僅提供了有限的主機資訊配置,并且主機的資訊一旦從遠端伺服器端配置設定之後,就很難再被修改;<code>DHCP</code>的出現改變了這種局面,<code>DHCP</code>幾乎提供了所有的主機配追資訊,并且引入了<code>租約</code>的概念,使得主機資訊能夠動态地産生變化和進行更改。此外,作為可以動态地更改主機的配置的協定,
<code>DHCP</code> 是一個基于 <code>Client/Server</code> 模式的網絡協定。
<code>DHCP</code> 是基于<code>UDP/IP</code>協定進行傳輸,伺服器端使用端口 <code>67</code>, <code>DHCP</code>用戶端使用端口号 <code>68</code>。
<code>DHCP</code>主要分為兩個部分: <code>網絡IP位址的管理</code> 和 <code>配置資訊的傳遞</code>
網絡IP位址的管理: 位址管理處理 <code>IP</code> 位址的動态配置設定, 并且為每一個主機 (Host) 提供位址的租約
配置資訊傳遞: 從伺服器端向主機端傳遞封包 和 狀态機的配置。
位址池 與 位址租約
如果使用者在用戶端中申請配置一個 <code>動态網絡位址配置</code>,那麼 <code>DHCP用戶端(Host)</code>會向 DHCP伺服器 發送一個 IP位址請求。 這個時候在遠端的 <code>DHCP伺服器</code> 就會維護一個 <code>IP位址池</code>,并且從這個位址池來取出一個<code>IP</code>回應給 DHCP用戶端。 在位址配置設定的過程中,<code>DHCP伺服器</code>也會指定回應給 <code>DHCP用戶端</code>的IP位址的租約期,在租約期中,這個位址可以被用戶端使用,租約期到之後這個IP位址被 DHCP伺服器自動收回。用戶端可以在租約期内請求延長租約。
DHCP 封包内容
DHCP的組成從網上有很多解釋,下圖來自網絡:

Op: 封包類型,分為 兩大類: <code>Request(1)</code> 和 <code>Reply(2)</code>
HW Type: 硬體類型,一般是以太網:1
HW Len: 硬體位址長度,機關位元組。對應以太網:6(mac位址長度為6位元組48bit)
Transaction ID:事務ID,随機數,有用戶端生成,伺服器Reply時,會把 Request 中建立的 Transaction 拷貝到Reply封包中。用于用戶端區分網絡上的目的地為自己的封包。
Secs: 距離第一次發射IP請求或Renew請求過去的秒數
Flags:标志位,目前僅第一個bit有使用,置1 标明廣播
Client IP Address:目前用戶端的IP位址,如果目前用戶端沒有IP位址,則置0
Your IP Address: 伺服器想用戶端提供IP位址時,會把IP位址填入本字段
(Next)Server IP Address:用戶端引導時需要的另一個伺服器的IP位址
Gateway (Relay) IP Address: 網關(中繼)IP位址,有DHCP 中繼器在轉發DHCP封包的時候填入
Server Name: Server名字,有64bytes,一般不使用,填充為0
Boot File name: boot file的路徑,128bytes, 一般不使用,填充為0
Option: 選項,不定長度。 DHCP封包中比較重要的字段
DHCP Option 内容
之前介紹過,因為<code>DHCP</code>是從<code>Bootp</code> 協定繼承和拓展過來的,是以很多不能在<code>Bootp</code>實作的内容都放到了<code>Option</code> 來實作。通俗來說,<code>DHCP</code>協定其實就是攜帶許多<code>Option</code>的<code>Bootp</code>。
封包中的<code>Option</code>遵循以下的形式:
如果Option沒有值,則隻有标志位之類的内容,則以一個位元組表示
如果Opiton有值,即Opiton是以下name-value對,則Opiton需要多個位元組表示,其中第一個位元組表示 option的名字,第二位元組表示value的長度,第三個位元組開始表示value。
常見的<code>Option</code>類型情參照下圖:
DHCP 将一台從未配置設定過的主機加入到網絡需要經曆四個階段: 1. 發現階段,2.提供階段,3.請求階段,4.确認階段。
發現階段
新的<code>Client</code>加入網絡時,會使用<code>0.0.0.0</code>作為源位址,發送<code>discover廣播封包</code>,查詢網絡上有哪些<code>DHCP Server</code>,以及這些<code>DHCP Server</code> 能<code>Offer</code>哪些<code>IP位址</code>。這個廣播幀的<code>MAC位址</code>為新的<code>Client</code>的<code>MAC位址</code>,類型字段為 <code>0x0800</code>,載荷資料為一個廣播 IP 封包,該封包的<code>目的IP位址</code> 為有限的廣播位址: <code>255.255.255.255</code>, 協定字段值為 <code>0x11</code>, 載荷資料是一個 UDP封包,消息為 <code>DHCPDISCOVER</code>。
在該階段中,與用戶端所在二層網絡中的所有網絡裝置都會接收到這個廣播幀,并将這個廣播幀洪泛出去,在其他裝置接收到這個資料幀的時候會将相關的載荷按照網絡分層的結構逐層上傳。在裝置的傳輸層 <code>UDP子產品</code> 在接收網絡層上傳的資料包之後會解析資料包的端口号。 對于一個DHCP伺服器來說,67 作為獨特的端口号,會被打開,而對于其他的裝置來說這個端口不被打開,那麼這個資料包就被丢棄。
在華為的數通教材HCNA中,給出的例子是路由器上運作了 <code>DHCP</code>伺服器 , 但是鍊路中可能有多個裝置也運作了<code>DHCP</code>伺服器,這個時候所有收到該請求包的DHCP伺服器都會給請求用戶端回複一個響應資料包來證明自己已經接收到了請求資訊,傳回的資料包都會被發送到請求的用戶端。
對于DHCP的傳輸模式 - UDP協定,是一種面向無連接配接的、不需要可靠傳輸的通信方式,是以 DHCP 需要依賴自己的一種可靠的傳輸傳輸方式,其中包括:什麼情況下需要重複發送已經發送過的請求(重傳消息機制),重複請求的間隔時間是多少,最大重複次數是多少等等...
提供階段
<code>DHCP Server</code>接收到<code>DHCP Discover</code>封包後,回應<code>Offer</code>封包,提供<code>IP位址</code>(可能包含DNS等其他資訊)給<code>Client</code>。
這個階段中,不涉及用戶端是否接受服務端給出的 IP 位址,隻是伺服器端給用戶端的一個響應。 每個接收到 <code>DHCPDISCOVER</code> 消息的伺服器,都從自己維護的 IP 位址池配置設定出一個有效的且未被使用的 IP位址,并通過 <code>DHCPOFFER</code> 消息将這個IP位址配置設定發送給用戶端。
對于一個 <code>DHCPOFFER</code> 消息來講,消息被封裝在用戶端預留端口号為<code>68</code>,源端口号<code>67</code>的一個UDP封包中,該UDP封包又是被上層封裝到一個被廣播的IP封包中。 這個IP封包的目的位址是一個有限廣播位址:<code>255.255.255.255</code>,源位址為DHCP伺服器端所對應的單點傳播位址,其中協定字段為<code>0x11</code>,該IP封包又被上層封裝到了一個廣播幀中,這個廣播幀的源MAC位址為 DHCP Server 所對應的單點傳播MAC位址,類型字段的值為 <code>0x0800</code>。
在傳輸的過程中,與請求用戶端所在同一個二層網絡中的所有裝置都會接收到這個請求資料包,隻有開啟了 <code>DHCP Client</code> 服務的用戶端才會接收到這個資料包的載荷資料(DHCPOFFER),并上傳至應用層上的 <code>DHCP Client</code> 中。
但是在同一個二層網絡中可能存在着其他同樣打開 <code>DHCP Client</code> 服務的用戶端,一個請求用戶端在接收到從 <code>DHCP Server</code> 傳回的封包<code>DHCPOFFER</code>如何區分在收到的傳回封包是不是自己發出的請求呢?
其實請求用戶端發送 <code>DHCPDISCOVER</code> 請求的時候就已經建立了一個用于差別請求和傳回且獨一無二的交易号(<code>Transaction ID</code>) ,這個交易号會在服務端向用戶端發送<code>DHCPOFFER</code>回執的時候會将這個交易号一起發送回去,在請求用戶端接收到<code>DHCPOFFER</code>時會判斷響應的封包中的交易号是否與之前建立的交易好相同。
建立的交易号為一個 4位元組 (32bit) 二進制數。
請求階段
在請求階段中,發送請求的用戶端可能會接收到多個 <code>DHCPOFFER</code>封包,這個時候請求用戶端會自己選擇一個<code>DHCP Server</code>,并廣播一個 <code>DHCPREQUEST</code> 的請求包給選擇的 <code>DHCP Server</code>。并向本地中其他的 <code>DHCP Server</code> 公告自己已經選擇了某個 <code>DHCP Server</code>的某個IP位址,這個時候其他的未被選擇的 <code>DHCP Server</code> 接收到了<code>DHCPREQUEST</code> 封包明白該請求用戶端已經選擇好了<code>DHCP Server</code>,那麼這些伺服器就會收回當初配置設定給請求用戶端的 <code>DHCPOFFER</code> 以及 預留的IP位址。
請求用戶端該過程發送的廣播幀的源MAC位址為該請求用戶端的MAC位址,類型字段的值為<code>0x0800</code>,載荷資料是一個廣播IP封包。該IP封包的目的位址是廣播位址(<code>255.255.255.255</code>),源位址是 <code>0.0.0.0</code>,協定字段的值為 <code>0x11</code>,載荷資料是一個UDP封包。該UDP封包的目的端口号為<code>67</code>,源端口号為<code>68</code>,載荷資料是一個 <code>DHCPREQUEST</code>。
<code>DHCPREQUEST</code>上攜帶者有請求用戶端已經標明的 <code>DHCP Server</code> 的辨別号 (Identifier),表示這個請求用戶端隻接受已經標明的<code>DHCP Server</code> 的 OFFER。
确認階段
在該階段中,<code>DHCP Server</code> 會向請求用戶端(DHCP Client)回複 <code>DHCPACK</code> 消息用來表示自己已經接收到了請求用戶端的請求。
<code>DHCPACK</code> 消息的類型是一廣播IP封包,IP封包的目的IP位址是一個有限的廣播位址 <code>255.255.255.255</code>,其源位址為請求用戶端對應的單點傳播IP位址。其載荷資料是一個UDP封包,UDP封包的源端口号是67,目的端口号是68。
在這個過程中有一個特殊情況,就是在請求用戶端和配置設定IP位址的<code>DHCP Server</code>通訊的過程中預先配置設定給請求用戶端的IP位址配置設定給了其他的主機應該怎麼辦?
請求用戶端接收到了 <code>DHCPACK</code> 封包之後,會立即借助 <code>Gratutious ARP</code> 消息機制來檢查自己的IP位址是不是唯一的。
如果這個位址已經被其他的用戶端占用,那麼該請求用戶端就會主動放棄該IP位址,并向 DHCP Server發送 <code>DHCPDECLINE</code> 告訴該位址已經被其他用戶端占用,然後經過一段時間之後重新嘗試擷取改位址。
如果這個位址一直無法被配置設定,那麼請求用戶端就會發送一個<code>DHCPRELEASE</code> 封包給 <code>DHCP Server</code>聲明放棄這個位址,然後重新從談發現階段開始。
1.此時可以跳過<code>DHCP Discover封包</code>和<code>DHCP Offer封包</code>。
2.<code>Client</code>發送攜帶目前<code>IP位址</code>的<code>Request封包</code>。
3.如果<code>Server</code>同意<code>Client</code>續約,則發送<code>DHCP ACK封包</code>。如果拒絕續約,則發送<code>DHCPNAK封包</code>。
下邊有一個圖來具體的說明 <code>DHCP</code> 的工作原理以及建立相關網絡聯系的流程和原理: