• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22553697083

01 Mar 2026 09:58PM UTC coverage: 75.673% (+2.0%) from 73.687%
22553697083

Pull #14925

github

web-flow
Merge 288827f07 into 90823fa90
Pull Request #14925: hs: false positive coverity warning in a reference string v1

241615 of 319288 relevant lines covered (75.67%)

1333554.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.4
/src/detect-lua.c
1
/* Copyright (C) 2007-2025 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 "conf.h"
27

28
#include "decode.h"
29

30
#include "detect.h"
31
#include "detect-parse.h"
32

33
#include "detect-engine.h"
34
#include "detect-engine-buffer.h"
35
#include "detect-engine-mpm.h"
36
#include "detect-engine-build.h"
37

38
#include "detect-byte.h"
39

40
#include "flow.h"
41
#include "flow-var.h"
42
#include "flow-util.h"
43

44
#include "util-byte.h"
45

46
#include "util-unittest.h"
47
#include "util-unittest-helper.h"
48

49
#include "app-layer.h"
50
#include "app-layer-parser.h"
51
#include "app-layer-htp.h"
52
#include "app-layer-ssl.h"
53

54
#include "stream-tcp.h"
55

56
#include "detect-lua.h"
57
#include "detect-lua-extensions.h"
58

59
#include "util-var-name.h"
60

61
#include "util-lua.h"
62
#include "util-lua-builtins.h"
63
#include "util-lua-common.h"
64
#include "util-lua-sandbox.h"
65

66
static int DetectLuaMatch (DetectEngineThreadCtx *,
67
        Packet *, const Signature *, const SigMatchCtx *);
68
static int DetectLuaAppTxMatch (DetectEngineThreadCtx *det_ctx,
69
                                Flow *f, uint8_t flags,
70
                                void *state, void *txv, const Signature *s,
71
                                const SigMatchCtx *ctx);
72
static int DetectLuaSetup (DetectEngineCtx *, Signature *, const char *);
73
#ifdef UNITTESTS
74
static void DetectLuaRegisterTests(void);
75
#endif
76
static void DetectLuaFree(DetectEngineCtx *, void *);
77
static int g_lua_ja3_list_id = 0;
78
static int g_lua_ja3s_list_id = 0;
79

80
/**
81
 * \brief Registration function for keyword: lua
82
 */
83
void DetectLuaRegister(void)
84
{
33✔
85
    sigmatch_table[DETECT_LUA].name = "lua";
33✔
86
    sigmatch_table[DETECT_LUA].desc = "match via a lua script";
33✔
87
    sigmatch_table[DETECT_LUA].url = "/rules/rule-lua-scripting.html";
33✔
88
    sigmatch_table[DETECT_LUA].Match = DetectLuaMatch;
33✔
89
    sigmatch_table[DETECT_LUA].AppLayerTxMatch = DetectLuaAppTxMatch;
33✔
90
    sigmatch_table[DETECT_LUA].Setup = DetectLuaSetup;
33✔
91
    sigmatch_table[DETECT_LUA].Free  = DetectLuaFree;
33✔
92
#ifdef UNITTESTS
3✔
93
    sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests;
3✔
94
#endif
3✔
95

96
    g_lua_ja3_list_id = DetectBufferTypeRegister("ja3.lua");
33✔
97
    DetectAppLayerInspectEngineRegister("ja3.lua", ALPROTO_TLS, SIG_FLAG_TOSERVER,
33✔
98
            TLS_STATE_CLIENT_HELLO_DONE, DetectEngineInspectGenericList, NULL);
33✔
99
    DetectAppLayerInspectEngineRegister(
33✔
100
            "ja3.lua", ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL);
33✔
101

102
    g_lua_ja3s_list_id = DetectBufferTypeRegister("ja3s.lua");
33✔
103
    DetectAppLayerInspectEngineRegister("ja3s.lua", ALPROTO_TLS, SIG_FLAG_TOCLIENT,
33✔
104
            TLS_STATE_SERVER_HELLO_DONE, DetectEngineInspectGenericList, NULL);
33✔
105
    DetectAppLayerInspectEngineRegister(
33✔
106
            "ja3s.lua", ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1, DetectEngineInspectGenericList, NULL);
33✔
107

108
    SCLogDebug("registering lua rule option");
33✔
109
}
33✔
110

111
/* Flags for DetectLuaThreadData. */
112
#define FLAG_DATATYPE_PACKET                    BIT_U32(0)
10✔
113
#define FLAG_DATATYPE_PAYLOAD                   BIT_U32(1)
10✔
114
#define FLAG_DATATYPE_STREAM                    BIT_U32(2)
×
115
#define FLAG_LIST_JA3                           BIT_U32(3)
4✔
116
#define FLAG_LIST_JA3S                          BIT_U32(4)
4✔
117
#define FLAG_DATATYPE_BUFFER                    BIT_U32(22)
×
118
#define FLAG_ERROR_LOGGED                       BIT_U32(23)
×
119
#define FLAG_BLOCKED_FUNCTION_LOGGED            BIT_U32(24)
×
120
#define FLAG_INSTRUCTION_LIMIT_LOGGED           BIT_U32(25)
×
121
#define FLAG_MEMORY_LIMIT_LOGGED                BIT_U32(26)
×
122

123
#define DEFAULT_LUA_ALLOC_LIMIT       500000
7,955✔
124
#define DEFAULT_LUA_INSTRUCTION_LIMIT 500000
7,955✔
125

126
/** \brief dump stack from lua state to screen */
127
void LuaDumpStack(lua_State *state, const char *prefix)
128
{
×
129
    int size = lua_gettop(state);
×
130
    printf("%s: size %d\n", prefix, size);
×
131

132
    for (int i = 1; i <= size; i++) {
×
133
        int type = lua_type(state, i);
×
134
        printf("- %s: Stack size=%d, level=%d, type=%d, ", prefix, size, i, type);
×
135

136
        switch (type) {
×
137
            case LUA_TFUNCTION:
×
138
                printf("function %s", lua_tostring(state, i));
×
139
                break;
×
140
            case LUA_TBOOLEAN:
×
141
                printf("bool %s", lua_toboolean(state, i) ? "true" : "false");
×
142
                break;
×
143
            case LUA_TNUMBER:
×
144
                printf("number %g", lua_tonumber(state, i));
×
145
                break;
×
146
            case LUA_TSTRING:
×
147
                printf("string `%s'", lua_tostring(state, i));
×
148
                break;
×
149
            case LUA_TTABLE:
×
150
                printf("table `%s'", lua_tostring(state, i));
×
151
                break;
×
152
            default:
×
153
                printf("other %s", lua_typename(state, type));
×
154
                break;
×
155

156
        }
×
157
        printf("\n");
×
158
    }
×
159
}
×
160

161
static void LuaStateSetDetectLuaData(lua_State *state, DetectLuaData *data)
162
{
7,967✔
163
    lua_pushlightuserdata(state, (void *)&luaext_key_ld);
7,967✔
164
    lua_pushlightuserdata(state, (void *)data);
7,967✔
165
    lua_settable(state, LUA_REGISTRYINDEX);
7,967✔
166
}
7,967✔
167

168
/**
169
 * \brief Common function to run the Lua match function and process
170
 *     the return value.
171
 */
172
static int DetectLuaRunMatch(
173
        DetectEngineThreadCtx *det_ctx, const DetectLuaData *lua, DetectLuaThreadData *tlua)
174
{
24✔
175
    /* Reset instruction count. */
176
    SCLuaSbResetInstructionCounter(tlua->luastate);
24✔
177

178
    if (lua_pcall(tlua->luastate, 1, 1, 0) != 0) {
24✔
179
        const char *reason = lua_tostring(tlua->luastate, -1);
×
180
        SCLuaSbState *context = SCLuaSbGetContext(tlua->luastate);
×
181
        uint32_t flag = 0;
×
182
        if (context->blocked_function_error) {
×
183
            StatsCounterIncr(&det_ctx->tv->stats, det_ctx->lua_blocked_function_errors);
×
184
            flag = FLAG_BLOCKED_FUNCTION_LOGGED;
×
185
        } else if (context->instruction_count_error) {
×
186
            StatsCounterIncr(&det_ctx->tv->stats, det_ctx->lua_instruction_limit_errors);
×
187
            flag = FLAG_INSTRUCTION_LIMIT_LOGGED;
×
188
        } else if (context->memory_limit_error) {
×
189
            StatsCounterIncr(&det_ctx->tv->stats, det_ctx->lua_memory_limit_errors);
×
190
            reason = "memory limit exceeded";
×
191
            flag = FLAG_MEMORY_LIMIT_LOGGED;
×
192
        } else {
×
193
            flag = FLAG_ERROR_LOGGED;
×
194
        }
×
195

196
        /* Log once per thread per error type, the message from Lua
197
         * will include the filename. */
198
        if (!(tlua->flags & flag)) {
×
199
            SCLogWarning("Lua script failed to run successfully: %s", reason);
×
200
            tlua->flags |= flag;
×
201
        }
×
202

203
        StatsCounterIncr(&det_ctx->tv->stats, det_ctx->lua_rule_errors);
×
204
        while (lua_gettop(tlua->luastate) > 0) {
×
205
            lua_pop(tlua->luastate, 1);
×
206
        }
×
207
        SCReturnInt(0);
×
208
    }
×
209

210
    int match = 0;
24✔
211

212
    /* process returns from script */
213
    if (lua_gettop(tlua->luastate) > 0) {
24✔
214
        /* script returns a number (return 1 or return 0) */
215
        if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) {
24✔
216
            lua_Integer script_ret = lua_tointeger(tlua->luastate, 1);
24✔
217
            SCLogDebug("script_ret %lld", script_ret);
24✔
218
            lua_pop(tlua->luastate, 1);
24✔
219
            if (script_ret == 1)
24✔
220
                match = 1;
12✔
221
        } else {
24✔
222
            SCLogDebug("Unsupported datatype returned from Lua script");
×
223
        }
×
224
    }
24✔
225

226
    if (lua->negated) {
24✔
227
        if (match == 1)
×
228
            match = 0;
×
229
        else
×
230
            match = 1;
×
231
    }
×
232

233
    while (lua_gettop(tlua->luastate) > 0) {
24✔
234
        lua_pop(tlua->luastate, 1);
×
235
    }
×
236

237
    SCReturnInt(match);
24✔
238
}
24✔
239

240
int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, const Signature *s,
241
        const SigMatchData *smd, const uint8_t *buffer, uint32_t buffer_len, uint32_t offset,
242
        Flow *f)
243
{
×
244
    SCEnter();
×
245

246
    if (buffer == NULL || buffer_len == 0)
×
247
        SCReturnInt(0);
×
248

249
    DetectLuaData *lua = (DetectLuaData *)smd->ctx;
×
250
    if (lua == NULL)
×
251
        SCReturnInt(0);
×
252

253
    DetectLuaThreadData *tlua =
×
254
            (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id);
×
255
    if (tlua == NULL)
×
256
        SCReturnInt(0);
×
257

258
    /* disable bytes limit temporarily to allow the setup of buffer and other data the script will
259
     * use. */
260
    const uint64_t cfg_limit = SCLuaSbResetBytesLimit(tlua->luastate);
×
261

262
    LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, f, /* no packet in the ctx */ NULL, s, 0);
×
263

