亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
打印 上一主題 下一主題

[原創(chuàng)]Netfilter源碼分析-我來拋磚,望能引玉 [復(fù)制鏈接]

論壇徽章:
0
41 [報(bào)告]
發(fā)表于 2005-12-23 16:01 |只看該作者
千萬不能修改代碼去掉 ip_conntrack 功能
我雖然看不懂,但是我知道那個(gè)功能是必不可少的,因?yàn)?netfilter 是基于狀態(tài)檢測(cè)的,如果那個(gè)功能去掉了基本就沒什么可用的了
新的內(nèi)核如果打了 patch 之后會(huì),載入 ip_conntrack 后會(huì)有 sysctl -a|grep estab 顯示中那樣的提示
你可以修改這個(gè)數(shù)(默認(rèn)是保持一天),也可以增大 ip_conntrack_max 值,最好兩者一起改

論壇徽章:
0
42 [報(bào)告]
發(fā)表于 2005-12-23 16:15 |只看該作者
原帖由 platinum 于 2005-12-23 16:01 發(fā)表
千萬不能修改代碼去掉 ip_conntrack 功能
我雖然看不懂,但是我知道那個(gè)功能是必不可少的,因?yàn)?netfilter 是基于狀態(tài)檢測(cè)的,如果那個(gè)功能去掉了基本就沒什么可用的了
新的內(nèi)核如果打了 patch 之后會(huì),載入 ip ...


謝謝,被這個(gè)問題困擾好久了,我試試!

論壇徽章:
0
43 [報(bào)告]
發(fā)表于 2005-12-23 16:26 |只看該作者
代碼方面還要多請(qǐng)九賤兄指點(diǎn)呢 ^_^

論壇徽章:
0
44 [報(bào)告]
發(fā)表于 2005-12-26 09:26 |只看該作者
/*kendo 2006-4-2修正原來對(duì)target部份描述不完全的情況*/

filter表的內(nèi)容,還剩下三個(gè)內(nèi)容:
1、target的匹配;
2、每個(gè)模塊的target/match等函數(shù)的實(shí)現(xiàn);
3、內(nèi)核與用戶空間的交互;

這里,以target的匹配做為2005的的結(jié)尾吧(因?yàn)槊魈祜w貴州,估計(jì)2005年是沒有機(jī)會(huì)再發(fā)貼了)

注:這里說匹配,其實(shí)不太正確,因?yàn)榍懊鎚atch是條件,匹配條件是正常的,target是動(dòng)作,應(yīng)該用執(zhí)行更準(zhǔn)確些。

target的匹配
要理解target的匹配,還是需要先了解相關(guān)的數(shù)據(jù)結(jié)構(gòu)。
與match相似,內(nèi)核中每個(gè)target模塊,通過一個(gè)struct ipt_target來實(shí)現(xiàn):
/* Registration hooks for targets. */
struct ipt_target
{
        struct list_head list;                                /*target鏈,初始為NULL*/

        const char name[IPT_FUNCTION_MAXNAMELEN];        /*target名稱*/

        /*target的模塊函數(shù),如果需要繼續(xù)處理則返回IPT_CONTINUE(-1),否則返回NF_ACCEPT、NF_DROP等值,
        它的調(diào)用者根據(jù)它的返回值來判斷如何處理它處理過的報(bào)文*/
        unsigned int (*target)(struct sk_buff **pskb,       
                               unsigned int hooknum,
                               const struct net_device *in,
                               const struct net_device *out,
                               const void *targinfo,
                               void *userdata);

        /* Called when user tries to insert an entry of this type:
           hook_mask is a bitmask of hooks from which it can be
           called. */
        /* 在使用本Match的規(guī)則注入表中之前調(diào)用,進(jìn)行有效性檢查,如果返回0,規(guī)則就不會(huì)加入iptables中 */
        int (*checkentry)(const char *tablename,
                          const struct ipt_entry *e,
                          void *targinfo,
                          unsigned int targinfosize,
                          unsigned int hook_mask);

        /* 在包含本Target的規(guī)則從表中刪除時(shí)調(diào)用,與checkentry配合可用于動(dòng)態(tài)內(nèi)存分配和釋放 */
        void (*destroy)(void *targinfo, unsigned int targinfosize);

        /* 表示當(dāng)前Target是否為模塊(NULL為否) */
        struct module *me;
};
這個(gè)結(jié)構(gòu)樣子與match的內(nèi)核模塊的描述幾乎是一模一樣了……

