wireshark源代碼分析

各位親,不是我不想回復你們的問題。是我也不了解。不能誤導。希望大家相互幫助。看看能否幫那些提問的小盆友們回復一下呢?

這些都是轉載的,如果實在沒有辦法,可以打開鏈接到原作者哪里去提問試試看。。。



經過多次嘗試,終于在windows上成功編譯wireshark源代碼,但用的不是下面的這個步驟,不過大同小異,我的是vs2005,所以用的:http://blog.csdn.net/alexander_vc/article/details/6198836?的方法。

  • 1.2.7版的wireshark的capture_if_details_dlg_win32.c對vs2005有bug,需要下載更新的wireshark版本,并更換該文件。詳見wireshark的


幾點注意:1.python要用2.4——2.6版本

??????????????????? 2.Cygwin安裝要把文中介紹的庫一并安裝

??????????????????? 3.如果執行命令,總是nmake報各種錯,請反復檢查你的Wireshark目錄里面config.nmake文件配置的是否正確。


用vs2005,vs2010都編譯成功了。不得不說這得靠人品,多試試,辦法總是有的。


原文地址:http://blog.sina.com.cn/xianjiaotonguniversity

在windows上編譯wireshark源代碼

在編譯過程中需要以下軟件:VisualStudio,Python,Cygwin以及Wireshark源代碼。

1. Visual Studio

我使用的是Visual Studio 2008版本。

2. Python

下載安裝Python,從2.4 –2.6應該都是可以的,我使用2.6版本。主要是在編譯過程中會使用到Python。

3. Cygwin

去Cygwin上下載最新版本安裝,然后開始安裝,整個安裝過程是在線安裝,特別注意的是,以下庫必須安裝,否則不能順利完成編譯:

Archive / unzip
Devel / bison
Devel / flex
Interpreters / perl
Utils / patch
Web / wget

4. 下載Wireshark源代碼 &編輯config.nmake

輸入這個網址,http://www.wireshark.org/download/src/all-versions/,從上面下載Wireshark源代碼,這里,值得一提的是,最好下載頁面中給出的svn中的源代碼,能保證該代碼絕對是最新的。

下載完成之后,在Wireshark目錄里面打開config.nmake,需要進行一些設置之后才可以開始編譯。

(1)WIRESHARK_LIBS, 設置編譯wireshark所需的庫所在的目錄,默認即可。
(2)PROGRAM_FILES,設置本機程序安裝目錄,默認即可。
(3)MSVC_VARIANT,因為我使用VS2008編譯,所以這里不要修改。如果使用的是其他版本的VS,則要將相應行前面的#去掉,并把其余行的#加上。例如如果你使用的是VS2005,則將值為MSVC2005的那一行前的#去掉,其余MSVC_VARIANT項行首全部加上#注釋掉。
(4)CYGWIN_PATH,將其設置為cygwin的bin目錄,例如D:\cygwin\bin。
(5)MSVCR_DLL,如果VS安裝在D盤,請在這里相應的地方用絕對路徑表示,而不要去修改前面的PROGRAM_FILES,否則會出現意想不到的錯誤。

5. 編譯Wireshark

用VS2008安裝的VS2008命令提示進入或者通過CMD進入之后,再去運行VC下面的vcvars32.bat,或者是把vcvars32.bat拖到命令窗口,再回車就行。然后進去Wireshark目錄,首先通過下面的命令檢驗一下:

nmake -f Makefile.nmake verify_tools
得到的信息如下:我忘了截圖,這是copy別人的圖,不過我的跟他的基本一樣,出了上面的版權信息是中文,以及版權信息下面有個Error,說是C:\wireshark-win32-libs\current_tag.txt中的內容應該是2011-06-27外,其他都是一樣的。不過這個錯誤不用管,不會影響編譯。
6.執行nmake –f Makefile.nmake setup得到很多信息,最后如下:7.先執行下nmake –f Makefile.nmake distclean8.執行nmake –f Makefile.nmake all這個過程要花上10幾分鐘,到這里,編譯就完成了。


wireshark源代碼分析報告之一

因為手頭的項目需要識別應用層協議,于是想到了wireshark,打算在項目中集成wireshark協議分析代碼。在官網上下了最新版的wireshark源代碼,我的天啊,200多M,這么多代碼文件怎么看?在網上了找了很久,希望能找到別人的分析報告,可惜的是,找了很久也沒有找到,比較多的還是怎么開發wireshark協議識別和分析插件,很少有人分析它的源代碼。于是,我找了個查看源代碼比較方便的工具——sourceinsight,打算先瞧一瞧這些代碼文件,說不定運氣好,看著看著就知道它是怎么工作的。

???看過wireshark源代碼的人應該知道,它的代碼文件很多很多,而我也是第一次閱讀別人這么多的代碼,所以要把wireshark的協議分析代碼集成到我的項目中,對我來說還真不是一件容易的事。花了很多時間,搜了很多資料,也看了很多資料,最后決定從wireshark的命令行模式——tshark入手,分析tshark是如何識別網絡協議的。

???我決定利用斷點調試查看tshark是如何工作的,但是要調試,就需要編譯連接wireshark源代碼。于是又開始找資料摸索怎么編譯我wireshark代碼。這部分的資料倒是比較好找,但是當時找的資料都不能順利編譯,最后在別人的基礎上,加上自己的思考,終于編譯成功。于是就有了上一篇文章描述如何在visual studio2008上編譯wireshark源代碼。

