iptables的maual的BUG一節:
BUGS
OK,我去netfilter的bug站點...唉,這幫人啊!
我相信很多人都遇到過iptables規則無法删除的問題,比如我使用了xtables-addons中的condition這個match子產品,當我成功設定了一個規則後:
iptables -t mangle -A PREROUTING -m condition --condition xtt -j ACCEPT
然後嘗試用上述規則的D指令删除之:
iptables -t mangle -D PREROUTING -m condition --condition xtt -j ACCEPT
我得到了一個報錯:
iptables: Bad rule (does a matching rule exist in that chain?).
然而如果我用rulenum的方式則可以成功删除!即先查找上述規則的rulenum,然後删除該num标示的規則就可以成功,但是這樣就多了一個步驟,我将不能僅僅通過簡單的A或者D控制一條規則的增加和删除,于是,我必須找出來到底是哪裡出了問題。
iptables規則儲存在哪裡呢?答案是儲存在核心裡面,并且一條規則處在一個連續的位址空間,布局大緻如下:
中繼資料|match1|match2|...|target
注意,使用者态是不儲存規則的,每當你要删除一條規則的時候,你必須提供足夠的你要删除的規則的詳細資訊,然後和核心中的規則群做比對,隻有在精确比對成功,即沒有任何二義性的比對成功後,該規則直接從核心中删除,具體的通信機制(Netlink,ioctl等)不重要,重要的是,iptables有多種删除規則的方式。
核心會為每一條儲存進核心的iptables規則進行編号索引,該索引在特定的HOOK點/TABLE上是唯一的,是以使用rulenum進行删除不會有任何二義性。
精确比對删除比較複雜,你必須給出規則的每一個細節,正如你當初添加該規則時一樣,和添加動作唯一不同的是,你要把-A改成-D。這種精确比對删除的成功依賴的就是使用者提供的所有match字段,target字段必須和核心中儲存的一模一樣,精确到位元組級别的比對。如果哪怕有一個位元組不比對,就會有二義性,删除失敗。
當你調用iptables -t $table -F的時候,該表下面的所有規則就不複存在了,由于規則隸屬于表,是以不會有二義性。整鍊删除含義類似,主要是由于,不管表也好,鍊也罷,都是具體規則的上級組織,正所謂皮之不存,毛将焉附!
問題之所在
以我實際碰到的問題為例,xt_condition的info結構體如下:
注意那個注釋!condvar字段隻用在核心。如果你用過condition子產品,你會知道,它除了一個名稱參數之外,不會攜帶任何參數,也就是說僅僅iptables的指令不會對condvar進行任何設定,預設可能是NULL,然而整個結構體,當然也包括condvar,在添加規則的時候,全都會被注入核心并被核心儲存起來,condvar的指派是在核心中進行的,它表示一個核心結構體的位址。
如果說現在使用精确比對法則删除一條使用condition的規則,會怎樣?核心中的該規則中的xt_condition_mtinfo結構體的condvar字段已經被指派為一個核心态位址空間的位址,它會被用來和使用者态的相同結構體進行位元組級的比對,第一個字段name顯然是精确比對的,第二個字段也沒有問題,condition_parse會處理得很好,然而第三個condvar字段就不比對了,使用者給出的規則中該字段為0,而核心态中該字段是一個位址!是以就會導緻删除失敗!
這個小節其實是無關緊要的,netfilter的hacker們早就修正了問題,但是那隻是在程式設計層面上,而我需要在業務層面上去闡述問題,因為iptables的每一個match和每一個target,除了内置少數幾個之外,都是子產品的形式提供,并且出現無法删除問題的不僅僅是condition子產品一個,有很多子產品都有這個問題,是以我個人認為,這并不算iptables的bug,而隻是各個子產品的bug。
我在xt_condition.c核心檔案偵測了規則到達核心後其xt_condition_mtinfo中condvar的值,我這裡的結果是:0XFFFF88000A2D0BC0。那麼在删除過程中,按照上述結構體的定義,肯定是在第33位元組出現了不比對,調試下來證明了這一點,核心結構體的第33位元組是0xC0,而iptables根據使用者敲入指令算出來的對應位元組是0x0。好吧,我在condition_parse解析回調函數中為其寫死:
這樣在make install之後,就可以成功删除了!
出了什麼問題我們已經看出來了,隻需要告訴iptables,不要比對結構體的condvar字段就可以了,怎麼做呢?iptables給出了接口,即xtables_match結構體的userspacesize字段,原始的condition子產品給出的定義是:
顯然這是不對的,而實際上它應該是:
有一種更好的辦法,即:
這樣iptables就會忽略掉condvar字段的比對。
但是,這就意味着你不能随意布局match/target子產品結構體中的字段,你必須将“核心專用”的字段全部放在結構體的最後面,然後用offsetof來取第一個這類字段的偏移,将其指派給userspacesize,這無疑給程式設計人員帶來了負擔,我覺得這倒可以算是一個bug。如果開發人員不懂這個規矩,調試都是很難的。更加智能一點的方式是,在建構結構體的時候,讓程式員指名字段的用途,或者幹脆分成使用者态,核心态兩個結構體,使用者填充後,iptables架構負責将其合并整合。
和其它bug不同的是,這個bug是大量存在的,并且不能一次性解決。如果你在http://bugzilla.netfilter.org上搜尋相關的bug,會出現大量結果,涉及多個子產品,一個子產品修正了并不意味着另一個子產品會被修正,雖然說兩個子產品的作者都犯了同樣一個錯誤。比如,就針對condition子產品而言,我在xtables-addons-1.46中第一次遇到它,發現了它的bug,後來下載下傳了xtables-addons-2.2版本,該bug依然健在!
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1348489