而內(nèi)核及用戶態(tài)中,具體地存儲(chǔ)描述一個(gè)target,是通過一個(gè)struct ipt_entry_target來實(shí)現(xiàn)的:
struct ipt_entry_target
{
        union {
                struct {
                        u_int16_t target_size;

                        /* Used by userspace */
                        char name[IPT_FUNCTION_MAXNAMELEN];
                } user;
                struct {
                        u_int16_t target_size;

                        /* Used inside the kernel */
                        struct ipt_target *target;
                } kernel;

                /* Total length */
                u_int16_t target_size;
        } u;

        unsigned char data[0];
};
這個(gè)結(jié)構(gòu)也與match一模一樣,那么我們是不是就可以按照分析match的思路來分析match呢?“通過成員struct ipt_target *target;來與內(nèi)核中注冊(cè)的target的處理模塊建立關(guān)連,再來調(diào)用u.kernel.target->target()函數(shù)進(jìn)行匹配”???
先不急,Netfilter的target共分為三類:內(nèi)建動(dòng)作、擴(kuò)展target和用戶自定義鏈。而以上兩個(gè)結(jié)構(gòu)是不夠的,它們只能描述基于擴(kuò)展target的匹配函數(shù),沒有或可以講至少?zèng)]有顯著地描述一個(gè)內(nèi)建動(dòng)作或者是用戶自定義鏈!事實(shí)上,Netfilter描述一個(gè)完整的target,是通過以下結(jié)構(gòu)來實(shí)現(xiàn)的:

struct ipt_standard_target
{
        struct ipt_entry_target target;                /*模塊函數(shù)*/       
        int verdict;                                /*常數(shù)*/
};

其中成員verdict(判斷、判決)表明用來針對(duì)內(nèi)建動(dòng)作(ACCEPT、DROP)或者是用戶自定義鏈,如果是擴(kuò)展的target,則通過其target成員去定位最終的模塊處理函數(shù)。

那么,問題又接踵而至了,如果內(nèi)核中,模塊也是以類似注冊(cè)/維護(hù)雙向鏈表的形式儲(chǔ)備,那么在內(nèi)核中匹配的時(shí)候如何來區(qū)分這三類target?

事實(shí)上,考慮到程序的通用性、擴(kuò)展性,對(duì)于內(nèi)建動(dòng)作或者是用戶自定義鏈,內(nèi)核是采用了“假注冊(cè)”的方式來處理(這個(gè)名字是偶私人取的,或許不正確),也就是說,把內(nèi)建動(dòng)作或者是用戶自定義鏈和擴(kuò)展的target采用一樣的處冊(cè)方式,只是這個(gè)注冊(cè),只是一個(gè)樣子,不具備實(shí)質(zhì)意義:
在標(biāo)準(zhǔn)模塊初始化Ip_tables.c的init函數(shù)注冊(cè)target 的時(shí)候,可以看到:
static int __init init(void)
{
        int ret;

        /* Noone else will be downing sem now, so we won't sleep */
        down(&ipt_mutex);
        list_append(&ipt_target, &ipt_standard_target);
        ……
其注冊(cè)的成員ipt_standard_target表示“標(biāo)準(zhǔn)的target”,即前文所提到的內(nèi)建動(dòng)作和用戶自定義鏈。我們來看看它的初始化值:
/* The built-in targets: standard (NULL) and error. */
static struct ipt_target ipt_standard_target
= { { NULL, NULL }, IPT_STANDARD_TARGET, NULL, NULL, NULL };

同樣,它也是一個(gè)ipt_target結(jié)構(gòu),也就是說和其它擴(kuò)展的target模塊一樣,但是,它的處理函數(shù)全為空的,如target函數(shù)指針。所以,匹配的時(shí)候,如果要匹分的話,可以判斷此指針函數(shù)是否指向NULL即可。而至于在標(biāo)準(zhǔn)的target中區(qū)分內(nèi)建動(dòng)作還是用戶自定議鏈,前面提到過,它們都是以struct ipt_standard_target結(jié)構(gòu)的verdict成員描述。到時(shí)候來判斷verdict的值就可以了。我們可以推斷出這段匹配的算法應(yīng)該大致如下:
do {
        ……        /*前面為匹配match部份,前幾節(jié)已分析過了*/
        假設(shè)e為當(dāng)前待匹配規(guī)則。
        t=get_current_target(e);        /*獲取當(dāng)前規(guī)則的當(dāng)前target*/
       
        /*因?yàn)槿绻?cè)時(shí),如果是標(biāo)準(zhǔn)target,則t->u.kernel.target->target==NULL*/
        if (!t->u.kernel.target->target)                /*如果是標(biāo)準(zhǔn)target*/
        {
                /*進(jìn)入標(biāo)準(zhǔn)target的話,還要來區(qū)分究竟是內(nèi)建的動(dòng)作,還是用戶自定鏈,前面分析
                struct ipt_standard_target時(shí)說過,它們都是以verdict成員來描述的,則*/
                if(判斷verdict==內(nèi)建動(dòng)作)
                {
                        /*相應(yīng)處理*/
                }
                else
                {
                        /*相應(yīng)處理*/
                }
        }
        else
        {
                /*如果是擴(kuò)展的target,調(diào)用target函數(shù)*/
                verdict = t->u.kernel.target->target();
        }
}while(……);

就是在規(guī)則的循環(huán)匹配中,先根據(jù)target函數(shù)指針的值判斷target,如果是標(biāo)準(zhǔn)的target,再根據(jù)的值匹別是內(nèi)建動(dòng)作還是自定義鏈。
程序?qū)嶋H的代碼與此已經(jīng)很相似了,唯一的區(qū)別在于程序在處理自定義鏈時(shí)有一些技巧。
回到struct ipt_standard_target的verdict成員上來,這是一個(gè)非常重要的東西。用戶空間表示一個(gè)接受動(dòng)作,使用ACCEPT,內(nèi)核不用能這個(gè)字符串來匹配,!strcmp(target.name,"ACCEPT"),這樣效率差了點(diǎn),一個(gè)自然的想法是,用一些整形數(shù)來代替,就像我們平常用1來代替true,0來代替false一樣。
鏈中還有一種規(guī)則的target,形如-j 自定義鏈名,內(nèi)核中的規(guī)則,并沒有直接的“鏈”的概念,是呈一維線性排例的,所以,需要跳轉(zhuǎn)至自定義鏈時(shí),就需要兩個(gè)東東:
1、待跳轉(zhuǎn)的鏈相對(duì)于這條-j 自定義鏈的偏移值;
2、回指針,跳完了,總要回來吧……并且,規(guī)則中-j RETURN這種規(guī)則,它同樣也需要回指針;
對(duì)于一條默認(rèn)鏈來講:
back = get_entry(table_base, table->private->underflow[hook]);
最初回指針是指向這條鏈的末尾處的。

