Skip to content

Latest commit

 

History

History
179 lines (159 loc) · 5.62 KB

0x02_插件加载.md

File metadata and controls

179 lines (159 loc) · 5.62 KB

插件加载

首先简单回顾一下上一章提到的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的函数,都是在对相关插件进行加载的,这里选择日志输出插件加载的函数看一下。

load_loggers()

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中我觉得最简单的一部分。