• ntopng源码分析


    参数初始化以及ntop主流程启动


    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支持


     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
    
    
  • 相关阅读:
    matplotlib实战
    matplotlib常用操作2
    matplotlib 常用操作
    pandas总结
    朴素贝叶斯算法python实现
    什么叫“回归”——“回归”名词的由来&&回归与拟合、分类的区别 && 回归分析
    Latex常用整理
    准备尝试openFrameworks
    常用工具库总结
    K-Means和K Nearest Neighbor
  • 原文地址:https://www.cnblogs.com/danxi/p/5799518.html
Copyright © 2020-2023  润新知