suricata
filetype.c
Go to the documentation of this file.
1/* Copyright (C) 2020-2024 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 "output-eve.h"
21#include "util-mem.h"
22#include "util-debug.h"
23
24#define FILETYPE_NAME "json-filetype-plugin"
25
26/**
27 * Per thread context data for each logging thread.
28 */
29typedef struct ThreadData_ {
30 /** The thread ID, for demonstration purposes only. */
32
33 /** The number of records logged on this thread. */
34 uint64_t count;
36
37/**
38 * A context object for each eve logger using this output.
39 */
40typedef struct Context_ {
41 /** Verbose, or print to stdout. */
44
45/**
46 * This function is called to initialize the output, it can be somewhat thought
47 * of like opening a file.
48 *
49 * \param conf The EVE configuration node using this output.
50 *
51 * \param threaded If true the EVE subsystem is running in threaded mode.
52 *
53 * \param data A pointer where context data can be stored relevant to this
54 * output.
55 *
56 * Eve output plugins need to be thread aware as the threading happens
57 * at a lower level than the EVE output, so a flag is provided here to
58 * notify the plugin if threading is enabled or not.
59 *
60 * If the plugin does not work with threads disabled, or enabled, this function
61 * should return -1.
62 *
63 * Note for upgrading a plugin from 6.0 to 7.0: The ConfNode in 7.0 is the
64 * configuration for the eve instance, not just a node named after the plugin.
65 * This allows the plugin to get more context about what it is logging.
66 */
67static int FiletypeInit(const SCConfNode *conf, const bool threaded, void **data)
68{
69 SCLogNotice("Initializing template eve output plugin: threaded=%d", threaded);
70 Context *context = SCCalloc(1, sizeof(Context));
71 if (context == NULL) {
72 return -1;
73 }
74
75 /* Verbose by default. */
76 int verbose = 1;
77
78 /* An example of how you can access configuration data from a
79 * plugin. */
80 if (conf && (conf = SCConfNodeLookupChild(conf, "eve-template")) != NULL) {
81 if (!SCConfGetChildValueBool(conf, "verbose", &verbose)) {
82 verbose = 1;
83 } else {
84 SCLogNotice("Read verbose configuration value of %d", verbose);
85 }
86 }
87 context->verbose = verbose;
88
89 *data = context;
90 return 0;
91}
92
93/**
94 * This function is called when the output is closed.
95 *
96 * This will be called after ThreadDeinit is called for each thread.
97 *
98 * \param data The data allocated in FiletypeInit. It should be cleaned up and
99 * deallocated here.
100 */
101static void FiletypeDeinit(void *data)
102{
103 SCLogNotice("data=%p", data);
104 Context *ctx = data;
105 if (ctx != NULL) {
106 SCFree(ctx);
107 }
108}
109
110/**
111 * Initialize per thread context.
112 *
113 * \param ctx The context created in TemplateInitOutput.
114 *
115 * \param thread_id An identifier for this thread.
116 *
117 * \param thread_data Pointer where thread specific context can be stored.
118 *
119 * When the EVE output is running in threaded mode this will be called once for
120 * each output thread with a unique thread_id. For regular file logging in
121 * threaded mode Suricata uses the thread_id to construct the files in the form
122 * of "eve.<thread_id>.json". This plugin may want to do similar, or open
123 * multiple connections to whatever the final logging location might be.
124 *
125 * In the case of non-threaded EVE logging this function is called
126 * once with a thread_id of 0.
127 */
128static int FiletypeThreadInit(const void *ctx, const ThreadId thread_id, void **thread_data)
129{
130 SCLogNotice("thread_id=%d", thread_id);
131 ThreadData *tdata = SCCalloc(1, sizeof(ThreadData));
132 if (tdata == NULL) {
133 SCLogError("Failed to allocate thread data");
134 return -1;
135 }
136 tdata->thread_id = thread_id;
137 *thread_data = tdata;
139 "Initialized thread %03d (pthread_id=%" PRIuMAX ")", tdata->thread_id, pthread_self());
140 return 0;
141}
142
143/**
144 * Deinitialize a thread.
145 *
146 * This is where any cleanup per thread should be done including free'ing of the
147 * thread_data if needed.
148 */
149static void FiletypeThreadDeinit(const void *ctx, void *thread_data)
150{
151 SCLogNotice("thread_data=%p", thread_data);
152 if (thread_data == NULL) {
153 // Nothing to do.
154 return;
155 }
156
157 ThreadData *tdata = thread_data;
159 "Deinitializing thread %d: records written: %" PRIu64, tdata->thread_id, tdata->count);
160 SCFree(tdata);
161}
162
163/**
164 * This method is called with formatted Eve JSON data.
165 *
166 * \param buffer Formatted JSON buffer \param buffer_len Length of formatted
167 * JSON buffer \param data Data set in Init callback \param thread_data Data set
168 * in ThreadInit callbacl
169 *
170 * Do not block in this thread, it will cause packet loss. Instead of outputting
171 * to any resource that may block it might be best to enqueue the buffers for
172 * further processing which will require copying of the provided buffer.
173 */
174static int FiletypeWrite(
175 const char *buffer, const int buffer_len, const void *data, void *thread_data)
176{
177 const Context *ctx = data;
178 ThreadData *thread = thread_data;
179
180 SCLogNotice("thread_id=%d, data=%p, thread_data=%p", thread->thread_id, data, thread_data);
181
182 thread->count++;
183
184 if (ctx->verbose) {
185 SCLogNotice("Received write with thread_data %p: %s", thread_data, buffer);
186 }
187 return 0;
188}
189
190/**
191 * Called by Suricata to initialize the module. This module registers
192 * new file type to the JSON logger.
193 */
194void PluginInit(void)
195{
196 SCEveFileType *my_output = SCCalloc(1, sizeof(SCEveFileType));
197 my_output->name = FILETYPE_NAME;
198 my_output->Init = FiletypeInit;
199 my_output->Deinit = FiletypeDeinit;
200 my_output->ThreadInit = FiletypeThreadInit;
201 my_output->ThreadDeinit = FiletypeThreadDeinit;
202 my_output->Write = FiletypeWrite;
203 if (!SCRegisterEveFileType(my_output)) {
204 FatalError("Failed to register filetype plugin: %s", FILETYPE_NAME);
205 }
206}
207
209 .version = SC_API_VERSION,
210 .suricata_version = SC_PACKAGE_VERSION,
211 .name = FILETYPE_NAME,
212 .plugin_version = "0.1.0",
213 .author = "FirstName LastName <name@example.org>",
214 .license = "GPL-2.0-only",
215 .Init = PluginInit,
216};
217
218/**
219 * The function called by Suricata after loading this plugin.
220 *
221 * A pointer to a populated SCPlugin struct must be returned.
222 */
224{
225 return &PluginRegistration;
226}
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition conf.c:796
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
Definition conf.c:515
const SCPlugin * SCPluginRegister()
Definition filetype.c:223
const SCPlugin PluginRegistration
Definition filetype.c:208
struct ThreadData_ ThreadData
struct Context_ Context
#define FILETYPE_NAME
Definition filetype.c:24
void PluginInit(void)
Definition filetype.c:194
struct Thresholds ctx
bool SCRegisterEveFileType(SCEveFileType *plugin)
Register an Eve file type.
Definition output-eve.c:100
EVE logging subsystem.
uint32_t ThreadId
Definition output-eve.h:37
int verbose
Definition filetype.c:42
Structure used to define an EVE output file type plugin.
Definition output-eve.h:74
void(* Deinit)(void *init_data)
Final call to deinitialize this filetype.
Definition output-eve.h:167
int(* Init)(const SCConfNode *conf, const bool threaded, void **init_data)
Function to initialize this filetype.
Definition output-eve.h:104
int(* Write)(const char *buffer, const int buffer_len, const void *init_data, void *thread_data)
Called for each EVE log record.
Definition output-eve.h:144
void(* ThreadDeinit)(const void *init_data, void *thread_data)
Called to deinitialize each thread.
Definition output-eve.h:157
const char * name
The name of the output, used in the configuration.
Definition output-eve.h:89
int(* ThreadInit)(const void *init_data, const ThreadId thread_id, void **thread_data)
Initialize thread specific data.
Definition output-eve.h:125
uint64_t version
uint64_t count
Definition filetype.c:34
ThreadId thread_id
Definition filetype.c:31
#define SC_PACKAGE_VERSION
#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 SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53