suricata
output-lua.c
Go to the documentation of this file.
1 /* Copyright (C) 2014-2022 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 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  */
24 
25 #include "suricata-common.h"
26 #include "debug.h"
27 #include "pkt-var.h"
28 #include "conf.h"
29 
30 #include "threads.h"
31 #include "threadvars.h"
32 #include "tm-threads.h"
33 
34 #include "util-print.h"
35 #include "util-unittest.h"
36 
37 #include "util-debug.h"
38 
39 #include "output.h"
40 #include "app-layer-htp.h"
41 #include "app-layer.h"
42 #include "app-layer-ssl.h"
43 #include "app-layer-ssh.h"
44 #include "app-layer-parser.h"
45 #include "util-privs.h"
46 #include "util-buffer.h"
47 #include "util-proto-name.h"
48 #include "util-logopenfile.h"
49 #include "util-time.h"
50 
51 #include "output-lua.h"
52 
53 #ifdef HAVE_LUA
54 
55 #include <lua.h>
56 #include <lualib.h>
57 #include <lauxlib.h>
58 
59 #include "util-lua.h"
60 #include "util-lua-common.h"
61 #include "util-lua-http.h"
62 #include "util-lua-dns.h"
63 #include "util-lua-ja3.h"
64 #include "util-lua-tls.h"
65 #include "util-lua-ssh.h"
66 #include "util-lua-hassh.h"
67 #include "util-lua-smtp.h"
68 
69 #define MODULE_NAME "LuaLog"
70 
71 /** \brief structure containing global config
72  * The OutputLuaLogInitSub which is run per script
73  * can access this to get global config info through
74  * it's parent_ctx->data ptr.
75  */
76 typedef struct LogLuaMasterCtx_ {
77  char path[PATH_MAX]; /**< contains script-dir */
78 } LogLuaMasterCtx;
79 
80 typedef struct LogLuaCtx_ {
81  SCMutex m;
82  lua_State *luastate;
83  int deinit_once;
84 } LogLuaCtx;
85 
86 typedef struct LogLuaThreadCtx_ {
87  LogLuaCtx *lua_ctx;
88 } LogLuaThreadCtx;
89 
90 static TmEcode LuaLogThreadInit(ThreadVars *t, const void *initdata, void **data);
91 static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data);
92 
93 /** \internal
94  * \brief TX logger for lua scripts
95  *
96  * A single call to this function will run one script on a single
97  * transaction.
98  *
99  * NOTE: The flow (f) also referenced by p->flow is locked.
100  */
101 static int LuaTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id)
102 {
103  SCEnter();
104 
105  LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data;
106 
107  SCMutexLock(&td->lua_ctx->m);
108 
109  LuaStateSetThreadVars(td->lua_ctx->luastate, tv);
110  LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p);
111  LuaStateSetTX(td->lua_ctx->luastate, txptr);
112  LuaStateSetFlow(td->lua_ctx->luastate, f);
113 
114  /* prepare data to pass to script */
115  lua_getglobal(td->lua_ctx->luastate, "log");
116  lua_newtable(td->lua_ctx->luastate);
117  LuaPushTableKeyValueInt(td->lua_ctx->luastate, "tx_id", (int)(tx_id));
118 
119  int retval = lua_pcall(td->lua_ctx->luastate, 1, 0, 0);
120  if (retval != 0) {
121  SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1));
122  }
123 
124  SCMutexUnlock(&td->lua_ctx->m);
125  SCReturnInt(0);
126 }
127 
128 /** \internal
129  * \brief Streaming logger for lua scripts
130  *
131  * Hooks into the Streaming Logger API. Gets called for each chunk of new
132  * streaming data.
133  */
134 static int LuaStreamingLogger(ThreadVars *tv, void *thread_data, const Flow *f,
135  const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
136 {
137  SCEnter();
138 
139  void *txptr = NULL;
140  LuaStreamingBuffer b = { data, data_len, flags };
141 
142  SCLogDebug("flags %02x", flags);
143 
145  if (f && f->alstate)
146  txptr = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, tx_id);
147  }
148 
149  LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data;
150 
151  SCMutexLock(&td->lua_ctx->m);
152 
153  LuaStateSetThreadVars(td->lua_ctx->luastate, tv);
155  LuaStateSetTX(td->lua_ctx->luastate, txptr);
156  LuaStateSetFlow(td->lua_ctx->luastate, (Flow *)f);
157  LuaStateSetStreamingBuffer(td->lua_ctx->luastate, &b);
158 
159  /* prepare data to pass to script */
160  lua_getglobal(td->lua_ctx->luastate, "log");
161  lua_newtable(td->lua_ctx->luastate);
162 
164  LuaPushTableKeyValueInt(td->lua_ctx->luastate, "tx_id", (int)(tx_id));
165 
166  int retval = lua_pcall(td->lua_ctx->luastate, 1, 0, 0);
167  if (retval != 0) {
168  SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1));
169  }
170 
171  SCMutexUnlock(&td->lua_ctx->m);
172 
174 }
175 
176 /** \internal
177  * \brief Packet Logger for lua scripts, for alerts
178  *
179  * A single call to this function will run one script for a single
180  * packet. If it is called, it means that the registered condition
181  * function has returned TRUE.
182  *
183  * The script is called once for each alert stored in the packet.
184  *
185  * NOTE: p->flow is UNlocked
186  */
187 static int LuaPacketLoggerAlerts(ThreadVars *tv, void *thread_data, const Packet *p)
188 {
189  LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data;
190 
191  char timebuf[64];
192  CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
193 
194  if (!(PKT_IS_IPV4(p)) && !(PKT_IS_IPV6(p))) {
195  /* decoder event */
196  goto not_supported;
197  }
198 
199  /* loop through alerts stored in the packet */
200  SCMutexLock(&td->lua_ctx->m);
201  uint16_t cnt;
202  for (cnt = 0; cnt < p->alerts.cnt; cnt++) {
203  const PacketAlert *pa = &p->alerts.alerts[cnt];
204  if (unlikely(pa->s == NULL)) {
205  continue;
206  }
207 
208  lua_getglobal(td->lua_ctx->luastate, "log");
209 
210  void *txptr = NULL;
211  if (p->flow && p->flow->alstate && (pa->flags & PACKET_ALERT_FLAG_TX))
212  txptr = AppLayerParserGetTx(p->proto, p->flow->alproto, p->flow->alstate, pa->tx_id);
213 
214  LuaStateSetThreadVars(td->lua_ctx->luastate, tv);
215  LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p);
216  LuaStateSetTX(td->lua_ctx->luastate, txptr);
217  LuaStateSetFlow(td->lua_ctx->luastate, p->flow);
218  LuaStateSetPacketAlert(td->lua_ctx->luastate, (PacketAlert *)pa);
219 
220  /* prepare data to pass to script */
221  //lua_newtable(td->lua_ctx->luastate);
222 
223  int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0);
224  if (retval != 0) {
225  SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1));
226  }
227  }
228  SCMutexUnlock(&td->lua_ctx->m);
229 not_supported:
230  SCReturnInt(0);
231 }
232 
233 static int LuaPacketConditionAlerts(ThreadVars *tv, void *data, const Packet *p)
234 {
235  if (p->alerts.cnt > 0)
236  return TRUE;
237  return FALSE;
238 }
239 
240 /** \internal
241  * \brief Packet Logger for lua scripts, for packets
242  *
243  * A single call to this function will run one script for a single
244  * packet. If it is called, it means that the registered condition
245  * function has returned TRUE.
246  *
247  * The script is called once for each packet.
248  *
249  * NOTE: p->flow is UNlocked
250  */
251 static int LuaPacketLogger(ThreadVars *tv, void *thread_data, const Packet *p)
252 {
253  LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data;
254 
255  char timebuf[64];
256 
257  if ((!(PKT_IS_IPV4(p))) && (!(PKT_IS_IPV6(p)))) {
258  goto not_supported;
259  }
260 
261  CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
262 
263  /* loop through alerts stored in the packet */
264  SCMutexLock(&td->lua_ctx->m);
265  lua_getglobal(td->lua_ctx->luastate, "log");
266 
267  LuaStateSetThreadVars(td->lua_ctx->luastate, tv);
268  LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p);
269  LuaStateSetFlow(td->lua_ctx->luastate, p->flow);
270 
271  /* prepare data to pass to script */
272  lua_newtable(td->lua_ctx->luastate);
273 
274  int retval = lua_pcall(td->lua_ctx->luastate, 1, 0, 0);
275  if (retval != 0) {
276  SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1));
277  }
278  SCMutexUnlock(&td->lua_ctx->m);
279 not_supported:
280  SCReturnInt(0);
281 }
282 
283 static int LuaPacketCondition(ThreadVars *tv, void *data, const Packet *p)
284 {
285  return TRUE;
286 }
287 
288 /** \internal
289  * \brief File API Logger function for Lua scripts
290  *
291  * Executes a script once for one file.
292  *
293  * NOTE p->flow is locked at this point
294  */
295 static int LuaFileLogger(ThreadVars *tv, void *thread_data, const Packet *p, const File *ff, uint8_t dir)
296 {
297  SCEnter();
298  LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data;
299 
300  if ((!(PKT_IS_IPV4(p))) && (!(PKT_IS_IPV6(p))))
301  return 0;
302 
303  BUG_ON(ff->flags & FILE_LOGGED);
304 
305  SCLogDebug("ff %p", ff);
306 
307  SCMutexLock(&td->lua_ctx->m);
308 
309  LuaStateSetThreadVars(td->lua_ctx->luastate, tv);
310  LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p);
311  if (p->flow && p->flow->alstate) {
312  void *txptr = AppLayerParserGetTx(p->proto, p->flow->alproto, p->flow->alstate, ff->txid);
313  if (txptr) {
314  LuaStateSetTX(td->lua_ctx->luastate, txptr);
315  }
316  }
317  LuaStateSetFlow(td->lua_ctx->luastate, p->flow);
318  LuaStateSetFile(td->lua_ctx->luastate, (File *)ff);
319 
320  /* get the lua function to call */
321  lua_getglobal(td->lua_ctx->luastate, "log");
322 
323  int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0);
324  if (retval != 0) {
325  SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1));
326  }
327  SCMutexUnlock(&td->lua_ctx->m);
328  return 0;
329 }
330 
331 /** \internal
332  * \brief Flow API Logger function for Lua scripts
333  *
334  * Executes a script once for one flow
335  *
336  * Note: flow 'f' is locked
337  */
338 static int LuaFlowLogger(ThreadVars *tv, void *thread_data, Flow *f)
339 {
340  SCEnter();
341  LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data;
342 
343  SCLogDebug("f %p", f);
344 
345  SCMutexLock(&td->lua_ctx->m);
346 
347  LuaStateSetThreadVars(td->lua_ctx->luastate, tv);
348  LuaStateSetFlow(td->lua_ctx->luastate, f);
349 
350  /* get the lua function to call */
351  lua_getglobal(td->lua_ctx->luastate, "log");
352 
353  int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0);
354  if (retval != 0) {
355  SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1));
356  }
357  SCMutexUnlock(&td->lua_ctx->m);
358  return 0;
359 }
360 
361 
362 
363 static int LuaStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st)
364 {
365  SCEnter();
366  LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data;
367 
368  SCMutexLock(&td->lua_ctx->m);
369 
370  lua_State *luastate = td->lua_ctx->luastate;
371  /* get the lua function to call */
372  lua_getglobal(td->lua_ctx->luastate, "log");
373 
374  /* create lua array, which is really just a table. The key is an int (1-x),
375  * the value another table with named fields: name, tm_name, value, pvalue.
376  * { 1, { name=<name>, tmname=<tm_name>, value=<value>, pvalue=<pvalue>}}
377  * { 2, { name=<name>, tmname=<tm_name>, value=<value>, pvalue=<pvalue>}}
378  * etc
379  */
380  lua_newtable(luastate);
381  uint32_t u = 0;
382  for (; u < st->nstats; u++) {
383  lua_pushinteger(luastate, u + 1);
384 
385  lua_newtable(luastate);
386 
387  lua_pushstring(luastate, "name");
388  lua_pushstring(luastate, st->stats[u].name);
389  lua_settable(luastate, -3);
390 
391  lua_pushstring(luastate, "tmname");
392  lua_pushstring(luastate, st->stats[u].tm_name);
393  lua_settable(luastate, -3);
394 
395  lua_pushstring(luastate, "value");
396  lua_pushinteger(luastate, st->stats[u].value);
397  lua_settable(luastate, -3);
398 
399  lua_pushstring(luastate, "pvalue");
400  lua_pushinteger(luastate, st->stats[u].pvalue);
401  lua_settable(luastate, -3);
402 
403  lua_settable(luastate, -3);
404  }
405 
406  int retval = lua_pcall(td->lua_ctx->luastate, 1, 0, 0);
407  if (retval != 0) {
408  SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1));
409  }
410  SCMutexUnlock(&td->lua_ctx->m);
411  return 0;
412 
413 }
414 
415 typedef struct LogLuaScriptOptions_ {
416  AppProto alproto;
417  int packet;
418  int alerts;
419  int file;
420  int streaming;
421  int tcp_data;
422  int http_body;
423  int flow;
424  int stats;
425 } LogLuaScriptOptions;
426 
427 /** \brief load and evaluate the script
428  *
429  * This function parses the script, checks if all the required functions
430  * are defined and runs the 'init' function. The init function will inform
431  * us what the scripts needs are.
432  *
433  * \param filename filename of lua script file
434  * \param options struct to pass script requirements/options back to caller
435  * \retval errcode 0 ok, -1 error
436  */
437 static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) {
438  lua_State *luastate = LuaGetState();
439  if (luastate == NULL)
440  goto error;
441  luaL_openlibs(luastate);
442 
443  int status = luaL_loadfile(luastate, filename);
444  if (status) {
445  SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(luastate, -1));
446  goto error;
447  }
448 
449  /* prime the script (or something) */
450  if (lua_pcall(luastate, 0, 0, 0) != 0) {
451  SCLogError(SC_ERR_LUA_ERROR, "couldn't prime file: %s", lua_tostring(luastate, -1));
452  goto error;
453  }
454 
455  lua_getglobal(luastate, "init");
456  if (lua_type(luastate, -1) != LUA_TFUNCTION) {
457  SCLogError(SC_ERR_LUA_ERROR, "no init function in script");
458  goto error;
459  }
460 
461  lua_newtable(luastate); /* stack at -1 */
462  if (lua_gettop(luastate) == 0 || lua_type(luastate, 2) != LUA_TTABLE) {
463  SCLogError(SC_ERR_LUA_ERROR, "no table setup");
464  goto error;
465  }
466 
467  lua_pushliteral(luastate, "script_api_ver");
468  lua_pushnumber (luastate, 1);
469  lua_settable(luastate, -3);
470 
471  if (lua_pcall(luastate, 1, 1, 0) != 0) {
472  SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'init' function: %s", lua_tostring(luastate, -1));
473  goto error;
474  }
475 
476  /* process returns from script */
477  if (lua_gettop(luastate) == 0) {
478  SCLogError(SC_ERR_LUA_ERROR, "init function in script should return table, nothing returned");
479  goto error;
480  }
481  if (lua_type(luastate, 1) != LUA_TTABLE) {
482  SCLogError(SC_ERR_LUA_ERROR, "init function in script should return table, returned is not table");
483  goto error;
484  }
485 
486  lua_pushnil(luastate);
487  const char *k, *v;
488  while (lua_next(luastate, -2)) {
489  k = lua_tostring(luastate, -2);
490  if (k == NULL)
491  continue;
492 
493  v = lua_tostring(luastate, -1);
494  lua_pop(luastate, 1);
495  if (v == NULL)
496  continue;
497 
498  SCLogDebug("k='%s', v='%s'", k, v);
499 
500  if (strcmp(k,"protocol") == 0 && strcmp(v, "http") == 0)
501  options->alproto = ALPROTO_HTTP1;
502  else if (strcmp(k,"protocol") == 0 && strcmp(v, "dns") == 0)
503  options->alproto = ALPROTO_DNS;
504  else if (strcmp(k,"protocol") == 0 && strcmp(v, "tls") == 0)
505  options->alproto = ALPROTO_TLS;
506  else if (strcmp(k,"protocol") == 0 && strcmp(v, "ssh") == 0)
507  options->alproto = ALPROTO_SSH;
508  else if (strcmp(k,"protocol") == 0 && strcmp(v, "smtp") == 0)
509  options->alproto = ALPROTO_SMTP;
510  else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0)
511  options->packet = 1;
512  else if (strcmp(k, "filter") == 0 && strcmp(v, "alerts") == 0)
513  options->alerts = 1;
514  else if (strcmp(k, "type") == 0 && strcmp(v, "file") == 0)
515  options->file = 1;
516  else if (strcmp(k, "type") == 0 && strcmp(v, "streaming") == 0)
517  options->streaming = 1;
518  else if (strcmp(k, "type") == 0 && strcmp(v, "flow") == 0)
519  options->flow = 1;
520  else if (strcmp(k, "filter") == 0 && strcmp(v, "tcp") == 0)
521  options->tcp_data = 1;
522  else if (strcmp(k, "type") == 0 && strcmp(v, "stats") == 0)
523  options->stats = 1;
524  else
525  SCLogInfo("unknown key and/or value: k='%s', v='%s'", k, v);
526  }
527 
528  if (((options->alproto != ALPROTO_UNKNOWN)) + options->packet + options->file > 1) {
529  SCLogError(SC_ERR_LUA_ERROR, "invalid combination of 'needs' in the script");
530  goto error;
531  }
532 
533  lua_getglobal(luastate, "setup");
534  if (lua_type(luastate, -1) != LUA_TFUNCTION) {
535  SCLogError(SC_ERR_LUA_ERROR, "no setup function in script");
536  goto error;
537  }
538 
539  lua_getglobal(luastate, "log");
540  if (lua_type(luastate, -1) != LUA_TFUNCTION) {
541  SCLogError(SC_ERR_LUA_ERROR, "no log function in script");
542  goto error;
543  }
544 
545  lua_getglobal(luastate, "deinit");
546  if (lua_type(luastate, -1) != LUA_TFUNCTION) {
547  SCLogError(SC_ERR_LUA_ERROR, "no deinit function in script");
548  goto error;
549  }
550 
551  LuaReturnState(luastate);
552  return 0;
553 error:
554  if (luastate)
555  LuaReturnState(luastate);
556  return -1;
557 }
558 
559 /** \brief setup a luastate for use at runtime
560  *
561  * This loads the script, primes it and then runs the 'setup' function.
562  *
563  * \retval state Returns the set up luastate on success, NULL on error
564  */
565 static lua_State *LuaScriptSetup(const char *filename)
566 {
567  lua_State *luastate = LuaGetState();
568  if (luastate == NULL) {
569  SCLogError(SC_ERR_LUA_ERROR, "luaL_newstate failed");
570  goto error;
571  }
572 
573  luaL_openlibs(luastate);
574 
575  int status = luaL_loadfile(luastate, filename);
576  if (status) {
577  SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(luastate, -1));
578  goto error;
579  }
580 
581  /* prime the script */
582  if (lua_pcall(luastate, 0, 0, 0) != 0) {
583  SCLogError(SC_ERR_LUA_ERROR, "couldn't prime file: %s", lua_tostring(luastate, -1));
584  goto error;
585  }
586 
587  lua_getglobal(luastate, "setup");
588 
589  /* register functions common to all */
590  LuaRegisterFunctions(luastate);
591  /* unconditionally register http function. They will only work
592  * if the tx is registered in the state at runtime though. */
593  LuaRegisterHttpFunctions(luastate);
594  LuaRegisterDnsFunctions(luastate);
595  LuaRegisterJa3Functions(luastate);
596  LuaRegisterTlsFunctions(luastate);
597  LuaRegisterSshFunctions(luastate);
598  LuaRegisterHasshFunctions(luastate);
599  LuaRegisterSmtpFunctions(luastate);
600 
601  if (lua_pcall(luastate, 0, 0, 0) != 0) {
602  SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'setup' function: %s", lua_tostring(luastate, -1));
603  goto error;
604  }
605 
606  SCLogDebug("lua_State %p is set up", luastate);
607  return luastate;
608 error:
609  if (luastate)
610  LuaReturnState(luastate);
611  return NULL;
612 }
613 
614 static void LogLuaSubFree(OutputCtx *oc) {
615  if (oc->data)
616  SCFree(oc->data);
617  SCFree(oc);
618 }
619 
620 /** \brief initialize output for a script instance
621  *
622  * Runs script 'setup' function.
623  */
624 static OutputInitResult OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ctx)
625 {
626  OutputInitResult result = { NULL, false };
627  if (conf == NULL)
628  return result;
629 
630  LogLuaCtx *lua_ctx = SCMalloc(sizeof(LogLuaCtx));
631  if (unlikely(lua_ctx == NULL))
632  return result;
633  memset(lua_ctx, 0x00, sizeof(*lua_ctx));
634 
635  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
636  if (unlikely(output_ctx == NULL)) {
637  SCFree(lua_ctx);
638  return result;
639  }
640 
641  SCMutexInit(&lua_ctx->m, NULL);
642 
643  const char *dir = "";
644  if (parent_ctx && parent_ctx->data) {
645  LogLuaMasterCtx *mc = parent_ctx->data;
646  dir = mc->path;
647  }
648 
649  char path[PATH_MAX] = "";
650  int ret = snprintf(path, sizeof(path),"%s%s%s", dir, strlen(dir) ? "/" : "", conf->val);
651  if (ret < 0 || ret == sizeof(path)) {
652  SCLogError(SC_ERR_SPRINTF,"failed to construct lua script path");
653  goto error;
654  }
655  SCLogDebug("script full path %s", path);
656 
657  SCMutexLock(&lua_ctx->m);
658  lua_ctx->luastate = LuaScriptSetup(path);
659  SCMutexUnlock(&lua_ctx->m);
660  if (lua_ctx->luastate == NULL)
661  goto error;
662 
663  SCLogDebug("lua_ctx %p", lua_ctx);
664 
665  output_ctx->data = lua_ctx;
666  output_ctx->DeInit = LogLuaSubFree;
667 
668  result.ctx = output_ctx;
669  result.ok = true;
670  return result;
671 error:
672  SCMutexDestroy(&lua_ctx->m);
673  SCFree(lua_ctx);
674  SCFree(output_ctx);
675  return result;
676 }
677 
678 static void LogLuaMasterFree(OutputCtx *oc)
679 {
680  if (oc->data)
681  SCFree(oc->data);
682 
683  OutputModule *om, *tom;
684  TAILQ_FOREACH_SAFE(om, &oc->submodules, entries, tom) {
685  SCFree(om);
686  }
687  SCFree(oc);
688 }
689 
690 /** \internal
691  * \brief initialize output instance for lua module
692  *
693  * Parses nested script list, primes them to find out what they
694  * inspect, then fills the OutputCtx::submodules list with the
695  * proper Logger function for the data type the script needs.
696  */
697 static OutputInitResult OutputLuaLogInit(ConfNode *conf)
698 {
699  OutputInitResult result = { NULL, false };
700  const char *dir = ConfNodeLookupChildValue(conf, "scripts-dir");
701  if (dir == NULL)
702  dir = "";
703 
704  ConfNode *scripts = ConfNodeLookupChild(conf, "scripts");
705  if (scripts == NULL) {
706  /* No "outputs" section in the configuration. */
707  SCLogInfo("scripts not defined");
708  return result;
709  }
710 
711  /* global output ctx setup */
712  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
713  if (unlikely(output_ctx == NULL)) {
714  return result;
715  }
716  output_ctx->DeInit = LogLuaMasterFree;
717  output_ctx->data = SCCalloc(1, sizeof(LogLuaMasterCtx));
718  if (unlikely(output_ctx->data == NULL)) {
719  SCFree(output_ctx);
720  return result;
721  }
722  LogLuaMasterCtx *master_config = output_ctx->data;
723  strlcpy(master_config->path, dir, sizeof(master_config->path));
724  TAILQ_INIT(&output_ctx->submodules);
725 
726  /* check the enables scripts and set them up as submodules */
727  ConfNode *script;
728  TAILQ_FOREACH(script, &scripts->head, next) {
729  SCLogInfo("enabling script %s", script->val);
730  LogLuaScriptOptions opts;
731  memset(&opts, 0x00, sizeof(opts));
732 
733  char path[PATH_MAX] = "";
734  snprintf(path, sizeof(path),"%s%s%s", dir, strlen(dir) ? "/" : "", script->val);
735  SCLogDebug("script full path %s", path);
736 
737  int r = LuaScriptInit(path, &opts);
738  if (r != 0) {
739  SCLogError(SC_ERR_LUA_ERROR, "couldn't initialize script");
740  goto error;
741  }
742 
743  /* create an OutputModule for this script, based
744  * on it's needs. */
745  OutputModule *om = SCCalloc(1, sizeof(*om));
746  if (om == NULL) {
747  SCLogError(SC_ERR_MEM_ALLOC, "calloc() failed");
748  goto error;
749  }
750 
751  om->name = MODULE_NAME;
752  om->conf_name = script->val;
753  om->InitSubFunc = OutputLuaLogInitSub;
754  om->ThreadInit = LuaLogThreadInit;
755  om->ThreadDeinit = LuaLogThreadDeinit;
756 
757  if (opts.alproto == ALPROTO_HTTP1 && opts.streaming) {
758  om->StreamingLogFunc = LuaStreamingLogger;
760  om->alproto = ALPROTO_HTTP1;
763  } else if (opts.alproto == ALPROTO_HTTP1) {
764  om->TxLogFunc = LuaTxLogger;
765  om->alproto = ALPROTO_HTTP1;
766  om->ts_log_progress = -1;
767  om->tc_log_progress = -1;
769  } else if (opts.alproto == ALPROTO_TLS) {
770  om->TxLogFunc = LuaTxLogger;
771  om->alproto = ALPROTO_TLS;
775  } else if (opts.alproto == ALPROTO_DNS) {
776  om->TxLogFunc = LuaTxLogger;
777  om->alproto = ALPROTO_DNS;
778  om->ts_log_progress = -1;
779  om->tc_log_progress = -1;
782  } else if (opts.alproto == ALPROTO_SSH) {
783  om->TxLogFunc = LuaTxLogger;
784  om->alproto = ALPROTO_SSH;
787  } else if (opts.alproto == ALPROTO_SMTP) {
788  om->TxLogFunc = LuaTxLogger;
789  om->alproto = ALPROTO_SMTP;
790  om->ts_log_progress = -1;
791  om->tc_log_progress = -1;
793  } else if (opts.packet && opts.alerts) {
794  om->PacketLogFunc = LuaPacketLoggerAlerts;
795  om->PacketConditionFunc = LuaPacketConditionAlerts;
796  } else if (opts.packet && opts.alerts == 0) {
797  om->PacketLogFunc = LuaPacketLogger;
798  om->PacketConditionFunc = LuaPacketCondition;
799  } else if (opts.file) {
800  om->FileLogFunc = LuaFileLogger;
802  } else if (opts.streaming && opts.tcp_data) {
803  om->StreamingLogFunc = LuaStreamingLogger;
805  } else if (opts.flow) {
806  om->FlowLogFunc = LuaFlowLogger;
807  } else if (opts.stats) {
808  om->StatsLogFunc = LuaStatsLogger;
809  } else {
810  SCLogError(SC_ERR_LUA_ERROR, "failed to setup thread module");
811  SCFree(om);
812  goto error;
813  }
814 
815  TAILQ_INSERT_TAIL(&output_ctx->submodules, om, entries);
816  }
817 
818  result.ctx = output_ctx;
819  result.ok = true;
820  return result;
821 
822 error:
823  if (output_ctx->DeInit)
824  output_ctx->DeInit(output_ctx);
825 
826  int failure_fatal = 0;
827  if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) {
828  SCLogDebug("ConfGetBool could not load the value.");
829  }
830  if (failure_fatal) {
832  "Error during setup of lua output. Details should be "
833  "described in previous error messages. Shutting down...");
834  }
835 
836  return result;
837 }
838 
839 /** \internal
840  * \brief Run the scripts 'deinit' function
841  */
842 static void OutputLuaLogDoDeinit(LogLuaCtx *lua_ctx)
843 {
844  lua_State *luastate = lua_ctx->luastate;
845 
846  lua_getglobal(luastate, "deinit");
847  if (lua_type(luastate, -1) != LUA_TFUNCTION) {
848  SCLogError(SC_ERR_LUA_ERROR, "no deinit function in script");
849  return;
850  }
851  //LuaPrintStack(luastate);
852 
853  if (lua_pcall(luastate, 0, 0, 0) != 0) {
854  SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'deinit' function: %s", lua_tostring(luastate, -1));
855  return;
856  }
857  LuaReturnState(luastate);
858 }
859 
860 /** \internal
861  * \brief Initialize the thread storage for lua
862  *
863  * Currently only stores a pointer to the global LogLuaCtx
864  */
865 static TmEcode LuaLogThreadInit(ThreadVars *t, const void *initdata, void **data)
866 {
867  LogLuaThreadCtx *td = SCMalloc(sizeof(*td));
868  if (unlikely(td == NULL))
869  return TM_ECODE_FAILED;
870  memset(td, 0, sizeof(*td));
871 
872  if (initdata == NULL) {
873  SCLogDebug("Error getting context for LuaLog. \"initdata\" argument NULL");
874  SCFree(td);
875  return TM_ECODE_FAILED;
876  }
877 
878  LogLuaCtx *lua_ctx = ((OutputCtx *)initdata)->data;
879  SCLogDebug("lua_ctx %p", lua_ctx);
880  td->lua_ctx = lua_ctx;
881  *data = (void *)td;
882  return TM_ECODE_OK;
883 }
884 
885 /** \internal
886  * \brief Deinit the thread storage for lua
887  *
888  * Calls OutputLuaLogDoDeinit if no-one else already did.
889  */
890 static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data)
891 {
892  LogLuaThreadCtx *td = (LogLuaThreadCtx *)data;
893  if (td == NULL) {
894  return TM_ECODE_OK;
895  }
896 
897  SCMutexLock(&td->lua_ctx->m);
898  if (td->lua_ctx->deinit_once == 0) {
899  OutputLuaLogDoDeinit(td->lua_ctx);
900  td->lua_ctx->deinit_once = 1;
901  }
902  SCMutexUnlock(&td->lua_ctx->m);
903 
904  /* clear memory */
905  memset(td, 0, sizeof(*td));
906 
907  SCFree(td);
908  return TM_ECODE_OK;
909 }
910 
911 void LuaLogRegister(void) {
912  /* register as separate module */
913  OutputRegisterModule(MODULE_NAME, "lua", OutputLuaLogInit);
914 }
915 
916 #else /* HAVE_LUA */
917 
918 void LuaLogRegister (void) {
919  /* no-op */
920 }
921 
922 #endif /* HAVE_LUA */
lua_State
void lua_State
Definition: util-lua.h:31
tm-threads.h
Packet_::proto
uint8_t proto
Definition: decode.h:455
AppLayerHtpNeedFileInspection
void AppLayerHtpNeedFileInspection(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request file...
Definition: app-layer-htp.c:508
util-lua-ssh.h
PacketAlert_::s
const struct Signature_ * s
Definition: decode.h:275
app-layer-ssh.h
util-lua-hassh.h
util-lua-common.h
PACKET_ALERT_FLAG_TX
#define PACKET_ALERT_FLAG_TX
Definition: decode.h:287
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:262
ALPROTO_DNS
@ ALPROTO_DNS
Definition: app-layer-protos.h:41
PKT_IS_IPV6
#define PKT_IS_IPV6(p)
Definition: decode.h:254
ConfNode_::val
char * val
Definition: conf.h:34
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:472
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
ALPROTO_TLS
@ ALPROTO_TLS
Definition: app-layer-protos.h:33
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:296
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
Flow_::proto
uint8_t proto
Definition: flow.h:375
util-lua.h
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:80
PacketAlerts_::cnt
uint16_t cnt
Definition: decode.h:297
threads.h
OutputModule_::name
const char * name
Definition: output.h:56
OutputModule_::StreamingLogFunc
StreamingLogger StreamingLogFunc
Definition: output.h:73
Flow_
Flow data structure.
Definition: flow.h:353
OutputModule_::FileLogFunc
FileLogger FileLogFunc
Definition: output.h:70
util-lua-ja3.h
OutputModule_::ts_log_progress
int ts_log_progress
Definition: output.h:78
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
PacketAlerts_::alerts
PacketAlert * alerts
Definition: decode.h:300
OutputModule_::StatsLogFunc
StatsLogger StatsLogFunc
Definition: output.h:74
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
util-privs.h
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
m
SCMutex m
Definition: flow-hash.h:6
OutputModule_::InitSubFunc
OutputInitSubFunc InitSubFunc
Definition: output.h:60
ALPROTO_SSH
@ ALPROTO_SSH
Definition: app-layer-protos.h:34
StatsRecord_::pvalue
int64_t pvalue
Definition: output-stats.h:33
OutputModule_::PacketLogFunc
PacketLogger PacketLogFunc
Definition: output.h:66
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:83
OUTPUT_STREAMING_FLAG_TRANSACTION
#define OUTPUT_STREAMING_FLAG_TRANSACTION
Definition: output-streaming.h:34
OutputModule_::alproto
AppProto alproto
Definition: output.h:75
Packet_::alerts
PacketAlerts alerts
Definition: decode.h:588
util-unittest.h
OutputCtx_::data
void * data
Definition: tm-modules.h:81
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:82
PacketAlert_::tx_id
uint64_t tx_id
Definition: decode.h:276
OutputCtx_
Definition: tm-modules.h:78
OutputModule_::stream_type
enum OutputStreamingType stream_type
Definition: output.h:76
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
MODULE_NAME
#define MODULE_NAME
Definition: alert-debuglog.c:62
app-layer-htp.h
OutputModule_::ThreadInit
ThreadInitFunc ThreadInit
Definition: output.h:62
SSHTxLogCondition
int SSHTxLogCondition(ThreadVars *tv, const Packet *p, void *state, void *tx, uint64_t tx_id)
Definition: app-layer-ssh.c:75
util-debug.h
OutputInitResult_::ctx
OutputCtx * ctx
Definition: output.h:45
OutputModule_::ThreadDeinit
ThreadDeinitFunc ThreadDeinit
Definition: output.h:63
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:32
AppLayerHtpEnableRequestBodyCallback
void AppLayerHtpEnableRequestBodyCallback(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request body...
Definition: app-layer-htp.c:466
AppLayerParserRegisterLogger
void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto)
Definition: app-layer-parser.c:492
OutputRegisterModule
void OutputRegisterModule(const char *, const char *, OutputInitFunc)
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:298
StatsRecord_::name
const char * name
Definition: output-stats.h:30
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:56
pkt-var.h
SC_ERR_LUA_ERROR
@ SC_ERR_LUA_ERROR
Definition: util-error.h:244
util-time.h
OutputInitResult_::ok
bool ok
Definition: output.h:46
app-layer-parser.h
TRUE
#define TRUE
Definition: suricata-common.h:33
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:281
StatsTable_
Definition: output-stats.h:36
FALSE
#define FALSE
Definition: suricata-common.h:34
StatsRecord_::value
int64_t value
Definition: output-stats.h:32
OutputModule_::conf_name
const char * conf_name
Definition: output.h:57
OutputModule_::FlowLogFunc
FlowLogger FlowLogFunc
Definition: output.h:72
Packet_
Definition: decode.h:433
SC_ERR_SPRINTF
@ SC_ERR_SPRINTF
Definition: util-error.h:42
conf.h
TmEcode
TmEcode
Definition: tm-threads-common.h:81
AppLayerHtpEnableResponseBodyCallback
void AppLayerHtpEnableResponseBodyCallback(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request body...
Definition: app-layer-htp.c:479
CreateTimeString
void CreateTimeString(const struct timeval *ts, char *str, size_t size)
Definition: util-time.c:278
util-proto-name.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:215
TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:329
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1124
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
StatsTable_::stats
StatsRecord * stats
Definition: output-stats.h:37
util-lua-smtp.h
ConfNodeLookupChild
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:770
PacketAlert_::flags
uint8_t flags
Definition: decode.h:274
File_::flags
uint16_t flags
Definition: util-file.h:76
File_
Definition: util-file.h:75
OutputInitResult_
Definition: output.h:44
Packet_::flow
struct Flow_ * flow
Definition: decode.h:470
OutputModule_::TxLogCondition
TxLoggerCondition TxLogCondition
Definition: output.h:69
flags
uint8_t flags
Definition: decode-gre.h:0
Packet_::ts
struct timeval ts
Definition: decode.h:476
suricata-common.h
OutputCtx_::DeInit
void(* DeInit)(struct OutputCtx_ *)
Definition: tm-modules.h:84
STREAMING_HTTP_BODIES
@ STREAMING_HTTP_BODIES
Definition: output-streaming.h:38
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:30
StatsRecord_::tm_name
const char * tm_name
Definition: output-stats.h:31
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:255
util-lua-dns.h
FatalError
#define FatalError(x,...)
Definition: util-debug.h:530
LuaLogRegister
void LuaLogRegister(void)
Definition: output-lua.c:918
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:31
OutputModule_::PacketConditionFunc
PacketLogCondition PacketConditionFunc
Definition: output.h:67
threadvars.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
FILE_LOGGED
#define FILE_LOGGED
Definition: util-file.h:53
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ConfNode_
Definition: conf.h:32
util-logopenfile.h
Flow_::alstate
void * alstate
Definition: flow.h:486
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
util-buffer.h
OutputModule_::TxLogFunc
TxLogger TxLogFunc
Definition: output.h:68
OutputModule_::tc_log_progress
int tc_log_progress
Definition: output.h:77
util-lua-tls.h
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
output-lua.h
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
PacketAlert_
Definition: decode.h:271
File_::txid
uint64_t txid
Definition: util-file.h:80
STREAMING_TCP_DATA
@ STREAMING_TCP_DATA
Definition: output-streaming.h:37
util-lua-http.h
OutputModule_
Definition: output.h:54
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:460
TLS_HANDSHAKE_DONE
@ TLS_HANDSHAKE_DONE
Definition: app-layer-ssl.h:78
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:302
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
StatsTable_::nstats
uint32_t nstats
Definition: output-stats.h:39
PKT_IS_IPV4
#define PKT_IS_IPV4(p)
Definition: decode.h:253
SCMutex
#define SCMutex
Definition: threads-debug.h:114
app-layer-ssl.h
debug.h
output.h
app-layer.h
ConfNodeLookupChildValue
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:798