小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

[原]Netfilter實(shí)現(xiàn)機(jī)制分析...

 jijo 2008-12-29
Netfilter實(shí)現(xiàn)機(jī)制分析【原】
                                             By Minit <tangwen1123@163.com>

                                                                                                          2008-12  


1.        前言
Netfilter作為目前進(jìn)行包過(guò)濾,連接跟蹤,地址轉(zhuǎn)換等的主要實(shí)現(xiàn)框架,了解其內(nèi)部機(jī)制對(duì)于我們更好的利用Netfilter進(jìn)行設(shè)計(jì)至關(guān)重要,因此本文通過(guò)閱讀內(nèi)核源碼2.6.21.2,根據(jù)自身的分析總結(jié)出Netfilter的大致實(shí)現(xiàn)機(jī)制,由于自身水平有限,且相關(guān)的參考資料較少,因此其中的結(jié)論不能保證完全正確,如果在閱讀本文的過(guò)程中發(fā)現(xiàn)了問(wèn)題歡迎及時(shí)與作者聯(lián)系。
2.        規(guī)則的存儲(chǔ)與遍歷機(jī)制
        規(guī)則的存儲(chǔ)機(jī)制
在Netfilter中規(guī)則是順序存儲(chǔ)的,一條規(guī)則主要包括三個(gè)部分:ipt_entry、ipt_entry_matches、ipt_entry_target。ipt_entry_matches由多個(gè)ipt_entry_match組成,ipt_entry結(jié)構(gòu)主要保存標(biāo)準(zhǔn)匹配的內(nèi)容,ipt_entry_match結(jié)構(gòu)主要保存擴(kuò)展匹配的內(nèi)容,ipt_entry_target結(jié)構(gòu)主要保存規(guī)則的動(dòng)作。在ipt_entry中還保存有與遍歷規(guī)則相關(guān)的變量target_offset與next_offset,通過(guò)target_offset可以找到規(guī)則中動(dòng)作部分ipt_entry_target的位置,通過(guò)next_offset可以找到下一條規(guī)則的位置。規(guī)則的存儲(chǔ)如下圖2-1所示。


圖2-1 規(guī)則的存儲(chǔ)

     ipt_entry結(jié)構(gòu)如下圖2-2所示,其成員ip指向結(jié)構(gòu)ipt_ip,該結(jié)構(gòu)主要保存規(guī)則中標(biāo)準(zhǔn)匹配的內(nèi)容(IP、mask、interface、proto等),target_offset的值等于ipt_entry的長(zhǎng)度與ipt_entry_matches的長(zhǎng)度之和,next_offset的值等于規(guī)則中三個(gè)部分的長(zhǎng)度之和。通過(guò)target_offset與next_offset可以實(shí)現(xiàn)規(guī)則的遍歷。

圖2-2 ipt_entry結(jié)構(gòu)

        ipt_entry_match主要保存規(guī)則中擴(kuò)展匹配內(nèi)容(tos、ttl、time等),其是Netfilter中內(nèi)核與用戶態(tài)交互的關(guān)鍵數(shù)據(jù)結(jié)構(gòu),在其內(nèi)核部分由一個(gè)函數(shù)指針指向一個(gè)ipt_match結(jié)構(gòu),該結(jié)構(gòu)體中包含了對(duì)包做匹配的函數(shù),是真正對(duì)包做匹配的地方。ipt_entry_target結(jié)構(gòu)與ipt_entry_match結(jié)構(gòu)很類似。
   
圖2-3 ipt_entry_match結(jié)構(gòu)
              

圖2-4 ipt_entry_target結(jié)構(gòu)
        
       規(guī)則的遍歷機(jī)制
在Netfilter中,函數(shù)ipt_do_table()實(shí)現(xiàn)了規(guī)則的遍歷,該函數(shù)根據(jù)傳入的參數(shù)table和hook找到相應(yīng)的規(guī)則起點(diǎn),即第一個(gè)ipt_entry的位置,主要通過(guò)函數(shù)get_entry()實(shí)現(xiàn)。

