最早的內核包過濾機制是ipfwadm,後來是ipchains,再後來就是iptables/netfilter了。再往後,也就是現在是nftables。不過nftables與iptables還處於爭雄階段,誰能勝出目前還沒有定論。但是他們都屬於netfilter項目的子成員。
netfilter基於鉤子,在內核網絡協議棧的幾個固定的位置由netfilter的鉤子。我們知道數據包有兩種流向,一種是給本機的:驅動接收——》路由表——》本機協議棧——》驅動發送。一種是要轉發給別人的:驅動接收——》路由表——》轉發——》驅動發送。針對這幾個關鍵位置,netfilter定義了幾個鉤子:NF_IP_PRE_ROUTING是在查路由表之前,NF_IP_LOCAL_IN實在查完路由表決定發送本機之後,NF_IP_FORWARD實在查完路由表決定轉發的時候,NF_IP_POST_ROUTING是要交給驅動發送之前,NF_IP_LOCAL_OUT是本機產生的數據交給驅動發送之前。通過在這幾個鉤子位置注冊函數,截斷數據包的流動,可以完成數據包的過濾和轉換功能。要知道的是,轉發功能一般只在路由器上打開,一般的PC如果發現不是自己的數據包就會直接選擇丟棄。所以,普通PC可以使用的鉤子有NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN、NF_IP_LOCAL_OUT、NF_IP_POST_ROUTING四個。可以看到都是在IP層的鉤子,然而,這些鉤子可不僅只可以處理IP層的數據,因為在IP層可以拿到完整的數據包,所以你想處理哪一層都是可以的。
iptables不是注冊在鉤子函數上,但是位置是一致的。是netfilter框架下的一個附屬的功能,由table、chain、rule組成。
netfilter提供了幾個重要的功能,方便無論是iptables還是nftables使用。caching功能可以有一個緩存,通過查詢數據包的某個位置可以決定該數據包根本不會經過後面的過濾規則。
chain和rule是iptables自創的概念,我們知道在鉤子函數的地方可以執行指定的函數調用。iptables系統就默認實現了幾個調用,並且用統一的數據結構來組織這個調用的形式。這個組織結構就是table、chain和rule。
在任何一個hook點,都可以定義多個table,一個table有多個chain,每個chain中可以定義多個rule。要記住的是table和chain只是容器,裡面的rule才是真正發揮作用的規則。理論上我們可以在任何一個hook點做過濾、nat、修改數據包等所有操作,但是iptables為了統一架構起見,在各個hook點定義了順序的幾個table,每個table用來完成一類的工作。預定義的table包括:filter、nat和mangle。這每一個table表示的是功能,並不是表示位置,一個table內部有多個chain,其中每個chain位於特定的位置。
下圖是一個內部已經定義的table、chain關系圖表:
https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg
FILTER: PREROUTING, FORWARD, POSTROUTING
NAT: PREROUTING, INPUT, OUTPUT, POSTROUTING
MANGLE: PREROUTING, INPUT, FORWARD, OUTPUT,POSTROUTING
可以看到,預定義的3個表表示3種不同的功能,每個表都在一些hook點定義了一組chain。如此,當一個用戶想要在某一個hook點做某一件事情,就可以定位到table(功能)——》chain(位置)——rule(行為)來完成數據包操作。
每一條rule的格式都是相同的,包括源IP地址、目的IP地址、上層協議、接口、操作(target)。但是並不是每個域對於每個chain都是可用的,例如在INPUT的地方匹配輸出接口就是永遠匹配不到的。所以有效的rule在不同的chain上是不同的。
iptables是個可擴展的軟件,其對TCP、UDP等常用協議的支持都是通過擴展,iptables本體只支持到ip層,你只要使用對應的選項就會自動的使用擴展。還有一些不是協議的擴展,這些擴展一般通過iptables –m 調用,例如iptables –m mac可以用來匹配mac地址。-m limit可以用來限制每秒鐘匹配的數目,超過的就放行。這些擴展包括:
l xt_mac.ko:匹配mac地址
l xt_limit.ko:限制每秒鐘匹配的數目,超過的就放行
l xt_owner.ko:用來匹配某個某個進程或用戶創建的數據包
l xt_state.ko:用來匹配處於某個連接狀態的數據包(例如NEW、ESTABLLISHED、RELATED)
l xt_pkttype.ko:用來根據多播、廣播還是單播來匹配包
l xt_quota.ko:可以為一個rule設置quota,當quota達到後,改rule失效
l xt_recent.ko:允許你設置一個IP列表,後續的IP列表的用戶都不生效
l xt_string.ko:允許你匹配數據包中的一個字符串
l xt_time.ko:允許你根據數據包的到達和離去時間進行匹配
l xt_u32.ko:通過匹配檢查數據包的某4位是否與要求的一致來進行操作
還有很多target的擴展和conntrack的擴展、ipv6的擴展。可以根據應用的類型進行匹配,可以修改ttl、TOS等數據位。基本能用得上的功能都有對應的擴展。
操作(target)也是可以擴展的,常見的默認的操作有ACCEPT和DROP,擴展的還有LOG、REJECT等,用戶還可以自己實現。還有兩種默認是QUEUE和RETURN,RETURN實現了各個規則之間的函數式調用,QUEUE則實現了數據包的排隊。這些操作也都對應著具體的模塊:nft_queue.ko、nft_reject.ko、xt_LOG.ko、nft_log.ko等。
用戶空間不止可以添加規則,還可以添加代碼。這是通過xt_bpf模塊實現的。iptables –m bpf –bytecode 後面跟具體的code就好了,從匯編編譯成code的程序再linux內核的tool/net下有。
不但是用戶空間可以給iptables添加規則,內核模塊添加規則的能力更強大。由於其具備編碼能力,所以不只是可以丟棄一個數據包,還可以返回NF_STOLEN,這樣這個數據包對於協議棧來說將會停止向上發送,而這個模塊將會處理這個數據包的後續流程。
應該注意的是,netfilter這個名字指的是內核過濾數據包這個架構,而iptables則是table、chain、rule這套設計。內核裡面一般直接使用netfilter的鉤子,而不使用iptables的規則。