曾樹洪惠州學院計算機科學系 廣東 516015
Netfilter是Linux操作系統從2.3.15版本開始推出的一款防火墻。Netfilter防火墻功能強大,除了可以進行包過濾之外,還可以進行Nat轉換等其他功能。并且Netfilter防火墻具有很強的擴展性,通過構造一個簡單的內核模塊就可以實現網絡新特性的擴展。這些特性使得Netfilter很快就成為linux下的一個重要的網絡工具。
從Linux2.4內核開始,Netfilter就實現了連接跟蹤功能,內核可以跟蹤并記錄每個連接的狀態。每一個經過 Netfilter的網絡數據包都對應一條連接記錄,每條連接記錄包括源地址、目的地址、源端口、目的端口、協議類型、連接狀態、連接引用數目和連接時間等信息。利用這些信息可以更加靈活的配置防火墻。連接跟蹤功能還是網絡地址轉換和其他功能模塊實現的基礎,在防火墻配置和擴展方面都有極其重要的作用。
Linux內核在不停的完善和增強中,連接跟蹤的實現在Linux2.6中也有了改進。本文中引用的內核代碼來源于Linux2.6.28版本。
每條連接記錄包括源地址、目的地址、源端口、目的端口、協議類型、連接狀態、連接引用數目和連接時間等信息。所有的連接記錄都放在一個表里,這個表就是連接跟蹤表。Linux內核采用hash表來表示連接跟蹤表。如圖1所示。

圖1 連接跟蹤hash表
連接跟蹤表是一個以hash值排列的雙向鏈表數組,鏈表中的每一個節點都是nf_conntrack_tuple_hash類型的數據結構:
struct nf_conntrack_tuple_hash
{
struct hlist_node hnode;
struct nf_conntrack_tuple tuple;
};
hnode成員用于組織雙向鏈表,tuple成員是網絡數據包進入Netfilter后的一個轉換。tuple包含src(來源)、dst(目的)兩個成員,src包含兩個成員:ip和相應協議端口。

圖2 鏈表節點結構
一個完整的連接包括正反兩個方向,在內核中使用nf_conn類型的數據結構來表示連接:
struct nf_conn
{
struct nf_conntrack ct_general;
……
struct nf_conntrack_tuple_hash tuplehash [IP_CT_DIR_MAX];
unsigned long status;
……
struct timer_list timeout;
……
};
nf_conn包含了許多成員,其中的tuplehash成員實際上是一個包含兩個連接跟蹤鏈表節點的數組:tuplehash[IP_CT_DIR_ORIGINAL]指向初始方向的連接跟蹤鏈表節點,tuplehash[IP_CT_DIR_REPLY]指向應答方向的連接跟蹤鏈表節點。通過tuplehash數組將一條完整的連接在內核里表示出來了。
類型為nf_conntrack的ct_general成員可用于對本連接記錄的公開引用進行計數。
struct nf_conntrack
{
atomic_t use;
};
status成員標記連接的狀態,timeout成員可對連接進行計時,并對超時的連接進行處理。
內核為連接跟蹤在Netfilter的其中4個注冊點注冊了處理函數:ipv4_conntrack_in()、ipv4_confirm()和ipv4_conntrack_local,他們的位置如圖3所示。

