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  */
29 typedef 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  */
40 typedef struct Context_ {
41  /** Verbose, or print to stdout. */
42  int verbose;
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  */
67 static int FiletypeInit(const ConfNode *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 = ConfNodeLookupChild(conf, "eve-template")) != NULL) {
81  if (!ConfGetChildValueBool(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  */
101 static 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  */
128 static 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;
138  SCLogNotice(
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  */
149 static 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;
158  SCLogNotice(
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  */
174 static 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  */
194 void 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  .name = FILETYPE_NAME,
210  .author = "FirstName LastName <name@example.org>",
211  .license = "GPL-2.0-only",
212  .Init = PluginInit,
213 };
214 
215 /**
216  * The function called by Suricata after loading this plugin.
217  *
218  * A pointer to a populated SCPlugin struct must be returned.
219  */
221 {
222  return &PluginRegistration;
223 }
suricata-plugin.h
ThreadData_::count
uint64_t count
Definition: filetype.c:34
ThreadData
struct ThreadData_ ThreadData
ThreadData_::thread_id
ThreadId thread_id
Definition: filetype.c:31
SCEveFileType_::name
const char * name
The name of the output, used in the configuration.
Definition: output-eve.h:89
Context_::verbose
int verbose
Definition: filetype.c:42
Context_
Definition: output-eve-syslog.c:40
ctx
struct Thresholds ctx
SCEveFileType_::Write
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
ThreadId
uint32_t ThreadId
Definition: output-eve.h:37
FILETYPE_NAME
#define FILETYPE_NAME
Definition: filetype.c:24
SCEveFileType_::ThreadDeinit
void(* ThreadDeinit)(const void *init_data, void *thread_data)
Called to deinitialize each thread.
Definition: output-eve.h:157
util-debug.h
Context
struct Context_ Context
SCRegisterEveFileType
bool SCRegisterEveFileType(SCEveFileType *plugin)
Register an Eve file type.
Definition: output-eve.c:100
ThreadData_
Definition: filetype.c:29
PluginInit
void PluginInit(void)
Definition: filetype.c:194
SCPlugin_
Definition: suricata-plugin.h:35
ConfNodeLookupChild
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:781
util-mem.h
suricata-common.h
SCPluginRegister
const SCPlugin * SCPluginRegister()
Definition: filetype.c:220
SCEveFileType_::Deinit
void(* Deinit)(void *init_data)
Final call to deinitialize this filetype.
Definition: output-eve.h:167
FatalError
#define FatalError(...)
Definition: util-debug.h:502
ConfGetChildValueBool
int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val)
Definition: conf.c:500
output-eve.h
EVE logging subsystem.
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ConfNode_
Definition: conf.h:32
PluginRegistration
const SCPlugin PluginRegistration
Definition: filetype.c:208
SCPlugin_::name
const char * name
Definition: suricata-plugin.h:36
SCEveFileType_::Init
int(* Init)(const ConfNode *conf, const bool threaded, void **init_data)
Function to initialize this filetype.
Definition: output-eve.h:104
SCEveFileType_::ThreadInit
int(* ThreadInit)(const void *init_data, const ThreadId thread_id, void **thread_data)
Initialize thread specific data.
Definition: output-eve.h:125
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:237
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCEveFileType_
Structure used to define an EVE output file type plugin.
Definition: output-eve.h:74