如今的移動端應用幾乎都會經過網絡請求來和服務器交互,經過抓包來診斷和網絡相關的bug是程序員的重要技能之一。抓包的手段有不少:針對http和https可使用Charles設置代理來作,對於更普遍的協議可使用tcpdump或者wireshark。wireshark提供GUI,方便作深刻全面的數據分析。tcpdump則輸出原始的包內容,好處是快速高效,以前寫過一篇簡單的微信紅包圖片的破解教程,就是用tcpdump來操做的。這篇文章主要介紹tcpdump的基本使用方法,閱讀目標是能基本掌握並運用tcpdump解決網絡相關的問題。閱讀前提是對TCP/IP有初步的瞭解。android
<br/>ios
<br/>git
iOS設備上啓動tcpdump比較方便。apple在mac上有個叫rvictrl的程序,能夠經過iOS設備的udid建立一個虛擬網卡,而後經過這個虛擬網卡監聽設備上全部的網絡流量。步驟以下:程序員
獲取itunes獲取設備udidgithub
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_1.png?raw=true" width="335">shell
打開終端(terminal),建立虛擬網卡服務器
在終端輸入rvictl -s udid,建立虛擬網卡。微信
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_2.png?raw=true" width="664">網絡
啓動tcpdump監控流量app
在終端繼續輸入sudo tcpdump -i rvi0 -AAl,啓動tcpdump監控。
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_3.png?raw=true" width="698">
<br/>
Android設備沒辦法經過rvictl建立虛擬網卡,可是能夠把tcpdump的可執行文件上傳到android設備上,而後經過mac遠程登陸android設備運行tcpdump,前提是這臺android設備必須已經root過。步驟以下:
下載android版本的tcpdump
從這個連接能夠下載到專門爲android系統編譯的tcpdump版本。
經過adb將tcpdump上傳到android設備
經過adb push將tcpdump文件上傳到特定的目錄,這裏咱們選擇/sdcard/data目錄。
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_4.png?raw=true" width="594">
在android設備上運行tcpdump
經過adb shell登錄設備,並執行tcpdump,最後一步執行./tcpdump便可。
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_5.png?raw=true" width="480">
<br/>
<br/>
通過上面的步驟成功運行tcpdump以後,接下來就能夠分析輸出的網絡包內容了,iOS設備和Android設備的輸出是一致的。咱們先來解析下幾個基本的格式:
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_6.png?raw=true" width="855">
圖中紅色方框內的部分是一個ip包的詳細記錄,相似的紀錄還有好幾條。這裏咱們着重分析第一條的各部分字段含義。
14:37:41.615018 很簡單,是該包接收到的時間。
17.143.164.37.5223 是發送方的ip地址及端口號(5223是端口號)。
10.29.44.140.58036 是我iphone的ip地址及端口號。
Flags [P.] 是tcp包header部分的第14個字節的P位。這個字節所包含的幾個flag很重要,後面我會單獨詳細講解。這裏P位表示接受方須要立刻將包push到應用層。
seq 1:54 tcp包的seq號,1是起始值,54結束值。tcp之因此被認爲是流,是由於tcp包所攜帶的每個字節都有標號(seq號)。1:54代表總共有54個字節被接受,其中一個字節是三次握手階段所使用,因此一共發送的長度是53字節。
ack 101 tcp包的ack號,ack 101代表seq號爲100的字節已被確認收到,下一個指望接收的seq號從101開始。
win 255 win表示的是tcp包發送方,做爲接受方還能夠接受的字節數。這裏win 255代表ip爲17.143.164.37的主機還能夠接受255個字節。
options [nop,nop,...] options[...]表示的是該tcp包的options區域,nop是no opertion的縮寫,沒什麼實際用途,主要是用作padding,由於options區域按協議規定必須是4字節的倍數。
options[... TS val 2381386761] ts val這個值是tcp包的時間戳,不過這個時間戳和設備的系統時間沒啥關係,剛開始是隨機值,後面隨着系統時鐘自增加。這個時間戳主要用處是seq序列號越界從0從新開始後,能夠確認包的順序。
options[... ecr 427050796] ts ecr這個值主要用來計算RTT。好比A發送一個tcp包給B,A會在包裏帶上TS val,B收到以後在ack包裏再把這個值原樣返回,A收到B的ack包以後再根據本地時鐘就能夠計算出RTT了。這個值只在ack包裏有效,非ack包ecr的值就爲0.
length 53 這個length是應用層傳過來的數據大小,不包括tcp的header。這個值和咱們上面分析的seq 1:54是一致的。
以上就是一個基本的tcp包結構,你們能夠按照上面的分析再把其餘幾個包理解下。咱們在作應用的時候面對的更可能是http協議,但對一個http請求是怎麼經過tcp/ip分解成一個個的packet,而後怎麼在網絡上穩定可靠的傳輸,要有個基本的印象。下面咱們再看下tcpdump更多的功能,這些功能都是基於對tcp/ip協議的理解,遇到不理解的建議多google下相關的技術概念。
<br/>
<br/>
再繼續深刻tcpdump以前,先貼上一張tcp header格式圖,常看常新。
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpheader.png?raw=true" width="1056">
咱們再仔細看下上面提到的flags概念,flags位於tcp header的第十四個字節,包含8個比特位,也就是上圖的CWR到FIN。這8個比特位都有特定的功能用途,分別是:CWR,ECE,URG,ACK,PSH,RST,SYN,FIN。
CWR ,ECE 兩個flag是用來配合作congestion control的,通常狀況下和應用層關係不大。發送方的包ECE(ECN-Echo)爲0的時候表示出現了congestion,接收方回的包裏CWR(Congestion Window Reduced)爲1代表收到congestion信息並作了處理。咱們重點看其餘六個flag。
URG URG表明Urgent,代表包的優先級高,須要優先傳送對方並處理。像咱們平時使用terminal的時候常常ctrl+c來結束某個任務,這種命令產生的網絡數據包就須要urgent。
ACK 也就是咱們所熟悉的ack包,用來告訴對方上一個數據包已經成功收到。不過通常不會爲了ack單獨發送一個包,都是在下一個要發送的packet裏設置ack位,這屬於tcp的優化機制,參見delayed ack。
PSH Push咱們上面解釋過,接收方接收到P位的flag包須要立刻將包交給應用層處理,通常咱們在http request的最後一個包裏都能看到P位被設置。
RST Reset位,代表packet的發送方立刻就要斷開當前鏈接了。在http請求結束的時候通常能夠看到一個數據包設置了RST位。
SYN SYN位在發送創建鏈接請求的時候會設置,咱們所熟悉的tcp三次握手就是syn和ack位的配合:syn->syn+ack->ack。
FIN Finish位設置了就表示發送方沒有更多的數據要發送了,以後就要單向關閉鏈接了,接收方通常會回一個ack包。接收方再同理發送一個FIN就能夠雙向關閉鏈接了。
這8個flag首字母分別是:C E U A P R S F。初看難以記憶,我腦洞了下,把它們組合成 supr cafe,固然少了super少了個e,我能夠將就下。咱們在使用tcpdump的時候會常常看到這幾個flag,[S],[P],[R],[F],[.]。其餘幾個都好理解,[.]特殊點,是個佔位符,沒有其餘flag被設置的時候就顯示這個佔位符,通常表示ack。
這部分咱們來看下tcpdump經常使用的一些命令參數。文章最開始部分的tcpdump命令是這樣的:sudo tcpdump -i rvi0 -AAl。 -i rvi0 -AAl都是屬於參數部分。常見的有這些:
-i, 要監聽的網卡名稱,-i rvi0監聽虛擬網卡。不設置的時候默認監聽全部網卡流量。
-A, 用ASCII碼展現所截取的流量,通常用於網頁或者app裏http請求。-AA能夠獲取更多的信息。
-X,用ASCII碼和hex來展現包的內容,和上面的-A比較像。-XX能夠展現更多的信息(好比link layer的header)。
-n,不解析hostname,tcpdump會優先暫時主機的名字。-nn則不展現主機名和端口名(好比443端口會被展現成https)。
-s,截取的包字節長度,默認狀況下tcpdump會展現96字節的長度,要獲取完整的長度能夠用-s0或者-s1600。
-c,只截取指定數目的包,而後退出。
-v,展現更多的有用信息,還能夠用-vv -vvv增長信息的展現量。
src,指明ip包的發送方地址。
dst,指明ip包的接收方地址。
port,指明tcp包發送方或者接收方的端口號。
and,or,not,操做法,字面意思。
上面幾個是我我的比較經常使用的,更多的參數能夠參考這個詳細文檔。有興趣的能夠分析下面幾個例子練習下:
tcpdump 'tcp[13] & 16!=0'
tcpdump src port 80 and tcp
tcpdump -vv src baidu and not dst port 23
tcpdump -nnvvS src 192.0.1.100 and dst port 443
<br/>
<br/>
說了這麼多,咱們再來實戰下,看一個完整的http請求流程。
下面截圖裏的流量是我監聽的 知乎App點贊以後發送的一個https請求。我以前先分析過server的ip地址了,tcpdump命令是:
sudo tcpdump -i rvi0 -AAl src 60.28.215.123 or dst 60.28.215.123
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_zhihu.png?raw=true" width="890">
圖中列出了6個前面的packet,10.29.44.240是我iphone的ip地址,60.28.215.123是知乎server的ip地址,紅色方框內是iphone發出的packet,白色方框內是server發出的packet。packet1是iphone三次握手的第一個syn包,packet2是server ack+syn的包,packet3是iphone ack的包。這3個packet以後tcp的三次握手就完成了。
packet4是iphone發出的http request。長度只有240個字節,因此一個packet就發過去了,固然還設置了flags的P位,request須要立刻被應用層處理。包裏面出現了spdy,點贊。
packet5是server ack剛收到的包,長度位0,因此這僅僅是一個ack包。
packet6是server返回http的response了,1388個字節。packet5和packet6都ack了seq爲241的包,固然是爲了增長ack的成功率。
中間還有好幾個packet就不仔細分析了,最後再看下請求完成的最後幾個包:
<img src="https://github.com/music4kid/music4kid.github.io/blob/master/images/tcpdump_zhihu2.png?raw=true" width="886">
最後兩個packet比較簡單,iphone發送個FIN+ACK的包就斷開鏈接了,server直接發送了一個RST包後也斷開鏈接了。
這篇教程到這裏就結束了,建議你們本身多練習下,遇到不懂的參數或關鍵字多google。最好能系統的學習下tcp/ip協議?。