private = table->private;
table_base = (void *)private->entries[smp_processor_id()];
e = get_entry(table_base, private->hook_entry[hook]);

        標(biāo)準(zhǔn)匹配是通過(guò)函數(shù)ip_packet_match()實(shí)現(xiàn)的,該函數(shù)主要對(duì)包的五元組信息進(jìn)行匹配,擴(kuò)展匹配則通過(guò)宏IPT_MATCH_ITERATE實(shí)現(xiàn),該宏的定義為:
#define IPT_MATCH_ITERATE(e, fn, args...)    \
({                        \
    unsigned int __i;            \
    int __ret = 0;                \
    struct ipt_entry_match *__match;    \
                        \
    for (__i = sizeof(struct ipt_entry);    \
     __i < (e)->target_offset;        \
     __i += __match->u.match_size) {    \
        __match = (void *)(e) + __i;    \
                        \
        __ret = fn(__match , ## args);    \
        if (__ret != 0)            \
            break;            \
    }                    \
    __ret;                    \
})

        宏IPT_MATCH_ITERATE依次調(diào)用各個(gè)ipt_entry_match所指向的ipt_match中match()處理數(shù)據(jù)包,在for循環(huán)中使用了terget_offset位置變量查找match的位置。
        在對(duì)數(shù)據(jù)包進(jìn)行了匹配后,接著需要進(jìn)行相應(yīng)的動(dòng)作處理,通過(guò)函數(shù)ipt_get_target()獲取規(guī)則動(dòng)作ipt_entry_target的位置:
         
static __inline__ struct ipt_entry_target *
ipt_get_target(struct ipt_entry *e)
{
    return (void *)e + e->target_offset;
}

        如果還需要繼續(xù)遍歷下一條規(guī)則,則繼續(xù)執(zhí)行以下語(yǔ)句以找到下一條規(guī)則的開(kāi)始位置:
         
e = (void *)e + e->next_offset;




3.        表、匹配、動(dòng)作存儲(chǔ)及管理機(jī)制
       表、匹配、動(dòng)作的存儲(chǔ)機(jī)制
規(guī)則中所使用到的match、target、table使用全局變量xt_af所指向的相應(yīng)鏈表保存,這些鏈表是在對(duì)Netfilter進(jìn)行初始化或匹配模塊擴(kuò)展時(shí)進(jìn)行更新的,在初始化時(shí),默認(rèn)的表及動(dòng)作則添加到相應(yīng)的鏈表中。Netfilter實(shí)現(xiàn)了很好的擴(kuò)展性,如需要對(duì)數(shù)據(jù)包的時(shí)間進(jìn)行匹配,則在match的鏈表中需要首先增加time擴(kuò)展匹配模塊,在相應(yīng)的規(guī)則中則通過(guò)指向該time模塊所對(duì)應(yīng)的函數(shù)match()以進(jìn)行時(shí)間的匹配。xt_af是個(gè)一維數(shù)組,其按照協(xié)議族的不同分別存儲(chǔ),目前我們常用的協(xié)議族主要是AF_INET。

圖3-1 match,target,table的全局存儲(chǔ)
        
match、target、table的全局存儲(chǔ)如上圖3-1所示,以下為各部分的詳細(xì)的結(jié)構(gòu)表示。當(dāng)擴(kuò)展一個(gè)匹配模塊時(shí),其會(huì)注冊(cè)一個(gè)ipt_match結(jié)構(gòu)到match鏈表中,該結(jié)構(gòu)的主要變量值如下圖所示,name表示擴(kuò)展模塊的名字,match()是該模塊最主要的函數(shù),其主要對(duì)數(shù)據(jù)包進(jìn)行相應(yīng)的比較,checkentry()主要對(duì)包進(jìn)行相應(yīng)的完整性檢驗(yàn),destroy()在對(duì)模塊進(jìn)行撤銷(xiāo)時(shí)調(diào)用。如果需要自己新加一個(gè)擴(kuò)展模塊,則需要構(gòu)造一個(gè)ipt_match結(jié)構(gòu)并注冊(cè)到相應(yīng)的鏈表中。ipt_target的結(jié)構(gòu)與ipt_match相似,其最主要的函數(shù)是target()。
  

圖3-2 ipt_match結(jié)構(gòu)的存儲(chǔ)
   

圖3-3 ipt_target結(jié)構(gòu)的存儲(chǔ)

table主要是用來(lái)對(duì)規(guī)則進(jìn)行管理,通過(guò)table中的相應(yīng)參數(shù)可以找到相應(yīng)的規(guī)則所處的入口位置。

圖3-4 ipt_table結(jié)構(gòu)的存儲(chǔ)
   
       表、匹配、動(dòng)作的管理機(jī)制
match、target、table的注冊(cè)分別調(diào)用xt_register_match()、xt_register_target()、xt_register_table()實(shí)現(xiàn),前兩個(gè)注冊(cè)函數(shù)很相似,xt_register_table()則稍微復(fù)雜些。撤銷(xiāo)時(shí)則分別調(diào)用相應(yīng)的unregister函數(shù)實(shí)現(xiàn)。xt_register_match()函數(shù)的定義如下(xt_match與ipt_match是一樣的):
         
int
xt_register_match(struct xt_match *match)
{
    int ret, af = match->family;

    ret = mutex_lock_interruptible(&xt[af].mutex);
    if (ret != 0)
        return ret;

    list_add(&match->list, &xt[af].match);
    mutex_unlock(&xt[af].mutex);

    return ret;
}

xt_register_table()函數(shù)的定義如下(xt_table與ipt_table是一樣的),因?yàn)橐粋€(gè)xt_table結(jié)構(gòu)中還指向另一結(jié)構(gòu)xt_table_info,該結(jié)構(gòu)主要描述表的相關(guān)信息,所以對(duì)表注冊(cè)時(shí)需要對(duì)這兩類結(jié)構(gòu)體進(jìn)行定義。
int xt_register_table(struct xt_table *table,
         struct xt_table_info *bootstrap,
         struct xt_table_info *newinfo)
{
    int ret;
    struct xt_table_info *private;
    struct xt_table *t;

