一 函数功能

将通过命令行解析的pcap对象列表内容导入snort的pcap队列。

二 队列、链表数据结构

snort.cc定义的队列与链表都是同一种数据结构,即:

typedef struct sf_list
{
SF_LNODE *head, *tail;
SF_LNODE *cur;
unsigned count;
} SF_QUEUE, SF_STACK, SF_LIST;
// 前驱后继双指针结构 NODE_DATA是void *
typedef struct sf_lnode
{
struct sf_lnode *next;
struct sf_lnode *prev;
NODE_DATA ndata;
} SF_QNODE, SF_SNODE, SF_LNODE;

队列、栈、列表都是双向链表,cur指向当前正操作结点,count是链表结点数量。

pcap_object_list和pcap_queue是全局静态对象:

static SF_LIST *pcap_object_list = NULL;
static SF_QUEUE *pcap_queue = NULL;

三 函数流程

static void PQ_SetUp(void)
{
if (pcap_object_list != NULL)
{
if (sflist_count(pcap_object_list) == 0) // 链表为空 程序退出
{
...
}
pcap_queue = sfqueue_new(); // 新建一个空结点 head tail和cur都是NULL
...
if (GetPcaps(pcap_object_list, pcap_queue) == -1) // 将pcap_object_list数据导入pcap_queue
// 释放pcap_object_list
...
}
...
}

四 函数GetPcaps流程分析

int GetPcaps(SF_LIST *pol, SF_QUEUE *pcap_queue)
{
...
for (pro = (PcapReadObject *)sflist_first(pol); // 获取链表头结点head的ndata
pro != NULL;
pro = (PcapReadObject *)sflist_next(pol)) // 移动cur指针到next位置 并返回cur移动前的ndata
{
type = pro->type; // snort命令行输入的参数 比如 --pcap-dir
arg = pro->arg; // snort命令行输入的参数 比如 /home/pcaps/modbus
filter = pro->filter; // libpcap过滤参数
switch (type)
{
case PCAP_SINGLE: // 命令行输入了单个pcap文件
...
if (strcmp(arg, '-') != 0) // arg是pcap文绝对件路径
{
// 使用stat获取arg状态 如果不是普通文件则报错 函数返回
...
}
...
ret = sfqueue_add(pcap_queue, (NODE_DATA)pcap); // 将文件名作为新结点的NDATA数据插入队列
...
}
...
}
}

五 命令行数据导入链表PQ_Multi

static void ParseCmdLine(int argc, char **argv)
{
...
while ((ch = getopt_long(argc, argv, valid_options, long_options, &option_index)) != -1) // 解析命令行输入
{
...
// 当用户在命令行输入snort --pcap-dir /home/wangbin/pcaps/
case PCAP_DIR:
case PCAP_LIST:
case PCAP_DIR:
PQ_Multi((char)ch, optarg);
}
}
static void PQ_Multi(char type, const char *list)
{
...
if (pcap_object_list == NULL)
{
pcap_object_list = sflist_new();
...
}
// 参数填充后加入链表尾部
if (sflist_add_tail(pcap_object_list, (NODE_DATA)pro) == -1)
...
}

六 pcap_queue出队业务

int SnortMain(int argc, char *argv[])
{
...
if (gbIsRunningModeIPs) // ips入侵防御模式
{
...
PacketLoop(); // 从pcap_queue取数据分析
}
}

void PacketLoop(void)
{
...
while (!exit_logged)
{
...
if (!ScReadMode() || !PQ_Next()) // 从队列取数据分析
...
}
...
}