]> git.ipfire.org Git - people/ms/suricata.git/blob - src/detect-dnp3.c
core: Remove unneeded consts
[people/ms/suricata.git] / src / detect-dnp3.c
1 /* Copyright (C) 2015 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 #include "suricata-common.h"
19
20 #include "stream.h"
21
22 #include "detect.h"
23 #include "detect-parse.h"
24 #include "detect-dnp3.h"
25 #include "detect-engine.h"
26 #include "detect-engine-mpm.h"
27 #include "detect-engine-prefilter.h"
28 #include "detect-engine-content-inspection.h"
29
30 #include "app-layer-dnp3.h"
31
32 static int g_dnp3_match_buffer_id = 0;
33 static int g_dnp3_data_buffer_id = 0;
34
35 /**
36 * The detection struct.
37 */
38 typedef struct DetectDNP3_ {
39 union {
40 struct {
41 /* Function code for function code detection. */
42 uint8_t function_code;
43 };
44 struct {
45 /* Internal indicator flags for IIN detection. */
46 uint16_t ind_flags;
47 };
48 struct {
49 /* Object info for object detection. */
50 uint8_t obj_group;
51 uint8_t obj_variation;
52 };
53 };
54 } DetectDNP3;
55
56 /**
57 * Indicator names to value mappings (Snort compatible).
58 */
59 DNP3Mapping DNP3IndicatorsMap[] = {
60 {"device_restart", 0x8000},
61 {"device_trouble", 0x4000},
62 {"local_control", 0x2000},
63 {"need_time", 0x1000},
64 {"class_3_events", 0x0800},
65 {"class_2_events", 0x0400},
66 {"class_1_events", 0x0200},
67 {"all_stations", 0x0100},
68
69 {"reserved_1", 0x0080},
70 {"reserved_2", 0x0040},
71 {"config_corrupt", 0x0020},
72 {"already_executing", 0x0010},
73 {"event_buffer_overflow", 0x0008},
74 {"parameter_error", 0x0004},
75 {"object_unknown", 0x0002},
76 {"no_func_code_support", 0x0001},
77
78 {NULL, 0},
79 };
80
81 /**
82 * Application function code name to code mappings (Snort compatible).
83 */
84 DNP3Mapping DNP3FunctionNameMap[] = {
85 {"confirm", 0},
86 {"read", 1},
87 {"write", 2},
88 {"select", 3},
89 {"operate", 4},
90 {"direct_operate", 5},
91 {"direct_operate_nr", 6},
92 {"immed_freeze", 7},
93 {"immed_freeze_nr", 8},
94 {"freeze_clear", 9},
95 {"freeze_clear_nr", 10},
96 {"freeze_at_time", 11},
97 {"freeze_at_time_nr", 12},
98 {"cold_restart", 13},
99 {"warm_restart", 14},
100 {"initialize_data", 15},
101 {"initialize_appl", 16},
102 {"start_appl", 17},
103 {"stop_appl", 18},
104 {"save_config", 19},
105 {"enable_unsolicited", 20},
106 {"disable_unsolicited", 21},
107 {"assign_class", 22},
108 {"delay_measure", 23},
109 {"record_current_time", 24},
110 {"open_file", 25},
111 {"close_file", 26},
112 {"delete_file", 27},
113 {"get_file_info", 28},
114 {"authenticate_file", 29},
115 {"abort_file", 30},
116 {"activate_config", 31},
117 {"authenticate_req", 32},
118 {"authenticate_err", 33},
119 {"response", 129},
120 {"unsolicited_response", 130},
121 {"authenticate_resp", 131}
122 };
123
124 #ifdef UNITTESTS
125 static void DetectDNP3FuncRegisterTests(void);
126 static void DetectDNP3IndRegisterTests(void);
127 static void DetectDNP3ObjRegisterTests(void);
128 static void DetectDNP3DataRegisterTests(void);
129 #endif
130
131 /**
132 * \brief Utility function to trim leading and trailing whitespace
133 * from a string.
134 */
135 static char *TrimString(char *str)
136 {
137 char *end = str + strlen(str) - 1;
138 while (isspace(*str)) {
139 str++;
140 }
141 while (end > str && isspace(*end)) {
142 end--;
143 }
144 *(end + 1) = '\0';
145 return str;
146 }
147
148 static InspectionBuffer *GetDNP3Data(DetectEngineThreadCtx *det_ctx,
149 const DetectEngineTransforms *transforms,
150 Flow *_f, const uint8_t flow_flags,
151 void *txv, const int list_id)
152 {
153 SCLogDebug("list_id %d", list_id);
154 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
155 if (buffer->inspect == NULL) {
156 DNP3Transaction *tx = (DNP3Transaction *)txv;
157 SCLogDebug("tx %p", tx);
158
159 const uint8_t *data = NULL;
160 uint32_t data_len = 0;
161
162 if (flow_flags & STREAM_TOSERVER) {
163 data = tx->request_buffer;
164 data_len = tx->request_buffer_len;
165 } else if (flow_flags & STREAM_TOCLIENT) {
166 data = tx->response_buffer;
167 data_len = tx->response_buffer_len;
168 }
169 if (data == NULL || data_len == 0)
170 return NULL;
171
172 SCLogDebug("tx %p data %p data_len %u", tx, data, data_len);
173 InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
174 InspectionBufferApplyTransforms(buffer, transforms);
175 }
176 return buffer;
177 }
178
179 static int DetectEngineInspectDNP3(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
180 const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
181 uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
182 {
183 return DetectEngineInspectGenericList(
184 de_ctx, det_ctx, s, engine->smd, f, flags, alstate, txv, tx_id);
185 }
186
187 /**
188 * \brief Parse the provided function name or code to its integer
189 * value.
190 *
191 * If the value passed is a number, it will be checked that it falls
192 * within the range of valid function codes. If function name is
193 * passed it will be resolved to its function code.
194 *
195 * \retval The function code as an integer if successul, -1 on
196 * failure.
197 */
198 static int DetectDNP3FuncParseFunctionCode(const char *str, uint8_t *fc)
199 {
200 if (StringParseUint8(fc, 10, strlen(str), str) >= 0) {
201 return 1;
202 }
203
204 /* Lookup by name. */
205 for (size_t i = 0;
206 i < sizeof(DNP3FunctionNameMap) / sizeof(DNP3Mapping); i++) {
207 if (strcasecmp(str, DNP3FunctionNameMap[i].name) == 0) {
208 *fc = DNP3FunctionNameMap[i].value;
209 return 1;
210 }
211 }
212
213 return 0;
214 }
215
216 static int DetectDNP3FuncSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
217 {
218 SCEnter();
219 DetectDNP3 *dnp3 = NULL;
220 SigMatch *sm = NULL;
221 uint8_t function_code;
222
223 if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0)
224 return -1;
225
226 if (!DetectDNP3FuncParseFunctionCode(str, &function_code)) {
227 SCLogError(SC_ERR_INVALID_SIGNATURE,
228 "Invalid argument \"%s\" supplied to dnp3_func keyword.", str);
229 return -1;
230 }
231
232 dnp3 = SCCalloc(1, sizeof(DetectDNP3));
233 if (unlikely(dnp3 == NULL)) {
234 goto error;
235 }
236 dnp3->function_code = function_code;
237
238 sm = SigMatchAlloc();
239 if (sm == NULL) {
240 goto error;
241 }
242 sm->type = DETECT_AL_DNP3FUNC;
243 sm->ctx = (void *)dnp3;
244
245 SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id);
246
247 SCReturnInt(0);
248 error:
249 if (dnp3 != NULL) {
250 SCFree(dnp3);
251 }
252 if (sm != NULL) {
253 SCFree(sm);
254 }
255 SCReturnInt(-1);
256 }
257
258 static int DetectDNP3IndParseByName(const char *str, uint16_t *flags)
259 {
260 char tmp[strlen(str) + 1];
261 char *p, *last = NULL;
262
263 strlcpy(tmp, str, sizeof(tmp));
264
265 for ((p = strtok_r(tmp, ",", &last)); p; (p = strtok_r(NULL, ",", &last))) {
266 p = TrimString(p);
267 int found = 0;
268 int i = 0;
269 while (DNP3IndicatorsMap[i].name != NULL) {
270 if (strcasecmp(p, DNP3IndicatorsMap[i].name) == 0) {
271 *flags |= DNP3IndicatorsMap[i].value;
272 found = 1;
273 break;
274 }
275 i++;
276 }
277
278 if (!found) {
279 SCLogError(SC_ERR_INVALID_SIGNATURE,
280 "Bad argument \"%s\" supplied to dnp3.ind keyword.", p);
281 return 0;
282 }
283 }
284
285 return 1;
286 }
287
288 static int DetectDNP3IndParse(const char *str, uint16_t *flags)
289 {
290 *flags = 0;
291
292 if (StringParseUint16(flags, 0, strlen(str), str) > 0) {
293 return 1;
294 }
295
296 /* Parse by name - will log a more specific error message on error. */
297 if (DetectDNP3IndParseByName(str, flags)) {
298 return 1;
299 }
300
301 return 0;
302 }
303
304 static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
305 {
306 SCEnter();
307 DetectDNP3 *detect = NULL;
308 SigMatch *sm = NULL;
309 uint16_t flags;
310
311 if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0)
312 return -1;
313
314 if (!DetectDNP3IndParse(str, &flags)) {
315 SCLogError(SC_ERR_INVALID_SIGNATURE,
316 "Invalid argument \"%s\" supplied to dnp3.ind keyword.", str);
317 return -1;
318 }
319
320 detect = SCCalloc(1, sizeof(DetectDNP3));
321 if (unlikely(detect == NULL)) {
322 goto error;
323 }
324 detect->ind_flags = flags;
325
326 sm = SigMatchAlloc();
327 if (sm == NULL) {
328 goto error;
329 }
330 sm->type = DETECT_AL_DNP3IND;
331 sm->ctx = (void *)detect;
332 SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id);
333
334 SCReturnInt(0);
335 error:
336 if (detect != NULL) {
337 SCFree(detect);
338 }
339 if (sm != NULL) {
340 SCFree(sm);
341 }
342 SCReturnInt(-1);
343 }
344
345 /**
346 * \brief Parse the value of string of the dnp3_obj keyword.
347 *
348 * \param str the input string
349 * \param gout pointer to variable to store the parsed group integer
350 * \param vout pointer to variable to store the parsed variation integer
351 *
352 * \retval 1 if parsing successful otherwise 0.
353 */
354 static int DetectDNP3ObjParse(const char *str, uint8_t *group, uint8_t *var)
355 {
356 size_t size = strlen(str) + 1;
357 char groupstr[size], *varstr, *sep;
358 strlcpy(groupstr, str, size);
359
360 sep = strchr(groupstr, ',');
361 if (sep == NULL) {
362 return 0;
363 }
364 *sep = '\0';
365 varstr = sep + 1;
366
367 if (StringParseUint8(group, 0, strlen(groupstr), groupstr) < 0) {
368 return 0;
369 }
370
371 if (StringParseUint8(var, 0, strlen(varstr), varstr) < 0) {
372 return 0;
373 }
374
375 return 1;
376 }
377
378 static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
379 {
380 SCEnter();
381 uint8_t group;
382 uint8_t variation;
383 DetectDNP3 *detect = NULL;
384 SigMatch *sm = NULL;
385
386 if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0)
387 return -1;
388
389 if (!DetectDNP3ObjParse(str, &group, &variation)) {
390 goto fail;
391 }
392
393 detect = SCCalloc(1, sizeof(*detect));
394 if (unlikely(detect == NULL)) {
395 goto fail;
396 }
397 detect->obj_group = group;
398 detect->obj_variation = variation;
399
400 sm = SigMatchAlloc();
401 if (unlikely(sm == NULL)) {
402 goto fail;
403 }
404 sm->type = DETECT_AL_DNP3OBJ;
405 sm->ctx = (void *)detect;
406 SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id);
407
408 SCReturnInt(1);
409 fail:
410 if (detect != NULL) {
411 SCFree(detect);
412 }
413 if (sm != NULL) {
414 SCFree(sm);
415 }
416 SCReturnInt(0);
417 }
418
419 static void DetectDNP3Free(DetectEngineCtx *de_ctx, void *ptr)
420 {
421 SCEnter();
422 if (ptr != NULL) {
423 SCFree(ptr);
424 }
425 SCReturn;
426 }
427
428 static int DetectDNP3FuncMatch(DetectEngineThreadCtx *det_ctx,
429 Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
430 const SigMatchCtx *ctx)
431 {
432 DNP3Transaction *tx = (DNP3Transaction *)txv;
433 DetectDNP3 *detect = (DetectDNP3 *)ctx;
434 int match = 0;
435
436 if (flags & STREAM_TOSERVER) {
437 match = detect->function_code == tx->request_ah.function_code;
438 }
439 else if (flags & STREAM_TOCLIENT) {
440 match = detect->function_code == tx->response_ah.function_code;
441 }
442
443 return match;
444 }
445
446 static int DetectDNP3ObjMatch(DetectEngineThreadCtx *det_ctx,
447 Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
448 const SigMatchCtx *ctx)
449 {
450 DNP3Transaction *tx = (DNP3Transaction *)txv;
451 DetectDNP3 *detect = (DetectDNP3 *)ctx;
452 DNP3ObjectList *objects = NULL;
453
454 if (flags & STREAM_TOSERVER) {
455 objects = &tx->request_objects;
456 }
457 else if (flags & STREAM_TOCLIENT) {
458 objects = &tx->response_objects;
459 }
460
461 if (objects != NULL) {
462 DNP3Object *object;
463 TAILQ_FOREACH(object, objects, next) {
464 if (object->group == detect->obj_group &&
465 object->variation == detect->obj_variation) {
466 return 1;
467 }
468 }
469 }
470
471 return 0;
472 }
473
474 static int DetectDNP3IndMatch(DetectEngineThreadCtx *det_ctx,
475 Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
476 const SigMatchCtx *ctx)
477 {
478 DNP3Transaction *tx = (DNP3Transaction *)txv;
479 DetectDNP3 *detect = (DetectDNP3 *)ctx;
480
481 if (flags & STREAM_TOCLIENT) {
482 if ((tx->response_iin.iin1 & (detect->ind_flags >> 8)) ||
483 (tx->response_iin.iin2 & (detect->ind_flags & 0xf))) {
484 return 1;
485 }
486 }
487
488 return 0;
489 }
490
491 static void DetectDNP3FuncRegister(void)
492 {
493 SCEnter();
494
495 sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3_func";
496 sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3.func";
497 sigmatch_table[DETECT_AL_DNP3FUNC].desc = "match on the application function code found in DNP3 request and responses";
498 sigmatch_table[DETECT_AL_DNP3FUNC].url = "/rules/dnp3-keywords.html#dnp3-func";
499 sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL;
500 sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerTxMatch = DetectDNP3FuncMatch;
501 sigmatch_table[DETECT_AL_DNP3FUNC].Setup = DetectDNP3FuncSetup;
502 sigmatch_table[DETECT_AL_DNP3FUNC].Free = DetectDNP3Free;
503 #ifdef UNITTESTS
504 sigmatch_table[DETECT_AL_DNP3FUNC].RegisterTests =
505 DetectDNP3FuncRegisterTests;
506 #endif
507 SCReturn;
508 }
509
510 static void DetectDNP3IndRegister(void)
511 {
512 SCEnter();
513
514 sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3_ind";
515 sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3.ind";
516 sigmatch_table[DETECT_AL_DNP3IND].desc = "match on the DNP3 internal indicator flags in the response application header";
517 sigmatch_table[DETECT_AL_DNP3IND].url = "/rules/dnp3-keywords.html#dnp3-ind";
518 sigmatch_table[DETECT_AL_DNP3IND].Match = NULL;
519 sigmatch_table[DETECT_AL_DNP3IND].AppLayerTxMatch = DetectDNP3IndMatch;
520 sigmatch_table[DETECT_AL_DNP3IND].Setup = DetectDNP3IndSetup;
521 sigmatch_table[DETECT_AL_DNP3IND].Free = DetectDNP3Free;
522 #ifdef UNITTESTS
523 sigmatch_table[DETECT_AL_DNP3IND].RegisterTests =
524 DetectDNP3IndRegisterTests;
525 #endif
526 SCReturn;
527 }
528
529 static void DetectDNP3ObjRegister(void)
530 {
531 SCEnter();
532
533 sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3_obj";
534 sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3.obj";
535 sigmatch_table[DETECT_AL_DNP3OBJ].desc = "match on the DNP3 application data objects";
536 sigmatch_table[DETECT_AL_DNP3OBJ].url = "/rules/dnp3-keywords.html#dnp3-obj";
537 sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL;
538 sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerTxMatch = DetectDNP3ObjMatch;
539 sigmatch_table[DETECT_AL_DNP3OBJ].Setup = DetectDNP3ObjSetup;
540 sigmatch_table[DETECT_AL_DNP3OBJ].Free = DetectDNP3Free;
541 #ifdef UNITTESTS
542 sigmatch_table[DETECT_AL_DNP3OBJ].RegisterTests =
543 DetectDNP3ObjRegisterTests;
544 #endif
545 SCReturn;
546 }
547
548 static int DetectDNP3DataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
549 {
550 SCEnter();
551 if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0)
552 return -1;
553
554 if (DetectBufferSetActiveList(s, g_dnp3_data_buffer_id) != 0)
555 return -1;
556
557 SCReturnInt(0);
558 }
559
560 static void DetectDNP3DataRegister(void)
561 {
562 SCEnter();
563
564 sigmatch_table[DETECT_AL_DNP3DATA].name = "dnp3.data";
565 sigmatch_table[DETECT_AL_DNP3DATA].alias = "dnp3_data";
566 sigmatch_table[DETECT_AL_DNP3DATA].desc = "make the following content options to match on the re-assembled application buffer";
567 sigmatch_table[DETECT_AL_DNP3DATA].url = "/rules/dnp3-keywords.html#dnp3-data";
568 sigmatch_table[DETECT_AL_DNP3DATA].Setup = DetectDNP3DataSetup;
569 #ifdef UNITTESTS
570 sigmatch_table[DETECT_AL_DNP3DATA].RegisterTests =
571 DetectDNP3DataRegisterTests;
572 #endif
573 sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER;
574
575 DetectAppLayerInspectEngineRegister2("dnp3_data",
576 ALPROTO_DNP3, SIG_FLAG_TOSERVER, 0,
577 DetectEngineInspectBufferGeneric,
578 GetDNP3Data);
579 DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOSERVER, 2,
580 PrefilterGenericMpmRegister, GetDNP3Data,
581 ALPROTO_DNP3, 0);
582
583 DetectAppLayerInspectEngineRegister2("dnp3_data",
584 ALPROTO_DNP3, SIG_FLAG_TOCLIENT, 0,
585 DetectEngineInspectBufferGeneric,
586 GetDNP3Data);
587 DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOCLIENT, 2,
588 PrefilterGenericMpmRegister, GetDNP3Data,
589 ALPROTO_DNP3, 0);
590
591 g_dnp3_data_buffer_id = DetectBufferTypeGetByName("dnp3_data");
592 SCReturn;
593 }
594
595 void DetectDNP3Register(void)
596 {
597 DetectDNP3DataRegister();
598
599 DetectDNP3FuncRegister();
600 DetectDNP3IndRegister();
601 DetectDNP3ObjRegister();
602
603 /* Register the list of func, ind and obj. */
604 DetectAppLayerInspectEngineRegister2(
605 "dnp3", ALPROTO_DNP3, SIG_FLAG_TOSERVER, 0, DetectEngineInspectDNP3, NULL);
606 DetectAppLayerInspectEngineRegister2(
607 "dnp3", ALPROTO_DNP3, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectDNP3, NULL);
608
609 g_dnp3_match_buffer_id = DetectBufferTypeRegister("dnp3");
610
611 }
612
613 #ifdef UNITTESTS
614
615 #include "util-unittest.h"
616 #include "util-unittest-helper.h"
617 #include "app-layer-parser.h"
618 #include "detect-engine.h"
619 #include "flow-util.h"
620 #include "stream-tcp.h"
621
622 static int DetectDNP3FuncParseFunctionCodeTest(void)
623 {
624 uint8_t fc;
625
626 /* Valid. */
627 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("0", &fc));
628 FAIL_IF(fc != 0);
629
630 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("1", &fc));
631 FAIL_IF(fc != 1);
632
633 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("254", &fc));
634 FAIL_IF(fc != 254);
635
636 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("255", &fc));
637 FAIL_IF(fc != 255);
638
639 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("confirm", &fc));
640 FAIL_IF(fc != 0);
641
642 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("CONFIRM", &fc));
643 FAIL_IF(fc != 0);
644
645 /* Invalid. */
646 FAIL_IF(DetectDNP3FuncParseFunctionCode("", &fc));
647 FAIL_IF(DetectDNP3FuncParseFunctionCode("-1", &fc));
648 FAIL_IF(DetectDNP3FuncParseFunctionCode("-2", &fc));
649 FAIL_IF(DetectDNP3FuncParseFunctionCode("256", &fc));
650 FAIL_IF(DetectDNP3FuncParseFunctionCode("unknown_function_code", &fc));
651
652 PASS;
653 }
654
655 static int DetectDNP3FuncTest01(void)
656 {
657 DetectEngineCtx *de_ctx = NULL;
658 DetectDNP3 *dnp3func = NULL;
659
660 de_ctx = DetectEngineCtxInit();
661 FAIL_IF_NULL(de_ctx);
662
663 de_ctx->sig_list = SigInit(de_ctx,
664 "alert dnp3 any any -> any any "
665 "(msg:\"SURICATA DNP3 Write request\"; "
666 "dnp3_func:2; sid:5000009; rev:1;)");
667 FAIL_IF_NULL(de_ctx->sig_list);
668
669 FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]);
670 FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx);
671
672 dnp3func = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx;
673 FAIL_IF(dnp3func->function_code != 2);
674
675 if (de_ctx != NULL) {
676 DetectEngineCtxFree(de_ctx);
677 }
678 PASS;
679 }
680
681 static int DetectDNP3IndTestParseAsInteger(void)
682 {
683 uint16_t flags = 0;
684
685 FAIL_IF(!DetectDNP3IndParse("0", &flags));
686 FAIL_IF(flags != 0);
687 FAIL_IF(!DetectDNP3IndParse("1", &flags));
688 FAIL_IF(flags != 0x0001);
689
690 FAIL_IF(!DetectDNP3IndParse("0x0", &flags));
691 FAIL_IF(flags != 0);
692 FAIL_IF(!DetectDNP3IndParse("0x0000", &flags));
693 FAIL_IF(flags != 0);
694 FAIL_IF(!DetectDNP3IndParse("0x0001", &flags));
695 FAIL_IF(flags != 0x0001);
696
697 FAIL_IF(!DetectDNP3IndParse("0x8421", &flags));
698 FAIL_IF(flags != 0x8421);
699
700 FAIL_IF(DetectDNP3IndParse("a", &flags));
701
702 PASS;
703 }
704
705 static int DetectDNP3IndTestParseByName(void)
706 {
707 uint16_t flags = 0;
708
709 FAIL_IF(!DetectDNP3IndParse("all_stations", &flags));
710 FAIL_IF(!(flags & 0x0100));
711 FAIL_IF(!DetectDNP3IndParse("class_1_events , class_2_events", &flags));
712 FAIL_IF(!(flags & 0x0200));
713 FAIL_IF(!(flags & 0x0400));
714 FAIL_IF((flags & 0xf9ff));
715
716 FAIL_IF(DetectDNP3IndParse("something", &flags));
717
718 PASS;
719 }
720
721 static int DetectDNP3ObjSetupTest(void)
722 {
723 DetectEngineCtx *de_ctx = NULL;
724 DetectDNP3 *detect = NULL;
725
726 de_ctx = DetectEngineCtxInit();
727 FAIL_IF(de_ctx == NULL);
728
729 de_ctx->sig_list = SigInit(de_ctx,
730 "alert dnp3 any any -> any any "
731 "(msg:\"SURICATA DNP3 Object Test\"; "
732 "dnp3_obj:99,99; sid:1; rev:1;)");
733 FAIL_IF(de_ctx->sig_list == NULL);
734
735 FAIL_IF(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id] == NULL);
736 FAIL_IF(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx == NULL);
737
738 detect = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx;
739 FAIL_IF(detect->obj_group != 99);
740 FAIL_IF(detect->obj_variation != 99);
741
742 if (de_ctx != NULL) {
743 DetectEngineCtxFree(de_ctx);
744 }
745 PASS;
746 }
747
748 static int DetectDNP3ObjParseTest(void)
749 {
750 uint8_t group, var;
751
752 FAIL_IF(!DetectDNP3ObjParse("0,0", &group, &var));
753 FAIL_IF(group != 0 || var != 0);
754
755 FAIL_IF(!DetectDNP3ObjParse("255,255", &group, &var));
756 FAIL_IF(group != 255 || var != 255);
757
758 FAIL_IF(DetectDNP3ObjParse("-1,-1", &group, &var));
759 FAIL_IF(DetectDNP3ObjParse("256,256", &group, &var));
760 FAIL_IF(DetectDNP3ObjParse("a,1", &group, &var));
761 FAIL_IF(DetectDNP3ObjParse("1,a", &group, &var));
762
763 PASS;
764 }
765
766 /**
767 * Test request (to server) content match.
768 */
769 static int DetectDNP3DataTest01(void)
770 {
771 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
772 DetectEngineThreadCtx *det_ctx = NULL;
773 DetectEngineCtx *de_ctx = NULL;
774 Flow f;
775 Packet *p;
776 TcpSession tcp;
777 ThreadVars tv;
778
779 uint8_t request[] = {
780 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
781 0xa5, 0xe9,
782
783 0xff, 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00,
784 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
785
786 /* CRC. */
787 0x72, 0xef,
788
789 0x00, 0x00, 0x00, 0x00, 0x00,
790
791 /* CRC. */
792 0xff, 0xff,
793 };
794
795 /* Setup flow. */
796 memset(&f, 0, sizeof(Flow));
797 memset(&tcp, 0, sizeof(TcpSession));
798 memset(&tv, 0, sizeof(ThreadVars));
799 p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP);
800 FLOW_INITIALIZE(&f);
801 f.alproto = ALPROTO_DNP3;
802 f.protoctx = (void *)&tcp;
803 f.proto = IPPROTO_TCP;
804 f.flags |= FLOW_IPV4;
805 p->flow = &f;
806 p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
807 p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
808 StreamTcpInitConfig(true);
809
810 de_ctx = DetectEngineCtxInit();
811 FAIL_IF(de_ctx == NULL);
812
813 /* Either direction - should match. */
814 Signature *s = DetectEngineAppendSig(de_ctx,
815 "alert dnp3 any any -> any any ("
816 "msg:\"DetectDNP3DataTest01\"; "
817 "dnp3_data; "
818 "content:\"|01 01 01 00 00 00 00 00 00 00|\"; "
819 "sid:1; rev:1;)");
820 FAIL_IF(s == NULL);
821
822 /* To server - should match. */
823 s = DetectEngineAppendSig(de_ctx,
824 "alert dnp3 any any -> any any ("
825 "msg:\"DetectDNP3DataTest01\"; "
826 "flow:established,to_server; "
827 "dnp3_data; "
828 "content:\"|01 01 01 00 00 00 00 00 00 00|\"; "
829 "sid:2; rev:1;)");
830 FAIL_IF(s == NULL);
831
832 /* To client - should not match. */
833 s = DetectEngineAppendSig(de_ctx,
834 "alert dnp3 any any -> any any ("
835 "msg:\"DetectDNP3DataTest01\"; "
836 "flow:established,to_client; "
837 "dnp3_data; "
838 "content:\"|01 01 01 00 00 00 00 00 00 00|\"; "
839 "sid:3; rev:1;)");
840 FAIL_IF(s == NULL);
841
842 /* The content of a CRC - should not match. */
843 s = DetectEngineAppendSig(de_ctx,
844 "alert dnp3 any any -> any any ("
845 "msg:\"DetectDNP3DataTest01\"; "
846 "dnp3_data; "
847 "content:\"|72 ef|\"; "
848 "sid:4; rev:1;)");
849 FAIL_IF(s == NULL);
850
851 SigGroupBuild(de_ctx);
852 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
853
854 SCMutexLock(&f.m);
855 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3,
856 STREAM_TOSERVER, request, sizeof(request));
857 SCMutexUnlock(&f.m);
858 FAIL_IF(r);
859
860 FAIL_IF(f.alstate == NULL);
861
862 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
863 FAIL_IF(!PacketAlertCheck(p, 1));
864 FAIL_IF(!PacketAlertCheck(p, 2));
865 FAIL_IF(PacketAlertCheck(p, 3));
866 FAIL_IF(PacketAlertCheck(p, 4));
867
868 if (alp_tctx != NULL)
869 AppLayerParserThreadCtxFree(alp_tctx);
870 if (det_ctx != NULL)
871 DetectEngineThreadCtxDeinit(&tv, det_ctx);
872 if (de_ctx != NULL)
873 SigGroupCleanup(de_ctx);
874 if (de_ctx != NULL)
875 DetectEngineCtxFree(de_ctx);
876 StreamTcpFreeConfig(true);
877 FLOW_DESTROY(&f);
878 UTHFreePacket(p);
879 PASS;
880 }
881
882 /**
883 * Test response (to client) content match.
884 */
885 static int DetectDNP3DataTest02(void)
886 {
887 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
888 DetectEngineThreadCtx *det_ctx = NULL;
889 DetectEngineCtx *de_ctx = NULL;
890 Flow f;
891 Packet *p;
892 TcpSession tcp;
893 ThreadVars tv;
894
895 uint8_t request[] = {
896 /* Link header. */
897 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
898
899 /* CRC. */
900 0xa5, 0xe9,
901
902 /* Transport header. */
903 0xff,
904
905 /* Application layer. */
906 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
907 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
908
909 /* CRC. */
910 0x72, 0xef,
911
912 /* Application layer. */
913 0x00, 0x00, 0x00, 0x00, 0x00,
914
915 /* CRC. */
916 0xff, 0xff,
917 };
918
919 uint8_t response[] = {
920 /* Link header. */
921 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
922
923 /* CRC. */
924 0xe2, 0x59,
925
926 /* Transport header. */
927 0xc3,
928
929 /* Application layyer. */
930 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
931 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00,
932
933 /* CRC. */
934 0x7a, 0x65,
935
936 /* Application layer. */
937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
938
939 /* CRC. */
940 0xff, 0xff
941 };
942
943 /* Setup flow. */
944 memset(&f, 0, sizeof(Flow));
945 memset(&tcp, 0, sizeof(TcpSession));
946 memset(&tv, 0, sizeof(ThreadVars));
947 p = UTHBuildPacket(response, sizeof(response), IPPROTO_TCP);
948 FLOW_INITIALIZE(&f);
949 f.alproto = ALPROTO_DNP3;
950 f.protoctx = (void *)&tcp;
951 f.proto = IPPROTO_TCP;
952 f.flags |= FLOW_IPV4;
953 p->flow = &f;
954 p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
955 p->flowflags |= FLOW_PKT_TOCLIENT | FLOW_PKT_ESTABLISHED;
956 StreamTcpInitConfig(true);
957
958 de_ctx = DetectEngineCtxInit();
959 FAIL_IF(de_ctx == NULL);
960
961 /* Either direction - should match. */
962 Signature *s = DetectEngineAppendSig(de_ctx,
963 "alert dnp3 any any -> any any ("
964 "msg:\"DetectDNP3DataTest01\"; "
965 "dnp3_data; "
966 "content:\"|01 01 01 00 00 00 00|\"; "
967 "sid:1; rev:1;)");
968 FAIL_IF(s == NULL);
969
970 /* To server - should not match. */
971 s = DetectEngineAppendSig(de_ctx,
972 "alert dnp3 any any -> any any ("
973 "msg:\"DetectDNP3DataTest01\"; "
974 "flow:established,to_server; "
975 "dnp3_data; "
976 "content:\"|01 01 01 00 00 00 00|\"; "
977 "sid:2; rev:1;)");
978 FAIL_IF(s == NULL);
979
980 /* To client - should match. */
981 s = DetectEngineAppendSig(de_ctx,
982 "alert dnp3 any any -> any any ("
983 "msg:\"DetectDNP3DataTest01\"; "
984 "flow:established,to_client; "
985 "dnp3_data; "
986 "content:\"|01 01 01 00 00 00 00|\"; "
987 "sid:3; rev:1;)");
988 FAIL_IF(s == NULL);
989
990 /* The content of a CRC - should not match. */
991 s = DetectEngineAppendSig(de_ctx,
992 "alert dnp3 any any -> any any ("
993 "msg:\"DetectDNP3DataTest01\"; "
994 "dnp3_data; "
995 "content:\"|7a 65|\"; "
996 "sid:4; rev:1;)");
997 FAIL_IF(s == NULL);
998
999 SigGroupBuild(de_ctx);
1000 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1001
1002 /* Send through the request, then response. */
1003 SCMutexLock(&f.m);
1004 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3,
1005 STREAM_TOSERVER, request, sizeof(request));
1006 SCMutexUnlock(&f.m);
1007 FAIL_IF(r);
1008 FAIL_IF(f.alstate == NULL);
1009
1010 SCMutexLock(&f.m);
1011 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3, STREAM_TOCLIENT,
1012 response, sizeof(response));
1013 SCMutexUnlock(&f.m);
1014 FAIL_IF(r);
1015
1016 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1017 FAIL_IF(!PacketAlertCheck(p, 1));
1018 FAIL_IF(PacketAlertCheck(p, 2));
1019 FAIL_IF(!PacketAlertCheck(p, 3));
1020 FAIL_IF(PacketAlertCheck(p, 4));
1021
1022 if (alp_tctx != NULL)
1023 AppLayerParserThreadCtxFree(alp_tctx);
1024 if (det_ctx != NULL)
1025 DetectEngineThreadCtxDeinit(&tv, det_ctx);
1026 if (de_ctx != NULL)
1027 SigGroupCleanup(de_ctx);
1028 if (de_ctx != NULL)
1029 DetectEngineCtxFree(de_ctx);
1030 StreamTcpFreeConfig(true);
1031 FLOW_DESTROY(&f);
1032 UTHFreePacket(p);
1033 PASS;
1034 }
1035
1036 static void DetectDNP3FuncRegisterTests(void)
1037 {
1038 UtRegisterTest("DetectDNP3FuncParseFunctionCodeTest",
1039 DetectDNP3FuncParseFunctionCodeTest);
1040 UtRegisterTest("DetectDNP3FuncTest01", DetectDNP3FuncTest01);
1041 }
1042
1043 static void DetectDNP3IndRegisterTests(void)
1044 {
1045 UtRegisterTest("DetectDNP3IndTestParseAsInteger",
1046 DetectDNP3IndTestParseAsInteger);
1047 UtRegisterTest("DetectDNP3IndTestParseByName",
1048 DetectDNP3IndTestParseByName);
1049 }
1050
1051 static void DetectDNP3ObjRegisterTests(void)
1052 {
1053 UtRegisterTest("DetectDNP3ObjParseTest", DetectDNP3ObjParseTest);
1054 UtRegisterTest("DetectDNP3ObjSetupTest", DetectDNP3ObjSetupTest);
1055 }
1056
1057 void DetectDNP3DataRegisterTests(void)
1058 {
1059 UtRegisterTest("DetectDNP3DataTest01", DetectDNP3DataTest01);
1060 UtRegisterTest("DetectDNP3DataTest02", DetectDNP3DataTest02);
1061 }
1062 #endif