    ret = mutex_lock_interruptible(&xt[table->af].mutex);
    if (ret != 0)
        return ret;

    /* Don't autoload: we'd eat our tail... */
    list_for_each_entry(t, &xt[table->af].tables, list) {
        if (strcmp(t->name, table->name) == 0) {
            ret = -EEXIST;
            goto unlock;
        }
    }

    /* Simplifies replace_table code. */
    table->private = bootstrap;
    rwlock_init(&table->lock);
    if (!xt_replace_table(table, 0, newinfo, &ret))
        goto unlock;

    private = table->private;
    duprintf("table->private->number = %u\n", private->number);

    /* save number of initial entries */
    private->initial_entries = private->number;

    list_add(&table->list, &xt[table->af].tables);

    ret = 0;
unlock:
    mutex_unlock(&xt[table->af].mutex);
    return ret;
}


4.        鉤子函數(shù)的存儲(chǔ)及管理機(jī)制
        鉤子函數(shù)的存儲(chǔ)機(jī)制
鉤子函數(shù)由一個(gè)全局二維鏈表nf_hooks保存,其按照協(xié)議族歸類存儲(chǔ),在每個(gè)協(xié)議族中,根據(jù)鉤子點(diǎn)順序排列,在鉤子點(diǎn)內(nèi)則根據(jù)鉤子函數(shù)的優(yōu)先級(jí)依次排列。鉤子函數(shù)的存儲(chǔ)圖如下圖4-1所示,鏈表中的每個(gè)元素都是指向結(jié)構(gòu)體nf_hook_ops中的hook()函數(shù)的指針,nf_hook_ops實(shí)際存儲(chǔ)了鉤子函數(shù)的內(nèi)容,其結(jié)構(gòu)如圖4-2所示。在相應(yīng)的鉤子點(diǎn)調(diào)用鉤子函數(shù)時(shí),則根據(jù)協(xié)議族和鉤子點(diǎn)找到相應(yīng)的鏈表入口,然后依次調(diào)用該鏈中的每一個(gè)鉤子函數(shù)對(duì)數(shù)據(jù)包進(jìn)行操作。


圖4-1 鉤子函數(shù)的全局存儲(chǔ)



