2020-06-04
關鍵字:Option60、新增Option、插入一個Option
1、DHCP是什么?
DHCP 全稱 Dynamic Host Configuration Protocol,動態主機配置協議。
說人話就是用於路由器給各個電腦、手機、網絡設備分配各種地址以使設備能訪問網絡用的,同時它還兼有管理某一局域網內設備的功能。
DHCP 的前身是 BOOTP,即 Bootstrap Protocol。
DHCP 是一種基於 UDP 協議的局域網通訊協議。
2、Option是什么?
DHCP 協議其實就是一段字節流,不同位置的字節數據代表着不同的含義。它大體上可以分成以下兩個組成部分:
1、正文部分
2、附加選項部分
正文部分就是一個DHCP包中必不可少的數據。
附加選項是可選的,即 Option。通常會根據實際的場景需求來決定是否添加。Option部分是直接插在DHCP包的末尾的,它仍舊屬於DHCP包。
Option 的作用就是用以擴展 DHCP 的功能的。因為 DHCP 協議除了簡單的分配地址外還要實現管理設備的功能,而不同應用場景往往又會催生出不同的需求,為了滿足這些客制化的需求,就需要這種可以由用戶自定義內容的“Option”可選項了。
Option 的格式簡單,大體可以分成三個組成部分:
1、Option代碼
1個字節。
2、內容長度
1個字節。
3、內容
內容長度個字節。
其格式如下圖所示:
因為 Option 代碼就是用來區分不同用途的標識符。因為它占 1 個字節,因此 Option 總共有 256 種(0 ~ 255,事實上只有 254 種可以使用的值,因為 0 和 255 是保留值)。
在一個 DHCP 包中可以插入多個 Option 字段。例如,我們以一個 攜帶了 Option 字段的 DHCP 報文為例,其 Option 數量與位置如下圖所示:
Option 代碼的值從 0 ~ 255 都代表了不同的含義,或者說代表了不同的控制類型。每一個代碼的詳細說明請各位同學自行參閱相關文檔,這里給出文檔鏈接如下:
https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xml
3、Option60
Option60 就是指 Option 的代碼為 0x3c 的字段值。它通常用於攜帶設備標識符信息以供 DHCP 服務器鑒權使用。從理論上來說,任何設備都可以接入到 DHCP 服務器並請求獲得相應資源。但如果我們的 DHCP 所提供的這種服務是被“商業化”了的,那當然就需要這種鑒權機制了。鑒權不通過,我 DHCP 服務器就可以忽略掉這個設備的服務請求。這種鑒權,通常就是交由 Option60 來實現的。
Option60 的格式如下圖所示:
Option60 的配置在 Android4.4 中們於如下代碼文件:
.\frameworks\base\core\java\android\net\EthernetDataTracker.java
在系統起來以后開始 DHCP 獲取 DHCP 時會調用 runDhcp() 方法:
private void runDhcp()
然后會在這里讀取是否有開啟 Option60 的標志以及要攜帶的數據信息。 Option60 的開啟標志與數據信息通常可以在設置APK中設定。因為 Option60 常用於鑒權,因為有些設備是往 Option60 中填寫一個通行證信息,並會做適當的加密操作。
runDhcp() 方法中隨后會通過 NetworkUtils.runDhcpPlus() 方法來將相應參數傳遞下去。這個方法是一個 native 方法,它的最終實現位於:
.\frameworks\base\core\jni\android_net_NetUtils.cpp static jboolean android_net_utils_runDhcpCommon(...)
隨后又會調用 dhcp_do_request() 函數繼續傳遞參數,如下圖所示:
隨后就到以下代碼中了:
.\system\core\libnetutils\dhcp_utils.c
這個 dhcp_do_request() 函數所做的事情,基本就是:根據參數組裝啟動 dhcpcd 服務的命令以及將參數信息寫到系統屬性中去。如下圖所示:
再然后就是 dhcpcd 服務登場了。dhcpcd 服務代碼目錄如下:
./external/dhcpcd/
dhcpcd 服務在爬起來以后就會跑以下代碼的 main() 函數:
.\external\dhcpcd\dhcpcd.c int main(int argc, char **argv)
然后在如下圖所示的函數中解析有哪些 Option 是要添加組裝要攜帶的信息的:
.\external\dhcpcd\if-options.c
這里還是以 Option60 為例,它在 parse_option() 中的解析如下圖所示:
再接下來就到真正的發送 DHCP 數據報文的時候了。這個操作於 dhcp.c 代碼中實現:
.\box\external\dhcpcd\dhcp.c
ssize_t make_message(struct dhcp_message **message, const struct interface *iface, uint8_t type)
關於 Option60 的組裝如下圖所示。
這個指針 p 就是記錄 DHCP 報文字節流用的了。
再往下就是將報文送到網卡驅動發送出去了。
4、如何在DHCP網絡包中插入一個新的Option?
在 Android 系統中一般都會有 Option60 的完整實現,用戶只需在設置APK中設置相應信息即可自動實現 Option60 的字段攜帶。
但如何新增一個系統尚不支持的字段呢?
其實也很簡單。
前面第 3 節介紹的 Option60 的調用組裝流程照着來一次就行的了。這里就以新增一個 Option156 來簡單說說如何在 DHCP 中插入一個新的 Option字段。
首先的是應用層將相應信息傳遞下來的流程。這個就不多說了,同學根據自己的實際需求實現就好。
然后我們可以關注 EthernetDataTracker.java 中的 runDhcp() 方法。可以依照 Option60 的做法將 Option156 的信息傳遞到這里來。如下圖所示:
然后,筆者為了偷懶,就直接將 Option156 的信息在這里寫到系統屬性中去了。這種做法不太好,因為按照常,我們應該將 Option156 的信息一步步傳到 C 代碼層,根據參數來組裝啟動 dhcpcd 服務的參數的。
但筆者偷懶了。
就這樣吧。
再然后就到 if-option.h 中去新增用於保存 Option156 信息的結構體變量:
.\external\dhcpcd\if-options.h
接下來是去 if-options.c 中解析 Option156 的信息,並將它拷貝到結構體中。直接復制 Option60 的做法來就行了:
.\external\dhcpcd\if-options.c
最后去到 dhcp.c 的 make_message() 函數中完成最后的拼裝:
.\external\dhcpcd\dhcp.c
如此,開機時抓一個 DHCP 的網絡包,就可以發現筆者新增的 Option156 字段信息了,如下圖所示:
上圖網絡包 wireshark 提示了筆者添加的 Option156 值錯誤的警告。它的意思是說 Option156 這個字段的“內容”的長度只允許是 1。但筆者在這里給它攜帶了一個長度為 19 個字節的字符串。因為違反了規范,所以 wireshark 給出了警告。但這其實並不重要。只要你的 DHCP 服務器能解析出來,就沒有問題。
參考資料:
http://www.360doc.com/content/15/1130/09/8335678_516871788.shtml
https://blog.csdn.net/zzd_zzd/article/details/88372014
https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xml
https://tools.ietf.org/rfc/rfc6926.txt