264
    /* prepare data to pass to script */
265
    lua_getglobal(tlua->luastate, "match");
×
266
    lua_newtable(tlua->luastate); /* stack at -1 */
×
267

268
    lua_pushliteral(tlua->luastate, "offset"); /* stack at -2 */
×
269
    lua_pushnumber(tlua->luastate, (int)(offset + 1));
×
270
    lua_settable(tlua->luastate, -3);
×
271

272
    lua_pushstring(tlua->luastate, lua->buffername); /* stack at -2 */
×
273
    LuaPushStringBuffer(tlua->luastate, (const uint8_t *)buffer, (size_t)buffer_len);
×
274
    lua_settable(tlua->luastate, -3);
×
275

276
    /* restore configured bytes limit and account for the allocations done for the setup above. */
277
    SCLuaSbRestoreBytesLimit(tlua->luastate, cfg_limit);
×
278
    SCLuaSbUpdateBytesLimit(tlua->luastate);
×
279
    int r = DetectLuaRunMatch(det_ctx, lua, tlua);
×
280
    /* restore configured limit */
281
    SCLuaSbRestoreBytesLimit(tlua->luastate, cfg_limit);
×
282
    SCReturnInt(r);
×
283
}
×
284

285
/**
286
 * \brief match the specified lua script
287
 *
288
 * \param t thread local vars
289
 * \param det_ctx pattern matcher thread local data
290
 * \param p packet
291
 * \param s signature being inspected
292
 * \param m sigmatch that we will cast into DetectLuaData
293
 *
294
 * \retval 0 no match
295
 * \retval 1 match
296
 */
297
static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx,
298
        Packet *p, const Signature *s, const SigMatchCtx *ctx)
299
{
8✔
300
    SCEnter();
8✔
301
    DetectLuaData *lua = (DetectLuaData *)ctx;
8✔
302
    if (lua == NULL)
8✔
303
        SCReturnInt(0);
×
304

305
    DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id);
8✔
306
    if (tlua == NULL)
8✔
307
        SCReturnInt(0);
×
308

309
    /* setup extension data for use in lua c functions */
310
    uint8_t flags = 0;
8✔
311
    if (p->flowflags & FLOW_PKT_TOSERVER)
8✔
312
        flags = STREAM_TOSERVER;
8✔
313
    else if (p->flowflags & FLOW_PKT_TOCLIENT)
×
314
        flags = STREAM_TOCLIENT;
×
315

316
    /* disable bytes limit temporarily to allow the setup of buffer and other data the script will
317
     * use. */
318
    const uint64_t cfg_limit = SCLuaSbResetBytesLimit(tlua->luastate);
8✔
319

320
    LuaStateSetThreadVars(tlua->luastate, det_ctx->tv);
8✔
321

322
    LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, p->flow, p, s, flags);
8✔
323

324
    if ((tlua->flags & FLAG_DATATYPE_PAYLOAD) && p->payload_len == 0)
8✔
325
        SCReturnInt(0);
×
326
    if ((tlua->flags & FLAG_DATATYPE_PACKET) && GET_PKT_LEN(p) == 0)
8✔
327
        SCReturnInt(0);
×
328

329
    lua_getglobal(tlua->luastate, "match");
8✔
330
    lua_newtable(tlua->luastate); /* stack at -1 */
8✔
331

332
    /* restore configured bytes limit and account for the allocations done for the setup above. */
333
    SCLuaSbRestoreBytesLimit(tlua->luastate, cfg_limit);
8✔
334
    SCLuaSbUpdateBytesLimit(tlua->luastate);
8✔
335
    int r = DetectLuaRunMatch(det_ctx, lua, tlua);
8✔
336
    /* restore configured limit */
337
    SCLuaSbRestoreBytesLimit(tlua->luastate, cfg_limit);
8✔
338
    SCReturnInt(r);
8✔
339
}
8✔
340

341
static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx,
342
        Flow *f, uint8_t flags, void *state,
343
        const Signature *s, const SigMatchCtx *ctx)
344
{
16✔
345
    SCEnter();
16✔
346
    DetectLuaData *lua = (DetectLuaData *)ctx;
16✔
347
    if (lua == NULL)
16✔
348
        SCReturnInt(0);
×
349

350
    DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id);
16✔
351
    if (tlua == NULL)
16✔
352
        SCReturnInt(0);
×
353

354
    /* disable bytes limit temporarily to allow the setup of buffer and other data the script will
355
     * use. */
356
    const uint64_t cfg_limit = SCLuaSbResetBytesLimit(tlua->luastate);
16✔
357

358
    /* setup extension data for use in lua c functions */
359
    LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, f, NULL, s, flags);
16✔
360

361
    lua_getglobal(tlua->luastate, "match");
16✔
362
    lua_newtable(tlua->luastate); /* stack at -1 */
16✔
363

364
    /* restore configured bytes limit and account for the allocations done for the setup above. */
365
    SCLuaSbRestoreBytesLimit(tlua->luastate, cfg_limit);
16✔
366
    SCLuaSbUpdateBytesLimit(tlua->luastate);
16✔
367
    int r = DetectLuaRunMatch(det_ctx, lua, tlua);
16✔
368
    /* restore configured limit */
369
    SCLuaSbRestoreBytesLimit(tlua->luastate, cfg_limit);
16✔
370
    SCReturnInt(r);
16✔
371
}
16✔
372

373
/**
374
 * \brief match the specified lua script in a list with a tx
375
 *
376
 * \param t thread local vars
377
 * \param det_ctx pattern matcher thread local data
378
 * \param s signature being inspected
379
 * \param m sigmatch that we will cast into DetectLuaData
380
 *
381
 * \retval 0 no match
382
 * \retval 1 match
383
 */
384
static int DetectLuaAppTxMatch (DetectEngineThreadCtx *det_ctx,
385
                                Flow *f, uint8_t flags,
386
                                void *state, void *txv, const Signature *s,
387
                                const SigMatchCtx *ctx)
388
{
16✔
389
    return DetectLuaAppMatchCommon(det_ctx, f, flags, state, s, ctx);
16✔
390
}
16✔
391

392
#ifdef UNITTESTS
393
/* if this ptr is set the lua setup functions will use this buffer as the
394
 * lua script instead of calling luaL_loadfile on the filename supplied. */
395
static const char *ut_script = NULL;
396
#endif
397

398
static void *DetectLuaThreadInit(void *data)
399
{
12✔
400
    int status;
12✔
401
    DetectLuaData *lua = (DetectLuaData *)data;
12✔
402
    BUG_ON(lua == NULL);
12✔
403

404
    DetectLuaThreadData *t = SCCalloc(1, sizeof(DetectLuaThreadData));
12✔
405
    if (unlikely(t == NULL)) {
12✔
406
        SCLogError("couldn't alloc ctx memory");
×
407
        return NULL;
×
408
    }
×
409

410
    t->flags = lua->flags;
12✔
411

412
    t->luastate = SCLuaSbStateNew(lua->alloc_limit, lua->instruction_limit);
12✔
413
    if (t->luastate == NULL) {
12✔
414
        SCLogError("luastate pool depleted");
×
415
        goto error;
×
416
    }
×
417

418
    if (lua->allow_restricted_functions) {
12✔
419
        luaL_openlibs(t->luastate);
×
420
        SCLuaRequirefBuiltIns(t->luastate);
×
421
    } else {
12✔
422
        SCLuaSbLoadLibs(t->luastate);
12✔
423
    }
12✔
424

425
    LuaStateSetDetectLuaData(t->luastate, lua);
12✔
426

427
    /* hackish, needed to allow unittests to pass buffers as scripts instead of files */
428
#ifdef UNITTESTS
12✔
429
    if (ut_script != NULL) {
12✔
430
        status = luaL_loadbuffer(t->luastate, ut_script, strlen(ut_script), "unittest");
12✔
431
        if (status) {
12✔
432
            SCLogError("couldn't load file: %s", lua_tostring(t->luastate, -1));
433
            goto error;
434
        }
435
    } else {
12✔
436
#endif
437
        status = luaL_loadfile(t->luastate, lua->filename);
×
438
        if (status) {
×
439
            SCLogError("couldn't load file: %s", lua_tostring(t->luastate, -1));
×
440
            goto error;
×
441
        }
×
442
#ifdef UNITTESTS
443
    }
444
#endif
12✔
445

446
    /* prime the script (or something) */
447
    if (lua_pcall(t->luastate, 0, 0, 0) != 0) {
12✔
448
        SCLogError("couldn't prime file: %s", lua_tostring(t->luastate, -1));
×
449
        goto error;
×
450
    }
×
451

452
    /* thread_init call */
453
    lua_getglobal(t->luastate, "thread_init");
12✔
454
    if (lua_isfunction(t->luastate, -1)) {
12✔
455
        if (lua_pcall(t->luastate, 0, 0, 0) != 0) {
12✔
456
            SCLogError("couldn't run script 'thread_init' function: %s",
×
457
                    lua_tostring(t->luastate, -1));
×
458
            goto error;
×
459
        }
×
460
    } else {
12✔
461
        lua_pop(t->luastate, 1);
×
462
    }
×
463

464
    return (void *)t;
12✔
465

466
error:
×
467
    if (t->luastate != NULL)
×
468
        SCLuaSbStateClose(t->luastate);
×
469
    SCFree(t);
×
470
    return NULL;
×
471
}
12✔
472

473
static void DetectLuaThreadFree(void *ctx)
474
{
12✔
475
    if (ctx != NULL) {
12✔
476
        DetectLuaThreadData *t = (DetectLuaThreadData *)ctx;
12✔
477
        if (t->luastate != NULL)
12✔
478
            SCLuaSbStateClose(t->luastate);
12✔
479
        SCFree(t);
12✔
480
    }
12✔
481
}
12✔
482

483
/**
484
 * \brief Parse the lua keyword
485
 *
486
 * \param de_ctx Pointer to the detection engine context
487
 * \param str Pointer to the user provided option
488
 *
489
 * \retval lua pointer to DetectLuaData on success
490
 * \retval NULL on failure
491
 */
492
static DetectLuaData *DetectLuaParse (DetectEngineCtx *de_ctx, const char *str)
493
{
7,955✔
494
    DetectLuaData *lua = NULL;
7,955✔
495

496
    /* We have a correct lua option */
497
    lua = SCCalloc(1, sizeof(DetectLuaData));
7,955✔
498
    if (unlikely(lua == NULL))
7,955✔
499
        goto error;
×
500

501
    if (strlen(str) && str[0] == '!') {
7,955✔
502
        lua->negated = 1;
5✔
503
        str++;
5✔
504
    }
5✔
505

506
    /* get full filename */
507
    lua->filename = DetectLoadCompleteSigPath(de_ctx, str);
7,955✔
508
    if (lua->filename == NULL) {
7,955✔
509
        goto error;
×
510
    }
×
511

512
    return lua;
7,955✔
513

514
error:
×
515
    DetectLuaFree(de_ctx, lua);
×
516
    return NULL;
×
517
}
7,955✔
518

