1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // action_manager.cc author Russ Combs <rucombs@cisco.com>
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "action_manager.h"
25
26 #include <vector>
27
28 #include "log/messages.h"
29 #include "main/snort_config.h"
30 #include "managers/module_manager.h"
31 #include "managers/plugin_manager.h"
32 #include "packet_io/active.h"
33 #include "parser/parser.h"
34
35 using namespace snort;
36 using namespace std;
37
38 struct ActionClass
39 {
40 const ActionApi* api;
41 bool initialized = false; // In the context of the main thread, this means that api.pinit()
42 // has been called. In the packet thread, it means that api.tinit()
43 // has been called.
44
ActionClassActionClass45 ActionClass(const ActionApi* p) : api(p) { }
46 };
47
48 struct ActionInst
49 {
50 ActionClass& cls;
51 IpsAction* act;
52
ActionInstActionInst53 ActionInst(ActionClass& cls, IpsAction* act) : cls(cls), act(act) { }
54 };
55
56 struct IpsActionsConfig
57 {
58 vector<ActionInst> clist;
59 };
60
61 using ACList = vector<ActionClass>;
62 using ACTypeList = unordered_map<string, Actions::Type>;
63 using ACPriorityList = map<IpsAction::IpsActionPriority, string, std::greater<int>>;
64
65 static ACList s_actors;
66 static ACTypeList s_act_types;
67 static ACPriorityList s_act_priorities;
68 static Actions::Type s_act_index = 0;
69
70 static THREAD_LOCAL ACList* s_tl_actors = nullptr;
71
72 //-------------------------------------------------------------------------
73 // Main thread operations
74 //-------------------------------------------------------------------------
75
76 // Plugin/Class operations
add_plugin(const ActionApi * api)77 void ActionManager::add_plugin(const ActionApi* api)
78 {
79 s_actors.emplace_back(api);
80 s_act_types.emplace(api->base.name, s_act_index++);
81 s_act_priorities.emplace(api->priority, api->base.name);
82 }
83
get_action_string(Actions::Type action)84 std::string ActionManager::get_action_string(Actions::Type action)
85 {
86 if ( action < s_act_index )
87 {
88 for ( const auto& type : s_act_types )
89 {
90 if ( type.second == action )
91 return type.first;
92 }
93 }
94
95 return "ERROR";
96 }
97
get_action_type(const char * s)98 Actions::Type ActionManager::get_action_type(const char* s)
99 {
100 auto type = s_act_types.find(s);
101
102 if (type != s_act_types.end())
103 return type->second;
104
105 return get_max_action_types();
106 }
107
get_max_action_types()108 Actions::Type ActionManager::get_max_action_types()
109 {
110 return s_act_index;
111 }
112
get_action_priorities(bool alert_before_pass)113 std::string ActionManager::get_action_priorities(bool alert_before_pass)
114 {
115 std::string priorities;
116
117 for (auto iter = s_act_priorities.begin(); iter != s_act_priorities.end(); )
118 {
119 if ( alert_before_pass )
120 {
121 if ( iter->second == "pass" )
122 {
123 iter++;
124 continue;
125 }
126 else if ( iter->second == "alert" )
127 {
128 priorities += "alert pass ";
129 iter++;
130 continue;
131 }
132 }
133
134 priorities += iter->second;
135
136 if ( ++iter != s_act_priorities.end() )
137 priorities += " ";
138 }
139
140 return priorities;
141 }
142
dump_plugins()143 void ActionManager::dump_plugins()
144 {
145 Dumper d("IPS Actions");
146
147 for ( auto& p : s_actors )
148 d.dump(p.api->base.name, p.api->base.version);
149 }
150
release_plugins()151 void ActionManager::release_plugins()
152 {
153 for ( auto& p : s_actors )
154 {
155 if ( p.api->pterm )
156 p.api->pterm();
157 }
158 s_actors.clear();
159 }
160
get_action_class(const ActionApi * api,IpsActionsConfig * iac)161 static ActionClass* get_action_class(const ActionApi* api, IpsActionsConfig* iac)
162 {
163 for ( auto& ai : iac->clist )
164 {
165 if ( ai.cls.api == api )
166 return &ai.cls;
167 }
168
169 for ( auto& ac : s_actors )
170 {
171 if ( ac.api == api )
172 {
173 if ( !ac.initialized )
174 {
175 if ( ac.api->pinit )
176 ac.api->pinit();
177 ac.initialized = true;
178 }
179 return ∾
180 }
181 }
182
183 return nullptr;
184 }
185
186 // Config operations
new_config(SnortConfig * sc)187 void ActionManager::new_config(SnortConfig* sc)
188 {
189 sc->ips_actions_config = new IpsActionsConfig;
190 }
191
delete_config(SnortConfig * sc)192 void ActionManager::delete_config(SnortConfig* sc)
193 {
194 if (!sc->ips_actions_config)
195 return;
196
197 // Delete all IPS action instances that were created as part of this configuration
198 for (auto& ia : sc->ips_actions_config->clist)
199 ia.cls.api->dtor(ia.act);
200
201 delete sc->ips_actions_config;
202 sc->ips_actions_config = nullptr;
203 }
204
instantiate(const ActionApi * api,Module * mod,SnortConfig * sc,IpsPolicy * ips)205 void ActionManager::instantiate(const ActionApi* api, Module* mod, SnortConfig* sc, IpsPolicy* ips)
206 {
207 ActionClass* cls = get_action_class(api, sc->ips_actions_config);
208
209 assert(cls != nullptr);
210
211 IpsAction* act = cls->api->ctor(mod);
212
213 if ( act )
214 {
215
216 RuleListNode* rln = CreateRuleType(sc, api->base.name, get_action_type(api->base.name));
217
218 // The plugin actions (e.g. reject, react, etc.) are per policy, per mode.
219 // At logging time, they have to be retrieved the way we store them here.
220 if ( !ips )
221 ips = get_ips_policy();
222
223 Actions::Type idx = rln->mode;
224 if (ips->action[idx] == nullptr)
225 {
226 ips->action[idx] = act;
227 // Add this instance to the list of those created for this config
228 sc->ips_actions_config->clist.emplace_back(*cls, act);
229 }
230 else
231 {
232 cls->api->dtor(act);
233 }
234 }
235 }
236
initialize_policies(SnortConfig * sc)237 void ActionManager::initialize_policies(SnortConfig* sc)
238 {
239 for (unsigned i = 0; i < sc->policy_map->ips_policy_count(); i++)
240 {
241 auto policy = sc->policy_map->get_ips_policy(i);
242
243 if ( !policy )
244 continue;
245
246 for ( auto actor : s_actors )
247 ActionManager::instantiate(actor.api, nullptr, sc, policy);
248 }
249 }
250
251 //-------------------------------------------------------------------------
252 // Packet thread operations
253 //-------------------------------------------------------------------------
get_thread_local_action_class(const ActionApi * api)254 static ActionClass& get_thread_local_action_class(const ActionApi* api)
255 {
256 for ( ActionClass& p : *s_tl_actors )
257 {
258 if ( p.api == api )
259 return p;
260 }
261 s_tl_actors->emplace_back(api);
262 return s_tl_actors->back();
263 }
264
thread_init(const SnortConfig * sc)265 void ActionManager::thread_init(const SnortConfig* sc)
266 {
267 // Initial build out of this thread's configured plugin registry
268 s_tl_actors = new ACList;
269 for ( auto& p : sc->ips_actions_config->clist )
270 {
271 ActionClass& tlac = get_thread_local_action_class(p.cls.api);
272 if ( tlac.api->tinit )
273 tlac.api->tinit();
274 tlac.initialized = true;
275 }
276 }
277
thread_reinit(const SnortConfig * sc)278 void ActionManager::thread_reinit(const SnortConfig* sc)
279 {
280 // Update this thread's configured plugin registry with any newly configured inspectors
281 for ( auto& p : sc->ips_actions_config->clist )
282 {
283 ActionClass& tlac = get_thread_local_action_class(p.cls.api);
284 if (!tlac.initialized)
285 {
286 if ( tlac.api->tinit )
287 tlac.api->tinit();
288 tlac.initialized = true;
289 }
290 }
291 Active::thread_init(sc);
292 }
293
thread_term()294 void ActionManager::thread_term()
295 {
296 if (s_tl_actors)
297 {
298 // Call tterm for every IPS action plugin ever configured during the lifetime of this thread
299 for ( auto& p : *s_tl_actors )
300 {
301 if ( p.api->tterm )
302 p.api->tterm();
303 }
304 delete s_tl_actors;
305 s_tl_actors = nullptr;
306 }
307 }
308
309 #ifdef PIGLET
310
311 //-------------------------------------------------------------------------
312 // piglet breach
313 //-------------------------------------------------------------------------
314
find_api(const char * name)315 static const ActionApi* find_api(const char* name)
316 {
317 for ( auto actor : s_actors )
318 if ( !strcmp(actor.api->base.name, name) )
319 return actor.api;
320
321 return nullptr;
322 }
323
instantiate(const char * name,Module * m)324 IpsActionWrapper* ActionManager::instantiate(const char* name, Module* m)
325 {
326 auto api = find_api(name);
327 if ( !api || !api->ctor )
328 return nullptr;
329
330 auto p = api->ctor(m);
331 if ( !p )
332 return nullptr;
333
334 return new IpsActionWrapper(api, p);
335 }
336
337 #endif
338
339