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