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