目錄:
-. 前言
二. 分析
三. 例子代碼
四. 附錄:與2.2在應用方面的區別簡介
五. 後記
-.前言
在Linux2.2內核中的防火牆ipchains已經被用戶廣泛認可,它提供了完整的防火牆功
能(包過濾,地址偽裝,透明代理),又避免了商業防火牆那高的驚人的價格。如果
你用的是某款國產防火牆,那麼十有八九你實際在受到ipchains(有些甚至是2.0系列
中ipfwadm)的保護:-).在未來的2.4內核中,被稱為netfilter(http://netfilter.
kernelnotes.org/)的防火牆以更好的結構重新構造,並實現了許多新功能,如完整的
動態NAT(2.2內核實際是多對一的"地址偽裝"),基於MAC及用戶的過濾,真正的基於狀
態的過濾(不再是簡單的查看tcp的標志位等),包速率限制等。
在原有的網絡部分的LKM中,如果對網絡部分進行處理,一般是先生成strUCt packet
_type結構,在用dev_add_pack將其插入網絡層(注意此時的packet_type實際相當於一
個的三層的協議,如ip_packet_type,ipx_8023_packet_type等),具體的例子可參見
phrack 55期 和本月小四寫的月刊文章<利用
LLKM處理網絡通信----對抗IDS、Firewall>。
而netfilter本身在IP層內提供了另外的5個插入點(其文檔中稱為HOOK):
NF_IP_PRE_ROUTING,NF_IP_LOCAL_IN,NF_IP_FORWARD,NF_IP_LOCAL_OUT,NF_IP_POST
_ROUTING,分別對應IP層的五個不同位置,這樣理論上在寫lkm時便可以選擇更適合的切
入點,再輔以netfilter內置的新功能(如connect tracking),應該會幫助寫出功能更
強的lkm。
本來准備寫出一個完整的例子(限制IP連接數),但計劃總趕不上變化:-(,只好先貼
出個簡單的例子來,權且自我安慰成拋磚引玉了。
本文的參考配置是linux2.4.0-test4和iptable-1.1.1,好,開始拋磚,閃人喽!
二.分析
通俗的說,netfilter的架構就是在整個網絡流程的若干位置放置了一些檢測點(HOOK
),而在每個檢測點上上登記了一些處理函數進行處理(如包過濾,NAT等,甚至可以是
用戶自定義的功能)。
IP層的五個HOOK點的位置如下圖所示(copy from ) :
--->[1]--->[ROUTE]--->[3]--->[4]--->
^
[ROUTE]
v
[2] [5]
^
v
[local process]
[1]:NF_IP_PRE_ROUTING:剛剛進入網絡層的數據包通過此點(剛剛進行完版本號,校驗
和等檢測), 源地址轉換在此點進行;
[2]:NF_IP_LOCAL_IN:經路由查找後,送往本機的通過此檢查點,INPUT包過濾在此點進行;
[3]:NF_IP_FORWARD:要轉發的包通過此檢測點,FORWord包過濾在此點進行;
[4]:NF_IP_POST_ROUTING:所有馬上便要通過網絡設備出去的包通過此檢測點,內置的目
的地址轉換功能(包括地址偽裝)在此點進行;
[5]:NF_IP_LOCAL_OUT:本機進程發出的包通過此檢測點,OUTPUT包過濾在此點進行。
在IP層代碼中,有一些帶有NF_HOOK宏的語句,如IP的轉發函數中有:
<-ipforward.c ip_forward()->
NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2,
ip_forward_finish);
其中NF_HOOK宏的定義提煉如下:
<-/include/linux/netfilter.h->
#ifdef CONFIG_NETFILTER
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
(list_empty(&nf_hooks[(pf)][(hook)]) \
? (okfn)(skb) \
: nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#endif /*CONFIG_NETFILTER*/
如果在編譯內核時沒有配置netfilter時,就相當於調用最後一個參數,此例中即執行
ip_forward_finish函數;否則進入HOOK點,執行通過nf_register_hook()登記的功能
(這句話表達的可能比較含糊,實際是進入nf_hook_slow()函數,再由它執行登記的
函數)。
NF_HOOK宏的參數分別為:
1.pf:協議族名,netfilter架構同樣可以用於IP層之外,因此這個變量還可以有諸如
PF_INET6,PF_DECnet等名字。
2.hook:HOOK點的名字,對於IP層,就是取上面的五個值;
3.skb:不用多解釋了吧;
4.indev:進來的設備,以struct net_device結構表示;
5.outdev:出去的設備,以struct net_device結構表示;
(後面可以看到,以上五個參數將傳到用nf_register_hook登記的處理函數中。)
6.okfn:是個函數指針,當所有的該HOOK點的所有登記函數調用完後,轉而走此流程。
這些點是已經在內核中定義好的,除非你是這部分內核代碼的維護者,否則無權增加
或修改,而在此檢測點進行的處理,則可由用戶指定。像packet filter,NAT,connection
track這些功能,也是以這種方式提供的。正如netfilter的當初的設計目標--提供一
個完善靈活的框架,為擴展功能提供方便。
如果我們想加入自己的代碼,便要用nf_register_hook函數,其函數原型為:
int nf_register_hook(struct nf_hook_ops *reg)
我們考察一下struct nf_hook_ops結構:
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;
};
我們的工作便是生成一個struct nf_hook_ops結構的實例,並用nf_register_hook將
其HOOK上。其中list項我們總要初始化為{NULL,NULL};由於一般在IP層工作,pf總是
PF_INET;hooknum就是我們選擇的HOOK點;一個HOOK點可能掛多個處理函數,誰先誰後
,便要看優先級,即priority的指定了。netfilter_ipv4.h中用一個枚舉類型指定了內
置的處理函數的優先級:
enum nf_ip_hook_priorities {
NF_IP_PRI_FIRST = INT_MIN,
NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_LAST = INT_MAX,
};
hook是提供的處理函數,也就是我們的主要工作,其原型為:
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 *));
它的五個參數將由NFHOOK宏傳進去。
了解了這些,基本上便可以可以寫一個lkm出來了。
三.例子代碼
這段代碼是一個例子,其功能實現了一個IDS,檢測幾個簡單攻擊(land,winnuke)和特殊
掃描(nmap),當然,不會有人真把它當嚴肅的IDS使用吧:-)。可以利用類似結構干點別
的。。。
<-example.c begin->
/*
* netfilter module example: it`s a kernel IDS(be quie,donot laugh, my friend)
*
[email protected]
* Compile:gcc -O -c -Wall sample.c ,under linux2.4 kernel,netfilter is needed.
*/
#define __KERNEL__
#define MODULE
#include
#include
#include
#include
#include
#include
#include
#include
#define ALERT(fmt,args...) printk("nsfocus: " fmt, ##args)
/*message will be print to screen(too many~),and logged to /var/log/message*/
static unsigned int sample(unsigned int hooknum,struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
struct tcphdr *tcph;
struct udphdr *udph;
__u32 sip;
__u32 dip;
__u16 sport;
__u16 dport;
iph=(*skb)->nh.iph;
sip=iph->saddr;
dip=iph->daddr;
/*play ip packet here
(note:checksum has been checked,if connection track is enabled,defrag have been done )*/
if(iph->ihl!=5){
ALERT("IP packet with packet from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
}
if(iph->protocol==6){
tcph=(struct tcphdr*)((__u32 *)iph+iph->ihl);
sport=tcph->source;
dport=tcph->dest;
/*play tcp packet here*/
if((tcph->syn)&&(sport==dport)&&(sip==dip)){
ALERT("maybe land attack