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

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 13291 | 回復(fù): 4
打印 上一主題 下一主題

Netfilter CONNMARK用法及分析(二)-- 內(nèi)核代碼分析 [復(fù)制鏈接]

論壇徽章:
36
IT運維版塊每日發(fā)帖之星
日期:2016-04-10 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-04-16 06:20:0015-16賽季CBA聯(lián)賽之廣東
日期:2016-04-16 19:59:32IT運維版塊每日發(fā)帖之星
日期:2016-04-18 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-04-19 06:20:00每日論壇發(fā)貼之星
日期:2016-04-19 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-04-25 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-06 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-08 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-13 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-28 06:20:00每日論壇發(fā)貼之星
日期:2016-05-28 06:20:00
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-11-02 10:29 |只看該作者 |倒序瀏覽
本文著重分析內(nèi)核中CONNMARK的實現(xiàn),同時還包括MARK的match和target模塊的實現(xiàn)。因為CONNMARK模塊通常是和MARK模塊搭配使用的。關(guān)于iptables中如何使用這三個模塊,參看本人的另外一篇文章《Netfilter CONNMARK用法及分析(一)-- iptables命令行的使用》。

本文歡迎自由轉(zhuǎn)載,但請標(biāo)明出處和本文鏈接,并保持本文的完整性。
CU: Godbach
    Blog:http://blog.chinaunix.net/u/33048/index.html
Oct 31, 2009


1. CONNMARK及相關(guān)模塊的選項
這里先列出CONNMARK、MARK和mark模塊的iptables命令行的選項,隨后我們再逐一分析各個模塊的內(nèi)核實現(xiàn)。iptables版本為v1.3.5。

(1)CONNMARK target的選項
選項        功能
--set-mark value[/mask]        給鏈接跟蹤記錄打標(biāo)記。
--save-mark [--mask mask]        將數(shù)據(jù)包上的標(biāo)記值記錄到鏈接跟蹤記錄上。
--restore-mark [--mask mask]        重新設(shè)置數(shù)據(jù)包的nfmark值。

(2)MARK target 的選項
選項        功能
--set-mark value        設(shè)置數(shù)據(jù)包的nfmark值。
--and-mark value        數(shù)據(jù)包的nfmark值和value進行按位與運算。
--or-mark  value        數(shù)據(jù)包的nfmark值和value進行按或與運算。

(3)MARK match的選項
選項        功能
[!] --mark value[/mask]        數(shù)據(jù)包的nfmark值與value進行匹配,其中mask的值為可選的。

其中CONNMARK和MARK match中都有mask選項,這個主要用來指定給出value值中哪幾位是需要設(shè)置的。通常,如果我們不指定mask的話,其值會被默認初始為0xFFFFFFFFUL。

