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