我很自豪的找到了一種截獲資料包的秘籍,那就是使用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的人都知道我要做什麼,我要做的就是截獲兩類流,一個是主動通路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中:
為了思路更清晰,将幫助函數/宏也列舉出來:
然後我們看一下skb->nfctinfo到底在哪裡初始化的,實際上不用找也知道是nf_conntrack_in裡面的resolve_normal_ct中:
可見,正方向的資料包的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
很奇怪,然而正确!要想修正這個問題,除了配置很奇怪的規則之外,隻需要去掉一個“!”号即可:
改為:
從“!!(info->invert_flags & XT_CONNTRACK_DIRECTION)”這一行代碼來看,筆誤的可能性比較大,否則實在想不通為何要用雙重否定句。
令人氣憤的是,如此一個問題怎麼竟然很少有人提出來啊,難道真的是能用就行嗎?或者說真的是我錯了?唉,反正不管怎麼說,我配反了就能用,配正了就錯誤!搞了一下午,真TM fuXX the conntrack,怎麼就沒人管呢?這麼成熟的iptables竟然都不可信,茫茫塵世,我還能信誰?
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1268998