ntopng源碼分析

參數初始化以及ntop主流程啓動web


1 #ifndef WIN32
2   if((argc == 2) && (argv[1][0] != '-'))
3     rc = prefs->loadFromFile(argv[1]);
4   else
5 #endif
//通常啓動ntopng的命令: ntopng /etc/ntopng/ntopng.conf 上面的代碼就是讀取配置文件/etc/ntopng/ntopng.conf裏的配置信息。
1 prefs->registerNetworkInterfaces();
2 
3   if(prefs->get_num_user_specified_interfaces() == 0) {
4     /* We add all interfaces available on this host */
5     prefs->add_default_interfaces();
6   }
//經過配置文件配置的interface信息註冊能夠使用的網卡信息:
//若是沒有配置網卡,ntopng會調用pcap的接口去查找全部可用的網卡,並註冊。

注:ntopng的配置文件跟命令行參數的輸入是同樣的 這種統一的配置方式很是方便,值得借鑑。
 1  // enable all protocols
 2     NDPI_BITMASK_SET_ALL(all);
 3     ndpi_set_protocol_detection_bitmask2(ndpi_struct, &all);
 4    // NetworkInterface類 初始化了協議檢查的全部類型,並提供了報文分析的函數。
 5 
 6    if(iface == NULL) {
 7       try {
 8     iface = new PcapInterface(ifName);
 9       } catch(...) {
10     ntop->getTrace()->traceEvent(TRACE_ERROR, "Unable to create interface %s", ifName);
11     iface = NULL;
12       }
13     }
14    //ntopng 默認使用libpcap來處理網卡抓包,這裏默認使用PcapInterface這個類,PcapInterface繼承了NetworkInterface類。
15     
16    iface->setCPUAffinity(core_id);
17    //若是是多核多網卡的服務器,則須要考慮到性能,設置CPU親和度,保證每一個網卡能有對應的CPU處理
18 
19   ntop->start();
20   //至此,進入抓包解析流程

HTTPServer的初始化端口和lua CGI支持api


 1  ntop->registerHTTPserver(new HTTPserver(prefs->get_http_port(),
 2                       prefs->get_docs_dir(),
 3                       prefs->get_scripts_dir()));
 4   //這裏註冊http服務器,以便後續的web監控使用。
 5 
 6   callbacks.begin_request = handle_lua_request;
 7   httpd_v4 = mg_start(&callbacks, NULL, (const char**)http_options);
 8   //而後調用第三方的http庫,啓用多線程的httpserver。
 9   //callbacks包含了處理http中請求lua腳本的功能函數。
10 
11 來到third-party/mongoose/mongoose.c文件, 函數mg_start:
12   // Start master (listening) thread
13   mg_start_thread(master_thread, ctx);
14 
15   // Start worker threads
16   for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) {
17     if (mg_start_thread(worker_thread, ctx) != 0) {
18       cry(fc(ctx), "Cannot start worker thread: %d", ERRNO);
19     } else {
20       ctx->num_threads++;
21     }
22   }
23   //master_thread負責監聽,並將accept接受的socket緩存到ctx->queue中;
24   //worker_thread負責處理ctx->queue緩存的socket處理http請求。
25 
26   static void prepare_lua_environment(struct mg_connection *conn, lua_State *L)
27   .....
28   // Register "print" function which calls mg_write()
29   lua_pushlightuserdata(L, conn);
30   lua_pushcclosure(L, lsp_mg_print, 1);
31   lua_setglobal(L, "print");
32 
33   // Register mg_read()
34   lua_pushlightuserdata(L, conn);
35   lua_pushcclosure(L, lsp_mg_read, 1);
36   lua_setglobal(L, "read");
37   //上面的代碼註冊了lua腳本使用的print和read函數。
38   //prepare_lua_environment函數使得httpserver支持lua腳本做爲CGI語言。
  //後續就能夠經過lua腳原本回應web客戶端的各類request;
  //lua又經過lua c api的擴展來獲取後面報文分析的結果來填充網頁的請求。

抓包和報文分析主流程緩存


下面的代碼是在src/ntopng.cpp  start函數:
1 for(int i=0; i<num_defined_interfaces; i++) {
2     iface[i]->allocateNetworkStats();
3     iface[i]->startPacketPolling();
4   }
5 //allocateNetworkStats 初始化網絡統計功能
6 //開始抓包
7 //startPacketPolling 注意是一個虛函數,這裏是多態,實際是PcapInterface的startPacketPolling 函數。
下面來到src/PcapInterface.cpp文件:
 1 void PcapInterface::startPacketPolling() { 
 2   pthread_create(&pollLoop, NULL, packetPollLoop, (void*)this);  
 3   pollLoopCreated = true;
 4   NetworkInterface::startPacketPolling();
 5 }
 6 
 7 //startPacketPolling函數建立了一個線程,線程主要處理函數是packetPollLoop。
 8 //static void* packetPollLoop(void* ptr), 就定義在PcapInterface.cpp文件裏。
 9 
10 //packetPollLoop函數開始了報文複製和分析的過程
11     FILE *pcap_list = iface->get_pcap_list();
12     ......
13     hdr->caplen = min_val(hdr->caplen, iface->getMTU());
14     iface->dissectPacket(hdr, pkt, &shaped, &p);

 

//dissectPacket 是NetworkInterface類的成員函數,裏面開始了複雜的報文解析流程。。。
//bool dissectPacket(const struct pcap_pkthdr *h, const u_char *packet, bool *shaped, u_int16_t *ndpiProtocol);
//分析出報文的類型以後,將報文傳給processPacket函數處理和統計
 1 bool processPacket(const struct bpf_timeval *when,
 2              const u_int64_t time,
 3              struct ndpi_ethhdr *eth,
 4              u_int16_t vlan_id,
 5              struct ndpi_iphdr *iph,
 6              struct ndpi_ipv6hdr *ip6,
 7              u_int16_t ipsize, u_int16_t rawsize,
 8              const struct pcap_pkthdr *h,
 9              const u_char *packet,
10              bool *shaped,
11              u_int16_t *ndpiProtocol);
12 
13 inline void incStats(time_t when, u_int16_t eth_proto, u_int16_t ndpi_proto,
14                u_int pkt_len, u_int num_pkts, u_int pkt_overhead) {
15     ethStats.incStats(eth_proto, num_pkts, pkt_len, pkt_overhead);
16     ndpiStats.incStats(ndpi_proto, 0, 0, 1, pkt_len);
17     pktStats.incStats(pkt_len);
18     if(lastSecUpdate == 0) lastSecUpdate = when; else if(lastSecUpdate != when) updateSecondTraffic(when);
19   };
20 //因涉及到pcap抓包,因此有些常量是pcap定義的
21 #define DLT_NULL    0    /* BSD loopback encapsulation */
22 #define DLT_EN10MB    1    /* Ethernet (10Mb) */
23 #define DLT_EN3MB    2    /* Experimental Ethernet (3Mb) */
24 #define DLT_AX25    3    /* Amateur Radio AX.25 */
25 #define DLT_PRONET    4    /* Proteon ProNET Token Ring */
26 #define DLT_CHAOS    5    /* Chaos */
27 #define DLT_IEEE802    6    /* 802.5 Token Ring */
28 #define DLT_ARCNET    7    /* ARCNET, with BSD-style header */
29 #define DLT_SLIP    8    /* Serial Line IP */
30 #define DLT_PPP        9    /* Point-to-point Protocol */
31 #define DLT_FDDI    10    /* FDDI */
32 
33 /*
34  * These are types that are different on some platforms, and that
35  * have been defined by <net/bpf.h> for ages.  We use #ifdefs to
36  * detect the BSDs that define them differently from the traditional
37  * libpcap <net/bpf.h>
38  *
39  * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS,
40  * but I don't know what the right #define is for BSD/OS.
41  */
42 #define DLT_ATM_RFC1483    11    /* LLC-encapsulated ATM */
43 
44 #ifdef __OpenBSD__
45 #define DLT_RAW        14    /* raw IP */
46 #else
47 #define DLT_RAW        12    /* raw IP */
48 #endif
相關文章
相關標籤/搜索