2. MARK target的內(nèi)核實現(xiàn)
我這里分析的內(nèi)核源碼版本是2.6.18,該模塊的代碼見文件xt_MARK.c,其核心的target實現(xiàn)代碼如下:
  1. 41 static unsigned int
  2. 42 target_v1(struct sk_buff **pskb,
  3. 43       const struct net_device *in,
  4. 44       const struct net_device *out,
  5. 45       unsigned int hooknum,
  6. 46       const struct xt_target *target,
  7. 47       const void *targinfo,
  8. 48       void *userinfo)
  9. 49 {
  10. 50     const struct xt_mark_target_info_v1 *markinfo = targinfo;
  11. 51     int mark = 0;
  12. 52
  13. 53     switch (markinfo->mode) {
  14. 54     case XT_MARK_SET:
  15. 55         mark = markinfo->mark;
  16. 56         break;
  17. 57
  18. 58     case XT_MARK_AND:
  19. 59         mark = (*pskb)->nfmark & markinfo->mark;
  20. 60         break;
  21. 61
  22. 62     case XT_MARK_OR:
  23. 63         mark = (*pskb)->nfmark | markinfo->mark;
  24. 64         break;
  25. 65     }
  26. 66          /*將用戶設(shè)置的mark值賦給數(shù)據(jù)包的nfmark*/
  27. 67     if((*pskb)->nfmark != mark)
  28. 68         (*pskb)->nfmark = mark;
  29. 69
  30. 70     return XT_CONTINUE;
復(fù)制代碼
MARK target三個選項中最常用的應(yīng)該是--set-mark,給數(shù)據(jù)包的nfmark設(shè)置標(biāo)記。諸如下面這條規(guī)則
iptables -A POSTROUTING -p tcp --dport 21 -t mangle -j MARK --set-mark 1

就是將符合前面匹配選項的數(shù)據(jù)包的nfmark值設(shè)置為1。在內(nèi)核中對應(yīng)的源碼為:
  1. 54     case XT_MARK_SET:
  2. 55         mark = markinfo->mark;
  3. 56         break;
  4.         選項--and-mark對應(yīng)的源碼為:
  5. 58     case XT_MARK_AND:
  6. 59         mark = (*pskb)->nfmark & markinfo->mark;
  7. 60         break;
復(fù)制代碼
功能就是將數(shù)據(jù)包中記錄的nfmark值和用戶設(shè)置的value進行按位與。同理選項--or-mark就是將數(shù)據(jù)包中記錄的nfmark值和用戶設(shè)置的value進行按位或,其源碼如下:
  1. 62     case XT_MARK_OR:
  2. 63         mark = (*pskb)->nfmark | markinfo->mark;
  3. 64         break;
復(fù)制代碼
該模塊最后統(tǒng)一判斷一下設(shè)置后的mark值是否與數(shù)據(jù)包中保存的nfmark值相等,如果不等,則更新數(shù)據(jù)包的nfmark值為剛剛設(shè)置的mark。其代碼如下:
  1. 67     if((*pskb)->nfmark != mark)
  2. 68         (*pskb)->nfmark = mark;
復(fù)制代碼
個人覺得不管數(shù)據(jù)包nfmark和mark是否相等,直接將mark賦給nfmark就可以了。這里加一條if判斷,難道是為了當(dāng)兩個值相等的時候,少執(zhí)行一次寫內(nèi)存的指令?

3. MARK match的內(nèi)核實現(xiàn)
該模塊的實現(xiàn)在內(nèi)核源碼的xt_mark.c中。其核心匹配模塊的實現(xiàn)代碼如下:
  1. 22 static int
  2. 23 match(const struct sk_buff *skb,
  3. 24       const struct net_device *in,
  4. 25       const struct net_device *out,
  5. 26       const struct xt_match *match,
  6. 27       const void *matchinfo,
  7. 28       int offset,
  8. 29       unsigned int protoff,
  9. 30       int *hotdrop)
  10. 31 {
  11. 32     const struct xt_mark_info *info = matchinfo;
  12. 33
  13. 34     return ((skb->nfmark & info->mask) == info->mark) ^ info->invert;
  14. 35 }
復(fù)制代碼
該模塊實現(xiàn)的功能相對簡單,就是判斷一下數(shù)據(jù)包的nfmark值是否與用戶指定的相同。判斷的時候要考慮mask以及取反的標(biāo)記位。
        下面這條iptables規(guī)則就是實現(xiàn)了對所有標(biāo)記不為0的數(shù)據(jù)包都執(zhí)行ACCEPT動作:
iptables -A POSTROUTING -t mangle -m mark ! --mark 0 -j ACCEPT

假設(shè)skb->nfmark為1,由于沒有指定mask,所以默認值為0xFFFFFFFFUL,info->mark為0,取反標(biāo)記位被置位,info->invert為1。因此,((skb->nfmark & info->mask) == info->mark) ^ info->invert的結(jié)果應(yīng)該是(1&0xFFFFFFFFUL)== 0)^1 = 0^1 = 1。
該模塊match函數(shù)的返回值為1,執(zhí)行ACCEPT動作。

