一般而言,防火牆都是嵌入在linux核心協議棧的處理過程中,執行在核心位址空間。這就要求開發者深入理解和掌握核心,以及核心協議棧的**。對於普通開發者來說,此要求顯然過於苛刻。為此,linux核心在netfilter框架的基礎上提供了ip queue機制,使得基於使用者態(user mode)的防火牆開發成為可能。
下面詳細闡述ip queue的原理及其程式設計介面。
核心報文處理流程
首先,大致了解一下核心處理資料報文的流程。正確理解這個流程,對於編寫完善的防火牆非常有幫助。
如圖1所示,在核心的ip報文處理過程中,散布了一些hook點(圖中橢圓形的節點),在這些點上,可以掛載外部處理函式,進行定製的報文處理。
圖1 linux核心報文處理流程簡圖
資料報文從圖1左邊「接收」處進入核心協議棧,經過hook點pre_routing後,進行路由選擇。若是發往本機的ip報文,則在經過hook點local_in後提交給本地的上層協議處理。如果是需要**的ip報文,則該報文在依次經過forward和post_routing兩個hook點後,被發往網路介面。
本地輸出的ip報文將先通過hook點local_out,再根據路由選擇,經過hook點post_routing以後,被發往網路介面。
上述這些hook點掛載的處理函式將返回適當的值,告知協議棧應該如何繼續處理當前報文。具體分為以下各值:
nf_drop 丟棄該報文,釋放所有與該報文相關的資源;
nf_accept 接受該報文,並繼續處理;
nf_stolen 該報文已經被hook函式接管,協議棧無須繼續處理;
nf_queue 將該報文傳遞到使用者態去做進一步的處理;
nf_repeat 再次呼叫本hook函式。
當hook處理函式返回nf_queue值時,核心協議棧將通過linux netlink通訊機制把當前報文傳遞到使用者態,由使用者態的防火牆程式進行處理。這樣,只要能夠在相應的hook點上返回nf_queue值,就可以安心地在使用者態使用自己的程式來過濾報文了,這個功能可以由iptables實現。
netlink機制
上面提到,使用ip queue的使用者態防火牆程式是通過netlink機制和核心協議棧進行通訊的。netlink是linux系統特有的、基於socket程式設計介面的通訊機制。
它是乙個面向資料報文的服務,並提供「路由操作(netlink_route)」、「ip queue操作(netlink_firewall)」和「使用者態arp表操作(netlink_arpd)」等通訊協議。在建立ipqueue netlink socket時,將採用如下系統呼叫:
fd = socket(pf_netlink, sock_raw, netlink_firewall);
這裡,pf_netlink指明要建立netlink socket;sock_raw指明採用原始套接字,也可以採用sock_dgram,因為netlink機制的實現並不區分sock_raw和sock_dgram;引數netlink_firewall則指明通訊協議採用ip queue。
既然ip queue是基於netlink的,其訊息格式自然也遵從netlink的規範。netlink訊息由兩部分組成:訊息頭(struct nlmsghdr)和資料負載(data payload)。
訊息頭的定義如下:
struct nlmsghdr;
所有的ip queue訊息都將包含乙個struct nlmsghdr訊息頭,具體的ip queue訊息則包含在netlink訊息的資料負載中。有關netlink訊息格式的詳情可以參見手冊頁netlink(7)。
ip queue程式設計介面
使用ip queue機制的程式必須包含如下的標頭檔案:
#include
在這個標頭檔案中定義了所有ip queue訊息的格式。
ip queue訊息可以分為兩大類:由核心協議棧發給使用者態程序的ip queue訊息和由使用者態程序發給核心的ip queue訊息。
由核心協議棧發給使用者態程序的ip queue訊息(nlmsghdr.nlmsg_type = ipqm_packet),其資料型別為ipq_packet_msg_t,定義如下:
typedef struct ipq_packet_msg ipq_packet_msg_t;
這個資料結構也被稱為「報文的元資料」。核心除可以單獨向使用者程序傳遞「報文的元資料」以外,也可以同時傳遞報文本身。此時,報文本身將儲存在ipq_packet_msg_t資料成員payload開始的地方。
由使用者態程序發給核心的訊息,其資料型別為ipq_peer_msg_t,定義如下:
typedef struct ipq_peer_msg msg;
} ipq_peer_msg_t;
由上述定義可知,這類訊息又分為「模式設定訊息(nlmsghdr.nlmsg_type = ipqm_mode)」和「斷言訊息(nlmsghdr.nlmsg_type = ipqm_verdict)」兩個子類。
「模式設定訊息」的資料型別定義如下:
typedef struct ipq_mode_msg ipq_mode_msg_t;
這裡,請求模式value的值可以是ipq_copy_none、ipq_copy_meta和ipq_copy_packet。當指定請求模式value為ipq_copy_none時,報文將被丟棄;當為ipq_copy_meta時,核心將在其後的報文傳遞中只傳遞「報文的元資料」;當為ipq_copy_packet時,核心將同時傳遞「報文的元資料」和報文本身,報文本身的傳遞長度由ipq_mode_msg_t的另乙個資料成員range指定。ip報文的最大長度為0xffff。
另一子類即「斷言訊息」,其資料型別定義如下:
typedef struct ipq_verdict_msg ipq_verdict_msg_t;
其中,value是使用者態程式回傳給核心的當前報文的處理意見,可以是nf_accept或nf_drop等值。id則是用以區分報文的標識號,即核心傳來的ipq_packet_msg_t結構中的packet_id。當使用者態程式修改了當前報文以後,需要將報文重新傳遞歸核心,此時,新的報文內容必須儲存在payload的開始處,並由data_len指明新報文的長度。
從上述內容可以看出,在整個ip queue的報文傳遞過程中,使用者態程式和核心協議棧之間的互動順序是,首先,使用者態程式利用「模式設定訊息」告訴核心協議棧所請求的報文傳遞模式。
然後,根據這個模式,核心組織好等待傳遞的訊息,通過netlink socket發給使用者態程式。最後,使用者態程式根據自己的防火牆規則,得出該報文的處理意見(可能同時修改當前報文),並回傳給核心。
編譯和執行防火牆
要編譯和執行防火牆程式,執行如下命令:
# gcc o ipqfw ipqfw.c
# ./ipqfw &
ipqfw.c是防火牆的**檔案。
為了在路由器上過濾**的ip報文,需要執行如下命令:
# iptables a forward j queue
這樣,所有經過hook點forward的報文都將被送到使用者態防火牆進行處理,使用者可以自行編寫適合具體情況的防火牆。
如何用vc編寫dll檔案
如何用vc編寫dll檔案 動態連線庫最大的特點就是能節省磁碟空間.當多個程序共享同乙個dll的時候,記憶體中只有乙個dll的 通過對映來使各個程序得以呼叫.1.用vc建立乙個win32 dll 我們利用vc編寫dll有幾種方法.如果用vc建立乙個win32 dll 工程.那這個工程就應該只匯出c 的...
Python 如何用python編寫無限猴子定理
python資料結構與演算法 一書中有無限猴子定理一題,問題如下 蒐集網上 除錯如下 import random num 1000 char list chr c ord a for c in range 26 返回c ord a 對應的ascii碼,a z 新增空格 該列表內的字元一共有27個 t...
如何用linux系統編寫c程式
目錄 toc 本部落格在我學習linux過程將持續更新 1 1 按下快捷鍵開啟終端 ctrl alt t 2 從左側工具欄中開啟終端。1.cd cd指返回當前目錄 如cd desktop program 便是指返回到desktop 桌面 的program 資料夾 2.gedit gedit指開啟某檔...