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;
115 #define NEXT_TH_SEQNO(current) ((current + 1) % DNP3_MAX_TRAN_SEQNO)
119 static const uint16_t crc_table[256] = {
120 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a,
121 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13,
122 0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1,
123 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78,
124 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35,
125 0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc,
126 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e,
127 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7,
128 0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4,
129 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d,
130 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af,
131 0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26,
132 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b,
133 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2,
134 0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00,
135 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489,
136 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526,
137 0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf,
138 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d,
139 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4,
140 0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89,
141 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300,
142 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2,
143 0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b,
144 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678,
145 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1,
146 0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413,
147 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a,
148 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7,
149 0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e,
150 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc,
151 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235
161 static uint16_t DNP3ComputeCRC(
const uint8_t *buf, uint32_t
len)
163 const uint8_t *
byte = buf;
168 idx = (
crc ^ *byte) & 0xff;
169 crc = (crc_table[idx] ^ (
crc >> 8)) & 0xffff;
173 return ~
crc & 0xffff;
184 static int DNP3CheckCRC(
const uint8_t *block, uint16_t
len)
186 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
199 if (((
crc & 0xff) == block[crc_offset]) &&
200 ((
crc >> 8) == block[crc_offset + 1])) {
214 static int DNP3CheckLinkHeaderCRC(
const DNP3LinkHeader *header)
216 return DNP3CheckCRC((uint8_t *)header,
sizeof(DNP3LinkHeader));
227 static int DNP3CheckUserDataCRCs(
const uint8_t *data, uint16_t
len)
240 if (!DNP3CheckCRC(data +
offset, block_size)) {
256 static int DNP3CheckStartBytes(
const DNP3LinkHeader *header)
263 #define DNP3_BANNER "DNP3"
273 static int DNP3ContainsBanner(
const uint8_t *input, uint32_t
len)
281 static uint16_t DNP3ProbingParser(
282 const Flow *f, uint8_t direction,
const uint8_t *input, uint32_t
len, uint8_t *rdir)
284 const DNP3LinkHeader *
const hdr = (
const DNP3LinkHeader *)input;
285 const bool toserver = (direction & STREAM_TOSERVER) != 0;
288 if (DNP3ContainsBanner(input,
len)) {
290 bool is_banner =
true;
292 for (uint32_t i = 0; i <
len && i < 0x100; i++) {
293 if (!isprint(input[i])) {
300 *rdir = STREAM_TOCLIENT;
307 if (
len <
sizeof(DNP3LinkHeader)) {
308 SCLogDebug(
"Length too small to be a DNP3 header.");
313 if (!DNP3CheckStartBytes(hdr)) {
320 SCLogDebug(
"Packet too small to be a valid DNP3 fragment.");
326 *rdir = toserver ? STREAM_TOCLIENT : STREAM_TOSERVER;
339 static int DNP3CalculateTransportLengthWithoutCRCs(uint16_t input_len)
382 static int DNP3ReassembleApplicationLayer(
383 const uint8_t *input, uint16_t input_len, uint8_t **output, uint16_t *output_len)
385 int len = DNP3CalculateTransportLengthWithoutCRCs(input_len);
397 if (*output == NULL) {
404 uint8_t *ptr =
SCRealloc(*output, (
size_t)(*output_len +
len));
411 uint16_t
offset = 0, block_size;
412 while (
offset < input_len) {
417 block_size = input_len -
offset;
442 memcpy(*output + *output_len, input +
offset,
457 static void *DNP3StateAlloc(
void *orig_state,
AppProto proto_orig)
476 static void DNP3SetEvent(
DNP3State *dnp3, uint8_t event)
478 if (dnp3 && dnp3->
curr) {
483 SCLogWarning(
"Failed to set event, state or tx pointer was NULL.");
539 static uint16_t DNP3CalculateLinkLength(uint8_t length)
541 uint16_t frame_len = 0;
559 return frame_len +
sizeof(DNP3LinkHeader);
569 static int DNP3IsUserData(
const DNP3LinkHeader *header)
588 static int DNP3HasUserData(
const DNP3LinkHeader *header, uint8_t direction)
590 if (direction == STREAM_TOSERVER) {
592 sizeof(DNP3ApplicationHeader);
596 sizeof(DNP3ApplicationHeader) +
sizeof(DNP3InternalInd);
603 static void DNP3BufferReset(
DNP3Buffer *buffer)
618 static int DNP3BufferAdd(
DNP3Buffer *buffer,
const uint8_t *data, uint32_t
len)
620 if (buffer->
size == 0) {
649 static void DNP3BufferTrim(
DNP3Buffer *buffer)
652 DNP3BufferReset(buffer);
654 else if (buffer->
offset > 0) {
665 static void DNP3ObjectFree(
DNP3Object *
object)
667 if (object->
points != NULL) {
684 if (object->
points == NULL) {
685 DNP3ObjectFree(
object);
706 static int DNP3DecodeApplicationObjects(
710 uint64_t point_count = 0;
711 uint64_t object_count = 0;
713 if (buf == NULL ||
len == 0) {
720 if (
len <
sizeof(DNP3ObjHeader)) {
723 DNP3ObjHeader *header = (DNP3ObjHeader *)buf;
724 offset +=
sizeof(DNP3ObjHeader);
727 if (++object_count > dnp3_max_objects) {
738 object->group = header->group;
739 object->variation = header->variation;
740 object->qualifier = header->qualifier;
750 if (
offset + (
sizeof(uint8_t) * 2) >
len) {
753 goto not_enough_data;
755 object->start = buf[
offset++];
756 object->stop = buf[
offset++];
757 object->count =
object->stop -
object->start + 1;
764 if (
offset + (
sizeof(uint16_t) * 2) >
len) {
767 goto not_enough_data;
770 offset +=
sizeof(uint16_t);
772 offset +=
sizeof(uint16_t);
773 object->count =
object->stop -
object->start + 1;
780 if (
offset + (
sizeof(uint32_t) * 2) >
len) {
783 goto not_enough_data;
786 offset +=
sizeof(uint32_t);
788 offset +=
sizeof(uint32_t);
789 object->count =
object->stop -
object->start + 1;
800 goto not_enough_data;
802 object->count = buf[
offset];
803 offset +=
sizeof(uint8_t);
809 goto not_enough_data;
812 offset +=
sizeof(uint16_t);
819 goto not_enough_data;
822 offset +=
sizeof(uint32_t);
829 goto not_enough_data;
831 object->count = *(uint8_t *)(buf +
offset);
832 offset +=
sizeof(uint8_t);
849 point_count +=
object->count;
850 if (point_count > max_points) {
882 static void DNP3HandleUserDataRequest(
883 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint16_t input_len)
887 DNP3ApplicationHeader *ah;
890 lh = (DNP3LinkHeader *)input;
892 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
893 input_len -
sizeof(DNP3LinkHeader))) {
897 th = input[
sizeof(DNP3LinkHeader)];
901 if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && ttx->is_request && !ttx->done &&
918 ah = (DNP3ApplicationHeader *)(input +
sizeof(DNP3LinkHeader) +
927 tx = DNP3TxAlloc(dnp3,
true);
937 if (!DNP3ReassembleApplicationLayer(input +
sizeof(DNP3LinkHeader),
960 if (DNP3DecodeApplicationObjects(tx, tx->
buffer +
sizeof(DNP3ApplicationHeader),
969 static void DNP3HandleUserDataResponse(
970 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint16_t input_len)
974 DNP3ApplicationHeader *ah;
975 DNP3InternalInd *iin;
979 lh = (DNP3LinkHeader *)input;
980 offset +=
sizeof(DNP3LinkHeader);
982 if (!DNP3CheckUserDataCRCs(input +
offset, input_len -
offset)) {
990 if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && !ttx->is_request &&
1007 ah = (DNP3ApplicationHeader *)(input +
offset);
1008 offset +=
sizeof(DNP3ApplicationHeader);
1009 iin = (DNP3InternalInd *)(input +
offset);
1011 tx = DNP3TxAlloc(dnp3,
false);
1024 if (!DNP3ReassembleApplicationLayer(input +
sizeof(DNP3LinkHeader),
1043 offset =
sizeof(DNP3ApplicationHeader) +
sizeof(DNP3InternalInd);
1044 if (DNP3DecodeApplicationObjects(
1059 static int DNP3HandleRequestLinkLayer(
1060 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
1063 uint32_t processed = 0;
1068 if (input_len <
sizeof(DNP3LinkHeader)) {
1072 DNP3LinkHeader *header = (DNP3LinkHeader *)input;
1074 if (!DNP3CheckStartBytes(header)) {
1078 if (!DNP3CheckLinkHeaderCRC(header)) {
1083 uint16_t frame_len = DNP3CalculateLinkLength(header->len);
1084 if (frame_len == 0) {
1088 if (input_len < frame_len) {
1094 if (!DNP3IsUserData(header)) {
1100 if (!DNP3HasUserData(header, STREAM_TOSERVER)) {
1105 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
1106 frame_len -
sizeof(DNP3LinkHeader))) {
1111 DNP3HandleUserDataRequest(f, dnp3, input, frame_len);
1116 input_len -= frame_len;
1117 processed += frame_len;
1143 const uint8_t *input = StreamSliceGetData(&stream_slice);
1144 uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1146 if (input_len == 0) {
1151 if (!DNP3BufferAdd(buffer, input, input_len)) {
1154 processed = DNP3HandleRequestLinkLayer(
1156 if (processed < 0) {
1159 buffer->
offset += processed;
1160 DNP3BufferTrim(buffer);
1163 processed = DNP3HandleRequestLinkLayer(f, dnp3, input, input_len);
1164 if (processed < 0) {
1165 SCLogDebug(
"Failed to process request link layer.");
1170 input_len -= processed;
1174 if (!DNP3BufferAdd(buffer, input, input_len)) {
1184 DNP3BufferReset(buffer);
1194 static int DNP3HandleResponseLinkLayer(
1195 Flow *f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
1198 uint32_t processed = 0;
1203 if (input_len <
sizeof(DNP3LinkHeader)) {
1207 DNP3LinkHeader *header = (DNP3LinkHeader *)input;
1209 if (!DNP3CheckStartBytes(header)) {
1213 if (!DNP3CheckLinkHeaderCRC(header)) {
1219 uint16_t frame_len = DNP3CalculateLinkLength(header->len);
1220 if (frame_len == 0) {
1224 if (input_len < frame_len) {
1230 if (!DNP3IsUserData(header)) {
1236 if (!DNP3HasUserData(header, STREAM_TOCLIENT)) {
1241 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
1242 frame_len -
sizeof(DNP3LinkHeader))) {
1247 DNP3HandleUserDataResponse(f, dnp3, input, frame_len);
1252 input_len -= frame_len;
1253 processed += frame_len;
1281 const uint8_t *input = StreamSliceGetData(&stream_slice);
1282 uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1285 if (!DNP3BufferAdd(buffer, input, input_len)) {
1288 processed = DNP3HandleResponseLinkLayer(
1290 if (processed < 0) {
1293 buffer->
offset += processed;
1294 DNP3BufferTrim(buffer);
1299 if (DNP3ContainsBanner(input, input_len)) {
1303 processed = DNP3HandleResponseLinkLayer(f, dnp3, input, input_len);
1304 if (processed < 0) {
1308 input_len -= processed;
1312 if (!DNP3BufferAdd(buffer, input, input_len)) {
1324 DNP3BufferReset(buffer);
1328 static void *DNP3GetTx(
void *alstate, uint64_t tx_id)
1333 uint64_t tx_num = tx_id + 1;
1340 if (tx_num != tx->
tx_num) {
1349 static uint64_t DNP3GetTxCnt(
void *state)
1352 uint64_t count = ((uint64_t)((
DNP3State *)state)->transaction_max);
1359 static void DNP3TxFreeObjectList(DNP3ObjectList *objects)
1365 DNP3ObjectFree(
object);
1376 if (tx->
buffer != NULL) {
1382 DNP3TxFreeObjectList(&tx->
objects);
1394 static void DNP3StateTxFree(
void *state, uint64_t tx_id)
1399 uint64_t tx_num = tx_id + 1;
1403 if (tx->
tx_num != tx_num) {
1407 if (tx == dnp3->
curr) {
1436 static void DNP3StateFree(
void *state)
1441 if (state != NULL) {
1442 while ((tx =
TAILQ_FIRST(&dnp3->tx_list)) != NULL) {
1460 static int DNP3GetAlstateProgress(
void *tx, uint8_t direction)
1468 SCLogDebug(
"flooded: returning tx as done.");
1481 static int DNP3StateGetEventInfo(
1494 static int DNP3StateGetEventInfoById(
1498 if (*event_name == NULL) {
1500 "the DNP3 enum event map table.",
1529 switch (prefix_code) {
1547 if (state->
un.
ptr == NULL) {
1553 while (tx_ptr->
tx_num < min_tx_id + 1) {
1559 if (tx_ptr->
tx_num >= max_tx_id + 1) {
1565 .tx_id = tx_ptr->
tx_num - 1,
1566 .has_next = (state->
un.
ptr != NULL),
1581 const char *proto_name =
"dnp3";
1588 sizeof(DNP3LinkHeader), STREAM_TOSERVER, DNP3ProbingParser, DNP3ProbingParser);
1592 0,
sizeof(DNP3LinkHeader), DNP3ProbingParser, DNP3ProbingParser)) {
1598 SCLogConfig(
"Protocol detection and parser disabled for DNP3.");
1611 DNP3StateAlloc, DNP3StateFree);
1620 DNP3GetAlstateProgress);
1624 DNP3StateGetEventInfo);
1626 DNP3StateGetEventInfoById);
1634 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-tx", &value)) {
1635 dnp3_max_tx = (uint64_t)value;
1639 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-points", &value)) {
1641 max_points = (uint64_t)value;
1646 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-objects", &value)) {
1648 dnp3_max_objects = (uint64_t)value;
1653 "Protocol detection still on.", proto_name);
1672 static void DNP3FixCrc(uint8_t *data, uint32_t
len)
1674 uint32_t block_size;
1682 uint16_t
crc = DNP3ComputeCRC(data, block_size);
1683 data[block_size + 1] = (
crc >> 8) & 0xff;
1684 data[block_size] =
crc & 0xff;
1693 static int DNP3ParserTestCheckCRC(
void)
1695 uint8_t request[] = {
1697 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
1704 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
1705 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
1709 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1713 FAIL_IF(!DNP3CheckCRC(request,
sizeof(DNP3LinkHeader)));
1716 FAIL_IF(!DNP3CheckCRC(request +
sizeof(DNP3LinkHeader),
1719 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1722 FAIL_IF(DNP3CheckCRC(request,
sizeof(DNP3LinkHeader)));
1726 request[
sizeof(DNP3LinkHeader) + 3]++;
1727 FAIL_IF(DNP3CheckCRC(request +
sizeof(DNP3LinkHeader),
1737 static int DNP3CheckUserDataCRCsTest(
void)
1740 uint8_t data_valid[] = {
1741 0xff, 0xc9, 0x05, 0x0c,
1742 0x01, 0x28, 0x01, 0x00,
1743 0x00, 0x00, 0x01, 0x01,
1744 0x01, 0x00, 0x00, 0x00,
1747 0xff, 0xc9, 0x05, 0x0c,
1748 0x01, 0x28, 0x01, 0x00,
1749 0x00, 0x00, 0x01, 0x01,
1750 0x01, 0x00, 0x00, 0x00,
1753 0xff, 0xc9, 0x05, 0x0c,
1754 0x01, 0x28, 0x01, 0x00,
1755 0x00, 0x00, 0x01, 0x01,
1756 0x01, 0x00, 0x00, 0x00,
1759 0x00, 0x00, 0x00, 0x00,
1763 FAIL_IF(!DNP3CheckUserDataCRCs(data_valid,
sizeof(data_valid)));
1765 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1767 uint8_t data_invalid[] = {
1768 0xff, 0xc9, 0x05, 0x0c,
1769 0x01, 0x28, 0x01, 0x00,
1770 0x00, 0x00, 0x01, 0x01,
1771 0x01, 0x00, 0x00, 0x00,
1774 0xff, 0xc9, 0x05, 0x0c,
1775 0x01, 0x28, 0x01, 0x00,
1776 0x00, 0x00, 0x01, 0x01,
1777 0x01, 0x00, 0x00, 0x00,
1780 0xff, 0xc9, 0x05, 0x0c,
1781 0x01, 0x28, 0x01, 0x00,
1782 0x00, 0x00, 0x01, 0x01,
1783 0x01, 0x00, 0x00, 0x00,
1786 0x00, 0x00, 0x00, 0x00,
1790 FAIL_IF(DNP3CheckUserDataCRCs(data_invalid,
sizeof(data_invalid)));
1793 uint8_t one_byte_nocrc[] = { 0x01 };
1794 FAIL_IF(DNP3CheckUserDataCRCs(one_byte_nocrc,
sizeof(one_byte_nocrc)));
1797 uint8_t two_byte_nocrc[] = { 0x01, 0x02 };
1798 FAIL_IF(DNP3CheckUserDataCRCs(two_byte_nocrc,
sizeof(two_byte_nocrc)));
1802 uint8_t three_bytes_good_crc[] = { 0x00, 0x00, 0x00 };
1803 *(uint16_t *)(three_bytes_good_crc + 1) = DNP3ComputeCRC(
1804 three_bytes_good_crc, 1);
1805 FAIL_IF(!DNP3CheckUserDataCRCs(three_bytes_good_crc,
1806 sizeof(three_bytes_good_crc)));
1818 static int DNP3CalculateLinkLengthTest(
void)
1821 FAIL_IF(DNP3CalculateLinkLength(0) != 0);
1822 FAIL_IF(DNP3CalculateLinkLength(1) != 0);
1823 FAIL_IF(DNP3CalculateLinkLength(2) != 0);
1824 FAIL_IF(DNP3CalculateLinkLength(3) != 0);
1825 FAIL_IF(DNP3CalculateLinkLength(4) != 0);
1828 FAIL_IF(DNP3CalculateLinkLength(5) != 10);
1831 FAIL_IF(DNP3CalculateLinkLength(21) != 28);
1834 FAIL_IF(DNP3CalculateLinkLength(37) != 46);
1838 FAIL_IF(DNP3CalculateLinkLength(38) != 49);
1841 FAIL_IF(DNP3CalculateLinkLength(255) != 292);
1850 static int DNP3CalculateTransportLengthWithoutCRCsTest(
void)
1852 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(0) != -1);
1853 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(1) != -1);
1854 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(2) != 0);
1855 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(3) != 1);
1856 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(16) != 14);
1857 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(17) != 15);
1858 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(18) != 16);
1861 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(19) != -1);
1865 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(20) != 16);
1867 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(21) != 17);
1875 static int DNP3ParserCheckLinkHeaderCRC(
void)
1878 uint8_t request[] = {
1880 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
1887 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
1888 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
1889 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1892 DNP3LinkHeader *header = (DNP3LinkHeader *)request;
1893 FAIL_IF(!DNP3CheckLinkHeaderCRC(header));
1895 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1898 FAIL_IF(DNP3CheckLinkHeaderCRC(header));
1907 static int DNP3ReassembleApplicationLayerTest01(
void)
1909 uint16_t reassembled_len = 0;
1910 uint8_t *output = NULL;
1912 uint8_t payload[] = {
1914 0xff, 0xc9, 0x05, 0x0c,
1915 0x01, 0x28, 0x01, 0x00,
1916 0x00, 0x00, 0x01, 0x01,
1917 0x01, 0x00, 0x00, 0x00,
1920 0xff, 0xc9, 0x05, 0x0c,
1921 0x01, 0x28, 0x01, 0x00,
1922 0x00, 0x00, 0x01, 0x01,
1923 0x01, 0x00, 0x00, 0x00,
1926 0xff, 0xc9, 0x05, 0x0c,
1927 0x01, 0x28, 0x01, 0x00,
1928 0x00, 0x00, 0x01, 0x01,
1929 0x01, 0x00, 0x00, 0x00,
1932 0x00, 0x00, 0x00, 0x00,
1937 uint8_t expected[] = {
1939 0x01, 0x28, 0x01, 0x00,
1940 0x00, 0x00, 0x01, 0x01,
1941 0x01, 0x00, 0x00, 0x00,
1943 0xff, 0xc9, 0x05, 0x0c,
1944 0x01, 0x28, 0x01, 0x00,
1945 0x00, 0x00, 0x01, 0x01,
1946 0x01, 0x00, 0x00, 0x00,
1948 0xff, 0xc9, 0x05, 0x0c,
1949 0x01, 0x28, 0x01, 0x00,
1950 0x00, 0x00, 0x01, 0x01,
1951 0x01, 0x00, 0x00, 0x00,
1953 0x00, 0x00, 0x00, 0x00,
1959 FAIL_IF(!DNP3ReassembleApplicationLayer(payload,
1960 sizeof(payload), &output, &reassembled_len));
1962 FAIL_IF(reassembled_len !=
sizeof(expected));
1963 FAIL_IF(memcmp(expected, output, reassembled_len));
1967 reassembled_len = 0;
1969 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 1, &output,
1972 FAIL_IF(reassembled_len != 0);
1975 reassembled_len = 0;
1977 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 2, &output,
1980 FAIL_IF(reassembled_len != 0);
1984 reassembled_len = 0;
1986 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 3, &output,
1989 FAIL_IF(reassembled_len != 0);
1992 reassembled_len = 0;
1994 FAIL_IF(!DNP3ReassembleApplicationLayer(payload, 4, &output,
1997 FAIL_IF(reassembled_len != 1);
2000 uint8_t short_payload1[] = {
2002 0xff, 0xc9, 0x05, 0x0c,
2003 0x01, 0x28, 0x01, 0x00,
2004 0x00, 0x00, 0x01, 0x01,
2005 0x01, 0x00, 0x00, 0x00,
2008 0xff, 0xc9, 0x05, 0x0c,
2009 0x01, 0x28, 0x01, 0x00,
2010 0x00, 0x00, 0x01, 0x01,
2011 0x01, 0x00, 0x00, 0x00,
2014 0xff, 0xc9, 0x05, 0x0c,
2015 0x01, 0x28, 0x01, 0x00,
2016 0x00, 0x00, 0x01, 0x01,
2017 0x01, 0x00, 0x00, 0x00,
2022 reassembled_len = 0;
2023 FAIL_IF(DNP3ReassembleApplicationLayer(short_payload1,
2024 sizeof(short_payload1), &output, &reassembled_len));
2027 uint8_t short_payload2[] = {
2029 0xff, 0xc9, 0x05, 0x0c,
2030 0x01, 0x28, 0x01, 0x00,
2031 0x00, 0x00, 0x01, 0x01,
2032 0x01, 0x00, 0x00, 0x00,
2035 0xff, 0xc9, 0x05, 0x0c,
2036 0x01, 0x28, 0x01, 0x00,
2037 0x00, 0x00, 0x01, 0x01,
2038 0x01, 0x00, 0x00, 0x00,
2041 0xff, 0xc9, 0x05, 0x0c,
2042 0x01, 0x28, 0x01, 0x00,
2043 0x00, 0x00, 0x01, 0x01,
2044 0x01, 0x00, 0x00, 0x00,
2049 reassembled_len = 0;
2050 FAIL_IF(DNP3ReassembleApplicationLayer(short_payload2,
2051 sizeof(short_payload2), &output, &reassembled_len));
2061 static int DNP3ProbingParserTest(
void)
2064 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00,
2070 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt,
sizeof(pkt), &rdir) !=
ALPROTO_DNP3);
2073 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt,
sizeof(DNP3LinkHeader) - 1, &rdir) !=
ALPROTO_UNKNOWN);
2087 char mybanner[] =
"Welcome to DNP3 SCADA.";
2088 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, (uint8_t *)mybanner,
sizeof(mybanner) - 1,
2090 FAIL_IF(rdir != STREAM_TOCLIENT);
2098 static int DNP3ParserTestRequestResponse(
void)
2102 uint8_t request[] = {
2104 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2111 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2112 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2113 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2116 uint8_t response[] = {
2118 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
2125 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
2126 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a,
2127 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2135 memset(&flow, 0,
sizeof(flow));
2136 memset(&ssn, 0,
sizeof(ssn));
2139 flow.
proto = IPPROTO_TCP;
2146 STREAM_TOSERVER, request,
sizeof(request)));
2162 STREAM_TOCLIENT, response,
sizeof(response)));
2181 static int DNP3ParserTestUnsolicitedResponseConfirm(
void)
2186 uint8_t response[] = {
2187 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2188 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02,
2189 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8,
2190 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9
2194 uint8_t confirm[] = {
2195 0x05, 0x64, 0x08, 0xc4, 0x02, 0x00,
2196 0x01, 0x00, 0xd3, 0xb7, 0xc0, 0xda, 0x00, 0x6a,
2204 memset(&flow, 0,
sizeof(flow));
2205 memset(&ssn, 0,
sizeof(ssn));
2208 flow.
proto = IPPROTO_TCP;
2215 STREAM_TOCLIENT, response,
sizeof(response)));
2230 STREAM_TOSERVER, confirm,
sizeof(confirm)));
2251 static int DNP3ParserTestFlooded(
void)
2255 uint8_t request[] = {
2257 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2264 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2265 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2266 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2273 memset(&flow, 0,
sizeof(flow));
2274 memset(&ssn, 0,
sizeof(ssn));
2277 flow.
proto = IPPROTO_TCP;
2284 STREAM_TOSERVER, request,
sizeof(request)));
2298 FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER));
2300 for (uint64_t i = 0; i < dnp3_max_tx - 1; i++) {
2303 STREAM_TOSERVER, request,
sizeof(request)));
2307 FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER));
2312 STREAM_TOSERVER, request,
sizeof(request)));
2317 FAIL_IF(!DNP3GetAlstateProgress(tx, 0));
2332 static int DNP3ParserTestPartialFrame(
void)
2338 uint8_t request_partial1[] = {
2340 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2347 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2350 uint8_t request_partial2[] = {
2352 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2353 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2356 uint8_t response_partial1[] = {
2358 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
2365 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
2368 uint8_t response_partial2[] = {
2369 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a,
2370 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2378 memset(&flow, 0,
sizeof(flow));
2379 memset(&ssn, 0,
sizeof(ssn));
2381 flow.
proto = IPPROTO_TCP;
2389 STREAM_TOSERVER, request_partial1,
sizeof(request_partial1));
2399 sizeof(request_partial1)));
2403 FAIL_IF(DNP3GetTx(state, 0) != NULL);
2408 STREAM_TOSERVER, request_partial2,
sizeof(request_partial2));
2418 tx = DNP3GetTx(state, 0);
2429 STREAM_TOCLIENT, response_partial1,
sizeof(response_partial1));
2434 tx = DNP3GetTx(state, 1);
2440 STREAM_TOCLIENT, response_partial2,
sizeof(response_partial2));
2449 tx = DNP3GetTx(state, 1);
2463 static int DNP3ParserTestMultiFrame(
void)
2468 uint8_t unsol_response1[] = {
2469 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2470 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02,
2471 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8,
2472 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9,
2476 uint8_t unsol_response2[] = {
2477 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2478 0x89, 0xe5, 0xc5, 0xfb, 0x82, 0x00, 0x00, 0x02,
2479 0x02, 0x17, 0x01, 0x0c, 0x01, 0xd8, 0x75, 0xd8,
2480 0x32, 0x4c, 0xc9, 0x3c, 0x01, 0xa1, 0xc9,
2483 uint8_t combined[
sizeof(unsol_response1) +
sizeof(unsol_response2)];
2484 memcpy(combined, unsol_response1,
sizeof(unsol_response1));
2485 memcpy(combined +
sizeof(unsol_response1), unsol_response2,
2486 sizeof(unsol_response2));
2493 memset(&flow, 0,
sizeof(flow));
2494 memset(&ssn, 0,
sizeof(ssn));
2496 flow.
proto = IPPROTO_TCP;
2502 STREAM_TOCLIENT, combined,
sizeof(combined));
2524 static int DNP3ParserTestParsePDU01(
void)
2528 const uint8_t pkt[] = {
2530 0x0b, 0xc4, 0x17, 0x00, 0xef, 0xff, 0xc4, 0x8f,
2531 0xe1, 0xc8, 0x01, 0x01, 0x00, 0x06, 0x77, 0x6e
2535 int pdus = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2545 DNP3StateFree(dnp3state);
2552 static int DNP3ParserDecodeG70V3Test(
void)
2554 const uint8_t pkt[] = {
2556 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, 0xc7, 0xee,
2557 0xc7, 0xc9, 0x1b, 0x46, 0x03, 0x5b, 0x01, 0x55,
2558 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
2559 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2561 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43,
2562 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44,
2563 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69,
2564 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
2565 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c,
2566 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65,
2567 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d,
2568 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65,
2569 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c,
2575 int bytes = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2576 FAIL_IF(bytes !=
sizeof(pkt));
2595 "C:/temp/DNPDeviceConfiguration written to Remote Device.xml") == 0);
2596 DNP3StateFree(dnp3state);
2603 static int DNP3ParserUnknownEventAlertTest(
void)
2607 0x05, 0x64, 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00,
2617 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
2618 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2620 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43,
2621 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44,
2622 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69,
2623 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
2624 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c,
2625 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65,
2626 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d,
2627 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65,
2628 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c,
2632 DNP3FixCrc(pkt + 10,
sizeof(pkt) - 10);
2636 int bytes = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2637 FAIL_IF(bytes !=
sizeof(pkt));
2639 DNP3StateFree(dnp3state);
2646 static int DNP3ParserIncorrectUserData(
void)
2648 uint8_t packet_bytes[] = {
2649 0x05, 0x64, 0x08, 0xc4, 0x03, 0x00, 0x04, 0x00,
2650 0xbf, 0xe9, 0xc1, 0xc1, 0x82, 0xc5, 0xee
2656 memset(&flow, 0,
sizeof(flow));
2657 memset(&ssn, 0,
sizeof(ssn));
2659 flow.
proto = IPPROTO_TCP;
2664 STREAM_TOCLIENT, packet_bytes,
sizeof(packet_bytes));
2679 UtRegisterTest(
"DNP3ParserTestCheckCRC", DNP3ParserTestCheckCRC);
2681 DNP3ParserCheckLinkHeaderCRC);
2682 UtRegisterTest(
"DNP3CheckUserDataCRCsTest", DNP3CheckUserDataCRCsTest);
2683 UtRegisterTest(
"DNP3CalculateLinkLengthTest", DNP3CalculateLinkLengthTest);
2685 DNP3CalculateTransportLengthWithoutCRCsTest);
2687 DNP3ReassembleApplicationLayerTest01);
2690 DNP3ParserTestRequestResponse);
2692 DNP3ParserTestUnsolicitedResponseConfirm);
2693 UtRegisterTest(
"DNP3ParserTestPartialFrame", DNP3ParserTestPartialFrame);
2694 UtRegisterTest(
"DNP3ParserTestMultiFrame", DNP3ParserTestMultiFrame);
2696 UtRegisterTest(
"DNP3ParserTestParsePDU01", DNP3ParserTestParsePDU01);
2697 UtRegisterTest(
"DNP3ParserDecodeG70V3Test", DNP3ParserDecodeG70V3Test);
2699 DNP3ParserUnknownEventAlertTest);
2700 UtRegisterTest(
"DNP3ParserIncorrectUserData", DNP3ParserIncorrectUserData);