1. 程式人生 > >Linux程序網路流量統計方法及實現

Linux程序網路流量統計方法及實現

1 前言

在某些應用安全場景需要結合程序級網路連線、流入流出流量等資料直接分析出程序的異常。例如,在內網主機上是否存在持續惡意外傳敏感資料的現象、在網路監控時發現伺服器大量頻寬被佔用但不清楚由系統具體哪個程序佔用。為此都需要獲取更細粒度的程序級網路流量資料直接鎖定異常服務。

在Linux系統中都有相應開源工具採集網路連線、程序、流量等資訊,像netstat命令檢視主機網路連線資訊,一般包括最基本的五元組資訊(源地址、目標地址、源埠、目標埠、協議號);ps命令採集程序資訊,包括pid, user, exe, cmdline等;iftop命令獲取網絡卡的實時流量資料。

同時在linux /proc目錄下可直接讀取主機級網路流量資料,例如/proc/net/snmp提供了主機各層IP、ICMP、ICMPMsg、TCP、UDP詳細資料,/proc/net/netstat檔案InBcastPkts、 OutBcastPkts、InOctets、OutOctets欄位能獲取主機的收發包數、收包位元組資料。

但很可惜沒有一個細粒度程序級流入流出網路流量資料。為此,本文旨在分享實現一種統計Linux程序級網路流量方式。

2 基礎資料

涉及linux /proc目錄下網路狀態檔案/proc/net/tcp、/proc/net/udp,程序檔案描述符目錄/proc/pid/fd。

2.1 網路狀態檔案

以tcp的狀態檔案為例/proc/net/tcp:

sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
6: 0100007F:22B8 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 623457565 1 ffff88004f918740 750 0 0 2 -1

重點關注網路連線五元組+連線狀態+inode號,分別在第2、3(local_address)、4(st)、11列(inode)。

第2、3列分別是主機位元組序ip:port ,例如"0100007F:22B8" -> “10.93.122.33:8888”

第4列是網路連線狀態資訊,狀態欄位含義如下:

"01": "ESTABLISHED",
"02": "SYN_SENT",
"03": "SYN_RECV",
"04": "FIN_WAIT1",
"05": "FIN_WAIT2",
"06": "TIME_WAIT",
"07": "CLOSE",
"08": "CLOSE_WAIT",
"09": "LAST_ACK",
"0A": "LISTEN",
"0B": "CLOSING"

常見網路狀態如0A,01 分別代表某程序正監聽和已建立連線狀態。

第11列是inode號,代表Linux系統中的一個檔案系統物件包括檔案、目錄、裝置檔案、socket、管道等的元資訊。如圖中623457565是某程序監聽socket(狀態0A)的inode號。

2.2 程序檔案描述符

/proc/pid/fd目錄是程序所有開啟的檔案資訊,其中0、1、2表示標準輸入、輸出、錯誤,網路連線是以socket:開頭的檔案描述符,其中[]號內的是socket對應inode號,這樣可以和網路狀態檔案/proc/net/tcp下的inode號可對應起來。

以pid:30168程序為例,該程序監聽8888(0x22B8)埠,在/proc/30168/fd目錄下顯示檔案描述符是3、5代表的是sokcet連線,對應inode號分別是623457565、623457729。

ls -l /proc/30168/fd

lrwx------ 1 root root 64 Oct 30 10:46 0 -> /dev/pts/0
lrwx------ 1 root root 64 Oct 30 10:47 1 -> /dev/pts/0
lrwx------ 1 root root 64 Oct 30 10:46 2 -> /dev/pts/0
lrwx------ 1 root root 64 Oct 30 10:47 3 -> socket:[623457565]
lrwx------ 1 root root 64 Oct 30 10:47 4 -> anon_inode:[eventpoll]
lrwx------ 1 root root 64 Oct 30 10:48 5 -> socket:[623457729]

再從/proc/net/tcp過濾22B8,可以發現有兩條記錄,狀態分別為"0A",“01”,inode號是623457565, 623457729,與前面30168程序fd目錄下的inode號一致,就可找到這連線歸屬的程序。

cat /proc/net/tcp |grep 22B8

6: 00000000:22B8 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 623457565 1 ffff8811f2fd1740 100 0 0 10 0
13: 0100007F:22B8 0100007F:ED2C 01 00000000:00000000 00:00000000 00000000     0        0 623457729 1 ffff8810880e1740 20 4 30 10 -1

根據上述檔案資訊可以從/proc/net/tcp建立起網路連線五元組->inode的對映, 再從/proc/pid/fd建立起連線inode ->程序的對映。

這樣通過inode號作為橋樑關聯起系統內的程序與網路連線的資訊。

3 實現流程

為了實時獲取網路連線流量在linux主機上使用開源libpcap庫來抓取網路報文。

整個實現流程圖如下包含以下5個關鍵步驟。

在這裡插入圖片描述

  1. 抓包
    使用抓包Libpcap庫獲取到網路報文packet結構。

  2. 解析報文
    解析出packet的五元組(源地址、目標地址、源埠、目標埠、協議號)資訊和當前報文的流量大小。

  3. 快取更新
    在ConnInodeHash快取查詢五元組組成的key對應的inode號,如果不存在,重新讀取/proc/net/tcp與udp,重新整理ConnInodeHash快取,建立起新連線與inode的對映; 並重新讀取/proc/pid/fd目錄對所有檔案描述符遍歷,過濾出以socket:開頭的連線,重新整理InodeProcessHash快取,重新建立inode與程序的對映。

  4. hash查詢
    根據查詢到inode號在InodeProcessHash快取查詢相應程序pid。

  5. 統計流量
    根據報文地址,判斷當前連線方向,累加程序流入、流出資料。

4 總結

通過對Linux主機抓包,結合網路狀態檔案、程序檔案描述符實現一種細粒度的程序級網路流量採集方式。利用Linux檔案inode號作為橋樑,關聯出程序、網路連線的對映關係。

本文的實現方式可以按程序維度統計接收/傳送的總量/平均值等各維度資料,也可以擴充套件按網路連線維度統計流量資料,這些在主機流量安全分析、網路監控排查等場景方面可作為重要依據。

本文介紹的流量統計方式是一種通用的實現方式,但持續使用libpcap抓包對主機效能有較明顯損耗; 滴滴雲的主機安全團隊研發了一種更高效的實現方式,主機上服務無任何感知能力,目前已在數萬臺主機上穩定執行,下篇文章進行詳細分析,敬請期待。

本文原作者:周嶠