OK,再回到偏移值的問題上來,內(nèi)核仍然以verdict這個(gè)成員來描述這個(gè)偏移值,剛才說過用verdict來描述ACCEPT等這些內(nèi)建動(dòng)作,難道它們不會(huì)沖突,答案是否定的。內(nèi)核約定:以負(fù)數(shù)來描述ACCEPT等內(nèi)建動(dòng)作,需要用到時(shí),再取其正值就行了。
例如:
#define NF_ACCEPT 1                     /*內(nèi)核中定義NF_ACCEPT這種動(dòng)作,對(duì)應(yīng)常數(shù)為1*/
當(dāng)用戶在iptables中輸入是"ACCEPT"字符串時(shí),將其轉(zhuǎn)換成:
verdict=-NF_ACCEPT - 1
到了內(nèi)核中,要用到NETFILTER的動(dòng)作時(shí),只需要反過來:
(unsigned)(-verdict) - 1;
就OK了。

也就是說,用:
v=target.verdict;
if(v<0)            /*內(nèi)核默認(rèn)動(dòng)作*/
{
    if (v != IPT_RETURN)
   {
            return verdict = (unsigned)(-v) - 1;     /*是默認(rèn)動(dòng)作,且不為RETURN,直接返回*/
    }
    //以下代碼處理RETURN的情況
   ……
}
else                   /*自定義鏈*/
{
}
就可以處理內(nèi)建動(dòng)作與自定義鏈或RETURN幾種情況了。讓我們來看內(nèi)核中實(shí)際的這塊的代碼處理:

/*獲取當(dāng)前規(guī)則的target*/
t = ipt_get_target(e);
/*如果不存在target模塊函數(shù),那么target應(yīng)為常數(shù),如ACCEPT,DROP等,或是自定義鏈*/
if (!t->u.kernel.target->target)
{
        int v;

        v = ((struct ipt_standard_target *)t)->verdict;        /*取得target的verdict值*/
        /*
#define NF_DROP 0
#define NF_ACCEPT 1
#define NF_STOLEN 2
#define NF_QUEUE 3
#define NF_REPEAT 4
#define NF_MAX_VERDICT NF_REPEAT

#define IPT_CONTINUE 0xFFFFFFFF

#define IPT_RETURN (-NF_MAX_VERDICT - 1)
        */
       
        if (v < 0)                /*動(dòng)作是默認(rèn)內(nèi)建的動(dòng)作*/
        {
                /* Pop from stack? */
                if (v != IPT_RETURN)                /*如果不是Return,返回相應(yīng)的動(dòng)作*/
                {
                        verdict = (unsigned)(-v) - 1;
                        break;
                }
                /*back用來描述return 動(dòng)作,或者是自定義鏈執(zhí)行完了,若還需繼續(xù)匹配,那它指向那條應(yīng)繼續(xù)匹配的規(guī)則,所以,這里用e=back來取得下一條待匹配的規(guī)則*/
                e = back;
                               /*重新設(shè)置back點(diǎn)*/
                back = get_entry(table_base, back->comefrom);
                continue;
        }
        /*v>=0的情況,v表示了一個(gè)偏移值——待跳轉(zhuǎn)的自定義鏈相對(duì)于規(guī)則起始地址的偏移,即如果是自定義鏈,那么應(yīng)該跳到哪條規(guī)則去繼續(xù)執(zhí)行匹配,這里這個(gè)判斷的意思是,如果下一條跳轉(zhuǎn)換規(guī)則剛好就是當(dāng)前規(guī)則的下一條規(guī)則,那就不用跳了……,否則,將當(dāng)前規(guī)則(形如-j 自定義鏈名這樣的規(guī)則)的下一條規(guī)則設(shè)置為back點(diǎn)*/
        if (table_base + v!= (void *)e + e->next_offset)        /*當(dāng)前鏈后還有規(guī)則*/
        {
                /* Save old back ptr in next entry */
                struct ipt_entry *next = (void *)e + e->next_offset;
                next->comefrom = (void *)back - table_base;
                /* set back pointer to next entry */
                back = next;
        }
        /*確定等匹配的下一條規(guī)則*/
        e = get_entry(table_base, v);
}
else                        /*如果存在target模塊函數(shù)*/
{
        /* 如果需要繼續(xù)處理則返回IPT_CONTINUE(-1),否則返回NF_ACCEPT、NF_DROP等值 */
        verdict = t->u.kernel.target->target(pskb,
                                hook,
                                in, out,
                                t->data,
                                userdata);

        /* Target might have changed stuff. */
        /*Target函數(shù)有可能已經(jīng)改變了stuff,所以這里重新定位指針*/
        ip = (*pskb)->nh.iph;
        protohdr = (u_int32_t *)ip + ip->ihl;
        datalen = (*pskb)->len - ip->ihl * 4;
       
        /*如果返回的動(dòng)作是繼續(xù)檢查下一條規(guī)則,則設(shè)置當(dāng)前規(guī)則為下一條規(guī)則,繼續(xù)循環(huán),否則,
        就跳出循環(huán),因?yàn)樵趇pt_do_table函數(shù)末尾有return verdict;表明,則將target函數(shù)決定的返回值返回給
        調(diào)用函數(shù)nf_iterate,由它來根據(jù)verdict決定數(shù)據(jù)包的命運(yùn)*/
        if (verdict == IPT_CONTINUE)
                e = (void *)e + e->next_offset;
        else
                /* Verdict */
                break;
}

[ 本帖最后由 獨(dú)孤九賤 于 2006-4-4 13:51 編輯 ]
rstevens 該用戶已被刪除
45 [報(bào)告]
發(fā)表于 2005-12-31 12:28 |只看該作者
提示: 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽

論壇徽章:
0
46 [報(bào)告]
發(fā)表于 2006-01-08 18:16 |只看該作者
呵呵,內(nèi)核的代碼才精彩呢。

我只能看懂大概,一到加鎖的細(xì)節(jié)就暈了!

論壇徽章:
0
47 [報(bào)告]
發(fā)表于 2006-01-08 18:39 |只看該作者
我認(rèn)為,一個(gè)數(shù)據(jù)報(bào)在netfilter處理的過程中,一直是在softirq中進(jìn)行的,因此,不可能被其他softirq打斷,

如果在一個(gè)netfilter的動(dòng)作,也即target中,直接調(diào)用dev_queue_xmit()來發(fā)送自己構(gòu)造的數(shù)據(jù)報(bào),會(huì)出現(xiàn)內(nèi)存泄漏嗎?

論壇徽章:
0
48 [報(bào)告]
發(fā)表于 2006-01-09 11:25 |只看該作者
原帖由 guotie 于 2006-1-8 18:39 發(fā)表
我認(rèn)為,一個(gè)數(shù)據(jù)報(bào)在netfilter處理的過程中,一直是在softirq中進(jìn)行的,因此,不可能被其他softirq打斷,