519
static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const Signature *s)
520
{
7,955✔
521
    int status;
7,955✔
522

523
    lua_State *luastate = SCLuaSbStateNew(ld->alloc_limit, ld->instruction_limit);
7,955✔
524
    if (luastate == NULL)
7,955✔
525
        return -1;
×
526
    if (ld->allow_restricted_functions) {
7,955✔
527
        luaL_openlibs(luastate);
×
528
        SCLuaRequirefBuiltIns(luastate);
×
529
    } else {
7,955✔
530
        SCLuaSbLoadLibs(luastate);
7,955✔
531
    }
7,955✔
532
    LuaStateSetDetectLuaData(luastate, ld);
7,955✔
533

534
    /* hackish, needed to allow unittests to pass buffers as scripts instead of files */
535
#ifdef UNITTESTS
12✔
536
    if (ut_script != NULL) {
12✔
537
        status = luaL_loadbuffer(luastate, ut_script, strlen(ut_script), "unittest");
12✔
538
        if (status) {
12✔
539
            SCLogError("couldn't load file: %s", lua_tostring(luastate, -1));
540
            goto error;
541
        }
542
    } else {
12✔
543
#endif
544
        status = luaL_loadfile(luastate, ld->filename);
7,943✔
545
        if (status) {
7,943✔
546
            SCLogError("couldn't load file: %s", lua_tostring(luastate, -1));
7,943✔
547
            goto error;
7,943✔
548
        }
7,943✔
549
#ifdef UNITTESTS
550
    }
551
#endif
12✔
552

553
    /* prime the script (or something) */
554
    if (lua_pcall(luastate, 0, 0, 0) != 0) {
12✔
555
        SCLogError("couldn't prime file: %s", lua_tostring(luastate, -1));
×
556
        goto error;
×
557
    }
×
558

559
    lua_getglobal(luastate, "init");
12✔
560
    if (lua_type(luastate, -1) != LUA_TFUNCTION) {
12✔
561
        SCLogError("no init function in script");
×
562
        goto error;
×
563
    }
×
564

565
    /* Pass the signature as the first argument, setting up bytevars depends on
566
     * access to the signature. */
567
    lua_pushlightuserdata(luastate, (void *)s);
12✔
568

569
    if (lua_pcall(luastate, 1, 1, 0) != 0) {
12✔
570
        SCLogError("couldn't run script 'init' function: %s", lua_tostring(luastate, -1));
×
571
        goto error;
×
572
    }
×
573

574
    /* process returns from script */
575
    if (lua_gettop(luastate) == 0) {
12✔
576
        SCLogError("init function in script should return table, nothing returned");
×
577
        goto error;
×
578
    }
×
579
    if (lua_type(luastate, 1) != LUA_TTABLE) {
12✔
580
        SCLogError("init function in script should return table, returned is not table");
×
581
        goto error;
×
582
    }
×
583

584
    lua_pushnil(luastate);
12✔
585
    const char *k;
12✔
586
    while (lua_next(luastate, -2)) {
16✔
587
        k = lua_tostring(luastate, -2);
4✔
588
        if (k == NULL)
4✔
589
            continue;
×
590

591
        /* handle flowvar and bytes separately as they have a table as value */
592
        if (strcmp(k, "flowvar") == 0) {
4✔
593
            if (lua_istable(luastate, -1)) {
×
594
                lua_pushnil(luastate);
×
595
                while (lua_next(luastate, -2) != 0) {
×
596
                    /* value at -1, key is at -2 which we ignore */
597
                    const char *value = lua_tostring(luastate, -1);
×
598
                    SCLogDebug("value %s", value);
×
599
                    /* removes 'value'; keeps 'key' for next iteration */
600
                    lua_pop(luastate, 1);
×
601

602
                    if (ld->flowvars == DETECT_LUA_MAX_FLOWVARS) {
×
603
                        SCLogError("too many flowvars registered");
×
604
                        goto error;
×
605
                    }
×
606

607
                    uint32_t idx = VarNameStoreRegister(value, VAR_TYPE_FLOW_VAR);
×
608
                    if (unlikely(idx == 0))
×
609
                        goto error;
×
610
                    ld->flowvar[ld->flowvars++] = idx;
×
611
                    SCLogDebug("script uses flowvar %u with script id %u", idx, ld->flowvars - 1);
×
612
                }
×
613
            }
×
614
            lua_pop(luastate, 1);
×
615
            continue;
×
616
        } else if (strcmp(k, "flowint") == 0) {
4✔
617
            if (lua_istable(luastate, -1)) {
×
618
                lua_pushnil(luastate);
×
619
                while (lua_next(luastate, -2) != 0) {
×
620
                    /* value at -1, key is at -2 which we ignore */
621
                    const char *value = lua_tostring(luastate, -1);
×
622
                    SCLogDebug("value %s", value);
×
623
                    /* removes 'value'; keeps 'key' for next iteration */
624
                    lua_pop(luastate, 1);
×
625

626
                    if (ld->flowints == DETECT_LUA_MAX_FLOWINTS) {
×
627
                        SCLogError("too many flowints registered");
×
628
                        goto error;
×
629
                    }
×
630

631
                    uint32_t idx = VarNameStoreRegister(value, VAR_TYPE_FLOW_INT);
×
632
                    if (unlikely(idx == 0))
×
633
                        goto error;
×
634
                    ld->flowint[ld->flowints++] = idx;
×
635
                    SCLogDebug("script uses flowint %u with script id %u", idx, ld->flowints - 1);
×
636
                }
×
637
            }
×
638
            lua_pop(luastate, 1);
×
639
            continue;
×
640
        }
×
641

642
        bool required = lua_toboolean(luastate, -1);
4✔
643
        lua_pop(luastate, 1);
4✔
644
        if (!required) {
4✔
645
            continue;
×
646
        }
×
647

648
        if (strcmp(k, "ja3") == 0) {
4✔
649
            ld->flags |= FLAG_LIST_JA3;
×
650
        } else if (strcmp(k, "ja3s") == 0) {
4✔
651
            ld->flags |= FLAG_LIST_JA3S;
×
652
        } else if (strcmp(k, "packet") == 0) {
4✔
653
            ld->flags |= FLAG_DATATYPE_PACKET;
2✔
654
        } else if (strcmp(k, "payload") == 0) {
2✔
655
            ld->flags |= FLAG_DATATYPE_PAYLOAD;
2✔
656
        } else if (strcmp(k, "buffer") == 0) {
2✔
657
            ld->flags |= FLAG_DATATYPE_BUFFER;
×
658

659
            ld->buffername = SCStrdup("buffer");
×
660
            if (ld->buffername == NULL) {
×
661
                SCLogError("alloc error");
×
662
                goto error;
×
663
            }
×
664
        } else if (strcmp(k, "stream") == 0) {
×
665
            ld->flags |= FLAG_DATATYPE_STREAM;
×
666

667
            ld->buffername = SCStrdup("stream");
×
668
            if (ld->buffername == NULL) {
×
669
                SCLogError("alloc error");
×
670
                goto error;
×
671
            }
×
672
            /* old options no longer supported */
673
        } else if (strncmp(k, "http", 4) == 0 || strncmp(k, "dns", 3) == 0 ||
×
674
                   strncmp(k, "tls", 3) == 0 || strncmp(k, "ssh", 3) == 0 ||
×
675
                   strncmp(k, "smtp", 4) == 0 || strncmp(k, "dnp3", 4) == 0) {
×
676
            SCLogError("data type %s no longer supported, use rule hooks", k);
×
677
            goto error;
×
678

679
        } else {
×
680
            SCLogError("unsupported data type %s", k);
×
681
            goto error;
×
682
        }
×
683
    }
4✔
684

685
    /* pop the table */
686
    lua_pop(luastate, 1);
12✔
687
    SCLuaSbStateClose(luastate);
12✔
688
    return 0;
12✔
689
error:
7,943✔
690
    SCLuaSbStateClose(luastate);
7,943✔
691
    return -1;
7,943✔
692
}
12✔
693

694
/**
695
 * \brief this function is used to parse lua options
696
 * \brief into the current signature
697
 *
698
 * \param de_ctx pointer to the Detection Engine Context
699
 * \param s pointer to the Current Signature
700
 * \param str pointer to the user provided "lua" option
701
 *
702
 * \retval 0 on Success
703
 * \retval -1 on Failure
704
 */
705
static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
706
{
7,955✔
707
    /* First check if Lua rules are enabled, by default Lua in rules
708
     * is disabled. */
709
    int enabled = 0;
7,955✔
710
    if (SCConfGetBool("security.lua.allow-rules", &enabled) == 1 && !enabled) {
7,955✔
711
        SCLogError("Lua rules disabled by security configuration: security.lua.allow-rules");
×
712
        return -1;
×
713
    }
×
714

715
    DetectLuaData *lua = DetectLuaParse(de_ctx, str);
7,955✔
716
    if (lua == NULL)
7,955✔
717
        return -1;
×
718

719
    /* Load lua sandbox configurations */
720
    intmax_t lua_alloc_limit = DEFAULT_LUA_ALLOC_LIMIT;
7,955✔
721
    intmax_t lua_instruction_limit = DEFAULT_LUA_INSTRUCTION_LIMIT;
7,955✔
722
    (void)SCConfGetInt("security.lua.max-bytes", &lua_alloc_limit);
7,955✔
723
    (void)SCConfGetInt("security.lua.max-instructions", &lua_instruction_limit);
7,955✔
724
    lua->alloc_limit = lua_alloc_limit;
7,955✔
725
    lua->instruction_limit = lua_instruction_limit;
7,955✔
726

727
    int allow_restricted_functions = 0;
7,955✔
728
    (void)SCConfGetBool("security.lua.allow-restricted-functions", &allow_restricted_functions);
7,955✔
729
    lua->allow_restricted_functions = allow_restricted_functions;
7,955✔
730

731
    if (DetectLuaSetupPrime(de_ctx, lua, s) == -1) {
7,955✔
732
        goto error;
7,943✔
733
    }
7,943✔
734

735
    lua->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "lua",
12✔
736
            DetectLuaThreadInit, (void *)lua,
12✔
737
            DetectLuaThreadFree, 0);
12✔
738
    if (lua->thread_ctx_id == -1)
12✔
739
        goto error;
×
740

741
    int list = DetectBufferGetActiveList(de_ctx, s);
12✔
742
    SCLogDebug("buffer list %d -> %d", list, s->init_data->list);
12✔
743
    if (list == -1 || (list == 0 && s->init_data->list == INT_MAX)) {
12✔
744
        /* what needs to happen here is: we register to the rule hook, so e.g.
745
         * http1.request_complete. This means we need a list.
746
         *
747
         * This includes each pkt, payload, stream, etc. */
748

749
        if (s->init_data->hook.type != SIGNATURE_HOOK_TYPE_NOT_SET) {
12✔
750
            list = s->init_data->hook.sm_list;
8✔
751
            SCLogDebug("setting list %d", list);
8✔
752
        }
8✔
753
    }
12✔
754

755
    if (list == -1) {
12✔
756
        SCLogError("lua failed to set up");
×
757
        goto error;
×
758
    }
×
759
    if (list == 0) {
12✔
760
        if (lua->flags & FLAG_LIST_JA3) {
4✔
761
            list = g_lua_ja3_list_id;
×
762
        } else if (lua->flags & FLAG_LIST_JA3S) {
4✔
763
            list = g_lua_ja3s_list_id;
×
764
        }
×
765
    }
4✔
766

767
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_LUA, (SigMatchCtx *)lua, list) == NULL) {
12✔
768
        goto error;
×
769
    }
×
770

771
    return 0;