圖3 連接跟蹤在Netfilter中的注冊點
函數 ipv4_conntrack_in()的主要功能是判斷當前數據包的轉換 tuple是否已經在連接跟蹤表里。網絡數據包進入Netfilter后被轉換為一個tuple,函數ipv4_conntrack_in()首先在連接跟蹤表里查找該tuple。如果在,說明當前數據包相關聯的連接已經建立好了;如果不在,說明這是一個新連接,內核會為該數據包生成相關的連接記錄并放到臨時表里。此時一條新的連接并未正式建立,因為該連接記錄并沒有被放到連接跟蹤表里,而是被放到一個臨時表里。
函數 ipv4_conntrack_local()進行一些相關操作后將馬上調用 ipv4_conntrack_in(),ipv4_conntrack_local()的主要功能就是調用ipv4_conntrack_in()進行連接跟蹤處理。
函數 ipv4_confirm()的主要功能是再次確認是否為數據包建立連接跟蹤并添加到連接跟蹤表中。在函數ipv4_conntrack_in()中建立的連接記錄到了 ipv4_confirm()里才從臨時表里添加到連接跟蹤表,一條新的連接才正式建立。如果數據包在中間的處理過程中被過濾掉了,數據包將不能到達ipv4_confirm(),也就不會為該數據包建立連接記錄。
由圖3可知新建一條連接記錄有以下三種途徑:
(1)本地接收數據包
數據包流經路線:
NF_INET_PRE_ROUTING ---> ROUTE --->NF_INET_LOCAL_IN
在 NF_INET_PRE_ROUTING處生成新的連接記錄(ipv4_conntrack_in()),在 NF_INET_LOCAL_IN處將該新連接記錄添加到連接跟蹤表(ipv4_confirm())。
(2)轉發數據包
數據包流經路線:
NF_INET_PRE_ROUTING ---> ROUTE --->NF_INET_FORWARD---> NF_INET_POST_ROUTING
在 NF_INET_PRE_ROUTING處生成新的連接記錄(ipv4_conntrack_in()),在NF_INET_POST_ROUTING處將該新連接記錄添加到連接跟蹤表(ipv4_confirm())。
(3)本地發送包
數據包流經路線:
NF_INET_LOCAL_OUT ---> ROUTE --->NF_INET_POST_ROUTING
在 NF_INET_LOCAL_OUT處生成新的連接記錄(ipv4_conntrack_local()),在 NF_INET_POST_ROUTING 處將該新連接記錄添加到連接跟蹤表(ipv4_confirm())。
連接跟蹤表記錄了每個連接的相應ip地址、協議、端口、連接數目以及連接狀態等相關信息。利用這些信息可以配置更加靈活和安全的防火墻。筆者的實驗環境:防火墻服務器采用雙網卡,一個連接外網(校園網),一個連接內網(實驗室)。防火墻服務器的操作系統為Fedora8,內核版本為2.26.28,Iptables版本為1.4.4。外網接口eth0的IP地址為:172.17.21.31,子網掩碼為:255.255.255.0,網關為:172.17.21.254,內網接口eth1的IP地址為:192.168.1.254。
使用connlimit模塊可以限制連接數,起到負載均衡的作用。這樣可以將工作負擔相對平均的分散到多部主機上,使每部主機獲得大致相等的工作量。
(1)限制局域網內每個用戶的連接數
如果需要限制局域網內每個用戶的連接數為 100,只需在服務器上添加如下規則:
iptables –A FORWARD -m connlimit --connlimit-above 100 -j DROP
這樣局域網內每個用戶的連接數當超過100時數據封包將被丟棄。
也可以寫成這樣的規則:
iptables –A FORWARD -m connlimit !--connlimit-above 100 -j ACCEPT
這樣局域網內的每個用戶的連接數在100以內的數據封包將被轉發,也就是連接數超過100的數據封包將被丟棄。以下的規則同理。
也可以針對某種傳輸協議限制每個用戶的連接數,如限制每用戶的tcp連接數在100以內,只需將規則修改如下:
iptables -A FORWARD -p tcp -m connlimit--connlimit-above 100 -j DROP
將規則里“-p tcp”的tcp修改成upd或icmp就可以限制每用戶的upd或icmp協議的連接數。
(2)限制局域網內單個用戶的連接數
如限制局域網內192.168.1.1用戶的連接數為100,在服務器上添加如下規則:
iptables -I FORWARD -s 192.168.1.1 -m connlimit--connlimit-above 100 -j DROP
如果要限制局域網內 192.168.1.1以外的用戶的連接數為100,規則只需修改如下:
iptables -I FORWARD !-s 192.168.1.1 -m connlimit--connlimit-above 100 -j DROP
(3)限制本機的連接數
數據封包進入局域網內或者從局域網內發出到外網,都要經過轉發鏈(FORWARD)。進入本機的數據封包或者從本機發出的數據封包不經過轉發鏈(FORWARD),但所有進入本機的數據封包都要經過輸入鏈(INPUT),從本機發出的數據封包都要經過輸出鏈(OUTPUT),限制本機的連接數需將規則里的FORWARD改成INPUT或OUTPUT:
iptables -I INPUT -m connlimit --connlimit-above 100 -j DROP
或者
iptables -I OUTPUT -m connlimit --connlimit-above 100 -j DROP
(4)基于某種協議限制連接數
connlimit功能模塊還可以只限制某種協議的連接數,只需在前面規則的基礎上加上“-p”選項,比如限制局域網內每個用戶的tcp連接數為100,規則如下:
iptables –A FORWARD -p tcp -m connlimit--connlimit-above 100 -j DROP
將tcp修改成udp或者icmp就可以限制相應協議的連接數,比如限制局域網內192.168.1.1用戶的udp連接數為100,規則修改如下:
iptables -I FORWARD -p udp -s 192.168.1.1 -m connlimit--connlimit-above 100 -j DROP
(5)限制某個端口連接數
connlimit模塊具有限制端口連接數的功能,如果要限制局域網內每個用戶的80端口連接數為10,規則如下:
iptables -I FORWARD -p tcp --dport 80 -m connlimit--connlimit-above 10 -j DROP
使用state模塊可以根據連接的狀態來進行防火墻配置,這里的連接狀態是指在用戶空間里能使用的4種狀態,如表1所示。

表1 數據包在用戶空間的狀態
如要禁止外網發起連接,可以添加規則:
iptables -A FORWARD -i eth0 -m state state NEW -j DROP
這樣一條連接只能是由局域網內用戶發起建立(這里服務器連接外網的網卡是eth0,連接內網的網卡是eth1)。外網進入NEW狀態的數據包都將丟棄。如果是針對主機而不是局域網設置,規則修改如下:
iptables -A INPUT -m state state NEW -j DROP
如要禁止局域網內用戶回應外網的ICMP封包,添加規則:
iptables -A FORWARD -p icmp -o eth 0 -m state --state ESTABLISHED -j DROP
Linux下的 Netfilter防火墻功能強大、擴展性強。本文分析了2.6.28內核下網絡數據包連接跟蹤的工作原理。利用Netfilter的連接跟蹤功能使實驗室或其他局域網內的用戶機負載更加均衡,更加方便和靈活的配置防火墻。
[1]博嘉科技.Linux 防火墻技術探秘[M].北京:國防工業出版社.2002.
[2]顧棟梁,周健,程克勤.基于Netfilter 的連接限制的研究與實現[J].計算機工程.2009.
[3] www.kernel.org.
[4]郭錫泉.應用層協議分析在狀態檢測防火墻中的應用[J].計算機工程.2007.