4. CONNMARK target的內(nèi)核實現(xiàn)
該模塊的實現(xiàn)在內(nèi)核源碼的xt_CONNMARK.c中。其核心動作模塊的實現(xiàn)代碼如下:
  1. 35 static unsigned int
  2. 36 target(struct sk_buff **pskb,
  3. 37        const struct net_device *in,
  4. 38        const struct net_device *out,
  5. 39        unsigned int hooknum,
  6. 40        const struct xt_target *target,
  7. 41        const void *targinfo,
  8. 42        void *userinfo)
  9. 43 {
  10. 44     const struct xt_connmark_target_info *markinfo = targinfo;
  11. 45     u_int32_t diff;
  12. 46     u_int32_t nfmark;
  13. 47     u_int32_t newmark;
  14. 48     u_int32_t ctinfo;
  15. 49     u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
  16. 50
  17. 51     if (ctmark) {
  18. 52         switch(markinfo->mode) {
  19. 53         case XT_CONNMARK_SET:
  20. 54         newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
  21. 55         if (newmark != *ctmark)
  22. 56             *ctmark = newmark;
  23. 57         break;
  24. 58         case XT_CONNMARK_SAVE:
  25. 59         newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
  26. 60         if (*ctmark != newmark)
  27. 61             *ctmark = newmark;
  28. 62         break;
  29. 63         case XT_CONNMARK_RESTORE:
  30. 64         nfmark = (*pskb)->nfmark;
  31. 65         diff = (*ctmark ^ nfmark) & markinfo->mask;
  32. 66         if (diff != 0)
  33. 67             (*pskb)->nfmark = nfmark ^ diff;
  34. 68         break;
  35. 69         }
  36. 70     }
  37. 71
  38. 72     return XT_CONTINUE;
  39. 73 }
復(fù)制代碼
這段代碼最開始先取出了數(shù)據(jù)包對應(yīng)的鏈接跟蹤中記錄mark值的地址:
  1. 49     u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
