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