00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 //
00004 // This program is free software; you can redistribute it and/or modify it
00005 // under the terms of the GNU General Public License Version 2 as published
00006 // by the Free Software Foundation. You may not use, modify or distribute
00007 // this program under any other version of the GNU General Public License.
00008 //
00009 // This program is distributed in the hope that it will be useful, but
00010 // WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program; if not, write to the Free Software Foundation, Inc.,
00016 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 //--------------------------------------------------------------------------
00018 // module_manager.cc author Russ Combs <rucombs@cisco.com>
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include "config.h"
00022 #endif
00023
00024 #include "module_manager.h"
00025
00026 #include <lua.hpp>
00027
00028 #include <cassert>
00029 #include <iostream>
00030 #include <mutex>
00031 #include <string>
00032
00033 #include "framework/base_api.h"
00034 #include "framework/module.h"
00035 #include "helpers/markup.h"
00036 #include "log/messages.h"
00037 #include "main/modules.h"
00038 #include "main/shell.h"
00039 #include "main/snort.h"
00040 #include "main/snort_config.h"
00041 #include "parser/parse_conf.h"
00042 #include "parser/parser.h"
00043 #include "parser/vars.h"
00044 #include "profiler/profiler.h"
00045
00046 #include "plugin_manager.h"
00047
00048 using namespace std;
00049
00050 struct ModHook
00051 {
00052 Module* mod;
00053 const BaseApi* api;
00054 luaL_Reg* reg;
00055
00056 ModHook(Module*, const BaseApi*);
00057 ~ModHook();
00058
00059 void init();
00060 };
00061
00062 typedef std::list<ModHook*> ModuleList;
00063 static ModuleList s_modules;
00064 static unsigned s_errors = 0;
00065
00066 std::set<uint32_t> ModuleManager::gids;
00067
00068 static string s_current;
00069 static string s_name;
00070 static string s_type;
00071
00072 // for callbacks from Lua
00073 static SnortConfig* s_config = nullptr;
00074
00075 static std::mutex stats_mutex;
00076
00077 // forward decls
00078 extern "C"
00079 {
00080 bool open_table(const char*, int);
00081 void close_table(const char*, int);
00082
00083 bool set_bool(const char* fqn, bool val);
00084 bool set_number(const char* fqn, double val);
00085 bool set_string(const char* fqn, const char* val);
00086 bool set_alias(const char* from, const char* to);
00087 }
00088
00089 //-------------------------------------------------------------------------
00090 // ModHook foo
00091 //-------------------------------------------------------------------------
00092
00093 ModHook::ModHook(Module* m, const BaseApi* b)
00094 {
00095 mod = m;
00096 api = b;
00097 reg = nullptr;
00098 init();
00099 }
00100
00101 ModHook::~ModHook()
00102 {
00103 if ( reg )
00104 delete[] reg;
00105
00106 if ( api && api->mod_dtor )
00107 api->mod_dtor(mod);
00108 else
00109 delete mod;
00110 }
00111
00112 void ModHook::init()
00113 {
00114 const Command* c = mod->get_commands();
00115
00116 if ( !c )
00117 return;
00118
00119 unsigned n = 0;
00120 while ( c[n].name )
00121 n++;
00122
00123 // constructing reg here may seem like overkill
00124 // ... why not just typedef Command to luaL_Reg?
00125 // because the help would not be supplied or it
00126 // would be out of date, out of sync, etc. QED
00127 reg = new luaL_Reg[++n];
00128 unsigned k = 0;
00129
00130 while ( k < n )
00131 {
00132 reg[k].name = c[k].name;
00133 reg[k].func = c[k].func;
00134 k++;
00135 }
00136 }
00137
00138 //-------------------------------------------------------------------------
00139 // helper functions
00140 //-------------------------------------------------------------------------
00141
00142 static void set_type(string& fqn)
00143 {
00144 if ( s_type.empty() )
00145 return;
00146
00147 size_t pos = fqn.find_first_of('.');
00148
00149 if ( pos == fqn.npos )
00150 pos = fqn.size();
00151
00152 fqn.replace(0, pos, s_type);
00153 }
00154
00155 static void set_top(string& fqn)
00156 {
00157 size_t pos = fqn.find_first_of('.');
00158
00159 if ( pos != fqn.npos )
00160 fqn.erase(pos);
00161 }
00162
00163 static void trace(const char* s, const char* fqn, Value& v)
00164 {
00165 #if 1
00166 if ( s )
00167 return;
00168 #endif
00169
00170 if ( v.get_type() == Value::VT_STR )
00171 printf("%s: %s = '%s'\n", s, fqn, v.get_string());
00172 else
00173 printf("%s: %s = %ld\n", s, fqn, v.get_long());
00174 }
00175
00176 static ModHook* get_hook(const char* s)
00177 {
00178 for ( auto p : s_modules )
00179 if ( !strcmp(p->mod->get_name(), s) )
00180 return p;
00181
00182 return nullptr;
00183 }
00184
00185 //-------------------------------------------------------------------------
00186 // dump methods:
00187 // recurse over parameters and output like this:
00188 // int snort_target_based.max_attribute_hosts = 0: maximum number of hosts
00189 // in attribute table { 32:207551 }
00190 // (type, fqn, default, brief help, range)
00191 //-------------------------------------------------------------------------
00192
00193 enum DumpFormat { DF_STD, DF_TAB, DF_LUA };
00194 static DumpFormat dump_fmt = DF_STD;
00195
00196 static void dump_field_std(const string& key, const Parameter* p)
00197 {
00198 cout << Markup::item();
00199 cout << Markup::escape(p->get_type());
00200 cout << " " << Markup::emphasis(Markup::escape(key));
00201
00202 if ( p->deflt )
00203 cout << " = " << Markup::escape(p->deflt);
00204
00205 cout << ": " << p->help;
00206
00207 if ( const char* r = p->get_range() )
00208 cout << " { " << Markup::escape(r) << " }";
00209
00210 cout << endl;
00211 }
00212
00213 static void dump_field_tab(const string& key, const Parameter* p)
00214 {
00215 cout << Markup::item();
00216 cout << p->get_type();
00217 cout << "\t" << Markup::emphasis(Markup::escape(key));
00218
00219 if ( p->deflt )
00220 cout << "\t" << Markup::escape(p->deflt);
00221 else
00222 cout << "\t";
00223
00224 cout << "\t" << p->help;
00225
00226 if ( const char* r = p->get_range() )
00227 cout << "\t" << Markup::escape(r);
00228 else
00229 cout << "\t";
00230
00231 cout << endl;
00232 }
00233
00234 static void dump_field_lua(const string& key, const Parameter* p, bool table = false)
00235 {
00236 // implied values (rule keywords) and command line args
00237 // don't really have defaults, so skip them
00238 if ( key.find('~') != string::npos ||
00239 key.find('-') != string::npos ||
00240 key.find('*') != string::npos )
00241 return;
00242
00243 if ( table || p->is_table() )
00244 cout << key << " = { }";
00245
00246 // if there is no default, emit nothing
00247 else if ( !p->deflt )
00248 return;
00249
00250 else if ( p->is_quoted() )
00251 {
00252 const char* s = p->deflt ? p->deflt : " ";
00253 cout << key << " = '" << s << "'";
00254 }
00255 else
00256 {
00257 const char* s = p->deflt ? p->deflt : "0";
00258 cout << key << " = " << s;
00259 }
00260
00261 cout << endl;
00262 }
00263
00264 static void dump_table(string&, const char* pfx, const Parameter*, bool list = false);
00265
00266 static void dump_field(string& key, const char* pfx, const Parameter* p, bool list = false)
00267 {
00268 unsigned n = key.size();
00269
00270 if ( list || !p->name )
00271 key += (dump_fmt == DF_LUA) ? "[1]" : "[]";
00272
00273 if ( p->name )
00274 {
00275 if ( n )
00276 key += ".";
00277 key += p->name;
00278 }
00279
00280 if ( pfx && strncmp(key.c_str(), pfx, strlen(pfx)) )
00281 {
00282 key.erase();
00283 return;
00284 }
00285 // we dump just one list entry
00286 if ( p->type == Parameter::PT_TABLE )
00287 dump_table(key, pfx, (const Parameter*)p->range);
00288
00289 else if ( p->type == Parameter::PT_LIST )
00290 dump_table(key, pfx, (const Parameter*)p->range, true);
00291
00292 else
00293 {
00294 if ( dump_fmt == DF_LUA )
00295 dump_field_lua(key, p);
00296
00297 else if ( dump_fmt == DF_TAB )
00298 dump_field_tab(key, p);
00299
00300 else
00301 dump_field_std(key, p);
00302 }
00303 key.erase(n);
00304 }
00305
00306 static void dump_table(string& key, const char* pfx, const Parameter* p, bool list)
00307 {
00308 if ( dump_fmt == DF_LUA )
00309 {
00310 dump_field_lua(key, p, true);
00311
00312 if ( list )
00313 {
00314 string fqn = key + "[1]";
00315 dump_field_lua(fqn, p, true);
00316 }
00317 }
00318 while ( p && p->name )
00319 dump_field(key, pfx, p++, list);
00320 }
00321
00322 //-------------------------------------------------------------------------
00323 // set methods
00324 //-------------------------------------------------------------------------
00325
00326 static const Parameter* get_params(
00327 const string& sfx, const Parameter* p, int idx = 1)
00328 {
00329 size_t pos = sfx.find_first_of('.');
00330 std::string new_fqn;
00331
00332 if ( pos == string::npos )
00333 {
00334 if ( p[0].name && !p[1].name )
00335 return p;
00336 else
00337 new_fqn = sfx;
00338 }
00339 else
00340 {
00341 new_fqn = sfx.substr(pos + 1);
00342 }
00343
00344 string name = new_fqn.substr(0, new_fqn.find_first_of('.'));
00345 while ( p->name && name != p->name )
00346 ++p;
00347
00348 if ( !p->name )
00349 return nullptr;
00350
00351 if ( p->type != Parameter::PT_TABLE &&
00352 p->type != Parameter::PT_LIST )
00353 return p;
00354
00355 if ( new_fqn.find_first_of('.') == std::string::npos )
00356 {
00357 if ( idx && p->type == Parameter::PT_LIST )
00358 {
00359 const Parameter* tmp_p =
00360 reinterpret_cast<const Parameter*>(p->range);
00361
00362 // FIXIT-L this will fail if we are opening a a list with only one Parameter
00363 if ( tmp_p[0].name && !tmp_p[1].name )
00364 return tmp_p;
00365 }
00366 return p;
00367 }
00368
00369 p = (const Parameter*)p->range;
00370 return get_params(new_fqn, p, idx);
00371 }
00372
00373 // FIXIT-M vars may have been defined on command line. that mechanism will
00374 // be replaced with pulling a Lua chunk from the command line and stuffing
00375 // into L before setting configs; that will overwrite
00376 //
00377 // FIXIT-M should only need one table with dynamically typed vars
00378 //
00379 //
00380 // FIXIT-M this is a hack to tell vars by naming convention; with one table
00381 // this is obviated but if multiple tables are kept might want to change
00382 // these to a module with parameters
00383 //
00384 // FIXIT-L presently no way to catch errors like EXTERNAL_NET = not HOME_NET
00385 // which becomes a bool var and is ignored.
00386 static bool set_var(const char* fqn, Value& val)
00387 {
00388 if ( val.get_type() != Value::VT_STR )
00389 return false;
00390
00391 if ( get_ips_policy() == nullptr )
00392 return true;
00393
00394 trace("var", fqn, val);
00395 const char* s = val.get_string();
00396
00397 if ( strstr(fqn, "PATH") )
00398 AddVarToTable(s_config, fqn, s);
00399
00400 else if ( strstr(fqn, "PORT") )
00401 PortVarDefine(s_config, fqn, s);
00402
00403 else if ( strstr(fqn, "NET") || strstr(fqn, "SERVER") )
00404 ParseIpVar(s_config, fqn, s);
00405
00406 return true;
00407 }
00408
00409 static bool set_param(Module* mod, const char* fqn, Value& val)
00410 {
00411 if ( !mod->verified_set(fqn, val, s_config) )
00412 {
00413 ParseError("%s is invalid", fqn);
00414 ++s_errors;
00415 }
00416
00417 trace("par", fqn, val);
00418 return true;
00419 }
00420
00421 static bool ignored(const char* fqn)
00422 {
00423 static const char* ignore = nullptr;
00424
00425 if ( !ignore )
00426 {
00427 ignore = getenv("SNORT_IGNORE");
00428 if ( !ignore )
00429 ignore = "";
00430 }
00431 const char* s = strstr(ignore, fqn);
00432
00433 if ( !s )
00434 return false;
00435
00436 if ( s != ignore && s[-1] != ' ' )
00437 return false;
00438
00439 s += strlen(fqn);
00440
00441 if ( *s && *s != ' ' )
00442 return false;
00443
00444 return true;
00445 }
00446
00447 static bool set_value(const char* fqn, Value& v)
00448 {
00449 string t = fqn;
00450 set_type(t);
00451 fqn = t.c_str();
00452
00453 string key = t;
00454 set_top(key);
00455
00456 Module* mod = ModuleManager::get_module(key.c_str());
00457
00458 if ( !mod )
00459 {
00460 bool found = set_var(fqn, v);
00461
00462 if ( !found && !ignored(fqn) )
00463 ParseWarning(WARN_SYMBOLS, "unknown symbol %s", fqn);
00464 return found;
00465 }
00466
00467 if ( mod->get_usage() != Module::INSPECT && only_inspection_policy() )
00468 return true;
00469
00470 if ( mod->get_usage() != Module::DETECT && only_ips_policy() )
00471 return true;
00472
00473 if ( mod->get_usage() != Module::CONTEXT && only_network_policy() )
00474 return true;
00475
00476 // now we must traverse the mod params to get the leaf
00477 string s = fqn;
00478 const Parameter* p = get_params(s, mod->get_parameters());
00479
00480 if ( !p )
00481 p = get_params(s, mod->get_default_parameters());
00482
00483 if ( !p )
00484 {
00485 // FIXIT-L handle things like x = { 1 } where x is a table not a
00486 // list and 1 should be considered a key not a value; ideally say
00487 // can't find x.1 instead of just can't find x
00488 ParseError("can't find %s", fqn);
00489 ++s_errors;
00490 return false;
00491 }
00492
00493 if ( p->validate(v) )
00494 {
00495 v.set(p);
00496 set_param(mod, fqn, v);
00497 return true;
00498 }
00499
00500 if ( v.get_type() == Value::VT_STR )
00501 ParseError("invalid %s = '%s'", fqn, v.get_string());
00502 else if ( v.get_real() == v.get_long() )
00503 ParseError("invalid %s = %ld", fqn, v.get_long());
00504 else
00505 ParseError("invalid %s = %g", fqn, v.get_real());
00506
00507 ++s_errors;
00508 return false;
00509 }
00510
00511 //-------------------------------------------------------------------------
00512 // defaults - set all parameter table defaults for each configured module
00513 // but there are no internal default list or list items. since Lua calls
00514 // open table for each explicitly configured table only, here is what we
00515 // do:
00516 //
00517 // -- on open_table(), call Module::begin() for each module, list, and list
00518 // item
00519 // -- recursively set all defaults after calling Module::begin(), skipping
00520 // lists and list items
00521 // -- on close_table(), call Module::end() for each module, list, and list
00522 // item
00523 //-------------------------------------------------------------------------
00524
00525 static bool top_level(const char* s)
00526 { return !strchr(s, '.'); }
00527
00528 static bool begin(Module* m, const Parameter* p, const char* s, int idx, int depth)
00529 {
00530 if ( !p )
00531 {
00532 p = m->get_parameters();
00533 assert(p);
00534 }
00535
00536 // Module::begin() top-level, lists, and list items only
00537 if ( top_level(s) or
00538 (!idx and p->type == Parameter::PT_LIST) or
00539 (idx and p->type != Parameter::PT_LIST) )
00540 {
00541 //printf("begin %s %d\n", s, idx);
00542 if ( !m->verified_begin(s, idx, s_config) )
00543 return false;
00544 }
00545 // don't set list defaults
00546 if ( m->is_list() or p->type == Parameter::PT_LIST )
00547 {
00548 if ( !idx )
00549 return true;
00550 }
00551
00552 // set list item defaults only if explicitly configured
00553 // (this is why it is done here and not in the loop below)
00554 if ( p->type == Parameter::PT_LIST )
00555 {
00556 const Parameter* t =
00557 reinterpret_cast<const Parameter*>(p->range);
00558
00559 return begin(m, t, s, idx, depth+1);
00560 }
00561
00562 // don't begin subtables again
00563 if ( !top_level(s) && !depth )
00564 return true;
00565
00566 while ( p->name )
00567 {
00568 string fqn = s;
00569 fqn += '.';
00570 fqn += p->name;
00571
00572 switch ( p->type )
00573 {
00574 // traverse subtables only to set defaults
00575 case Parameter::PT_TABLE:
00576 {
00577 const Parameter* t =
00578 reinterpret_cast<const Parameter*>(p->range);
00579
00580 if ( !begin(m, t, fqn.c_str(), idx, depth+1) )
00581 return false;
00582 }
00583 break;
00584
00585 // skip lists, they must be configured explicitly
00586 case Parameter::PT_LIST:
00587 case Parameter::PT_MAX:
00588 break;
00589
00590 case Parameter::PT_BOOL:
00591 if ( p->deflt )
00592 {
00593 bool b = p->get_bool();
00594 //printf("set default %s = %s\n", fqn.c_str(), p->deflt);
00595 set_bool(fqn.c_str(), b);
00596 }
00597 break;
00598
00599 case Parameter::PT_INT:
00600 case Parameter::PT_PORT:
00601 case Parameter::PT_REAL:
00602 if ( p->deflt )
00603 {
00604 double d = p->get_number();
00605 //printf("set default %s = %f\n", fqn.c_str(), d);
00606 set_number(fqn.c_str(), d);
00607 }
00608 break;
00609
00610 // everything else is a string of some sort
00611 default:
00612 if ( p->deflt )
00613 {
00614 //printf("set default %s = %s\n", fqn.c_str(), p->deflt);
00615 set_string(fqn.c_str(), p->deflt);
00616 }
00617 break;
00618 }
00619 ++p;
00620 }
00621 return true;
00622 }
00623
00624 // no need to recurse here; we only call Module::end() for
00625 // top-level, lists, and list items
00626 static bool end(Module* m, const Parameter* p, const char* s, int idx)
00627 {
00628 bool top_param = !p;
00629
00630 if ( !p )
00631 {
00632 p = m->get_parameters();
00633 assert(p);
00634 }
00635 // same as begin() but we must include top_param to catch
00636 // top-level lists
00637 if ( top_level(s) or
00638 (top_param and p->type != Parameter::PT_TABLE) or
00639 (!idx and p->type == Parameter::PT_LIST) or
00640 (idx and p->type != Parameter::PT_LIST) )
00641 {
00642 //printf("end %s %d\n", s, idx);
00643 return m->verified_end(s, idx, s_config);
00644 }
00645 return true;
00646 }
00647
00648 //-------------------------------------------------------------------------
00649 // ffi methods
00650 //-------------------------------------------------------------------------
00651
00652 SO_PUBLIC bool set_alias(const char* from, const char* to)
00653 {
00654 s_name = from;
00655 s_type = to;
00656 return true;
00657 }
00658
00659 SO_PUBLIC bool open_table(const char* s, int idx)
00660 {
00661 //printf("open %s %d\n", s, idx);
00662
00663 const char* orig = s;
00664 string fqn = s;
00665 set_type(fqn);
00666 s = fqn.c_str();
00667
00668 string key = fqn;
00669 set_top(key);
00670
00671 // ips option parameters only used in rules which
00672 // are non-lua; may be possible to allow a subtable
00673 // for lua config of ips option globals
00674 ModHook* h = get_hook(key.c_str());
00675
00676 if ( !h || (h->api && h->api->type == PT_IPS_OPTION) )
00677 return false;
00678
00679 // FIXIT-M only basic modules and inspectors can be reloaded at present
00680 if ( ( Snort::is_reloading() )
00681 and h->api and h->api->type != PT_INSPECTOR )
00682 return false;
00683
00684 Module* m = h->mod;
00685 const Parameter* p = nullptr;
00686
00687 if ( m->get_usage() != Module::INSPECT && only_inspection_policy() )
00688 return true;
00689
00690 if ( m->get_usage() != Module::DETECT && only_ips_policy() )
00691 return true;
00692
00693 if ( m->get_usage() != Module::CONTEXT && only_network_policy() )
00694 return true;
00695
00696 if ( strcmp(m->get_name(), s) )
00697 {
00698 std::string sfqn = s;
00699 p = get_params(sfqn, m->get_parameters(), idx);
00700
00701 if ( !p )
00702 p = get_params(sfqn, m->get_default_parameters(), idx);
00703
00704 if ( !p )
00705 {
00706 ParseError("can't find %s", s);
00707 return false;
00708 }
00709 else if ((idx > 0) && (p->type == Parameter::PT_TABLE))
00710 {
00711 ParseError("%s is a table; all elements must be named", s);
00712 return false;
00713 }
00714 }
00715
00716 if ( s_current != key )
00717 {
00718 if ( fqn != orig )
00719 LogMessage("\t%s (%s)\n", key.c_str(), orig);
00720 else
00721 LogMessage("\t%s\n", key.c_str());
00722 s_current = key;
00723 }
00724
00725 if ( !begin(m, p, s, idx, 0) )
00726 {
00727 ParseError("can't open %s", m->get_name());
00728 return false;
00729 }
00730 return true;
00731 }
00732
00733 SO_PUBLIC void close_table(const char* s, int idx)
00734 {
00735 //printf("close %s %d\n", s, idx);
00736
00737 string fqn = s;
00738 set_type(fqn);
00739 s = fqn.c_str();
00740
00741 string key = fqn;
00742 set_top(key);
00743
00744 if ( ModHook* h = get_hook(key.c_str()) )
00745 {
00746 if ( h->mod->get_usage() != Module::INSPECT && only_inspection_policy() )
00747 return;
00748
00749 if ( h->mod->get_usage() != Module::DETECT && only_ips_policy() )
00750 return;
00751
00752 if ( h->mod->get_usage() != Module::CONTEXT && only_network_policy() )
00753 return;
00754
00755 if ( !end(h->mod, nullptr, s, idx) )
00756 ParseError("can't close %s", h->mod->get_name());
00757
00758 else if ( !s_name.empty() )
00759 PluginManager::instantiate(h->api, h->mod, s_config, s_name.c_str());
00760
00761 else if ( !idx && h->api && (key == s) )
00762 PluginManager::instantiate(h->api, h->mod, s_config);
00763 }
00764 s_name.clear();
00765 s_type.clear();
00766 }
00767
00768 SO_PUBLIC bool set_bool(const char* fqn, bool b)
00769 {
00770 //printf("bool %s %d\n", fqn, b);
00771 Value v(b);
00772 return set_value(fqn, v);
00773 }
00774
00775 SO_PUBLIC bool set_number(const char* fqn, double d)
00776 {
00777 //printf("real %s %f\n", fqn, d);
00778 Value v(d);
00779 return set_value(fqn, v);
00780 }
00781
00782 SO_PUBLIC bool set_string(const char* fqn, const char* s)
00783 {
00784 //printf("string %s %s\n", fqn, s);
00785 Value v(s);
00786 return set_value(fqn, v);
00787 }
00788
00789 static bool comp_mods(const ModHook* l, const ModHook* r)
00790 {
00791 const Module* lm = l->mod;
00792 const Module* rm = r->mod;
00793 return strcmp(lm->get_name(), rm->get_name()) < 0;
00794 }
00795
00796 static bool comp_gids(const ModHook* l, const ModHook* r)
00797 {
00798 const Module* lm = l->mod;
00799 const Module* rm = r->mod;
00800 return ( lm->get_gid() < rm->get_gid() );
00801 }
00802
00803 //-------------------------------------------------------------------------
00804 // public methods
00805 //-------------------------------------------------------------------------
00806
00807 void ModuleManager::init()
00808 {
00809 module_init();
00810 }
00811
00812 void ModuleManager::term()
00813 {
00814 for ( auto* p : s_modules )
00815 delete p;
00816
00817 s_modules.clear();
00818 }
00819
00820 void ModuleManager::add_module(Module* m, const BaseApi* b)
00821 {
00822 ModHook* mh = new ModHook(m, b);
00823 s_modules.push_back(mh);
00824
00825 Profiler::register_module(m);
00826
00827 if ( m->get_gid() )
00828 gids.emplace(m->get_gid());
00829 }
00830
00831 Module* ModuleManager::get_module(const char* s)
00832 {
00833 for ( auto p : s_modules )
00834 if ( !strcmp(p->mod->get_name(), s) )
00835 return p->mod;
00836
00837 return nullptr;
00838 }
00839
00840 Module* ModuleManager::get_default_module(const char* s, SnortConfig* sc)
00841 {
00842 Module* mod = get_module(s);
00843
00844 if ( mod )
00845 {
00846 mod->verified_begin(s, 0, sc);
00847 mod->verified_end(s, 0, nullptr);
00848 }
00849 return mod;
00850 }
00851
00852 const char* ModuleManager::get_current_module()
00853 { return s_current.c_str(); }
00854
00855 list<Module*> ModuleManager::get_all_modules()
00856 {
00857 list<Module*> ret;
00858
00859 for ( auto& m : s_modules )
00860 ret.push_back(m->mod);
00861
00862 return ret;
00863 }
00864
00865 void ModuleManager::set_config(SnortConfig* sc)
00866 { s_config = sc; }
00867
00868 void ModuleManager::reset_errors()
00869 { s_errors = 0; }
00870
00871 unsigned ModuleManager::get_errors()
00872 { return s_errors; }
00873
00874 void ModuleManager::list_modules(const char* s)
00875 {
00876 PlugType pt = s ? PluginManager::get_type(s) : PT_MAX;
00877 s_modules.sort(comp_mods);
00878 unsigned c = 0;
00879
00880 for ( auto* p : s_modules )
00881 {
00882 if (
00883 !s || !*s ||
00884 (p->api && p->api->type == pt) ||
00885 (!p->api && !strcmp(s, "basic"))
00886 )
00887 {
00888 LogMessage("%s\n", p->mod->get_name());
00889 c++;
00890 }
00891 }
00892 if ( !c )
00893 cout << "no match" << endl;
00894 }
00895
00896 void ModuleManager::show_modules()
00897 {
00898 s_modules.sort(comp_mods);
00899
00900 for ( auto* p : s_modules )
00901 {
00902 const char* t = p->api ? PluginManager::get_type_name(p->api->type) : "basic";
00903
00904 cout << Markup::item();
00905 cout << Markup::emphasis(p->mod->get_name());
00906 cout << " (" << t;
00907 cout << "): " << p->mod->get_help();
00908 cout << endl;
00909 }
00910 }
00911
00912 void ModuleManager::dump_modules()
00913 {
00914 s_modules.sort(comp_mods);
00915 Dumper d("Modules");
00916
00917 for ( auto* p : s_modules )
00918 if ( !p->api )
00919 d.dump(p->mod->get_name());
00920 }
00921
00922 static const char* mod_type(const BaseApi* api)
00923 {
00924 if ( !api )
00925 return "basic";
00926
00927 return PluginManager::get_type_name(api->type);
00928 }
00929
00930 static const char* mod_use(Module::Usage use)
00931 {
00932 switch ( use )
00933 {
00934 case Module::GLOBAL : return "global";
00935 case Module::CONTEXT: return "context";
00936 case Module::INSPECT: return "inspect";
00937 case Module::DETECT : return "detect";
00938 }
00939 assert(false);
00940 return "error";
00941 }
00942
00943 void ModuleManager::show_module(const char* name)
00944 {
00945 if ( !name || !*name )
00946 {
00947 cerr << "module name required" << endl;
00948 return;
00949 }
00950 s_modules.sort(comp_gids);
00951 unsigned c = 0;
00952
00953 for ( auto p : s_modules )
00954 {
00955 const Module* m = p->mod;
00956 assert(m);
00957
00958 if ( strcmp(m->get_name(), name) )
00959 continue;
00960
00961 cout << endl << Markup::head(3) << Markup::escape(name) << endl << endl;
00962
00963 if ( const char* h = m->get_help() )
00964 cout << endl << "What: " << Markup::escape(h) << endl;
00965
00966 cout << endl << "Type: " << mod_type(p->api) << endl;
00967 cout << endl << "Usage: " << mod_use(m->get_usage()) << endl;
00968
00969 const Parameter* params = m->get_parameters();
00970 const Parameter* def_params = m->get_default_parameters();
00971
00972 if ( ( params and params->type < Parameter::PT_MAX ) ||
00973 ( def_params and params->type < Parameter::PT_MAX ) )
00974 {
00975 cout << endl << "Configuration: " << endl << endl;
00976 show_configs(name, true);
00977 }
00978
00979 if ( m->get_commands() )
00980 {
00981 cout << endl << "Commands: " << endl << endl;
00982 show_commands(name, true);
00983 }
00984
00985 if ( m->get_rules() )
00986 {
00987 cout << endl << "Rules: " << endl << endl;
00988 show_rules(name, true);
00989 }
00990
00991 if ( m->get_pegs() )
00992 {
00993 cout << endl << "Peg counts: " << endl << endl;
00994 show_pegs(name, true);
00995 }
00996 c++;
00997 }
00998 if ( !c )
00999 cout << "no match" << endl;
01000 }
01001
01002 static bool selected(const Module* m, const char* pfx, bool exact)
01003 {
01004 if ( !pfx )
01005 return true;
01006
01007 if ( exact && strcmp(m->get_name(), pfx) )
01008 return false;
01009
01010 else if ( !exact && strncmp(m->get_name(), pfx, strlen(pfx)) )
01011 return false;
01012
01013 return true;
01014 }
01015
01016 void ModuleManager::show_configs(const char* pfx, bool exact)
01017 {
01018 s_modules.sort(comp_mods);
01019 unsigned c = 0;
01020
01021 for ( auto p : s_modules )
01022 {
01023 Module* m = p->mod;
01024 string s;
01025
01026 if ( !selected(m, pfx, exact) )
01027 continue;
01028
01029 if ( m->is_list() )
01030 {
01031 s = m->name;
01032
01033 if ( m->params->name )
01034 dump_table(s, pfx, m->params, true);
01035 else
01036 dump_field(s, pfx, m->params);
01037 }
01038 else if ( m->is_table() )
01039 {
01040 s = m->name;
01041 dump_table(s, pfx, m->params);
01042 }
01043 else
01044 {
01045 dump_field(s, pfx, m->params);
01046 }
01047
01048 s = m->name;
01049
01050 if ( m->default_params )
01051 dump_table(s, pfx, m->default_params);
01052
01053 if ( !pfx )
01054 cout << endl;
01055
01056 c++;
01057 }
01058 if ( !c )
01059 cout << "no match" << endl;
01060 }
01061
01062 void ModuleManager::dump_defaults(const char* pfx)
01063 {
01064 dump_fmt = DF_LUA;
01065 cout << "require('snort_config')" << endl;
01066 show_configs(pfx);
01067 }
01068
01069 void ModuleManager::show_commands(const char* pfx, bool exact)
01070 {
01071 s_modules.sort(comp_mods);
01072 unsigned n = 0;
01073
01074 for ( auto p : s_modules )
01075 {
01076 const Module* m = p->mod;
01077
01078 if ( !selected(m, pfx, exact) )
01079 continue;
01080
01081 const Command* c = m->get_commands();
01082
01083 if ( !c )
01084 continue;
01085
01086 while ( c->name )
01087 {
01088 cout << Markup::item();
01089 cout << Markup::emphasis_on();
01090 cout << Markup::escape(p->mod->get_name());
01091 cout << "." << Markup::escape(c->name);
01092 cout << Markup::emphasis_off();
01093 cout << c->get_arg_list();
01094 cout << ": " << Markup::escape(c->help);
01095 cout << endl;
01096 c++;
01097 }
01098 n++;
01099 }
01100 if ( !n )
01101 cout << "no match" << endl;
01102 }
01103
01104 bool ModuleManager::gid_in_use(uint32_t gid)
01105 {
01106 return gids.find(gid) != gids.end();
01107 }
01108
01109 void ModuleManager::show_gids(const char* pfx, bool exact)
01110 {
01111 s_modules.sort(comp_gids);
01112 unsigned c = 0;
01113
01114 for ( auto p : s_modules )
01115 {
01116 const Module* m = p->mod;
01117 assert(m);
01118
01119 if ( !selected(m, pfx, exact) )
01120 continue;
01121
01122 unsigned gid = m->get_gid();
01123
01124 if ( gid )
01125 {
01126 cout << Markup::item();
01127 cout << Markup::emphasis_on();
01128 cout << gid;
01129 cout << Markup::emphasis_off();
01130 cout << ": " << Markup::escape(m->get_name());
01131 cout << endl;
01132 }
01133 c++;
01134 }
01135 if ( !c )
01136 cout << "no match" << endl;
01137 }
01138
01139 static const char* peg_op(CountType ct)
01140 {
01141 switch ( ct )
01142 {
01143 case CountType::SUM: return " (sum)";
01144 case CountType::NOW: return " (now)";
01145 case CountType::MAX: return " (max)";
01146 default: break;
01147 }
01148 assert(false);
01149 return "error";
01150 }
01151
01152 void ModuleManager::show_pegs(const char* pfx, bool exact)
01153 {
01154 s_modules.sort(comp_gids);
01155 unsigned c = 0;
01156
01157 for ( auto p : s_modules )
01158 {
01159 const Module* m = p->mod;
01160 assert(m);
01161
01162 if ( !selected(m, pfx, exact) )
01163 continue;
01164
01165 const PegInfo* pegs = m->get_pegs();
01166
01167 if ( !pegs )
01168 continue;
01169
01170 while ( pegs->name )
01171 {
01172 cout << Markup::item();
01173 cout << Markup::emphasis_on();
01174 cout << Markup::escape(p->mod->get_name());
01175 cout << "." << Markup::escape(pegs->name);
01176 cout << Markup::emphasis_off();
01177 cout << ": " << Markup::escape(pegs->help);
01178 cout << Markup::escape(peg_op(pegs->type));
01179 cout << endl;
01180 ++pegs;
01181 }
01182 c++;
01183 }
01184 if ( !c )
01185 cout << "no match" << endl;
01186 }
01187
01188 void ModuleManager::show_rules(const char* pfx, bool exact)
01189 {
01190 s_modules.sort(comp_gids);
01191 unsigned c = 0;
01192
01193 for ( auto p : s_modules )
01194 {
01195 const Module* m = p->mod;
01196
01197 if ( !selected(m, pfx, exact) )
01198 continue;
01199
01200 const RuleMap* r = m->get_rules();
01201 unsigned gid = m->get_gid();
01202
01203 if ( !r )
01204 continue;
01205
01206 while ( r->msg )
01207 {
01208 cout << Markup::item();
01209 cout << Markup::emphasis_on();
01210 cout << gid << ":" << r->sid;
01211 cout << Markup::emphasis_off();
01212 cout << " (" << m->get_name() << ")";
01213 cout << " " << Markup::escape(r->msg);
01214 cout << endl;
01215 r++;
01216 }
01217 c++;
01218 }
01219 if ( !c )
01220 cout << "no match" << endl;
01221 }
01222
01223 void ModuleManager::load_commands(Shell* sh)
01224 {
01225 // FIXIT-L ideally only install commands from configured modules
01226 // FIXIT-L install commands into working shell
01227
01228 for ( auto p : s_modules )
01229 {
01230 if ( p->reg )
01231 sh->install(p->mod->get_name(), p->reg);
01232 }
01233 }
01234
01235 // move builtin generation to a better home?
01236 // FIXIT-L builtins should allow configurable nets and ports
01237 // FIXIT-L builtins should have accurate proto
01238 // (but ip winds up in all others)
01239 // FIXIT-L if msg has C escaped embedded quotes, we break
01240 //ss << "alert tcp any any -> any any ( ";
01241 static void make_rule(ostream& os, const Module* m, const RuleMap* r)
01242 {
01243 os << "alert ( ";
01244 os << "gid:" << m->get_gid() << "; ";
01245 os << "sid:" << r->sid << "; ";
01246 os << "rev:1; priority:3; ";
01247 os << "msg:\"" << "(" << m->get_name() << ") ";
01248 os << r->msg << "\"; )";
01249 os << endl;
01250 }
01251
01252 // FIXIT-L currently no way to know whether a module was activated or not
01253 // so modules with common rules will cause duplicate sid warnings
01254 // eg http_server (old) and http_inspect (new) both have 119:1-34
01255 // only way to avoid that now is to not load plugins with common rules
01256 // (we don't want to suppress it because it could mean something is broken)
01257 void ModuleManager::load_rules(SnortConfig* sc)
01258 {
01259 s_modules.sort(comp_gids);
01260 push_parse_location("builtin");
01261
01262 for ( auto p : s_modules )
01263 {
01264 const Module* m = p->mod;
01265 const RuleMap* r = m->get_rules();
01266
01267 if ( !r )
01268 continue;
01269
01270 stringstream ss;
01271
01272 while ( r->msg )
01273 {
01274 ss.str("");
01275 make_rule(ss, m, r);
01276
01277 // note: you can NOT do ss.str().c_str() here
01278 const string& rule = ss.str();
01279 ParseConfigString(sc, rule.c_str());
01280
01281 r++;
01282 }
01283 }
01284 pop_parse_location();
01285 }
01286
01287 void ModuleManager::dump_rules(const char* pfx)
01288 {
01289 s_modules.sort(comp_gids);
01290 unsigned len = pfx ? strlen(pfx) : 0;
01291 unsigned c = 0;
01292
01293 for ( auto p : s_modules )
01294 {
01295 const Module* m = p->mod;
01296
01297 if ( pfx && strncmp(m->get_name(), pfx, len) )
01298 continue;
01299
01300 const RuleMap* r = m->get_rules();
01301
01302 if ( !r )
01303 continue;
01304
01305 ostream& ss = cout;
01306
01307 while ( r->msg )
01308 {
01309 make_rule(ss, m, r);
01310 r++;
01311 }
01312 c++;
01313 }
01314 if ( !c )
01315 cout << "no match" << endl;
01316 }
01317
01318 void ModuleManager::dump_msg_map(const char* pfx)
01319 {
01320 s_modules.sort(comp_gids);
01321 unsigned len = pfx ? strlen(pfx) : 0;
01322 unsigned c = 0;
01323
01324 for ( auto p : s_modules )
01325 {
01326 const Module* m = p->mod;
01327
01328 if ( pfx && strncmp(m->get_name(), pfx, len) )
01329 continue;
01330
01331 const RuleMap* r = m->get_rules();
01332
01333 if ( !r )
01334 continue;
01335
01336 unsigned gid = m->get_gid();
01337
01338 while ( r->msg )
01339 {
01340 cout << gid << " || " << r->sid << " || ";
01341 cout << m->get_name() << ": ";
01342 cout << r->msg << endl;
01343 r++;
01344 }
01345 c++;
01346 }
01347 if ( !c )
01348 cout << "no match" << endl;
01349 }
01350
01351 void ModuleManager::dump_stats(SnortConfig*, const char* skip)
01352 {
01353 for ( auto p : s_modules )
01354 {
01355 if ( !skip || !strstr(skip, p->mod->get_name()) )
01356 {
01357 std::lock_guard<std::mutex> lock(stats_mutex);
01358 p->mod->show_stats();
01359 }
01360 }
01361 }
01362
01363 void ModuleManager::accumulate(SnortConfig*)
01364 {
01365 for ( auto p : s_modules )
01366 {
01367 std::lock_guard<std::mutex> lock(stats_mutex);
01368 p->mod->sum_stats(true);
01369 }
01370 std::lock_guard<std::mutex> lock(stats_mutex);
01371 pc_sum();
01372 }
01373
01374 void ModuleManager::reset_stats(SnortConfig*)
01375 {
01376 for ( auto p : s_modules )
01377 {
01378 std::lock_guard<std::mutex> lock(stats_mutex);
01379 p->mod->reset_stats();
01380 }
01381 }
01382
END OF CODE