41 #define DNP3_DEFAULT_PORT "20000"
44 #define DNP3_START_BYTE0 0x05
45 #define DNP3_START_BYTE1 0x64
48 #define DNP3_MIN_LEN 5
51 #define DNP3_CRC_LEN 2
55 #define DNP3_BLOCK_SIZE 16
58 #define DNP3_MAX_TRAN_SEQNO 64
65 #define DNP3_LINK_HDR_LEN 5
81 #define DNP3_OBJ_PREFIX(x) ((x >> 4) & 0x7)
84 #define DNP3_OBJ_RANGE(x) (x & 0xf)
92 static uint64_t dnp3_max_tx = 32;
95 static uint64_t max_points = 16384;
98 static uint64_t dnp3_max_objects = 2048;
114 #define NEXT_TH_SEQNO(current) ((current + 1) % DNP3_MAX_TRAN_SEQNO)
118 static const uint16_t crc_table[256] = {
119 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a,
120 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13,
121 0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1,
122 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78,
123 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35,
124 0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc,
125 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e,
126 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7,
127 0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4,
128 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d,
129 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af,
130 0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26,
131 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b,
132 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2,
133 0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00,
134 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489,
135 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526,
136 0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf,
137 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d,
138 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4,
139 0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89,
140 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300,
141 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2,
142 0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b,
143 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678,
144 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1,
145 0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413,
146 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a,
147 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7,
148 0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e,
149 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc,
150 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235
160 static uint16_t DNP3ComputeCRC(
const uint8_t *buf, uint32_t
len)
162 const uint8_t *
byte = buf;
167 idx = (
crc ^ *byte) & 0xff;
168 crc = (crc_table[idx] ^ (
crc >> 8)) & 0xffff;
172 return ~
crc & 0xffff;
183 static int DNP3CheckCRC(
const uint8_t *block, uint32_t
len)
185 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
198 if (((
crc & 0xff) == block[crc_offset]) &&
199 ((
crc >> 8) == block[crc_offset + 1])) {
213 static int DNP3CheckLinkHeaderCRC(
const DNP3LinkHeader *header)
215 return DNP3CheckCRC((uint8_t *)header,
sizeof(DNP3LinkHeader));
226 static int DNP3CheckUserDataCRCs(
const uint8_t *data, uint32_t
len)
239 if (!DNP3CheckCRC(data +
offset, block_size)) {
255 static int DNP3CheckStartBytes(
const DNP3LinkHeader *header)
262 #define DNP3_BANNER "DNP3"
272 static int DNP3ContainsBanner(
const uint8_t *input, uint32_t
len)
280 static uint16_t DNP3ProbingParser(
281 const Flow *f, uint8_t direction,
const uint8_t *input, uint32_t
len, uint8_t *rdir)
283 const DNP3LinkHeader *
const hdr = (
const DNP3LinkHeader *)input;
284 const bool toserver = (direction & STREAM_TOSERVER) != 0;
287 if (DNP3ContainsBanner(input,
len)) {
289 bool is_banner =
true;
291 for (uint32_t i = 0; i <
len && i < 0x100; i++) {
292 if (!isprint(input[i])) {
299 *rdir = STREAM_TOCLIENT;
306 if (
len <
sizeof(DNP3LinkHeader)) {
307 SCLogDebug(
"Length too small to be a DNP3 header.");
312 if (!DNP3CheckStartBytes(hdr)) {
319 SCLogDebug(
"Packet too small to be a valid DNP3 fragment.");
325 *rdir = toserver ? STREAM_TOCLIENT : STREAM_TOSERVER;
338 static int DNP3CalculateTransportLengthWithoutCRCs(uint32_t input_len)
381 static int DNP3ReassembleApplicationLayer(
const uint8_t *input,
382 uint32_t input_len, uint8_t **output, uint32_t *output_len)
384 int len = DNP3CalculateTransportLengthWithoutCRCs(input_len);
396 if (*output == NULL) {
403 uint8_t *ptr =
SCRealloc(*output, (
size_t)(*output_len +
len));
410 int offset = 0, block_size;
411 while ((uint32_t)
offset < input_len) {
416 block_size = input_len -
offset;
441 memcpy(*output + *output_len, input +
offset,
456 static void *DNP3StateAlloc(
void *orig_state,
AppProto proto_orig)
475 static void DNP3SetEvent(
DNP3State *dnp3, uint8_t event)
477 if (dnp3 && dnp3->
curr) {
482 SCLogWarning(
"Failed to set event, state or tx pointer was NULL.");
538 static uint32_t DNP3CalculateLinkLength(uint8_t length)
540 uint32_t frame_len = 0;
558 return frame_len +
sizeof(DNP3LinkHeader);
568 static int DNP3IsUserData(
const DNP3LinkHeader *header)
587 static int DNP3HasUserData(
const DNP3LinkHeader *header, uint8_t direction)
589 if (direction == STREAM_TOSERVER) {
591 sizeof(DNP3ApplicationHeader);
595 sizeof(DNP3ApplicationHeader) +
sizeof(DNP3InternalInd);
602 static void DNP3BufferReset(
DNP3Buffer *buffer)
617 static int DNP3BufferAdd(
DNP3Buffer *buffer,
const uint8_t *data, uint32_t
len)
619 if (buffer->
size == 0) {
648 static void DNP3BufferTrim(
DNP3Buffer *buffer)
651 DNP3BufferReset(buffer);
653 else if (buffer->
offset > 0) {
664 static void DNP3ObjectFree(
DNP3Object *
object)
666 if (object->
points != NULL) {
683 if (object->
points == NULL) {
684 DNP3ObjectFree(
object);
705 static int DNP3DecodeApplicationObjects(
DNP3Transaction *tx,
const uint8_t *buf,
706 uint32_t
len, DNP3ObjectList *objects)
709 uint64_t point_count = 0;
710 uint64_t object_count = 0;
712 if (buf == NULL ||
len == 0) {
719 if (
len <
sizeof(DNP3ObjHeader)) {
722 DNP3ObjHeader *header = (DNP3ObjHeader *)buf;
723 offset +=
sizeof(DNP3ObjHeader);
726 if (++object_count > dnp3_max_objects) {
737 object->group = header->group;
738 object->variation = header->variation;
739 object->qualifier = header->qualifier;
749 if (
offset + (
sizeof(uint8_t) * 2) >
len) {
752 goto not_enough_data;
754 object->start = buf[
offset++];
755 object->stop = buf[
offset++];
756 object->count =
object->stop -
object->start + 1;
763 if (
offset + (
sizeof(uint16_t) * 2) >
len) {
766 goto not_enough_data;
769 offset +=
sizeof(uint16_t);
771 offset +=
sizeof(uint16_t);
772 object->count =
object->stop -
object->start + 1;
779 if (
offset + (
sizeof(uint32_t) * 2) >
len) {
782 goto not_enough_data;
785 offset +=
sizeof(uint32_t);
787 offset +=
sizeof(uint32_t);
788 object->count =
object->stop -
object->start + 1;
799 goto not_enough_data;
801 object->count = buf[
offset];
802 offset +=
sizeof(uint8_t);
808 goto not_enough_data;
811 offset +=
sizeof(uint16_t);
818 goto not_enough_data;
821 offset +=
sizeof(uint32_t);
828 goto not_enough_data;
830 object->count = *(uint8_t *)(buf +
offset);
831 offset +=
sizeof(uint8_t);
848 point_count +=
object->count;
849 if (point_count > max_points) {
881 static void DNP3HandleUserDataRequest(
882 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
886 DNP3ApplicationHeader *ah;
889 lh = (DNP3LinkHeader *)input;
891 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
892 input_len -
sizeof(DNP3LinkHeader))) {
896 th = input[
sizeof(DNP3LinkHeader)];
900 if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && ttx->is_request && !ttx->done &&
917 ah = (DNP3ApplicationHeader *)(input +
sizeof(DNP3LinkHeader) +
926 tx = DNP3TxAlloc(dnp3,
true);
936 if (!DNP3ReassembleApplicationLayer(input +
sizeof(DNP3LinkHeader),
952 if (DNP3DecodeApplicationObjects(tx, tx->
buffer +
sizeof(DNP3ApplicationHeader),
961 static void DNP3HandleUserDataResponse(
962 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
966 DNP3ApplicationHeader *ah;
967 DNP3InternalInd *iin;
971 lh = (DNP3LinkHeader *)input;
972 offset +=
sizeof(DNP3LinkHeader);
974 if (!DNP3CheckUserDataCRCs(input +
offset, input_len -
offset)) {
982 if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && !ttx->is_request &&
999 ah = (DNP3ApplicationHeader *)(input +
offset);
1000 offset +=
sizeof(DNP3ApplicationHeader);
1001 iin = (DNP3InternalInd *)(input +
offset);
1003 tx = DNP3TxAlloc(dnp3,
false);
1007 tx->
tx_data.updated_tc =
true;
1016 if (!DNP3ReassembleApplicationLayer(input +
sizeof(DNP3LinkHeader),
1028 offset =
sizeof(DNP3ApplicationHeader) +
sizeof(DNP3InternalInd);
1029 if (DNP3DecodeApplicationObjects(
1044 static int DNP3HandleRequestLinkLayer(
1045 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
1048 uint32_t processed = 0;
1053 if (input_len <
sizeof(DNP3LinkHeader)) {
1057 DNP3LinkHeader *header = (DNP3LinkHeader *)input;
1059 if (!DNP3CheckStartBytes(header)) {
1063 if (!DNP3CheckLinkHeaderCRC(header)) {
1068 uint32_t frame_len = DNP3CalculateLinkLength(header->len);
1069 if (frame_len == 0) {
1073 if (input_len < frame_len) {
1079 if (!DNP3IsUserData(header)) {
1085 if (!DNP3HasUserData(header, STREAM_TOSERVER)) {
1090 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
1091 frame_len -
sizeof(DNP3LinkHeader))) {
1096 DNP3HandleUserDataRequest(f, dnp3, input, frame_len);
1101 input_len -= frame_len;
1102 processed += frame_len;
1128 const uint8_t *input = StreamSliceGetData(&stream_slice);
1129 uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1131 if (input_len == 0) {
1136 if (!DNP3BufferAdd(buffer, input, input_len)) {
1139 processed = DNP3HandleRequestLinkLayer(
1141 if (processed < 0) {
1144 buffer->
offset += processed;
1145 DNP3BufferTrim(buffer);
1148 processed = DNP3HandleRequestLinkLayer(f, dnp3, input, input_len);
1149 if (processed < 0) {
1150 SCLogDebug(
"Failed to process request link layer.");
1155 input_len -= processed;
1159 if (!DNP3BufferAdd(buffer, input, input_len)) {
1169 DNP3BufferReset(buffer);
1179 static int DNP3HandleResponseLinkLayer(
1180 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
1183 uint32_t processed = 0;
1188 if (input_len <
sizeof(DNP3LinkHeader)) {
1192 DNP3LinkHeader *header = (DNP3LinkHeader *)input;
1194 if (!DNP3CheckStartBytes(header)) {
1198 if (!DNP3CheckLinkHeaderCRC(header)) {
1204 uint32_t frame_len = DNP3CalculateLinkLength(header->len);
1205 if (frame_len == 0) {
1209 if (input_len < frame_len) {
1215 if (!DNP3IsUserData(header)) {
1221 if (!DNP3HasUserData(header, STREAM_TOCLIENT)) {
1226 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
1227 frame_len -
sizeof(DNP3LinkHeader))) {
1232 DNP3HandleUserDataResponse(f, dnp3, input, frame_len);
1237 input_len -= frame_len;
1238 processed += frame_len;
1266 const uint8_t *input = StreamSliceGetData(&stream_slice);
1267 uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1270 if (!DNP3BufferAdd(buffer, input, input_len)) {
1273 processed = DNP3HandleResponseLinkLayer(
1275 if (processed < 0) {
1278 buffer->
offset += processed;
1279 DNP3BufferTrim(buffer);
1284 if (DNP3ContainsBanner(input, input_len)) {
1288 processed = DNP3HandleResponseLinkLayer(f, dnp3, input, input_len);
1289 if (processed < 0) {
1293 input_len -= processed;
1297 if (!DNP3BufferAdd(buffer, input, input_len)) {
1309 DNP3BufferReset(buffer);
1313 static void *DNP3GetTx(
void *alstate, uint64_t tx_id)
1318 uint64_t tx_num = tx_id + 1;
1325 if (tx_num != tx->
tx_num) {
1334 static uint64_t DNP3GetTxCnt(
void *state)
1337 uint64_t count = ((uint64_t)((
DNP3State *)state)->transaction_max);
1344 static void DNP3TxFreeObjectList(DNP3ObjectList *objects)
1350 DNP3ObjectFree(
object);
1361 if (tx->
buffer != NULL) {
1365 SCAppLayerTxDataCleanup(&tx->
tx_data);
1367 DNP3TxFreeObjectList(&tx->
objects);
1379 static void DNP3StateTxFree(
void *state, uint64_t tx_id)
1384 uint64_t tx_num = tx_id + 1;
1388 if (tx->
tx_num != tx_num) {
1392 if (tx == dnp3->
curr) {
1396 if (tx->
tx_data.events != NULL) {
1421 static void DNP3StateFree(
void *state)
1426 if (state != NULL) {
1427 while ((tx =
TAILQ_FIRST(&dnp3->tx_list)) != NULL) {
1445 static int DNP3GetAlstateProgress(
void *tx, uint8_t direction)
1453 SCLogDebug(
"flooded: returning tx as done.");
1466 static int DNP3StateGetEventInfo(
1479 static int DNP3StateGetEventInfoById(
1483 if (*event_name == NULL) {
1485 "the DNP3 enum event map table.",
1514 switch (prefix_code) {
1532 if (state->
un.
ptr == NULL) {
1538 while (tx_ptr->
tx_num < min_tx_id + 1) {
1544 if (tx_ptr->
tx_num >= max_tx_id + 1) {
1550 .tx_id = tx_ptr->
tx_num - 1,
1551 .has_next = (state->
un.
ptr != NULL),
1566 const char *proto_name =
"dnp3";
1573 sizeof(DNP3LinkHeader), STREAM_TOSERVER, DNP3ProbingParser, DNP3ProbingParser);
1577 0,
sizeof(DNP3LinkHeader), DNP3ProbingParser, DNP3ProbingParser)) {
1583 SCLogConfig(
"Protocol detection and parser disabled for DNP3.");
1596 DNP3StateAlloc, DNP3StateFree);
1605 DNP3GetAlstateProgress);
1609 DNP3StateGetEventInfo);
1611 DNP3StateGetEventInfoById);
1619 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-tx", &value)) {
1620 dnp3_max_tx = (uint64_t)value;
1624 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-points", &value)) {
1626 max_points = (uint64_t)value;
1631 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-objects", &value)) {
1633 dnp3_max_objects = (uint64_t)value;
1638 "Protocol detection still on.", proto_name);
1657 static void DNP3FixCrc(uint8_t *data, uint32_t
len)
1659 uint32_t block_size;
1667 uint16_t
crc = DNP3ComputeCRC(data, block_size);
1668 data[block_size + 1] = (
crc >> 8) & 0xff;
1669 data[block_size] =
crc & 0xff;
1678 static int DNP3ParserTestCheckCRC(
void)
1680 uint8_t request[] = {
1682 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
1689 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
1690 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
1694 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1698 FAIL_IF(!DNP3CheckCRC(request,
sizeof(DNP3LinkHeader)));
1701 FAIL_IF(!DNP3CheckCRC(request +
sizeof(DNP3LinkHeader),
1704 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1707 FAIL_IF(DNP3CheckCRC(request,
sizeof(DNP3LinkHeader)));
1711 request[
sizeof(DNP3LinkHeader) + 3]++;
1712 FAIL_IF(DNP3CheckCRC(request +
sizeof(DNP3LinkHeader),
1722 static int DNP3CheckUserDataCRCsTest(
void)
1725 uint8_t data_valid[] = {
1726 0xff, 0xc9, 0x05, 0x0c,
1727 0x01, 0x28, 0x01, 0x00,
1728 0x00, 0x00, 0x01, 0x01,
1729 0x01, 0x00, 0x00, 0x00,
1732 0xff, 0xc9, 0x05, 0x0c,
1733 0x01, 0x28, 0x01, 0x00,
1734 0x00, 0x00, 0x01, 0x01,
1735 0x01, 0x00, 0x00, 0x00,
1738 0xff, 0xc9, 0x05, 0x0c,
1739 0x01, 0x28, 0x01, 0x00,
1740 0x00, 0x00, 0x01, 0x01,
1741 0x01, 0x00, 0x00, 0x00,
1744 0x00, 0x00, 0x00, 0x00,
1748 FAIL_IF(!DNP3CheckUserDataCRCs(data_valid,
sizeof(data_valid)));
1750 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1752 uint8_t data_invalid[] = {
1753 0xff, 0xc9, 0x05, 0x0c,
1754 0x01, 0x28, 0x01, 0x00,
1755 0x00, 0x00, 0x01, 0x01,
1756 0x01, 0x00, 0x00, 0x00,
1759 0xff, 0xc9, 0x05, 0x0c,
1760 0x01, 0x28, 0x01, 0x00,
1761 0x00, 0x00, 0x01, 0x01,
1762 0x01, 0x00, 0x00, 0x00,
1765 0xff, 0xc9, 0x05, 0x0c,
1766 0x01, 0x28, 0x01, 0x00,
1767 0x00, 0x00, 0x01, 0x01,
1768 0x01, 0x00, 0x00, 0x00,
1771 0x00, 0x00, 0x00, 0x00,
1775 FAIL_IF(DNP3CheckUserDataCRCs(data_invalid,
sizeof(data_invalid)));
1778 uint8_t one_byte_nocrc[] = { 0x01 };
1779 FAIL_IF(DNP3CheckUserDataCRCs(one_byte_nocrc,
sizeof(one_byte_nocrc)));
1782 uint8_t two_byte_nocrc[] = { 0x01, 0x02 };
1783 FAIL_IF(DNP3CheckUserDataCRCs(two_byte_nocrc,
sizeof(two_byte_nocrc)));
1787 uint8_t three_bytes_good_crc[] = { 0x00, 0x00, 0x00 };
1788 *(uint16_t *)(three_bytes_good_crc + 1) = DNP3ComputeCRC(
1789 three_bytes_good_crc, 1);
1790 FAIL_IF(!DNP3CheckUserDataCRCs(three_bytes_good_crc,
1791 sizeof(three_bytes_good_crc)));
1803 static int DNP3CalculateLinkLengthTest(
void)
1806 FAIL_IF(DNP3CalculateLinkLength(0) != 0);
1807 FAIL_IF(DNP3CalculateLinkLength(1) != 0);
1808 FAIL_IF(DNP3CalculateLinkLength(2) != 0);
1809 FAIL_IF(DNP3CalculateLinkLength(3) != 0);
1810 FAIL_IF(DNP3CalculateLinkLength(4) != 0);
1813 FAIL_IF(DNP3CalculateLinkLength(5) != 10);
1816 FAIL_IF(DNP3CalculateLinkLength(21) != 28);
1819 FAIL_IF(DNP3CalculateLinkLength(37) != 46);
1823 FAIL_IF(DNP3CalculateLinkLength(38) != 49);
1826 FAIL_IF(DNP3CalculateLinkLength(255) != 292);
1835 static int DNP3CalculateTransportLengthWithoutCRCsTest(
void)
1837 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(0) != -1);
1838 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(1) != -1);
1839 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(2) != 0);
1840 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(3) != 1);
1841 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(16) != 14);
1842 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(17) != 15);
1843 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(18) != 16);
1846 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(19) != -1);
1850 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(20) != 16);
1852 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(21) != 17);
1860 static int DNP3ParserCheckLinkHeaderCRC(
void)
1863 uint8_t request[] = {
1865 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
1872 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
1873 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
1874 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1877 DNP3LinkHeader *header = (DNP3LinkHeader *)request;
1878 FAIL_IF(!DNP3CheckLinkHeaderCRC(header));
1880 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1883 FAIL_IF(DNP3CheckLinkHeaderCRC(header));
1892 static int DNP3ReassembleApplicationLayerTest01(
void)
1894 uint32_t reassembled_len = 0;
1895 uint8_t *output = NULL;
1897 uint8_t payload[] = {
1899 0xff, 0xc9, 0x05, 0x0c,
1900 0x01, 0x28, 0x01, 0x00,
1901 0x00, 0x00, 0x01, 0x01,
1902 0x01, 0x00, 0x00, 0x00,
1905 0xff, 0xc9, 0x05, 0x0c,
1906 0x01, 0x28, 0x01, 0x00,
1907 0x00, 0x00, 0x01, 0x01,
1908 0x01, 0x00, 0x00, 0x00,
1911 0xff, 0xc9, 0x05, 0x0c,
1912 0x01, 0x28, 0x01, 0x00,
1913 0x00, 0x00, 0x01, 0x01,
1914 0x01, 0x00, 0x00, 0x00,
1917 0x00, 0x00, 0x00, 0x00,
1922 uint8_t expected[] = {
1924 0x01, 0x28, 0x01, 0x00,
1925 0x00, 0x00, 0x01, 0x01,
1926 0x01, 0x00, 0x00, 0x00,
1928 0xff, 0xc9, 0x05, 0x0c,
1929 0x01, 0x28, 0x01, 0x00,
1930 0x00, 0x00, 0x01, 0x01,
1931 0x01, 0x00, 0x00, 0x00,
1933 0xff, 0xc9, 0x05, 0x0c,
1934 0x01, 0x28, 0x01, 0x00,
1935 0x00, 0x00, 0x01, 0x01,
1936 0x01, 0x00, 0x00, 0x00,
1938 0x00, 0x00, 0x00, 0x00,
1944 FAIL_IF(!DNP3ReassembleApplicationLayer(payload,
1945 sizeof(payload), &output, &reassembled_len));
1947 FAIL_IF(reassembled_len !=
sizeof(expected));
1948 FAIL_IF(memcmp(expected, output, reassembled_len));
1952 reassembled_len = 0;
1954 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 1, &output,
1957 FAIL_IF(reassembled_len != 0);
1960 reassembled_len = 0;
1962 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 2, &output,
1965 FAIL_IF(reassembled_len != 0);
1969 reassembled_len = 0;
1971 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 3, &output,
1974 FAIL_IF(reassembled_len != 0);
1977 reassembled_len = 0;
1979 FAIL_IF(!DNP3ReassembleApplicationLayer(payload, 4, &output,
1982 FAIL_IF(reassembled_len != 1);
1985 uint8_t short_payload1[] = {
1987 0xff, 0xc9, 0x05, 0x0c,
1988 0x01, 0x28, 0x01, 0x00,
1989 0x00, 0x00, 0x01, 0x01,
1990 0x01, 0x00, 0x00, 0x00,
1993 0xff, 0xc9, 0x05, 0x0c,
1994 0x01, 0x28, 0x01, 0x00,
1995 0x00, 0x00, 0x01, 0x01,
1996 0x01, 0x00, 0x00, 0x00,
1999 0xff, 0xc9, 0x05, 0x0c,
2000 0x01, 0x28, 0x01, 0x00,
2001 0x00, 0x00, 0x01, 0x01,
2002 0x01, 0x00, 0x00, 0x00,
2007 reassembled_len = 0;
2008 FAIL_IF(DNP3ReassembleApplicationLayer(short_payload1,
2009 sizeof(short_payload1), &output, &reassembled_len));
2012 uint8_t short_payload2[] = {
2014 0xff, 0xc9, 0x05, 0x0c,
2015 0x01, 0x28, 0x01, 0x00,
2016 0x00, 0x00, 0x01, 0x01,
2017 0x01, 0x00, 0x00, 0x00,
2020 0xff, 0xc9, 0x05, 0x0c,
2021 0x01, 0x28, 0x01, 0x00,
2022 0x00, 0x00, 0x01, 0x01,
2023 0x01, 0x00, 0x00, 0x00,
2026 0xff, 0xc9, 0x05, 0x0c,
2027 0x01, 0x28, 0x01, 0x00,
2028 0x00, 0x00, 0x01, 0x01,
2029 0x01, 0x00, 0x00, 0x00,
2034 reassembled_len = 0;
2035 FAIL_IF(DNP3ReassembleApplicationLayer(short_payload2,
2036 sizeof(short_payload2), &output, &reassembled_len));
2046 static int DNP3ProbingParserTest(
void)
2049 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00,
2055 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt,
sizeof(pkt), &rdir) !=
ALPROTO_DNP3);
2058 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt,
sizeof(DNP3LinkHeader) - 1, &rdir) !=
ALPROTO_UNKNOWN);
2072 char mybanner[] =
"Welcome to DNP3 SCADA.";
2073 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, (uint8_t *)mybanner,
sizeof(mybanner) - 1,
2075 FAIL_IF(rdir != STREAM_TOCLIENT);
2083 static int DNP3ParserTestRequestResponse(
void)
2087 uint8_t request[] = {
2089 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2096 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2097 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2098 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2101 uint8_t response[] = {
2103 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
2110 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
2111 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a,
2112 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2120 memset(&flow, 0,
sizeof(flow));
2121 memset(&ssn, 0,
sizeof(ssn));
2124 flow.
proto = IPPROTO_TCP;
2131 STREAM_TOSERVER, request,
sizeof(request)));
2147 STREAM_TOCLIENT, response,
sizeof(response)));
2166 static int DNP3ParserTestUnsolicitedResponseConfirm(
void)
2171 uint8_t response[] = {
2172 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2173 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02,
2174 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8,
2175 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9
2179 uint8_t confirm[] = {
2180 0x05, 0x64, 0x08, 0xc4, 0x02, 0x00,
2181 0x01, 0x00, 0xd3, 0xb7, 0xc0, 0xda, 0x00, 0x6a,
2189 memset(&flow, 0,
sizeof(flow));
2190 memset(&ssn, 0,
sizeof(ssn));
2193 flow.
proto = IPPROTO_TCP;
2200 STREAM_TOCLIENT, response,
sizeof(response)));
2215 STREAM_TOSERVER, confirm,
sizeof(confirm)));
2236 static int DNP3ParserTestFlooded(
void)
2240 uint8_t request[] = {
2242 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2249 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2250 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2251 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2258 memset(&flow, 0,
sizeof(flow));
2259 memset(&ssn, 0,
sizeof(ssn));
2262 flow.
proto = IPPROTO_TCP;
2269 STREAM_TOSERVER, request,
sizeof(request)));
2283 FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER));
2285 for (uint64_t i = 0; i < dnp3_max_tx - 1; i++) {
2288 STREAM_TOSERVER, request,
sizeof(request)));
2292 FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER));
2297 STREAM_TOSERVER, request,
sizeof(request)));
2302 FAIL_IF(!DNP3GetAlstateProgress(tx, 0));
2317 static int DNP3ParserTestPartialFrame(
void)
2323 uint8_t request_partial1[] = {
2325 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2332 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2335 uint8_t request_partial2[] = {
2337 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2338 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2341 uint8_t response_partial1[] = {
2343 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
2350 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
2353 uint8_t response_partial2[] = {
2354 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a,
2355 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2363 memset(&flow, 0,
sizeof(flow));
2364 memset(&ssn, 0,
sizeof(ssn));
2366 flow.
proto = IPPROTO_TCP;
2374 STREAM_TOSERVER, request_partial1,
sizeof(request_partial1));
2384 sizeof(request_partial1)));
2388 FAIL_IF(DNP3GetTx(state, 0) != NULL);
2393 STREAM_TOSERVER, request_partial2,
sizeof(request_partial2));
2403 tx = DNP3GetTx(state, 0);
2414 STREAM_TOCLIENT, response_partial1,
sizeof(response_partial1));
2419 tx = DNP3GetTx(state, 1);
2425 STREAM_TOCLIENT, response_partial2,
sizeof(response_partial2));
2434 tx = DNP3GetTx(state, 1);
2448 static int DNP3ParserTestMultiFrame(
void)
2453 uint8_t unsol_response1[] = {
2454 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2455 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02,
2456 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8,
2457 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9,
2461 uint8_t unsol_response2[] = {
2462 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2463 0x89, 0xe5, 0xc5, 0xfb, 0x82, 0x00, 0x00, 0x02,
2464 0x02, 0x17, 0x01, 0x0c, 0x01, 0xd8, 0x75, 0xd8,
2465 0x32, 0x4c, 0xc9, 0x3c, 0x01, 0xa1, 0xc9,
2468 uint8_t combined[
sizeof(unsol_response1) +
sizeof(unsol_response2)];
2469 memcpy(combined, unsol_response1,
sizeof(unsol_response1));
2470 memcpy(combined +
sizeof(unsol_response1), unsol_response2,
2471 sizeof(unsol_response2));
2478 memset(&flow, 0,
sizeof(flow));
2479 memset(&ssn, 0,
sizeof(ssn));
2481 flow.
proto = IPPROTO_TCP;
2487 STREAM_TOCLIENT, combined,
sizeof(combined));
2509 static int DNP3ParserTestParsePDU01(
void)
2513 const uint8_t pkt[] = {
2515 0x0b, 0xc4, 0x17, 0x00, 0xef, 0xff, 0xc4, 0x8f,
2516 0xe1, 0xc8, 0x01, 0x01, 0x00, 0x06, 0x77, 0x6e
2520 int pdus = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2530 DNP3StateFree(dnp3state);
2537 static int DNP3ParserDecodeG70V3Test(
void)
2539 const uint8_t pkt[] = {
2541 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, 0xc7, 0xee,
2542 0xc7, 0xc9, 0x1b, 0x46, 0x03, 0x5b, 0x01, 0x55,
2543 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
2544 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2546 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43,
2547 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44,
2548 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69,
2549 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
2550 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c,
2551 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65,
2552 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d,
2553 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65,
2554 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c,
2560 int bytes = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2561 FAIL_IF(bytes !=
sizeof(pkt));
2580 "C:/temp/DNPDeviceConfiguration written to Remote Device.xml") == 0);
2581 DNP3StateFree(dnp3state);
2588 static int DNP3ParserUnknownEventAlertTest(
void)
2592 0x05, 0x64, 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00,
2602 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
2603 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2605 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43,
2606 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44,
2607 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69,
2608 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
2609 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c,
2610 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65,
2611 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d,
2612 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65,
2613 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c,
2617 DNP3FixCrc(pkt + 10,
sizeof(pkt) - 10);
2621 int bytes = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2622 FAIL_IF(bytes !=
sizeof(pkt));
2624 DNP3StateFree(dnp3state);
2631 static int DNP3ParserIncorrectUserData(
void)
2633 uint8_t packet_bytes[] = {
2634 0x05, 0x64, 0x08, 0xc4, 0x03, 0x00, 0x04, 0x00,
2635 0xbf, 0xe9, 0xc1, 0xc1, 0x82, 0xc5, 0xee
2641 memset(&flow, 0,
sizeof(flow));
2642 memset(&ssn, 0,
sizeof(ssn));
2644 flow.
proto = IPPROTO_TCP;
2649 STREAM_TOCLIENT, packet_bytes,
sizeof(packet_bytes));
2664 UtRegisterTest(
"DNP3ParserTestCheckCRC", DNP3ParserTestCheckCRC);
2666 DNP3ParserCheckLinkHeaderCRC);
2667 UtRegisterTest(
"DNP3CheckUserDataCRCsTest", DNP3CheckUserDataCRCsTest);
2668 UtRegisterTest(
"DNP3CalculateLinkLengthTest", DNP3CalculateLinkLengthTest);
2670 DNP3CalculateTransportLengthWithoutCRCsTest);
2672 DNP3ReassembleApplicationLayerTest01);
2675 DNP3ParserTestRequestResponse);
2677 DNP3ParserTestUnsolicitedResponseConfirm);
2678 UtRegisterTest(
"DNP3ParserTestPartialFrame", DNP3ParserTestPartialFrame);
2679 UtRegisterTest(
"DNP3ParserTestMultiFrame", DNP3ParserTestMultiFrame);
2681 UtRegisterTest(
"DNP3ParserTestParsePDU01", DNP3ParserTestParsePDU01);
2682 UtRegisterTest(
"DNP3ParserDecodeG70V3Test", DNP3ParserDecodeG70V3Test);
2684 DNP3ParserUnknownEventAlertTest);
2685 UtRegisterTest(
"DNP3ParserIncorrectUserData", DNP3ParserIncorrectUserData);