Coverage Report

Created: 2025-11-16 07:09

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