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