iptables的手冊也不能盡信啊

來源:互聯網
上載者:User
我很自豪的找到了一種截獲資料包的秘籍,那就是使用conntrack的ctdir,第一步當然是看iptables的man手冊,發現:
--ctdir {ORIGINAL|REPLY}
    Match packets that are flowing in the specified direction. If this flag is not specified at all, matches  packets
    in both directions.
於是我寫下來以下以下的規則:
iptables -t mangle -A PREROUTING -d x.x.x.x/a -i eth2 -m conntrack --ctdir ORIGINAL -j MARK --set-xmark 100iptables -t mangle -A PREROUTING -s y.y.y.y/b -i eth2 -m conntrack --ctdir REPLY -j MARK --set-xmark 100

我這麼寫有什麼問題嗎?絕對沒有!懂iptables的人都知道我要做什麼,我要做的就是截獲兩類流,一個是主動訪問x.x.x.x/a的流,另一類是y.y.y.y/b被訪問的流。OK,一切看起來很好。然而當我將上述規則實際部署的時候,出問題了,截取竟然是相反的流,也就是說,截取了兩類流,一類是x.x.x.x/a被訪問的流,另一類是主動訪問y.y.y.y/b的流...我該怎麼辦?很長一段時間,我一直認為我錯了,google過,百度過,毫無結果。作為一個成熟的用了這麼久的iptables,不會犯錯,一定是我錯了。因此我的下一個計劃就是找到:我哪裡錯了?
        這隻是一個安慰罷了,其實我知道我沒有錯,按照英文字面理解,REPLY就是代表返回的意思。我的實際計劃應該是,找到一個證據證明自己沒有錯。這個證據我在互連網找了好久,因此我決定看一下代碼。首先我看的是conntrack的通用match函數,核心版本為2.6.32。通過match函數在/net/netfilter/xt_conntrack.c中:

static boolconntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par,             u16 state_mask, u16 status_mask){    const struct xt_conntrack_mtinfo2 *info = par->matchinfo;    enum ip_conntrack_info ctinfo;    const struct nf_conn *ct;    unsigned int statebit;    ct = nf_ct_get(skb, &ctinfo);    /* 這些都不是當前所關注的,當前只關注ctdir */    ...        if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&        (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^        !!(info->invert_flags & XT_CONNTRACK_DIRECTION))        return false;    /* 這些都不是當前所關注的,當前只關注ctdir */    ...    return true;}

為了思路更清晰,將協助函數/宏也列舉出來:

enum ip_conntrack_dir{    IP_CT_DIR_ORIGINAL,    IP_CT_DIR_REPLY,    IP_CT_DIR_MAX};enum ip_conntrack_info{    /* Part of an established connection (either direction). */    IP_CT_ESTABLISHED,    /* Like NEW, but related to an existing connection, or ICMP error       (in either direction). */    IP_CT_RELATED,    /* Started a new connection to track (only           IP_CT_DIR_ORIGINAL); may be a retransmission. */    IP_CT_NEW,    /* >= this indicates reply direction */    IP_CT_IS_REPLY,    /* Number of distinct IP_CT types (no NEW in reply dirn). */    IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1};#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)static inline struct nf_conn *nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo){    *ctinfo = skb->nfctinfo;    return (struct nf_conn *)skb->nfct;}

然後我們看一下skb->nfctinfo到底在哪裡初始化的,實際上不用找也知道是nf_conntrack_in裡面的resolve_normal_ct中:

if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {    *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;    /* Please set reply bit if this packet OK */    *set_reply = 1;} else {  //只要不是返回方向的,都是正向包。    /* Once we've had two way comms, always ESTABLISHED. */    if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {        *ctinfo = IP_CT_ESTABLISHED;    } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {        *ctinfo = IP_CT_RELATED;    } else {        *ctinfo = IP_CT_NEW;    }    *set_reply = 0;}skb->nfct = &ct->ct_general;skb->nfctinfo = *ctinfo;

可見,正方向的資料包的nfctinfo被初始化成了IP_CT_ESTABLISHED,IP_CT_RELATED或者IP_CT_NEW,而這些都比IP_CT_IS_REPLY要小,因此正方向的資料包的CTINFO2DIR肯定是IP_CT_DIR_ORIGINAL(詳見CTINFO2DIR宏定義)。另一個證據在init_conntrack函數,它是一個初始化ct的函數,這種情況下ct肯定被認為是正方向的,該函數在最後返回的是&ct->tuplehash[IP_CT_DIR_ORIGINAL],一個IP_CT_DIR_ORIGINAL方向的ct-part。
        現在看看conntrack_mt函數,對於正方向的包,(CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)為1,如果iptables的ctdir設定為ORIGINAL的話,(info->invert_flags & XT_CONNTRACK_DIRECTION))為0(詳見ip_conntrack_dir枚舉),因此二者異或為1,最終返回false,這不是瞪著眼睛說瞎話嗎?對於返回包,也就是反方向的包,反而返回true...起碼從代碼看來,ip_conntrack將ctdir完全搞反了。因此如果想讓你的配置按照你的想法生效,那就要反過來配置:
iptables -t mangle -A PREROUTING -d x.x.x.x/a -i eth2 -m conntrack --ctdir REPLY -j MARK --set-xmark 100
iptables -t mangle -A PREROUTING -s y.y.y.y/b -i eth2 -m conntrack --ctdir ORIGINAL -j MARK --set-xmark 100

很奇怪,然而正確!要想修正這個問題,除了配置很奇怪的規則之外,只需要去掉一個“!”號即可:

(CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^!!(info->invert_flags & XT_CONNTRACK_DIRECTION))

改為:

(CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^!(info->invert_flags & XT_CONNTRACK_DIRECTION))

從“!!(info->invert_flags & XT_CONNTRACK_DIRECTION)”這一行代碼來看,筆誤的可能性比較大,否則實在想不通為何要用雙重否定句。

       令人氣憤的是,如此一個問題怎麼竟然很少有人提出來啊,難道真的是能用就行嗎?或者說真的是我錯了?唉,反正不管怎麼說,我配反了就能用,配正了就錯誤!搞了一下午,真TM fuXX the conntrack,怎麼就沒人管呢?這麼成熟的iptables竟然都不可信,茫茫塵世,我還能信誰?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.