ndpi工作流程

2021-07-08 12:08:46 字數 3607 閱讀 7334

第一步是程式的初始化,呼叫setupdetection()函式,這裡所做的工作也比較多,打算新寫一篇文章來專門講述此函式作用。

接下來會開啟執行緒呼叫libpcap庫函式對通過電腦網絡卡的資料報進行抓取,或者讀取傳入的.pcap檔案(具體的 如何執行等簡單操作可以參考官方給出的文件,在doc資料夾下)

接下來對每乙個資料報(這裡需要明確兩個概念,資料報(packet)和資料流(flow),乙個資料流中可能會有很多個資料報,就像我們申請乙個網頁請求,由於頁面資訊很大,所以會分成很多個資料報來傳輸,但這些資料報同屬於乙個資料流),首先對其資料鏈路層和ip層進行拆包分析pcap_packet_callback()函式,判斷是否為基於ip協議等,並獲得其源目的ip、協議型別等。

在接下來呼叫packet_processing()函式,進行傳輸層分析。在進行傳輸層分析時呼叫了get_ndpi_flow()函式,該函式返回ndpi_flow這個結構體(這裡需要注意ndpi_flow和ndpi_flow_struct兩個結構體的區別)。在get_ndpi_flow()函式中獲取傳輸層的資訊如源目的埠等資訊。然後根據(源目的ip、源目的埠、協議型別(tcp\udp))這五個元素計算出idx。

idx = (vlan_id + lower_ip + upper_ip + iph->protocol + lower_port + upper_port) % num_roots;

ret = ndpi_tfind(&flow, &ndpi_thread_info[thread_id].ndpi_flows_root[idx], node_cmp);

這裡就是我剛開始開原始碼時困擾我的地方,開始一直不知道idx的作用,後來發現程式維護了乙個陣列,用來記錄所有的資料流,而idx是用來標識不同的資料流,根據前面解析出資料報的五元組計算idx,然後查詢 ndpi_flows_root這個陣列在索引為idx位置是否已經有了記錄。一般,對於乙個資料流而言,該流的第乙個資料報查詢時ndpi_flows_root[idx]為空,則建立乙個新的ndpi_flow物件並儲存到該位置處;等抓到該資料流的後續資料報時,因為屬於同乙個流(即idx相同),所以ndpi_flows_root[idx]不為空,則直接返回已經有的ndpi_flow即可。至此,我們得到了ndpi_flow這個結構體,這也是get_ndpi_flow()這個函式的意義。

接下來函式會呼叫ndpi_detection_process_packet()這個函式進行應用層分析。這也是應用協議分析的主體函式。注意這個函式傳進的引數是ndpi_flow_struct(下面記為flow),函式首先會對flow->packet即對packet這個結構體進行初始化。因為對於同乙個流flow而言,在該結構體中有些變數在第乙個資料報時已經初始化了,這些變數可能在特定情況下才會發生改變,比如檢測出了協議等;而對每乙個資料報,flow中必須要變的就是flow->packet中的資訊。接下來會呼叫ndpi_connection_tracking()函式,這個函式的主要作用是判斷這個包的『位置』,熟悉tcp協議的人都知道,乙個tcp經過三次握手建立連線bababababa….這裡自行腦補,主要要知道syn,ack,seq,ack_seq四個變數的作用和功能。這個函式在資料報重組等功能中會有很重要的作用。這裡貼出部分**

if(tcph->syn != 0 && tcph->ack == 0 && flow->l4.tcp.seen_syn == 0 && flow->l4.tcp.seen_syn_ack == 0

&& flow->l4.tcp.seen_ack == 0) //第一次

if(tcph->syn != 0 && tcph->ack != 0 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 0

&& flow->l4.tcp.seen_ack == 0) //第二次

if(tcph->syn == 0 && tcph->ack == 1 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 1

&& flow->l4.tcp.seen_ack == 0) //第三次

//上面三句是三次握手相應的判斷語句

if((flow->next_tcp_seq_nr[0] == 0 && flow->next_tcp_seq_nr[1] == 0)

|| (proxy_enabled && (flow->next_tcp_seq_nr[0] == 0 || flow->next_tcp_seq_nr[1] == 0)))

}} else

if(packet->payload_packet_len > 0)

接下來會對ndpi_selection_packet進行設定,這個變數主要記錄每個資料報的下四層資訊。該變數是ndpi_selection_bitmask_protocol_size型別,大概就是乙個10101011這樣的東西,如下面**所示,把這幾個變數進行與或操作得到乙個值,比如110111101中的兩個0就表示不是ipv6和不是tcp。

#define ndpi_selection_bitmask_protocol_size            u_int32_t

#define ndpi_selection_bitmask_protocol_ip (1<<0)

#define ndpi_selection_bitmask_protocol_int_tcp (1<<1)

#define ndpi_selection_bitmask_protocol_int_udp (1<<2)//移位操作

#define ndpi_selection_bitmask_protocol_int_tcp_or_udp (1<<3)

#define ndpi_selection_bitmask_protocol_has_payload (1<<4)

#define ndpi_selection_bitmask_protocol_no_tcp_retransmission (1<<5)

#define ndpi_selection_bitmask_protocol_ipv6 (1<<6)

#define ndpi_selection_bitmask_protocol_ipv4_or_ipv6 (1<<7)

#define ndpi_selection_bitmask_protocol_complete_traffic (1<<8)

在接下來呼叫下面**,這裡的guessed_protocol_id 我還沒有搞明白是做什麼用的,之後用到再看吧

flow->guessed_protocol_id = (int16_t)ndpi_guess_protocol_id(ndpi_struct, protocol,

sport, dport);

flow->protocol_id_already_guessed = 1;

最後,呼叫check_ndpi_flow_func()函式進行具體應用協議的檢測,這裡會根據tcp\udp\二者都不進入不同的介面。這裡的東西也比較多,暫時想著針對http協議型別再寫一篇文章,所以就不詳細敘述了。經過這個函式之後如果仍然沒有檢測出協議型別,那麼就繼續檢測下乙個資料報直到檢測出該資料流的協議型別為止。

Struts工作流程

文章分類 招聘求職 乙個使用者的請求是通actionservlet來處理和 的。那麼,actionservlet如何決定把使用者請求 給哪個action物件呢?這就需要一些描述使用者請求路徑和action衍射關係的配置資訊了。在struts中,這些配置對映資訊都儲存在特定的xml檔案struts c...

zf工作流程

zend controller是使用mvc模式來構建乙個站點的基礎。zend controller體系是乙個輕量的,模組化和可擴充套件的體系。它只提供最核心的必要的部分,允許開發者有很大的自由來靈活地構建自己的站點。使用zend controller的站點,其檔案組織和 結構會比較相似。zend c...

spring MVC 工作流程

1 首先來配置一下dispatcherservlet spring mvc和大部分mvc框架一樣,底層也是依賴servlet api的,所以spring mvc的請求處理也是從乙個servlet開始,這個servlet就是dispatcherservlet.以下是在web.xml中dispatche...