suricata
detect-engine-modbus.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 ANSSI
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /** \file
29  *
30  * \author David DIALLO <diallo@et.esiea.fr>
31  *
32  * Based on detect-engine-dns.c
33  */
34 
35 #include "suricata-common.h"
36 
37 #include "app-layer.h"
38 #include "app-layer-modbus.h"
39 
40 #include "detect.h"
41 #include "detect-modbus.h"
42 
43 #include "detect-engine-modbus.h"
44 
45 #include "flow.h"
46 
47 #include "util-debug.h"
48 
49 /** \internal
50  *
51  * \brief Value match detection code
52  *
53  * \param value Modbus value context (min, max and mode)
54  * \param min Minimum value to compare
55  * \param inter Interval or maximum (min + inter) value to compare
56  *
57  * \retval 1 match or 0 no match
58  */
59 static int DetectEngineInspectModbusValueMatch(DetectModbusValue *value,
60  uint16_t min,
61  uint16_t inter)
62 {
63  SCEnter();
64  uint16_t max = min + inter;
65 
66  int ret = 0;
67 
68  switch (value->mode) {
69  case DETECT_MODBUS_EQ:
70  if ((value->min >= min) && (value->min <= max))
71  ret = 1;
72  break;
73 
74  case DETECT_MODBUS_LT:
75  if (value->min > min)
76  ret = 1;
77  break;
78 
79  case DETECT_MODBUS_GT:
80  if (value->min < max)
81  ret = 1;
82  break;
83 
84  case DETECT_MODBUS_RA:
85  if ((value->max > min) && (value->min < max))
86  ret = 1;
87  break;
88  }
89 
90  SCReturnInt(ret);
91 }
92 
93 /** \internal
94  *
95  * \brief Do data (and address) inspection & validation for a signature
96  *
97  * \param tx Pointer to Modbus Transaction
98  * \param address Address inspection
99  * \param data Pointer to data signature structure to match
100  *
101  * \retval 0 no match or 1 match
102  */
103 static int DetectEngineInspectModbusData(ModbusTransaction *tx,
104  uint16_t address,
105  DetectModbusValue *data)
106 {
107  SCEnter();
108  uint16_t offset, value = 0, type = tx->type;
109 
110  if (type & MODBUS_TYP_SINGLE) {
111  /* Output/Register(s) Value */
112  if (type & MODBUS_TYP_COILS)
113  value = (tx->data[0])? 1 : 0;
114  else
115  value = tx->data[0];
116  } else if (type & MODBUS_TYP_MULTIPLE) {
117  int i, size = (int) sizeof(tx->data);
118 
119  offset = address - (tx->write.address + 1);
120 
121  /* In case of Coils, offset is in bit (convert in byte) */
122  if (type & MODBUS_TYP_COILS)
123  offset >>= 3;
124 
125  for (i=0; i< size; i++) {
126  /* Select the correct register/coils amongst the output value */
127  if (!(offset--)) {
128  value = tx->data[i];
129  break;
130  }
131  }
132 
133  /* In case of Coils, offset is now in the bit is the rest of previous convert */
134  if (type & MODBUS_TYP_COILS) {
135  offset = (address - (tx->write.address + 1)) & 0x7;
136  value = (value >> offset) & 0x1;
137  }
138  } else {
139  /* It is not possible to define the value that is writing for Mask */
140  /* Write Register function because the current content is not available.*/
141  SCReturnInt(0);
142  }
143 
144  SCReturnInt(DetectEngineInspectModbusValueMatch(data, value, 0));
145 }
146 
147 /** \internal
148  *
149  * \brief Do address inspection & validation for a signature
150  *
151  * \param tx Pointer to Modbus Transaction
152  * \param address Pointer to address signature structure to match
153  * \param access Access mode (READ or WRITE)
154  *
155  * \retval 0 no match or 1 match
156  */
157 static int DetectEngineInspectModbusAddress(ModbusTransaction *tx,
158  DetectModbusValue *address,
159  uint8_t access)
160 {
161  SCEnter();
162  int ret = 0;
163 
164  /* Check if read/write address of request is at/in the address range of signature */
165  if (access == MODBUS_TYP_READ) {
166  /* In the PDU Coils are addresses starting at zero */
167  /* therefore Coils numbered 1-16 are addressed as 0-15 */
168  ret = DetectEngineInspectModbusValueMatch(address,
169  tx->read.address + 1,
170  tx->read.quantity - 1);
171  } else {
172  /* In the PDU Registers are addresses starting at zero */
173  /* therefore Registers numbered 1-16 are addressed as 0-15 */
174  if (tx->type & MODBUS_TYP_SINGLE)
175  ret = DetectEngineInspectModbusValueMatch(address,
176  tx->write.address + 1,
177  0);
178  else
179  ret = DetectEngineInspectModbusValueMatch(address,
180  tx->write.address + 1,
181  tx->write.quantity - 1);
182  }
183 
184  SCReturnInt(ret);
185 }
186 
187 /** \brief Do the content inspection & validation for a signature
188  *
189  * \param de_ctx Detection engine context
190  * \param det_ctx Detection engine thread context
191  * \param s Signature to inspect ( and sm: SigMatch to inspect)
192  * \param f Flow
193  * \param flags App layer flags
194  * \param alstate App layer state
195  * \param txv Pointer to Modbus Transaction structure
196  *
197  * \retval 0 no match or 1 match
198  */
200  DetectEngineCtx *de_ctx,
201  DetectEngineThreadCtx *det_ctx,
202  const Signature *s,
203  const SigMatchData *smd,
204  Flow *f,
205  uint8_t flags,
206  void *alstate,
207  void *txv,
208  uint64_t tx_id)
209 {
210  SCEnter();
212  DetectModbus *modbus = (DetectModbus *) smd->ctx;
213 
214  int ret = 0;
215 
216  if (modbus == NULL) {
217  SCLogDebug("no modbus state, no match");
218  SCReturnInt(0);
219  }
220 
221  if (modbus->unit_id != NULL) {
222  if (DetectEngineInspectModbusValueMatch(modbus->unit_id, tx->unit_id, 0) == 0) {
223  SCReturnInt(0);
224  } else {
225  ret = 1;
226  }
227  }
228 
229  if (modbus->type == MODBUS_TYP_NONE) {
230  if (modbus->category == MODBUS_CAT_NONE) {
231  if (modbus->function != MODBUS_FUNC_NONE) {
232  if (modbus->function == tx->function) {
233  if (modbus->subfunction != NULL) {
234  SCLogDebug("looking for Modbus server function %d and subfunction %d",
235  modbus->function, *(modbus->subfunction));
236  ret = (*(modbus->subfunction) == (tx->subFunction))? 1 : 0;
237  } else {
238  SCLogDebug("looking for Modbus server function %d", modbus->function);
239  ret = 1;
240  }
241  } else {
242  ret = 0;
243  }
244  }
245  } else {
246  SCLogDebug("looking for Modbus category function %d", modbus->category);
247  ret = (tx->category & modbus->category)? 1 : 0;
248  }
249  } else {
250  uint8_t access = modbus->type & MODBUS_TYP_ACCESS_MASK;
251  uint8_t function = modbus->type & MODBUS_TYP_ACCESS_FUNCTION_MASK;
252 
253  if (access != MODBUS_TYP_NONE) {
254  if ((access & tx->type) && ((function == MODBUS_TYP_NONE) || (function & tx->type))) {
255  if (modbus->address != NULL) {
256  ret = DetectEngineInspectModbusAddress(tx, modbus->address, access);
257 
258  if (ret && (modbus->data != NULL)) {
259  ret = DetectEngineInspectModbusData(tx, modbus->address->min, modbus->data);
260  }
261  } else {
262  SCLogDebug("looking for Modbus access type %d and function type %d", access, function);
263  ret = 1;
264  }
265  } else {
266  ret = 0;
267  }
268  }
269  }
270 
271  SCReturnInt(ret);
272 }
273 
274 #ifdef UNITTESTS /* UNITTESTS */
275 #include "app-layer-parser.h"
276 
277 #include "detect-parse.h"
278 
279 #include "detect-engine.h"
280 
281 #include "flow-util.h"
282 
283 #include "stream-tcp.h"
284 
285 #include "util-unittest.h"
286 #include "util-unittest-helper.h"
287 
288 /* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
289 /* Example of a request to read discrete outputs 20-38 */
290 static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00,
291  /* Protocol ID */ 0x00, 0x00,
292  /* Length */ 0x00, 0x06,
293  /* Unit ID */ 0x0a,
294  /* Function code */ 0x01,
295  /* Starting Address */ 0x78, 0x90,
296  /* Quantity of coils */ 0x00, 0x13 };
297 
298 /* Modbus Application Protocol Specification V1.1b3 6.4: Read Input Registers */
299 /* Example of a request to read input register 9 */
300 static uint8_t readInputsRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A,
301  /* Protocol ID */ 0x00, 0x00,
302  /* Length */ 0x00, 0x06,
303  /* Unit ID */ 0x00,
304  /* Function code */ 0x04,
305  /* Starting Address */ 0x00, 0x08,
306  /* Quantity of Registers */ 0x00, 0x60};
307 
308 /* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */
309 /* Example of a request to read six registers starting at register 4, */
310 /* and to write three registers starting at register 15 */
311 static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34,
312  /* Protocol ID */ 0x00, 0x00,
313  /* Length */ 0x00, 0x11,
314  /* Unit ID */ 0x0a,
315  /* Function code */ 0x17,
316  /* Read Starting Address */ 0x00, 0x03,
317  /* Quantity to Read */ 0x00, 0x06,
318  /* Write Starting Address */ 0x00, 0x0E,
319  /* Quantity to Write */ 0x00, 0x03,
320  /* Write Byte count */ 0x06,
321  /* Write Registers Value */ 0x12, 0x34, /* 15 */
322  0x56, 0x78, /* 16 */
323  0x9A, 0xBC};/* 17 */
324 
325 /* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */
326 /* Example of a request to to remote device to its Listen Only MOde for Modbus Communications. */
327 static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00,
328  /* Protocol ID */ 0x00, 0x00,
329  /* Length */ 0x00, 0x06,
330  /* Unit ID */ 0x00,
331  /* Function code */ 0x08,
332  /* Sub-function code */ 0x00, 0x04,
333  /* Data */ 0x00, 0x00};
334 
335 /* Modbus Application Protocol Specification V1.1b3 Annex A */
336 /* Modbus Reserved Function codes, Subcodes and MEI types */
337 static uint8_t encapsulatedInterfaceTransport[] = {
338  /* Transaction ID */ 0x00, 0x10,
339  /* Protocol ID */ 0x00, 0x00,
340  /* Length */ 0x00, 0x05,
341  /* Unit ID */ 0x00,
342  /* Function code */ 0x2B,
343  /* MEI Type */ 0x0F,
344  /* Data */ 0x00, 0x00};
345 
346 static uint8_t unassigned[] = {/* Transaction ID */ 0x00, 0x0A,
347  /* Protocol ID */ 0x00, 0x00,
348  /* Length */ 0x00, 0x02,
349  /* Unit ID */ 0x00,
350  /* Function code */ 0x12};
351 
352 /** \test Test code function. */
353 static int DetectEngineInspectModbusTest01(void)
354 {
356  DetectEngineThreadCtx *det_ctx = NULL;
357  DetectEngineCtx *de_ctx = NULL;
358  Flow f;
359  Packet *p = NULL;
360  Signature *s = NULL;
361  TcpSession ssn;
362  ThreadVars tv;
363 
364  FAIL_IF_NULL(alp_tctx);
365 
366  memset(&tv, 0, sizeof(ThreadVars));
367  memset(&f, 0, sizeof(Flow));
368  memset(&ssn, 0, sizeof(TcpSession));
369 
370  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
371 
372  FLOW_INITIALIZE(&f);
374  f.protoctx = (void *)&ssn;
375  f.proto = IPPROTO_TCP;
376  f.flags |= FLOW_IPV4;
377 
378  p->flow = &f;
381 
383 
384  de_ctx = DetectEngineCtxInit();
385  FAIL_IF_NULL(de_ctx);
386 
387  de_ctx->flags |= DE_QUIET;
388  s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
389  "(msg:\"Testing modbus code function\"; "
390  "modbus: function 23; sid:1;)");
391  FAIL_IF_NULL(s);
392 
393  SigGroupBuild(de_ctx);
394  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
395 
396  FLOWLOCK_WRLOCK(&f);
397  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
399  readWriteMultipleRegistersReq,
400  sizeof(readWriteMultipleRegistersReq));
401  FAIL_IF_NOT(r == 0);
402  FLOWLOCK_UNLOCK(&f);
403 
404  ModbusState *modbus_state = f.alstate;
405  FAIL_IF_NULL(modbus_state);
406 
407  /* do detect */
408  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
409 
411 
412  AppLayerParserThreadCtxFree(alp_tctx);
413  DetectEngineThreadCtxDeinit(&tv, det_ctx);
414  SigGroupCleanup(de_ctx);
415  DetectEngineCtxFree(de_ctx);
416 
418  FLOW_DESTROY(&f);
419  UTHFreePacket(p);
420  PASS;
421 }
422 
423 /** \test code function and code subfunction. */
424 static int DetectEngineInspectModbusTest02(void)
425 {
427  DetectEngineThreadCtx *det_ctx = NULL;
428  DetectEngineCtx *de_ctx = NULL;
429  Flow f;
430  Packet *p = NULL;
431  Signature *s = NULL;
432  TcpSession ssn;
433  ThreadVars tv;
434 
435  FAIL_IF_NULL(alp_tctx);
436 
437  memset(&tv, 0, sizeof(ThreadVars));
438  memset(&f, 0, sizeof(Flow));
439  memset(&ssn, 0, sizeof(TcpSession));
440 
441  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
442 
443  FLOW_INITIALIZE(&f);
445  f.protoctx = (void *)&ssn;
446  f.proto = IPPROTO_TCP;
447  f.flags |= FLOW_IPV4;
448 
449  p->flow = &f;
452 
454 
455  de_ctx = DetectEngineCtxInit();
456  FAIL_IF_NULL(de_ctx);
457 
458  de_ctx->flags |= DE_QUIET;
459 
460  s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
461  "(msg:\"Testing modbus function and subfunction\"; "
462  "modbus: function 8, subfunction 4; sid:1;)");
463  FAIL_IF_NULL(s);
464 
465  SigGroupBuild(de_ctx);
466  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
467 
468  FLOWLOCK_WRLOCK(&f);
469  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
470  STREAM_TOSERVER, forceListenOnlyMode,
471  sizeof(forceListenOnlyMode));
472  FAIL_IF_NOT(r == 0);
473  FLOWLOCK_UNLOCK(&f);
474 
475  ModbusState *modbus_state = f.alstate;
476  FAIL_IF_NULL(modbus_state);
477 
478  /* do detect */
479  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
480 
482 
483  AppLayerParserThreadCtxFree(alp_tctx);
484  DetectEngineThreadCtxDeinit(&tv, det_ctx);
485  SigGroupCleanup(de_ctx);
486  DetectEngineCtxFree(de_ctx);
487 
489  FLOW_DESTROY(&f);
490  UTHFreePacket(p);
491  PASS;
492 }
493 
494 /** \test function category. */
495 static int DetectEngineInspectModbusTest03(void)
496 {
498  DetectEngineThreadCtx *det_ctx = NULL;
499  DetectEngineCtx *de_ctx = NULL;
500  Flow f;
501  Packet *p = NULL;
502  Signature *s = NULL;
503  TcpSession ssn;
504  ThreadVars tv;
505 
506  FAIL_IF_NULL(alp_tctx);
507 
508  memset(&tv, 0, sizeof(ThreadVars));
509  memset(&f, 0, sizeof(Flow));
510  memset(&ssn, 0, sizeof(TcpSession));
511 
512  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
513 
514  FLOW_INITIALIZE(&f);
516  f.protoctx = (void *)&ssn;
517  f.proto = IPPROTO_TCP;
518  f.flags |= FLOW_IPV4;
519 
520  p->flow = &f;
523 
525 
526  de_ctx = DetectEngineCtxInit();
527  FAIL_IF_NULL(de_ctx);
528 
529  de_ctx->flags |= DE_QUIET;
530 
531  s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
532  "(msg:\"Testing modbus category function\"; "
533  "modbus: function reserved; sid:1;)");
534  FAIL_IF_NULL(s);
535 
536  SigGroupBuild(de_ctx);
537  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
538 
539  FLOWLOCK_WRLOCK(&f);
540  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
542  encapsulatedInterfaceTransport,
543  sizeof(encapsulatedInterfaceTransport));
544  FAIL_IF_NOT(r == 0);
545  FLOWLOCK_UNLOCK(&f);
546 
547  ModbusState *modbus_state = f.alstate;
548  FAIL_IF_NULL(modbus_state);
549 
550  /* do detect */
551  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
552 
554 
555  AppLayerParserThreadCtxFree(alp_tctx);
556  DetectEngineThreadCtxDeinit(&tv, det_ctx);
557  SigGroupCleanup(de_ctx);
558  DetectEngineCtxFree(de_ctx);
559 
561  FLOW_DESTROY(&f);
562  UTHFreePacket(p);
563  PASS;
564 }
565 
566 /** \test negative function category. */
567 static int DetectEngineInspectModbusTest04(void)
568 {
570  DetectEngineThreadCtx *det_ctx = NULL;
571  DetectEngineCtx *de_ctx = NULL;
572  Flow f;
573  Packet *p = NULL;
574  Signature *s = NULL;
575  TcpSession ssn;
576  ThreadVars tv;
577 
578  FAIL_IF_NULL(alp_tctx);
579 
580  memset(&tv, 0, sizeof(ThreadVars));
581  memset(&f, 0, sizeof(Flow));
582  memset(&ssn, 0, sizeof(TcpSession));
583 
584  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
585 
586  FLOW_INITIALIZE(&f);
588  f.protoctx = (void *)&ssn;
589  f.proto = IPPROTO_TCP;
590  f.flags |= FLOW_IPV4;
591 
592  p->flow = &f;
595 
597 
598  de_ctx = DetectEngineCtxInit();
599  FAIL_IF_NULL(de_ctx);
600 
601  de_ctx->flags |= DE_QUIET;
602 
603  s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
604  "(msg:\"Testing modbus category function\"; "
605  "modbus: function !assigned; sid:1;)");
606  FAIL_IF_NULL(s);
607 
608  SigGroupBuild(de_ctx);
609  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
610 
611  FLOWLOCK_WRLOCK(&f);
612  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
613  STREAM_TOSERVER, unassigned,
614  sizeof(unassigned));
615  FAIL_IF_NOT(r == 0);
616  FLOWLOCK_UNLOCK(&f);
617 
618  ModbusState *modbus_state = f.alstate;
619  FAIL_IF_NULL(modbus_state);
620 
621  /* do detect */
622  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
623 
625 
626  AppLayerParserThreadCtxFree(alp_tctx);
627  DetectEngineThreadCtxDeinit(&tv, det_ctx);
628  SigGroupCleanup(de_ctx);
629  DetectEngineCtxFree(de_ctx);
630 
632  FLOW_DESTROY(&f);
633  UTHFreePacket(p);
634  PASS;
635 }
636 
637 /** \test access type. */
638 static int DetectEngineInspectModbusTest05(void)
639 {
641  DetectEngineThreadCtx *det_ctx = NULL;
642  DetectEngineCtx *de_ctx = NULL;
643  Flow f;
644  Packet *p = NULL;
645  Signature *s = NULL;
646  TcpSession ssn;
647  ThreadVars tv;
648 
649  FAIL_IF_NULL(alp_tctx);
650 
651  memset(&tv, 0, sizeof(ThreadVars));
652  memset(&f, 0, sizeof(Flow));
653  memset(&ssn, 0, sizeof(TcpSession));
654 
655  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
656 
657  FLOW_INITIALIZE(&f);
659  f.protoctx = (void *)&ssn;
660  f.proto = IPPROTO_TCP;
661  f.flags |= FLOW_IPV4;
662 
663  p->flow = &f;
666 
668 
669  de_ctx = DetectEngineCtxInit();
670  FAIL_IF_NULL(de_ctx);
671 
672  de_ctx->flags |= DE_QUIET;
673 
674  s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
675  "(msg:\"Testing modbus access type\"; "
676  "modbus: access read; sid:1;)");
677  FAIL_IF_NULL(s);
678 
679  SigGroupBuild(de_ctx);
680  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
681 
682  FLOWLOCK_WRLOCK(&f);
683  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
684  STREAM_TOSERVER, readCoilsReq,
685  sizeof(readCoilsReq));
686  FAIL_IF_NOT(r == 0);
687  FLOWLOCK_UNLOCK(&f);
688 
689  ModbusState *modbus_state = f.alstate;
690  FAIL_IF_NULL(modbus_state);
691 
692  /* do detect */
693  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
694 
696 
697  AppLayerParserThreadCtxFree(alp_tctx);
698  DetectEngineThreadCtxDeinit(&tv, det_ctx);
699  SigGroupCleanup(de_ctx);
700  DetectEngineCtxFree(de_ctx);
701 
703  FLOW_DESTROY(&f);
704  UTHFreePacket(p);
705  PASS;
706 }
707 
708 /** \test access function. */
709 static int DetectEngineInspectModbusTest06(void)
710 {
712  DetectEngineThreadCtx *det_ctx = NULL;
713  DetectEngineCtx *de_ctx = NULL;
714  Flow f;
715  Packet *p = NULL;
716  Signature *s = NULL;
717  TcpSession ssn;
718  ThreadVars tv;
719 
720  FAIL_IF_NULL(alp_tctx);
721 
722  memset(&tv, 0, sizeof(ThreadVars));
723  memset(&f, 0, sizeof(Flow));
724  memset(&ssn, 0, sizeof(TcpSession));
725 
726  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
727 
728  FLOW_INITIALIZE(&f);
730  f.protoctx = (void *)&ssn;
731  f.proto = IPPROTO_TCP;
732  f.flags |= FLOW_IPV4;
733 
734  p->flow = &f;
737 
739 
740  de_ctx = DetectEngineCtxInit();
741  FAIL_IF_NULL(de_ctx);
742 
743  de_ctx->flags |= DE_QUIET;
744 
745  s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
746  "(msg:\"Testing modbus access type\"; "
747  "modbus: access read input; sid:1;)");
748  FAIL_IF_NULL(s);
749 
750  SigGroupBuild(de_ctx);
751  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
752 
753  FLOWLOCK_WRLOCK(&f);
754  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
755  STREAM_TOSERVER, readInputsRegistersReq,
756  sizeof(readInputsRegistersReq));
757  FAIL_IF_NOT(r == 0);
758  FLOWLOCK_UNLOCK(&f);
759 
760  ModbusState *modbus_state = f.alstate;
761  FAIL_IF_NULL(modbus_state);
762 
763  /* do detect */
764  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
765 
767 
768  AppLayerParserThreadCtxFree(alp_tctx);
769  DetectEngineThreadCtxDeinit(&tv, det_ctx);
770  SigGroupCleanup(de_ctx);
771  DetectEngineCtxFree(de_ctx);
772 
774  FLOW_DESTROY(&f);
775  UTHFreePacket(p);
776  PASS;
777 }
778 
779 /** \test read access at an address. */
780 static int DetectEngineInspectModbusTest07(void)
781 {
783  DetectEngineThreadCtx *det_ctx = NULL;
784  DetectEngineCtx *de_ctx = NULL;
785  Flow f;
786  Packet *p = NULL;
787  Signature *s = NULL;
788  TcpSession ssn;
789  ThreadVars tv;
790 
791  FAIL_IF_NULL(alp_tctx);
792 
793  memset(&tv, 0, sizeof(ThreadVars));
794  memset(&f, 0, sizeof(Flow));
795  memset(&ssn, 0, sizeof(TcpSession));
796 
797  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
798 
799  FLOW_INITIALIZE(&f);
801  f.protoctx = (void *)&ssn;
802  f.proto = IPPROTO_TCP;
803  f.flags |= FLOW_IPV4;
804 
805  p->flow = &f;
808 
810 
811  de_ctx = DetectEngineCtxInit();
812  FAIL_IF_NULL(de_ctx);
813 
814  de_ctx->flags |= DE_QUIET;
815 
816  s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
817  "(msg:\"Testing modbus address access\"; "
818  "modbus: access read, address 30870; sid:1;)");
819  FAIL_IF_NULL(s);
820 
821  SigGroupBuild(de_ctx);
822  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
823 
824  FLOWLOCK_WRLOCK(&f);
825  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
826  STREAM_TOSERVER, readCoilsReq,
827  sizeof(readCoilsReq));
828  FAIL_IF_NOT(r == 0);
829  FLOWLOCK_UNLOCK(&f);
830 
831  ModbusState *modbus_state = f.alstate;
832  FAIL_IF_NULL(modbus_state);
833 
834  /* do detect */
835  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
836 
838 
839  AppLayerParserThreadCtxFree(alp_tctx);
840  DetectEngineThreadCtxDeinit(&tv, det_ctx);
841  SigGroupCleanup(de_ctx);
842  DetectEngineCtxFree(de_ctx);
843 
845  FLOW_DESTROY(&f);
846  UTHFreePacket(p);
847  PASS;
848 }
849 
850 /** \test read access at a range of address. */
851 static int DetectEngineInspectModbusTest08(void)
852 {
854  DetectEngineThreadCtx *det_ctx = NULL;
855  DetectEngineCtx *de_ctx = NULL;
856  Flow f;
857  Packet *p = NULL;
858  Signature *s = NULL;
859  TcpSession ssn;
860  ThreadVars tv;
861 
862  FAIL_IF_NULL(alp_tctx);
863 
864  memset(&tv, 0, sizeof(ThreadVars));
865  memset(&f, 0, sizeof(Flow));
866  memset(&ssn, 0, sizeof(TcpSession));
867 
868  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
869 
870  FLOW_INITIALIZE(&f);
872  f.protoctx = (void *)&ssn;
873  f.proto = IPPROTO_TCP;
874  f.flags |= FLOW_IPV4;
875 
876  p->flow = &f;
879 
881 
882  de_ctx = DetectEngineCtxInit();
883  FAIL_IF_NULL(de_ctx);
884 
885  de_ctx->flags |= DE_QUIET;
886 
887  /* readInputsRegistersReq, Starting Address = 0x08, Quantity of Registers = 0x60 */
888  /* Read access address from 9 to 104 */
889  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
890  "(msg:\"Testing modbus access\"; "
891  "modbus: access read input, "
892  "address <9; sid:1;)");
893 
894  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
895  "(msg:\"Testing modbus access\"; "
896  "modbus: access read input, "
897  "address 9; sid:2;)");
898 
899  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
900  "(msg:\"Testing modbus access\"; "
901  "modbus: access read input, "
902  "address 5<>9; sid:3;)");
903 
904  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
905  "(msg:\"Testing modbus access\"; "
906  "modbus: access read input, "
907  "address <10; sid:4;)");
908 
909  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
910  "(msg:\"Testing modbus access\"; "
911  "modbus: access read input, "
912  "address 5<>10; sid:5;)");
913 
914  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
915  "(msg:\"Testing modbus access\"; "
916  "modbus: access read input, "
917  "address >103; sid:6;)");
918 
919  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
920  "(msg:\"Testing modbus access\"; "
921  "modbus: access read input, "
922  "address 103<>110; sid:7;)");
923 
924  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
925  "(msg:\"Testing modbus access\"; "
926  "modbus: access read input, "
927  "address 104; sid:8;)");
928 
929  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
930  "(msg:\"Testing modbus access\"; "
931  "modbus: access read input, "
932  "address >104; sid:9;)");
933 
934  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
935  "(msg:\"Testing modbus access\"; "
936  "modbus: access read input, "
937  "address 104<>110; sid:10;)");
938  FAIL_IF_NULL(s);
939 
940  SigGroupBuild(de_ctx);
941  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
942 
943  FLOWLOCK_WRLOCK(&f);
944  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
945  STREAM_TOSERVER, readInputsRegistersReq,
946  sizeof(readInputsRegistersReq));
947  FAIL_IF_NOT(r == 0);
948  FLOWLOCK_UNLOCK(&f);
949 
950  ModbusState *modbus_state = f.alstate;
951  FAIL_IF_NULL(modbus_state);
952 
953  /* do detect */
954  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
955 
956  FAIL_IF(PacketAlertCheck(p, 1));
957  FAIL_IF(PacketAlertCheck(p, 3));
958  FAIL_IF(PacketAlertCheck(p, 9));
959  FAIL_IF(PacketAlertCheck(p, 10));
960 
967 
968  AppLayerParserThreadCtxFree(alp_tctx);
969  DetectEngineThreadCtxDeinit(&tv, det_ctx);
970  SigGroupCleanup(de_ctx);
971  DetectEngineCtxFree(de_ctx);
972 
974  FLOW_DESTROY(&f);
975  UTHFreePacket(p);
976  PASS;
977 }
978 
979 /** \test write access at a address in a range of value. */
980 static int DetectEngineInspectModbusTest09(void)
981 {
983  DetectEngineThreadCtx *det_ctx = NULL;
984  DetectEngineCtx *de_ctx = NULL;
985  Flow f;
986  Packet *p = NULL;
987  Signature *s = NULL;
988  TcpSession ssn;
989  ThreadVars tv;
990 
991  FAIL_IF_NULL(alp_tctx);
992 
993  memset(&tv, 0, sizeof(ThreadVars));
994  memset(&f, 0, sizeof(Flow));
995  memset(&ssn, 0, sizeof(TcpSession));
996 
997  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
998 
999  FLOW_INITIALIZE(&f);
1000  f.alproto = ALPROTO_MODBUS;
1001  f.protoctx = (void *)&ssn;
1002  f.proto = IPPROTO_TCP;
1003  f.flags |= FLOW_IPV4;
1004 
1005  p->flow = &f;
1008 
1010 
1011  de_ctx = DetectEngineCtxInit();
1012  FAIL_IF_NULL(de_ctx);
1013 
1014  de_ctx->flags |= DE_QUIET;
1015 
1016  /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
1017  /* Write access register address 15 = 0x1234 (4660) */
1018  /* Write access register address 16 = 0x5678 (22136) */
1019  /* Write access register address 17 = 0x9ABC (39612) */
1020  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1021  "(msg:\"Testing modbus write access\"; "
1022  "modbus: access write holding, "
1023  "address 15, value <4660; sid:1;)");
1024 
1025  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1026  "(msg:\"Testing modbus write access\"; "
1027  "modbus: access write holding, "
1028  "address 16, value <22137; sid:2;)");
1029 
1030  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1031  "(msg:\"Testing modbus write access\"; "
1032  "modbus: access write holding, "
1033  "address 17, value 39612; sid:3;)");
1034 
1035  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1036  "(msg:\"Testing modbus write access\"; "
1037  "modbus: access write holding, "
1038  "address 15, value 4661; sid:4;)");
1039 
1040  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1041  "(msg:\"Testing modbus write access\"; "
1042  "modbus: access write holding, "
1043  "address 16, value 20000<>22136; sid:5;)");
1044 
1045  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1046  "(msg:\"Testing modbus write access\"; "
1047  "modbus: access write holding, "
1048  "address 17, value 30000<>39613; sid:6;)");
1049 
1050  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1051  "(msg:\"Testing modbus write access\"; "
1052  "modbus: access write holding, "
1053  "address 15, value 4659<>5000; sid:7;)");
1054 
1055  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1056  "(msg:\"Testing modbus write access\"; "
1057  "modbus: access write holding, "
1058  "address 16, value 22136<>30000; sid:8;)");
1059 
1060  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1061  "(msg:\"Testing modbus write access\"; "
1062  "modbus: access write holding, "
1063  "address 17, value >39611; sid:9;)");
1064 
1065  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1066  "(msg:\"Testing modbus write access\"; "
1067  "modbus: access write holding, "
1068  "address 15, value >4660; sid:10;)");
1069  FAIL_IF_NULL(s);
1070 
1071  SigGroupBuild(de_ctx);
1072  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1073 
1074  FLOWLOCK_WRLOCK(&f);
1075  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1077  readWriteMultipleRegistersReq,
1078  sizeof(readWriteMultipleRegistersReq));
1079  FAIL_IF_NOT(r == 0);
1080  FLOWLOCK_UNLOCK(&f);
1081 
1082  ModbusState *modbus_state = f.alstate;
1083  FAIL_IF_NULL(modbus_state);
1084 
1085  /* do detect */
1086  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1087 
1088  FAIL_IF(PacketAlertCheck(p, 1));
1089  FAIL_IF(PacketAlertCheck(p, 4));
1090  FAIL_IF(PacketAlertCheck(p, 5));
1091  FAIL_IF(PacketAlertCheck(p, 8));
1092  FAIL_IF(PacketAlertCheck(p, 10));
1093 
1099 
1100  AppLayerParserThreadCtxFree(alp_tctx);
1101  DetectEngineThreadCtxDeinit(&tv, det_ctx);
1102  SigGroupCleanup(de_ctx);
1103  DetectEngineCtxFree(de_ctx);
1104 
1106  FLOW_DESTROY(&f);
1107  UTHFreePacket(p);
1108  PASS;
1109 }
1110 
1111 /** \test Test code unit_id. */
1112 static int DetectEngineInspectModbusTest10(void)
1113 {
1115  DetectEngineThreadCtx *det_ctx = NULL;
1116  DetectEngineCtx *de_ctx = NULL;
1117  Flow f;
1118  Packet *p = NULL;
1119  Signature *s = NULL;
1120  TcpSession ssn;
1121  ThreadVars tv;
1122 
1123  FAIL_IF_NULL(alp_tctx);
1124 
1125  memset(&tv, 0, sizeof(ThreadVars));
1126  memset(&f, 0, sizeof(Flow));
1127  memset(&ssn, 0, sizeof(TcpSession));
1128 
1129  p = UTHBuildPacket(readWriteMultipleRegistersReq,
1130  sizeof(readWriteMultipleRegistersReq),
1131  IPPROTO_TCP);
1132 
1133  FLOW_INITIALIZE(&f);
1134  f.alproto = ALPROTO_MODBUS;
1135  f.protoctx = (void *)&ssn;
1136  f.proto = IPPROTO_TCP;
1137  f.flags |= FLOW_IPV4;
1138 
1139  p->flow = &f;
1142 
1144 
1145  de_ctx = DetectEngineCtxInit();
1146  FAIL_IF_NULL(de_ctx);
1147 
1148  de_ctx->flags |= DE_QUIET;
1149 
1150  /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
1151  /* Unit ID = 0x0a (10) */
1152  /* Function code = 0x17 (23) */
1153  /* Write access register address 15 = 0x1234 (4660) */
1154  /* Write access register address 16 = 0x5678 (22136) */
1155  /* Write access register address 17 = 0x9ABC (39612) */
1156  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1157  "(msg:\"Testing modbus code unit_id\"; "
1158  "modbus: unit 10; sid:1;)");
1159 
1160  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1161  "(msg:\"Testing modbus code unit_id\"; "
1162  "modbus: unit 12; sid:2;)");
1163 
1164  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1165  "(msg:\"Testing modbus code unit_id\"; "
1166  "modbus: unit 5<>15; sid:3;)");
1167 
1168  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1169  "(msg:\"Testing modbus code unit_id\"; "
1170  "modbus: unit 5<>9; sid:4;)");
1171 
1172  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1173  "(msg:\"Testing modbus code unit_id\"; "
1174  "modbus: unit 11<>15; sid:5;)");
1175 
1176  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1177  "(msg:\"Testing modbus code unit_id\"; "
1178  "modbus: unit >9; sid:6;)");
1179 
1180  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1181  "(msg:\"Testing modbus code unit_id\"; "
1182  "modbus: unit >11; sid:7;)");
1183 
1184  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1185  "(msg:\"Testing modbus code unit_id\"; "
1186  "modbus: unit <11; sid:8;)");
1187 
1188  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1189  "(msg:\"Testing modbus code unit_id\"; "
1190  "modbus: unit <9; sid:9;)");
1191  FAIL_IF_NULL(s);
1192 
1193  SigGroupBuild(de_ctx);
1194  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1195 
1196  FLOWLOCK_WRLOCK(&f);
1197  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1199  readWriteMultipleRegistersReq,
1200  sizeof(readWriteMultipleRegistersReq));
1201  FAIL_IF_NOT(r == 0);
1202  FLOWLOCK_UNLOCK(&f);
1203 
1204  ModbusState *modbus_state = f.alstate;
1205  FAIL_IF_NULL(modbus_state);
1206 
1207  /* do detect */
1208  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1209 
1210  FAIL_IF(PacketAlertCheck(p, 2));
1211  FAIL_IF(PacketAlertCheck(p, 4));
1212  FAIL_IF(PacketAlertCheck(p, 5));
1213  FAIL_IF(PacketAlertCheck(p, 7));
1214  FAIL_IF(PacketAlertCheck(p, 9));
1215 
1220 
1221  AppLayerParserThreadCtxFree(alp_tctx);
1222  DetectEngineThreadCtxDeinit(&tv, det_ctx);
1223  SigGroupCleanup(de_ctx);
1224  DetectEngineCtxFree(de_ctx);
1225 
1227  FLOW_DESTROY(&f);
1228  UTHFreePacket(p);
1229  PASS;
1230 }
1231 
1232 /** \test Test code unit_id and code function. */
1233 static int DetectEngineInspectModbusTest11(void)
1234 {
1236  DetectEngineThreadCtx *det_ctx = NULL;
1237  DetectEngineCtx *de_ctx = NULL;
1238  Flow f;
1239  Packet *p = NULL;
1240  Signature *s = NULL;
1241  TcpSession ssn;
1242  ThreadVars tv;
1243 
1244  FAIL_IF_NULL(alp_tctx);
1245 
1246  memset(&tv, 0, sizeof(ThreadVars));
1247  memset(&f, 0, sizeof(Flow));
1248  memset(&ssn, 0, sizeof(TcpSession));
1249 
1250  p = UTHBuildPacket(readWriteMultipleRegistersReq,
1251  sizeof(readWriteMultipleRegistersReq),
1252  IPPROTO_TCP);
1253 
1254  FLOW_INITIALIZE(&f);
1255  f.alproto = ALPROTO_MODBUS;
1256  f.protoctx = (void *)&ssn;
1257  f.proto = IPPROTO_TCP;
1258  f.flags |= FLOW_IPV4;
1259 
1260  p->flow = &f;
1263 
1265 
1266  de_ctx = DetectEngineCtxInit();
1267  FAIL_IF_NULL(de_ctx);
1268 
1269  de_ctx->flags |= DE_QUIET;
1270 
1271  /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
1272  /* Unit ID = 0x0a (10) */
1273  /* Function code = 0x17 (23) */
1274  /* Write access register address 15 = 0x1234 (4660) */
1275  /* Write access register address 16 = 0x5678 (22136) */
1276  /* Write access register address 17 = 0x9ABC (39612) */
1277  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1278  "(msg:\"Testing modbus code unit_id\"; "
1279  "modbus: unit 10, function 20; sid:1;)");
1280 
1281  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1282  "(msg:\"Testing modbus code unit_id\"; "
1283  "modbus: unit 10, function 23; sid:2;)");
1284 
1285  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1286  "(msg:\"Testing modbus code unit_id\"; "
1287  "modbus: unit 11, function 20; sid:3;)");
1288 
1289  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1290  "(msg:\"Testing modbus code unit_id\"; "
1291  "modbus: unit 11, function 23; sid:4;)");
1292 
1293  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1294  "(msg:\"Testing modbus code unit_id\"; "
1295  "modbus: unit 10, function public; sid:5;)");
1296 
1297  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1298  "(msg:\"Testing modbus code unit_id\"; "
1299  "modbus: unit 11, function public; sid:6;)");
1300 
1301  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1302  "(msg:\"Testing modbus code unit_id\"; "
1303  "modbus: unit 10, function user; sid:7;)");
1304 
1305  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1306  "(msg:\"Testing modbus code unit_id\"; "
1307  "modbus: unit 10, function !user; sid:8;)");
1308  FAIL_IF_NULL(s);
1309 
1310  SigGroupBuild(de_ctx);
1311  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1312 
1313  FLOWLOCK_WRLOCK(&f);
1314  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1316  readWriteMultipleRegistersReq,
1317  sizeof(readWriteMultipleRegistersReq));
1318  FAIL_IF_NOT(r == 0);
1319  FLOWLOCK_UNLOCK(&f);
1320 
1321  ModbusState *modbus_state = f.alstate;
1322  FAIL_IF_NULL(modbus_state);
1323 
1324  /* do detect */
1325  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1326 
1327  FAIL_IF(PacketAlertCheck(p, 1));
1328  FAIL_IF(PacketAlertCheck(p, 3));
1329  FAIL_IF(PacketAlertCheck(p, 4));
1330  FAIL_IF(PacketAlertCheck(p, 6));
1331  FAIL_IF(PacketAlertCheck(p, 7));
1332 
1336 
1337  AppLayerParserThreadCtxFree(alp_tctx);
1338  DetectEngineThreadCtxDeinit(&tv, det_ctx);
1339  SigGroupCleanup(de_ctx);
1340  DetectEngineCtxFree(de_ctx);
1341 
1343  FLOW_DESTROY(&f);
1344  UTHFreePacket(p);
1345  PASS;
1346 }
1347 
1348 /** \test unit_id and read access at an address. */
1349 static int DetectEngineInspectModbusTest12(void)
1350 {
1352  DetectEngineThreadCtx *det_ctx = NULL;
1353  DetectEngineCtx *de_ctx = NULL;
1354  Flow f;
1355  Packet *p = NULL;
1356  Signature *s = NULL;
1357  TcpSession ssn;
1358  ThreadVars tv;
1359 
1360  FAIL_IF_NULL(alp_tctx);
1361 
1362  memset(&tv, 0, sizeof(ThreadVars));
1363  memset(&f, 0, sizeof(Flow));
1364  memset(&ssn, 0, sizeof(TcpSession));
1365 
1366  p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
1367 
1368  FLOW_INITIALIZE(&f);
1369  f.alproto = ALPROTO_MODBUS;
1370  f.protoctx = (void *)&ssn;
1371  f.proto = IPPROTO_TCP;
1372  f.flags |= FLOW_IPV4;
1373 
1374  p->flow = &f;
1377 
1379 
1380  de_ctx = DetectEngineCtxInit();
1381  FAIL_IF_NULL(de_ctx);
1382 
1383  de_ctx->flags |= DE_QUIET;
1384 
1385  /* readCoilsReq, Read coils Starting Address = 0x7890 (30864), Quantity of coils = 0x13 (19) */
1386  /* Unit ID = 0x0a (10) */
1387  /* Function code = 0x01 (01) */
1388  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1389  "(msg:\"Testing modbus address access\"; "
1390  "modbus: unit 10, access read, address 30870; sid:1;)");
1391 
1392  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1393  "(msg:\"Testing modbus address access\"; "
1394  "modbus: unit 10, access read, address 30863; sid:2;)");
1395 
1396  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1397  "(msg:\"Testing modbus address access\"; "
1398  "modbus: unit 11, access read, address 30870; sid:3;)");
1399 
1400  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1401  "(msg:\"Testing modbus address access\"; "
1402  "modbus: unit 11, access read, address 30863; sid:4;)");
1403 
1404  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1405  "(msg:\"Testing modbus address access\"; "
1406  "modbus: unit 10, access write; sid:5;)");
1407  FAIL_IF_NULL(s);
1408 
1409  SigGroupBuild(de_ctx);
1410  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1411 
1412  FLOWLOCK_WRLOCK(&f);
1413  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1414  STREAM_TOSERVER, readCoilsReq,
1415  sizeof(readCoilsReq));
1416  FAIL_IF_NOT(r == 0);
1417  FLOWLOCK_UNLOCK(&f);
1418 
1419  ModbusState *modbus_state = f.alstate;
1420  FAIL_IF_NULL(modbus_state);
1421 
1422  /* do detect */
1423  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1424 
1425  FAIL_IF(PacketAlertCheck(p, 2));
1426  FAIL_IF(PacketAlertCheck(p, 3));
1427  FAIL_IF(PacketAlertCheck(p, 4));
1428  FAIL_IF(PacketAlertCheck(p, 5));
1429 
1431 
1432  AppLayerParserThreadCtxFree(alp_tctx);
1433  DetectEngineThreadCtxDeinit(&tv, det_ctx);
1434  SigGroupCleanup(de_ctx);
1435  DetectEngineCtxFree(de_ctx);
1436 
1438  FLOW_DESTROY(&f);
1439  UTHFreePacket(p);
1440  PASS;
1441 }
1442 #endif /* UNITTESTS */
1443 
1445 {
1446 #ifdef UNITTESTS
1447  UtRegisterTest("DetectEngineInspectModbusTest01 - Code function",
1448  DetectEngineInspectModbusTest01);
1449  UtRegisterTest("DetectEngineInspectModbusTest02 - code function and code subfunction",
1450  DetectEngineInspectModbusTest02);
1451  UtRegisterTest("DetectEngineInspectModbusTest03 - Function category",
1452  DetectEngineInspectModbusTest03);
1453  UtRegisterTest("DetectEngineInspectModbusTest04 - Negative function category",
1454  DetectEngineInspectModbusTest04);
1455  UtRegisterTest("DetectEngineInspectModbusTest05 - Access type",
1456  DetectEngineInspectModbusTest05);
1457  UtRegisterTest("DetectEngineInspectModbusTest06 - Access function",
1458  DetectEngineInspectModbusTest06);
1459  UtRegisterTest("DetectEngineInspectModbusTest07 - Read access at an address",
1460  DetectEngineInspectModbusTest07);
1461  UtRegisterTest("DetectEngineInspectModbusTest08 - Read access at a range of address",
1462  DetectEngineInspectModbusTest08);
1463  UtRegisterTest("DetectEngineInspectModbusTest09 - Write access at an address a range of value",
1464  DetectEngineInspectModbusTest09);
1465  UtRegisterTest("DetectEngineInspectModbusTest10 - Code unit_id",
1466  DetectEngineInspectModbusTest10);
1467  UtRegisterTest("DetectEngineInspectModbusTest11 - Code unit_id and code function",
1468  DetectEngineInspectModbusTest11);
1469  UtRegisterTest("DetectEngineInspectModbusTest12 - Code unit_id and acces function",
1470  DetectEngineInspectModbusTest12);
1471 #endif /* UNITTESTS */
1472  return;
1473 }
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
uint16_t flags
#define SCLogDebug(...)
Definition: util-debug.h:335
struct Flow_ * flow
Definition: decode.h:445
#define MODBUS_TYP_ACCESS_MASK
struct ModbusTransaction_::@18::@20::@22 read
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
uint8_t proto
Definition: flow.h:344
#define MODBUS_TYP_ACCESS_FUNCTION_MASK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:243
int DetectEngineInspectModbus(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
#define PASS
Pass the test.
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
Signature * sig_list
Definition: detect.h:762
uint64_t offset
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
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
#define MODBUS_TYP_MULTIPLE
Signature container.
Definition: detect.h:517
#define MODBUS_TYP_COILS
#define TRUE
void * protoctx
Definition: flow.h:400
main detection engine ctx
Definition: detect.h:756
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
void * alstate
Definition: flow.h:438
DetectModbusMode mode
Definition: detect-modbus.h:49
#define DE_QUIET
Definition: detect.h:287
uint8_t flags
Definition: detect.h:757
uint8_t type
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
#define MODBUS_TYP_SINGLE
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
#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 FLOW_PKT_TOSERVER
Definition: flow.h:201
DetectModbusValue * data
Definition: detect-modbus.h:59
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
int SigGroupCleanup(DetectEngineCtx *de_ctx)
#define SCReturnInt(x)
Definition: util-debug.h:341
uint16_t * subfunction
Definition: detect-modbus.h:55
#define MODBUS_CAT_NONE
void DetectEngineInspectModbusRegisterTests(void)
uint8_t address
Definition: decode-ppp.h:311
uint8_t function
Definition: detect-modbus.h:54
uint16_t tx_id
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
#define STREAM_TOSERVER
Definition: stream.h:31
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself...
#define MODBUS_TYP_NONE
#define PKT_HAS_FLOW
Definition: decode.h:1090
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
struct ModbusTransaction_::@18::@20::@23 write
DetectModbusValue * unit_id
Definition: detect-modbus.h:57
Per thread variable structure.
Definition: threadvars.h:57
uint8_t category
Definition: detect-modbus.h:53
#define MODBUS_FUNC_NONE
AppProto alproto
application level protocol
Definition: flow.h:409
DetectModbusValue * address
Definition: detect-modbus.h:58
uint32_t flags
Definition: decode.h:443
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Flow data structure.
Definition: flow.h:325
#define FLOW_IPV4
Definition: flow.h:94
uint32_t flags
Definition: flow.h:379
#define PKT_STREAM_EST
Definition: decode.h:1088
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
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)
#define MODBUS_TYP_READ