???啰嗦了這么多,真正開始分析tshark代碼了。

???首先,成功編譯后的wireshark源代碼文件夾中出現了很多目標文件,還生成了一個wireshark-gtk2文件夾,里面有好幾個exe文件,比如wireshark.exe,tshark.exe,dumpcap.exe等。具體如下所示:




??這個圖片就是wireshark-gtk2文件夾中的一部分。

?? 接下來,可以用visualstudio2008(工具不限制,但最后是跟你編譯時選定的工具保持一致)打開wireshark-gtk2所在目錄下的工程文件,這樣的工程文件有好幾個,隨便打開一個,其他的幾個就會自動添加進來,因為所有的工程文件都在一個解決方案中,如下圖所示:



???因為只分析tshark部分的代碼,所以可以把它之外的工程全部刪除,然后在tshark工程源文件中有一個tshark.c的文件,在里面找到main()函數,這就是程序的入口,這時就可以下斷點跟蹤調試了。

???今天先寫到此,明天再附上詳細的分析報告。


wireshark源代碼分析報告之二

一、源代碼結構

在wireshark源代碼根目錄下,可以看到以下子目錄:

1)物理結構


???其中,epan文件夾負責所有網絡協議識別工作,plugins里面存放了wireshark所有插件,gtk文件夾里面是wireshark的界面部分代碼,其余文件夾沒有單獨研究。

2)邏輯結構

???下圖給出了Ethereal功能模塊:

??a)?GTK1/2

??????處理用戶的輸入輸出,源碼在gtk目錄

???b)?Core

??????將其他模塊連接在一起,源碼在根目錄

??c)?Epan

??????Ethereal?Packetage?Analyzing,包分析引擎,源碼在epan目錄

?l?Protocol-Tree:保存數據包的協議信息

?l?Dissectors:在epan/dissector目錄下,各種協議解碼器

?l?Plugins:一些協議解碼器以插件形式實現,源碼在plugins目錄

?l?Display-Filters:顯示過濾引擎,源碼在epan/dfilter目錄

??d)?Capture

??捕包引擎

?

??e)?Wiretap

??????從文件中讀取數據包,支持多種文件格式,源碼在wiretap目錄



二、Tshark協議解析模塊

主要處理流程如下所示:

第一步:?

cf_status_t?cf_open(capture_file?*cf,?const?char?*fname,?gboolean?is_tempfile,?int?*err)

????? 該函數首先調用wtap*?wtap_open_offline?(const?char?*filename,?int?*err,?char?**err_info,gboolean?do_random)?函數,獲得一個wtap?struct

wtap結構體的定義在wiretap目錄下的Wtap-int.h

struct wtap {
?? ?FILE_T?? ??? ??? ?fh;
?? ?FILE_T?? ??? ??? ?random_fh;??? /* Secondary FILE_T for random access */
?? ?int?? ??? ??? ?file_type;
?? ?guint?? ??? ??? ?snapshot_length;
?? ?struct Buffer?? ??? ?*frame_buffer;
?? ?struct wtap_pkthdr?? ?phdr;
?? ?union wtap_pseudo_header pseudo_header;

?? ?gint64?? ??? ??? ?data_offset;
?? ?void?? ??? ??? ?*priv;

?? ?subtype_read_func?? ?subtype_read;
?? ?subtype_seek_read_func?? ?subtype_seek_read;
?? ?void?? ??? ??? ?(*subtype_sequential_close)(struct wtap*);
?? ?void?? ??? ??? ?(*subtype_close)(struct wtap*);
?? ?int?? ??? ??? ?file_encap;?? ?/* per-file, for those file formats that have per-file encapsulation types */
?? ?int?? ??? ??? ?tsprecision;?? ?/* timestamp precision of the lower 32bits * e.g. WTAP_FILE_TSPREC_USEC */

??? wtap_new_ipv4_callback_t add_new_ipv4;
?? ?wtap_new_ipv6_callback_t add_new_ipv6;
?? ?GPtrArray *fast_seek;
};

a)?wtap_open_offline()?函數的處理流程:

  • 調用int?libpcap_open(wtap?*wth,?int?*err,?gchar?**err_info)函數讀取給定pcap文件的文件頭信息,總共28個字節,如下所示:

?文件頭結構體
?sturct?pcap_file_header
?{
??????DWORD???????????magic;//4個字節
??????WORD???????????version_major;//主版本號,通常為2
??????WORD???????????version_minor;//副版本號,通常為4
??????DWORD???????????thiszone;
??????DWORD???????????sigfigs;
??????DWORD???????????snaplen;
??????DWORD???????????linktype;
?}?

libpcap_open()?函數首先讀取magic信息,如果文件沒有被修改,則繼續讀取文件頭的后續信息。讀取整個文件頭信息后,判斷該信息是否合法,如果合法,再嘗試讀取給定pcap文件的前2個數據包的包頭記錄,這個工作通過調用static?libpcap_try_t?libpcap_try(wtap?*wth,?int?*err)函數完成。

libpcap_try()函數首先調用libpcap_read_header()函數讀取第一個數據包的數據包頭,該數據包頭的結構如下所示:

struct?pcap_pkthdr
{
struct?tim?????????ts;
??????DWORD??????????????caplen;//所捕獲數據包保存在pcap文件中的實際長度,以字節為單位。
??????DWORD??????????????len;//所捕獲的數據包的真實長度。
}
?
struct?tim
{
DWORD???????GMTtime;//捕獲數據包的時間,從格林尼治時間的1970年1月1日00:00:00到抓包時經過的秒數。
DWORD???????microTime;//抓取數據包時的微秒值。
}?

該數據包頭總共16個字節。然后再調用file_seek()(該函數主要功能就是實現文件定位)函數定位到第一個數據包之后,即24字節的文件頭+16字節的數據包頭+caplen字節的第一個數據包的數據部分長度。如果file_seek()操作正確,即不返回-1,則libpcap_try()函數再次調用libpcap_read_header()函數,讀取第二個數據包的包頭信息。如果讀取正確,則libpcap_try()函數返回THIS_FORMAT,表示pcap文件格式正確。

這時libpcap_open()調用file_seek()定位到給定pcap文件的文件頭之后,也就是24字節處,并返回1,表示操作成功。

?

b)wtap_open_offline()函數為wtapframe_buffer結構體的buffer部分分配最大空間1500字節,然后返回給定pcap文件的wtap信息。

?

c)當wtap_open_offline()函數正確返回wtap信息后,cf_open()函數調用cleanup_dissection()函數清空接下來在協議解析工作中需要用到的數據結構。

  • cleanup_dissection()的清空工作包括:

??????????1) conversation(epan_conversation_cleanup());

??????????2) circuits(epan_circuit_cleanup());

??????????3) protocol-specific?variables(g_slist_foreach(init_routines,?&call_init_routine,?NULL));

??????????4) stream-handling?tables(stream_cleanup());

??????????5) expert?infos(expert_cleanup())。

  • cleanup_dissection()返回后,cf_open()函數調用init_dissection()函數初始化后續解析工作中要用到的所有數據。init_dissection()的初始化工作基本上與cleanup_dissection()清空的內容一致。
  • 這些工作完成后,設置capture_file信息并返回到main()函數。

?

2.?設置時間精度

?

3.?static?int?load_cap_file(capture_file?*cf,?char?*save_file,?int?out_file_type,?gboolean?out_file_name_res,?int?max_packet_count,?gint64?max_byte_count)函數加載給定的pcap文件。

load_cap_file()函數完成的具體工作如下:

a)?如果save_file(保存捕獲的數據包信息)參數不為空,則調用wtap_dump_open()函數獲取wtap_dump結構體。

b)?調用gboolean?wtap_read(wtap?*wth,?int?*err,?gchar?**err_info,?gint64?*data_offset)函數讀取給定pcap文件數據。

c)?調用wtap結構中的subtype_read指向的函數,即libpcap_read()函數,讀取下一個數據包數據。這部分的處理流程類似于第一階段的cf_open()中的處理方式,也就是libpcap_read()函數調用libpcap_read_header()函數讀取下一個數據包16個字節的包頭部分,具體讀取16字節包頭的工作由libpcap_read_header()函數調用file_read()完成。

d)?如果libpcap_read_header()操作正確,成功返回讀取的數據包字節數,則libpcap_read()函數調整文件指針偏移量,然后調用pcap_process_pseudo_header()函數處理該數據包的pseudo_header信息,主要是確定FCS的長度。(pseudo翻譯成"虛假的,假冒的",可能是有些數據包有些假冒包頭吧,不是很了解!)然后返回pseudo_header的長度。

e)?Libpcap_reader()函數根據返回的pseudo_header長度,調整數據包的實際長度,以及文件的偏移量,具體操作是:

? ?

??????????????orig_size?-=?phdr_len;//phdr_len?is?the?length?of?pseudo_header.

??????????????packet_size?-=?phdr_len;

??????????????wth->data_offset?+=?phdr_len;

f)?Libpcap_read()函數調用buffer_assure_space()函數確保wtap結構中的frame_buffer中分配的空間足夠容納正在讀取的數據包的大小,如果不夠,則需要把frame_buffer中已經用掉的空間中存放的內容移到frame_buffer的前面,然后在分配1024個字節給frame_buffer,并返回。

g)?Libpcap_read()函數調用libpcap_read_rec_data()函數讀取改數據包的數據部分,具體的讀取工作同樣由file_read()函數完成。

h)?調整文件偏移量,更新timestamp,調用pcap_read_post_process()函數,根據wtap_encap值,確定pseudo_headereth.fcs_len的大小。

i)?Libpcap_read()工作完成,返回到wtap_read(),如果libpcap_read()返回truewtap_read()也返回true

j)?調用static?gboolean?process_packet(capture_file?*cf,?gint64?offset,?const?struct?wtap_pkthdr?*whdr,?union?wtap_pseudo_header?*pseudo_header,?const?guchar?*pd,?gboolean?filtering_tap_listeners,?guint?tap_flags)函數處理前面讀取的數據包內容。具體操作如下:

i.?Process_packet()函數調用frame_data_init()函數初始化該數據包的幀數據結構,包括記錄數據包頭信息等。如果需要解析數據包,在判斷是否需要創建協議樹(打印協議詳細信息),接著調用epan_dissect_t*?epan_dissect_init(epan_dissect_t?*edt,?const?gboolean?create_proto_tree,?const?gboolean?proto_tree_visible)函數完成解析前的初始化工作。在epan_dissect_init()函數中,如果create_proto_tree為真,就調用protp_tree_create_root()函數創建協議樹的根節點,并賦值為edt->tree,并且,調用proto_tree_set_visible()設置該協議樹的可見性為proto_tree_visible參數的值。如果create_proto_tree為假,則edt->tree=NULL;返回edt。至此,epan_dissect_init()的工作完成

ii.?接著,判斷是否設置有讀過濾器,即capture_file結構體的rfnode是否為空。如果不為空,就調用epan_dissect_prime_dfilter(&edt,?cf->rfnode)進行處理(具體處理過程還沒跟蹤調試!)。

iii.?調用void?col_custom_prime_edt(epan_dissect_t?*edt,?column_info?*cinfo)函數(這個函數具體任務不確定)。如果沒有用戶自定義的打印內容,則直接返回;否則要根據用戶設定,進行一些操作。

iv.?調用void?tap_queue_init(epan_dissect_t?*edt)函數初始化tap?queue

v.?調用frame_data_set_before_dissect()函數進行解析前的幀數據設置操作。

具體內容包括:

1)設置第一個包和前一個包的時間戳。如果first_ts未設置,則表示當前的包是第一個數據包,則把first_ts設為第一個數據包的時間;如果prev_cap_ts未設置,也表明當前的數據包是第一個數據包,則也把它設為第一個包的時間,即frame_data結構體的abs_ts屬性。

2)計算當前數據包接收時間與第一個數據包接收時間之差。

3)計算前一個數據包已經被打印的數據包的接收時間與當前數據包的接收時間之差。如果前一個被打印的數據包的接收時間沒有設置,則表示在當前數據包之前,還沒有數據包被打印。這個時候,就把前一個被打印數據包的接收時間設為0;否則計算這個差值。

4)計算前一個數據包的捕捉時間與當前數據包的捕捉時間之差,并保存到frame_datedel_cap_ts屬性中。

5)以上4步完成之后,把前一個數據包的捕捉時間設為當前數據包的捕捉時間,?返回到process_packet()

vi.?調用void?epan_dissect_run(epan_dissect_t?*edt,?void*?pseudo_header,?const?guint8*?data,?frame_data?*fd,?column_info?*cinfo)函數開始真正的解析工作。該函數的處理過程大致如下所示:

a)?調用ep_free_all()函數釋放前一個數據包中的解析工作中分配的所有內存。

b)?調用void?dissect_packet(epan_dissect_t?*edt,?union?wtap_pseudo_header?*pseudo_header,?const?guchar?*pd,?frame_data?*fd,?column_info?*cinfo)函數進行解析。

具體操作為:

1)如果column_info不為空,則調用col_init(column_info?*)?函數初始化該結構體。

2)設置edt->pi的值。如下所示:

edt->pi.current_proto?=?"<Missing?Protocol?Name>";

??????????????????????????????????edt->pi.cinfo?=?cinfo;

??????????????????????????????????edt->pi.fd?=?fd;

??????????????????????????????????edt->pi.pseudo_header?=?pseudo_header;

??????????????????????????????????edt->pi.dl_src.type?=?AT_NONE;

??????????????????????????????????edt->pi.dl_dst.type?=?AT_NONE;

??????????????????????????????????edt->pi.net_src.type?=?AT_NONE;

??????????????????????????????????edt->pi.net_dst.type?=?AT_NONE;

??????????????????????????????????edt->pi.src.type?=?AT_NONE;

??????????????????????????????????edt->pi.dst.type?=?AT_NONE;

??????????????????????????????????edt->pi.ctype?=?CT_NONE;

???????????????????????????????????edt->pi.noreassembly_reason?=?"";

??????????????????????????????????edt->pi.ptype?=?PT_NONE;

??????????????????????????????????edt->pi.p2p_dir?=?P2P_DIR_UNKNOWN;

??????????????????????????????????edt->pi.dcetransporttype?=?-1;

???????????????????????????????????edt->pi.annex_a_used?=?MTP2_ANNEX_A_USED_UNKNOWN;

??????????????????????????????????edt->pi.dcerpc_procedure_name="";

??????????????????????????????????edt->pi.link_dir?=?LINK_DIR_UNKNOWN;

3)調用tvbuff_t*?tvb_new_real_data(const?guint8*?data,?const?guint?length,?const?gint?reported_length),根據數據包長度,分配一個tvbuff_t的數據結構空間,并調用tvb_set_real_data_no_exceptions(tvb,?data,?length,?reported_length)函數,為剛申請的tvbuff_t空間賦值,然后返回其指針。

4)調用void?add_new_data_source(packet_info?*pinfo,?tvbuff_t?*tvb,?const?char?*name)函數,申請一片data_source結構的空間,并把步驟3)中得到的tvbuff_t指針賦給data_sourcetvb屬性,最后把這個data_source空間的指針添加到data_source結構體的列表中。

5)調用int?call_dissector(dissector_handle_t?handle,?tvbuff_t?*tvb,packet_info?*pinfo,?proto_tree?*tree)函數解析當前數據包的數據。該函數首先根據給定的handleframe_handle)進行解析,如果失敗,再利用data_handle進行解析。不管是用frame_handle還是用data_handle,都是通過調用static?int?call_dissector_work?(dissector_handle_t?handle,?tvbuff_t?*tvb,?packet_info?*pinfo_arg,?proto_tree?*tree,?gboolean?add_proto_name)函數完成(該函數又調用call_dissector_through_handle()函數完成)。

vii.?調用tap_push_tapped_queue(&edt)函數(該函數具體作用不清楚!)。

viii.?如果cf->rfcode不為空,則調用dfilter_applu_edt(cf->rfcode,?&edt)讀過濾函數(具體操作還未跟蹤調試!)。

ix.?調用void?frame_data_set_after_dissect(frame_data?*fdata,?guint32?*cum_bytes,?nstime_t?*prev_dis_ts)函數為解析后的幀數據進行必要的設置,包括記錄總的數據包字節數,以及設置上一個包的顯示時間prev_dis_ts為當前解析包的時間。

x.?調用static?gboolean?print_packet(capture_file?*cf,?epan_dissect_t?*edt)函數打印剛才被解析的數據包信息。Print_packet()函數的處理過程大致為:

a)?判斷是否需要打印協議樹中的信息:如果verbose為真,則表示需要打印協議樹種的內容(這部分的處理流程還未具體調試!);否則調用epan_dissect_fill_in_columns()函數填充column信息(主要由col_fill_in_frame_data()函數完成具體的填充任務)。

b)?根據output_action的值,打印剛才解析的數據包信息。調用print_columns(capture_file*?cf)函數打印列信息。如果需要打印十六進制信息,則再調用print_hex_data(print_stream,edt)打印十六進制信息。(打印列信息,就只需要capture_file,打印十六進制信息則需要edt,考慮下次調試時,讓其打印十六進制信息,看在不創建協議樹的情況下,這兩種打印有什么不同,為什么需要的參數不一樣。到目前為止,個人感覺capture_file中記錄的信息要比edt中多很多,而且capture_file結構體中有一個edt屬性,這樣的定義感覺有些冗余!

xi.?如果do_dissection為真,表示已經完成解析工作,這時調用epan_dissect_cleanup(&edt)完成下列清空工作:

a)?調用free_data_sources(&edt->pi)?清空data?source列表;

b)?調用tvb_free_chain(edt->tvb)?清空tvb創建的所有內存空間;

c)?如果edt->tree不為空,再調用proto_tree_free(edt->tree)釋放解析過程中創建的協議樹空間。

xii.?Epan_dissect_cleanup()函數返回后,再調用frame_data_cleanup(frame_data*)函數完成下列清空工作:

a)?如果fdata->pfd不為空,則釋放該列表;

b)?把fdata->pfd置為NULL,并返回。

k)process_packet()函數返回到load_cap_file()函數后,如果wtap_dumper*?pdp不為空,則調用wtap_dump()函數。Wtap_dump()函數則調用pcapng_dump()(該函數的主要處理過程不清楚)。

l)剛才讀取的數據包已經解析并打印完成,這時跳轉到步驟b),讀取下一個數據包數據,直到到達給定pcap文件的文件尾。

?


——————————————————————————————————下面是另一個作者分析的。

原文百度文庫:

http://wenku.baidu.com/view/5adbe902b52acfc789ebc91a.html

1.?wireshark流程分析

1)?初始化

Wireshark的初始化包括一些全局變量的初始化、協議分析引擎的初始化和Gtk相關初始化,顯示Ethereal主窗口,等待用戶進一步操作。重點就是Epan模塊的初始化。

Epan初始化:

n?tvbuff初始化:全局變量tvbuff_mem_chunk指向用memchunk分配的固定大小的空閑內存塊,每個內存塊是tvbuff_t結構,從空閑內存塊中取出后,用來保存原始數據包。

n?協議初始化:

u?全局變量:

l?proto_names?

l?proto_short_names?

l?proto_filter_names?

以上三個全局變量主要用來判斷新注冊的協議名是否重復,如果重復,給出提示信息,在協議解析過程中并沒有使用。

u?協議注冊:

l?注冊協議:將三個參數分別注冊給proto_names、proto_short_names、proto_filter_names三個全局變量中,

l?注冊字段,需要在wireshark協議樹顯示的報文內容字段。

l?協議解析表

u?Handoff注冊

l?將協議與父協議節點關聯起來

n?Packet(包)初始化

u?全局變量:

l?frame_handle:協議解析從frame開始,層層解析,直到所有的協議都解析完為止。frame_handle保存了frame協議的handle。

l?data_handle:有的協議無法從frame開始,那么就從data開始。原理同frame。?

n?讀配置文件preference

n?讀capture?filter和display?filter文件,分別保存在全局變量capture_filter和display_filter中。

n?讀disabled?protocols文件,保存全局變量global_disabled_protos和disabled_protos中

n?初始化全局變量cfile

u?Cfile是個重要的變量,數據類型為capture?file,它保存了數據包的所有信息,

n?取得命令行啟動時,參數列表,并進行相應的處理

2)?處理流程

Wireshark初始化完成以后進入實際處理階段,主程序創建抓包進程,捕包進程和主程序是通過PIPE進行傳遞數據的,主程序把抓取的數據寫入臨時文件,通過函數add_packet_to_packet_list將數據包加入包列表。處理時,主程序從列表中選取一個數據包,提取該數據包中的數據填寫在數據結構中,最后調用協議解析函數epan_dissect_run進行處理,從epan_dissect_run開始,是實際的協議解析過程,

下面以HTTP協議報文為例,流程如下:

a)?解析frame層

調用函數dissect_frame對frame層進行解析,并在協議樹上填充相應字段信息。函數最后會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這里函數dissector_try_port根據pinfo->fd->lnk_t查找對應的上層協議處理函數,pinfo->fd->lnk_t值為1,上層封裝協議為以太網協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置為dissect_eth_maybefcs,至此,frame層解析結束。

a)?解析以太網層

函數call_dissector_work根據dissector_handle調用frame上層協議解析函數dissect_eth_maybefcs對以太網層進行解析,并在協議樹上填充相應字段,包括目的MAC地址和以太網上層協議類型等信息。函數最后會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這里函數dissector_try_port根據etype查找對應的上層協議處理函數,以太網字段etype為0800的報文是ip報文,上層封裝協議為IP協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置為dissect_ip,至此,以太網層解析結束。

b)?解析IP層

函數call_dissector_work根據dissector_handle調用以太網上層協議解析函數dissect_ip對以太網層進行解析,并在協議樹上填充相應字段,包括版本號,源地址,目的地址等信息。函數最后會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這里函數dissector_try_port根據nxt?(nxt?=?iph->ip_p)查找對應的上層協議處理函數,以太網字段nxt為06的報文是TCP報文,上層封裝協議為TCP協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置為dissect_tcp,至此,IP層解析結束。

c)?解析TCP層

函數call_dissector_work根據dissector_handle調用以太網上層協議解析函數dissect_tcp對TCP層進行解析,包括對TCP頭的解析和選項字段的解析,并在協議樹上填充相應字段,包括源端口,目的端口,標志位等信息。函數最后會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這里函數dissector_try_port根據port查找對應的上層協議處理函數,將源端口和目的端口分別賦值給low_port和high_port,根據low_port和high_port分別匹配上層協議解析函數,port為80的報文是HTTP報文,上層封裝協議為HTTP協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置為dissect_http,至此,TCP層解析結束。

d)?解析HTTP層

至此wireshark進入應用層協議檢測階段,wireshark解析dissect_http函數中注冊的字段,并提取相應的字段值添加到協議樹中,應用層的具體解析流程將在下面介紹。HTTP協議具體函數調用過程參見:

重要的數據結構

struct?_epan_dissect_t?{

tvbuff_t *tvb;//用來保存原始數據包

proto_tree *tree;//協議樹結構

packet_info pi;//?包括各種關于數據包和協議顯示的相關信息

};

/**?Each?proto_tree,?proto_item?is?one?of?these.?*/

typedef?struct?_proto_node?{

struct?_proto_node?*first_child;//協議樹節點的第一個子節點指針

struct?_proto_node?*last_child;?//協議樹節點的最后一個子節點指針

struct?_proto_node?*next;?//協議樹節點的下一個節點指針

struct?_proto_node?*parent;//父節點指針

field_info??*finfo;//保存當前協議要顯示的地段

tree_data_t?*tree_data;//協議樹信息

}?proto_node;

typedef?struct?_packet_info?{

??const?char?*current_proto; //當前正在解析的協議名稱

??column_info?*cinfo; //wireshark顯示的信息

??frame_data?*fd;//現在分析的原始數據指針

??union?wtap_pseudo_header?*pseudo_header;//frame類型信息

??GSList?*data_src; /*frame層信息?*/

??address?dl_src; /*?源MAC?*/

??address?dl_dst; /*目的MAC?*/

??address?net_src; /*?源IP?*/

??address?net_dst; /*目的IP?*/

??address?src; /*源IP?*/

??address?dst; /*目的IP?*/

??guint32?ethertype; /*以太網類型字段*/

??guint32?ipproto; /*?IP協議類型*/

??guint32?ipxptype; /*?IPX?包類型?*/

??guint32?mpls_label; /*?MPLS包標簽*/

??circuit_type?ctype;

??guint32?circuit_id; /*環路ID?*/

??const?char?*noreassembly_reason;??/*?重組失敗原因*/

??gboolean?fragmented; /*為真表示未分片*/

??gboolean?in_error_pkt; /*錯誤包標志*/

??port_type?ptype; /*端口類型?*/

??guint32?srcport; /*源端口*/

??guint32?destport; /*目的端口*/

??guint32?match_port;???????????/*進行解析函數匹配時的匹配端口*/

??const?char?*match_string; /*調用子解析引擎時匹配的協議字段指針*/

??guint16?can_desegment; /*?能否分段標志*/

??guint16?saved_can_desegment;

??int?desegment_offset; /*分段大小*/

#define?DESEGMENT_ONE_MORE_SEGMENT?0x0fffffff

#define?DESEGMENT_UNTIL_FIN????????0x0ffffffe

??guint32?desegment_len;

??guint16?want_pdu_tracking;

??guint32?bytes_until_next_pdu;

??int?????iplen;????????????????/*IP包總長*/

??int?????iphdrlen;?????????????/*IP頭長度*/

??int ??p2p_dir;??????????????

??guint16?oxid;?????????????????/*?next?2?fields?reqd?to?identify?fibre?*/

??guint16?rxid;?????????????????/*?channel?conversations?*/

??guint8??r_ctl;????????????????/*?R_CTL?field?in?Fibre?Channel?Protocol?*/

??guint8??sof_eof;?????????????

??guint16?src_idx;??????????????/*?Source?port?index?(Cisco?MDS-specific)?*/

??guint16?dst_idx;??????????????/*?Dest?port?index?(Cisco?MDS-specific)?*/

??guint16?vsan;?????????????????/*?Fibre?channel/Cisco?MDS-specific?*/

??/*?Extra?data?for?DCERPC?handling?and?tracking?of?context?ids?*/

??guint16?dcectxid;?????????????/*?Context?ID?(DCERPC-specific)?*/

??int?????dcetransporttype;

??guint16?dcetransportsalt; /*?fid:?if?transporttype==DCE_CN_TRANSPORT_SMBPIPE?*/

#define?DECRYPT_GSSAPI_NORMAL 1

#define?DECRYPT_GSSAPI_DCE 2

??guint16?decrypt_gssapi_tvb;

??tvbuff_t?*gssapi_wrap_tvb;

??tvbuff_t?*gssapi_encrypted_tvb;

??tvbuff_t?*gssapi_decrypted_tvb;

??gboolean?gssapi_data_encrypted;

??guint32?ppid;??/*?SCTP?PPI?of?current?DATA?chunk?*/

??guint32?ppids[MAX_NUMBER_OF_PPIDS];?/*?The?first?NUMBER_OF_PPIDS?PPIDS?which?are?present?*?in?the?SCTP?packet*/

??void????*private_data; /*?pointer?to?data?passed?from?one?dissector?to?another?*/

??/*?TODO:?Use?emem_strbuf_t?instead?*/

??GString?*layer_names;? /*?layers?of?each?protocol?*/

??guint16?link_number;

??guint8??annex_a_used;

??guint16?profinet_type;? /*?the?type?of?PROFINET?packet?(0:?not?a?PROFINET?packet)?*/

??void?*profinet_conv;? ???/*?the?PROFINET?conversation?data?(NULL:?not?a?PROFINET?packet)?*/

??void?*usb_conv_info;

??void?*tcp_tree; /*?proto_tree?for?the?tcp?layer?*/

??const?char?*dcerpc_procedure_name; /*?Used?by?PIDL?to?store?the?name?of?the?current?dcerpc?procedure?*/

??struct?_sccp_msg_info_t*?sccp_info;

??guint16?clnp_srcref;??????/*?clnp/cotp?source?reference?(can't?use?srcport,?this?would?confuse?tpkt)?*/

??guint16?clnp_dstref;??????/*?clnp/cotp?destination?reference?(can't?use?dstport,?this?would?confuse?tpkt)?*/

??guint16?zbee_cluster_id;??/*?ZigBee?cluster?ID,?an?application-specific?message?identifier?that

?????????????????????????????*?happens?to?be?included?in?the?transport?(APS)?layer?header.

?????????????????????????????*/

??guint8?zbee_stack_vers;?????int?link_dir; /*?3GPP?messages?are?sometime?different?UP?link(UL)?or?Downlink(DL)*/

}?packet_info;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385053.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385053.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385053.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言寫數據庫(三)

遇到的問題以及解決思路方法 1.外部導入數據庫文件 進入mysql&#xff0c;創建數據庫sh_robot source /home/exbot/sh_robot.sql 查看數據庫編碼格式 show variables like “%char%”; 2.數據庫插入操作 進入相關數據庫&#xff1a;use 數據庫名&#xff1b; 查詢存在該表是否存…

Makefile(一)

在一個文件夾中建一個c文件 //main.c #include<stdio.h> int main() {printf("version 1.0");return 0; } 在當前目錄下編寫makefile文件 //makefile: test : main.o //一種依賴關系聲明&#xff0c;生成test可執行程序需要以來main.o文件gcc -o test main.…

Defunct進程 僵尸進程

在測試基于 DirectFBGstreamer 的視頻聯播系統的一個 Demo 的時候&#xff0c;其中大量使用 system 調用的語句&#xff0c;例如在 menu 代碼中的 system("./play") &#xff0c;而且多次執行&#xff0c;這種情況下&#xff0c;在 ps -ef 列表中出現了大量的 defunc…

make文件基礎用法

參照&#xff1a;https://www.jianshu.com/p/0b2a7cb9a469 創建工作目錄&#xff0c;包含一下文件 main.cperson.cb.hc.h/*** c.h ***/ //this is c.h /*** b.h ***/ //this is b.h /*** main.c ***/ #include<stdio.h> //#include"a1.h" //#include"b.h&…

一個Linux下C線程池的實現(轉)

1.線程池基本原理 在傳統服務器結構中, 常是 有一個總的 監聽線程監聽有沒有新的用戶連接服務器, 每當有一個新的 用戶進入, 服務器就開啟一個新的線程用戶處理這 個用戶的數據包。這個線程只服務于這個用戶 , 當 用戶與服務器端關閉連接以后, 服務器端銷毀這個線程。然而頻繁地…

二維數組作為函數參數