復(fù)制代碼
然后判斷ctmark是否為NULL:
  1. 51     if (ctmark) {
復(fù)制代碼
如果ctmark == NULL,說明鏈接跟蹤中沒有ct->mark這個字段,惟一可能的原因就是內(nèi)核的配置文件中并沒有對CONFIG_NF_CONNTRACK_MARK進行配置,也就是沒有啟用Conntrack Mark的功能。否則,就根據(jù)用戶配置的動作進行相應(yīng)的實現(xiàn)。
以下將分成三個部分介紹。

(1)給鏈接跟蹤設(shè)置標(biāo)記(--set-mark)
        實現(xiàn)代碼如下:
  1. 53         case XT_CONNMARK_SET:
  2. 54         newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
  3. 55         if (newmark != *ctmark)
  4. 56             *ctmark = newmark;
  5. 57         break;
復(fù)制代碼
這里先按照markinfo->mask中所有被置位的bit,將*ctmark中對應(yīng)的bit位清零,然后再與markinfo->mark進行按位或。這樣就保證了mask中置位的bit位,一定為按照mark中的值重新設(shè)置。
        55~57行代碼的實現(xiàn)和我們第2部分分析的67~68代碼的實現(xiàn)相同。

(2)保存標(biāo)記值到鏈接跟蹤(--save-mark)
        實現(xiàn)代碼如下:
  1. 58         case XT_CONNMARK_SAVE:
  2. 59         newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
  3. 60         if (*ctmark != newmark)
  4. 61             *ctmark = newmark;
  5. 62         break;
復(fù)制代碼
這部分代碼中mask的功能和上面分析的相同。為了簡單化分析起見,我們假設(shè)用戶沒有指定mask,默認值為0xFFFFFFFFUL。這樣,59行的計算簡化為:
        newmark = (*pskb)->nfmark
再加上后兩行代碼:
  1. 60         if (*ctmark != newmark)
  2. 61             *ctmark = newmark;
復(fù)制代碼
具體的功能就很明確了,將當(dāng)前數(shù)據(jù)包記錄的nfmark值記錄到鏈接跟蹤中的ct->mark中。
        那么,按理說如果數(shù)據(jù)包的流程走到這部分代碼,應(yīng)該就是數(shù)據(jù)包已經(jīng)被打上標(biāo)記了,也就是前面分析的MARK target中--set-mark進行的處理。因此,在下在iptables規(guī)則的時候,通常--set-mark的規(guī)則在前,--save-mark的規(guī)則在后。這就保證了數(shù)據(jù)包先被打上標(biāo)記,然后再將數(shù)據(jù)包上的標(biāo)記記錄到其對應(yīng)的鏈接跟蹤上。以下幾條示例規(guī)則就是按照這個流程進行的:
iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 21 -t mangle -j MARK --set-mark 1
iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 80 -t mangle -j MARK --set-mark 2
iptables -A POSTROUTING -m mark --mark 0 -t mangle -p tcp -j MARK --set-mark 3
iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark


(3)重新設(shè)置數(shù)據(jù)包的標(biāo)記值(--restore-mark)
實現(xiàn)代碼如下:
  1. 63         case XT_CONNMARK_RESTORE:
  2. 64         nfmark = (*pskb)->nfmark;
  3. 65         diff = (*ctmark ^ nfmark) & markinfo->mask;
  4. 66         if (diff != 0)
  5. 67             (*pskb)->nfmark = nfmark ^ diff;
  6. 68         break;
復(fù)制代碼
這里我們同樣默認用戶沒有設(shè)置mask,其初始值為0xFFFFFFFFUL。因此,64行代碼可簡化為:
  1.         diff = *ctmark ^ nfmark
復(fù)制代碼
結(jié)合代碼
  1. 66         if (diff != 0)
  2. 67             (*pskb)->nfmark = nfmark ^ diff;
復(fù)制代碼
我們可以看出這個功能就是將鏈接記錄上的*ctmark保存到了(*pskb)->nfmark上。
        簡單的說來,如果一個鏈接跟蹤記錄被打上了標(biāo)記,那么通過該段代碼,就確保了所有屬于該鏈接的數(shù)據(jù)包也都被打上了該標(biāo)記。這樣,系統(tǒng)中后面的模塊就可以根據(jù)數(shù)據(jù)報上的標(biāo)記進一步的處理,譬如TC可以根據(jù)該標(biāo)記繼續(xù)帶寬管理。

5.總結(jié)

        那么--restore-mark規(guī)則應(yīng)該怎么與--set-mark和--save-mark進行配合,完成給鏈接打標(biāo)記,進而為連接上的所有數(shù)據(jù)包打標(biāo)記呢?請看下面幾條規(guī)則:
  1. iptables -A POSTROUTING -t mangle -j CONNMARK --restore-mark
  2. iptables -A POSTROUTING -t mangle -m mark ! --mark 0 -j ACCEPT
  3. iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 21 -t mangle -j MARK --set-mark 1
  4. iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 80 -t mangle -j MARK --set-mark 2
  5. iptables -A POSTROUTING -m mark --mark 0 -t mangle -p tcp -j MARK --set-mark 3
  6. iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark
復(fù)制代碼
解釋如下:
1)第1條規(guī)則就是完成了將鏈接跟蹤上的標(biāo)記記錄到該連接上的每一個數(shù)據(jù)包中;
2)第2條規(guī)則判斷數(shù)據(jù)包的標(biāo)記,如果不為0,則直接ACCEPT。如果數(shù)據(jù)包上沒有被打標(biāo)記,則交由后面的規(guī)則進行匹配并打標(biāo)記。這里為什么會出現(xiàn)經(jīng)過了CONNMARK模塊,數(shù)據(jù)包仍未被打標(biāo)記呢?可以想到,如果一條鏈接的第1個數(shù)據(jù)包經(jīng)過第1條規(guī)則處理之后,由于ct->mark為0,所以其數(shù)據(jù)包的標(biāo)記skb->nfmark應(yīng)該仍舊為0,就需要進行后面規(guī)則的匹配。
3)第3~5條規(guī)則,則按照匹配選項對符合規(guī)則的數(shù)據(jù)包打上不同的標(biāo)記。
4)第6條規(guī)則就是將數(shù)據(jù)包上的標(biāo)記記錄到鏈接跟蹤上。這樣,當(dāng)屬于該鏈接的下一個數(shù)據(jù)包走到第1條規(guī)則的時候,就會被打上標(biāo)記,然后就會命中第2條規(guī)則,執(zhí)行動作ACCEPT。
        至此,內(nèi)核模塊CONNMARK、MARK的match和target實現(xiàn)都已分析完畢。如有分析不妥或遺漏指出,請大家多多指正。

[ 本帖最后由 godbach 于 2009-11-2 10:38 編輯 ]

評分

參與人數(shù) 2可用積分 +60 收起 理由
scutan + 30 精品文章
dreamice + 30 精品文章

查看全部評分

論壇徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辭舊歲徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
2 [報告]
發(fā)表于 2009-11-02 12:12 |只看該作者
好東西,分析得很好!

論壇徽章:
36
IT運維版塊每日發(fā)帖之星
日期:2016-04-10 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-04-16 06:20:0015-16賽季CBA聯(lián)賽之廣東
日期:2016-04-16 19:59:32IT運維版塊每日發(fā)帖之星
日期:2016-04-18 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-04-19 06:20:00每日論壇發(fā)貼之星
日期:2016-04-19 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-04-25 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-06 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-08 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-13 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-05-28 06:20:00每日論壇發(fā)貼之星
日期:2016-05-28 06:20:00
3 [報告]
發(fā)表于 2009-11-02 13:13 |只看該作者
原帖由 dreamice 于 2009-11-2 12:12 發(fā)表
好東西,分析得很好!


dreamice兄過獎了。前兩天正好分析一個問題,就跟蹤到CONNMARK里了,順便分析了一下。

論壇徽章:
0
4 [報告]
發(fā)表于 2011-07-20 18:08 |只看該作者
本文著重分析內(nèi)核中CONNMARK的實現(xiàn),同時還包括MARK的match和target模塊的實現(xiàn)。因為CONNMARK模塊通常是和M ...
godbach 發(fā)表于 2009-11-02 10:29



    超級好~對我很有幫助,謝謝版主~

論壇徽章:
0
5 [報告]
發(fā)表于 2011-07-21 11:21 |只看該作者
(1)給鏈接跟蹤設(shè)置標(biāo)記(--set-mark)
        實現(xiàn)代碼如下: 53         case XT_CONNMARK_SET:

54         newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
55         if (newmark != *ctmark)

56             *ctmark = newmark;

57         break;
復(fù)制代碼這里先按照markinfo->mask中所有被置位的bit,將*ctmark中對應(yīng)的bit位清零,然后再與markinfo->mark進行按位或。這樣就保證了mask中置位的bit位,一定為按照mark中的值重新設(shè)置。
        55~57行代碼的實現(xiàn)和我們第2部分分析的67~68代碼的實現(xiàn)相同。

在iptables/extensions/libxt_CONNMARK.c 核心代碼
/* Function which parses command options; returns true if it
   ate an option */
static int
parse(int c, char **argv, int invert, unsigned int *flags,
      const struct ipt_entry *entry,
      struct ipt_entry_target **target)
{
        struct ipt_connmark_target_info *markinfo
                = (struct ipt_connmark_target_info *)(*target)->data;

        markinfo->mask = 0xffffffffUL;

        switch (c) {
                char *end;
        case '1':
                markinfo->mode = IPT_CONNMARK_SET;

                markinfo->mark = strtoul(optarg, &end, 0);
                if (*end == '/' && end[1] != '\0')
                    markinfo->mask = strtoul(end+1, &end, 0);

                if (*end != '\0' || end == optarg)
                        exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
                if (*flags)
                        exit_error(PARAMETER_PROBLEM,
                                   "CONNMARK target: Can't specify --set-mark twice");
                *flags = 1;
                break;
        case '2':
                markinfo->mode = IPT_CONNMARK_SAVE;
                if (*flags)
                        exit_error(PARAMETER_PROBLEM,
                                   "CONNMARK target: Can't specify --save-mark twice");
                *flags = 1;
                break;
        case '3':
                markinfo->mode = IPT_CONNMARK_RESTORE;
                if (*flags)
                        exit_error(PARAMETER_PROBLEM,
                                   "CONNMARK target: Can't specify --restore-mark twice");
                *flags = 1;
                break;
        case '4':
                if (!*flags)
                        exit_error(PARAMETER_PROBLEM,
                                   "CONNMARK target: Can't specify --mask without a operation");
                markinfo->mask = strtoul(optarg, &end, 0);

                if (*end != '\0' || end == optarg)
                        exit_error(PARAMETER_PROBLEM, "Bad MASK value `%s'", optarg);
                break;
        default:
                return 0;
        }

        return 1;
}

版主,問一下,markinfo->mark = strtoul(optarg, &end, 0);
                if (*end == '/' && end[1] != '\0')
                    markinfo->mask = strtoul(end+1, &end, 0);
optarg是--set-mark后面的參數(shù)? --set-mark 111時, optarg=111
其中:static struct option opts[] = {
        { "set-mark", 1, 0, '1' },
        { "save-mark", 0, 0, '2' },
        { "restore-mark", 0, 0, '3' },
        { "mask", 1, 0, '4' },
        { 0 }
}; 怎么理解下命令時,markinfo->mask的值,和其作用???
您需要登錄后才可以回帖 登錄 | 注冊

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

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP