某天被人出了一個題目「如何知道 Web Site 實際發出的 Request 數量?」
其實這個題目有好幾種解法,例如:
- 直接查看 Cloud Host 的報表
- 開啓 Web Server 的 access.log,再透過 Log 分析來取得
- 安裝 Network Traffic Analyser 來記錄與分析
其實上述的方法都可以 Google 找到現成的解決方案,但自己卻沒來由的突發奇想,想知道「是否可以由封包記錄中取得這樣的資訊?」經過一番研究,還真的做的到,而且實作起來並不困難,以下就簡單的分享經驗。
實作方式其實很簡單,首先透過 Linux 的指令 tcpdump 過濾並記錄某種特別的封包,並將封包接收資訊另存為 Log File,最後再透過 Parser 去分析 Log 即可。
tcpdump 的指令詳解,可以參考鳥哥的網站,或者自己直接在 command line 去問 man。
$ man tcpdump
最終會使用的 tcpdump 指令如下
$ tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-push) != 0 and dst net xxx.xxx.xxx.xxx and port 80' -q > requests.log
簡單說明所使用到的選項與參數
-i eth0
(代表只要抓取 eth0 這個 interface 的封包資料,請輸入主機真正對外的 interface。)-n
(代表只要以 ip 顯示封包來源。)tcp[tcpflags] & (tcp-push) != 0
(代表只抓取帶有「tcp-push」這個 Flag 的封包。)and dst net xxx.xxx.xxx.xxx
(xxx.xxx.xxx.xxx請取代為你的主機的 ip,代表只要抓取由你的主機發出的封包。) and port 80(代表只要抓取 PORT 80 的封包。)-q
(代表只要在畫面上印出簡易的封包資訊。)> requests.log
(配合前面所有的選項與參數,最後將印出畫面的資訊都存入 requests.log 這個檔案中。)
有了上面的指令,就可以完成「記錄封包」這個主要工作。但若實際使用後,就會發現要先中斷 tcpdump,才能在 requests.log 中看到所記錄的資料,因此如果要用 tcpdump 長期記錄封包,建議還是要寫成 shell script,排入 crontab 中,讓指令可以被定期中斷並按區間將封包資料一一存為 Log。
例如下面即是一個土法煉鋼的範例:
#!/bin/bash
time="$(date +"%Y-%m-%d_%H.%M.%S")"
localip="162.243.152.212"
port="80"
pkill tcpdump
/usr/sbin/tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-push) != 0 and dst net '$localip' and port '$port'' -q > $time.log
利用 pkill 中斷 tcpdump 讓封包資訊寫入 Log,接著再次啟動 tcpdump 繼續記錄封包,如此反覆地定期取得最新的 Log。 而 Log 的內容會呈現如下面的格式:
06:27:40.981843 IP xxx.xxx.xxx.xxx.44502 > XXX.XXX.XXX.XXX.80: tcp 333
06:29:32.177434 IP xxx.xxx.xxx.xxx.40203 > XXX.XXX.XXX.XXX.80: tcp 463
06:29:34.378050 IP xxx.xxx.xxx.xxx.40203 > XXX.XXX.XXX.XXX.80: tcp 569
每一行 Log 就代表一次 request,因此只要透過 crontab 定期運行上面的 script,再另外撰寫 Log 分析程式,就能獲得我們想要知道的 request 次數。且 Log 中其實還包含了「請求時間」、「對方的 IP」兩種資訊,若有需要也可以一併分析,藉此得知使用者們訪問的時間與地點。
2015/3/24 補充說明: 為何只要抓取帶有「tcp-push」這個 Flag 的封包呢?可以參考鳥哥的這一篇《TCP/IP 的傳輸層相關封包與資料》,或下面的參考資料,總之封包中會包含一些必要資訊,因此當然有資訊會標記說此封包是一個 Request 的開始,而我們就是要抓取這樣的封包,並存入 Log 之中。
參考資料: