參數初始化以及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