Linux系統中的Netfilter提供了一個抽象通用化的框架該框架定義的一個子功能的實現就是包過濾子系統框架包含以下五部分
為每種網絡協議(IPvIPv等)定義一套鉤子函數(IPv定義了個鉤子函數)
這些鉤子函數在數據報流過協議棧的幾個關鍵點被調用在這幾個點中協議棧將把數據報及鉤子函數標號作為參數調用Netfilter框架
內核的任何模塊可以對每種協議的一個或多個鉤子進行注冊實現掛接這樣當某個數據包被傳遞給Netfilter框架時內核能檢測是否有任何模塊對該協議和鉤子函數進行了注冊若注冊了則調用該模塊的注冊時使用的回調函數這樣這些模塊就有機會檢查(可能還會修改)該數據包丟棄該數據包及指示Netfilter將該數據包傳入用戶空間的隊列
那些排隊的數據包是被傳遞給用戶空間的異步地進行處理一個用戶進程能檢查數據包修改數據包甚至可以重新將該數據包通過離開內核的同一個鉤子函數中注入到內核中
任何在IP層要被拋棄的IP數據包在真正拋棄之前都要進行檢查例如允許模塊檢查IPSpoofed包(被路由拋棄)
IP層的五個HOOK點的位置如下所示
()NF_IP_PRE_ROUTING剛剛進入網絡層的數據包通過此點(剛剛進行完版本號校驗
和等檢測)源地址轉換在此點進行IP_Inputc中IP_Rcv調用
()NF_IP_LOCAL_IN經路由查找後送往本機的通過此檢查點INPUT包過濾在此點進行IP_local_deliver中調用
()NF_IP_FORWARD要轉發的包通過此檢測點FORWORD包過濾在此點進行
()NF_IP_POST_ROUTING所有馬上便要通過網絡設備出去的包通過此檢測點內置的目的地址轉換功能(包括地址偽裝)在此點進行
()NF_IP_LOCAL_OUT本機進程發出的包通過此檢測點OUTPUT包過濾在此點進行
這些點是已經在內核中定義好的內核模塊能夠注冊在這些HOOK點進行的處理可使用nf_register_hook函數指定在數據報經過這些鉤子函數時被調用從而模塊可以修改這些數據報並向Netfilter返回如下值
NF_ACCEPT 繼續正常傳輸數據報
NF_DROP 丟棄該數據報不再傳輸
NF_STOLEN 模塊接管該數據報不要繼續傳輸該數據報
NF_QUEUE 對該數據報進行排隊(通常用於將數據報給用戶空間的進程進行處理)
NF_REPEAT 再次調用該鉤子函數
NF_ACCEPT 繼續正常傳輸數據報
NF_DROP 丟棄該數據報不再傳輸
NF_STOLEN 模塊接管該數據報不要繼續傳輸該數據報
NF_QUEUE 對該數據報進行排隊(通常用於將數據報給用戶空間的進程進行處理)
NF_REPEAT 再次調用該鉤子函數
一個基於Netfilter框架的稱為IPtables的數據報選擇系統在Linux內核中被應用其實它就是IPchains的後繼工具但卻有更強的可擴展性內核模塊可以注冊一個新的規則表(table)並要求數據報流經指定的規則表這種數據報選擇用於實現數據報過濾(filter表)網絡地址轉換(Nat表)及數據報處理(Mangle表)
Linux內核提供的這三種數據報處理功能都基於Netfilter的鉤子函數和IP表它們是獨立的模塊相互之間是獨立的它們都完美的集成到由Netfileter提供的框架中
包過濾
Filter表格不會對數據報進行修改而只對數據報進行過濾IPtables優於IPchains的一個方面就是它更為小巧和快速它是通過鉤子函數NF_IP_LOCAL_INNF_IP_FORWARD及NF_IP_LOCAL_OUT接入Netfilter框架的因此對於任何一個數
報只有一個地方對其進行過濾這相對IPchains來說是一個巨大的改進因為在IPchains中一個被轉發的數據報會遍歷三條鏈
NAT
NAT表格監聽三個Netfilter鉤子函數NF_IP_PRE_ROUTINGNF_IP_POST_ROUTING及NF_IP_LOCAL_OUT
NF_IP_PRE_ROUTING實現對需要轉發的數據報的源地址進行地址轉換而NF_IP_POST_ROUTING則對需要轉發的數據包的目的地址進行地址轉換對於本地數據報的目的地址的轉換則由NF_IP_LOCAL_OUT來實現NAT表格不同於filter表格因為只有新連接的第一個數據報將遍歷表格而隨後的數據報將根據第一個數據報的結果進行同樣的轉換處理NAT表格被用在源NAT目的NAT偽裝(其是源NAT的一個特例)及透明代理(其是目的NAT的一個特例)
數據報處理(Packet Mangling)
Mangle表格在NF_IP_PRE_ROUTING和NF_IP_LOCAL_OUT鉤子中進行注冊使用
mangle表可以實現對數據報的修改或給數據報附上一些帶外數據當前mangle表支持修改TOS位及設置skb的nfmard字段
源碼分析
如果我們想加入自己的代碼便要用nf_register_hook函數其函數原型為
int nf_register_hook(struct nf_hook_ops *reg)
struct nf_hook_ops
{
struct list_head list;
/* User fills in from here down */
nf_hookfn *hook;
int pf;
int hooknum;
/* Hooks are ordered in ascending priority */
int priority;
};
From:http://tw.wingwit.com/Article/os/fwq/201404/30370.html