是不是要重新設計Netfilter的HOOK點位置了?無疑這是一個沒有意義的問題,因為你無法證明新的方案更好,你可能只是看上了另一個平台的方案而已,而這個方案和Netfilter的方案是不同的。事實上,我就是這樣一個人。
Cisco的ACL可以被編譯在連接埠上,事實上Cisco裝置的網路連接埠角色是可以被定義的,Linux的理念和此完全不同,Linux核心認為定義角色這種事是使用者態的職責,如何要實現一個具有完備性的,不依賴使用者態配置的資料包攔截機制,那就必須在協議棧路徑上進行攔截。換句話說,Netfilter是完全基於skb本身來攔截並處理資料包的,這一點可以從NF_HOOK宏的參數看得出來,但是你可以看到,它還有兩個net_device參數,基於這一點,我們就可以模仿Cisco裝置的方式將規則綁定到裝置了,這麼做是有好處的,可以大大提高效率。比如如果你配置了10000條規則,如果有不相關網口裝置進來的資料包,那麼這些資料包就不必經過iptables規則的過濾。
需要修改的地方比較少,這裡只給出ipt_hook的修改:
static unsigned intipt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ struct netns_table_per_dev { struct list_head list; struct net_device *dev; struct xt_table *table; }; // dev_net(in)->ipv4.iptable_filter不再是一個xt_table,而是一個list struct wrap_table { struct list_head *tb_list; }; struct xt_table *table; struct netns_table_per_dev *table_dev; struct list_head *pos; struct wrap_table *tb_list = (struct wrap_table *)dev_net(in)->ipv4.iptable_filter; list_for_each(pos, tb_list->tb_list) { table_dev = list_entry(pos, struct netns_table_per_dev, dev); if (table_dev->dev == in) { table = table_dev->table; } } if (table == NULL) { return NF_ACCEPT; } return ipt_do_table(skb, hook, in, out, table);}
一個在協議棧攔截,一個在裝置攔截,該手術做的有點大,顛覆了既有的理念,不知道會不會有後遺症。
不管怎樣,不能走火入魔。