#include<stdio.h> //#include<> //二位數組作為函數參數時&#xff0c;可以不指定第一個下標 void print_buf(int (*p)[3],int a,int b) //void print_buf(int p[][3],int a,int b) {int i,j;for(i 0 ; i < a; i){for(j 0; j < b; j){printf("p[%…

mystrcat

#include<stdio.h> //如果一個數組做為函數的形參傳遞&#xff0c;那么數組可以在被調用的函數中修改 //有時候不希望這個事發生&#xff0c;所以對形參采用const參數 //size_t strlen(const char *s); //strcpy(char* s1,const char* s2); void mystrcat(char *s1,cons…

關于非阻塞的recv的時候返回的處理

注意recv&#xff08;&#xff09;如果讀到數據為0&#xff0c;那么就表示文件結束了&#xff0c;如果在讀的過程中遇到了中斷那么會返回-1&#xff0c;同時置errno為EINTR。 因此判斷recv的條件&#xff1a; 如果read返回<0 如果0 表示文件結束&…

帶參程序

windows環境 #include<stdio.h>int main(int argc, char *argv[]) {printf("argc %d\n", argc);for (int i 0; i < argc; i){printf("argv[%d] %s\n",i, argv[i]);}system("pause");return 0; } windows環境下&#xff0c;帶參函數…

Ubuntu安裝mysql步驟

1.打開終端&#xff0c;輸入&#xff1a; sudo apt-get updata 輸入root用戶密碼 2.更新完畢后&#xff0c;輸入 sudo apt-get install mysql-server ubuntu14.04安裝中間會讓你設置密碼&#xff0c;輸入密碼后點擊確認(mysql123) 3.安裝結束后&#xff0c;查看端口號是否開啟 …

Pthread創建線程后必須使用join或detach釋放線程資源

這兩天在看Pthread 資料的時候&#xff0c;無意中看到這樣一句話(man pthread_detach): Either pthread_join(3) or pthread_detach() should be called for each thread that an application creates, so that system resources for the thread can be released. …

二維數組求平均值(指針的使用)

#include<stdio.h>int main() {int buf[3][5] {{1,2,3,4,5},{4,5,6,7,8},{7,8,9,10,11}};int i;int j;//求行平均值 for(i 0; i < 3; i){int sum 0;for(j 0; j < 5; j){sum (*(*(buf i) j));}printf("sum %d\n",sum/5);}//求列平均值for(i 0; i …

linux終端關閉時為什么會導致在其上啟動的進程退出?

現象 經常在linux下開發的人應該都有這樣的經驗&#xff0c;就是在終端上啟動的程序&#xff0c;在關閉終端時&#xff0c;這個程序的進程也被一起關閉了。看下面這個程序&#xff0c;為了使進程永遠運行&#xff0c;在輸出helloworld后&#xff0c;循環調用sleep&#xff1a; …

二維數組做函數參數傳遞

#include<stdio.h> //#include<> //二位數組作為函數參數時&#xff0c;可以不指定第一個下標 void print_buf(int (*p)[3],int a,int b) //void print_buf(int p[][3],int a,int b) {int i,j;for(i 0 ; i < a; i){for(j 0; j < b; j){printf("p[%…

libevent源碼深度剖析

第一章 1&#xff0c;前言 Libevent是一個輕量級的開源高性能網絡庫&#xff0c;使用者眾多&#xff0c;研究者更甚&#xff0c;相關文章也不少。寫這一系列文章的用意在于&#xff0c;一則分享心得&#xff1b;二則對libevent代碼和設計思想做系統的、更深層次的分析&#xff…

函數返回指針類型(strchr函數)

#include<stdio.h> #include<string.h> char *mystrchr(char *s,char c) {while(*s){if(*s c){return s;}s;}return NULL; }int main() {char str[100] "hello world";//char* s strchr(str,a);char *s mystrchr(str,e);//返回ello world字符串 prin…

函數與指針

#include<stdio.h>int add(int a,int b) {return ab; }int main() {void *p(int,char *); //聲明了一個函數 &#xff0c;函數名為p&#xff0c;函數返回值為void*,函數的 void (*p)(int,char *);//定義了一個指向參數為int和char*返回值為void的函數指針//定義一個參數為…

使用指針在函數中交換數值

#include<stdio.h>void swap(int* a,int *b) {/*int temp *a;*a * b;*b temp;*/*a *b;*b *a - *b;*a *a - *b; }int main() {int a 10;int b 20;swap(&a,&b);printf("a %d,b %d\n",a,b);} 轉載于:https://www.cnblogs.com/wanghao-boke/p/1…

linux C 基于鏈表鏈的定時器

源碼如下&#xff1a;util_timer.h#ifndef LST_TIMER#define LST_TIMER#include <time.h>#include <sys/time.h>#include <stdlib.h>#include <signal.h>#define BUFFER_SIZE 64struct util_timer;/*struct client_data{sockaddr_in address;int sockf…

libevent學習筆記 一、基礎知識

一、libevent是什么libevent是一個輕量級的開源的高性能的事件觸發的網絡庫&#xff0c;適用于windows、linux、bsd等多種平臺&#xff0c;內部使用select、epoll、kqueue等系統調用管理事件機制。它被眾多的開源項目使用&#xff0c;例如大名鼎鼎的memcached等。特點&#xff…