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 "util-plugin.h"
23 #include "util-debug.h"
24 #include "conf.h"
25 
26 #ifdef HAVE_PLUGINS
27 
28 #include "app-layer-protos.h"
29 #include "app-layer-parser.h"
30 #include "detect-engine-register.h"
31 #include "output.h"
32 
33 #include <dlfcn.h>
34 
35 typedef struct PluginListNode_ {
36  SCPlugin *plugin;
37  void *lib;
38  TAILQ_ENTRY(PluginListNode_) entries;
39 } PluginListNode;
40 
41 /**
42  * The list of loaded plugins.
43  *
44  * Currently only used as a place to stash the pointer returned from
45  * dlopen, but could have other uses, such as a plugin unload destructor.
46  */
47 static TAILQ_HEAD(, PluginListNode_) plugins = TAILQ_HEAD_INITIALIZER(plugins);
48 
49 static TAILQ_HEAD(, SCCapturePlugin_) capture_plugins = TAILQ_HEAD_INITIALIZER(capture_plugins);
50 
51 bool RegisterPlugin(SCPlugin *plugin, void *lib)
52 {
53  if (plugin->version != SC_API_VERSION) {
54  SCLogError("Suricata and plugin versions differ: plugin has %" PRIx64
55  " (%s) vs Suricata %" PRIx64 " (plugin was built with %s)",
56  plugin->version, plugin->plugin_version, SC_API_VERSION, plugin->suricata_version);
57  return false;
58  }
59  BUG_ON(plugin->name == NULL);
60  BUG_ON(plugin->author == NULL);
61  BUG_ON(plugin->license == NULL);
62  BUG_ON(plugin->Init == NULL);
63 
64  PluginListNode *node = SCCalloc(1, sizeof(*node));
65  if (node == NULL) {
66  SCLogError("Failed to allocate memory for plugin");
67  return false;
68  }
69  node->plugin = plugin;
70  node->lib = lib;
71  TAILQ_INSERT_TAIL(&plugins, node, entries);
72  SCLogNotice("Initializing plugin %s; version= %s; author=%s; license=%s; built from %s",
73  plugin->name, plugin->plugin_version, plugin->author, plugin->license,
74  plugin->suricata_version);
75  (*plugin->Init)();
76  return true;
77 }
78 
79 static void InitPlugin(char *path)
80 {
81  void *lib = dlopen(path, RTLD_NOW);
82  if (lib == NULL) {
83  SCLogNotice("Failed to open %s as a plugin: %s", path, dlerror());
84  } else {
85  SCLogNotice("Loading plugin %s", path);
86 
87  SCPluginRegisterFunc plugin_register = dlsym(lib, "SCPluginRegister");
88  if (plugin_register == NULL) {
89  SCLogError("Plugin does not export SCPluginRegister function: %s", path);
90  dlclose(lib);
91  return;
92  }
93 
94  if (!RegisterPlugin(plugin_register(), lib)) {
95  SCLogError("Plugin registration failed: %s", path);
96  dlclose(lib);
97  return;
98  }
99  }
100 }
101 
102 void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args)
103 {
104  ConfNode *conf = ConfGetNode("plugins");
105  if (conf == NULL) {
106  return;
107  }
108  ConfNode *plugin = NULL;
109  TAILQ_FOREACH(plugin, &conf->head, next) {
110  struct stat statbuf;
111  if (stat(plugin->val, &statbuf) == -1) {
112  SCLogError("Bad plugin path: %s: %s", plugin->val, strerror(errno));
113  continue;
114  }
115  if (S_ISDIR(statbuf.st_mode)) {
116  // coverity[toctou : FALSE]
117  DIR *dir = opendir(plugin->val);
118  if (dir == NULL) {
119  SCLogError("Failed to open plugin directory %s: %s", plugin->val, strerror(errno));
120  continue;
121  }
122  struct dirent *entry = NULL;
123  char path[PATH_MAX];
124  while ((entry = readdir(dir)) != NULL) {
125  if (strstr(entry->d_name, ".so") != NULL) {
126  snprintf(path, sizeof(path), "%s/%s", plugin->val, entry->d_name);
127  InitPlugin(path);
128  }
129  }
130  closedir(dir);
131  } else {
132  InitPlugin(plugin->val);
133  }
134  }
135 
136  if (SCRunmodeGet() == RUNMODE_PLUGIN) {
137  SCCapturePlugin *capture = SCPluginFindCaptureByName(capture_plugin_name);
138  if (capture == NULL) {
139  FatalError("No capture plugin found with name %s", capture_plugin_name);
140  }
141  capture->Init(capture_plugin_args, RUNMODE_PLUGIN, TMM_RECEIVEPLUGIN,
143  }
144 }
145 
147 {
148  TAILQ_INSERT_TAIL(&capture_plugins, plugin, entries);
149  SCLogNotice("Capture plugin registered: %s", plugin->name);
150  return 0;
151 }
152 
154 {
155  SCCapturePlugin *plugin = NULL;
156  TAILQ_FOREACH(plugin, &capture_plugins, entries) {
157  if (strcmp(name, plugin->name) == 0) {
158  return plugin;
159  }
160  }
161  return plugin;
162 }
163 
165 {
166  AppProto alproto = g_alproto_max;
167  AppProtoRegisterProtoString(alproto, plugin->name);
168  if (plugin->Register) {
169  if (AppLayerParserPreRegister(plugin->Register) != 0) {
170  return 1;
171  }
172  }
173  if (plugin->KeywordsRegister) {
174  if (SigTablePreRegister(plugin->KeywordsRegister) != 0) {
175  return 1;
176  }
177  }
178  if (plugin->Logger) {
180  .confname = plugin->confname,
181  .logname = plugin->logname,
182  .alproto = alproto,
183  .LogTx = (EveJsonSimpleTxLogFunc)plugin->Logger,
184  };
185  if (OutputPreRegisterLogger(reg_data) != 0) {
186  return 1;
187  }
188  }
189  return 0;
190 }
191 #endif
suricata-plugin.h
SCPluginRegisterCapture
int SCPluginRegisterCapture(SCCapturePlugin *)
TMM_RECEIVEPLUGIN
@ TMM_RECEIVEPLUGIN
Definition: tm-threads-common.h:42
SCRunmodeGet
int SCRunmodeGet(void)
Get the current run mode.
Definition: suricata.c:264
SCAppLayerPlugin_::name
const char * name
Definition: suricata-plugin.h:66
ConfNode_::val
char * val
Definition: conf.h:34
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:85
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:181
SCAppLayerPlugin_::Logger
bool(* Logger)(const void *tx, void *jb)
Definition: suricata-plugin.h:71
SCAppLayerPlugin_::logname
const char * logname
Definition: suricata-plugin.h:69
detect-engine-register.h
SCCapturePlugin_::Init
void(* Init)(const char *args, int plugin_slot, int receive_slot, int decode_slot)
Definition: suricata-plugin.h:56
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
SCAppLayerPlugin_::KeywordsRegister
void(* KeywordsRegister)(void)
Definition: suricata-plugin.h:68
SCPlugin_::version
uint64_t version
Definition: suricata-plugin.h:43
EveJsonSimpleTxLogFunc
bool(* EveJsonSimpleTxLogFunc)(void *, struct JsonBuilder *)
Definition: output.h:175
TAILQ_ENTRY
#define TAILQ_ENTRY(type)
Definition: queue.h:239
TMM_DECODEPLUGIN
@ TMM_DECODEPLUGIN
Definition: tm-threads-common.h:43
SCAppLayerPlugin_::confname
const char * confname
Definition: suricata-plugin.h:70
TAILQ_HEAD_INITIALIZER
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:236
util-debug.h
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:29
SCCapturePlugin_::name
char * name
Definition: suricata-plugin.h:55
AppProtoRegisterProtoString
void AppProtoRegisterProtoString(AppProto alproto, const char *proto_name)
Definition: app-layer-protos.c:74
SCCapturePlugin_
Definition: suricata-plugin.h:54
RegisterPlugin
bool RegisterPlugin(SCPlugin *, void *)
SCPlugin_::plugin_version
const char * plugin_version
Definition: suricata-plugin.h:46
app-layer-parser.h
SCAppLayerPlugin_
Definition: suricata-plugin.h:65
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:309
SCPlugin_::license
const char * license
Definition: suricata-plugin.h:47
SCPlugin_::author
const char * author
Definition: suricata-plugin.h:48
SCPlugin_
Definition: suricata-plugin.h:41
EveJsonTxLoggerRegistrationData
Definition: output.h:184
conf.h
name
const char * name
Definition: tm-threads.c:2081
util-plugin.h
runmodes.h
SCPluginsLoad
void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args)
SCPlugin_::suricata_version
const char * suricata_version
Definition: suricata-plugin.h:44
SCAppLayerPlugin_::Register
void(* Register)(void)
Definition: suricata-plugin.h:67
SCPluginRegisterAppLayer
int SCPluginRegisterAppLayer(SCAppLayerPlugin *)
AppLayerParserPreRegister
int AppLayerParserPreRegister(void(*Register)(void))
Definition: app-layer-parser.c:1705
suricata-common.h
EveJsonTxLoggerRegistrationData::confname
const char * confname
Definition: output.h:185
SCPlugin_::Init
void(* Init)(void)
Definition: suricata-plugin.h:49
FatalError
#define FatalError(...)
Definition: util-debug.h:502
SigTablePreRegister
int SigTablePreRegister(void(*KeywordsRegister)(void))
Definition: detect-engine-register.c:477
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
app-layer-protos.h
suricata.h
SCPlugin_::name
const char * name
Definition: suricata-plugin.h:45
OutputPreRegisterLogger
int OutputPreRegisterLogger(EveJsonTxLoggerRegistrationData reg_data)
Definition: output.c:980
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:43
SCPluginFindCaptureByName
SCCapturePlugin * SCPluginFindCaptureByName(const char *name)
output.h
SCPluginRegisterFunc
SCPlugin *(* SCPluginRegisterFunc)(void)
Definition: suricata-plugin.h:52