12✔
772

773
error:
7,943✔
774
    if (lua != NULL)
7,943✔
775
        DetectLuaFree(de_ctx, lua);
7,943✔
776
    return -1;
7,943✔
777
}
12✔
778

779
/**
780
 * \brief this function will free memory associated with DetectLuaData
781
 *
782
 * \param ptr pointer to DetectLuaData
783
 */
784
static void DetectLuaFree(DetectEngineCtx *de_ctx, void *ptr)
785
{
7,955✔
786
    if (ptr != NULL) {
7,955✔
787
        DetectLuaData *lua = (DetectLuaData *)ptr;
7,955✔
788

789
        if (lua->buffername)
7,955✔
790
            SCFree(lua->buffername);
×
791
        if (lua->filename)
7,955✔
792
            SCFree(lua->filename);
7,955✔
793

794
        for (uint16_t i = 0; i < lua->flowints; i++) {
7,961✔
795
            VarNameStoreUnregister(lua->flowint[i], VAR_TYPE_FLOW_INT);
6✔
796
        }
6✔
797
        for (uint16_t i = 0; i < lua->flowvars; i++) {
7,961✔
798
            VarNameStoreUnregister(lua->flowvar[i], VAR_TYPE_FLOW_VAR);
6✔
799
        }
6✔
800
        for (uint16_t i = 0; i < lua->bytevars; i++) {
7,955✔
801
            SCFree(lua->bytevar[i].name);
×
802
        }
×
803

804
        DetectUnregisterThreadCtxFuncs(de_ctx, lua, "lua");
7,955✔
805

806
        SCFree(lua);
7,955✔
807
    }
7,955✔
808
}
7,955✔
809

810
#ifdef UNITTESTS
811
#include "detect-engine-alert.h"
812

813
/** \test http buffer */
814
static int LuaMatchTest01(void)
815
{
1✔
816
    SCConfSetFinal("security.lua.allow-rules", "true");
1✔
817

818
    const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
1✔
819
                          "function init (args)\n"
1✔
820
                          "   flowvarlib.register(\"cnt\")\n"
1✔
821
                          "   return {}\n"
1✔
822
                          "end\n"
1✔
823
                          "function thread_init (args)\n"
1✔
824
                          "   cnt = flowvarlib.get(\"cnt\")\n"
1✔
825
                          "end\n"
1✔
826
                          "\n"
1✔
827
                          "function match(args)\n"
1✔
828
                          "   a = cnt:value()\n"
1✔
829
                          "   if a then\n"
1✔
830
                          "       a = tostring(tonumber(a)+1)\n"
1✔
831
                          "       print (a)\n"
1✔
832
                          "       cnt:set(a, #a)\n"
1✔
833
                          "   else\n"
1✔
834
                          "       a = tostring(1)\n"
1✔
835
                          "       print (a)\n"
1✔
836
                          "       cnt:set(a, #a)\n"
1✔
837
                          "   end\n"
1✔
838
                          "   \n"
1✔
839
                          "   print (\"pre check: \" .. (a))\n"
1✔
840
                          "   if tonumber(a) == 2 then\n"
1✔
841
                          "       print \"match\"\n"
1✔
842
                          "       return 1\n"
1✔
843
                          "   end\n"
1✔
844
                          "   return 0\n"
1✔
845
                          "end\n"
1✔
846
                          "return 0\n";
1✔
847
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
848
                 "sid:1;)";
1✔
849
    uint8_t httpbuf1[] =
1✔
850
        "POST / HTTP/1.1\r\n"
1✔
851
        "Host: www.emergingthreats.net\r\n\r\n";
1✔
852
    uint8_t httpbuf2[] =
1✔
853
        "POST / HTTP/1.1\r\n"
1✔
854
        "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
855
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
856
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
857
    TcpSession ssn;
1✔
858
    Flow f;
1✔
859
    ThreadVars th_v;
1✔
860
    DetectEngineThreadCtx *det_ctx;
1✔
861

862
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
863

864
    ut_script = script;
1✔
865

866
    memset(&th_v, 0, sizeof(th_v));
1✔
867
    StatsThreadInit(&th_v.stats);
1✔
868
    memset(&f, 0, sizeof(f));
1✔
869
    memset(&ssn, 0, sizeof(ssn));
1✔
870

871
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
872
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
873

874
    FLOW_INITIALIZE(&f);
1✔
875
    f.protoctx = (void *)&ssn;
1✔
876
    f.proto = IPPROTO_TCP;
1✔
877
    f.flags |= FLOW_IPV4;
1✔
878
    f.alproto = ALPROTO_HTTP1;
1✔
879

880
    p1->flow = &f;
1✔
881
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
882
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
883
    p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
884
    p2->flow = &f;
1✔
885
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
886
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
887
    p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
888

889
    StreamTcpInitConfig(true);
1✔
890

891
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
892
    FAIL_IF_NULL(de_ctx);
1✔
893
    de_ctx->flags |= DE_QUIET;
1✔
894

895
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
896
    FAIL_IF_NULL(s);
1✔
897

898
    SigGroupBuild(de_ctx);
1✔
899
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
900

901
    int r = AppLayerParserParse(
1✔
902
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
903
    FAIL_IF(r != 0);
1✔
904
    HtpState *http_state = f.alstate;
1✔
905
    FAIL_IF_NULL(http_state);
1✔
906

907
    /* do detect for p1 */
908
    SCLogDebug("inspecting p1");
1✔
909
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
910
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
911

912
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
913
    FAIL_IF(r != 0);
1✔
914

915
    /* do detect for p2 */
916
    SCLogDebug("inspecting p2");
1✔
917
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
918
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
919

920
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_VAR);
1✔
921
    FAIL_IF(id == 0);
1✔
922

923
    FlowVar *fv = FlowVarGet(&f, id);
1✔
924
    FAIL_IF_NULL(fv);
1✔
925
    FAIL_IF(fv->data.fv_str.value_len != 1);
1✔
926
    FAIL_IF(memcmp(fv->data.fv_str.value, "2", 1) != 0);
1✔
927

928
    UTHFreePackets(&p1, 1);
1✔
929
    UTHFreePackets(&p2, 1);
1✔
930
    FLOW_DESTROY(&f);
1✔
931

932
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
933
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
934
    DetectEngineCtxFree(de_ctx);
1✔
935
    StreamTcpFreeConfig(true);
1✔
936
    StatsThreadCleanup(&th_v.stats);
1✔
937
    PASS;
1✔
938
}
1✔
939

940
static int LuaMatchTest01a(void)
941
{
1✔
942
    const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
1✔
943
                          "function init (args)\n"
1✔
944
                          "   flowvarlib.register(\"cnt\")\n"
1✔
945
                          "   return {}\n"
1✔
946
                          "end\n"
1✔
947
                          "function thread_init (args)\n"
1✔
948
                          "   cnt = flowvarlib.get(\"cnt\")\n"
1✔
949
                          "end\n"
1✔
950
                          "\n"
1✔
951
                          "function match(args)\n"
1✔
952
                          "   a = cnt:value(0)\n"
1✔
953
                          "   if a then\n"
1✔
954
                          "       a = tostring(tonumber(a)+1)\n"
1✔
955
                          "       print (a)\n"
1✔
956
                          "       cnt:set(a, #a)\n"
1✔
957
                          "   else\n"
1✔
958
                          "       a = tostring(1)\n"
1✔
959
                          "       print (a)\n"
1✔
960
                          "       cnt:set(a, #a)\n"
1✔
961
                          "   end\n"
1✔
962
                          "   \n"
1✔
963
                          "   print (\"pre check: \" .. (a))\n"
1✔
964
                          "   if tonumber(a) == 2 then\n"
1✔
965
                          "       print \"match\"\n"
1✔
966
                          "       return 1\n"
1✔
967
                          "   end\n"
1✔
968
                          "   return 0\n"
1✔
969
                          "end\n"
1✔
970
                          "return 0\n";
1✔
971
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
972
                 "sid:1;)";
1✔
973
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"
1✔
974
                         "Host: www.emergingthreats.net\r\n\r\n";
1✔
975
    uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n"
1✔
976
                         "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
977
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
978
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
979
    TcpSession ssn;
1✔
980
    Flow f;
1✔
981
    ThreadVars th_v;
1✔
982
    DetectEngineThreadCtx *det_ctx;
1✔
983

984
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
985

986
    ut_script = script;
1✔
987

988
    memset(&th_v, 0, sizeof(th_v));
1✔
989
    StatsThreadInit(&th_v.stats);
1✔
990
    memset(&f, 0, sizeof(f));
1✔
991
    memset(&ssn, 0, sizeof(ssn));
1✔
992

993
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
994
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
995

996
    FLOW_INITIALIZE(&f);
1✔
997
    f.protoctx = (void *)&ssn;
1✔
998
    f.proto = IPPROTO_TCP;
1✔
999
    f.flags |= FLOW_IPV4;
1✔
1000
    f.alproto = ALPROTO_HTTP1;
1✔
1001

1002
    p1->flow = &f;
1✔
1003
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1004
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1005
    p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1006
    p2->flow = &f;
1✔
1007
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1008
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1009
    p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1010

1011
    StreamTcpInitConfig(true);
1✔
1012

1013
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1014
    FAIL_IF_NULL(de_ctx);
1✔
1015
    de_ctx->flags |= DE_QUIET;
1✔
1016

1017
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1018
    FAIL_IF_NULL(s);
1✔
1019

1020
    SigGroupBuild(de_ctx);
1✔
1021
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1022

1023
    int r = AppLayerParserParse(
1✔
1024
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
1025
    FAIL_IF(r != 0);
1✔
1026

1027
    HtpState *http_state = f.alstate;
1✔
1028
    FAIL_IF_NULL(http_state);
1✔
1029

1030
    /* do detect for p1 */
1031
    SCLogDebug("inspecting p1");
1✔
1032
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1033
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1034

1035
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
1036
    FAIL_IF(r != 0);
1✔
1037
    /* do detect for p2 */
1038
    SCLogDebug("inspecting p2");
1✔
1039
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1040
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1041

1042
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_VAR);
1✔
1043
    FAIL_IF(id == 0);
1✔
1044

1045
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1046
    FAIL_IF_NULL(fv);
1✔
1047
    FAIL_IF(fv->data.fv_str.value_len != 1);
1✔
1048
    FAIL_IF(memcmp(fv->data.fv_str.value, "2", 1) != 0);
1✔
1049

1050
    UTHFreePackets(&p1, 1);
1✔
1051
    UTHFreePackets(&p2, 1);
1✔
1052
    FLOW_DESTROY(&f);
1✔
1053

1054
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
1055
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1056
    DetectEngineCtxFree(de_ctx);
1✔
1057
    StreamTcpFreeConfig(true);
1✔
1058
    StatsThreadCleanup(&th_v.stats);
1✔
1059
    PASS;
1✔
1060
}
1✔
1061

1062
/** \test payload buffer */
1063
static int LuaMatchTest02(void)
1064
{
1✔
1065
    const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
1✔
1066
                          "function init (args)\n"
1✔
1067
                          "   flowvarlib.register(\"cnt\")\n"
1✔
1068
                          "   local needs = {}\n"
1✔
1069
                          "   needs[\"payload\"] = tostring(true)\n"
1✔
1070
                          "   return needs\n"
1✔
1071
                          "end\n"
1✔
1072
                          "function thread_init (args)\n"
1✔
1073
                          "   cnt = flowvarlib.get(\"cnt\")\n"
1✔
1074
                          "end\n"
1✔
1075
                          "\n"
1✔
1076
                          "function match(args)\n"
1✔
1077
                          "   a = cnt:value()\n"
1✔
1078
                          "   if a then\n"
1✔
1079
                          "       a = tostring(tonumber(a)+1)\n"
1✔
1080
                          "       print (a)\n"
1✔
1081
                          "       cnt:set(a, #a)\n"
1✔
1082
                          "   else\n"
1✔
1083
                          "       a = tostring(1)\n"
1✔
1084
                          "       print (a)\n"
1✔
1085
                          "       cnt:set(a, #a)\n"
1✔
1086
                          "   end\n"
1✔
1087
                          "   \n"
1✔
1088
                          "   print (\"pre check: \" .. (a))\n"
1✔
1089
                          "   if tonumber(a) == 2 then\n"
1✔
1090
                          "       print \"match\"\n"
1✔
1091
                          "       return 1\n"
1✔
1092
                          "   end\n"
1✔
1093
                          "   return 0\n"
1✔
1094
                          "end\n"
1✔
1095
                          "return 0\n";
1✔
1096
    char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1✔
1097
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"
1✔
1098
                         "Host: www.emergingthreats.net\r\n\r\n";
1✔
1099
    uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n"
1✔
1100
                         "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1101
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1102
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1103
    TcpSession ssn;
1✔
1104
    Flow f;
1✔
1105
    ThreadVars th_v;
1✔
1106
    DetectEngineThreadCtx *det_ctx;
1✔
1107

1108
    ut_script = script;
1✔
1109

1110
    memset(&th_v, 0, sizeof(th_v));
1✔
1111
    StatsThreadInit(&th_v.stats);
1✔
1112
    memset(&f, 0, sizeof(f));
1✔
1113
    memset(&ssn, 0, sizeof(ssn));
1✔
1114

1115
    Packet *p1 = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP);
1✔
1116
    Packet *p2 = UTHBuildPacket(httpbuf2, httplen2, IPPROTO_TCP);
1✔
1117

1118
    FLOW_INITIALIZE(&f);
1✔
1119
    f.protoctx = (void *)&ssn;
1✔
1120
    f.proto = IPPROTO_TCP;
1✔
1121
    f.flags |= FLOW_IPV4;
1✔
1122
    f.alproto = ALPROTO_HTTP1;
1✔
1123

1124
    p1->flow = &f;
1✔
1125
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1126
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1127
    p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1128
    p2->flow = &f;
1✔
1129
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1130
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1131
    p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1132

1133
    StreamTcpInitConfig(true);
1✔
1134

1135
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1136
    FAIL_IF_NULL(de_ctx);
1✔
1137
    de_ctx->flags |= DE_QUIET;
1✔
1138

1139
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1140
    FAIL_IF_NULL(s);
1✔
1141

1142
    SigGroupBuild(de_ctx);
1✔
1143
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1144

1145
    /* do detect for p1 */
1146
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1147

1148
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1149

1150
    /* do detect for p2 */
1151
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1152

1153
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1154

1155
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_VAR);
1✔
1156
    FAIL_IF(id == 0);
1✔
1157

1158
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1159
    FAIL_IF_NULL(fv);
1✔
1160
    FAIL_IF(fv->data.fv_str.value_len != 1);
1✔
1161
    FAIL_IF(memcmp(fv->data.fv_str.value, "2", 1) != 0);
1✔
1162

1163
    UTHFreePackets(&p1, 1);
1✔
1164
    UTHFreePackets(&p2, 1);
1✔
1165
    FLOW_DESTROY(&f);
1✔
1166

1167
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1168
    DetectEngineCtxFree(de_ctx);
1✔
1169
    StreamTcpFreeConfig(true);
1✔
1170
    StatsThreadCleanup(&th_v.stats);
1✔
1171
    PASS;
1✔
1172
}
1✔
1173

1174
/** \test payload buffer */
1175
static int LuaMatchTest02a(void)
1176
{
1✔
1177
    const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
1✔
1178
                          "function init (args)\n"
1✔
1179
                          "   flowvarlib.register(\"cnt\")"
1✔
1180
                          "   local needs = {}\n"
1✔
1181
                          "   needs[\"payload\"] = tostring(true)\n"
1✔
1182
                          "   return needs\n"
1✔
1183
                          "end\n"
1✔
1184
                          "function thread_init (args)\n"
1✔
1185
                          "   cnt = flowvarlib.get(\"cnt\")"
1✔
1186
                          "end\n"
1✔
1187
                          "\n"
1✔
1188
                          "function match(args)\n"
1✔
1189
                          "   a = cnt:value()\n"
1✔
1190
                          "   if a then\n"
1✔
1191
                          "       a = tostring(tonumber(a)+1)\n"
1✔
1192
                          "       print (a)\n"
1✔
1193
                          "       cnt:set(a, #a)\n"
1✔
1194
                          "   else\n"
1✔
1195
                          "       a = tostring(1)\n"
1✔
1196
                          "       print (a)\n"
1✔
1197
                          "       cnt:set(a, #a)\n"
1✔
1198
                          "   end\n"
1✔
1199
                          "   \n"
1✔
1200
                          "   print (\"pre check: \" .. (a))\n"
1✔
1201
                          "   if tonumber(a) == 2 then\n"
1✔
1202
                          "       print \"match\"\n"
1✔
1203
                          "       return 1\n"
1✔
1204
                          "   end\n"
1✔
1205
                          "   return 0\n"
1✔
1206
                          "end\n"
1✔
1207
                          "return 0\n";
1✔
1208
    char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1✔
1209
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"
1✔
1210
                         "Host: www.emergingthreats.net\r\n\r\n";
1✔
1211
    uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n"
1✔
1212
                         "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1213
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1214
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1215
    TcpSession ssn;
1✔
1216
    Flow f;
1✔
1217
    ThreadVars th_v;
1✔
1218
    DetectEngineThreadCtx *det_ctx;
1✔
1219

1220
    ut_script = script;
1✔
1221

1222
    memset(&th_v, 0, sizeof(th_v));
1✔
1223
    StatsThreadInit(&th_v.stats);
1✔
1224
    memset(&f, 0, sizeof(f));
1✔
1225
    memset(&ssn, 0, sizeof(ssn));
1✔
1226

1227
    Packet *p1 = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP);
1✔
1228
    Packet *p2 = UTHBuildPacket(httpbuf2, httplen2, IPPROTO_TCP);
1✔
1229

1230
    FLOW_INITIALIZE(&f);
1✔
1231
    f.protoctx = (void *)&ssn;
1✔
1232
    f.proto = IPPROTO_TCP;
1✔
1233
    f.flags |= FLOW_IPV4;
1✔
1234
    f.alproto = ALPROTO_HTTP1;
1✔
1235

1236
    p1->flow = &f;
1✔
1237
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1238
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1239
    p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1240
    p2->flow = &f;
1✔
1241
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1242
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1243
    p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1244

1245
    StreamTcpInitConfig(true);
1✔
1246

1247
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1248
    FAIL_IF_NULL(de_ctx);
1✔
1249
    de_ctx->flags |= DE_QUIET;
1✔
1250

1251
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1252
    FAIL_IF_NULL(s);
1✔
1253

1254
    SigGroupBuild(de_ctx);
1✔
1255
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1256

1257
    /* do detect for p1 */
1258
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1259
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1260

1261
    /* do detect for p2 */
1262
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1263
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1264

1265
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_VAR);
1✔
1266
    FAIL_IF(id == 0);
1✔
1267

1268
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1269
    FAIL_IF_NULL(fv);
1✔
1270
    FAIL_IF(fv->data.fv_str.value_len != 1);
1✔
1271
    FAIL_IF(memcmp(fv->data.fv_str.value, "2", 1) != 0);
1✔
1272

1273
    UTHFreePackets(&p1, 1);
1✔
1274
    UTHFreePackets(&p2, 1);
1✔
1275
    FLOW_DESTROY(&f);
1✔
1276

1277
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1278
    DetectEngineCtxFree(de_ctx);
1✔
1279
    StreamTcpFreeConfig(true);
1✔
1280
    StatsThreadCleanup(&th_v.stats);
1✔
1281
    PASS;
1✔
1282
}
1✔
1283

1284
/** \test packet buffer */
1285
static int LuaMatchTest03(void)
1286
{
1✔
1287
    const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
1✔
1288
                          "function init (args)\n"
1✔
1289
                          "   flowvarlib.register(\"cnt\")\n"
1✔
1290
                          "   local needs = {}\n"
1✔
1291
                          "   needs[\"packet\"] = tostring(true)\n"
1✔
1292
                          "   return needs\n"
1✔
1293
                          "end\n"
1✔
1294
                          "\n"
1✔
1295
                          "function thread_init (args)\n"
1✔
1296
                          "   cnt = flowvarlib.get(\"cnt\")\n"
1✔
1297
                          "end\n"
1✔
1298
                          "\n"
1✔
1299
                          "function match(args)\n"
1✔
1300
                          "   a = cnt:value()\n"
1✔
1301
                          "   if a then\n"
1✔
1302
                          "       a = tostring(tonumber(a)+1)\n"
1✔
1303
                          "       print (a)\n"
1✔
1304
                          "       cnt:set(a, #a)\n"
1✔
1305
                          "   else\n"
1✔
1306
                          "       a = tostring(1)\n"
1✔
1307
                          "       print (a)\n"
1✔
1308
                          "       cnt:set(a, #a)\n"
1✔
1309
                          "   end\n"
1✔
1310
                          "   \n"
1✔
1311
                          "   print (\"pre check: \" .. (a))\n"
1✔
1312
                          "   if tonumber(a) == 2 then\n"
1✔
1313
                          "       print \"match\"\n"
1✔
1314
                          "       return 1\n"
1✔
1315
                          "   end\n"
1✔
1316
                          "   return 0\n"
1✔
1317
                          "end\n"
1✔
1318
                          "return 0\n";
1✔
1319
    char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1✔
1320
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"
1✔
1321
                         "Host: www.emergingthreats.net\r\n\r\n";
1✔
1322
    uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n"
1✔
1323
                         "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1324
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1325
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1326
    TcpSession ssn;
1✔
1327
    Flow f;
1✔
1328
    ThreadVars th_v;
1✔
1329
    DetectEngineThreadCtx *det_ctx;
1✔
1330

1331
    ut_script = script;
1✔
1332

1333
    memset(&th_v, 0, sizeof(th_v));
1✔
1334
    StatsThreadInit(&th_v.stats);
1✔
1335
    memset(&f, 0, sizeof(f));
1✔
1336
    memset(&ssn, 0, sizeof(ssn));
1✔
1337

1338
    Packet *p1 = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP);
1✔
1339
    Packet *p2 = UTHBuildPacket(httpbuf2, httplen2, IPPROTO_TCP);
1✔
1340

1341
    FLOW_INITIALIZE(&f);
1✔
1342
    f.protoctx = (void *)&ssn;
1✔
1343
    f.proto = IPPROTO_TCP;
1✔
1344
    f.flags |= FLOW_IPV4;
1✔
1345
    f.alproto = ALPROTO_HTTP1;
