suricata
detect-lua.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2014 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 "threads.h"
29 #include "debug.h"
30 #include "decode.h"
31 
32 #include "detect.h"
33 #include "detect-parse.h"
34 
35 #include "detect-engine.h"
36 #include "detect-engine-mpm.h"
37 #include "detect-engine-state.h"
38 
39 #include "flow.h"
40 #include "flow-var.h"
41 #include "flow-util.h"
42 
43 #include "util-debug.h"
44 #include "util-spm-bm.h"
45 #include "util-print.h"
46 
47 #include "util-unittest.h"
48 #include "util-unittest-helper.h"
49 
50 #include "app-layer.h"
51 #include "app-layer-parser.h"
52 #include "app-layer-htp.h"
53 
54 #include "stream-tcp.h"
55 
56 #include "detect-lua.h"
57 #include "detect-lua-extensions.h"
58 
59 #include "queue.h"
60 #include "util-cpu.h"
61 #include "util-var-name.h"
62 
63 #ifndef HAVE_LUA
64 
65 static int DetectLuaSetupNoSupport (DetectEngineCtx *a, Signature *b, const char *c)
66 {
67  SCLogError(SC_ERR_NO_LUA_SUPPORT, "no Lua support built in, needed for lua/luajit keyword");
68  return -1;
69 }
70 
71 /**
72  * \brief Registration function for keyword: lua
73  */
75 {
77  sigmatch_table[DETECT_LUA].alias = "luajit";
78  sigmatch_table[DETECT_LUA].Setup = DetectLuaSetupNoSupport;
82 
83  SCLogDebug("registering lua rule option");
84  return;
85 }
86 
87 #else /* HAVE_LUA */
88 
89 #include "util-lua.h"
90 
91 static int DetectLuaMatch (DetectEngineThreadCtx *,
92  Packet *, const Signature *, const SigMatchCtx *);
93 static int DetectLuaAppTxMatch (DetectEngineThreadCtx *det_ctx,
94  Flow *f, uint8_t flags,
95  void *state, void *txv, const Signature *s,
96  const SigMatchCtx *ctx);
97 static int DetectLuaSetup (DetectEngineCtx *, Signature *, const char *);
98 static void DetectLuaRegisterTests(void);
99 static void DetectLuaFree(void *);
100 static int g_smtp_generic_list_id = 0;
101 
102 static int InspectSmtpGeneric(ThreadVars *tv,
103  DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
104  const Signature *s, const SigMatchData *smd,
105  Flow *f, uint8_t flags, void *alstate,
106  void *txv, uint64_t tx_id);
107 
108 /**
109  * \brief Registration function for keyword: lua
110  */
111 void DetectLuaRegister(void)
112 {
113  sigmatch_table[DETECT_LUA].name = "lua";
114  sigmatch_table[DETECT_LUA].alias = "luajit";
115  sigmatch_table[DETECT_LUA].desc = "match via a lua script";
116  sigmatch_table[DETECT_LUA].url = DOC_URL DOC_VERSION "/rules/rule-lua-scripting.html";
117  sigmatch_table[DETECT_LUA].Match = DetectLuaMatch;
118  sigmatch_table[DETECT_LUA].AppLayerTxMatch = DetectLuaAppTxMatch;
119  sigmatch_table[DETECT_LUA].Setup = DetectLuaSetup;
120  sigmatch_table[DETECT_LUA].Free = DetectLuaFree;
121  sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests;
122 
123  g_smtp_generic_list_id = DetectBufferTypeRegister("smtp_generic");
124 
127  InspectSmtpGeneric);
130  InspectSmtpGeneric);
131 
132  SCLogDebug("registering lua rule option");
133  return;
134 }
135 
136 static int InspectSmtpGeneric(ThreadVars *tv,
137  DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
138  const Signature *s, const SigMatchData *smd,
139  Flow *f, uint8_t flags, void *alstate,
140  void *txv, uint64_t tx_id)
141 {
142  return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd,
143  f, flags, alstate, txv, tx_id);
144 }
145 
146 #define DATATYPE_PACKET (1<<0)
147 #define DATATYPE_PAYLOAD (1<<1)
148 #define DATATYPE_STREAM (1<<2)
149 
150 #define DATATYPE_HTTP_URI (1<<3)
151 #define DATATYPE_HTTP_URI_RAW (1<<4)
152 
153 #define DATATYPE_HTTP_REQUEST_HEADERS (1<<5)
154 #define DATATYPE_HTTP_REQUEST_HEADERS_RAW (1<<6)
155 #define DATATYPE_HTTP_REQUEST_COOKIE (1<<7)
156 #define DATATYPE_HTTP_REQUEST_UA (1<<8)
157 
158 #define DATATYPE_HTTP_REQUEST_LINE (1<<9)
159 #define DATATYPE_HTTP_REQUEST_BODY (1<<10)
160 
161 #define DATATYPE_HTTP_RESPONSE_COOKIE (1<<11)
162 #define DATATYPE_HTTP_RESPONSE_BODY (1<<12)
163 
164 #define DATATYPE_HTTP_RESPONSE_HEADERS (1<<13)
165 #define DATATYPE_HTTP_RESPONSE_HEADERS_RAW (1<<14)
166 
167 #define DATATYPE_DNS_RRNAME (1<<15)
168 #define DATATYPE_DNS_REQUEST (1<<16)
169 #define DATATYPE_DNS_RESPONSE (1<<17)
170 
171 #define DATATYPE_TLS (1<<18)
172 #define DATATYPE_SSH (1<<19)
173 #define DATATYPE_SMTP (1<<20)
174 
175 #define DATATYPE_DNP3 (1<<21)
176 
177 #define DATATYPE_BUFFER (1<<22)
178 
179 #if 0
180 /** \brief dump stack from lua state to screen */
181 void LuaDumpStack(lua_State *state)
182 {
183  int size = lua_gettop(state);
184  int i;
185 
186  for (i = 1; i <= size; i++) {
187  int type = lua_type(state, i);
188  printf("Stack size=%d, level=%d, type=%d, ", size, i, type);
189 
190  switch (type) {
191  case LUA_TFUNCTION:
192  printf("function %s", lua_tostring(state, i) ? "true" : "false");
193  break;
194  case LUA_TBOOLEAN:
195  printf("bool %s", lua_toboolean(state, i) ? "true" : "false");
196  break;
197  case LUA_TNUMBER:
198  printf("number %g", lua_tonumber(state, i));
199  break;
200  case LUA_TSTRING:
201  printf("string `%s'", lua_tostring(state, i));
202  break;
203  case LUA_TTABLE:
204  printf("table `%s'", lua_tostring(state, i));
205  break;
206  default:
207  printf("other %s", lua_typename(state, type));
208  break;
209 
210  }
211  printf("\n");
212  }
213 }
214 #endif
215 
217  const Signature *s, const SigMatchData *smd,
218  uint8_t *buffer, uint32_t buffer_len, uint32_t offset,
219  Flow *f)
220 {
221  SCEnter();
222  int ret = 0;
223 
224  if (buffer == NULL || buffer_len == 0)
225  SCReturnInt(0);
226 
227  DetectLuaData *lua = (DetectLuaData *)smd->ctx;
228  if (lua == NULL)
229  SCReturnInt(0);
230 
231  DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id);
232  if (tlua == NULL)
233  SCReturnInt(0);
234 
235  LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx,
236  f, /* no packet in the ctx */NULL, 0);
237 
238  /* prepare data to pass to script */
239  lua_getglobal(tlua->luastate, "match");
240  lua_newtable(tlua->luastate); /* stack at -1 */
241 
242  lua_pushliteral (tlua->luastate, "offset"); /* stack at -2 */
243  lua_pushnumber (tlua->luastate, (int)(offset + 1));
244  lua_settable(tlua->luastate, -3);
245 
246  lua_pushstring (tlua->luastate, lua->buffername); /* stack at -2 */
247  LuaPushStringBuffer(tlua->luastate, (const uint8_t *)buffer, (size_t)buffer_len);
248  lua_settable(tlua->luastate, -3);
249 
250  int retval = lua_pcall(tlua->luastate, 1, 1, 0);
251  if (retval != 0) {
252  SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1));
253  }
254 
255  /* process returns from script */
256  if (lua_gettop(tlua->luastate) > 0) {
257  /* script returns a number (return 1 or return 0) */
258  if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) {
259  double script_ret = lua_tonumber(tlua->luastate, 1);
260  SCLogDebug("script_ret %f", script_ret);
261  lua_pop(tlua->luastate, 1);
262 
263  if (script_ret == 1.0)
264  ret = 1;
265 
266  /* script returns a table */
267  } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) {
268  lua_pushnil(tlua->luastate);
269  const char *k, *v;
270  while (lua_next(tlua->luastate, -2)) {
271  v = lua_tostring(tlua->luastate, -1);
272  lua_pop(tlua->luastate, 1);
273  k = lua_tostring(tlua->luastate, -1);
274 
275  if (!k || !v)
276  continue;
277 
278  SCLogDebug("k='%s', v='%s'", k, v);
279 
280  if (strcmp(k, "retval") == 0) {
281  if (atoi(v) == 1)
282  ret = 1;
283  } else {
284  /* set flow var? */
285  }
286  }
287 
288  /* pop the table */
289  lua_pop(tlua->luastate, 1);
290  }
291  } else {
292  SCLogDebug("no stack");
293  }
294 
295  /* clear the stack */
296  while (lua_gettop(tlua->luastate) > 0) {
297  lua_pop(tlua->luastate, 1);
298  }
299 
300  if (lua->negated) {
301  if (ret == 1)
302  ret = 0;
303  else
304  ret = 1;
305  }
306 
307  SCReturnInt(ret);
308 }
309 
310 /**
311  * \brief match the specified lua script
312  *
313  * \param t thread local vars
314  * \param det_ctx pattern matcher thread local data
315  * \param p packet
316  * \param s signature being inspected
317  * \param m sigmatch that we will cast into DetectLuaData
318  *
319  * \retval 0 no match
320  * \retval 1 match
321  */
322 static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx,
323  Packet *p, const Signature *s, const SigMatchCtx *ctx)
324 {
325  SCEnter();
326  int ret = 0;
327  DetectLuaData *lua = (DetectLuaData *)ctx;
328  if (lua == NULL)
329  SCReturnInt(0);
330 
331  DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id);
332  if (tlua == NULL)
333  SCReturnInt(0);
334 
335  /* setup extension data for use in lua c functions */
336  uint8_t flags = 0;
337  if (p->flowflags & FLOW_PKT_TOSERVER)
338  flags = STREAM_TOSERVER;
339  else if (p->flowflags & FLOW_PKT_TOCLIENT)
340  flags = STREAM_TOCLIENT;
341 
342  LuaStateSetThreadVars(tlua->luastate, det_ctx->tv);
343 
344  LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx,
345  p->flow, p, flags);
346 
347  if ((tlua->flags & DATATYPE_PAYLOAD) && p->payload_len == 0)
348  SCReturnInt(0);
349  if ((tlua->flags & DATATYPE_PACKET) && GET_PKT_LEN(p) == 0)
350  SCReturnInt(0);
351  if (tlua->alproto != ALPROTO_UNKNOWN) {
352  if (p->flow == NULL)
353  SCReturnInt(0);
354 
355  AppProto alproto = p->flow->alproto;
356  if (tlua->alproto != alproto)
357  SCReturnInt(0);
358  }
359 
360  lua_getglobal(tlua->luastate, "match");
361  lua_newtable(tlua->luastate); /* stack at -1 */
362 
363  if ((tlua->flags & DATATYPE_PAYLOAD) && p->payload_len) {
364  lua_pushliteral(tlua->luastate, "payload"); /* stack at -2 */
365  LuaPushStringBuffer (tlua->luastate, (const uint8_t *)p->payload, (size_t)p->payload_len); /* stack at -3 */
366  lua_settable(tlua->luastate, -3);
367  }
368  if ((tlua->flags & DATATYPE_PACKET) && GET_PKT_LEN(p)) {
369  lua_pushliteral(tlua->luastate, "packet"); /* stack at -2 */
370  LuaPushStringBuffer (tlua->luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */
371  lua_settable(tlua->luastate, -3);
372  }
373  if (tlua->alproto == ALPROTO_HTTP) {
374  HtpState *htp_state = p->flow->alstate;
375  if (htp_state != NULL && htp_state->connp != NULL) {
376  htp_tx_t *tx = NULL;
379  uint64_t total_txs= AppLayerParserGetTxCnt(p->flow, htp_state);
380  for ( ; idx < total_txs; idx++) {
381  tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, idx);
382  if (tx == NULL)
383  continue;
384 
385  if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL &&
386  bstr_len(tx->request_line) > 0) {
387  lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */
388  LuaPushStringBuffer(tlua->luastate,
389  (const uint8_t *)bstr_ptr(tx->request_line),
390  bstr_len(tx->request_line));
391  lua_settable(tlua->luastate, -3);
392  }
393  }
394  }
395  }
396 
397  int retval = lua_pcall(tlua->luastate, 1, 1, 0);
398  if (retval != 0) {
399  SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1));
400  }
401 
402  /* process returns from script */
403  if (lua_gettop(tlua->luastate) > 0) {
404 
405  /* script returns a number (return 1 or return 0) */
406  if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) {
407  double script_ret = lua_tonumber(tlua->luastate, 1);
408  SCLogDebug("script_ret %f", script_ret);
409  lua_pop(tlua->luastate, 1);
410 
411  if (script_ret == 1.0)
412  ret = 1;
413 
414  /* script returns a table */
415  } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) {
416  lua_pushnil(tlua->luastate);
417  const char *k, *v;
418  while (lua_next(tlua->luastate, -2)) {
419  v = lua_tostring(tlua->luastate, -1);
420  lua_pop(tlua->luastate, 1);
421  k = lua_tostring(tlua->luastate, -1);
422 
423  if (!k || !v)
424  continue;
425 
426  SCLogDebug("k='%s', v='%s'", k, v);
427 
428  if (strcmp(k, "retval") == 0) {
429  if (atoi(v) == 1)
430  ret = 1;
431  } else {
432  /* set flow var? */
433  }
434  }
435 
436  /* pop the table */
437  lua_pop(tlua->luastate, 1);
438  }
439  }
440  while (lua_gettop(tlua->luastate) > 0) {
441  lua_pop(tlua->luastate, 1);
442  }
443 
444  if (lua->negated) {
445  if (ret == 1)
446  ret = 0;
447  else
448  ret = 1;
449  }
450 
451  SCReturnInt(ret);
452 }
453 
454 static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx,
455  Flow *f, uint8_t flags, void *state,
456  const Signature *s, const SigMatchCtx *ctx)
457 {
458  SCEnter();
459  int ret = 0;
460  DetectLuaData *lua = (DetectLuaData *)ctx;
461  if (lua == NULL)
462  SCReturnInt(0);
463 
464  DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id);
465  if (tlua == NULL)
466  SCReturnInt(0);
467 
468  /* setup extension data for use in lua c functions */
469  LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx,
470  f, NULL, flags);
471 
472  if (tlua->alproto != ALPROTO_UNKNOWN) {
473  int alproto = f->alproto;
474  if (tlua->alproto != alproto)
475  SCReturnInt(0);
476  }
477 
478  lua_getglobal(tlua->luastate, "match");
479  lua_newtable(tlua->luastate); /* stack at -1 */
480 
481  if (tlua->alproto == ALPROTO_HTTP) {
482  HtpState *htp_state = state;
483  if (htp_state != NULL && htp_state->connp != NULL) {
484  htp_tx_t *tx = NULL;
485  tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, det_ctx->tx_id);
486  if (tx != NULL) {
487  if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL &&
488  bstr_len(tx->request_line) > 0) {
489  lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */
490  LuaPushStringBuffer(tlua->luastate,
491  (const uint8_t *)bstr_ptr(tx->request_line),
492  bstr_len(tx->request_line));
493  lua_settable(tlua->luastate, -3);
494  }
495  }
496  }
497  }
498 
499  int retval = lua_pcall(tlua->luastate, 1, 1, 0);
500  if (retval != 0) {
501  SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1));
502  }
503 
504  /* process returns from script */
505  if (lua_gettop(tlua->luastate) > 0) {
506 
507  /* script returns a number (return 1 or return 0) */
508  if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) {
509  double script_ret = lua_tonumber(tlua->luastate, 1);
510  SCLogDebug("script_ret %f", script_ret);
511  lua_pop(tlua->luastate, 1);
512 
513  if (script_ret == 1.0)
514  ret = 1;
515 
516  /* script returns a table */
517  } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) {
518  lua_pushnil(tlua->luastate);
519  const char *k, *v;
520  while (lua_next(tlua->luastate, -2)) {
521  v = lua_tostring(tlua->luastate, -1);
522  lua_pop(tlua->luastate, 1);
523  k = lua_tostring(tlua->luastate, -1);
524 
525  if (!k || !v)
526  continue;
527 
528  SCLogDebug("k='%s', v='%s'", k, v);
529 
530  if (strcmp(k, "retval") == 0) {
531  if (atoi(v) == 1)
532  ret = 1;
533  } else {
534  /* set flow var? */
535  }
536  }
537 
538  /* pop the table */
539  lua_pop(tlua->luastate, 1);
540  }
541  }
542  while (lua_gettop(tlua->luastate) > 0) {
543  lua_pop(tlua->luastate, 1);
544  }
545 
546  if (lua->negated) {
547  if (ret == 1)
548  ret = 0;
549  else
550  ret = 1;
551  }
552 
553  SCReturnInt(ret);
554 }
555 
556 /**
557  * \brief match the specified lua script in a list with a tx
558  *
559  * \param t thread local vars
560  * \param det_ctx pattern matcher thread local data
561  * \param s signature being inspected
562  * \param m sigmatch that we will cast into DetectLuaData
563  *
564  * \retval 0 no match
565  * \retval 1 match
566  */
567 static int DetectLuaAppTxMatch (DetectEngineThreadCtx *det_ctx,
568  Flow *f, uint8_t flags,
569  void *state, void *txv, const Signature *s,
570  const SigMatchCtx *ctx)
571 {
572  return DetectLuaAppMatchCommon(det_ctx, f, flags, state, s, ctx);
573 }
574 
575 #ifdef UNITTESTS
576 /* if this ptr is set the lua setup functions will use this buffer as the
577  * lua script instead of calling luaL_loadfile on the filename supplied. */
578 static const char *ut_script = NULL;
579 #endif
580 
581 static void *DetectLuaThreadInit(void *data)
582 {
583  int status;
584  DetectLuaData *lua = (DetectLuaData *)data;
585  BUG_ON(lua == NULL);
586 
587  DetectLuaThreadData *t = SCMalloc(sizeof(DetectLuaThreadData));
588  if (unlikely(t == NULL)) {
589  SCLogError(SC_ERR_LUA_ERROR, "couldn't alloc ctx memory");
590  return NULL;
591  }
592  memset(t, 0x00, sizeof(DetectLuaThreadData));
593 
594  t->alproto = lua->alproto;
595  t->flags = lua->flags;
596 
597  t->luastate = LuaGetState();
598  if (t->luastate == NULL) {
599  SCLogError(SC_ERR_LUA_ERROR, "luastate pool depleted");
600  goto error;
601  }
602 
603  luaL_openlibs(t->luastate);
604 
605  LuaRegisterExtensions(t->luastate);
606 
607  lua_pushinteger(t->luastate, (lua_Integer)(lua->sid));
608  lua_setglobal(t->luastate, "SCRuleSid");
609  lua_pushinteger(t->luastate, (lua_Integer)(lua->rev));
610  lua_setglobal(t->luastate, "SCRuleRev");
611  lua_pushinteger(t->luastate, (lua_Integer)(lua->gid));
612  lua_setglobal(t->luastate, "SCRuleGid");
613 
614  /* hackish, needed to allow unittests to pass buffers as scripts instead of files */
615 #ifdef UNITTESTS
616  if (ut_script != NULL) {
617  status = luaL_loadbuffer(t->luastate, ut_script, strlen(ut_script), "unittest");
618  if (status) {
619  SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(t->luastate, -1));
620  goto error;
621  }
622  } else {
623 #endif
624  status = luaL_loadfile(t->luastate, lua->filename);
625  if (status) {
626  SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(t->luastate, -1));
627  goto error;
628  }
629 #ifdef UNITTESTS
630  }
631 #endif
632 
633  /* prime the script (or something) */
634  if (lua_pcall(t->luastate, 0, 0, 0) != 0) {
635  SCLogError(SC_ERR_LUA_ERROR, "couldn't prime file: %s", lua_tostring(t->luastate, -1));
636  goto error;
637  }
638 
639  return (void *)t;
640 
641 error:
642  if (t->luastate != NULL)
643  LuaReturnState(t->luastate);
644  SCFree(t);
645  return NULL;
646 }
647 
648 static void DetectLuaThreadFree(void *ctx)
649 {
650  if (ctx != NULL) {
651  DetectLuaThreadData *t = (DetectLuaThreadData *)ctx;
652  if (t->luastate != NULL)
653  LuaReturnState(t->luastate);
654  SCFree(t);
655  }
656 }
657 
658 /**
659  * \brief Parse the lua keyword
660  *
661  * \param str Pointer to the user provided option
662  *
663  * \retval lua pointer to DetectLuaData on success
664  * \retval NULL on failure
665  */
666 static DetectLuaData *DetectLuaParse (const DetectEngineCtx *de_ctx, const char *str)
667 {
668  DetectLuaData *lua = NULL;
669 
670  /* We have a correct lua option */
671  lua = SCMalloc(sizeof(DetectLuaData));
672  if (unlikely(lua == NULL))
673  goto error;
674 
675  memset(lua, 0x00, sizeof(DetectLuaData));
676 
677  if (strlen(str) && str[0] == '!') {
678  lua->negated = 1;
679  str++;
680  }
681 
682  /* get full filename */
683  lua->filename = DetectLoadCompleteSigPath(de_ctx, str);
684  if (lua->filename == NULL) {
685  goto error;
686  }
687 
688  return lua;
689 
690 error:
691  if (lua != NULL)
692  DetectLuaFree(lua);
693  return NULL;
694 }
695 
696 static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld)
697 {
698  int status;
699 
700  lua_State *luastate = luaL_newstate();
701  if (luastate == NULL)
702  return -1;
703  luaL_openlibs(luastate);
704 
705  /* hackish, needed to allow unittests to pass buffers as scripts instead of files */
706 #ifdef UNITTESTS
707  if (ut_script != NULL) {
708  status = luaL_loadbuffer(luastate, ut_script, strlen(ut_script), "unittest");
709  if (status) {
710  SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(luastate, -1));
711  goto error;
712  }
713  } else {
714 #endif
715  status = luaL_loadfile(luastate, ld->filename);
716  if (status) {
717  SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(luastate, -1));
718  goto error;
719  }
720 #ifdef UNITTESTS
721  }
722 #endif
723 
724  /* prime the script (or something) */
725  if (lua_pcall(luastate, 0, 0, 0) != 0) {
726  SCLogError(SC_ERR_LUA_ERROR, "couldn't prime file: %s", lua_tostring(luastate, -1));
727  goto error;
728  }
729 
730  lua_getglobal(luastate, "init");
731  if (lua_type(luastate, -1) != LUA_TFUNCTION) {
732  SCLogError(SC_ERR_LUA_ERROR, "no init function in script");
733  goto error;
734  }
735 
736  lua_newtable(luastate); /* stack at -1 */
737  if (lua_gettop(luastate) == 0 || lua_type(luastate, 2) != LUA_TTABLE) {
738  SCLogError(SC_ERR_LUA_ERROR, "no table setup");
739  goto error;
740  }
741 
742  lua_pushliteral(luastate, "script_api_ver"); /* stack at -2 */
743  lua_pushnumber (luastate, 1); /* stack at -3 */
744  lua_settable(luastate, -3);
745 
746  if (lua_pcall(luastate, 1, 1, 0) != 0) {
747  SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'init' function: %s", lua_tostring(luastate, -1));
748  goto error;
749  }
750 
751  /* process returns from script */
752  if (lua_gettop(luastate) == 0) {
753  SCLogError(SC_ERR_LUA_ERROR, "init function in script should return table, nothing returned");
754  goto error;
755  }
756  if (lua_type(luastate, 1) != LUA_TTABLE) {
757  SCLogError(SC_ERR_LUA_ERROR, "init function in script should return table, returned is not table");
758  goto error;
759  }
760 
761  lua_pushnil(luastate);
762  const char *k, *v;
763  while (lua_next(luastate, -2)) {
764  k = lua_tostring(luastate, -2);
765  if (k == NULL)
766  continue;
767 
768  /* handle flowvar separately as it has a table as value */
769  if (strcmp(k, "flowvar") == 0) {
770  if (lua_istable(luastate, -1)) {
771  lua_pushnil(luastate);
772  while (lua_next(luastate, -2) != 0) {
773  /* value at -1, key is at -2 which we ignore */
774  const char *value = lua_tostring(luastate, -1);
775  SCLogDebug("value %s", value);
776  /* removes 'value'; keeps 'key' for next iteration */
777  lua_pop(luastate, 1);
778 
779  if (ld->flowvars == DETECT_LUAJIT_MAX_FLOWVARS) {
780  SCLogError(SC_ERR_LUA_ERROR, "too many flowvars registered");
781  goto error;
782  }
783 
784  uint32_t idx = VarNameStoreSetupAdd((char *)value, VAR_TYPE_FLOW_VAR);
785  ld->flowvar[ld->flowvars++] = idx;
786  SCLogDebug("script uses flowvar %u with script id %u", idx, ld->flowvars - 1);
787  }
788  }
789  lua_pop(luastate, 1);
790  continue;
791  } else if (strcmp(k, "flowint") == 0) {
792  if (lua_istable(luastate, -1)) {
793  lua_pushnil(luastate);
794  while (lua_next(luastate, -2) != 0) {
795  /* value at -1, key is at -2 which we ignore */
796  const char *value = lua_tostring(luastate, -1);
797  SCLogDebug("value %s", value);
798  /* removes 'value'; keeps 'key' for next iteration */
799  lua_pop(luastate, 1);
800 
801  if (ld->flowints == DETECT_LUAJIT_MAX_FLOWINTS) {
802  SCLogError(SC_ERR_LUA_ERROR, "too many flowints registered");
803  goto error;
804  }
805 
806  uint32_t idx = VarNameStoreSetupAdd((char *)value, VAR_TYPE_FLOW_INT);
807  ld->flowint[ld->flowints++] = idx;
808  SCLogDebug("script uses flowint %u with script id %u", idx, ld->flowints - 1);
809  }
810  }
811  lua_pop(luastate, 1);
812  continue;
813  }
814 
815  v = lua_tostring(luastate, -1);
816  lua_pop(luastate, 1);
817  if (v == NULL)
818  continue;
819 
820  SCLogDebug("k='%s', v='%s'", k, v);
821  if (strcmp(k, "packet") == 0 && strcmp(v, "true") == 0) {
822  ld->flags |= DATATYPE_PACKET;
823  } else if (strcmp(k, "payload") == 0 && strcmp(v, "true") == 0) {
824  ld->flags |= DATATYPE_PAYLOAD;
825  } else if (strcmp(k, "buffer") == 0 && strcmp(v, "true") == 0) {
826  ld->flags |= DATATYPE_BUFFER;
827 
828  ld->buffername = SCStrdup("buffer");
829  if (ld->buffername == NULL) {
830  SCLogError(SC_ERR_LUA_ERROR, "alloc error");
831  goto error;
832  }
833  } else if (strcmp(k, "stream") == 0 && strcmp(v, "true") == 0) {
834  ld->flags |= DATATYPE_STREAM;
835 
836  ld->buffername = SCStrdup("stream");
837  if (ld->buffername == NULL) {
838  SCLogError(SC_ERR_LUA_ERROR, "alloc error");
839  goto error;
840  }
841 
842  } else if (strncmp(k, "http", 4) == 0 && strcmp(v, "true") == 0) {
843  if (ld->alproto != ALPROTO_UNKNOWN && ld->alproto != ALPROTO_HTTP) {
844  SCLogError(SC_ERR_LUA_ERROR, "can just inspect script against one app layer proto like HTTP at a time");
845  goto error;
846  }
847  if (ld->flags != 0) {
848  SCLogError(SC_ERR_LUA_ERROR, "when inspecting HTTP buffers only a single buffer can be inspected");
849  goto error;
850  }
851 
852  /* http types */
853  ld->alproto = ALPROTO_HTTP;
854 
855  if (strcmp(k, "http.uri") == 0)
856  ld->flags |= DATATYPE_HTTP_URI;
857 
858  else if (strcmp(k, "http.uri.raw") == 0)
859  ld->flags |= DATATYPE_HTTP_URI_RAW;
860 
861  else if (strcmp(k, "http.request_line") == 0)
862  ld->flags |= DATATYPE_HTTP_REQUEST_LINE;
863 
864  else if (strcmp(k, "http.request_headers") == 0)
865  ld->flags |= DATATYPE_HTTP_REQUEST_HEADERS;
866 
867  else if (strcmp(k, "http.request_headers.raw") == 0)
868  ld->flags |= DATATYPE_HTTP_REQUEST_HEADERS_RAW;
869 
870  else if (strcmp(k, "http.request_cookie") == 0)
871  ld->flags |= DATATYPE_HTTP_REQUEST_COOKIE;
872 
873  else if (strcmp(k, "http.request_user_agent") == 0)
874  ld->flags |= DATATYPE_HTTP_REQUEST_UA;
875 
876  else if (strcmp(k, "http.request_body") == 0)
877  ld->flags |= DATATYPE_HTTP_REQUEST_BODY;
878 
879  else if (strcmp(k, "http.response_body") == 0)
880  ld->flags |= DATATYPE_HTTP_RESPONSE_BODY;
881 
882  else if (strcmp(k, "http.response_cookie") == 0)
883  ld->flags |= DATATYPE_HTTP_RESPONSE_COOKIE;
884 
885  else if (strcmp(k, "http.response_headers") == 0)
886  ld->flags |= DATATYPE_HTTP_RESPONSE_HEADERS;
887 
888  else if (strcmp(k, "http.response_headers.raw") == 0)
889  ld->flags |= DATATYPE_HTTP_RESPONSE_HEADERS_RAW;
890 
891  else {
892  SCLogError(SC_ERR_LUA_ERROR, "unsupported http data type %s", k);
893  goto error;
894  }
895 
896  ld->buffername = SCStrdup(k);
897  if (ld->buffername == NULL) {
898  SCLogError(SC_ERR_LUA_ERROR, "alloc error");
899  goto error;
900  }
901  } else if (strncmp(k, "dns", 3) == 0 && strcmp(v, "true") == 0) {
902 
903  ld->alproto = ALPROTO_DNS;
904 
905  if (strcmp(k, "dns.rrname") == 0)
906  ld->flags |= DATATYPE_DNS_RRNAME;
907  else if (strcmp(k, "dns.request") == 0)
908  ld->flags |= DATATYPE_DNS_REQUEST;
909  else if (strcmp(k, "dns.response") == 0)
910  ld->flags |= DATATYPE_DNS_RESPONSE;
911 
912  else {
913  SCLogError(SC_ERR_LUA_ERROR, "unsupported dns data type %s", k);
914  goto error;
915  }
916  ld->buffername = SCStrdup(k);
917  if (ld->buffername == NULL) {
918  SCLogError(SC_ERR_LUA_ERROR, "alloc error");
919  goto error;
920  }
921  } else if (strncmp(k, "tls", 3) == 0 && strcmp(v, "true") == 0) {
922 
923  ld->alproto = ALPROTO_TLS;
924 
925  ld->flags |= DATATYPE_TLS;
926 
927  } else if (strncmp(k, "ssh", 3) == 0 && strcmp(v, "true") == 0) {
928 
929  ld->alproto = ALPROTO_SSH;
930 
931  ld->flags |= DATATYPE_SSH;
932 
933  } else if (strncmp(k, "smtp", 4) == 0 && strcmp(v, "true") == 0) {
934 
935  ld->alproto = ALPROTO_SMTP;
936 
937  ld->flags |= DATATYPE_SMTP;
938 
939  } else if (strncmp(k, "dnp3", 4) == 0 && strcmp(v, "true") == 0) {
940 
941  ld->alproto = ALPROTO_DNP3;
942 
943  ld->flags |= DATATYPE_DNP3;
944 
945  } else {
946  SCLogError(SC_ERR_LUA_ERROR, "unsupported data type %s", k);
947  goto error;
948  }
949  }
950 
951  /* pop the table */
952  lua_pop(luastate, 1);
953  lua_close(luastate);
954  return 0;
955 error:
956  lua_close(luastate);
957  return -1;
958 }
959 
960 /**
961  * \brief this function is used to parse lua options
962  * \brief into the current signature
963  *
964  * \param de_ctx pointer to the Detection Engine Context
965  * \param s pointer to the Current Signature
966  * \param str pointer to the user provided "lua" option
967  *
968  * \retval 0 on Success
969  * \retval -1 on Failure
970  */
971 static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
972 {
973  DetectLuaData *lua = NULL;
974  SigMatch *sm = NULL;
975 
976  lua = DetectLuaParse(de_ctx, str);
977  if (lua == NULL)
978  goto error;
979 
980  if (DetectLuaSetupPrime(de_ctx, lua) == -1) {
981  goto error;
982  }
983 
984  lua->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "lua",
985  DetectLuaThreadInit, (void *)lua,
986  DetectLuaThreadFree, 0);
987  if (lua->thread_ctx_id == -1)
988  goto error;
989 
990  if (lua->alproto != ALPROTO_UNKNOWN) {
991  if (s->alproto != ALPROTO_UNKNOWN && lua->alproto != s->alproto) {
992  goto error;
993  }
994  s->alproto = lua->alproto;
995  }
996 
997  /* Okay so far so good, lets get this into a SigMatch
998  * and put it in the Signature. */
999  sm = SigMatchAlloc();
1000  if (sm == NULL)
1001  goto error;
1002 
1003  sm->type = DETECT_LUA;
1004  sm->ctx = (SigMatchCtx *)lua;
1005 
1006  int list = -1;
1007  if (lua->alproto == ALPROTO_UNKNOWN) {
1008  if (lua->flags & DATATYPE_STREAM)
1009  list = DETECT_SM_LIST_PMATCH;
1010  else {
1011  if (lua->flags & DATATYPE_BUFFER) {
1012  if (DetectBufferGetActiveList(de_ctx, s) != -1) {
1013  list = s->init_data->list;
1014  } else {
1015  SCLogError(SC_ERR_LUA_ERROR, "Lua and sticky buffer failure");
1016  goto error;
1017  }
1018  } else
1019  list = DETECT_SM_LIST_MATCH;
1020  }
1021 
1022  } else if (lua->alproto == ALPROTO_HTTP) {
1023  if (lua->flags & DATATYPE_HTTP_RESPONSE_BODY) {
1024  list = DetectBufferTypeGetByName("file_data");
1025  } else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) {
1026  list = DetectBufferTypeGetByName("http_client_body");
1027  } else if (lua->flags & DATATYPE_HTTP_URI) {
1028  list = DetectBufferTypeGetByName("http_uri");
1029  } else if (lua->flags & DATATYPE_HTTP_URI_RAW) {
1030  list = DetectBufferTypeGetByName("http_raw_uri");
1031  } else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE ||
1032  lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE)
1033  {
1034  list = DetectBufferTypeGetByName("http_cookie");
1035  } else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) {
1036  list = DetectBufferTypeGetByName("http_user_agent");
1037  } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) {
1038  list = DetectBufferTypeGetByName("http_header");
1039  } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) {
1040  list = DetectBufferTypeGetByName("http_raw_header");
1041  } else {
1042  list = DetectBufferTypeGetByName("http_request_line");
1043  }
1044  } else if (lua->alproto == ALPROTO_DNS) {
1045  if (lua->flags & DATATYPE_DNS_RRNAME) {
1046  list = DetectBufferTypeGetByName("dns_query");
1047  } else if (lua->flags & DATATYPE_DNS_REQUEST) {
1048  list = DetectBufferTypeGetByName("dns_request");
1049  } else if (lua->flags & DATATYPE_DNS_RESPONSE) {
1050  list = DetectBufferTypeGetByName("dns_response");
1051  }
1052  } else if (lua->alproto == ALPROTO_TLS) {
1053  list = DetectBufferTypeGetByName("tls_generic");
1054  } else if (lua->alproto == ALPROTO_SSH) {
1055  list = DetectBufferTypeGetByName("ssh_banner");
1056  } else if (lua->alproto == ALPROTO_SMTP) {
1057  list = g_smtp_generic_list_id;
1058  } else if (lua->alproto == ALPROTO_DNP3) {
1059  list = DetectBufferTypeGetByName("dnp3");
1060  } else {
1061  SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s",
1062  AppLayerGetProtoName(lua->alproto));
1063  goto error;
1064  }
1065 
1066  if (list == -1) {
1067  SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s",
1068  AppLayerGetProtoName(lua->alproto));
1069  goto error;
1070  }
1071 
1072  SigMatchAppendSMToList(s, sm, list);
1073 
1074  return 0;
1075 
1076 error:
1077  if (lua != NULL)
1078  DetectLuaFree(lua);
1079  if (sm != NULL)
1080  SCFree(sm);
1081  return -1;
1082 }
1083 
1084 /** \brief post-sig parse function to set the sid,rev,gid into the
1085  * ctx, as this isn't available yet during parsing.
1086  */
1088 {
1089  int i;
1090  SigMatch *sm;
1091 
1092  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
1093  for (sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
1094  if (sm->type != DETECT_LUA)
1095  continue;
1096 
1097  DetectLuaData *ld = (DetectLuaData *)sm->ctx;
1098  ld->sid = s->id;
1099  ld->rev = s->rev;
1100  ld->gid = s->gid;
1101  }
1102  }
1103 }
1104 
1105 /**
1106  * \brief this function will free memory associated with DetectLuaData
1107  *
1108  * \param ptr pointer to DetectLuaData
1109  */
1110 static void DetectLuaFree(void *ptr)
1111 {
1112  if (ptr != NULL) {
1113  DetectLuaData *lua = (DetectLuaData *)ptr;
1114 
1115  if (lua->buffername)
1116  SCFree(lua->buffername);
1117  if (lua->filename)
1118  SCFree(lua->filename);
1119 
1120  SCFree(lua);
1121  }
1122 }
1123 
1124 #ifdef UNITTESTS
1125 /** \test http buffer */
1126 static int LuaMatchTest01(void)
1127 {
1128  const char script[] =
1129  "function init (args)\n"
1130  " local needs = {}\n"
1131  " needs[\"http.request_headers\"] = tostring(true)\n"
1132  " needs[\"flowvar\"] = {\"cnt\"}\n"
1133  " return needs\n"
1134  "end\n"
1135  "\n"
1136  "function match(args)\n"
1137  " a = ScFlowvarGet(0)\n"
1138  " if a then\n"
1139  " a = tostring(tonumber(a)+1)\n"
1140  " print (a)\n"
1141  " ScFlowvarSet(0, a, #a)\n"
1142  " else\n"
1143  " a = tostring(1)\n"
1144  " print (a)\n"
1145  " ScFlowvarSet(0, a, #a)\n"
1146  " end\n"
1147  " \n"
1148  " print (\"pre check: \" .. (a))\n"
1149  " if tonumber(a) == 2 then\n"
1150  " print \"match\"\n"
1151  " return 1\n"
1152  " end\n"
1153  " return 0\n"
1154  "end\n"
1155  "return 0\n";
1156  char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1157  int result = 0;
1158  uint8_t httpbuf1[] =
1159  "POST / HTTP/1.1\r\n"
1160  "Host: www.emergingthreats.net\r\n\r\n";
1161  uint8_t httpbuf2[] =
1162  "POST / HTTP/1.1\r\n"
1163  "Host: www.openinfosecfoundation.org\r\n\r\n";
1164  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1165  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1166  TcpSession ssn;
1167  Packet *p1 = NULL;
1168  Packet *p2 = NULL;
1169  Flow f;
1170  Signature *s = NULL;
1171  ThreadVars th_v;
1172  DetectEngineThreadCtx *det_ctx;
1173 
1175 
1176  ut_script = script;
1177 
1178  memset(&th_v, 0, sizeof(th_v));
1179  memset(&f, 0, sizeof(f));
1180  memset(&ssn, 0, sizeof(ssn));
1181 
1182  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1183  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1184 
1185  FLOW_INITIALIZE(&f);
1186  f.protoctx = (void *)&ssn;
1187  f.proto = IPPROTO_TCP;
1188  f.flags |= FLOW_IPV4;
1189  f.alproto = ALPROTO_HTTP;
1190 
1191  p1->flow = &f;
1195  p2->flow = &f;
1199 
1201 
1203  if (de_ctx == NULL) {
1204  goto end;
1205  }
1206  de_ctx->flags |= DE_QUIET;
1207 
1208  s = DetectEngineAppendSig(de_ctx, sig);
1209  if (s == NULL) {
1210  printf("sig parse failed: ");
1211  goto end;
1212  }
1213 
1214  SigGroupBuild(de_ctx);
1215  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1216 
1217  FLOWLOCK_WRLOCK(&f);
1218  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1219  STREAM_TOSERVER, httpbuf1, httplen1);
1220  if (r != 0) {
1221  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1222  FLOWLOCK_UNLOCK(&f);
1223  goto end;
1224  }
1225  FLOWLOCK_UNLOCK(&f);
1226  HtpState *http_state = f.alstate;
1227  if (http_state == NULL) {
1228  printf("no http state: ");
1229  goto end;
1230  }
1231 
1232  /* do detect for p1 */
1233  SCLogDebug("inspecting p1");
1234  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1235 
1236  if ((PacketAlertCheck(p1, 1))) {
1237  printf("sid 1 didn't match on p1 but should have: ");
1238  goto end;
1239  }
1240 
1241  FLOWLOCK_WRLOCK(&f);
1242  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1243  STREAM_TOSERVER, httpbuf2, httplen2);
1244  if (r != 0) {
1245  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1246  FLOWLOCK_UNLOCK(&f);
1247  goto end;
1248  }
1249  FLOWLOCK_UNLOCK(&f);
1250  /* do detect for p2 */
1251  SCLogDebug("inspecting p2");
1252  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1253 
1254  if (!(PacketAlertCheck(p2, 1))) {
1255  printf("sid 1 didn't match on p2 but should have: ");
1256  goto end;
1257  }
1258 
1259  FlowVar *fv = FlowVarGet(&f, 1);
1260  if (fv == NULL) {
1261  printf("no flowvar: ");
1262  goto end;
1263  }
1264 
1265  if (fv->data.fv_str.value_len != 1) {
1266  printf("%u != %u: ", fv->data.fv_str.value_len, 1);
1267  goto end;
1268  }
1269 
1270  if (memcmp(fv->data.fv_str.value, "2", 1) != 0) {
1271  PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len);
1272 
1273  printf("buffer mismatch: ");
1274  goto end;
1275  }
1276 
1277  result = 1;
1278 end:
1279  if (alp_tctx != NULL)
1280  AppLayerParserThreadCtxFree(alp_tctx);
1281  if (de_ctx != NULL)
1282  DetectEngineCtxFree(de_ctx);
1283 
1285  FLOW_DESTROY(&f);
1286  UTHFreePackets(&p1, 1);
1287  UTHFreePackets(&p2, 1);
1288  return result;
1289 }
1290 
1291 /** \test payload buffer */
1292 static int LuaMatchTest02(void)
1293 {
1294  const char script[] =
1295  "function init (args)\n"
1296  " local needs = {}\n"
1297  " needs[\"payload\"] = tostring(true)\n"
1298  " needs[\"flowvar\"] = {\"cnt\"}\n"
1299  " return needs\n"
1300  "end\n"
1301  "\n"
1302  "function match(args)\n"
1303  " a = ScFlowvarGet(0)\n"
1304  " if a then\n"
1305  " a = tostring(tonumber(a)+1)\n"
1306  " print (a)\n"
1307  " ScFlowvarSet(0, a, #a)\n"
1308  " else\n"
1309  " a = tostring(1)\n"
1310  " print (a)\n"
1311  " ScFlowvarSet(0, a, #a)\n"
1312  " end\n"
1313  " \n"
1314  " print (\"pre check: \" .. (a))\n"
1315  " if tonumber(a) == 2 then\n"
1316  " print \"match\"\n"
1317  " return 1\n"
1318  " end\n"
1319  " return 0\n"
1320  "end\n"
1321  "return 0\n";
1322  char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1323  int result = 0;
1324  uint8_t httpbuf1[] =
1325  "POST / HTTP/1.1\r\n"
1326  "Host: www.emergingthreats.net\r\n\r\n";
1327  uint8_t httpbuf2[] =
1328  "POST / HTTP/1.1\r\n"
1329  "Host: www.openinfosecfoundation.org\r\n\r\n";
1330  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1331  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1332  TcpSession ssn;
1333  Packet *p1 = NULL;
1334  Packet *p2 = NULL;
1335  Flow f;
1336  Signature *s = NULL;
1337  ThreadVars th_v;
1338  DetectEngineThreadCtx *det_ctx;
1339 
1340  ut_script = script;
1341 
1342  memset(&th_v, 0, sizeof(th_v));
1343  memset(&f, 0, sizeof(f));
1344  memset(&ssn, 0, sizeof(ssn));
1345 
1346  p1 = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP);
1347  p2 = UTHBuildPacket(httpbuf2, httplen2, IPPROTO_TCP);
1348 
1349  FLOW_INITIALIZE(&f);
1350  f.protoctx = (void *)&ssn;
1351  f.proto = IPPROTO_TCP;
1352  f.flags |= FLOW_IPV4;
1353  f.alproto = ALPROTO_HTTP;
1354 
1355  p1->flow = &f;
1359  p2->flow = &f;
1363 
1365 
1367  if (de_ctx == NULL) {
1368  goto end;
1369  }
1370  de_ctx->flags |= DE_QUIET;
1371 
1372  s = DetectEngineAppendSig(de_ctx, sig);
1373  if (s == NULL) {
1374  printf("sig parse failed: ");
1375  goto end;
1376  }
1377 
1378  SigGroupBuild(de_ctx);
1379  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1380 
1381  /* do detect for p1 */
1382  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1383 
1384  if ((PacketAlertCheck(p1, 1))) {
1385  printf("sid 1 didn't match on p1 but should have: ");
1386  goto end;
1387  }
1388 
1389  /* do detect for p2 */
1390  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1391 
1392  if (!(PacketAlertCheck(p2, 1))) {
1393  printf("sid 1 didn't match on p2 but should have: ");
1394  goto end;
1395  }
1396 
1397  FlowVar *fv = FlowVarGet(&f, 1);
1398  if (fv == NULL) {
1399  printf("no flowvar: ");
1400  goto end;
1401  }
1402 
1403  if (fv->data.fv_str.value_len != 1) {
1404  printf("%u != %u: ", fv->data.fv_str.value_len, 1);
1405  goto end;
1406  }
1407 
1408  if (memcmp(fv->data.fv_str.value, "2", 1) != 0) {
1409  PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len);
1410 
1411  printf("buffer mismatch: ");
1412  goto end;
1413  }
1414 
1415  result = 1;
1416 end:
1417  if (de_ctx != NULL)
1418  DetectEngineCtxFree(de_ctx);
1419 
1421  FLOW_DESTROY(&f);
1422  UTHFreePackets(&p1, 1);
1423  UTHFreePackets(&p2, 1);
1424  return result;
1425 }
1426 
1427 /** \test packet buffer */
1428 static int LuaMatchTest03(void)
1429 {
1430  const char script[] =
1431  "function init (args)\n"
1432  " local needs = {}\n"
1433  " needs[\"packet\"] = tostring(true)\n"
1434  " needs[\"flowvar\"] = {\"cnt\"}\n"
1435  " return needs\n"
1436  "end\n"
1437  "\n"
1438  "function match(args)\n"
1439  " a = ScFlowvarGet(0)\n"
1440  " if a then\n"
1441  " a = tostring(tonumber(a)+1)\n"
1442  " print (a)\n"
1443  " ScFlowvarSet(0, a, #a)\n"
1444  " else\n"
1445  " a = tostring(1)\n"
1446  " print (a)\n"
1447  " ScFlowvarSet(0, a, #a)\n"
1448  " end\n"
1449  " \n"
1450  " print (\"pre check: \" .. (a))\n"
1451  " if tonumber(a) == 2 then\n"
1452  " print \"match\"\n"
1453  " return 1\n"
1454  " end\n"
1455  " return 0\n"
1456  "end\n"
1457  "return 0\n";
1458  char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1459  int result = 0;
1460  uint8_t httpbuf1[] =
1461  "POST / HTTP/1.1\r\n"
1462  "Host: www.emergingthreats.net\r\n\r\n";
1463  uint8_t httpbuf2[] =
1464  "POST / HTTP/1.1\r\n"
1465  "Host: www.openinfosecfoundation.org\r\n\r\n";
1466  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1467  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1468  TcpSession ssn;
1469  Packet *p1 = NULL;
1470  Packet *p2 = NULL;
1471  Flow f;
1472  Signature *s = NULL;
1473  ThreadVars th_v;
1474  DetectEngineThreadCtx *det_ctx;
1475 
1476  ut_script = script;
1477 
1478  memset(&th_v, 0, sizeof(th_v));
1479  memset(&f, 0, sizeof(f));
1480  memset(&ssn, 0, sizeof(ssn));
1481 
1482  p1 = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP);
1483  p2 = UTHBuildPacket(httpbuf2, httplen2, IPPROTO_TCP);
1484 
1485  FLOW_INITIALIZE(&f);
1486  f.protoctx = (void *)&ssn;
1487  f.proto = IPPROTO_TCP;
1488  f.flags |= FLOW_IPV4;
1489  f.alproto = ALPROTO_HTTP;
1490 
1491  p1->flow = &f;
1495  p2->flow = &f;
1499 
1501 
1503  if (de_ctx == NULL) {
1504  goto end;
1505  }
1506  de_ctx->flags |= DE_QUIET;
1507 
1508  s = DetectEngineAppendSig(de_ctx, sig);
1509  if (s == NULL) {
1510  printf("sig parse failed: ");
1511  goto end;
1512  }
1513 
1514  SigGroupBuild(de_ctx);
1515  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1516 
1517  /* do detect for p1 */
1518  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1519 
1520  if ((PacketAlertCheck(p1, 1))) {
1521  printf("sid 1 didn't match on p1 but should have: ");
1522  goto end;
1523  }
1524 
1525  /* do detect for p2 */
1526  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1527 
1528  if (!(PacketAlertCheck(p2, 1))) {
1529  printf("sid 1 didn't match on p2 but should have: ");
1530  goto end;
1531  }
1532 
1533  FlowVar *fv = FlowVarGet(&f, 1);
1534  if (fv == NULL) {
1535  printf("no flowvar: ");
1536  goto end;
1537  }
1538 
1539  if (fv->data.fv_str.value_len != 1) {
1540  printf("%u != %u: ", fv->data.fv_str.value_len, 1);
1541  goto end;
1542  }
1543 
1544  if (memcmp(fv->data.fv_str.value, "2", 1) != 0) {
1545  PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len);
1546 
1547  printf("buffer mismatch: ");
1548  goto end;
1549  }
1550 
1551  result = 1;
1552 end:
1553  if (de_ctx != NULL)
1554  DetectEngineCtxFree(de_ctx);
1555 
1557  FLOW_DESTROY(&f);
1558  UTHFreePackets(&p1, 1);
1559  UTHFreePackets(&p2, 1);
1560  return result;
1561 }
1562 
1563 /** \test http buffer, flowints */
1564 static int LuaMatchTest04(void)
1565 {
1566  const char script[] =
1567  "function init (args)\n"
1568  " local needs = {}\n"
1569  " needs[\"http.request_headers\"] = tostring(true)\n"
1570  " needs[\"flowint\"] = {\"cnt\"}\n"
1571  " return needs\n"
1572  "end\n"
1573  "\n"
1574  "function match(args)\n"
1575  " print \"inspecting\""
1576  " a = ScFlowintGet(0)\n"
1577  " if a then\n"
1578  " ScFlowintSet(0, a + 1)\n"
1579  " else\n"
1580  " ScFlowintSet(0, 1)\n"
1581  " end\n"
1582  " \n"
1583  " a = ScFlowintGet(0)\n"
1584  " if a == 2 then\n"
1585  " print \"match\"\n"
1586  " return 1\n"
1587  " end\n"
1588  " return 0\n"
1589  "end\n"
1590  "return 0\n";
1591  char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1592  int result = 0;
1593  uint8_t httpbuf1[] =
1594  "POST / HTTP/1.1\r\n"
1595  "Host: www.emergingthreats.net\r\n\r\n";
1596  uint8_t httpbuf2[] =
1597  "POST / HTTP/1.1\r\n"
1598  "Host: www.openinfosecfoundation.org\r\n\r\n";
1599  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1600  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1601  TcpSession ssn;
1602  Packet *p1 = NULL;
1603  Packet *p2 = NULL;
1604  Flow f;
1605  Signature *s = NULL;
1606  ThreadVars th_v;
1607  DetectEngineThreadCtx *det_ctx;
1608 
1610 
1611  ut_script = script;
1612 
1613  memset(&th_v, 0, sizeof(th_v));
1614  memset(&f, 0, sizeof(f));
1615  memset(&ssn, 0, sizeof(ssn));
1616 
1617  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1618  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1619 
1620  FLOW_INITIALIZE(&f);
1621  f.protoctx = (void *)&ssn;
1622  f.proto = IPPROTO_TCP;
1623  f.flags |= FLOW_IPV4;
1624  f.alproto = ALPROTO_HTTP;
1625 
1626  p1->flow = &f;
1630 
1631  p2->flow = &f;
1635 
1637 
1639  if (de_ctx == NULL) {
1640  goto end;
1641  }
1642  de_ctx->flags |= DE_QUIET;
1643 
1644  s = DetectEngineAppendSig(de_ctx, sig);
1645  if (s == NULL) {
1646  printf("sig parse failed: ");
1647  goto end;
1648  }
1649 
1650  SigGroupBuild(de_ctx);
1651  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1652 
1653  FLOWLOCK_WRLOCK(&f);
1654  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1655  STREAM_TOSERVER, httpbuf1, httplen1);
1656  if (r != 0) {
1657  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1658  FLOWLOCK_UNLOCK(&f);
1659  goto end;
1660  }
1661  FLOWLOCK_UNLOCK(&f);
1662  HtpState *http_state = f.alstate;
1663  if (http_state == NULL) {
1664  printf("no http state: ");
1665  goto end;
1666  }
1667 
1668  /* do detect for p1 */
1669  SCLogInfo("p1");
1670  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1671 
1672  if (PacketAlertCheck(p1, 1)) {
1673  printf("sid 1 matched on p1 but should not have: ");
1674  goto end;
1675  }
1676 
1677  FLOWLOCK_WRLOCK(&f);
1678  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1679  STREAM_TOSERVER, httpbuf2, httplen2);
1680  if (r != 0) {
1681  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1682  FLOWLOCK_UNLOCK(&f);
1683  goto end;
1684  }
1685  FLOWLOCK_UNLOCK(&f);
1686  /* do detect for p2 */
1687  SCLogInfo("p2");
1688  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1689 
1690  if (!(PacketAlertCheck(p2, 1))) {
1691  printf("sid 1 didn't match on p2 but should have: ");
1692  goto end;
1693  }
1694 
1695  FlowVar *fv = FlowVarGet(&f, 1);
1696  if (fv == NULL) {
1697  printf("no flowvar: ");
1698  goto end;
1699  }
1700 
1701  if (fv->data.fv_int.value != 2) {
1702  printf("%u != %u: ", fv->data.fv_int.value, 2);
1703  goto end;
1704  }
1705 
1706  result = 1;
1707 end:
1708  if (alp_tctx != NULL)
1709  AppLayerParserThreadCtxFree(alp_tctx);
1710  if (de_ctx != NULL)
1711  DetectEngineCtxFree(de_ctx);
1712 
1714  FLOW_DESTROY(&f);
1715  UTHFreePackets(&p1, 1);
1716  UTHFreePackets(&p2, 1);
1717  return result;
1718 }
1719 
1720 /** \test http buffer, flowints */
1721 static int LuaMatchTest05(void)
1722 {
1723  const char script[] =
1724  "function init (args)\n"
1725  " local needs = {}\n"
1726  " needs[\"http.request_headers\"] = tostring(true)\n"
1727  " needs[\"flowint\"] = {\"cnt\"}\n"
1728  " return needs\n"
1729  "end\n"
1730  "\n"
1731  "function match(args)\n"
1732  " print \"inspecting\""
1733  " a = ScFlowintIncr(0)\n"
1734  " if a == 2 then\n"
1735  " print \"match\"\n"
1736  " return 1\n"
1737  " end\n"
1738  " return 0\n"
1739  "end\n"
1740  "return 0\n";
1741  char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1742  int result = 0;
1743  uint8_t httpbuf1[] =
1744  "POST / HTTP/1.1\r\n"
1745  "Host: www.emergingthreats.net\r\n\r\n";
1746  uint8_t httpbuf2[] =
1747  "POST / HTTP/1.1\r\n"
1748  "Host: www.openinfosecfoundation.org\r\n\r\n";
1749  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1750  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1751  TcpSession ssn;
1752  Packet *p1 = NULL;
1753  Packet *p2 = NULL;
1754  Flow f;
1755  Signature *s = NULL;
1756  ThreadVars th_v;
1757  DetectEngineThreadCtx *det_ctx;
1758 
1760 
1761  ut_script = script;
1762 
1763  memset(&th_v, 0, sizeof(th_v));
1764  memset(&f, 0, sizeof(f));
1765  memset(&ssn, 0, sizeof(ssn));
1766 
1767  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1768  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1769 
1770  FLOW_INITIALIZE(&f);
1771  f.protoctx = (void *)&ssn;
1772  f.proto = IPPROTO_TCP;
1773  f.flags |= FLOW_IPV4;
1774  f.alproto = ALPROTO_HTTP;
1775 
1776  p1->flow = &f;
1780 
1781  p2->flow = &f;
1785 
1787 
1789  if (de_ctx == NULL) {
1790  goto end;
1791  }
1792  de_ctx->flags |= DE_QUIET;
1793 
1794  s = DetectEngineAppendSig(de_ctx, sig);
1795  if (s == NULL) {
1796  printf("sig parse failed: ");
1797  goto end;
1798  }
1799 
1800  SigGroupBuild(de_ctx);
1801  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1802 
1803  FLOWLOCK_WRLOCK(&f);
1804  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1805  STREAM_TOSERVER, httpbuf1, httplen1);
1806  if (r != 0) {
1807  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1808  FLOWLOCK_UNLOCK(&f);
1809  goto end;
1810  }
1811  FLOWLOCK_UNLOCK(&f);
1812  HtpState *http_state = f.alstate;
1813  if (http_state == NULL) {
1814  printf("no http state: ");
1815  goto end;
1816  }
1817 
1818  /* do detect for p1 */
1819  SCLogInfo("p1");
1820  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1821 
1822  if (PacketAlertCheck(p1, 1)) {
1823  printf("sid 1 matched on p1 but should not have: ");
1824  goto end;
1825  }
1826 
1827  FLOWLOCK_WRLOCK(&f);
1828  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1829  STREAM_TOSERVER, httpbuf2, httplen2);
1830  if (r != 0) {
1831  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1832  FLOWLOCK_UNLOCK(&f);
1833  goto end;
1834  }
1835  FLOWLOCK_UNLOCK(&f);
1836  /* do detect for p2 */
1837  SCLogInfo("p2");
1838  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1839 
1840  if (!(PacketAlertCheck(p2, 1))) {
1841  printf("sid 1 didn't match on p2 but should have: ");
1842  goto end;
1843  }
1844 
1845  FlowVar *fv = FlowVarGet(&f, 1);
1846  if (fv == NULL) {
1847  printf("no flowvar: ");
1848  goto end;
1849  }
1850 
1851  if (fv->data.fv_int.value != 2) {
1852  printf("%u != %u: ", fv->data.fv_int.value, 2);
1853  goto end;
1854  }
1855 
1856  result = 1;
1857 end:
1858  if (alp_tctx != NULL)
1859  AppLayerParserThreadCtxFree(alp_tctx);
1860  if (de_ctx != NULL)
1861  DetectEngineCtxFree(de_ctx);
1862 
1864  FLOW_DESTROY(&f);
1865  UTHFreePackets(&p1, 1);
1866  UTHFreePackets(&p2, 1);
1867  return result;
1868 }
1869 
1870 /** \test http buffer, flowints */
1871 static int LuaMatchTest06(void)
1872 {
1873  const char script[] =
1874  "function init (args)\n"
1875  " local needs = {}\n"
1876  " needs[\"http.request_headers\"] = tostring(true)\n"
1877  " needs[\"flowint\"] = {\"cnt\"}\n"
1878  " return needs\n"
1879  "end\n"
1880  "\n"
1881  "function match(args)\n"
1882  " print \"inspecting\""
1883  " a = ScFlowintGet(0)\n"
1884  " if a == nil then\n"
1885  " print \"new var set to 2\""
1886  " ScFlowintSet(0, 2)\n"
1887  " end\n"
1888  " a = ScFlowintDecr(0)\n"
1889  " if a == 0 then\n"
1890  " print \"match\"\n"
1891  " return 1\n"
1892  " end\n"
1893  " return 0\n"
1894  "end\n"
1895  "return 0\n";
1896  char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)";
1897  int result = 0;
1898  uint8_t httpbuf1[] =
1899  "POST / HTTP/1.1\r\n"
1900  "Host: www.emergingthreats.net\r\n\r\n";
1901  uint8_t httpbuf2[] =
1902  "POST / HTTP/1.1\r\n"
1903  "Host: www.openinfosecfoundation.org\r\n\r\n";
1904  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1905  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1906  TcpSession ssn;
1907  Packet *p1 = NULL;
1908  Packet *p2 = NULL;
1909  Flow f;
1910  Signature *s = NULL;
1911  ThreadVars th_v;
1912  DetectEngineThreadCtx *det_ctx;
1913 
1915 
1916  ut_script = script;
1917 
1918  memset(&th_v, 0, sizeof(th_v));
1919  memset(&f, 0, sizeof(f));
1920  memset(&ssn, 0, sizeof(ssn));
1921 
1922  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1923  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1924 
1925  FLOW_INITIALIZE(&f);
1926  f.protoctx = (void *)&ssn;
1927  f.proto = IPPROTO_TCP;
1928  f.flags |= FLOW_IPV4;
1929  f.alproto = ALPROTO_HTTP;
1930 
1931  p1->flow = &f;
1935 
1936  p2->flow = &f;
1940 
1942 
1944  if (de_ctx == NULL) {
1945  goto end;
1946  }
1947  de_ctx->flags |= DE_QUIET;
1948 
1949  s = DetectEngineAppendSig(de_ctx, sig);
1950  if (s == NULL) {
1951  printf("sig parse failed: ");
1952  goto end;
1953  }
1954 
1955  SigGroupBuild(de_ctx);
1956  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1957 
1958  FLOWLOCK_WRLOCK(&f);
1959  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1960  STREAM_TOSERVER, httpbuf1, httplen1);
1961  if (r != 0) {
1962  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1963  FLOWLOCK_UNLOCK(&f);
1964  goto end;
1965  }
1966  FLOWLOCK_UNLOCK(&f);
1967  HtpState *http_state = f.alstate;
1968  if (http_state == NULL) {
1969  printf("no http state: ");
1970  goto end;
1971  }
1972 
1973  /* do detect for p1 */
1974  SCLogInfo("p1");
1975  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1976 
1977  if (PacketAlertCheck(p1, 1)) {
1978  printf("sid 1 matched on p1 but should not have: ");
1979  goto end;
1980  }
1981 
1982  FLOWLOCK_WRLOCK(&f);
1983  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
1984  STREAM_TOSERVER, httpbuf2, httplen2);
1985  if (r != 0) {
1986  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1987  FLOWLOCK_UNLOCK(&f);
1988  goto end;
1989  }
1990  FLOWLOCK_UNLOCK(&f);
1991  /* do detect for p2 */
1992  SCLogInfo("p2");
1993  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1994 
1995  if (!(PacketAlertCheck(p2, 1))) {
1996  printf("sid 1 didn't match on p2 but should have: ");
1997  goto end;
1998  }
1999 
2000  FlowVar *fv = FlowVarGet(&f, 1);
2001  if (fv == NULL) {
2002  printf("no flowvar: ");
2003  goto end;
2004  }
2005 
2006  if (fv->data.fv_int.value != 0) {
2007  printf("%u != %u: ", fv->data.fv_int.value, 0);
2008  goto end;
2009  }
2010 
2011  result = 1;
2012 end:
2013  if (alp_tctx != NULL)
2014  AppLayerParserThreadCtxFree(alp_tctx);
2015  if (de_ctx != NULL)
2016  DetectEngineCtxFree(de_ctx);
2017 
2019  FLOW_DESTROY(&f);
2020  UTHFreePackets(&p1, 1);
2021  UTHFreePackets(&p2, 1);
2022  return result;
2023 }
2024 
2025 #endif
2026 
2027 void DetectLuaRegisterTests(void)
2028 {
2029 #ifdef UNITTESTS
2030  UtRegisterTest("LuaMatchTest01", LuaMatchTest01);
2031  UtRegisterTest("LuaMatchTest02", LuaMatchTest02);
2032  UtRegisterTest("LuaMatchTest03", LuaMatchTest03);
2033  UtRegisterTest("LuaMatchTest04", LuaMatchTest04);
2034  UtRegisterTest("LuaMatchTest05", LuaMatchTest05);
2035  UtRegisterTest("LuaMatchTest06", LuaMatchTest06);
2036 #endif
2037 }
2038 
2039 #endif /* HAVE_LUAJIT */
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1439
SignatureInitData * init_data
Definition: detect.h:586
uint16_t flags
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1179
#define SCLogDebug(...)
Definition: util-debug.h:335
uint16_t value_len
Definition: flow-var.h:39
struct Flow_ * flow
Definition: decode.h:445
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
#define BUG_ON(x)
uint8_t proto
Definition: flow.h:344
uint32_t id
Definition: detect.h:550
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:243
#define unlikely(expr)
Definition: util-optimize.h:35
ThreadVars * tv
Definition: detect.h:1005
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
void * DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
Retrieve thread local keyword ctx by id.
uint64_t offset
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:203
Data needed for Match()
Definition: detect.h:322
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:669
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:240
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
const char * name
Definition: detect.h:1193
uint16_t AppProto
int DetectEngineInspectGenericList(ThreadVars *tv, const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, const uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Signature container.
Definition: detect.h:517
#define TRUE
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:308
void * protoctx
Definition: flow.h:400
uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction)
struct SigMatch_ * next
Definition: detect.h:317
main detection engine ctx
Definition: detect.h:756
FlowVarTypeStr fv_str
Definition: flow-var.h:57
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
void * alstate
Definition: flow.h:438
void DetectLuaPostSetup(Signature *s)
#define DE_QUIET
Definition: detect.h:287
int DetectBufferTypeGetByName(const char *name)
#define str(s)
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
#define SIG_FLAG_TOCLIENT
Definition: detect.h:233
uint8_t flags
Definition: detect.h:757
#define SIGMATCH_NOT_BUILT
Definition: detect.h:1368
Data structures and function prototypes for keeping state for the detection engine.
void(* Free)(void *)
Definition: detect.h:1184
uint8_t type
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1670
uint32_t value
Definition: flow-var.h:44
void DetectLuaRegister(void)
Registration function for keyword: lua.
Definition: detect-lua.c:74
#define SIG_FLAG_TOSERVER
Definition: detect.h:232
#define SCEnter(...)
Definition: util-debug.h:337
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
uint8_t flowflags
Definition: decode.h:439
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
#define STREAM_TOCLIENT
Definition: stream.h:32
#define FLOW_PKT_TOSERVER
Definition: flow.h:201
AppProto alproto
Definition: detect.h:521
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1163
uint32_t gid
Definition: detect.h:551
uint8_t type
Definition: detect.h:314
#define SCReturnInt(x)
Definition: util-debug.h:341
const char * desc
Definition: detect.h:1195
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:288
struct SigMatch_ ** smlists
Definition: detect.h:511
FlowVarTypeInt fv_int
Definition: flow-var.h:58
int DetectBufferTypeRegister(const char *name)
char * DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, const char *sig_file)
Create the path if default-rule-path was specified.
int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void(*FreeFunc)(void *), int mode)
Register Thread keyword context Funcs.
uint8_t * value
Definition: flow-var.h:38
SigMatchCtx * ctx
Definition: detect.h:316
const char * alias
Definition: detect.h:1194
#define SCMalloc(a)
Definition: util-mem.h:222
union FlowVar_::@116 data
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
FlowVar * FlowVarGet(Flow *f, uint32_t idx)
get the flowvar with index &#39;idx&#39; from the flow
Definition: flow-var.c:78
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:141
#define SCFree(a)
Definition: util-mem.h:322
uint16_t tx_id
htp_connp_t * connp
uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type)
add to staging or return existing id if already in there
const char * url
Definition: detect.h:1196
int(* AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *)
Definition: detect.h:1166
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
#define STREAM_TOSERVER
Definition: stream.h:31
uint32_t rev
Definition: detect.h:552
#define GET_PKT_DATA(p)
Definition: decode.h:225
#define PKT_HAS_FLOW
Definition: decode.h:1090
#define SCStrdup(a)
Definition: util-mem.h:268
#define DOC_URL
Definition: suricata.h:86
const char * AppLayerGetProtoName(AppProto alproto)
Given the internal protocol id, returns a string representation of the protocol.
Definition: app-layer.c:766
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
Per thread variable structure.
Definition: threadvars.h:57
#define FLOW_PKT_TOCLIENT
Definition: flow.h:202
AppProto alproto
application level protocol
Definition: flow.h:409
#define GET_PKT_LEN(p)
Definition: decode.h:224
int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f)
uint32_t flags
Definition: decode.h:443
uint16_t payload_len
Definition: decode.h:541
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1187
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself...
Flow data structure.
Definition: flow.h:325
#define FLOW_IPV4
Definition: flow.h:94
uint8_t * payload
Definition: decode.h:540
uint32_t flags
Definition: flow.h:379
#define PKT_STREAM_EST
Definition: decode.h:1088
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr Callback)
register inspect engine at start up time
void(* RegisterTests)(void)
Definition: detect.h:1185
a single match condition for a signature
Definition: detect.h:313
AppLayerParserState * alparser
Definition: flow.h:437
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len)
SigMatchCtx * ctx
Definition: detect.h:325
DetectEngineCtx * DetectEngineCtxInit(void)