本文首先概述三種常用的Linux路由器計費方式,然後詳細介紹Linux系統的Netfilter包過濾技術,並在此基礎上探討以Netfilter為核心開發的高效、低負載、可擴展的流量統計系統。 Linux路由器的計費方式 由於Linux系統的穩定性、可用性越來越高,基於Linux系統的路由應用也越來越廣泛。無論是對於純IP轉發應用,還是基於NAT技術及透明代理技術的Linux路由器系統,如何高效、准確地進行計費都是一個值得研究的課題。 在Linux的世界裡,解決問題的辦法往往不止一種。目前常用的Linux路由器計費方式有以下三種: 1. 基於數據鏈路層的、網絡監聽模式的計費。 使用專門的網絡監聽主機,此時主機處於混雜模式(Promiscuous),對流經的數據包進行監聽和計費,監聽的主機必須與路由器處在同一個廣播段。由於監聽高速以太網會產生嚴重的丟包問題,故此方法應用並不廣泛。 2. 基於SNMP技術的計費。 通過在Linux路由器上配置SNMP代理進行流量統計。此方法應用較為廣泛,但SNMP代理的安裝會增加路由器的負載,並帶來相關的安全性問題。 3. 使用第三方軟件,如xtacacsd等。 基於Linux內核的Netfilter技術 Netfilter 是Linux下的包過濾軟件系統,目的是實現完整的包過濾、防火牆和網絡地址翻譯(NAT)等功能。其原理基於檢查數據包的頭部,並根據規則進行處理,實現數據包的控制、安全、偽裝、分割管理。具體實現是通過加載內核模塊iptables_filter.o和命令 iptables來操作。 Netfilter內建三個表,其功能如表1所示。
表1 Netfilter的組成默認情況下,數據包從某網絡進入Linux路由器所經過的Netfilter過程如圖1所示。
圖1 Netfilter的數據包路由1.當一個數據包進入(如網絡1),內核首先檢查包的目的地(路由決策)。 2.如果它是進入本機的,包會向圖的下方移動,到達INPUT鏈。在這裡,任何等待該包的進程都會收到它。 3.否則,如果內核未被允許轉發,或者不知道如何轉發該包,它就會被丟棄。如果允許轉發,而且包的目的地是另一個網絡接口(如網絡2),那麼包繼續向圖的下邊行進,到達FORWARD鏈。如果策略允許通過(ACCEPT),它將被送出。 4.服務器上的進程也可以發送網絡包,這些包直接通過OUTPUT鏈發送,如果被允許(ACCEPT),那麼該包繼續向可到達其目的地的網絡接口發送。 “nat 表”管理網絡地址翻譯,其中PREROUTING鏈可定義進行目的地址NAT的規則。因為路由器進行路由時只檢查數據包的目的 IP地址,所以為了使數據包能正確路由,必須在路由之前就進行目的NAT。POSTROUTING鏈用來定義進行源地址NAT的規則,系統在決定數據包的路由以後才執行該鏈中的規則。OUTPUT鏈定義對本地產生的數據包的目的地址NAT規則。 除了內建鏈,Netfilter還支持用戶自建鏈,支持更復雜、功能更強的應用。 計費規則
根據Netfilter可擴展表鏈的特性,可以通過自定義鏈來實現對數據包的流量計費。從網絡芾?/u>的角度考慮,需要關注的流量一般是總流入流出及一些基本的網絡應用流量,如FTP、WWW、SMTP、POP等,更多的監控可以根據需要添加。
iptables的流量計費功能在同一鏈內只能實現一次,因此自定義表必須精心設計,保證目標數據包經過計費鏈。首先建立用戶自定義表ACC-IN、ACC-OUT、ACC-OUT-SMTP、ACC-IN-POP3、ACC-IN-WWW、ACC-IN-FTP。
對於Linux路由器,往往需要實現IP偽裝與透明代理,其計費鏈與傳統的包轉發路由器有所不同。對於IP偽裝(網絡地址翻譯),第一個分組IP包經過 PREROUTING(nat)鏈,此後所有的IP包均經過FORWARD(filter)鏈,因此實際上對NAT的計費是在 FORWARD鏈上完成的。對於透明代理,其實質是將用戶HTTP的80端口請求轉發到代理服務進程,如果代理服務進程在本地,則相應的流量發生在本地的 OUTPUT鏈。
流入量統計的iptables表與用戶自定義表的順序關系如圖2。
圖2 計費表的順序關系如圖2所示,每一個流入的IP包都會遍歷所有的計費鏈,流出圖與之類似。如果IP包符合計費規則,則iptables記數,相應的規則如表2示。
表2 計費類型說明◆ 對於總流入,由於是在本地網絡流入計費,所以本地的TCP流量可以忽略,相應的規則如下(eth0為內網網卡,內網為10.0.0.0/24):
#iptables -A FORWARD -o eth0 -s ! 10.0.0.0/24 -s *.*.*.* -j ACC-IN◆ FTP流量包括20、21端口,由於21端口只負責FTP控制信令傳送,故只需對負責數據傳送的20端口計費即可:
#iptables -A ACC-IN -o eth0 -p tcp --source-port 20 -d *.*.*.* -j ACC-IN-FTP◆ WWW流量如果不設置透明代理,則計費發生在FORWARD鏈:
iptables -A ACC-IN -o eth0 -p tcp --source-port 80 -d *.*.*.* -j ACC-IN-WWW◆ 對於使用透明代理的流量,計費發生在OUTPUT鏈(其中10.x.x.x為內網IP,X為代理進程的端口號):
iptables -A OUTPUT -o eth0 -p tcp -s 10.x.x.x --source-port x -d *.*.*.* -j ACC-IN-WWW其它協議的計費方式類似。對於任意的TCP及UDP協議,只要知道服務端口號,都可以進行計費。 實際的計費規則采用PERL自動生成。首先生成需要計費的IP地址列表文件,然後通過PERL程序讀取該文件並自動生成計費規則。程序示例如下:
sub set_iptables_rules{ my(@mylist)=@_; open (FILE,$mylist[0]); #讀取配置文件 @lines=<FILE>; close FILE; foreach $address(@lines) { chomp($address); #處理配置文件 @address_var=split(/ +/,$address); #根據配置文件生成計費規則 `$iptables $mylist[2] FORWARD -i $local_nic -s $address_var[0] -d ! $local_net -j ACC-OUT`; `$iptables $mylist[2] ACC-OUT -i $local_nic -p tcp -s $address_var[0] --dport 25 -j ACC-OUT-SMTP`; ...... } }Linux 路由器的防火牆規則也基於iptables進行設置,主要是針對INPUT鏈和FORWARD鏈。計費規則也使用了 iptables的系統默認鏈FORWARD和OUTPUT,與防火牆設置的FORWARD鏈上出現重疊。因此要保證在FORWARD鏈上的計費規則必須先於防火牆規則,才能使計費規則與防火牆規則同時發生作用。 系統結構 整個流量計費系統的結構如圖3示,數據包流經Linux路由器並被計費;統計數據送入數據庫;用戶通過前端界面查詢流量,同時可對計費規則進行監控和管理。
圖3 系統結構示意圖系統的後台程序 iptables的計數功能僅僅提供了簡單的流量顯示,使用參數iptables -nvxL可得到更多的流量詳細數據。例如:
Chain FORWARD (policy ACCEPT 28951 packets, 18212425 bytes) pkts bytes target prot opt in out source destination 116 8465 ACC-OUT all -- eth0 * 10.2.229.2 !10.0.0.0/8 134 59582 ACC-IN all -- * eth0 !10.0.0.0/8 10.2.229.2一個切實可用的計費系統需要數據庫的支持,並提供友好的查詢界面,必須在後台對iptables提供的數據進行處理,並且輸入至數據庫。使用PERL語言的正則表達式,可以對iptables輸出的數據進行處理,以選取需要的數據段。對於每一行數據都要提取流量及IP地址,所以要對目的數據段用正則表達式進行處理:
for ($i=0;$i<=$count;$i++) {$lines_in[$i]=~/^\s+\d+\s+(\d+)\s+(\D+\d)\s+(\W\d+\.\d+\.\d+\.\d+\/\d+)(\d+\.\d+\.\d+\.\d+).*$/; $ac_ip=$4; $ac_in=$1; #讀取IP地址與總流量 ...... #將流量記錄輸入至數據庫 $sth = $dbh->do ("INSERT INTO $mysql_table_name (date,ip,acc_in,acc_out,acc_in_ftp,acc_in_pop3,acc_in_www,acc_out _smtp) VALUES ('$date','$ac_ip','$ac_in','$ac_out',' $ac_in_ftp','$ac_in_pop3','$ac_in_www','$ac_out_smtp')"); }計費周期可根據需要選擇,但必須兼顧存儲量與效率。這裡計費周期選取為24小時,即設定系統的crontab,定時每天執行後台程序將流量輸入數據庫。計費完成後將流量記數器清零:
#iptables -Z FORWARD計費後台程序由於采用PERL語言編寫,程序緊湊高效,與SNMP計費方式相比,實現方法簡單,可定制性強,而且每天執行一次,對Linux路由器沒有增加額外的負載。 數據庫與前端實現 由於Linux路由器承擔大量用戶的IP包轉發任務,負載較重,為了避免對其性能的影響,後台數據庫不設置在本地,而采用多台路由器使用同一後台MySQL數據庫來進行管理。 前台查詢界面則可采用PHP語言編寫,提供給用戶日流量、月流量、年流量的查詢,同時可對計費策略進行監控和管理,如圖4示。
圖4 用戶查詢界面本計費系統由於基於Netfilter技術,實現簡單、高效,對系統的性能影響不大,同時保持了良好的可擴充能力,在實際的應用過程中能夠根據用戶的需要增加計費類型,是一個高效、低負載、可擴展的Linux路由器流量統計系統。
作者:徐彬 賀蘊普 賽迪