- 論壇徽章:
- 0
|
前一段時(shí)間看到這篇帖子,確實(shí)很經(jīng)典,于是翻出了英文原版再讀,順便再翻譯出來(lái)供大家學(xué)習(xí),這篇文章的中文版也早都有了,不過(guò)出于完全理解的目的,我還是將它翻譯了出來(lái),加進(jìn)了自己的代碼,雖然在上一周的翻譯過(guò)程中,我盡量保留文章的原汁原味,但錯(cuò)誤肯定在所難免,在末尾附上原文和我自己調(diào)試通過(guò)的代碼,已經(jīng)夠構(gòu)運(yùn)行,大家可以參考一下!(有錯(cuò)誤之處請(qǐng)指出)
深入Linux內(nèi)核網(wǎng)絡(luò)堆棧
作者:bioforge alkerr@yifan.net
原名: <<Hacking the Linux Kernel Network Stack>>
翻譯,修改: duanjigang <duanjigang1983@126.com>
翻譯參考:raodan (raod_at_30san.com) 2003-08-22
第一章 簡(jiǎn)介
本文將描述如何利用Linux網(wǎng)絡(luò)堆棧的竅門(mén)(不一定都是漏洞)來(lái)達(dá)到一些目的,或者是惡意的,或者是出于其它意圖的。文中會(huì)就后門(mén)通訊對(duì)Netfilter鉤子進(jìn)行討論,并在本地機(jī)器上實(shí)現(xiàn)將這個(gè)傳輸從基于Libpcap的嗅探器(sniffer)中隱藏。
Netfilter是2.4內(nèi)核的一個(gè)子系統(tǒng)。Netfilter可以通過(guò)在內(nèi)核的網(wǎng)絡(luò)代碼中使用各種鉤子來(lái)實(shí)現(xiàn)數(shù)據(jù)包過(guò)濾,網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)和連接跟蹤等網(wǎng)絡(luò)欺騙。這些鉤子被放置在內(nèi)核代碼段,或者靜態(tài)編譯進(jìn)內(nèi)核,或者作為一個(gè)可動(dòng)態(tài)加載/卸載的可卸載模塊,然后就可以注冊(cè)稱(chēng)之為網(wǎng)絡(luò)事件的函數(shù)(比如數(shù)據(jù)包的接收)。
1.1 本文論述的內(nèi)容
本文將講述內(nèi)核模塊的編寫(xiě)者如何利用Netfilter的鉤子來(lái)達(dá)到任何目的,以及怎樣將網(wǎng)絡(luò)傳輸從一個(gè)Libpcap的應(yīng)用中隱藏掉。盡管Linux2.4支持對(duì)IPV4,IPV6以及DECnet的鉤子,本文只提及IPV4的鉤子。但是,對(duì)IPV4的大多數(shù)應(yīng)用內(nèi)容同樣也可以應(yīng)用于其他協(xié)議。出于教學(xué)目的,我們?cè)诟戒汚給出了一個(gè)可以工作的內(nèi)核模塊,實(shí)現(xiàn)基本的數(shù)據(jù)包過(guò)濾功能。針對(duì)本文中所列技術(shù)的所有開(kāi)發(fā)和試驗(yàn)都在Intel機(jī)子上的Linux2.4.5系統(tǒng)上進(jìn)行過(guò)。對(duì)Netfilte 鉤子行為的測(cè)試使用的是回環(huán)設(shè)備(Loopback device),以太網(wǎng)設(shè)備和一個(gè)點(diǎn)對(duì)點(diǎn)接口的調(diào)制解調(diào)器。
對(duì)Netfilter進(jìn)行完全理解是我撰寫(xiě)本文的另一個(gè)初衷。我不能保證這篇文章所附的代碼100%的沒(méi)有差錯(cuò),但是所列舉的所有代碼我都事先測(cè)試過(guò)了。我已經(jīng)飽嘗了內(nèi)核錯(cuò)誤帶來(lái)的磨礪,而你卻不必再經(jīng)受這些。同樣,我不會(huì)為按照這篇文檔所說(shuō)的任何東西進(jìn)行的作所所為帶來(lái)的損失而負(fù)責(zé)。閱讀本篇文章的讀者最好熟悉C程序設(shè)計(jì)語(yǔ)言,并且對(duì)內(nèi)核可卸載模塊有一定的經(jīng)驗(yàn)。
如果我在文中犯了任何錯(cuò)誤的話(huà),請(qǐng)告知我。我對(duì)于你們的建議和針對(duì)此文的改進(jìn)或者其它的Netfilter應(yīng)用會(huì)傾心接受。
1.2 本文不會(huì)涉及到的方面
本文并不是Netfilter的完全貫穿(或者進(jìn)進(jìn)出出的講解)。也不是iptables命令的介紹。如果你想更好的學(xué)習(xí)iptables的命令,可以去咨詢(xún)man手冊(cè)。
讓我們從介紹Nerfilter的使用開(kāi)始吧……….
第二章 各種NetFilter 鉤子及其用法
2.1 Linux內(nèi)核對(duì)數(shù)據(jù)包的處理
我將盡最大努力去分析內(nèi)核處理數(shù)據(jù)包的詳細(xì)內(nèi)幕,然而對(duì)于事件觸發(fā)處理以及之后的Netfilter 鉤子不做介紹。原因很簡(jiǎn)單,因?yàn)镠arald Welte 關(guān)于這個(gè)已經(jīng)寫(xiě)了一篇再好不過(guò)的文章<<Journey of a Packet Through the Linux 2.4 Network Stack>>,如果你想獲取更多關(guān)于Linux對(duì)數(shù)據(jù)包的相關(guān)處理知識(shí)的話(huà),我強(qiáng)烈建議你也閱讀一下這篇文章。目前,就認(rèn)為數(shù)據(jù)包只是經(jīng)過(guò)了Linux內(nèi)核的網(wǎng)絡(luò)堆棧,它穿過(guò)幾層鉤子,在經(jīng)過(guò)這些鉤子時(shí),數(shù)據(jù)包被解析,保留或者丟棄。這就是所謂的Netfilter 鉤子。
2.2 Ipv4中的Netfilter鉤子
Netfilter為IPV4定義了5個(gè)鉤子?梢栽 linux/netfilter-ipv4.h里面找到這些符號(hào)的定義,表2.1列出了這些鉤子。
表 2.1. ipv4中定義的鉤子
- 鉤子名稱(chēng) 調(diào)用時(shí)機(jī)
- NF_IP_PRE_ROUTING 完整性校驗(yàn)之后,路由決策之前
- NF_IP_LOCAL_IN 目的地為本機(jī),路由決策之后
- NF_IP_FORWARD 數(shù)據(jù)包要到達(dá)另外一個(gè)接口去
- NF_IP_LOCAL_OUT 本地進(jìn)程的數(shù)據(jù),發(fā)送出去的過(guò)程中
- NF_IP_POST_ROUTING 向外流出的數(shù)據(jù)上線(xiàn)之前
復(fù)制代碼
NF_IP_PRE_ROUTING 鉤子稱(chēng)為是數(shù)據(jù)包接收后第一個(gè)調(diào)用的鉤子程序,這個(gè)鉤子在我們后面提到的模塊當(dāng)中將會(huì)被用到。其他的鉤子也很重要,但是目前我們只集中探討NF_IP_PRE_ROUTING這個(gè)鉤子。
不管鉤子函數(shù)對(duì)數(shù)據(jù)包做了哪些處理,它都必須返回表2.2中的一個(gè)預(yù)定義好的Netfilter返回碼。
表2.2 Netfilter 返回碼
- 返回碼 含義
- NF_DROP 丟棄這個(gè)數(shù)據(jù)包
- NF_ACCEPT 保留這個(gè)數(shù)據(jù)包
- NF_STOLEN 忘掉這個(gè)數(shù)據(jù)包
- NF_QUEUE 讓這個(gè)數(shù)據(jù)包在用戶(hù)空間排隊(duì)
- NF_REPEAT 再次調(diào)用這個(gè)鉤子函數(shù)
復(fù)制代碼
NF_DROP 表示要丟棄這個(gè)數(shù)據(jù)包,并且為這個(gè)數(shù)據(jù)包申請(qǐng)的所有資源都要得到釋放。NF_ACCEPT告訴Netfilter到目前為止,這個(gè)數(shù)據(jù)包仍然可以被接受,應(yīng)該將它移到網(wǎng)絡(luò)堆棧的下一層。NF_STOLEN是非常有趣的一個(gè)返回碼,它告訴Netfilter讓其忘掉這個(gè)數(shù)據(jù)包。也就是說(shuō)鉤子函數(shù)會(huì)在這里對(duì)這個(gè)數(shù)據(jù)包進(jìn)行完全的處理,而Netfilter就應(yīng)該放棄任何對(duì)它的處理了。然而這并不意味著為該數(shù)據(jù)包申請(qǐng)的所有資源都要釋放掉。這個(gè)數(shù)據(jù)包和它各自的sk_buff結(jié)構(gòu)體依然有效,只是鉤子函數(shù)從Netfilter奪取了對(duì)這個(gè)數(shù)據(jù)包的掌控權(quán)。不幸的是,我對(duì)于NF_QUEUE這個(gè)返回碼的真實(shí)作用還不是很清楚,所在目前不對(duì)它進(jìn)行討論。最后一個(gè)返回值NF_REPEAT請(qǐng)求Netfilter再次調(diào)用這個(gè)鉤子函數(shù),很明顯,你應(yīng)該慎重的應(yīng)用這個(gè)返回值,以免程序陷入死循環(huán)。
第三章 注冊(cè)和注銷(xiāo)NetFilter 鉤子
注冊(cè)一個(gè)鉤子函數(shù)是一個(gè)圍繞nf_hook_ops結(jié)構(gòu)體的很簡(jiǎn)單的過(guò)程,在linux/netfilter.h中有這個(gè)結(jié)構(gòu)體的定義,定義如下:
- 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;
- };
復(fù)制代碼
這個(gè)結(jié)構(gòu)體的成員列表主要是用來(lái)維護(hù)注冊(cè)的鉤子函數(shù)列表的,對(duì)于用戶(hù)來(lái)說(shuō),在注冊(cè)時(shí)并沒(méi)有多么重要。hook是指向nf_hookfn函數(shù)的指針。也就是為這個(gè)鉤子將要調(diào)用的所有函數(shù)。nf_hookfn同樣定義在linux/netfilter.h這個(gè)文件中。pf字段指定了協(xié)議簇(protocol family)。Linux/socket.h中定義了可用的協(xié)議簇。但是對(duì)于IPV4我們只使用PF_INET。hooknum 域指名了為哪個(gè)特殊的鉤子安裝這個(gè)函數(shù),也就是表2.1中所列出的條目中的一個(gè)。Priority域表示在運(yùn)行時(shí)這個(gè)鉤子函數(shù)執(zhí)行的順序。為了演示例子模塊,我們選擇NF_IP_PRI_FIRST這個(gè)優(yōu)先級(jí)。
注冊(cè)一個(gè)Netfilter鉤子要用到nf_hook_ops這個(gè)結(jié)構(gòu)體和nf_register_hook()函數(shù)。nf_register_hook()函數(shù)以一個(gè)nf_hook_ops結(jié)構(gòu)體的地址作為參數(shù),返回一個(gè)整型值。如果你閱讀了net/core/netfilter.c中nf_register_鉤子()的源代碼的話(huà),你就會(huì)發(fā)現(xiàn)這個(gè)函數(shù)只返回了一個(gè)0。下面這個(gè)例子注冊(cè)了一個(gè)丟棄所有進(jìn)入的數(shù)據(jù)包的函數(shù)。這段代碼同時(shí)會(huì)向你演示Netfilter的返回值是如何被解析的。
代碼列表1. Netfilter鉤子的注冊(cè)
- /* Sample code to install a Netfilter hook function that will
- * drop all incoming packets. */
- #define __KERNEL__
- #define MODULE
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/netfilter.h>
- #include <linux/netfilter_ipv4.h>
- /* This is the structure we shall use to register our function */
- static struct nf_hook_ops nfho;
- /* This is the hook function itself */
- unsigned int hook_func(unsigned int hooknum,
- struct sk_buff **skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
- {
- return NF_DROP; /* Drop ALL packets */
- }
- /* Initialisation routine */
- int init_module()
- {
- /* Fill in our hook structure */
- nfho.hook = hook_func; /* Handler function */
- nfho.hooknum = NF_IP_PRE_ROUTING; /* First hook for IPv4 */
- nfho.pf = PF_INET;
- nfho.priority = NF_IP_PRI_FIRST; /* Make our function first */
- nf_register_hook(&nfho);
- return 0;
- }
- /* Cleanup routine */
- void cleanup_module()
- {
- nf_unregister_hook(&nfho);
- }
復(fù)制代碼
這就是注冊(cè)所要做的一切。從代碼列表1你可以看到注銷(xiāo)一個(gè)Netfilter鉤子也是很簡(jiǎn)單的一件事情,只需要調(diào)用nf_unregister_hook()函數(shù),并將注冊(cè)時(shí)用到的結(jié)構(gòu)體地址再次作為注銷(xiāo)函數(shù)參數(shù)使用就可以了。
第四章 基本的NetFilter數(shù)據(jù)包過(guò)濾技術(shù)
4.1 鉤子函數(shù)近距離接觸
現(xiàn)在是我們來(lái)查看獲得的數(shù)據(jù)如何傳入鉤子函數(shù)并被用來(lái)進(jìn)行過(guò)濾決策的時(shí)候了。所以,我們需要更多的關(guān)注于nf_hookfn函數(shù)的模型。Linux/netfilter.h給出了如下的接口定義:
- typedef unsigned int nf_hookfn(unsigned int hooknum,
- struct sk_buff **skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *));
復(fù)制代碼
nf_hookfn函數(shù)的第一個(gè)參數(shù)指定了表2.1給出的鉤子類(lèi)型中的一種。第二個(gè)參數(shù)更有趣,它是一個(gè)指向指針(這個(gè)指針指向一個(gè)sk_buff類(lèi)型的結(jié)構(gòu)體)的指針,它是網(wǎng)絡(luò)堆棧用來(lái)描述數(shù)據(jù)包的結(jié)構(gòu)體。這個(gè)結(jié)構(gòu)體定義在linux/skbuff.h中,由于這個(gè)結(jié)構(gòu)體的定義很大,這里我只著重于它當(dāng)中更有趣的一些域。
或許sk_buff結(jié)構(gòu)體中最有用的域就是其中的三個(gè)聯(lián)合了,這三個(gè)聯(lián)合描述了傳輸層的頭信息(例如 UDP,TCP,ICMP,SPX),網(wǎng)絡(luò)層的頭信息(例如ipv4/6, IPX, RAW)和鏈路層的頭信息(Ethernet 或者RAW)。三個(gè)聯(lián)合相應(yīng)的名字分別為:h,nh和mac。根據(jù)特定數(shù)據(jù)包使用的不同協(xié)議,這些聯(lián)合包含了不同的結(jié)構(gòu)體。應(yīng)當(dāng)注意,傳輸層的頭和網(wǎng)絡(luò)層的頭極有可能在內(nèi)存中指向相同的內(nèi)存單元。在TCP數(shù)據(jù)包中也是這樣的情況,h和nh都是指向IP頭結(jié)構(gòu)體的指針。這就意味著,如果認(rèn)為h->th指向TCP頭,從而想通過(guò)h->th來(lái)獲取一個(gè)值的話(huà),將會(huì)導(dǎo)致錯(cuò)誤發(fā)生。因?yàn)閔->th實(shí)際指向IP頭,等同于nh->iph。
其他比較有趣的域就是len域和data域了。len表示包中從data開(kāi)始的數(shù)據(jù)總長(zhǎng)度。因此,現(xiàn)在我們就知道如何通過(guò)一個(gè)skbuff結(jié)構(gòu)體去訪問(wèn)單個(gè)的協(xié)議頭或者數(shù)據(jù)包本身的數(shù)據(jù)。還有什么有趣的數(shù)據(jù)位對(duì)于Netfilter的鉤子函數(shù)而言是有用的呢?
跟在sk_buff之后的兩個(gè)參數(shù)都是指向net_device結(jié)構(gòu)體的指針。net_devices結(jié)構(gòu)體是Linux內(nèi)核用來(lái)描述各種網(wǎng)絡(luò)接口的。第一個(gè)結(jié)構(gòu)體,in,代表了數(shù)據(jù)包將要到達(dá)的接口,當(dāng)然 out就代表了數(shù)據(jù)包將要離開(kāi)的接口。有很重要的一點(diǎn)必須認(rèn)識(shí)到,那就是通常情況下這兩個(gè)參數(shù)最多只提供一個(gè)。 例如,in通常情況下只會(huì)被提供給NF_IP_PRE_ROUTING和NF_IP_LOCAL_IN鉤子。out通常只被提供給NF_IP_LOCAL_OUT和NF_IP_POST_ROUTING鉤子。在這個(gè)階段,我沒(méi)有測(cè)試他們中的那個(gè)對(duì)于NF_IP_FORWARD是可用的。如果你能在廢棄之前確認(rèn)它們(in和out)不空的話(huà),那么你很優(yōu)秀。
最后,傳給鉤子函數(shù)的最后一個(gè)參數(shù)是一個(gè)名為okfn的指向函數(shù)的指針,這個(gè)函數(shù)有一個(gè)sk_buff的結(jié)構(gòu)體作為參數(shù),返回一個(gè)整型值。我也不能確定這個(gè)函數(shù)做什么,在net/core/netfilter.c中有兩處對(duì)此函數(shù)的調(diào)用。這兩處調(diào)用就是在函數(shù)nf_hook_slow()和函數(shù)nf_reinject()里,在這兩個(gè)調(diào)用處當(dāng)Netfilter鉤子的返回值為NF_ACCEPT時(shí),此函數(shù)被調(diào)用。如果有誰(shuí)知道關(guān)于okfn更詳細(xì)的信息,請(qǐng)告訴我。
現(xiàn)在我們已經(jīng)對(duì)Netfilter接收到的數(shù)據(jù)中最有趣和最有用的部分進(jìn)行了分析,下面就要開(kāi)始介紹如何利用這些信息對(duì)數(shù)據(jù)包進(jìn)行各種各樣的過(guò)濾。
4.2 基于接口的過(guò)濾
這將是我們能做的最簡(jiǎn)單的過(guò)濾技術(shù)。是否還記得我們的鉤子函數(shù)接收到的net_device結(jié)構(gòu)體?利用net_device結(jié)構(gòu)體中的name鍵值,我們可以根據(jù)數(shù)據(jù)包的目的接口名或者源接口名來(lái)丟棄這些數(shù)據(jù)包。為了拋棄所有發(fā)向”eth0”的數(shù)據(jù),我們只需要比較一下“in->name”和“eth0”,如果匹配的話(huà),鉤子函數(shù)返回NF_DROP,然后這個(gè)數(shù)據(jù)包就被銷(xiāo)毀了。它就是這樣的簡(jiǎn)單。列表2給出了示例代碼。請(qǐng)注意輕量級(jí)防火墻(LWFW)會(huì)使用到這里提到的所有過(guò)濾方法。LWFW同時(shí)還包含了一個(gè)IOCTL方法來(lái)動(dòng)態(tài)改變自身的行為。
列表2. 基于源接口(網(wǎng)卡名)的數(shù)據(jù)過(guò)濾技術(shù)
- /* Sample code to install a Netfilter hook function that will
- * drop all incoming packets from an IP address we specify */
- #define __KERNEL__
- #define MODULE
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/skbuff.h>
- #include <linux/ip.h> /* For IP header */
- #include <linux/netfilter.h>
- #include <linux/netfilter_ipv4.h>
- /* This is the structure we shall use to register our function */
- static struct nf_hook_ops nfho;
- /* IP address we want to drop packets from, in NB order */
- static unsigned char *drop_ip = "\x7f\x00\x00\x01";
- /* This is the hook function itself */
- unsigned int hook_func(unsigned int hook_num,
- struct sk_buff **skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
- {
- struct sk_buff *sb = *skb;
- if (sb->nh.iph->saddr == drop_ip) {
- printk("Dropped packet from... %d.%d.%d.%d\n",
- *drop_ip, *(drop_ip + 1),
- *(drop_ip + 2), *(drop_ip + 3));
- return NF_DROP;
- } else {
- return NF_ACCEPT;
- }
- }
- /* Initialisation routine */
- int init_module()
- {
- /* Fill in our hook structure */
- nfho.hook = hook_func;
- /* Handler function */
- nfho.hook_num = NF_IP_PRE_ROUTING; /* First for IPv4 */
- nfho.pf = PF_INET;
- nfho.priority = NF_IP_PRI_FIRST; /* Make our func first */
-
- nf_register_hook(&nfho);
- return 0;
- }
-
- /* Cleanup routine */
- void cleanup_module()
- {
- nf_unregister_hook(&nfho);
- }
復(fù)制代碼
現(xiàn)在看看,是不是很簡(jiǎn)單?下面讓我們看看基于IP地址的過(guò)濾技術(shù)。
4.3 基于IP地址的過(guò)濾
類(lèi)似基于接口的數(shù)據(jù)包過(guò)濾技術(shù),基于源/目的IP地址的數(shù)據(jù)包過(guò)濾技術(shù)也很簡(jiǎn)單。這次我們對(duì)sk_buff結(jié)構(gòu)體比較感興趣,F(xiàn)在應(yīng)該記起來(lái),Skb參數(shù)是一個(gè)指向sk_buff結(jié)構(gòu)體的指針的指針。為了避免運(yùn)行時(shí)出現(xiàn)錯(cuò)誤,通常有一個(gè)好的習(xí)慣就是另外聲明一個(gè)指針指向sk_buff結(jié)構(gòu)體的指針,把它賦值為雙重指針?biāo)赶虻膬?nèi)容,像這樣:
- struct sk_buff *sb = *skb; /* Remove 1 level of indirection* /
復(fù)制代碼
然后你只需要引用一次就可以訪問(wèn)結(jié)構(gòu)體中的成員了?梢允褂胹k_buff結(jié)構(gòu)體中的網(wǎng)絡(luò)層頭信息來(lái)獲取此數(shù)據(jù)包的IP頭信息。這個(gè)頭包含在一個(gè)聯(lián)合中,可以通過(guò)sk_buff->nh.iph來(lái)獲取。列表3的函數(shù)演示了當(dāng)給定一個(gè)數(shù)據(jù)包的sk_buff結(jié)構(gòu)時(shí),如何根據(jù)給定的要拒絕的IP對(duì)這個(gè)數(shù)據(jù)包進(jìn)行源IP地址的檢驗(yàn)。這段代碼是直接從LWFW中拉出來(lái)的。唯一的不同之處就是LWFW中對(duì)LWFW統(tǒng)計(jì)量的更新被去掉了。
列表3.檢測(cè)接收到數(shù)據(jù)包的源IP地址
- unsigned char *deny_ip = "\x7f\x00\x00\x01"; /* 127.0.0.1 */
-
- ...
- static int check_ip_packet(struct sk_buff *skb)
- {
- /* We don't want any NULL pointers in the chain to
- * the IP header. */
- if (!skb )return NF_ACCEPT;
- if (!(skb->nh.iph)) return NF_ACCEPT;
- if (skb->nh.iph->saddr == *(unsigned int *)deny_ip)
- {
- return NF_DROP;
- }
- return NF_ACCEPT;
- }
復(fù)制代碼
如果源IP地址與我們想拋棄數(shù)據(jù)包的IP地址匹配的話(huà),數(shù)據(jù)包就會(huì)被丟棄。為了使函數(shù)能正常工作,deny_ip的值應(yīng)該以網(wǎng)絡(luò)字節(jié)序的方式存儲(chǔ)(與intel相反的Big-endian格式)。盡管這個(gè)函數(shù)在被調(diào)用的時(shí)候有一個(gè)空指針作參數(shù)這種情況不太可能,但是稍微偏執(zhí)(小心)一點(diǎn)總不會(huì)有什么壞處。當(dāng)然,如果調(diào)用時(shí)出現(xiàn)了差錯(cuò)的話(huà),函數(shù)將會(huì)返回一個(gè)NF_ACCEPT值,以便于Netfilter能夠繼續(xù)處理這個(gè)數(shù)據(jù)包。列表4 展現(xiàn)了一個(gè)簡(jiǎn)單的基于IP地址的數(shù)據(jù)包過(guò)濾的模塊,這個(gè)模塊是由基于接口的過(guò)濾模塊修改得到的。你可以修改IP地址來(lái)實(shí)現(xiàn)對(duì)指定IP地址發(fā)來(lái)的數(shù)據(jù)包的丟棄。
列表4. 基于數(shù)據(jù)包源IP地址的過(guò)濾技術(shù)
- /* Sample code to install a Netfilter hook function that will
- * drop all incoming packets from an IP address we specify */
- #define __KERNEL__
- #define MODULE
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/skbuff.h>
- #include <linux/ip.h> /* For IP header */
- #include <linux/netfilter.h>
- #include <linux/netfilter_ipv4.h>
- /* This is the structure we shall use to register our function */
- static struct nf_hook_ops nfho;
- /* IP address we want to drop packets from, in NB order */
- static unsigned char *drop_ip = "\x7f\x00\x00\x01";
- /* This is the hook function itself */
- unsigned int hook_func(unsigned int hooknum,
- struct sk_buff **skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
- {
- struct sk_buff *sb = *skb;
- if (sb->nh.iph->saddr == drop_ip) {
- printk("Dropped packet from... %d.%d.%d.%d\n",
- *drop_ip, *(drop_ip + 1),
- *(drop_ip + 2), *(drop_ip + 3));
- return NF_DROP;
- } else {
- return NF_ACCEPT;
- }
- }
- /* Initialisation routine */
- int init_module()
- {
- /* Fill in our hook structure */
- nfho.hook = hook_func;
- /* Handler function */
- nfho.hooknum = NF_IP_PRE_ROUTING; /* First for IPv4 */
- nfho.pf = PF_INET;
- nfho.priority = NF_IP_PRI_FIRST; /* Make our func first */
- nf_register_hook(&nfho);
- return 0;
- }
- /* Cleanup routine */
- void cleanup_module()
- {
- nf_unregister_hook(&nfho);
- }
復(fù)制代碼
4.4 基于TCP端口的過(guò)濾
另外一個(gè)要執(zhí)行的簡(jiǎn)單的規(guī)則就是基于TCP目的端口的數(shù)據(jù)包過(guò)濾。這比檢驗(yàn)IP地址稍微復(fù)雜一點(diǎn),因?yàn)槲覀円约簞?chuàng)建一個(gè)指向TCP頭的指針。還記得前面關(guān)于傳輸層頭和網(wǎng)絡(luò)層頭所做的討論嗎?獲得一個(gè)TCP頭指針很簡(jiǎn)單,只需要申請(qǐng)一個(gè)指向tcphdr(定義在linux/tcp.h中)結(jié)構(gòu)體的指針,并將它指向包數(shù)據(jù)中的IP頭后面。或許一個(gè)例子就可以了。列表5展示了怎樣檢測(cè)一個(gè)數(shù)據(jù)包的TCP目的端口與我們想丟棄數(shù)據(jù)的指定端口是否一致。與列表3一樣,這段代碼也是從LWFW中拿出來(lái)的
列表5. 檢測(cè)接收到數(shù)據(jù)包的TCP目的端口
- unsigned char *deny_port = "\x00\x19"; /* port 25 */
- ...
- static int check_tcp_packet(struct sk_buff *skb)
- {
- struct tcphdr *thead;
- /* We don't want any NULL pointers in the chain
- * to the IP header. */
- if (!skb ) return NF_ACCEPT;
- if (!(skb->nh.iph)) return NF_ACCEPT;
- /* Be sure this is a TCP packet first */
- if (skb->nh.iph->protocol != IPPROTO_TCP) {
- return NF_ACCEPT;
- }
- thead = (struct tcphdr *)(skb->data + (skb->nh.iph->ihl * 4));
- /* Now check the destination port */
- if ((thead->dest) == *(unsigned short *)deny_port) {
- return NF_DROP;
- }
- return NF_ACCEPT;
- }
復(fù)制代碼
世紀(jì)上非常簡(jiǎn)單。不要忘了deny_port是網(wǎng)絡(luò)字節(jié)序時(shí),這個(gè)函數(shù)才能工作。數(shù)據(jù)包過(guò)濾技術(shù)的基礎(chǔ)就是:對(duì)于一個(gè)特定的數(shù)據(jù)包,你必須對(duì)怎樣到達(dá)你想要的信息段的方法非常了解。下面,我們將進(jìn)入更有趣的世界。
[ 本帖最后由 duanjigang 于 2006-5-21 18:45 編輯 ] |
-
-
souce.rar
2006-05-21 09:43 上傳
點(diǎn)擊文件名下載附件
39.03 KB, 下載次數(shù): 202
|