首先简单回顾一下上一章提到的Snort::setup(argc, argv)
void Snort::init(int argc, char** argv)
{
.....................
//加载action模块,它实现了replace reject react等动作,简单的看了一下这部分的源码,就是通过给源发送RST数据包来达到例如断开链接等功能
load_actions();
//数据包解码模块,这里实现了各种各样的协议的解码,常见的如tcp ip udp icmp等,还有一些工控协议和gprs的协议,它这儿都有对应的插件
load_codecs();
//这里加载上的插件就比较少,只有file链接和tcp链接,文档中有提到,它用来和外部进行通信
load_connectors();
//规则相关的插件,实现一些检测功能,例如flags检查
load_ips_options();
//日志功能插件,日志的数据形式比较多样,包括文件,控制台输出,unixsock等等
load_loggers();
#ifdef PIGLET
load_piglets();
#endif
//添加搜索引擎,大致看了下它的代码,比较像是匹配包内容一类的情况使用的
load_search_engines();
//加载流检查器,这里主要是tcp ip udp 等流的处理
load_stream_inspectors();
//加载网络检查插件,这里包括了扫描以及arp欺骗等行为的嗅探检测插件
load_network_inspectors();
//加载服务检查插件,包括的检查插件有http http2 ssl等
load_service_inspectors();
.....................
}
这里有很多load_xxxxx的函数,都是在对相关插件进行加载的,这里选择日志输出插件加载的函数看一下。
void load_loggers()
{
// loggers
PluginManager::load_plugins(log_codecs);
PluginManager::load_plugins(alert_sf_socket);
#ifdef STATIC_LOGGERS
// alerters
PluginManager::load_plugins(alert_csv);
PluginManager::load_plugins(alert_fast);
PluginManager::load_plugins(alert_full);
PluginManager::load_plugins(alert_json);
PluginManager::load_plugins(alert_syslog);
PluginManager::load_plugins(alert_talos);
PluginManager::load_plugins(alert_unixsock);
// loggers
PluginManager::load_plugins(log_hext);
PluginManager::load_plugins(log_pcap);
// both
PluginManager::load_plugins(eh_unified2);
#endif
.......
PluginManager::load_plugins(snort_cmd_line_conf->plugin_path);
}
几乎所有的插件,都实现了BaseApi这个接口,并通过PluginManager::load_plugins
进行注册。
调用顺序为load_plugins->load_list->register_plugin
static bool register_plugin(
const BaseApi* api, void* handle, const char* file)
{
......
Symbol* sym = symbols + api->type;
......
string key;
set_key(key, sym, api->name); //这里会根据类型等对插件的key进行拼接
Plugin& p = plug_map[key]; //在map中建立对应插件的节点并设置相关成员变量
......
p.key = key;
p.api = api;
p.handle = handle;
p.source = file;
if ( handle )
++ref_map[handle].count;
return true;
}
在最后的PluginManager::load_plugins(snort_cmd_line_conf->plugin_path);
中,调用的是同名的另一函数,它会遍历上面这个plug_map,并调用add_plugin函数
static void add_plugins()
{
PlugMap::iterator it;
for ( it = plug_map.begin(); it != plug_map.end(); ++it )
add_plugin(it->second);
}
static void add_plugin(Plugin& p)
{
Module* m = nullptr;
if ( p.api->mod_ctor )
{
current_plugin = p.api->name;
m = p.api->mod_ctor();
ModuleManager::add_module(m, p.api);
}
switch ( p.api->type )
{
case PT_CODEC:
CodecManager::add_plugin((const CodecApi*)p.api);
break;
case PT_INSPECTOR:
// probes must always be global. they run regardless of selected policy.
assert( (m && ((const InspectApi*)p.api)->type == IT_PROBE) ?
m->get_usage() == Module::GLOBAL :
true );
InspectorManager::add_plugin((const InspectApi*)p.api);
break;
case PT_IPS_ACTION:
ActionManager::add_plugin((const ActionApi*)p.api);
break;
case PT_IPS_OPTION:
IpsManager::add_plugin((const IpsApi*)p.api);
break;
case PT_SEARCH_ENGINE:
MpseManager::add_plugin((const MpseApi*)p.api);
break;
case PT_SO_RULE:
SoManager::add_plugin((const SoApi*)p.api);
break;
case PT_LOGGER:
EventManager::add_plugin((const LogApi*)p.api);
break;
case PT_CONNECTOR:
ConnectorManager::add_plugin((const ConnectorApi*)p.api);
break;
#ifdef PIGLET
case PT_PIGLET:
Piglet::Manager::add_plugin((const Piglet::Api*)p.api);
break;
#endif
default:
assert(false);
break;
}
}
这里涉及到比较多的Manager,其实他们的功能比较接近,都是将传入的插件按照类型存入自身的一个集合中,在需要使用的时候再取出来,这里以IpsManager::add_plugin为例
void IpsManager::add_plugin(const IpsApi* api)
{
s_options.emplace_back(new Option(api));
}
可以看到,传入的插件都存入了s_options的集合中,而它的get_opt函数会根据key取出对应的options
static Option* get_opt(const char* keyword)
{
for ( auto* p : s_options )
if ( !strcasecmp(p->api->base.name, keyword) )
return p;
return nullptr;
}
get_opt这个函数会在规则被解析的过程中调用,具体的过程,留到下一章再分析。
emmmm.....我也不知道这部分要总结啥了,就是把插件加入对应类型的集合中,这里是整个snort中我觉得最简单的一部分。