1 /* Copyright (C) 2015 Open Information Security Foundation
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
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.
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
18 #include "suricata-common.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"
30 #include "app-layer-dnp3.h"
32 static int g_dnp3_match_buffer_id
= 0;
33 static int g_dnp3_data_buffer_id
= 0;
36 * The detection struct.
38 typedef struct DetectDNP3_
{
41 /* Function code for function code detection. */
42 uint8_t function_code
;
45 /* Internal indicator flags for IIN detection. */
49 /* Object info for object detection. */
51 uint8_t obj_variation
;
57 * Indicator names to value mappings (Snort compatible).
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},
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},
82 * Application function code name to code mappings (Snort compatible).
84 DNP3Mapping DNP3FunctionNameMap
[] = {
90 {"direct_operate", 5},
91 {"direct_operate_nr", 6},
93 {"immed_freeze_nr", 8},
95 {"freeze_clear_nr", 10},
96 {"freeze_at_time", 11},
97 {"freeze_at_time_nr", 12},
100 {"initialize_data", 15},
101 {"initialize_appl", 16},
105 {"enable_unsolicited", 20},
106 {"disable_unsolicited", 21},
107 {"assign_class", 22},
108 {"delay_measure", 23},
109 {"record_current_time", 24},
113 {"get_file_info", 28},
114 {"authenticate_file", 29},
116 {"activate_config", 31},
117 {"authenticate_req", 32},
118 {"authenticate_err", 33},
120 {"unsolicited_response", 130},
121 {"authenticate_resp", 131}
125 static void DetectDNP3FuncRegisterTests(void);
126 static void DetectDNP3IndRegisterTests(void);
127 static void DetectDNP3ObjRegisterTests(void);
128 static void DetectDNP3DataRegisterTests(void);
132 * \brief Utility function to trim leading and trailing whitespace
135 static char *TrimString(char *str
)
137 char *end
= str
+ strlen(str
) - 1;
138 while (isspace(*str
)) {
141 while (end
> str
&& isspace(*end
)) {
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
)
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
);
159 const uint8_t *data
= NULL
;
160 uint32_t data_len
= 0;
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
;
169 if (data
== NULL
|| data_len
== 0)
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
);
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
)
183 return DetectEngineInspectGenericList(
184 de_ctx
, det_ctx
, s
, engine
->smd
, f
, flags
, alstate
, txv
, tx_id
);
188 * \brief Parse the provided function name or code to its integer
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.
195 * \retval The function code as an integer if successul, -1 on
198 static int DetectDNP3FuncParseFunctionCode(const char *str
, uint8_t *fc
)
200 if (StringParseUint8(fc
, 10, strlen(str
), str
) >= 0) {
204 /* Lookup by name. */
206 i
< sizeof(DNP3FunctionNameMap
) / sizeof(DNP3Mapping
); i
++) {
207 if (strcasecmp(str
, DNP3FunctionNameMap
[i
].name
) == 0) {
208 *fc
= DNP3FunctionNameMap
[i
].value
;
216 static int DetectDNP3FuncSetup(DetectEngineCtx
*de_ctx
, Signature
*s
, const char *str
)
219 DetectDNP3
*dnp3
= NULL
;
221 uint8_t function_code
;
223 if (DetectSignatureSetAppProto(s
, ALPROTO_DNP3
) != 0)
226 if (!DetectDNP3FuncParseFunctionCode(str
, &function_code
)) {
227 SCLogError(SC_ERR_INVALID_SIGNATURE
,
228 "Invalid argument \"%s\" supplied to dnp3_func keyword.", str
);
232 dnp3
= SCCalloc(1, sizeof(DetectDNP3
));
233 if (unlikely(dnp3
== NULL
)) {
236 dnp3
->function_code
= function_code
;
238 sm
= SigMatchAlloc();
242 sm
->type
= DETECT_AL_DNP3FUNC
;
243 sm
->ctx
= (void *)dnp3
;
245 SigMatchAppendSMToList(s
, sm
, g_dnp3_match_buffer_id
);
258 static int DetectDNP3IndParseByName(const char *str
, uint16_t *flags
)
260 char tmp
[strlen(str
) + 1];
261 char *p
, *last
= NULL
;
263 strlcpy(tmp
, str
, sizeof(tmp
));
265 for ((p
= strtok_r(tmp
, ",", &last
)); p
; (p
= strtok_r(NULL
, ",", &last
))) {
269 while (DNP3IndicatorsMap
[i
].name
!= NULL
) {
270 if (strcasecmp(p
, DNP3IndicatorsMap
[i
].name
) == 0) {
271 *flags
|= DNP3IndicatorsMap
[i
].value
;
279 SCLogError(SC_ERR_INVALID_SIGNATURE
,
280 "Bad argument \"%s\" supplied to dnp3.ind keyword.", p
);
288 static int DetectDNP3IndParse(const char *str
, uint16_t *flags
)
292 if (StringParseUint16(flags
, 0, strlen(str
), str
) > 0) {
296 /* Parse by name - will log a more specific error message on error. */
297 if (DetectDNP3IndParseByName(str
, flags
)) {
304 static int DetectDNP3IndSetup(DetectEngineCtx
*de_ctx
, Signature
*s
, const char *str
)
307 DetectDNP3
*detect
= NULL
;
311 if (DetectSignatureSetAppProto(s
, ALPROTO_DNP3
) != 0)
314 if (!DetectDNP3IndParse(str
, &flags
)) {
315 SCLogError(SC_ERR_INVALID_SIGNATURE
,
316 "Invalid argument \"%s\" supplied to dnp3.ind keyword.", str
);
320 detect
= SCCalloc(1, sizeof(DetectDNP3
));
321 if (unlikely(detect
== NULL
)) {
324 detect
->ind_flags
= flags
;
326 sm
= SigMatchAlloc();
330 sm
->type
= DETECT_AL_DNP3IND
;
331 sm
->ctx
= (void *)detect
;
332 SigMatchAppendSMToList(s
, sm
, g_dnp3_match_buffer_id
);
336 if (detect
!= NULL
) {
346 * \brief Parse the value of string of the dnp3_obj keyword.
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
352 * \retval 1 if parsing successful otherwise 0.
354 static int DetectDNP3ObjParse(const char *str
, uint8_t *group
, uint8_t *var
)
356 size_t size
= strlen(str
) + 1;
357 char groupstr
[size
], *varstr
, *sep
;
358 strlcpy(groupstr
, str
, size
);
360 sep
= strchr(groupstr
, ',');
367 if (StringParseUint8(group
, 0, strlen(groupstr
), groupstr
) < 0) {
371 if (StringParseUint8(var
, 0, strlen(varstr
), varstr
) < 0) {
378 static int DetectDNP3ObjSetup(DetectEngineCtx
*de_ctx
, Signature
*s
, const char *str
)
383 DetectDNP3
*detect
= NULL
;
386 if (DetectSignatureSetAppProto(s
, ALPROTO_DNP3
) != 0)
389 if (!DetectDNP3ObjParse(str
, &group
, &variation
)) {
393 detect
= SCCalloc(1, sizeof(*detect
));
394 if (unlikely(detect
== NULL
)) {
397 detect
->obj_group
= group
;
398 detect
->obj_variation
= variation
;
400 sm
= SigMatchAlloc();
401 if (unlikely(sm
== NULL
)) {
404 sm
->type
= DETECT_AL_DNP3OBJ
;
405 sm
->ctx
= (void *)detect
;
406 SigMatchAppendSMToList(s
, sm
, g_dnp3_match_buffer_id
);
410 if (detect
!= NULL
) {
419 static void DetectDNP3Free(DetectEngineCtx
*de_ctx
, void *ptr
)
428 static int DetectDNP3FuncMatch(DetectEngineThreadCtx
*det_ctx
,
429 Flow
*f
, uint8_t flags
, void *state
, void *txv
, const Signature
*s
,
430 const SigMatchCtx
*ctx
)
432 DNP3Transaction
*tx
= (DNP3Transaction
*)txv
;
433 DetectDNP3
*detect
= (DetectDNP3
*)ctx
;
436 if (flags
& STREAM_TOSERVER
) {
437 match
= detect
->function_code
== tx
->request_ah
.function_code
;
439 else if (flags
& STREAM_TOCLIENT
) {
440 match
= detect
->function_code
== tx
->response_ah
.function_code
;
446 static int DetectDNP3ObjMatch(DetectEngineThreadCtx
*det_ctx
,
447 Flow
*f
, uint8_t flags
, void *state
, void *txv
, const Signature
*s
,
448 const SigMatchCtx
*ctx
)
450 DNP3Transaction
*tx
= (DNP3Transaction
*)txv
;
451 DetectDNP3
*detect
= (DetectDNP3
*)ctx
;
452 DNP3ObjectList
*objects
= NULL
;
454 if (flags
& STREAM_TOSERVER
) {
455 objects
= &tx
->request_objects
;
457 else if (flags
& STREAM_TOCLIENT
) {
458 objects
= &tx
->response_objects
;
461 if (objects
!= NULL
) {
463 TAILQ_FOREACH(object
, objects
, next
) {
464 if (object
->group
== detect
->obj_group
&&
465 object
->variation
== detect
->obj_variation
) {
474 static int DetectDNP3IndMatch(DetectEngineThreadCtx
*det_ctx
,
475 Flow
*f
, uint8_t flags
, void *state
, void *txv
, const Signature
*s
,
476 const SigMatchCtx
*ctx
)
478 DNP3Transaction
*tx
= (DNP3Transaction
*)txv
;
479 DetectDNP3
*detect
= (DetectDNP3
*)ctx
;
481 if (flags
& STREAM_TOCLIENT
) {
482 if ((tx
->response_iin
.iin1
& (detect
->ind_flags
>> 8)) ||
483 (tx
->response_iin
.iin2
& (detect
->ind_flags
& 0xf))) {
491 static void DetectDNP3FuncRegister(void)
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
;
504 sigmatch_table
[DETECT_AL_DNP3FUNC
].RegisterTests
=
505 DetectDNP3FuncRegisterTests
;
510 static void DetectDNP3IndRegister(void)
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
;
523 sigmatch_table
[DETECT_AL_DNP3IND
].RegisterTests
=
524 DetectDNP3IndRegisterTests
;
529 static void DetectDNP3ObjRegister(void)
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
;
542 sigmatch_table
[DETECT_AL_DNP3OBJ
].RegisterTests
=
543 DetectDNP3ObjRegisterTests
;
548 static int DetectDNP3DataSetup(DetectEngineCtx
*de_ctx
, Signature
*s
, const char *str
)
551 if (DetectSignatureSetAppProto(s
, ALPROTO_DNP3
) != 0)
554 if (DetectBufferSetActiveList(s
, g_dnp3_data_buffer_id
) != 0)
560 static void DetectDNP3DataRegister(void)
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
;
570 sigmatch_table
[DETECT_AL_DNP3DATA
].RegisterTests
=
571 DetectDNP3DataRegisterTests
;
573 sigmatch_table
[DETECT_AL_DNP3DATA
].flags
|= SIGMATCH_NOOPT
|SIGMATCH_INFO_STICKY_BUFFER
;
575 DetectAppLayerInspectEngineRegister2("dnp3_data",
576 ALPROTO_DNP3
, SIG_FLAG_TOSERVER
, 0,
577 DetectEngineInspectBufferGeneric
,
579 DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOSERVER
, 2,
580 PrefilterGenericMpmRegister
, GetDNP3Data
,
583 DetectAppLayerInspectEngineRegister2("dnp3_data",
584 ALPROTO_DNP3
, SIG_FLAG_TOCLIENT
, 0,
585 DetectEngineInspectBufferGeneric
,
587 DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOCLIENT
, 2,
588 PrefilterGenericMpmRegister
, GetDNP3Data
,
591 g_dnp3_data_buffer_id
= DetectBufferTypeGetByName("dnp3_data");
595 void DetectDNP3Register(void)
597 DetectDNP3DataRegister();
599 DetectDNP3FuncRegister();
600 DetectDNP3IndRegister();
601 DetectDNP3ObjRegister();
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
);
609 g_dnp3_match_buffer_id
= DetectBufferTypeRegister("dnp3");
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"
622 static int DetectDNP3FuncParseFunctionCodeTest(void)
627 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("0", &fc
));
630 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("1", &fc
));
633 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("254", &fc
));
636 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("255", &fc
));
639 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("confirm", &fc
));
642 FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("CONFIRM", &fc
));
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
));
655 static int DetectDNP3FuncTest01(void)
657 DetectEngineCtx
*de_ctx
= NULL
;
658 DetectDNP3
*dnp3func
= NULL
;
660 de_ctx
= DetectEngineCtxInit();
661 FAIL_IF_NULL(de_ctx
);
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
);
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
);
672 dnp3func
= (DetectDNP3
*)de_ctx
->sig_list
->sm_lists_tail
[g_dnp3_match_buffer_id
]->ctx
;
673 FAIL_IF(dnp3func
->function_code
!= 2);
675 if (de_ctx
!= NULL
) {
676 DetectEngineCtxFree(de_ctx
);
681 static int DetectDNP3IndTestParseAsInteger(void)
685 FAIL_IF(!DetectDNP3IndParse("0", &flags
));
687 FAIL_IF(!DetectDNP3IndParse("1", &flags
));
688 FAIL_IF(flags
!= 0x0001);
690 FAIL_IF(!DetectDNP3IndParse("0x0", &flags
));
692 FAIL_IF(!DetectDNP3IndParse("0x0000", &flags
));
694 FAIL_IF(!DetectDNP3IndParse("0x0001", &flags
));
695 FAIL_IF(flags
!= 0x0001);
697 FAIL_IF(!DetectDNP3IndParse("0x8421", &flags
));
698 FAIL_IF(flags
!= 0x8421);
700 FAIL_IF(DetectDNP3IndParse("a", &flags
));
705 static int DetectDNP3IndTestParseByName(void)
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));
716 FAIL_IF(DetectDNP3IndParse("something", &flags
));
721 static int DetectDNP3ObjSetupTest(void)
723 DetectEngineCtx
*de_ctx
= NULL
;
724 DetectDNP3
*detect
= NULL
;
726 de_ctx
= DetectEngineCtxInit();
727 FAIL_IF(de_ctx
== NULL
);
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
);
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
);
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);
742 if (de_ctx
!= NULL
) {
743 DetectEngineCtxFree(de_ctx
);
748 static int DetectDNP3ObjParseTest(void)
752 FAIL_IF(!DetectDNP3ObjParse("0,0", &group
, &var
));
753 FAIL_IF(group
!= 0 || var
!= 0);
755 FAIL_IF(!DetectDNP3ObjParse("255,255", &group
, &var
));
756 FAIL_IF(group
!= 255 || var
!= 255);
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
));
767 * Test request (to server) content match.
769 static int DetectDNP3DataTest01(void)
771 AppLayerParserThreadCtx
*alp_tctx
= AppLayerParserThreadCtxAlloc();
772 DetectEngineThreadCtx
*det_ctx
= NULL
;
773 DetectEngineCtx
*de_ctx
= NULL
;
779 uint8_t request
[] = {
780 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
783 0xff, 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00,
784 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x00,
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
);
801 f
.alproto
= ALPROTO_DNP3
;
802 f
.protoctx
= (void *)&tcp
;
803 f
.proto
= IPPROTO_TCP
;
804 f
.flags
|= FLOW_IPV4
;
806 p
->flags
|= PKT_HAS_FLOW
| PKT_STREAM_EST
;
807 p
->flowflags
|= FLOW_PKT_TOSERVER
| FLOW_PKT_ESTABLISHED
;
808 StreamTcpInitConfig(true);
810 de_ctx
= DetectEngineCtxInit();
811 FAIL_IF(de_ctx
== NULL
);
813 /* Either direction - should match. */
814 Signature
*s
= DetectEngineAppendSig(de_ctx
,
815 "alert dnp3 any any -> any any ("
816 "msg:\"DetectDNP3DataTest01\"; "
818 "content:\"|01 01 01 00 00 00 00 00 00 00|\"; "
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; "
828 "content:\"|01 01 01 00 00 00 00 00 00 00|\"; "
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; "
838 "content:\"|01 01 01 00 00 00 00 00 00 00|\"; "
842 /* The content of a CRC - should not match. */
843 s
= DetectEngineAppendSig(de_ctx
,
844 "alert dnp3 any any -> any any ("
845 "msg:\"DetectDNP3DataTest01\"; "
847 "content:\"|72 ef|\"; "
851 SigGroupBuild(de_ctx
);
852 DetectEngineThreadCtxInit(&tv
, (void *)de_ctx
, (void *)&det_ctx
);
855 int r
= AppLayerParserParse(NULL
, alp_tctx
, &f
, ALPROTO_DNP3
,
856 STREAM_TOSERVER
, request
, sizeof(request
));
860 FAIL_IF(f
.alstate
== NULL
);
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));
868 if (alp_tctx
!= NULL
)
869 AppLayerParserThreadCtxFree(alp_tctx
);
871 DetectEngineThreadCtxDeinit(&tv
, det_ctx
);
873 SigGroupCleanup(de_ctx
);
875 DetectEngineCtxFree(de_ctx
);
876 StreamTcpFreeConfig(true);
883 * Test response (to client) content match.
885 static int DetectDNP3DataTest02(void)
887 AppLayerParserThreadCtx
*alp_tctx
= AppLayerParserThreadCtxAlloc();
888 DetectEngineThreadCtx
*det_ctx
= NULL
;
889 DetectEngineCtx
*de_ctx
= NULL
;
895 uint8_t request
[] = {
897 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
902 /* Transport header. */
905 /* Application layer. */
906 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
907 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
912 /* Application layer. */
913 0x00, 0x00, 0x00, 0x00, 0x00,
919 uint8_t response
[] = {
921 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
926 /* Transport header. */
929 /* Application layyer. */
930 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
931 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00,
936 /* Application layer. */
937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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
);
949 f
.alproto
= ALPROTO_DNP3
;
950 f
.protoctx
= (void *)&tcp
;
951 f
.proto
= IPPROTO_TCP
;
952 f
.flags
|= FLOW_IPV4
;
954 p
->flags
|= PKT_HAS_FLOW
| PKT_STREAM_EST
;
955 p
->flowflags
|= FLOW_PKT_TOCLIENT
| FLOW_PKT_ESTABLISHED
;
956 StreamTcpInitConfig(true);
958 de_ctx
= DetectEngineCtxInit();
959 FAIL_IF(de_ctx
== NULL
);
961 /* Either direction - should match. */
962 Signature
*s
= DetectEngineAppendSig(de_ctx
,
963 "alert dnp3 any any -> any any ("
964 "msg:\"DetectDNP3DataTest01\"; "
966 "content:\"|01 01 01 00 00 00 00|\"; "
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; "
976 "content:\"|01 01 01 00 00 00 00|\"; "
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; "
986 "content:\"|01 01 01 00 00 00 00|\"; "
990 /* The content of a CRC - should not match. */
991 s
= DetectEngineAppendSig(de_ctx
,
992 "alert dnp3 any any -> any any ("
993 "msg:\"DetectDNP3DataTest01\"; "
995 "content:\"|7a 65|\"; "
999 SigGroupBuild(de_ctx
);
1000 DetectEngineThreadCtxInit(&tv
, (void *)de_ctx
, (void *)&det_ctx
);
1002 /* Send through the request, then response. */
1004 int r
= AppLayerParserParse(NULL
, alp_tctx
, &f
, ALPROTO_DNP3
,
1005 STREAM_TOSERVER
, request
, sizeof(request
));
1006 SCMutexUnlock(&f
.m
);
1008 FAIL_IF(f
.alstate
== NULL
);
1011 r
= AppLayerParserParse(NULL
, alp_tctx
, &f
, ALPROTO_DNP3
, STREAM_TOCLIENT
,
1012 response
, sizeof(response
));
1013 SCMutexUnlock(&f
.m
);
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));
1022 if (alp_tctx
!= NULL
)
1023 AppLayerParserThreadCtxFree(alp_tctx
);
1024 if (det_ctx
!= NULL
)
1025 DetectEngineThreadCtxDeinit(&tv
, det_ctx
);
1027 SigGroupCleanup(de_ctx
);
1029 DetectEngineCtxFree(de_ctx
);
1030 StreamTcpFreeConfig(true);
1036 static void DetectDNP3FuncRegisterTests(void)
1038 UtRegisterTest("DetectDNP3FuncParseFunctionCodeTest",
1039 DetectDNP3FuncParseFunctionCodeTest
);
1040 UtRegisterTest("DetectDNP3FuncTest01", DetectDNP3FuncTest01
);
1043 static void DetectDNP3IndRegisterTests(void)
1045 UtRegisterTest("DetectDNP3IndTestParseAsInteger",
1046 DetectDNP3IndTestParseAsInteger
);
1047 UtRegisterTest("DetectDNP3IndTestParseByName",
1048 DetectDNP3IndTestParseByName
);
1051 static void DetectDNP3ObjRegisterTests(void)
1053 UtRegisterTest("DetectDNP3ObjParseTest", DetectDNP3ObjParseTest
);
1054 UtRegisterTest("DetectDNP3ObjSetupTest", DetectDNP3ObjSetupTest
);
1057 void DetectDNP3DataRegisterTests(void)
1059 UtRegisterTest("DetectDNP3DataTest01", DetectDNP3DataTest01
);
1060 UtRegisterTest("DetectDNP3DataTest02", DetectDNP3DataTest02
);