suricata
util-plugin.c
Go to the documentation of this file.
1 /* Copyright (C) 2020-2021 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "suricata-common.h"
19 #include "suricata-plugin.h"
20 #include "suricata.h"
21 #include "runmodes.h"
22 #include "output-eve-syslog.h"
23 #include "util-plugin.h"
24 #include "util-debug.h"
25 
26 #ifdef HAVE_PLUGINS
27 
28 #include <dlfcn.h>
29 
30 typedef struct PluginListNode_ {
31  SCPlugin *plugin;
32  void *lib;
33  TAILQ_ENTRY(PluginListNode_) entries;
34 } PluginListNode;
35 
36 /**
37  * The list of loaded plugins.
38  *
39  * Currently only used as a place to stash the pointer returned from
40  * dlopen, but could have other uses, such as a plugin unload destructor.
41  */
42 static TAILQ_HEAD(, PluginListNode_) plugins = TAILQ_HEAD_INITIALIZER(plugins);
43 
44 static TAILQ_HEAD(, SCEveFileType_) output_types = TAILQ_HEAD_INITIALIZER(output_types);
45 
46 static TAILQ_HEAD(, SCCapturePlugin_) capture_plugins = TAILQ_HEAD_INITIALIZER(capture_plugins);
47 
48 bool RegisterPlugin(SCPlugin *plugin, void *lib)
49 {
50  BUG_ON(plugin->name == NULL);
51  BUG_ON(plugin->author == NULL);
52  BUG_ON(plugin->license == NULL);
53  BUG_ON(plugin->Init == NULL);
54 
55  PluginListNode *node = SCCalloc(1, sizeof(*node));
56  if (node == NULL) {
57  SCLogError("Failed to allocate memory for plugin");
58  return false;
59  }
60  node->plugin = plugin;
61  node->lib = lib;
62  TAILQ_INSERT_TAIL(&plugins, node, entries);
63  SCLogNotice("Initializing plugin %s; author=%s; license=%s", plugin->name, plugin->author,
64  plugin->license);
65  (*plugin->Init)();
66  return true;
67 }
68 
69 static void InitPlugin(char *path)
70 {
71  void *lib = dlopen(path, RTLD_NOW);
72  if (lib == NULL) {
73  SCLogNotice("Failed to open %s as a plugin: %s", path, dlerror());
74  } else {
75  SCLogNotice("Loading plugin %s", path);
76 
77  SCPluginRegisterFunc plugin_register = dlsym(lib, "SCPluginRegister");
78  if (plugin_register == NULL) {
79  SCLogError("Plugin does not export SCPluginRegister function: %s", path);
80  dlclose(lib);
81  return;
82  }
83 
84  if (!RegisterPlugin(plugin_register(), lib)) {
85  SCLogError("Plugin registration failed: %s", path);
86  dlclose(lib);
87  return;
88  }
89  }
90 }
91 
92 void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args)
93 {
94  ConfNode *conf = ConfGetNode("plugins");
95  if (conf == NULL) {
96  return;
97  }
98  ConfNode *plugin = NULL;
99  TAILQ_FOREACH(plugin, &conf->head, next) {
100  struct stat statbuf;
101  if (stat(plugin->val, &statbuf) == -1) {
102  SCLogError("Bad plugin path: %s: %s", plugin->val, strerror(errno));
103  continue;
104  }
105  if (S_ISDIR(statbuf.st_mode)) {
106  // coverity[toctou : FALSE]
107  DIR *dir = opendir(plugin->val);
108  if (dir == NULL) {
109  SCLogError("Failed to open plugin directory %s: %s", plugin->val, strerror(errno));
110  continue;
111  }
112  struct dirent *entry = NULL;
113  char path[PATH_MAX];
114  while ((entry = readdir(dir)) != NULL) {
115  if (strstr(entry->d_name, ".so") != NULL) {
116  snprintf(path, sizeof(path), "%s/%s", plugin->val, entry->d_name);
117  InitPlugin(path);
118  }
119  }
120  closedir(dir);
121  } else {
122  InitPlugin(plugin->val);
123  }
124  }
125 
126  if (run_mode == RUNMODE_PLUGIN) {
127  SCCapturePlugin *capture = SCPluginFindCaptureByName(capture_plugin_name);
128  if (capture == NULL) {
129  FatalError("No capture plugin found with name %s", capture_plugin_name);
130  }
131  capture->Init(capture_plugin_args, RUNMODE_PLUGIN, TMM_RECEIVEPLUGIN,
133  }
134 }
135 
136 static bool IsBuiltinTypeName(const char *name)
137 {
138  const char *builtin[] = {
139  "regular",
140  "unix_dgram",
141  "unix_stream",
142  "redis",
143  NULL,
144  };
145  for (int i = 0;; i++) {
146  if (builtin[i] == NULL) {
147  break;
148  }
149  if (strcmp(builtin[i], name) == 0) {
150  return true;
151  }
152  }
153  return false;
154 }
155 
156 /**
157  * \brief Register an Eve file type.
158  *
159  * \retval true if registered successfully, false if the file type name
160  * conflicts with a built-in or previously registered
161  * file type.
162  */
164 {
165  /* First check that the name doesn't conflict with a built-in filetype. */
166  if (IsBuiltinTypeName(plugin->name)) {
167  SCLogError("Eve file type name conflicts with built-in type: %s", plugin->name);
168  return false;
169  }
170 
171  /* Now check against previously registered file types. */
172  SCEveFileType *existing = NULL;
173  TAILQ_FOREACH (existing, &output_types, entries) {
174  if (strcmp(existing->name, plugin->name) == 0) {
175  SCLogError("Eve file type name conflicts with previously registered type: %s",
176  plugin->name);
177  return false;
178  }
179  }
180 
181  SCLogDebug("Registering EVE file type plugin %s", plugin->name);
182  TAILQ_INSERT_TAIL(&output_types, plugin, entries);
183  return true;
184 }
185 
186 SCEveFileType *SCPluginFindFileType(const char *name)
187 {
188  SCEveFileType *plugin = NULL;
189  TAILQ_FOREACH(plugin, &output_types, entries) {
190  if (strcmp(name, plugin->name) == 0) {
191  return plugin;
192  }
193  }
194  return NULL;
195 }
196 
198 {
199  TAILQ_INSERT_TAIL(&capture_plugins, plugin, entries);
200  SCLogNotice("Capture plugin registered: %s", plugin->name);
201  return 0;
202 }
203 
205 {
206  SCCapturePlugin *plugin = NULL;
207  TAILQ_FOREACH(plugin, &capture_plugins, entries) {
208  if (strcmp(name, plugin->name) == 0) {
209  return plugin;
210  }
211  }
212  return plugin;
213 }
214 #endif
suricata-plugin.h
SCPluginRegisterCapture
int SCPluginRegisterCapture(SCCapturePlugin *)
TMM_RECEIVEPLUGIN
@ TMM_RECEIVEPLUGIN
Definition: tm-threads-common.h:44
SCEveFileType_::name
const char * name
Definition: suricata-plugin.h:50
ConfNode_::val
char * val
Definition: conf.h:34
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:181
SCCapturePlugin_::Init
void(* Init)(const char *args, int plugin_slot, int receive_slot, int decode_slot)
Definition: suricata-plugin.h:69
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
TAILQ_ENTRY
#define TAILQ_ENTRY(type)
Definition: queue.h:239
TMM_DECODEPLUGIN
@ TMM_DECODEPLUGIN
Definition: tm-threads-common.h:45
TAILQ_HEAD_INITIALIZER
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:236
util-debug.h
SCCapturePlugin_::name
char * name
Definition: suricata-plugin.h:68
SCRegisterEveFileType
bool SCRegisterEveFileType(SCEveFileType *)
SCCapturePlugin_
Definition: suricata-plugin.h:67
RegisterPlugin
bool RegisterPlugin(SCPlugin *, void *)
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:295
SCPlugin_::license
const char * license
Definition: suricata-plugin.h:37
SCPlugin_::author
const char * author
Definition: suricata-plugin.h:38
SCPlugin_
Definition: suricata-plugin.h:35
util-plugin.h
runmodes.h
SCPluginsLoad
void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args)
SCPluginFindFileType
SCEveFileType * SCPluginFindFileType(const char *name)
suricata-common.h
run_mode
int run_mode
Definition: suricata.c:175
output-eve-syslog.h
SCPlugin_::Init
void(* Init)(void)
Definition: suricata-plugin.h:39
FatalError
#define FatalError(...)
Definition: util-debug.h:502
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
ConfNode_
Definition: conf.h:32
TAILQ_HEAD
#define TAILQ_HEAD(name, type)
Definition: queue.h:230
suricata.h
SCPlugin_::name
const char * name
Definition: suricata-plugin.h:36
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:237
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
RUNMODE_PLUGIN
@ RUNMODE_PLUGIN
Definition: runmodes.h:45
SCPluginFindCaptureByName
SCCapturePlugin * SCPluginFindCaptureByName(const char *name)
SCPluginRegisterFunc
SCPlugin *(* SCPluginRegisterFunc)(void)
Definition: suricata-plugin.h:42
SCEveFileType_
Definition: suricata-plugin.h:47