1✔
1346

1347
    p1->flow = &f;
1✔
1348
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1349
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1350
    p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1351
    p2->flow = &f;
1✔
1352
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1353
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1354
    p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1355

1356
    StreamTcpInitConfig(true);
1✔
1357

1358
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1359
    FAIL_IF_NULL(de_ctx);
1✔
1360
    de_ctx->flags |= DE_QUIET;
1✔
1361

1362
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1363
    FAIL_IF_NULL(s);
1✔
1364

1365
    SigGroupBuild(de_ctx);
1✔
1366
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1367

1368
    /* do detect for p1 */
1369
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1370
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1371

1372
    /* do detect for p2 */
1373
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1374
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1375

1376
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_VAR);
1✔
1377
    FAIL_IF(id == 0);
1✔
1378
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1379
    FAIL_IF_NULL(fv);
1✔
1380
    FAIL_IF(fv->data.fv_str.value_len != 1);
1✔
1381
    FAIL_IF(memcmp(fv->data.fv_str.value, "2", 1) != 0);
1✔
1382

1383
    UTHFreePackets(&p1, 1);
1✔
1384
    UTHFreePackets(&p2, 1);
1✔
1385
    FLOW_DESTROY(&f);
1✔
1386

1387
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1388
    DetectEngineCtxFree(de_ctx);
1✔
1389
    StreamTcpFreeConfig(true);
1✔
1390
    StatsThreadCleanup(&th_v.stats);
1✔
1391
    PASS;
1✔
1392
}
1✔
1393

1394
/** \test packet buffer */
1395
static int LuaMatchTest03a(void)
1396
{
1✔
1397
    const char script[] = "local flowvarlib = require(\"suricata.flowvar\")\n"
1✔
1398
                          "function init (args)\n"
1✔
1399
                          "   flowvarlib.register(\"cnt\")\n"
1✔
1400
                          "   local needs = {}\n"
1✔
1401
                          "   needs[\"packet\"] = tostring(true)\n"
1✔
1402
                          "   return needs\n"
1✔
1403
                          "end\n"
1✔
1404
                          "\n"
1✔
1405
                          "function thread_init (args)\n"
1✔
1406
                          "   cnt = flowvarlib.get(\"cnt\")\n"
1✔
1407
                          "end\n"
1✔
1408
                          "\n"
1✔
1409
                          "function match(args)\n"
1✔
1410
                          "   a = cnt:value()\n"
1✔
1411
                          "   if a then\n"
1✔
1412
                          "       a = tostring(tonumber(a)+1)\n"
1✔
1413
                          "       print (a)\n"
1✔
1414
                          "       cnt:set(a, #a)\n"
1✔
1415
                          "   else\n"
1✔
1416
                          "       a = tostring(1)\n"
1✔
1417
                          "       print (a)\n"
1✔
1418
                          "       cnt:set(a, #a)\n"
1✔
1419
                          "   end\n"
1✔
1420
                          "   \n"
1✔
1421
                          "   print (\"pre check: \" .. (a))\n"
1✔
1422
                          "   if tonumber(a) == 2 then\n"
1✔
1423
                          "       print \"match\"\n"
1✔
1424
                          "       return 1\n"
1✔
1425
                          "   end\n"
1✔
1426
                          "   return 0\n"
1✔
1427
                          "end\n"
1✔
1428
                          "return 0\n";
1✔
1429
    char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1✔
1430
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"
1✔
1431
                         "Host: www.emergingthreats.net\r\n\r\n";
1✔
1432
    uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n"
1✔
1433
                         "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1434
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1435
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1436
    TcpSession ssn;
1✔
1437
    Flow f;
1✔
1438
    ThreadVars th_v;
1✔
1439
    DetectEngineThreadCtx *det_ctx;
1✔
1440

1441
    ut_script = script;
1✔
1442

1443
    memset(&th_v, 0, sizeof(th_v));
1✔
1444
    StatsThreadInit(&th_v.stats);
1✔
1445
    memset(&f, 0, sizeof(f));
1✔
1446
    memset(&ssn, 0, sizeof(ssn));
1✔
1447

1448
    Packet *p1 = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP);
1✔
1449
    Packet *p2 = UTHBuildPacket(httpbuf2, httplen2, IPPROTO_TCP);
1✔
1450

1451
    FLOW_INITIALIZE(&f);
1✔
1452
    f.protoctx = (void *)&ssn;
1✔
1453
    f.proto = IPPROTO_TCP;
1✔
1454
    f.flags |= FLOW_IPV4;
1✔
1455
    f.alproto = ALPROTO_HTTP1;
1✔
1456

1457
    p1->flow = &f;
1✔
1458
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1459
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1460
    p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1461
    p2->flow = &f;
1✔
1462
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1463
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1464
    p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1465

1466
    StreamTcpInitConfig(true);
1✔
1467

1468
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1469
    FAIL_IF_NULL(de_ctx);
1✔
1470
    de_ctx->flags |= DE_QUIET;
1✔
1471

1472
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1473
    FAIL_IF_NULL(s);
1✔
1474

1475
    SigGroupBuild(de_ctx);
1✔
1476
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1477

1478
    /* do detect for p1 */
1479
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1480
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1481

1482
    /* do detect for p2 */
1483
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1484
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1485

1486
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_VAR);
1✔
1487
    FAIL_IF(id == 0);
1✔
1488
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1489
    FAIL_IF_NULL(fv);
1✔
1490
    FAIL_IF(fv->data.fv_str.value_len != 1);
1✔
1491
    FAIL_IF(memcmp(fv->data.fv_str.value, "2", 1) != 0);
1✔
1492

1493
    UTHFreePackets(&p1, 1);
1✔
1494
    UTHFreePackets(&p2, 1);
1✔
1495
    FLOW_DESTROY(&f);
1✔
1496

1497
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1498
    DetectEngineCtxFree(de_ctx);
1✔
1499
    StreamTcpFreeConfig(true);
1✔
1500
    StatsThreadCleanup(&th_v.stats);
1✔
1501
    PASS;
1✔
1502
}
1✔
1503

1504
/** \test http buffer, flowints */
1505
static int LuaMatchTest04(void)
1506
{
1✔
1507
    const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
1✔
1508
                          "function init (args)\n"
1✔
1509
                          "   flowintlib.register(\"cnt\")\n"
1✔
1510
                          "   return {}\n"
1✔
1511
                          "end\n"
1✔
1512
                          "\n"
1✔
1513
                          "function thread_init (args)\n"
1✔
1514
                          "   cnt = flowintlib.get(\"cnt\")\n"
1✔
1515
                          "end\n"
1✔
1516
                          "\n"
1✔
1517
                          "function match(args)\n"
1✔
1518
                          "   print \"inspecting\""
1✔
1519
                          "   a = cnt:value()\n"
1✔
1520
                          "   if a then\n"
1✔
1521
                          "       cnt:set(a + 1)\n"
1✔
1522
                          "   else\n"
1✔
1523
                          "       cnt:set(1)\n"
1✔
1524
                          "   end\n"
1✔
1525
                          "   \n"
1✔
1526
                          "   a = cnt:value()\n"
1✔
1527
                          "   if a == 2 then\n"
1✔
1528
                          "       print \"match\"\n"
1✔
1529
                          "       return 1\n"
1✔
1530
                          "   end\n"
1✔
1531
                          "   return 0\n"
1✔
1532
                          "end\n"
1✔
1533
                          "return 0\n";
1✔
1534
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
1535
                 "sid:1;)";
1✔
1536
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"
1✔
1537
                         "Host: www.emergingthreats.net\r\n\r\n";
1✔
1538
    uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n"
1✔
1539
                         "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1540
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1541
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1542
    TcpSession ssn;
1✔
1543
    Flow f;
1✔
1544
    ThreadVars th_v;
1✔
1545
    DetectEngineThreadCtx *det_ctx;
1✔
1546

1547
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
1548

1549
    ut_script = script;
1✔
1550

1551
    memset(&th_v, 0, sizeof(th_v));
1✔
1552
    StatsThreadInit(&th_v.stats);
1✔
1553
    memset(&f, 0, sizeof(f));
1✔
1554
    memset(&ssn, 0, sizeof(ssn));
1✔
1555

1556
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1557
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1558

1559
    FLOW_INITIALIZE(&f);
1✔
1560
    f.protoctx = (void *)&ssn;
1✔
1561
    f.proto = IPPROTO_TCP;
1✔
1562
    f.flags |= FLOW_IPV4;
1✔
1563
    f.alproto = ALPROTO_HTTP1;
1✔
1564

1565
    p1->flow = &f;
1✔
1566
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1567
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1568
    p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1569

1570
    p2->flow = &f;
1✔
1571
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1572
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1573
    p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
1✔
1574

1575
    StreamTcpInitConfig(true);
1✔
1576

1577
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1578
    FAIL_IF_NULL(de_ctx);
1✔
1579
    de_ctx->flags |= DE_QUIET;
1✔
1580

1581
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1582
    FAIL_IF_NULL(s);
1✔
1583

1584
    SigGroupBuild(de_ctx);
1✔
1585
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1586

1587
    int r = AppLayerParserParse(
1✔
1588
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
1589
    FAIL_IF(r != 0);
1✔
1590
    HtpState *http_state = f.alstate;
1✔
1591
    FAIL_IF_NULL(http_state);
1✔
1592

1593
    /* do detect for p1 */
1594
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1595
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1596

1597
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
1598
    FAIL_IF(r != 0);
1✔
1599

1600
    /* do detect for p2 */
1601
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1602
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1603

1604
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_INT);
1✔
1605
    FAIL_IF(id == 0);
1✔
1606
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1607
    FAIL_IF_NULL(fv);
1✔
1608
    FAIL_IF(fv->data.fv_int.value != 2);
1✔
1609

1610
    UTHFreePackets(&p1, 1);
1✔
1611
    UTHFreePackets(&p2, 1);
1✔
1612
    FLOW_DESTROY(&f);
1✔
1613

1614
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
1615
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1616
    DetectEngineCtxFree(de_ctx);
1✔
1617
    StreamTcpFreeConfig(true);
1✔
1618
    StatsThreadCleanup(&th_v.stats);
1✔
1619
    PASS;
1✔
1620
}
1✔
1621

1622
/** \test http buffer, flowints */
1623
static int LuaMatchTest04a(void)
1624
{
1✔
1625
    const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
1✔
1626
                          "function init (args)\n"
1✔
1627
                          "   flowintlib.register(\"cnt\")\n"
1✔
1628
                          "   return {}\n"
1✔
1629
                          "end\n"
1✔
1630
                          "\n"
1✔
1631
                          "function thread_init (args)\n"
1✔
1632
                          "   cnt = flowintlib.get(\"cnt\")\n"
1✔
1633
                          "end\n"
1✔
1634
                          "\n"
1✔
1635
                          "function match(args)\n"
1✔
1636
                          "   print \"inspecting\""
1✔
1637
                          "   a = cnt:value()\n"
1✔
1638
                          "   if a then\n"
1✔
1639
                          "       cnt:set(a + 1)\n"
1✔
1640
                          "   else\n"
1✔
1641
                          "       cnt:set(1)\n"
1✔
1642
                          "   end\n"
1✔
1643
                          "   \n"
1✔
1644
                          "   a = cnt:value()\n"
1✔
1645
                          "   if a == 2 then\n"
1✔
1646
                          "       print \"match\"\n"
1✔
1647
                          "       return 1\n"
1✔
1648
                          "   end\n"
1✔
1649
                          "   return 0\n"
1✔
1650
                          "end\n"
1✔
1651
                          "return 0\n";
1✔
1652
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
1653
                 "sid:1;)";
1✔
1654
    uint8_t httpbuf1[] =
1✔
1655
        "POST / HTTP/1.1\r\n"
1✔
1656
        "Host: www.emergingthreats.net\r\n\r\n";
1✔
1657
    uint8_t httpbuf2[] =
1✔
1658
        "POST / HTTP/1.1\r\n"
1✔
1659
        "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1660
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1661
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1662
    TcpSession ssn;
1✔
1663
    Flow f;
1✔
1664
    ThreadVars th_v;
1✔
1665
    DetectEngineThreadCtx *det_ctx;
1✔
1666

1667
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
1668

1669
    ut_script = script;
1✔
1670

1671
    memset(&th_v, 0, sizeof(th_v));
1✔
1672
    StatsThreadInit(&th_v.stats);
1✔
1673
    memset(&f, 0, sizeof(f));
1✔
1674
    memset(&ssn, 0, sizeof(ssn));
1✔
1675

1676
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1677
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1678

1679
    FLOW_INITIALIZE(&f);
1✔
1680
    f.protoctx = (void *)&ssn;
1✔
1681
    f.proto = IPPROTO_TCP;
1✔
1682
    f.flags |= FLOW_IPV4;
1✔
1683
    f.alproto = ALPROTO_HTTP1;
1✔
1684

1685
    p1->flow = &f;
1✔
1686
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1687
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1688
    p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
1689

1690
    p2->flow = &f;
1✔
1691
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1692
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1693
    p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
1694

1695
    StreamTcpInitConfig(true);
1✔
1696

1697
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1698
    FAIL_IF_NULL(de_ctx);
1✔
1699
    de_ctx->flags |= DE_QUIET;
1✔
1700

1701
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1702
    FAIL_IF_NULL(s);
1✔
1703

1704
    SigGroupBuild(de_ctx);
1✔
1705
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1706

1707
    int r = AppLayerParserParse(
1✔
1708
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
1709
    FAIL_IF(r != 0);
1✔
1710
    HtpState *http_state = f.alstate;
1✔
1711
    FAIL_IF_NULL(http_state);
1✔
1712

1713
    /* do detect for p1 */
1714
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1715
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1716

1717
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
1718
    FAIL_IF(r != 0);
1✔
1719

1720
    /* do detect for p2 */
1721
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1722
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1723

1724
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_INT);
1✔
1725
    FAIL_IF(id == 0);
1✔
1726
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1727
    FAIL_IF_NULL(fv);
1✔
1728
    FAIL_IF(fv->data.fv_int.value != 2);
1✔
1729

1730
    UTHFreePackets(&p1, 1);
1✔
1731
    UTHFreePackets(&p2, 1);
1✔
1732
    FLOW_DESTROY(&f);
1✔
1733

1734
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
1735
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1736
    DetectEngineCtxFree(de_ctx);
1✔
1737
    StreamTcpFreeConfig(true);
1✔
1738
    StatsThreadCleanup(&th_v.stats);
1✔
1739
    PASS;
1✔
1740
}
1✔
1741

1742
/** \test http buffer, flowints */
1743
static int LuaMatchTest05(void)
1744
{
1✔
1745
    const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
1✔
1746
                          "function init (args)\n"
1✔
1747
                          "   flowintlib.register(\"cnt\")\n"
1✔
1748
                          "   return {}\n"
1✔
1749
                          "end\n"
1✔
1750
                          "\n"
1✔
1751
                          "function thread_init (args)\n"
1✔
1752
                          "   cnt = flowintlib.get(\"cnt\")\n"
1✔
1753
                          "end\n"
1✔
1754
                          "\n"
1✔
1755
                          "function match(args)\n"
1✔
1756
                          "   print \"inspecting\""
1✔
1757
                          "   a = cnt:incr()\n"
1✔
1758
                          "   if a == 2 then\n"
1✔
1759
                          "       print \"match\"\n"
1✔
1760
                          "       return 1\n"
1✔
1761
                          "   end\n"
1✔
1762
                          "   return 0\n"
1✔
1763
                          "end\n"
1✔
1764
                          "return 0\n";
1✔
1765
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
1766
                 "sid:1;)";
1✔
1767
    uint8_t httpbuf1[] =
1✔
1768
        "POST / HTTP/1.1\r\n"
1✔
1769
        "Host: www.emergingthreats.net\r\n\r\n";
1✔
1770
    uint8_t httpbuf2[] =
1✔
1771
        "POST / HTTP/1.1\r\n"
1✔
1772
        "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1773
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1774
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1775
    TcpSession ssn;
1✔
1776
    Flow f;
1✔
1777
    ThreadVars th_v;
1✔
1778
    DetectEngineThreadCtx *det_ctx;
1✔
1779

1780
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
1781

1782
    ut_script = script;
1✔
1783

1784
    memset(&th_v, 0, sizeof(th_v));
1✔
1785
    StatsThreadInit(&th_v.stats);
1✔
1786
    memset(&f, 0, sizeof(f));
1✔
1787
    memset(&ssn, 0, sizeof(ssn));
1✔
1788

1789
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1790
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1791

1792
    FLOW_INITIALIZE(&f);
1✔
1793
    f.protoctx = (void *)&ssn;
1✔
1794
    f.proto = IPPROTO_TCP;
1✔
1795
    f.flags |= FLOW_IPV4;
1✔
1796
    f.alproto = ALPROTO_HTTP1;
1✔
1797

1798
    p1->flow = &f;
1✔
1799
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1800
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1801
    p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
1802

1803
    p2->flow = &f;
1✔
1804
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1805
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1806
    p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
1807

1808
    StreamTcpInitConfig(true);
1✔
1809

1810
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1811
    FAIL_IF_NULL(de_ctx);
1✔
1812
    de_ctx->flags |= DE_QUIET;
1✔
1813

1814
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1815
    FAIL_IF_NULL(s);
1✔
1816

1817
    SigGroupBuild(de_ctx);
1✔
1818
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1819

1820
    int r = AppLayerParserParse(
1✔
1821
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
1822
    FAIL_IF(r != 0);
1✔
1823
    HtpState *http_state = f.alstate;
1✔
1824
    FAIL_IF_NULL(http_state);
1✔
1825

1826
    /* do detect for p1 */
1827
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1828
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1829

1830
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
1831
    FAIL_IF(r != 0);
1✔
1832

1833
    /* do detect for p2 */
1834
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1835
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1836

1837
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_INT);
1✔
1838
    FAIL_IF(id == 0);
1✔
1839
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1840
    FAIL_IF_NULL(fv);
1✔
1841
    FAIL_IF(fv->data.fv_int.value != 2);
1✔
1842

1843
    UTHFreePackets(&p1, 1);
1✔
1844
    UTHFreePackets(&p2, 1);
1✔
1845
    FLOW_DESTROY(&f);
1✔
1846

1847
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
1848
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1849
    DetectEngineCtxFree(de_ctx);
1✔
1850
    StreamTcpFreeConfig(true);
1✔
1851
    StatsThreadCleanup(&th_v.stats);
1✔
1852
    PASS;
1✔
1853
}
1✔
1854

1855
/** \test http buffer, flowints */
1856
static int LuaMatchTest05a(void)
1857
{
1✔
1858
    const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
1✔
1859
                          "function init (args)\n"
1✔
1860
                          "   flowintlib.register(\"cnt\")\n"
1✔
1861
                          "   return {}\n"
1✔
1862
                          "end\n"
1✔
1863
                          "\n"
1✔
1864
                          "function thread_init (args)\n"
1✔
1865
                          "   cnt = flowintlib.get(\"cnt\")\n"
1✔
1866
                          "end\n"
1✔
1867
                          "\n"
1✔
1868
                          "function match(args)\n"
1✔
1869
                          "   print \"inspecting\""
1✔
1870
                          "   a = cnt:incr()\n"
1✔
1871
                          "   if a == 2 then\n"
1✔
1872
                          "       print \"match\"\n"
1✔
1873
                          "       return 1\n"
1✔
1874
                          "   end\n"
1✔
1875
                          "   return 0\n"
1✔
1876
                          "end\n"
1✔
1877
                          "return 0\n";
1✔
1878
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
1879
                 "sid:1;)";
1✔
1880
    uint8_t httpbuf1[] =
1✔
1881
        "POST / HTTP/1.1\r\n"
1✔
1882
        "Host: www.emergingthreats.net\r\n\r\n";
1✔
1883
    uint8_t httpbuf2[] =
1✔
1884
        "POST / HTTP/1.1\r\n"
1✔
1885
        "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
1886
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
1887
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
1888
    TcpSession ssn;
1✔
1889
    Flow f;
1✔
1890
    ThreadVars th_v;
1✔
1891
    DetectEngineThreadCtx *det_ctx;
1✔
1892

1893
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
1894

1895
    ut_script = script;
1✔
1896

1897
    memset(&th_v, 0, sizeof(th_v));
1✔
1898
    StatsThreadInit(&th_v.stats);
1✔
1899
    memset(&f, 0, sizeof(f));
1✔
1900
    memset(&ssn, 0, sizeof(ssn));
1✔
1901

1902
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1903
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
1904

1905
    FLOW_INITIALIZE(&f);
1✔
1906
    f.protoctx = (void *)&ssn;
1✔
1907
    f.proto = IPPROTO_TCP;
1✔
1908
    f.flags |= FLOW_IPV4;
1✔
1909
    f.alproto = ALPROTO_HTTP1;
1✔
1910

1911
    p1->flow = &f;
1✔
1912
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
1913
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1914
    p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
1915

1916
    p2->flow = &f;
1✔
1917
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
1918
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
1919
    p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
1920

1921
    StreamTcpInitConfig(true);
1✔
1922

1923
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1924
    FAIL_IF_NULL(de_ctx);
1✔
1925
    de_ctx->flags |= DE_QUIET;
1✔
1926

1927
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
1928
    FAIL_IF_NULL(s);
1✔
1929

1930
    SigGroupBuild(de_ctx);
1✔
1931
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1932

1933
    int r = AppLayerParserParse(
1✔
1934
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
1935
    FAIL_IF(r != 0);
1✔
1936
    HtpState *http_state = f.alstate;
1✔
1937
    FAIL_IF_NULL(http_state);
1✔
1938

1939
    /* do detect for p1 */
1940
    SCLogInfo("p1");
1✔
1941
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
1942
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
1943

1944
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
1945
    FAIL_IF(r != 0);
1✔
1946
    /* do detect for p2 */
1947
    SCLogInfo("p2");
1✔
1948
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
1949

1950
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
1951

1952
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_INT);
1✔
1953
    FAIL_IF(id == 0);
1✔
1954
    FlowVar *fv = FlowVarGet(&f, id);
1✔
1955
    FAIL_IF_NULL(fv);
1✔
1956
    FAIL_IF(fv->data.fv_int.value != 2);
1✔
1957

1958
    UTHFreePackets(&p1, 1);
1✔
1959
    UTHFreePackets(&p2, 1);
1✔
1960
    FLOW_DESTROY(&f);
1✔
1961

1962
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
1963
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1964
    DetectEngineCtxFree(de_ctx);
1✔
1965
    StreamTcpFreeConfig(true);
1✔
1966
    StatsThreadCleanup(&th_v.stats);
1✔
1967
    PASS;
1✔
1968
}
1✔
1969

1970
/** \test http buffer, flowints */
1971
static int LuaMatchTest06(void)
1972
{
1✔
1973
    const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
1✔
1974
                          "function init (args)\n"
1✔
1975
                          "   flowintlib.register(\"cnt\")\n"
1✔
1976
                          "   return {}\n"
1✔
1977
                          "end\n"
1✔
1978
                          "\n"
1✔
1979
                          "function thread_init (args)\n"
1✔
1980
                          "   cnt = flowintlib.get(\"cnt\")\n"
1✔
1981
                          "end\n"
1✔
1982
                          "\n"
1✔
1983
                          "function match(args)\n"
1✔
1984
                          "   print \"inspecting\""
1✔
1985
                          "   a = cnt:value()\n"
1✔
1986
                          "   if a == nil then\n"
1✔
1987
                          "       print \"new var set to 2\""
1✔
1988
                          "       cnt:set(2)\n"
1✔
1989
                          "   end\n"
1✔
1990
                          "   a = cnt:decr()\n"
1✔
1991
                          "   if a == 0 then\n"
1✔
1992
                          "       print \"match\"\n"
1✔
1993
                          "       return 1\n"
1✔
1994
                          "   end\n"
1✔
1995
                          "   return 0\n"
1✔
1996
                          "end\n"
1✔
1997
                          "return 0\n";
1✔
1998
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
1999
                 "sid:1;)";
1✔
2000
    uint8_t httpbuf1[] =
1✔
2001
        "POST / HTTP/1.1\r\n"
1✔
2002
        "Host: www.emergingthreats.net\r\n\r\n";
1✔
2003
    uint8_t httpbuf2[] =
1✔
2004
        "POST / HTTP/1.1\r\n"
1✔
2005
        "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
2006
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
2007
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
2008
    TcpSession ssn;
1✔
2009
    Flow f;
1✔
2010
    ThreadVars th_v;
1✔
2011
    DetectEngineThreadCtx *det_ctx;
1✔
2012

2013
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
2014

2015
    ut_script = script;
1✔
2016

2017
    memset(&th_v, 0, sizeof(th_v));
1✔
2018
    StatsThreadInit(&th_v.stats);
1✔
2019
    memset(&f, 0, sizeof(f));
1✔
2020
    memset(&ssn, 0, sizeof(ssn));
1✔
2021

2022
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
2023
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
2024

2025
    FLOW_INITIALIZE(&f);
1✔
2026
    f.protoctx = (void *)&ssn;
1✔
2027
    f.proto = IPPROTO_TCP;
1✔
2028
    f.flags |= FLOW_IPV4;
1✔
2029
    f.alproto = ALPROTO_HTTP1;
1✔
2030

2031
    p1->flow = &f;
1✔
2032
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
2033
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
2034
    p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
2035

2036
    p2->flow = &f;
1✔
2037
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
2038
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
2039
    p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
2040

2041
    StreamTcpInitConfig(true);
1✔
2042

2043
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
2044
    FAIL_IF_NULL(de_ctx);
1✔
2045
    de_ctx->flags |= DE_QUIET;
1✔
2046

2047
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
2048
    FAIL_IF_NULL(s);
1✔
2049

2050
    SigGroupBuild(de_ctx);
1✔
2051
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
2052

2053
    int r = AppLayerParserParse(
1✔
2054
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
2055
    FAIL_IF(r != 0);
1✔
2056
    HtpState *http_state = f.alstate;
1✔
2057
    FAIL_IF_NULL(http_state);
1✔
2058

2059
    /* do detect for p1 */
2060
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
2061
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
2062

2063
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
2064
    FAIL_IF(r != 0);
1✔
2065

2066
    /* do detect for p2 */
2067
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
2068
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
2069

2070
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_INT);
1✔
2071
    FAIL_IF(id == 0);
1✔
2072
    FlowVar *fv = FlowVarGet(&f, id);
1✔
2073
    FAIL_IF_NULL(fv);
1✔
2074
    FAIL_IF(fv->data.fv_int.value != 0);
1✔
2075

2076
    UTHFreePackets(&p1, 1);
1✔
2077
    UTHFreePackets(&p2, 1);
1✔
2078
    FLOW_DESTROY(&f);
1✔
2079

2080
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
2081
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
2082
    DetectEngineCtxFree(de_ctx);
1✔
2083
    StreamTcpFreeConfig(true);
1✔
2084
    StatsThreadCleanup(&th_v.stats);
1✔
2085
    PASS;
1✔
2086
}
1✔
2087

2088
/** \test http buffer, flowints */
2089
static int LuaMatchTest06a(void)
2090
{
1✔
2091
    const char script[] = "local flowintlib = require(\"suricata.flowint\")\n"
1✔
2092
                          "function init (args)\n"
1✔
2093
                          "   flowintlib.register(\"cnt\")\n"
1✔
2094
                          "   return {}\n"
1✔
2095
                          "end\n"
1✔
2096
                          "\n"
1✔
2097
                          "function thread_init (args)\n"
1✔
2098
                          "   cnt = flowintlib.get(\"cnt\")\n"
1✔
2099
                          "end\n"
1✔
2100
                          "\n"
1✔
2101
                          "function match(args)\n"
1✔
2102
                          "   print \"inspecting\""
1✔
2103
                          "   a = cnt:value()\n"
1✔
2104
                          "   if a == nil then\n"
1✔
2105
                          "       print \"new var set to 2\""
1✔
2106
                          "       cnt:set(2)\n"
1✔
2107
                          "   end\n"
1✔
2108
                          "   a = cnt:decr()\n"
1✔
2109
                          "   if a == 0 then\n"
1✔
2110
                          "       print \"match\"\n"
1✔
2111
                          "       return 1\n"
1✔
2112
                          "   end\n"
1✔
2113
                          "   return 0\n"
1✔
2114
                          "end\n"
1✔
2115
                          "return 0\n";
1✔
2116
    char sig[] = "alert http1:request_complete any any -> any any (flow:to_server; lua:unittest; "
1✔
2117
                 "sid:1;)";
1✔
2118
    uint8_t httpbuf1[] =
1✔
2119
        "POST / HTTP/1.1\r\n"
1✔
2120
        "Host: www.emergingthreats.net\r\n\r\n";
1✔
2121
    uint8_t httpbuf2[] =
1✔
2122
        "POST / HTTP/1.1\r\n"
1✔
2123
        "Host: www.openinfosecfoundation.org\r\n\r\n";
1✔
2124
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1✔
2125
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1✔
2126
    TcpSession ssn;
1✔
2127
    Flow f;
1✔
2128
    ThreadVars th_v;
1✔
2129
    DetectEngineThreadCtx *det_ctx;
1✔
2130

2131
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1✔
2132

2133
    ut_script = script;
1✔
2134

2135
    memset(&th_v, 0, sizeof(th_v));
1✔
2136
    StatsThreadInit(&th_v.stats);
1✔
2137
    memset(&f, 0, sizeof(f));
1✔
2138
    memset(&ssn, 0, sizeof(ssn));
1✔
2139

2140
    Packet *p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
2141
    Packet *p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1✔
2142

2143
    FLOW_INITIALIZE(&f);
1✔
2144
    f.protoctx = (void *)&ssn;
1✔
2145
    f.proto = IPPROTO_TCP;
1✔
2146
    f.flags |= FLOW_IPV4;
1✔
2147
    f.alproto = ALPROTO_HTTP1;
1✔
2148

2149
    p1->flow = &f;
1✔
2150
    p1->flowflags |= FLOW_PKT_TOSERVER;
1✔
2151
    p1->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
2152
    p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
2153

2154
    p2->flow = &f;
1✔
2155
    p2->flowflags |= FLOW_PKT_TOSERVER;
1✔
2156
    p2->flowflags |= FLOW_PKT_ESTABLISHED;
1✔
2157
    p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1✔
2158

2159
    StreamTcpInitConfig(true);
1✔
2160

2161
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
2162
    FAIL_IF_NULL(de_ctx);
1✔
2163
    de_ctx->flags |= DE_QUIET;
1✔
2164

2165
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
1✔
2166
    FAIL_IF_NULL(s);
1✔
2167

2168
    SigGroupBuild(de_ctx);
1✔
2169
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
2170

2171
    int r = AppLayerParserParse(
1✔
2172
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1✔
2173
    FAIL_IF(r != 0);
1✔
2174
    HtpState *http_state = f.alstate;
1✔
2175
    FAIL_IF_NULL(http_state);
1✔
2176

2177
    /* do detect for p1 */
2178
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1✔
2179
    FAIL_IF(PacketAlertCheck(p1, 1));
1✔
2180

2181
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1✔
2182
    FAIL_IF(r != 0);
1✔
2183

2184
    /* do detect for p2 */
2185
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1✔
2186
    FAIL_IF_NOT(PacketAlertCheck(p2, 1));
1✔
2187

2188
    uint32_t id = VarNameStoreLookupByName("cnt", VAR_TYPE_FLOW_INT);
1✔
2189
    FAIL_IF(id == 0);
1✔
2190
    FlowVar *fv = FlowVarGet(&f, id);
1✔
2191
    FAIL_IF_NULL(fv);
1✔
2192
    FAIL_IF(fv->data.fv_int.value != 0);
1✔
2193

2194
    UTHFreePackets(&p1, 1);
1✔
2195
    UTHFreePackets(&p2, 1);
1✔
2196
    FLOW_DESTROY(&f);
1✔
2197

2198
    AppLayerParserThreadCtxFree(alp_tctx);
1✔
2199
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
2200
    DetectEngineCtxFree(de_ctx);
1✔
2201
    StreamTcpFreeConfig(true);
1✔
2202
    StatsThreadCleanup(&th_v.stats);
1✔
2203
    PASS;
1✔
2204
}
1✔
2205

2206
void DetectLuaRegisterTests(void)
2207
{
1✔
2208
    UtRegisterTest("LuaMatchTest01", LuaMatchTest01);
1✔
2209
    UtRegisterTest("LuaMatchTest01a", LuaMatchTest01a);
1✔
2210
    UtRegisterTest("LuaMatchTest02", LuaMatchTest02);
1✔
2211
    UtRegisterTest("LuaMatchTest02a", LuaMatchTest02a);
1✔
2212
    UtRegisterTest("LuaMatchTest03", LuaMatchTest03);
1✔
2213
    UtRegisterTest("LuaMatchTest03a", LuaMatchTest03a);
1✔
2214
    UtRegisterTest("LuaMatchTest04", LuaMatchTest04);
1✔
2215
    UtRegisterTest("LuaMatchTest04a", LuaMatchTest04a);
1✔
2216
    UtRegisterTest("LuaMatchTest05", LuaMatchTest05);
1✔
2217
    UtRegisterTest("LuaMatchTest05a", LuaMatchTest05a);
1✔
2218
    UtRegisterTest("LuaMatchTest06", LuaMatchTest06);
1✔
2219
    UtRegisterTest("LuaMatchTest06a", LuaMatchTest06a);
1✔
2220
}
1✔
2221
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc