曾樹洪惠州學(xué)院計算機科學(xué)系 廣東 516015
Netfilter是Linux操作系統(tǒng)從2.3.15版本開始推出的一款防火墻。Netfilter防火墻功能強大,除了可以進(jìn)行包過濾之外,還可以進(jìn)行Nat轉(zhuǎn)換等其他功能。并且Netfilter防火墻具有很強的擴(kuò)展性,通過構(gòu)造一個簡單的內(nèi)核模塊就可以實現(xiàn)網(wǎng)絡(luò)新特性的擴(kuò)展。這些特性使得Netfilter很快就成為linux下的一個重要的網(wǎng)絡(luò)工具。
從Linux2.4內(nèi)核開始,Netfilter就實現(xiàn)了連接跟蹤功能,內(nèi)核可以跟蹤并記錄每個連接的狀態(tài)。每一個經(jīng)過 Netfilter的網(wǎng)絡(luò)數(shù)據(jù)包都對應(yīng)一條連接記錄,每條連接記錄包括源地址、目的地址、源端口、目的端口、協(xié)議類型、連接狀態(tài)、連接引用數(shù)目和連接時間等信息。利用這些信息可以更加靈活的配置防火墻。連接跟蹤功能還是網(wǎng)絡(luò)地址轉(zhuǎn)換和其他功能模塊實現(xiàn)的基礎(chǔ),在防火墻配置和擴(kuò)展方面都有極其重要的作用。
Linux內(nèi)核在不停的完善和增強中,連接跟蹤的實現(xiàn)在Linux2.6中也有了改進(jìn)。本文中引用的內(nèi)核代碼來源于Linux2.6.28版本。
每條連接記錄包括源地址、目的地址、源端口、目的端口、協(xié)議類型、連接狀態(tài)、連接引用數(shù)目和連接時間等信息。所有的連接記錄都放在一個表里,這個表就是連接跟蹤表。Linux內(nèi)核采用hash表來表示連接跟蹤表。如圖1所示。
圖1 連接跟蹤hash表
連接跟蹤表是一個以hash值排列的雙向鏈表數(shù)組,鏈表中的每一個節(jié)點都是nf_conntrack_tuple_hash類型的數(shù)據(jù)結(jié)構(gòu):
struct nf_conntrack_tuple_hash
{
struct hlist_node hnode;
struct nf_conntrack_tuple tuple;
};
hnode成員用于組織雙向鏈表,tuple成員是網(wǎng)絡(luò)數(shù)據(jù)包進(jìn)入Netfilter后的一個轉(zhuǎn)換。tuple包含src(來源)、dst(目的)兩個成員,src包含兩個成員:ip和相應(yīng)協(xié)議端口。
圖2 鏈表節(jié)點結(jié)構(gòu)
一個完整的連接包括正反兩個方向,在內(nèi)核中使用nf_conn類型的數(shù)據(jù)結(jié)構(gòu)來表示連接:
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成員實際上是一個包含兩個連接跟蹤鏈表節(jié)點的數(shù)組:tuplehash[IP_CT_DIR_ORIGINAL]指向初始方向的連接跟蹤鏈表節(jié)點,tuplehash[IP_CT_DIR_REPLY]指向應(yīng)答方向的連接跟蹤鏈表節(jié)點。通過tuplehash數(shù)組將一條完整的連接在內(nèi)核里表示出來了。
類型為nf_conntrack的ct_general成員可用于對本連接記錄的公開引用進(jìn)行計數(shù)。
struct nf_conntrack
{
atomic_t use;
};
status成員標(biāo)記連接的狀態(tài),timeout成員可對連接進(jìn)行計時,并對超時的連接進(jìn)行處理。
內(nèi)核為連接跟蹤在Netfilter的其中4個注冊點注冊了處理函數(shù):ipv4_conntrack_in()、ipv4_confirm()和ipv4_conntrack_local,他們的位置如圖3所示。
圖3 連接跟蹤在Netfilter中的注冊點
函數(shù) ipv4_conntrack_in()的主要功能是判斷當(dāng)前數(shù)據(jù)包的轉(zhuǎn)換 tuple是否已經(jīng)在連接跟蹤表里。網(wǎng)絡(luò)數(shù)據(jù)包進(jìn)入Netfilter后被轉(zhuǎn)換為一個tuple,函數(shù)ipv4_conntrack_in()首先在連接跟蹤表里查找該tuple。如果在,說明當(dāng)前數(shù)據(jù)包相關(guān)聯(lián)的連接已經(jīng)建立好了;如果不在,說明這是一個新連接,內(nèi)核會為該數(shù)據(jù)包生成相關(guān)的連接記錄并放到臨時表里。此時一條新的連接并未正式建立,因為該連接記錄并沒有被放到連接跟蹤表里,而是被放到一個臨時表里。
函數(shù) ipv4_conntrack_local()進(jìn)行一些相關(guān)操作后將馬上調(diào)用 ipv4_conntrack_in(),ipv4_conntrack_local()的主要功能就是調(diào)用ipv4_conntrack_in()進(jìn)行連接跟蹤處理。
函數(shù) ipv4_confirm()的主要功能是再次確認(rèn)是否為數(shù)據(jù)包建立連接跟蹤并添加到連接跟蹤表中。在函數(shù)ipv4_conntrack_in()中建立的連接記錄到了 ipv4_confirm()里才從臨時表里添加到連接跟蹤表,一條新的連接才正式建立。如果數(shù)據(jù)包在中間的處理過程中被過濾掉了,數(shù)據(jù)包將不能到達(dá)ipv4_confirm(),也就不會為該數(shù)據(jù)包建立連接記錄。
由圖3可知新建一條連接記錄有以下三種途徑:
(1)本地接收數(shù)據(jù)包
數(shù)據(jù)包流經(jīng)路線:
NF_INET_PRE_ROUTING ---> ROUTE --->NF_INET_LOCAL_IN
在 NF_INET_PRE_ROUTING處生成新的連接記錄(ipv4_conntrack_in()),在 NF_INET_LOCAL_IN處將該新連接記錄添加到連接跟蹤表(ipv4_confirm())。
(2)轉(zhuǎn)發(fā)數(shù)據(jù)包
數(shù)據(jù)包流經(jīng)路線:
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)本地發(fā)送包
數(shù)據(jù)包流經(jīng)路線:
NF_INET_LOCAL_OUT ---> ROUTE --->NF_INET_POST_ROUTING
在 NF_INET_LOCAL_OUT處生成新的連接記錄(ipv4_conntrack_local()),在 NF_INET_POST_ROUTING 處將該新連接記錄添加到連接跟蹤表(ipv4_confirm())。
連接跟蹤表記錄了每個連接的相應(yīng)ip地址、協(xié)議、端口、連接數(shù)目以及連接狀態(tài)等相關(guān)信息。利用這些信息可以配置更加靈活和安全的防火墻。筆者的實驗環(huán)境:防火墻服務(wù)器采用雙網(wǎng)卡,一個連接外網(wǎng)(校園網(wǎng)),一個連接內(nèi)網(wǎng)(實驗室)。防火墻服務(wù)器的操作系統(tǒng)為Fedora8,內(nèi)核版本為2.26.28,Iptables版本為1.4.4。外網(wǎng)接口eth0的IP地址為:172.17.21.31,子網(wǎng)掩碼為:255.255.255.0,網(wǎng)關(guān)為:172.17.21.254,內(nèi)網(wǎng)接口eth1的IP地址為:192.168.1.254。
使用connlimit模塊可以限制連接數(shù),起到負(fù)載均衡的作用。這樣可以將工作負(fù)擔(dān)相對平均的分散到多部主機上,使每部主機獲得大致相等的工作量。
(1)限制局域網(wǎng)內(nèi)每個用戶的連接數(shù)
如果需要限制局域網(wǎng)內(nèi)每個用戶的連接數(shù)為 100,只需在服務(wù)器上添加如下規(guī)則:
iptables –A FORWARD -m connlimit --connlimit-above 100 -j DROP
這樣局域網(wǎng)內(nèi)每個用戶的連接數(shù)當(dāng)超過100時數(shù)據(jù)封包將被丟棄。
也可以寫成這樣的規(guī)則:
iptables –A FORWARD -m connlimit !--connlimit-above 100 -j ACCEPT
這樣局域網(wǎng)內(nèi)的每個用戶的連接數(shù)在100以內(nèi)的數(shù)據(jù)封包將被轉(zhuǎn)發(fā),也就是連接數(shù)超過100的數(shù)據(jù)封包將被丟棄。以下的規(guī)則同理。
也可以針對某種傳輸協(xié)議限制每個用戶的連接數(shù),如限制每用戶的tcp連接數(shù)在100以內(nèi),只需將規(guī)則修改如下:
iptables -A FORWARD -p tcp -m connlimit--connlimit-above 100 -j DROP
將規(guī)則里“-p tcp”的tcp修改成upd或icmp就可以限制每用戶的upd或icmp協(xié)議的連接數(shù)。
(2)限制局域網(wǎng)內(nèi)單個用戶的連接數(shù)
如限制局域網(wǎng)內(nèi)192.168.1.1用戶的連接數(shù)為100,在服務(wù)器上添加如下規(guī)則:
iptables -I FORWARD -s 192.168.1.1 -m connlimit--connlimit-above 100 -j DROP
如果要限制局域網(wǎng)內(nèi) 192.168.1.1以外的用戶的連接數(shù)為100,規(guī)則只需修改如下:
iptables -I FORWARD !-s 192.168.1.1 -m connlimit--connlimit-above 100 -j DROP
(3)限制本機的連接數(shù)
數(shù)據(jù)封包進(jìn)入局域網(wǎng)內(nèi)或者從局域網(wǎng)內(nèi)發(fā)出到外網(wǎng),都要經(jīng)過轉(zhuǎn)發(fā)鏈(FORWARD)。進(jìn)入本機的數(shù)據(jù)封包或者從本機發(fā)出的數(shù)據(jù)封包不經(jīng)過轉(zhuǎn)發(fā)鏈(FORWARD),但所有進(jìn)入本機的數(shù)據(jù)封包都要經(jīng)過輸入鏈(INPUT),從本機發(fā)出的數(shù)據(jù)封包都要經(jīng)過輸出鏈(OUTPUT),限制本機的連接數(shù)需將規(guī)則里的FORWARD改成INPUT或OUTPUT:
iptables -I INPUT -m connlimit --connlimit-above 100 -j DROP
或者
iptables -I OUTPUT -m connlimit --connlimit-above 100 -j DROP
(4)基于某種協(xié)議限制連接數(shù)
connlimit功能模塊還可以只限制某種協(xié)議的連接數(shù),只需在前面規(guī)則的基礎(chǔ)上加上“-p”選項,比如限制局域網(wǎng)內(nèi)每個用戶的tcp連接數(shù)為100,規(guī)則如下:
iptables –A FORWARD -p tcp -m connlimit--connlimit-above 100 -j DROP
將tcp修改成udp或者icmp就可以限制相應(yīng)協(xié)議的連接數(shù),比如限制局域網(wǎng)內(nèi)192.168.1.1用戶的udp連接數(shù)為100,規(guī)則修改如下:
iptables -I FORWARD -p udp -s 192.168.1.1 -m connlimit--connlimit-above 100 -j DROP
(5)限制某個端口連接數(shù)
connlimit模塊具有限制端口連接數(shù)的功能,如果要限制局域網(wǎng)內(nèi)每個用戶的80端口連接數(shù)為10,規(guī)則如下:
iptables -I FORWARD -p tcp --dport 80 -m connlimit--connlimit-above 10 -j DROP
使用state模塊可以根據(jù)連接的狀態(tài)來進(jìn)行防火墻配置,這里的連接狀態(tài)是指在用戶空間里能使用的4種狀態(tài),如表1所示。
表1 數(shù)據(jù)包在用戶空間的狀態(tài)
如要禁止外網(wǎng)發(fā)起連接,可以添加規(guī)則:
iptables -A FORWARD -i eth0 -m state state NEW -j DROP
這樣一條連接只能是由局域網(wǎng)內(nèi)用戶發(fā)起建立(這里服務(wù)器連接外網(wǎng)的網(wǎng)卡是eth0,連接內(nèi)網(wǎng)的網(wǎng)卡是eth1)。外網(wǎng)進(jìn)入NEW狀態(tài)的數(shù)據(jù)包都將丟棄。如果是針對主機而不是局域網(wǎng)設(shè)置,規(guī)則修改如下:
iptables -A INPUT -m state state NEW -j DROP
如要禁止局域網(wǎng)內(nèi)用戶回應(yīng)外網(wǎng)的ICMP封包,添加規(guī)則:
iptables -A FORWARD -p icmp -o eth 0 -m state --state ESTABLISHED -j DROP
Linux下的 Netfilter防火墻功能強大、擴(kuò)展性強。本文分析了2.6.28內(nèi)核下網(wǎng)絡(luò)數(shù)據(jù)包連接跟蹤的工作原理。利用Netfilter的連接跟蹤功能使實驗室或其他局域網(wǎng)內(nèi)的用戶機負(fù)載更加均衡,更加方便和靈活的配置防火墻。
[1]博嘉科技.Linux 防火墻技術(shù)探秘[M].北京:國防工業(yè)出版社.2002.
[2]顧棟梁,周健,程克勤.基于Netfilter 的連接限制的研究與實現(xiàn)[J].計算機工程.2009.
[3] www.kernel.org.
[4]郭錫泉.應(yīng)用層協(xié)議分析在狀態(tài)檢測防火墻中的應(yīng)用[J].計算機工程.2007.