圖4-2 鉤子函數(shù)的鏈表
        鉤子函數(shù)的管理機(jī)制
如果需要在相應(yīng)的鉤子點(diǎn)掛載鉤子函數(shù),則需要首先定義一個(gè)nf_hook_ops結(jié)構(gòu),在其中實(shí)現(xiàn)實(shí)際的鉤子函數(shù),再調(diào)用函數(shù)nf_register_hook()將該鉤子函數(shù)注冊(cè)到圖4-1所示的二維鏈表中,nf_register_hook()函數(shù)的定義如下:
int nf_register_hook(struct nf_hook_ops *reg)
{
    struct list_head *i;
    int err;

    err = mutex_lock_interruptible(&nf_hook_mutex);
    if (err < 0)
        return err;
    list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
        if (reg->priority < ((struct nf_hook_ops *)i)->priority)
            break;
    }
    list_add_rcu(&reg->list, i->prev);
    mutex_unlock(&nf_hook_mutex);
    return 0;
}


5.        Netfilter的流程框架
      在Netfilter中的不同鉤子點(diǎn)調(diào)用了不同的鉤子函數(shù),這些鉤子函數(shù)的調(diào)用如圖4-1所示,其調(diào)用的流程框架如下圖5-1所示。




圖5-1 Netfilter中hook函數(shù)的調(diào)用流程

        Netfilter中默認(rèn)表filter在建立時(shí)則在NF_IP_LOCAL_IN,NF_IP_FORWARD鉤子點(diǎn)注冊(cè)了鉤子函數(shù)ipt_hook(),在NF_IP_LOCAL_OUT這個(gè)點(diǎn)注冊(cè)了鉤子函數(shù)ipt_local_out_hook(),兩個(gè)鉤子函數(shù)都會(huì)調(diào)用ipt_do_table()對(duì)相對(duì)應(yīng)的表和鉤子點(diǎn)的規(guī)則進(jìn)行遍歷。調(diào)用的流程如下圖5-2所示。

圖5-2 Netfilter中規(guī)則的調(diào)用流程
6.        總結(jié)
以上只是簡(jiǎn)單分析了Netfilter的整體框架,主要描述了其中的實(shí)現(xiàn)機(jī)制。在這個(gè)機(jī)制上已經(jīng)實(shí)現(xiàn)了很多功能,除了對(duì)基本的功能進(jìn)行完善和改進(jìn)外,還出現(xiàn)了很多新的擴(kuò)展功能。如在此架構(gòu)上實(shí)現(xiàn)的連接跟蹤機(jī)制和NAT機(jī)制,以及結(jié)合連接跟蹤機(jī)制與Netfilter框架實(shí)現(xiàn)的Layer7擴(kuò)展匹配模塊等。對(duì)此框架的了解,有助于我們更好的利用Netfilter框架實(shí)現(xiàn)我們的設(shè)計(jì),鑒于自身水平有限,因此以上的分析不能保證全部正確。希望各位批評(píng)指正。

由于主要是為了描繪出整個(gè)Netfilter的框架,故對(duì)其中較細(xì)節(jié)的的內(nèi)容有所忽略而未深入分析,如規(guī)則的另外一個(gè)動(dòng)作ipt_standard_target,table表注冊(cè)時(shí)的初始化等,但這并不影響對(duì)整個(gè)框架的了解。至于Netfilter在鏈路層的實(shí)現(xiàn)機(jī)制此處也并未分析,因?yàn)槠鋵?shí)現(xiàn)較簡(jiǎn)單,且我們大部分是在網(wǎng)絡(luò)層利用Netfilter架構(gòu)。分析中也未涉及到用戶態(tài)規(guī)則與內(nèi)核態(tài)規(guī)則之間的關(guān)系,對(duì)于iptables如何操作內(nèi)核中的規(guī)則并未介紹,以后有機(jī)會(huì)再做詳細(xì)分析。

[ 本帖最后由 Minit 于 2008-12-29 10:19 編輯 ]


2008-12-29 10:14
  下載次數(shù): 2
Linux-netfilter機(jī)制分析.pdf (264.71 KB)
  Linux-netfilter機(jī)制分析.pdf

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多