如果在一個(gè)netfilter的動(dòng)作,也即target中,直接調(diào)用dev_queue_xmit()來發(fā)送自己構(gòu)造的數(shù)據(jù)報(bào),會(huì)出現(xiàn) ...


Why?不太同意你的說法
netfilter和softirq有關(guān)系嗎???最多是受影響而已吧?
softirq更多的是和網(wǎng)卡收發(fā)數(shù)據(jù)有關(guān)系,而這個(gè)處理,從2.4.20有了較大的改變……使用了一個(gè)類似poll的動(dòng)作……

論壇徽章:
0
49 [報(bào)告]
發(fā)表于 2006-02-22 10:13 |只看該作者
我有一處不明白。還望各位多指點(diǎn):
規(guī)則的組織方式是struct ipt_ip + struct ipt_entry_match + struct ipt_entry_match + ... + struct ipt_entry_target;

而規(guī)則在初始化的時(shí)候(建立的時(shí)候),需要分配它的內(nèi)存,而match和target都要儲(chǔ)存在這個(gè)分配給規(guī)則的內(nèi)存空間中,也就是儲(chǔ)存在unsigned char elems[0];的elems地址開始之處,那么給規(guī)則分配內(nèi)存的時(shí)候豈不是要分配(sizeof(struct ipt_ip + struct ipt_entry_match + struct ipt_entry_match + ... + struct ipt_entry_target))這么大么??
這樣的話每一條規(guī)則不是只能儲(chǔ)存一定數(shù)目的match嗎?太大會(huì)超過規(guī)則的空間,內(nèi)存溢出??
如果match很少,不是浪費(fèi)資源嗎??

如果我有理解不對(duì)的地方,各位多多包涵,耐心指正,本人十分感激。

論壇徽章:
0
50 [報(bào)告]
發(fā)表于 2006-02-22 12:24 |只看該作者
原帖由 wwwspirit 于 2006-2-22 10:13 發(fā)表
我有一處不明白。還望各位多指點(diǎn):
規(guī)則的組織方式是struct ipt_ip + struct ipt_entry_match + struct ipt_entry_match + ... + struct ipt_entry_target;

而規(guī)則在初始化的時(shí)候(建立的時(shí)候),需要分 ...


想法是對(duì)了的……只是想得太過簡(jiǎn)單了……

我們以規(guī)則的添加為例來描述規(guī)則的構(gòu)造,
看先iptables的源碼的do_command()函數(shù):
其中,分析一些標(biāo)準(zhǔn)的規(guī)則參數(shù),如地址等等,存儲(chǔ)于struct ipt_entry fw這個(gè)結(jié)構(gòu)中,這個(gè)略去不表,重點(diǎn)在match和target.

每添加一個(gè)mathc,都對(duì)應(yīng)一個(gè)-m,我們來看選項(xiàng)分析的case 'm':
                case 'm': {
……
                        m->m = fw_calloc(1, size);
……
                }
這樣,就為每個(gè)match動(dòng)態(tài)分析了一段地址!!target類似,略去不表。然后是調(diào)用每個(gè)match的parse函數(shù)分析,填充相應(yīng)的值。

好,最后來看規(guī)則的整合了:
e = generate_entry(&fw, iptables_matches, target->t);

有是你所說的規(guī)則,fw是標(biāo)準(zhǔn)規(guī)則部份,每二個(gè)是match的全局結(jié)構(gòu)變量,過會(huì)會(huì)遍歷它,后一個(gè)是target:
只需看這個(gè)函數(shù)的前面開頭部份就可以回答你的問題了:

static struct ipt_entry *
generate_entry(const struct ipt_entry *fw,
               struct iptables_match *matches,
               struct ipt_entry_target *target)
{
        unsigned int size;
        struct iptables_match *m;
        struct ipt_entry *e;

        size = sizeof(struct ipt_entry);
        for (m = matches; m; m = m->next) {
                if (!m->used)
                        continue;

                size += m->m->u.match_size;
        }

        e = fw_malloc(size + target->u.target_size);
……
其中size用來計(jì)算規(guī)是空間,其實(shí)就是分別計(jì)算三個(gè)部份的長(zhǎng)度,然后一起分配,所以即不會(huì)浪費(fèi),也不會(huì)有溢出等等……

而到了內(nèi)核中,只需把用戶空間的內(nèi)容直接拷貝到對(duì)應(yīng)地址空間即可。!
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP