可以通过设置全局变量nids_params.multiproc不为0来在libnids中使用多线程捕获数据包。libnids使用的是glib库的gthread-2.0线程函数(该函数库某些函数已经过时,例如线程创建函数;过时的api:https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html;新版thread接口:https://developer.gnome.org/glib/stable/glib-Threads.html)。
在libnids1.24源文件libnids.c中nids_run会调用pcap_loop函数进行循环捕获数据包的操作;pcap_loop函数的回调函数nids_pcap_heandler在设置了全局变量multiproc时,会将捕获的数据包片段插入到异步捕获队列中(这里的异步队列是glib的接口,用于在不同线程之间通信,https://developer.gnome.org/glib/stable/glib-Asynchronous-Queues.html)
int nids_run()
{
if (!desc) {
strcpy(nids_errbuf, "Libnids not initialized");
return 0;
}
START_CAP_QUEUE_PROCESS_THREAD(); /* threading... */
pcap_loop(desc, -1, (pcap_handler) nids_pcap_handler, 0); //循环捕获数据包
/* FIXME: will this code ever be called? Don't think so - mcree */
STOP_CAP_QUEUE_PROCESS_THREAD();
nids_exit();
return 0;
}
nids_pcap_handler部分代码:
#ifdef HAVE_LIBGTHREAD_2_0
if(nids_params.multiproc) { //如果系统有thread_2_0函数库并设置了使用多线程
/*
* Insert received fragment into the async capture queue.
* We hope that the overhead of memcpy
* will be saturated by the benefits of SMP - mcree
*/
qitem=malloc(sizeof(struct cap_queue_item));
if (qitem && (qitem->data=malloc(hdr->caplen - nids_linkoffset))) {
qitem->caplen=hdr->caplen - nids_linkoffset;
memcpy(qitem->data,data_aligned,qitem->caplen);
g_async_queue_lock(cap_queue); //为异步队列加锁
/* ensure queue does not overflow,如果队列长度大于全局变量queue_limit的限制就说明overflow了*/
if(g_async_queue_length_unlocked(cap_queue) > nids_params.queue_limit) {
/* queue limit reached: drop packet - should we notify user via syslog? */
free(qitem->data); //丢弃数据包数据
free(qitem); //销毁数据包
} else {
/* insert packet to queue */
g_async_queue_push_unlocked(cap_queue,qitem);
}
g_async_queue_unlock(cap_queue); //解锁异步队列
}
} else { /* user requested simple passthru - no threading */
call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset);
}
#else
call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset);
#endif
}
可以看出nids_run函数中是通过宏START_CAP_QUEUE_PROCESS_THREAD()来创建新线程的,通过STOP_CAP_QUEUE_PROCESS_THREAD()来销毁线程的。
如下是宏 START_CAP_QUEUE_PROCESS_THREAD()和STOP_CAP_QUEUE_PROCESS_THREAD()的定义:
//g_thread_create_full从version 2.32开始被废弃了 and should not be used in newly-written code.
//https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html#g-thread-create-full
#define START_CAP_QUEUE_PROCESS_THREAD() \
if(nids_params.multiproc) { /* threading... */ \
if(!(g_thread_create_full((GThreadFunc)cap_queue_process_thread,NULL,0,FALSE,TRUE,G_THREAD_PRIORITY_LOW,&gerror))) { \
strcpy(nids_errbuf, "thread: "); \
strncat(nids_errbuf, gerror->message, sizeof(nids_errbuf) - 8); \
return 0; \
}; \
}
#define STOP_CAP_QUEUE_PROCESS_THREAD() \
if(nids_params.multiproc) { /* stop the capture process thread */ \
g_async_queue_push(cap_queue,&EOF_item); \
}
g_thread_create_full创建新线程,其中第一个参数cap_queue_process_thread是要在新创建的线程里执行的函数,它的定义如下:
/* thread entry point
* pops capture queue items and feeds them to
* the ip fragment processors - mcree
*/
static void cap_queue_process_thread()
{
struct cap_queue_item *qitem;
while(1) { /* loop "forever" */
qitem=g_async_queue_pop(cap_queue);
if (qitem==&EOF_item) break; /* EOF item received: we should exit */
call_ip_frag_procs(qitem->data,qitem->caplen);
free(qitem->data);
free(qitem);
}
g_thread_exit(NULL);
}
该函数从异步队列中不断取出pcap_loop捕获的数据包,交给call_ip_frag_procs函数进行处理。上面nids_pcap_handler函数的部分代码中可以看出,如果没有设置使用多线程,那么直接在nids_pcap_handler函数中就使用call_ip_frag_procs函数处理数据包了。接下来处理过程参考
http://blog.csdn.net/u013074465/article/details/45555837