1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18
19 // cip_parsing.cc author RA/Cisco
20
21 /* Description: Data parsing for EtherNet/IP and CIP formats.
22 Note: No pointer parameters to these functions can be passed as null. */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "cip_parsing.h"
29
30 #include "framework/data_bus.h"
31 #include "utils/endian.h"
32
33 #include "cip.h"
34 #include "cip_session.h" // For CIP connection tracking
35
36 using namespace snort;
37
38 /// EtherNet/IP Parsing Constants
39
40 // Common Packet Format Item IDs.
41 enum CpfItemId
42 {
43 CPF_NULL_ADDRESS_ITEM_ID = 0x0000,
44 CPF_LIST_IDENTITY_ITEM_ID = 0x000C,
45 CPF_CONNECTED_ADDRESS_ITEM_ID = 0x00A1,
46 CPF_CONNECTED_DATA_ITEM_ID = 0x00B1,
47 CPF_UNCONNECTED_DATA_ITEM_ID = 0x00B2,
48 CPF_LIST_SERVICES_ITEM_ID = 0x0100,
49 CPF_SOCKADDR_INFO_OT_ITEM_ID = 0x8000,
50 CPF_SOCKADDR_INFO_TO_ITEM_ID = 0x8001,
51 CPF_SEQUENCED_ADDRESS_ITEM_ID = 0x8002
52 };
53
54 #define CPF_ADDRESS_ITEM_SLOT 0
55 #define CPF_DATA_ITEM_SLOT 1
56 #define CPF_LIST_REPLY_SLOT 0
57
58 // Some ENIP command ranges are reserved for future range.
59 #define ENIP_COMMAND_RESERVED1_START 0x0006
60 #define ENIP_COMMAND_RESERVED1_END 0x0062
61 #define ENIP_COMMAND_RESERVED2_START 0x00C8
62
63 // Some CPF Item IDs are reserved for future range.
64 #define ENIP_CPF_ITEM_RESERVED1_START 0x0086
65 #define ENIP_CPF_ITEM_RESERVED1_END 0x0090
66 #define ENIP_CPF_ITEM_RESERVED2_START 0x0092
67 #define ENIP_CPF_ITEM_RESERVED2_END 0x00A0
68 #define ENIP_CPF_ITEM_RESERVED3_START 0x00A5
69 #define ENIP_CPF_ITEM_RESERVED3_END 0x00B0
70 #define ENIP_CPF_ITEM_RESERVED4_START 0x00B3
71 #define ENIP_CPF_ITEM_RESERVED4_END 0x00FF
72 #define ENIP_CPF_ITEM_RESERVED5_START 0x0110
73 #define ENIP_CPF_ITEM_RESERVED5_END 0x7FFF
74 #define ENIP_CPF_ITEM_RESERVED6_START 0x8004
75
76 #define REGISTER_SESSION_DATA_SIZE 4
77
78 /// CIP Layer Parsing Constants
79 const size_t CIP_PATH_SEGMENT_MIN_SIZE_BYTES = sizeof(uint16_t);
80
81 // Typical payload size offset in CIP segment
82 #define CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET 1
83
84 // Offset to Segment Type/Format byte
85 #define CIP_PATH_TYPE_OFFSET 0
86
87 // Logical segment format mask and types.
88 #define CIP_PATH_LOGICAL_FORMAT_MASK 0x03
89
90 enum LogicalValueType
91 {
92 CIP_PATH_LOGICAL_8_BIT = 0x00,
93 CIP_PATH_LOGICAL_16_BIT = 0x01,
94 CIP_PATH_LOGICAL_32_BIT = 0x02
95 };
96
97 // Logical segment types
98 enum LogicalSegmentType
99 {
100 CIP_PATH_LOGICAL_CLASS = 0x00,
101 CIP_PATH_LOGICAL_INSTANCE = 0x04,
102 CIP_PATH_LOGICAL_MEMBER = 0x08,
103 CIP_PATH_LOGICAL_CONN_POINT = 0x0c,
104 CIP_PATH_LOGICAL_ATTRIBUTE = 0x10,
105 CIP_PATH_LOGICAL_SPECIAL = 0x14,
106 CIP_PATH_LOGICAL_SERVICE_ID = 0x18,
107 CIP_PATH_LOGICAL_EXTENDED = 0x1C
108 };
109
110 enum SegmentType
111 {
112 CIP_PATH_SEGMENT_PORT = 0x00,
113 CIP_PATH_SEGMENT_LOGICAL = 0x20,
114 CIP_PATH_SEGMENT_NETWORK = 0x40,
115 CIP_PATH_SEGMENT_SYMBOLIC = 0x60,
116 CIP_PATH_SEGMENT_DATA = 0x80
117 };
118
119 enum ExtendedStringType
120 {
121 EXTENDED_STRING_DOUBLE = 0x20,
122 EXTENDED_STRING_TRIPLE = 0x40,
123 EXTENDED_STRING_NUMERIC = 0xC0
124 };
125
126 #define MESSAGE_ROUTER_RESPONSE_MASK 0x80
127
128 #define CIP_STATUS_MIN_SIZE 2
129
130 /// Prototypes
131 static bool parse_logical_address_format(const uint8_t* data,
132 size_t data_length,
133 bool logical_extended,
134 CipSegment* segment);
135
136 static bool parse_message_router_request(const uint8_t* data,
137 size_t data_length,
138 CipRequest* cip_request,
139 CipGlobalSessionData* global_data);
140
141 /// Functions
enip_command_valid(uint16_t command)142 static bool enip_command_valid(uint16_t command)
143 {
144 if ((ENIP_COMMAND_RESERVED1_START <= command && command <= ENIP_COMMAND_RESERVED1_END)
145 || (ENIP_COMMAND_RESERVED2_START <= command))
146 {
147 return false;
148 }
149
150 return true;
151 }
152
enip_command_tcp_only(uint16_t command)153 static bool enip_command_tcp_only(uint16_t command)
154 {
155 // Allocated command codes.
156 if (command == ENIP_COMMAND_NOP
157 || command == ENIP_COMMAND_REGISTER_SESSION
158 || command == ENIP_COMMAND_UNREGISTER_SESSION
159 || command == ENIP_COMMAND_SEND_RR_DATA
160 || command == ENIP_COMMAND_SEND_UNIT_DATA)
161 {
162 return true;
163 }
164
165 return false;
166 }
167
parse_enip_header(const uint8_t * data,size_t data_length,EnipSessionData * enip_session)168 static bool parse_enip_header(const uint8_t* data,
169 size_t data_length,
170 EnipSessionData* enip_session)
171 {
172 EnipHeader* enip_header = &enip_session->enip_header;
173
174 if (data_length < ENIP_HEADER_SIZE)
175 {
176 return false;
177 }
178
179 #define ENIP_HEADER_OFFSET_COMMAND 0
180 #define ENIP_HEADER_OFFSET_LENGTH 2
181 #define ENIP_HEADER_OFFSET_HANDLE 4
182 #define ENIP_HEADER_OFFSET_STATUS 8
183 #define ENIP_HEADER_OFFSET_CONTEXT 12
184 #define ENIP_HEADER_OFFSET_OPTIONS 20
185
186 enip_header->command = LETOHS(&data[ENIP_HEADER_OFFSET_COMMAND]);
187 enip_header->length = LETOHS(&data[ENIP_HEADER_OFFSET_LENGTH]);
188 enip_header->session_handle = LETOHL(&data[ENIP_HEADER_OFFSET_HANDLE]);
189 enip_header->status = LETOHL(&data[ENIP_HEADER_OFFSET_STATUS]);
190 memcpy(&enip_header->sender_context,
191 &data[ENIP_HEADER_OFFSET_CONTEXT],
192 sizeof(enip_header->sender_context));
193 enip_header->options = LETOHL(&data[ENIP_HEADER_OFFSET_OPTIONS]);
194
195 if (!enip_command_valid(enip_header->command))
196 {
197 enip_session->enip_invalid_nonfatal |= ENIP_INVALID_COMMAND;
198 }
199
200 return true;
201 }
202
cpf_item_id_valid(uint16_t item_id)203 static bool cpf_item_id_valid(uint16_t item_id)
204 {
205 if ((ENIP_CPF_ITEM_RESERVED1_START <= item_id && item_id <= ENIP_CPF_ITEM_RESERVED1_END)
206 || (ENIP_CPF_ITEM_RESERVED2_START <= item_id && item_id <= ENIP_CPF_ITEM_RESERVED2_END)
207 || (ENIP_CPF_ITEM_RESERVED3_START <= item_id && item_id <= ENIP_CPF_ITEM_RESERVED3_END)
208 || (ENIP_CPF_ITEM_RESERVED4_START <= item_id && item_id <= ENIP_CPF_ITEM_RESERVED4_END)
209 || (ENIP_CPF_ITEM_RESERVED5_START <= item_id && item_id <= ENIP_CPF_ITEM_RESERVED5_END)
210 || (ENIP_CPF_ITEM_RESERVED6_START <= item_id))
211 {
212 return false;
213 }
214
215 return true;
216 }
217
cpf_item_length_valid(uint16_t item_id,size_t item_length)218 static bool cpf_item_length_valid(uint16_t item_id, size_t item_length)
219 {
220 #define NULL_ADDRESS_ITEM_DATA_SIZE 0
221 #define CONNECTED_ADDRESS_ITEM_DATA_SIZE 4
222 #define SOCKADDR_INFO_ITEM_DATA_SIZE 16
223 #define SEQUENCED_ADDRESS_ITEM_DATA_SIZE 8
224
225 // Minimum data size for Connected and Unconnected Data Items when used with
226 // CIP Class 3 / Explicit data.
227 #define MIN_CPF_CIP_DATA_SIZE 2
228
229 bool valid = true;
230
231 switch (item_id)
232 {
233 case CPF_NULL_ADDRESS_ITEM_ID:
234 if (item_length != NULL_ADDRESS_ITEM_DATA_SIZE)
235 {
236 valid = false;
237 }
238 break;
239 case CPF_CONNECTED_ADDRESS_ITEM_ID:
240 if (item_length != CONNECTED_ADDRESS_ITEM_DATA_SIZE)
241 {
242 valid = false;
243 }
244 break;
245 case CPF_CONNECTED_DATA_ITEM_ID:
246 if (item_length < MIN_CPF_CIP_DATA_SIZE)
247 {
248 valid = false;
249 }
250 break;
251 case CPF_UNCONNECTED_DATA_ITEM_ID:
252 if (item_length < MIN_CPF_CIP_DATA_SIZE)
253 {
254 valid = false;
255 }
256 break;
257 case CPF_SOCKADDR_INFO_OT_ITEM_ID:
258 case CPF_SOCKADDR_INFO_TO_ITEM_ID:
259 if (item_length != SOCKADDR_INFO_ITEM_DATA_SIZE)
260 {
261 valid = false;
262 }
263 break;
264 case CPF_SEQUENCED_ADDRESS_ITEM_ID:
265 if (item_length != SEQUENCED_ADDRESS_ITEM_DATA_SIZE)
266 {
267 valid = false;
268 }
269 break;
270 case CPF_LIST_IDENTITY_ITEM_ID:
271 case CPF_LIST_SERVICES_ITEM_ID:
272 default:
273 // No length checks for anything else.
274 break;
275 }
276
277 return valid;
278 }
279
enip_command_cpf_valid(uint16_t command,const EnipCpf * enip_cpf)280 static bool enip_command_cpf_valid(uint16_t command, const EnipCpf* enip_cpf)
281 {
282 #define MIN_CPF_ITEMS_CIP_MESSAGE 2
283 #define MIN_CPF_ITEMS_LIST_REPLY 1
284
285 bool valid = true;
286
287 switch (command)
288 {
289 case ENIP_COMMAND_SEND_RR_DATA:
290 if (enip_cpf->item_count < MIN_CPF_ITEMS_CIP_MESSAGE
291 || enip_cpf->item_list[CPF_ADDRESS_ITEM_SLOT].type != CPF_NULL_ADDRESS_ITEM_ID
292 || enip_cpf->item_list[CPF_DATA_ITEM_SLOT].type != CPF_UNCONNECTED_DATA_ITEM_ID)
293 {
294 valid = false;
295 }
296 break;
297 case ENIP_COMMAND_SEND_UNIT_DATA:
298 if (enip_cpf->item_count != MIN_CPF_ITEMS_CIP_MESSAGE
299 || enip_cpf->item_list[CPF_ADDRESS_ITEM_SLOT].type != CPF_CONNECTED_ADDRESS_ITEM_ID
300 || enip_cpf->item_list[CPF_DATA_ITEM_SLOT].type != CPF_CONNECTED_DATA_ITEM_ID)
301 {
302 valid = false;
303 }
304 break;
305 case ENIP_COMMAND_LIST_SERVICES:
306 // Used in Reply only.
307 if (enip_cpf->item_count < MIN_CPF_ITEMS_LIST_REPLY
308 || enip_cpf->item_list[CPF_LIST_REPLY_SLOT].type != CPF_LIST_SERVICES_ITEM_ID)
309 {
310 valid = false;
311 }
312 break;
313 case ENIP_COMMAND_LIST_IDENTITY:
314 // Used in Reply only.
315 if (enip_cpf->item_count < MIN_CPF_ITEMS_LIST_REPLY
316 || enip_cpf->item_list[CPF_LIST_REPLY_SLOT].type != CPF_LIST_IDENTITY_ITEM_ID)
317 {
318 valid = false;
319 }
320 break;
321 default:
322 // Ignore commands without defined CPF items.
323 break;
324 }
325
326 return valid;
327 }
328
329 // Returns the CIP message type based on packet and session data. The data must already:
330 // 1. Be ENIP_COMMAND_SEND_UNIT_DATA or ENIP_COMMAND_SEND_RR_DATA
331 // 2. Have the required CPF items for that ENIP command.
332 // This also saves connection related data for the given packet and updates connection timestamps.
get_cip_message_type(CipCurrentData * current_data,CipGlobalSessionData * global_data)333 static CipMessageType get_cip_message_type(CipCurrentData* current_data,
334 CipGlobalSessionData* global_data)
335 {
336 CipMessageType cip_message_type = CipMessageTypeUnknown;
337
338 if (current_data->enip_data.enip_header.command == ENIP_COMMAND_SEND_RR_DATA)
339 {
340 cip_message_type = CipMessageTypeExplicit;
341 }
342 else // ENIP_COMMAND_SEND_UNIT_DATA
343 {
344 const EnipCpf* enip_cpf = ¤t_data->enip_data.enip_cpf;
345
346 if (enip_cpf->item_list[CPF_ADDRESS_ITEM_SLOT].length > 0)
347 {
348 uint32_t connection_id = LETOHL(enip_cpf->item_list[CPF_ADDRESS_ITEM_SLOT].data);
349
350 // Validate connected messages against CIP Connection List.
351 CipConnection* connection = cip_find_connection_by_id(
352 &global_data->connection_list,
353 current_data->direction,
354 connection_id,
355 true);
356 if (connection)
357 {
358 if (current_data->direction == CIP_FROM_CLIENT)
359 {
360 connection->ot_timestamp = global_data->snort_packet->pkth->ts;
361 }
362 else
363 {
364 connection->to_timestamp = global_data->snort_packet->pkth->ts;
365 }
366
367 current_data->enip_data.connection_class_id = connection->class_id;
368
369 if (connection->class_id == MESSAGE_ROUTER_CLASS_ID)
370 {
371 cip_message_type = CipMessageTypeExplicit;
372 }
373 else
374 {
375 cip_message_type = CipMessageTypeImplicit;
376 }
377 }
378 else
379 {
380 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_CONNECTION_ID;
381 cip_message_type = CipMessageTypeUnknown;
382 }
383 }
384 }
385
386 return cip_message_type;
387 }
388
parse_common_packet_format(const uint8_t * data,size_t data_length,EnipCpf * enip_cpf,CipCurrentData * current_data)389 static bool parse_common_packet_format(const uint8_t* data,
390 size_t data_length,
391 EnipCpf* enip_cpf,
392 CipCurrentData* current_data)
393 {
394 // The total item count is always first.
395 #define CPF_ITEM_COUNT_SIZE 2
396 if (data_length < CPF_ITEM_COUNT_SIZE)
397 {
398 return false;
399 }
400
401 #define CPF_OFFSET_ITEM_COUNT 0
402 #define CPF_ITEM_OFFSET_TYPE 0
403 #define CPF_ITEM_OFFSET_LENGTH 2
404 #define CPF_ITEM_OFFSET_DATA 4
405
406 enip_cpf->item_count = LETOHS(&data[CPF_OFFSET_ITEM_COUNT]);
407 data_length -= CPF_ITEM_COUNT_SIZE;
408
409 bool valid = true;
410
411 size_t current_item_offset = CPF_ITEM_COUNT_SIZE;
412
413 int i;
414 for (i = 0; i < enip_cpf->item_count; ++i)
415 {
416 uint16_t item_type;
417 uint16_t item_length;
418 const uint8_t* item_data;
419 /* This contains Type ID and Length. */
420 #define CPF_ITEM_HEADER_SIZE 4
421 if (data_length < CPF_ITEM_HEADER_SIZE)
422 {
423 valid = false;
424 break;
425 }
426
427 item_type = LETOHS(&data[current_item_offset + CPF_ITEM_OFFSET_TYPE]);
428 item_length = LETOHS(&data[current_item_offset + CPF_ITEM_OFFSET_LENGTH]);
429 item_data = nullptr;
430 if (item_length > 0)
431 {
432 item_data = &data[current_item_offset + CPF_ITEM_OFFSET_DATA];
433 }
434
435 data_length -= CPF_ITEM_HEADER_SIZE;
436
437 if (!cpf_item_id_valid(item_type))
438 {
439 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_RESERVED_FUTURE_CPF_TYPE;
440 }
441
442 if (!cpf_item_length_valid(item_type, item_length))
443 {
444 valid = false;
445 break;
446 }
447
448 // Check that there is enough data left for the Item Length.
449 if (data_length < item_length)
450 {
451 valid = false;
452 break;
453 }
454
455 // Validate every CPF item, but only store data for a set amount.
456 if (i < MAX_NUM_CPF_ITEMS)
457 {
458 enip_cpf->item_list[i].type = item_type;
459 enip_cpf->item_list[i].length = item_length;
460 enip_cpf->item_list[i].data = item_data;
461 }
462
463 // Get data for the next item.
464 current_item_offset = current_item_offset + CPF_ITEM_HEADER_SIZE + item_length;
465 data_length -= item_length;
466 }
467
468 if (valid)
469 {
470 current_data->enip_data.required_cpf_items_present
471 = enip_command_cpf_valid(current_data->enip_data.enip_header.command, enip_cpf);
472 if (!current_data->enip_data.required_cpf_items_present)
473 {
474 current_data->enip_data.enip_invalid_nonfatal |=
475 ENIP_INVALID_ENIP_COMMAND_CPF_MISMATCH;
476 }
477 }
478
479 return valid;
480 }
481
482 // If there in an unknown segment type, then just set this segment to include
483 // all of the data left.
set_unknown_segment_type(size_t data_length,CipSegment * segment)484 static void set_unknown_segment_type(size_t data_length,
485 CipSegment* segment)
486 {
487 segment->type = CipSegment_Type_UNKNOWN;
488 segment->size = data_length;
489 }
490
491 // Return the timeout, in milliseconds, based on the priority/time_tick and time-out_ticks fields
492 // that are common to: Unconnected Send, Forward Open, Forward Close.
493 // This requires that enough data is available to read 2 bytes.
get_unconnected_timeout(const uint8_t * data)494 static uint32_t get_unconnected_timeout(const uint8_t* data)
495 {
496 #define UNCONNECTED_OFFSET_PRIORITY_TIME_TICK 0
497 #define UNCONNECTED_OFFSET_TIMEOUT_TICKS 1
498 #define TICK_TIME_MASK 0xF
499
500 uint8_t tick_time = data[UNCONNECTED_OFFSET_PRIORITY_TIME_TICK] & TICK_TIME_MASK;
501 uint8_t timeout_ticks = data[UNCONNECTED_OFFSET_TIMEOUT_TICKS];
502
503 return (1 << tick_time) * timeout_ticks;
504 }
505
506 // Parses RPI and Network Connection Parameters from a Forward Open Request.
507 // Note: Assumes there is enough data to parse the RPI and Network Connection Parameters.
parse_connection_parameters(const uint8_t * data,bool large_forward_open,CipConnectionParameters * connection_parameters)508 static void parse_connection_parameters(const uint8_t* data,
509 bool large_forward_open,
510 CipConnectionParameters* connection_parameters)
511 {
512 #define NULL_CONNECTION_TYPE_MASK 0x6000
513 static const uint32_t LARGE_NULL_CONNECTION_TYPE_MASK = 0x60000000;
514
515 // Offsets to the RPI and Network Connection Parameters data, from the RPI data.
516 #define OFFSET_RPI 0
517 #define OFFSET_NETWORK_PARAMETERS 4
518
519 connection_parameters->rpi = LETOHL_UNALIGNED(&data[OFFSET_RPI]);
520
521 if (!large_forward_open)
522 {
523 uint16_t network_connection_parameters = LETOHS(&data[OFFSET_NETWORK_PARAMETERS]);
524 connection_parameters->network_connection_parameters = network_connection_parameters;
525
526 if ((network_connection_parameters & NULL_CONNECTION_TYPE_MASK) == 0)
527 {
528 connection_parameters->is_null_connection = true;
529 }
530 }
531 else // SERVICE_LARGE_FORWARD_OPEN
532 {
533 uint32_t network_connection_parameters = LETOHL(&data[OFFSET_NETWORK_PARAMETERS]);
534 connection_parameters->network_connection_parameters = network_connection_parameters;
535
536 if ((network_connection_parameters & LARGE_NULL_CONNECTION_TYPE_MASK) == 0)
537 {
538 connection_parameters->is_null_connection = true;
539 }
540 }
541 }
542
543 // Note: Assumes there is enough data for a full Connection Signature.
parse_connection_signature(const uint8_t * data,CipConnectionSignature * connection_signature)544 static void parse_connection_signature(const uint8_t* data,
545 CipConnectionSignature* connection_signature)
546 {
547 #define OFFSET_CONNECTION_SERIAL 0
548 #define OFFSET_VENDOR 2
549 #define OFFSET_ORIGINATOR_SERIAL 4
550
551 connection_signature->connection_serial_number = LETOHS(&data[OFFSET_CONNECTION_SERIAL]);
552 connection_signature->vendor_id = LETOHS(&data[OFFSET_VENDOR]);
553 connection_signature->originator_serial_number = LETOHL(&data[OFFSET_ORIGINATOR_SERIAL]);
554 }
555
parse_segment_electronic_key(const uint8_t * data,size_t data_length,CipSegment * segment)556 static bool parse_segment_electronic_key(const uint8_t* data,
557 size_t data_length,
558 CipSegment* segment)
559 {
560 #define ELECTRONIC_KEY_FORMAT_TABLE 0x04
561 #define ELECTRONIC_KEY_FORMAT_TABLE_SIZE 10
562
563 // Check that there is enough size for the Key Format Table.
564 if (ELECTRONIC_KEY_FORMAT_TABLE_SIZE > data_length)
565 {
566 return false;
567 }
568
569 // Currently, the only supported Key Format is the Key Format Table.
570 #define ELECTRONIC_KEY_OFFSET_FORMAT_TABLE 1
571 if (data[ELECTRONIC_KEY_OFFSET_FORMAT_TABLE] != ELECTRONIC_KEY_FORMAT_TABLE)
572 {
573 return false;
574 }
575
576 segment->type = CipSegment_Type_LOGICAL_ELECTRONIC_KEY;
577 segment->size = ELECTRONIC_KEY_FORMAT_TABLE_SIZE;
578
579 return true;
580 }
581
parse_segment_extended_symbol(const uint8_t * data,size_t data_length,CipSegment * segment)582 static bool parse_segment_extended_symbol(const uint8_t* data,
583 size_t data_length,
584 CipSegment* segment)
585 {
586 size_t symbol_size_bytes;
587 size_t segment_size_bytes;
588 symbol_size_bytes = data[CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET];
589
590 // calculate expected size
591 segment_size_bytes = CIP_PATH_SEGMENT_MIN_SIZE_BYTES + symbol_size_bytes;
592
593 // add padding
594 segment_size_bytes += segment_size_bytes % 2;
595
596 // Exit early, if we know we won't fit.
597 if (segment_size_bytes > data_length)
598 {
599 return false;
600 }
601
602 segment->type = CipSegment_Type_DATA_EXT_SYMBOL;
603 segment->data = &data[CIP_PATH_SEGMENT_MIN_SIZE_BYTES];
604 segment->data_size = symbol_size_bytes;
605 segment->size = segment_size_bytes;
606
607 return true;
608 }
609
parse_segment_logical(const uint8_t * data,size_t data_length,CipSegment * segment)610 static bool parse_segment_logical(const uint8_t* data,
611 size_t data_length,
612 CipSegment* segment)
613 {
614 uint8_t segment_type = data[CIP_PATH_TYPE_OFFSET];
615
616 // parse particular logical type
617 bool valid = true;
618 #define CIP_PATH_LOGICAL_TYPE_MASK 0x1C
619 switch (segment_type & CIP_PATH_LOGICAL_TYPE_MASK)
620 {
621 case CIP_PATH_LOGICAL_CLASS:
622 segment->type = CipSegment_Type_LOGICAL_CLASS;
623 valid = parse_logical_address_format(data, data_length, false, segment);
624 break;
625 case CIP_PATH_LOGICAL_INSTANCE:
626 segment->type = CipSegment_Type_LOGICAL_INSTANCE;
627 valid = parse_logical_address_format(data, data_length, false, segment);
628 break;
629 case CIP_PATH_LOGICAL_MEMBER:
630 segment->type = CipSegment_Type_LOGICAL_MEMBER;
631 valid = parse_logical_address_format(data, data_length, false, segment);
632 break;
633 case CIP_PATH_LOGICAL_CONN_POINT:
634 segment->type = CipSegment_Type_LOGICAL_CONN_POINT;
635 valid = parse_logical_address_format(data, data_length, false, segment);
636 break;
637 case CIP_PATH_LOGICAL_ATTRIBUTE:
638 segment->type = CipSegment_Type_LOGICAL_ATTRIBUTE;
639 valid = parse_logical_address_format(data, data_length, false, segment);
640 break;
641 case CIP_PATH_LOGICAL_EXTENDED:
642 segment->type = CipSegment_Type_LOGICAL_EXTENDED;
643 valid = parse_logical_address_format(data, data_length, true, segment);
644 break;
645 case CIP_PATH_LOGICAL_SPECIAL:
646 {
647 // Logical Segment Electronic Key Logical Format.
648 #define CIP_PATH_SEGMENT_ELECTRONIC_KEY 0x34
649
650 if (segment_type == CIP_PATH_SEGMENT_ELECTRONIC_KEY)
651 {
652 valid = parse_segment_electronic_key(data,
653 data_length,
654 segment);
655 }
656 else
657 {
658 set_unknown_segment_type(data_length, segment);
659 }
660
661 break;
662 }
663 case CIP_PATH_LOGICAL_SERVICE_ID:
664 {
665 #define CIP_PATH_SEGMENT_SERVICE_ID 0x38
666 if (segment_type == CIP_PATH_SEGMENT_SERVICE_ID)
667 {
668 segment->type = CipSegment_Type_LOGICAL_SERVICE_ID;
669 valid = parse_logical_address_format(data, data_length, false, segment);
670 }
671 else
672 {
673 set_unknown_segment_type(data_length, segment);
674 }
675
676 break;
677 }
678 default:
679 // Can't happen.
680 set_unknown_segment_type(data_length, segment);
681 break;
682 }
683
684 return valid;
685 }
686
parse_segment_network(const uint8_t * data,size_t data_length,CipSegment * segment)687 static bool parse_segment_network(const uint8_t* data,
688 size_t data_length,
689 CipSegment* segment)
690 {
691 #define CIP_PATH_NETWORK_FORMAT_MASK 0xF0
692 #define CIP_PATH_NETWORK_ONE_BYTE 0x40
693
694 size_t segment_size_bytes = 0;
695
696 uint8_t segment_type = data[CIP_PATH_TYPE_OFFSET];
697 uint8_t network_segment_type = segment_type & CIP_PATH_NETWORK_FORMAT_MASK;
698 if (network_segment_type == CIP_PATH_NETWORK_ONE_BYTE)
699 {
700 segment_size_bytes = CIP_PATH_SEGMENT_MIN_SIZE_BYTES;
701 }
702 else // Variable length network segment (0x50)
703 {
704 size_t data_size_bytes = data[CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET] * CIP_WORD_TO_BYTES;
705 segment_size_bytes = CIP_PATH_SEGMENT_MIN_SIZE_BYTES + data_size_bytes;
706 if (segment_size_bytes > data_length)
707 {
708 return false;
709 }
710 }
711
712 segment->type = CipSegment_Type_NETWORK;
713 segment->size = segment_size_bytes;
714
715 return true;
716 }
717
parse_segment_port(const uint8_t * data,size_t data_length,CipSegment * segment)718 static bool parse_segment_port(const uint8_t* data,
719 size_t data_length,
720 CipSegment* segment)
721 {
722 uint8_t segment_type = data[CIP_PATH_TYPE_OFFSET];
723
724 // set minimal expected segment size
725 size_t segment_size_bytes = CIP_PATH_SEGMENT_MIN_SIZE_BYTES;
726
727 // port segment extended port threshold
728 #define CIP_PATH_PORT_EXTENDED 0x0F
729
730 // calculate simple port (extended port is also a mask)
731 uint16_t port_number = segment_type & CIP_PATH_PORT_EXTENDED;
732
733 bool is_port_extended = port_number == CIP_PATH_PORT_EXTENDED;
734
735 #define CIP_PATH_PORT_EXTENDED_LINK_ADDRESS_MASK 0x10
736 bool is_long_address = (segment_type & CIP_PATH_PORT_EXTENDED_LINK_ADDRESS_MASK) != 0;
737
738 if (is_long_address)
739 {
740 // add length of address
741 segment_size_bytes += data[CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET];
742
743 // add padding
744 segment_size_bytes += segment_size_bytes % 2;
745 }
746
747 if (is_port_extended)
748 {
749 // add length of extended port
750 segment_size_bytes += sizeof(uint16_t);
751 }
752
753 // Exit early, if we know we won't fit.
754 if (segment_size_bytes > data_length)
755 {
756 return false;
757 }
758
759 if (is_port_extended)
760 {
761 size_t extended_port_offset = CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET;
762
763 if (is_long_address)
764 {
765 extended_port_offset += sizeof(uint8_t);
766 }
767
768 port_number = LETOHS(&data[extended_port_offset]);
769 }
770
771 segment->port_id = port_number;
772
773 if (!is_long_address)
774 {
775 size_t link_address_offset = CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET;
776
777 if (is_port_extended)
778 {
779 link_address_offset += sizeof(uint16_t);
780 }
781
782 segment->type = CipSegment_Type_PORT_LINK_ADDRESS;
783 segment->link_address = data[link_address_offset];
784 }
785 else
786 {
787 size_t link_address_offset = CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET + sizeof(uint8_t);
788
789 if (is_port_extended)
790 {
791 link_address_offset += sizeof(uint16_t);
792 }
793
794 segment->type = CipSegment_Type_PORT_LINK_ADDRESS_EXTENDED;
795 segment->data = &data[link_address_offset];
796 segment->data_size = data[CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET];
797 }
798
799 segment->size = segment_size_bytes;
800
801 return true;
802 }
803
parse_segment_simple_data(const uint8_t * data,size_t data_length,CipSegment * segment)804 static bool parse_segment_simple_data(const uint8_t* data,
805 size_t data_length,
806 CipSegment* segment)
807 {
808 size_t data_size_bytes
809 = data[CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET] * CIP_WORD_TO_BYTES;
810
811 // calculate expected size
812 size_t segment_size_bytes = CIP_PATH_SEGMENT_MIN_SIZE_BYTES + data_size_bytes;
813
814 // Exit early, if we know we won't fit.
815 if (segment_size_bytes > data_length)
816 {
817 return false;
818 }
819
820 segment->type = CipSegment_Type_DATA_SIMPLE;
821 segment->data = &data[CIP_PATH_SEGMENT_MIN_SIZE_BYTES];
822 segment->data_size = data_size_bytes;
823 segment->size = segment_size_bytes;
824
825 return true;
826 }
827
parse_segment_symbolic_extended_string(const uint8_t * data,size_t data_length,CipSegment * segment)828 static bool parse_segment_symbolic_extended_string(const uint8_t* data,
829 size_t data_length,
830 CipSegment* segment)
831 {
832 #define EXTENDED_STRING_SIZE_MASK 0x1F
833 #define EXTENDED_STRING_FORMAT_MASK 0xE0
834
835 #define NUMERIC_SYMBOL_USINT 6
836 #define NUMERIC_SYMBOL_UINT 7
837 #define NUMERIC_SYMBOL_UDINT 8
838
839 #define DOUBLE_BYTE 2
840 #define TRIPLE_BYTE 3
841
842 uint8_t extended_format_byte = data[CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET];
843 uint8_t extended_format_size = extended_format_byte & EXTENDED_STRING_SIZE_MASK;
844
845 bool valid = true;
846 size_t data_size = 0;
847 switch (extended_format_byte & EXTENDED_STRING_FORMAT_MASK)
848 {
849 case EXTENDED_STRING_DOUBLE:
850 data_size = extended_format_size * DOUBLE_BYTE;
851 break;
852 case EXTENDED_STRING_TRIPLE:
853 data_size = extended_format_size * TRIPLE_BYTE;
854 break;
855 case EXTENDED_STRING_NUMERIC:
856 if (extended_format_size == NUMERIC_SYMBOL_USINT)
857 {
858 data_size = sizeof(uint8_t);
859 }
860 else if (extended_format_size == NUMERIC_SYMBOL_UINT)
861 {
862 data_size = sizeof(uint16_t);
863 }
864 else if (extended_format_size == NUMERIC_SYMBOL_UDINT)
865 {
866 data_size = sizeof(uint32_t);
867 }
868 else
869 {
870 valid = false;
871 }
872 break;
873 default:
874 valid = false;
875 break;
876 }
877
878 size_t segment_size_bytes = CIP_PATH_SEGMENT_MIN_SIZE_BYTES + data_size;
879
880 // Add padding.
881 segment_size_bytes += segment_size_bytes % 2;
882
883 if (data_length < segment_size_bytes)
884 {
885 return false;
886 }
887
888 segment->type = CipSegment_Type_SYMBOLIC;
889 segment->data = &data[CIP_PATH_SEGMENT_MIN_SIZE_BYTES];
890 segment->data_size = data_size;
891 segment->size = segment_size_bytes;
892
893 return valid;
894 }
895
parse_segment_symbolic(const uint8_t * data,size_t data_length,CipSegment * segment)896 static bool parse_segment_symbolic(const uint8_t* data,
897 size_t data_length,
898 CipSegment* segment)
899 {
900 #define CIP_PATH_SYMBOLIC_SIZE_MASK 0x1F
901
902 bool valid = true;
903
904 uint8_t symbol_size_bytes = data[CIP_PATH_TYPE_OFFSET] & CIP_PATH_SYMBOLIC_SIZE_MASK;
905 if (symbol_size_bytes == 0)
906 {
907 valid = parse_segment_symbolic_extended_string(data, data_length, segment);
908 }
909 else // Size 1 - 31.
910 {
911 size_t expected_segment_size = CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET + symbol_size_bytes;
912
913 // Add padding
914 expected_segment_size += expected_segment_size % 2;
915
916 if (expected_segment_size > data_length)
917 {
918 valid = false;
919 }
920 else
921 {
922 segment->type = CipSegment_Type_SYMBOLIC;
923 segment->data = &data[CIP_PATH_SEGMENT_PAYLOAD_SIZE_OFFSET];
924 segment->data_size = symbol_size_bytes;
925 segment->size = expected_segment_size;
926 }
927 }
928
929 return valid;
930 }
931
parse_cip_segment(const uint8_t * data,size_t data_length,CipSegment * segment)932 static bool parse_cip_segment(const uint8_t* data,
933 size_t data_length,
934 CipSegment* segment)
935 {
936 bool valid = true;
937
938 #define CIP_PATH_SEGMENT_TYPE_MASK 0xE0
939
940 uint8_t segment_type = data[CIP_PATH_TYPE_OFFSET];
941 switch (segment_type & CIP_PATH_SEGMENT_TYPE_MASK)
942 {
943 case CIP_PATH_SEGMENT_PORT:
944 valid = parse_segment_port(
945 data,
946 data_length,
947 segment);
948 break;
949 case CIP_PATH_SEGMENT_LOGICAL:
950 valid = parse_segment_logical(
951 data,
952 data_length,
953 segment);
954 break;
955 case CIP_PATH_SEGMENT_DATA:
956 {
957 #define CIP_PATH_SEGMENT_SIMPLE_DATA 0x80
958 #define CIP_PATH_SEGMENT_EXT_SYMBOL 0x91
959
960 if (segment_type == CIP_PATH_SEGMENT_EXT_SYMBOL)
961 {
962 valid = parse_segment_extended_symbol(
963 data,
964 data_length,
965 segment);
966 }
967 else if (segment_type == CIP_PATH_SEGMENT_SIMPLE_DATA)
968 {
969 valid = parse_segment_simple_data(
970 data,
971 data_length,
972 segment);
973 }
974 else
975 {
976 set_unknown_segment_type(data_length, segment);
977 }
978 break;
979 }
980 case CIP_PATH_SEGMENT_NETWORK:
981 valid = parse_segment_network(data, data_length, segment);
982 break;
983 case CIP_PATH_SEGMENT_SYMBOLIC:
984 valid = parse_segment_symbolic(data, data_length, segment);
985 break;
986 default:
987 set_unknown_segment_type(data_length, segment);
988 break;
989 }
990
991 return valid;
992 }
993
parse_cip_segments(const uint8_t * data,size_t data_length,CipPath * path)994 static bool parse_cip_segments(const uint8_t* data,
995 size_t data_length,
996 CipPath* path)
997 {
998 bool valid = true;
999
1000 // Parse all CIP segments.
1001 while (data_length > 0)
1002 {
1003 CipSegment segment;
1004 /* Check that there is enough data to start. */
1005 if (data_length < CIP_PATH_SEGMENT_MIN_SIZE_BYTES)
1006 {
1007 valid = false;
1008 break;
1009 }
1010
1011 memset(&segment, 0, sizeof(segment));
1012 if (!parse_cip_segment(data, data_length, &segment))
1013 {
1014 valid = false;
1015 break;
1016 }
1017
1018 // Save off key data in this segment for later use.
1019 if (segment.type == CipSegment_Type_LOGICAL_CLASS)
1020 {
1021 path->has_class_id = true;
1022 path->class_id = segment.logical_value;
1023
1024 path->primary_segment_type = CipSegment_Type_LOGICAL_CLASS;
1025 }
1026 else if (segment.type == CipSegment_Type_DATA_EXT_SYMBOL)
1027 {
1028 path->primary_segment_type = CipSegment_Type_DATA_EXT_SYMBOL;
1029 }
1030 else if (segment.type == CipSegment_Type_LOGICAL_INSTANCE)
1031 {
1032 path->has_instance_id = true;
1033 path->instance_id = segment.logical_value;
1034 }
1035 else if (segment.type == CipSegment_Type_LOGICAL_ATTRIBUTE)
1036 {
1037 path->has_attribute_id = true;
1038 path->attribute_id = segment.logical_value;
1039 }
1040 else if (segment.type == CipSegment_Type_UNKNOWN)
1041 {
1042 path->has_unknown_segment = true;
1043 }
1044
1045 // Move to the next segment.
1046 data_length -= segment.size;
1047 data += segment.size;
1048 }
1049
1050 return valid;
1051 }
1052
parse_cip_epath(const uint8_t * data,size_t data_length,bool path_contains_reserved_byte,CipPath * path)1053 static bool parse_cip_epath(const uint8_t* data,
1054 size_t data_length,
1055 bool path_contains_reserved_byte,
1056 CipPath* path)
1057 {
1058 #define PATH_SIZE_FIELD_BYTES 1
1059 #define PATH_SIZE_OFFSET 0
1060 size_t path_size_bytes;
1061 size_t path_header_size;
1062
1063 // There is a size byte and optionally a padding byte before the actual path data.
1064 path_header_size = PATH_SIZE_FIELD_BYTES;
1065 if (path_contains_reserved_byte)
1066 {
1067 path_header_size++;
1068 }
1069
1070 // Validate/Get the Path Size.
1071 if (data_length < path_header_size)
1072 {
1073 return false;
1074 }
1075
1076 path_size_bytes = data[PATH_SIZE_OFFSET] * CIP_WORD_TO_BYTES;
1077 if (data_length - path_header_size < path_size_bytes)
1078 {
1079 return false;
1080 }
1081
1082 if (!parse_cip_segments(data + path_header_size, path_size_bytes, path))
1083 {
1084 return false;
1085 }
1086
1087 path->full_path_size = path_header_size + path_size_bytes;
1088 path->decoded = true;
1089
1090 return true;
1091 }
1092
1093 // Parse the logical addressing format which is common to all logical segment
1094 // types, except Special and Service ID.
parse_logical_address_format(const uint8_t * data,size_t data_length,bool logical_extended,CipSegment * segment)1095 static bool parse_logical_address_format(const uint8_t* data,
1096 size_t data_length,
1097 bool logical_extended,
1098 CipSegment* segment)
1099 {
1100 #define LOGICAL_8_BIT_SIZE 2
1101 #define LOGICAL_8_BIT_EXTENDED_SIZE 4
1102 #define LOGICAL_16_BIT_SIZE 4
1103 #define LOGICAL_32_BIT_SIZE 6
1104 #define LOGICAL_DEFAULT_DATA_OFFSET 2
1105 #define LOGICAL_8_BIT_DATA_OFFSET 1
1106
1107 uint32_t logical_value;
1108 bool valid = true;
1109
1110 uint8_t segment_type = data[CIP_PATH_TYPE_OFFSET];
1111
1112 // Get the expected segment size and data offset.
1113 size_t segment_size = 0;
1114 size_t data_offset = LOGICAL_DEFAULT_DATA_OFFSET;
1115 switch (segment_type & CIP_PATH_LOGICAL_FORMAT_MASK)
1116 {
1117 case CIP_PATH_LOGICAL_32_BIT:
1118 segment_size = LOGICAL_32_BIT_SIZE;
1119 break;
1120 case CIP_PATH_LOGICAL_16_BIT:
1121 segment_size = LOGICAL_16_BIT_SIZE;
1122 break;
1123 case CIP_PATH_LOGICAL_8_BIT:
1124 if (logical_extended)
1125 {
1126 segment_size = LOGICAL_8_BIT_EXTENDED_SIZE;
1127 }
1128 else
1129 {
1130 segment_size = LOGICAL_8_BIT_SIZE;
1131 data_offset = LOGICAL_8_BIT_DATA_OFFSET;
1132 }
1133 break;
1134 default:
1135 valid = false;
1136 break;
1137 }
1138
1139 // Exit early, if we know we won't fit.
1140 if (segment_size > data_length)
1141 {
1142 return false;
1143 }
1144
1145 // Get the logical value.
1146 logical_value = 0;
1147 switch (segment_type & CIP_PATH_LOGICAL_FORMAT_MASK)
1148 {
1149 case CIP_PATH_LOGICAL_32_BIT:
1150 logical_value = LETOHL(&data[data_offset]);
1151 break;
1152 case CIP_PATH_LOGICAL_16_BIT:
1153 logical_value = LETOHS(&data[data_offset]);
1154 break;
1155 case CIP_PATH_LOGICAL_8_BIT:
1156 logical_value = data[data_offset];
1157 break;
1158 default:
1159 valid = false;
1160 break;
1161 }
1162
1163 segment->logical_value = logical_value;
1164 segment->size = segment_size;
1165
1166 return valid;
1167 }
1168
parse_cip_status(const uint8_t * data,size_t data_length,CipStatus * status)1169 static bool parse_cip_status(const uint8_t* data,
1170 size_t data_length,
1171 CipStatus* status)
1172 {
1173 if (data_length < CIP_STATUS_MIN_SIZE)
1174 {
1175 return false;
1176 }
1177
1178 #define CIP_STATUS_OFFSET_GEN_STATUS 0
1179 status->general_status = data[CIP_STATUS_OFFSET_GEN_STATUS];
1180
1181 #define CIP_STATUS_OFFSET_EXT_STATUS_SIZE 1
1182 status->extended_status_size = data[CIP_STATUS_OFFSET_EXT_STATUS_SIZE] * CIP_WORD_TO_BYTES;
1183
1184 // extended status size does not fit the response
1185 if (data_length < (CIP_STATUS_MIN_SIZE + status->extended_status_size))
1186 {
1187 return false;
1188 }
1189
1190 return true;
1191 }
1192
1193 /// Forward Open/Close parsing.
parse_forward_open_request(const uint8_t * data,size_t data_length,bool large_forward_open,CipForwardOpenRequest * forward_open_request,CipRequest * cip_request)1194 static bool parse_forward_open_request(const uint8_t* data,
1195 size_t data_length,
1196 bool large_forward_open,
1197 CipForwardOpenRequest* forward_open_request,
1198 CipRequest* cip_request)
1199 {
1200 // This includes all data up to, but not including, the Connection Path Size.
1201 #define CIP_FORWARD_OPEN_PREFIX_SIZE 35
1202 #define CIP_LARGE_FORWARD_OPEN_PREFIX_SIZE 39
1203 #define FWD_OPEN_OFFSET_CONN_SIGNATURE 10
1204 #define DEFAULT_CONNECTION_TIMEOUT (10 * USEC_PER_SEC)
1205 size_t forward_open_prefix_size;
1206
1207 // Size of the common connection-related parameters fields. This includes
1208 // the RPI and the Network Connection Parameters.
1209 size_t connection_parameters_size;
1210 size_t offset_to_parameters;
1211 size_t offset_transport_type_trigger;
1212 size_t offset_connection_path_size;
1213 uint8_t connection_timeout_multiplier;
1214 const bool NO_PATH_RESERVED_BYTE = false;
1215
1216 if (large_forward_open)
1217 {
1218 connection_parameters_size = sizeof(uint32_t) + sizeof(uint32_t);
1219 forward_open_prefix_size = CIP_LARGE_FORWARD_OPEN_PREFIX_SIZE;
1220 }
1221 else
1222 {
1223 connection_parameters_size = sizeof(uint32_t) + sizeof(uint16_t);
1224 forward_open_prefix_size = CIP_FORWARD_OPEN_PREFIX_SIZE;
1225 }
1226
1227 // Ensure that there is enough data for the common part of a Forward Open.
1228 if (data_length < forward_open_prefix_size)
1229 {
1230 return false;
1231 }
1232 data_length -= forward_open_prefix_size;
1233
1234 #define FWD_OPEN_OFFSET_TIMEOUT_MULTIPLIER 18
1235 #define FWD_OPEN_OFFSET_OT_RPI 22
1236 offset_to_parameters = FWD_OPEN_OFFSET_OT_RPI + connection_parameters_size;
1237 offset_transport_type_trigger = offset_to_parameters + connection_parameters_size;
1238 offset_connection_path_size = offset_transport_type_trigger + 1;
1239
1240 forward_open_request->timeout_ms = get_unconnected_timeout(data);
1241 parse_connection_signature(&data[FWD_OPEN_OFFSET_CONN_SIGNATURE],
1242 &forward_open_request->connection_signature);
1243 parse_connection_parameters(&data[FWD_OPEN_OFFSET_OT_RPI],
1244 large_forward_open,
1245 &forward_open_request->ot_parameters);
1246 parse_connection_parameters(&data[offset_to_parameters],
1247 large_forward_open,
1248 &forward_open_request->to_parameters);
1249
1250 // Get the overall connection timeouts.
1251 connection_timeout_multiplier = data[FWD_OPEN_OFFSET_TIMEOUT_MULTIPLIER];
1252 #define MULTIPLIER_DEFAULT 2
1253 #define MAX_TIMEOUT_MULTIPLIER 7
1254 if (connection_timeout_multiplier <= MAX_TIMEOUT_MULTIPLIER)
1255 {
1256 uint16_t actual_multiplier = 1 << (connection_timeout_multiplier + MULTIPLIER_DEFAULT);
1257 forward_open_request->ot_connection_timeout_us
1258 = forward_open_request->ot_parameters.rpi * actual_multiplier;
1259 forward_open_request->to_connection_timeout_us
1260 = forward_open_request->to_parameters.rpi * actual_multiplier;
1261 }
1262 else
1263 {
1264 cip_request->cip_req_invalid_nonfatal |= CIP_REQ_INVALID_TIMEOUT_MULTIPLIER;
1265 forward_open_request->ot_connection_timeout_us = DEFAULT_CONNECTION_TIMEOUT;
1266 forward_open_request->to_connection_timeout_us = DEFAULT_CONNECTION_TIMEOUT;
1267 }
1268
1269 if (forward_open_request->ot_parameters.is_null_connection
1270 && forward_open_request->to_parameters.is_null_connection)
1271 {
1272 forward_open_request->is_null_forward_open = true;
1273 }
1274
1275 uint8_t transport_type_trigger = data[offset_transport_type_trigger];
1276 forward_open_request->transport_class = transport_type_trigger & TRANSPORT_CLASS_MASK;
1277
1278 // Parse out the Connection Path. This is a variable length section.
1279 bool valid = parse_cip_epath(&data[offset_connection_path_size],
1280 data_length,
1281 NO_PATH_RESERVED_BYTE,
1282 &forward_open_request->connection_path);
1283
1284 return valid;
1285 }
1286
parse_forward_open_response_success(const uint8_t * data,size_t data_length,CipForwardOpenResponse * forward_open_response)1287 static bool parse_forward_open_response_success(const uint8_t* data,
1288 size_t data_length,
1289 CipForwardOpenResponse* forward_open_response)
1290 {
1291 #define FWD_OPEN_OFFSET_CON_SIGNATURE 8
1292 #define CIP_FORWARD_OPEN_RESPONSE_PREFIX_SIZE 26
1293 if (data_length < CIP_FORWARD_OPEN_RESPONSE_PREFIX_SIZE)
1294 {
1295 return false;
1296 }
1297
1298 #define FWD_OPEN_OFFSET_OT_CONNECTION 0
1299 #define FWD_OPEN_OFFSET_TO_CONNECTION 4
1300 #define FWD_OPEN_OFFSET_REPLY_SIZE 24
1301
1302 forward_open_response->connection_pair.ot_connection_id
1303 = LETOHL(&data[FWD_OPEN_OFFSET_OT_CONNECTION]);
1304 forward_open_response->connection_pair.to_connection_id
1305 = LETOHL(&data[FWD_OPEN_OFFSET_TO_CONNECTION]);
1306 parse_connection_signature(&data[FWD_OPEN_OFFSET_CON_SIGNATURE],
1307 &forward_open_response->connection_signature);
1308 forward_open_response->application_reply_size
1309 = data[FWD_OPEN_OFFSET_REPLY_SIZE] * CIP_WORD_TO_BYTES;
1310
1311 data_length -= CIP_FORWARD_OPEN_RESPONSE_PREFIX_SIZE;
1312 if (data_length < forward_open_response->application_reply_size)
1313 {
1314 return false;
1315 }
1316
1317 forward_open_response->success = true;
1318
1319 return true;
1320 }
1321
parse_forward_open_response_fail(const uint8_t * data,size_t data_length,CipForwardOpenResponse * forward_open_response)1322 static bool parse_forward_open_response_fail(const uint8_t* data,
1323 size_t data_length,
1324 CipForwardOpenResponse* forward_open_response)
1325 {
1326 #define CIP_FORWARD_OPEN_RESPONSE_FAIL_SIZE 10
1327 if (data_length < CIP_FORWARD_OPEN_RESPONSE_FAIL_SIZE)
1328 {
1329 return false;
1330 }
1331
1332 parse_connection_signature(data, &forward_open_response->connection_signature);
1333
1334 forward_open_response->success = false;
1335
1336 return true;
1337 }
1338
parse_forward_open_response(const uint8_t * data,size_t data_length,uint8_t response_status,CipForwardOpenResponse * forward_open_response)1339 static bool parse_forward_open_response(const uint8_t* data,
1340 size_t data_length,
1341 uint8_t response_status,
1342 CipForwardOpenResponse* forward_open_response)
1343 {
1344 bool valid = true;
1345
1346 // Forward Open Success and Failure cases have different formats.
1347 if (response_status == CIP_STATUS_SUCCESS)
1348 {
1349 valid = parse_forward_open_response_success(data, data_length, forward_open_response);
1350 }
1351 else
1352 {
1353 valid = parse_forward_open_response_fail(data, data_length, forward_open_response);
1354 }
1355
1356 return valid;
1357 }
1358
parse_forward_close_request(const uint8_t * data,size_t data_length,CipForwardCloseRequest * forward_close_request)1359 static bool parse_forward_close_request(const uint8_t* data,
1360 size_t data_length,
1361 CipForwardCloseRequest* forward_close_request)
1362 {
1363 bool valid;
1364 const bool PATH_RESERVED_BYTE = true;
1365 #define CIP_FORWARD_CLOSE_PREFIX_SIZE 10
1366 if (data_length < CIP_FORWARD_CLOSE_PREFIX_SIZE)
1367 {
1368 return false;
1369 }
1370
1371 #define FWD_CLOSE_OFFSET_CONNECTION_SIGNATURE 2
1372
1373 forward_close_request->timeout_ms = get_unconnected_timeout(data);
1374 parse_connection_signature(&data[FWD_CLOSE_OFFSET_CONNECTION_SIGNATURE],
1375 &forward_close_request->connection_signature);
1376
1377 // Parse out the Connection Path. This is a variable length section.
1378 valid = parse_cip_epath(data + CIP_FORWARD_CLOSE_PREFIX_SIZE,
1379 data_length - CIP_FORWARD_CLOSE_PREFIX_SIZE,
1380 PATH_RESERVED_BYTE,
1381 &forward_close_request->connection_path);
1382
1383 return valid;
1384 }
1385
1386 // Returns size of the CIP Request Header that was parsed.
parse_cip_request_header(const uint8_t * data,size_t data_length,size_t * header_size,CipRequest * cip_request)1387 static bool parse_cip_request_header(const uint8_t* data,
1388 size_t data_length,
1389 size_t* header_size,
1390 CipRequest* cip_request)
1391 {
1392 bool valid;
1393 CipPath* path;
1394 const bool NO_PATH_RESERVED_BYTE = false;
1395 #define CIP_SERVICE_SIZE 1
1396 if (data_length < CIP_SERVICE_SIZE)
1397 {
1398 return false;
1399 }
1400
1401 #define CIP_SERVICE_OFFSET 0
1402 cip_request->service = data[CIP_SERVICE_OFFSET];
1403
1404 // Reset all path information.
1405 memset(&cip_request->request_path, 0, sizeof(cip_request->request_path));
1406 path = &cip_request->request_path;
1407
1408 valid = parse_cip_epath(data + CIP_SERVICE_SIZE,
1409 data_length - CIP_SERVICE_SIZE,
1410 NO_PATH_RESERVED_BYTE,
1411 path);
1412 if (!valid)
1413 {
1414 return false;
1415 }
1416
1417 if (path->has_unknown_segment)
1418 {
1419 cip_request->cip_req_invalid_nonfatal |= CIP_REQ_INVALID_UNKNOWN_SEGMENT;
1420 }
1421
1422 *header_size = CIP_SERVICE_SIZE + path->full_path_size;
1423
1424 return true;
1425 }
1426
cip_status_size(const CipStatus * status)1427 static size_t cip_status_size(const CipStatus* status)
1428 {
1429 return CIP_STATUS_MIN_SIZE + status->extended_status_size;
1430 }
1431
parse_multiple_service_packet(const uint8_t * data,size_t data_length,CipRequest * cip_request,CipGlobalSessionData * global_data)1432 static bool parse_multiple_service_packet(const uint8_t* data,
1433 size_t data_length,
1434 CipRequest* cip_request,
1435 CipGlobalSessionData* global_data)
1436 {
1437 // Save the original data length for use in handling the offsets of embedded services.
1438 uint16_t number_services;
1439 size_t total_offset_size;
1440 size_t data_offset;
1441 size_t first_offset;
1442 bool valid;
1443 uint16_t i;
1444 size_t original_data_length = data_length;
1445
1446 // Check that the number of services will fit.
1447 #define CIP_MSP_NUMBER_SERVICES_FIELD_SIZE 2
1448 if (data_length < CIP_MSP_NUMBER_SERVICES_FIELD_SIZE)
1449 {
1450 return false;
1451 }
1452
1453 #define CIP_MSP_OFFSET_NUMBER_SERVICES 0
1454 number_services = data[CIP_MSP_OFFSET_NUMBER_SERVICES];
1455 data_length -= CIP_MSP_NUMBER_SERVICES_FIELD_SIZE;
1456
1457 // Check that the offsets will fit.
1458 #define CIP_MSP_OFFSET_FIELD_SIZE 2
1459 total_offset_size = number_services * CIP_MSP_OFFSET_FIELD_SIZE;
1460 if (data_length < total_offset_size)
1461 {
1462 return false;
1463 }
1464
1465 // Length of actual data left after the offsets.
1466 data_length -= total_offset_size;
1467
1468 // Check that offset data starts after the last offset.
1469 data_offset = CIP_MSP_NUMBER_SERVICES_FIELD_SIZE + total_offset_size;
1470 first_offset = LETOHS(&data[CIP_MSP_NUMBER_SERVICES_FIELD_SIZE]);
1471 if (first_offset < data_offset)
1472 {
1473 return false;
1474 }
1475
1476 valid = true;
1477
1478 // Process each embedded service.
1479 for (i = 1; i <= number_services; ++i)
1480 {
1481 size_t msp_length;
1482 CipRequest embedded_request;
1483 CipEventData cip_event_data;
1484 CipEvent cip_event(global_data->snort_packet, &cip_event_data);
1485
1486 /* This if the offset from the Number of Services field, to the Offset field. */
1487 uint16_t buffer_offset = i * CIP_MSP_OFFSET_FIELD_SIZE;
1488
1489 /* This if the offset from the Number of Services field to the data. */
1490 size_t msp_offset = LETOHS(&data[buffer_offset]);
1491
1492 /* There is no end offset specified, so the next offset needs checked
1493 to find the length of the current service. For the last packet,
1494 this needs to use the total length of the Multiple Service Packet. */
1495 size_t msp_offset_end = 0;
1496 if (i == number_services)
1497 {
1498 msp_offset_end = original_data_length;
1499 }
1500 else
1501 {
1502 uint16_t next_buffer_offset = buffer_offset + CIP_MSP_OFFSET_FIELD_SIZE;
1503 msp_offset_end = LETOHS(&data[next_buffer_offset]);
1504 }
1505
1506 // Check that offsets are increasing.
1507 if (msp_offset >= msp_offset_end)
1508 {
1509 valid = false;
1510 break;
1511 }
1512
1513 // Check embedded length against the data size left.
1514 msp_length = msp_offset_end - msp_offset;
1515 if (data_length < msp_length)
1516 {
1517 valid = false;
1518 break;
1519 }
1520
1521 data_length -= msp_length;
1522
1523 memset(&embedded_request, 0, sizeof(embedded_request));
1524 if (!parse_message_router_request(data + msp_offset,
1525 msp_length,
1526 &embedded_request,
1527 global_data))
1528 {
1529 valid = false;
1530 break;
1531 }
1532
1533 // Store embedded packet errors in the parent request.
1534 cip_request->cip_req_invalid_nonfatal |= embedded_request.cip_req_invalid_nonfatal;
1535
1536 // Publish embedded CIP data to appid.
1537 memset(&cip_event_data, 0, sizeof(cip_event_data));
1538
1539 pack_cip_request_event(&embedded_request, &cip_event_data);
1540
1541 DataBus::publish(CIP_EVENT_TYPE_CIP_DATA_KEY, cip_event, global_data->snort_packet->flow);
1542 }
1543
1544 return valid;
1545 }
1546
parse_unconnected_send_request(const uint8_t * data,size_t data_length,CipRequest * cip_request,CipGlobalSessionData * global_data)1547 static bool parse_unconnected_send_request(const uint8_t* data,
1548 size_t data_length,
1549 CipRequest* cip_request,
1550 CipGlobalSessionData* global_data)
1551 {
1552 bool valid;
1553 uint16_t message_request_size;
1554 const bool PATH_RESERVED_BYTE = true;
1555 // This includes: Timeout data, embedded message size.
1556 #define UNCONNECTED_SEND_HEADER_SIZE 4
1557 if (data_length < UNCONNECTED_SEND_HEADER_SIZE)
1558 {
1559 return false;
1560 }
1561
1562 cip_request->timeout_ms = get_unconnected_timeout(data);
1563 cip_request->has_timeout = true;
1564
1565 #define UNCONNECTED_SEND_OFFSET_MESSAGE_SIZE 2
1566 message_request_size = LETOHS(&data[UNCONNECTED_SEND_OFFSET_MESSAGE_SIZE]);
1567
1568 data += UNCONNECTED_SEND_HEADER_SIZE;
1569 data_length -= UNCONNECTED_SEND_HEADER_SIZE;
1570
1571 // Verify that expected length of embedded request will fit in actual data.
1572 if (message_request_size > data_length)
1573 {
1574 return false;
1575 }
1576
1577 if (!parse_message_router_request(data, message_request_size, cip_request, global_data))
1578 {
1579 return false;
1580 }
1581
1582 // Parse the Route Path.
1583 valid = parse_cip_epath(data + message_request_size,
1584 data_length - message_request_size,
1585 PATH_RESERVED_BYTE,
1586 &cip_request->route_path);
1587
1588 return valid;
1589 }
1590
parse_cip_command_specific_data_request(const uint8_t * data,size_t data_length,CipRequest * cip_request,CipGlobalSessionData * global_data)1591 static bool parse_cip_command_specific_data_request(const uint8_t* data,
1592 size_t data_length,
1593 CipRequest* cip_request,
1594 CipGlobalSessionData* global_data)
1595 {
1596 const CipProtoConf* config;
1597 /* If the request path doesn't have a Class ID, then we don't know how to
1598 parse the response.*/
1599 if (!cip_request->request_path.has_class_id)
1600 {
1601 cip_request->request_type = CipRequestTypeOther;
1602 return true;
1603 }
1604
1605 bool valid = true;
1606
1607 uint8_t service = cip_request->service;
1608 uint32_t class_id = cip_request->request_path.class_id;
1609 if (service == SERVICE_MULTIPLE_SERVICE_PACKET)
1610 {
1611 valid = parse_multiple_service_packet(data, data_length, cip_request, global_data);
1612 cip_request->request_type = CipRequestTypeMultipleServiceRequest;
1613 }
1614 else if (class_id == CONNECTION_MANAGER_CLASS_ID
1615 && service == CONNECTION_MANAGER_UNCONNECTED_SEND)
1616 {
1617 valid = parse_unconnected_send_request(data,
1618 data_length,
1619 cip_request,
1620 global_data);
1621 cip_request->request_type = CipRequestTypeUnconnectedSend;
1622 }
1623 else if (class_id == CONNECTION_MANAGER_CLASS_ID
1624 && (service == CONNECTION_MANAGER_FORWARD_OPEN
1625 || service == CONNECTION_MANAGER_LARGE_FORWARD_OPEN))
1626 {
1627 CipForwardOpenRequest forward_open_request;
1628 memset(&forward_open_request, 0, sizeof(forward_open_request));
1629
1630 bool large_forward_open = (service == CONNECTION_MANAGER_LARGE_FORWARD_OPEN);
1631 valid = parse_forward_open_request(data,
1632 data_length,
1633 large_forward_open,
1634 &forward_open_request,
1635 cip_request);
1636 forward_open_request.timestamp = global_data->snort_packet->pkth->ts;
1637
1638 if (valid)
1639 {
1640 // Only store connection information for Class 3, Non-Null connections.
1641 if (!forward_open_request.is_null_forward_open
1642 && forward_open_request.transport_class == 3)
1643 {
1644 if (!cip_add_connection_to_pending(&global_data->connection_list,
1645 &forward_open_request))
1646 {
1647 // Error if the connection couldn't be added to the list.
1648 cip_request->cip_req_invalid_nonfatal |= CIP_REQ_INVALID_CONNECTION_ADD_FAILED;
1649 }
1650 }
1651
1652 cip_request->is_forward_open_request = true;
1653 cip_request->connection_path_class_id = forward_open_request.connection_path.class_id;
1654 cip_request->timeout_ms = forward_open_request.timeout_ms;
1655 cip_request->has_timeout = true;
1656 }
1657
1658 cip_request->request_type = CipRequestTypeForwardOpen;
1659 }
1660 else if (class_id == CONNECTION_MANAGER_CLASS_ID
1661 && service == CONNECTION_MANAGER_FORWARD_CLOSE)
1662 {
1663 CipForwardCloseRequest forward_close_request;
1664 memset(&forward_close_request, 0, sizeof(forward_close_request));
1665
1666 valid = parse_forward_close_request(data,
1667 data_length,
1668 &forward_close_request);
1669
1670 if (valid)
1671 {
1672 const bool connection_established = true;
1673 cip_remove_connection(&global_data->connection_list,
1674 &forward_close_request.connection_signature,
1675 connection_established);
1676
1677 cip_request->timeout_ms = forward_close_request.timeout_ms;
1678 cip_request->has_timeout = true;
1679 }
1680
1681 cip_request->request_type = CipRequestTypeForwardClose;
1682 }
1683 else
1684 {
1685 // This is a regular CIP request. No need to parse data.
1686 cip_request->request_type = CipRequestTypeOther;
1687 }
1688
1689 // Parse any embedded CIP packet that is configured.
1690 config = global_data->config;
1691 if (config->embedded_cip_enabled
1692 && class_id == config->embedded_cip_class_id
1693 && service == config->embedded_cip_service_id)
1694 {
1695 valid = parse_message_router_request(data, data_length, cip_request, global_data);
1696 }
1697
1698 return valid;
1699 }
1700
parse_cip_command_specific_data_response(const CipStatus * status,const uint8_t * data,size_t data_length,CipRequestType request_type,CipGlobalSessionData * global_data)1701 static bool parse_cip_command_specific_data_response(const CipStatus* status,
1702 const uint8_t* data,
1703 size_t data_length,
1704 CipRequestType request_type,
1705 CipGlobalSessionData* global_data)
1706 {
1707 bool valid = true;
1708
1709 if (request_type == CipRequestTypeForwardOpen)
1710 {
1711 CipForwardOpenResponse forward_open_response;
1712 memset(&forward_open_response, 0, sizeof(forward_open_response));
1713
1714 valid = parse_forward_open_response(data,
1715 data_length,
1716 status->general_status,
1717 &forward_open_response);
1718 forward_open_response.timestamp = global_data->snort_packet->pkth->ts;
1719
1720 if (forward_open_response.success)
1721 {
1722 cip_add_connection_to_active(&global_data->connection_list, &forward_open_response);
1723 }
1724 else
1725 {
1726 const bool connection_established = false;
1727 cip_remove_connection(&global_data->connection_list,
1728 &forward_open_response.connection_signature,
1729 connection_established);
1730 }
1731 }
1732
1733 return valid;
1734 }
1735
1736
parse_message_router_request(const uint8_t * data,size_t data_length,CipRequest * cip_request,CipGlobalSessionData * global_data)1737 static bool parse_message_router_request(const uint8_t* data,
1738 size_t data_length,
1739 CipRequest* cip_request,
1740 CipGlobalSessionData* global_data)
1741 {
1742 size_t header_size = 0;
1743 if (!parse_cip_request_header(data,
1744 data_length,
1745 &header_size,
1746 cip_request))
1747 {
1748 return false;
1749 }
1750
1751 cip_request->cip_data = data + header_size;
1752 cip_request->cip_data_size = data_length - header_size;
1753
1754 bool valid = parse_cip_command_specific_data_request(data + header_size,
1755 data_length - header_size,
1756 cip_request,
1757 global_data);
1758
1759 return valid;
1760 }
1761
parse_message_router_response(const uint8_t * data,size_t data_length,CipRequestType request_type,CipResponse * cip_response,CipGlobalSessionData * global_data)1762 static bool parse_message_router_response(const uint8_t* data,
1763 size_t data_length,
1764 CipRequestType request_type,
1765 CipResponse* cip_response,
1766 CipGlobalSessionData* global_data)
1767 {
1768 bool valid;
1769 size_t response_header_size;
1770 size_t status_size;
1771 #define MESSAGE_ROUTER_RESPONSE_MIN_SIZE 4
1772 if (data_length < MESSAGE_ROUTER_RESPONSE_MIN_SIZE)
1773 {
1774 return false;
1775 }
1776
1777 #define CIP_SERVICE_OFFSET 0
1778 #define CIP_STATUS_OFFSET 2
1779
1780 cip_response->service = data[CIP_SERVICE_OFFSET] & ~MESSAGE_ROUTER_RESPONSE_MASK;
1781
1782 if (!parse_cip_status(data + CIP_STATUS_OFFSET,
1783 data_length - CIP_STATUS_OFFSET,
1784 &cip_response->status))
1785 {
1786 return false;
1787 }
1788
1789 status_size = cip_status_size(&cip_response->status);
1790
1791 // This includes: Service, reserved field, total status data.
1792 response_header_size = CIP_STATUS_OFFSET + status_size;
1793
1794 valid = true;
1795 // Don't attempt to decode the command specific response if there wasn't a
1796 // match to an existing request.
1797 if (request_type != CipRequestTypeNoMatchFound)
1798 {
1799 valid = parse_cip_command_specific_data_response(&cip_response->status,
1800 data + response_header_size,
1801 data_length - response_header_size,
1802 request_type,
1803 global_data);
1804 }
1805
1806 return valid;
1807 }
1808
1809 // Returns true if the serviceId was a request service.
is_service_request(uint8_t service_id)1810 static bool is_service_request(uint8_t service_id)
1811 {
1812 return (service_id & MESSAGE_ROUTER_RESPONSE_MASK) == 0;
1813 }
1814
parse_message_router(const uint8_t * data,size_t data_length,CipCurrentData * current_data,CipGlobalSessionData * global_data)1815 static bool parse_message_router(const uint8_t* data,
1816 size_t data_length,
1817 CipCurrentData* current_data,
1818 CipGlobalSessionData* global_data)
1819 {
1820 bool valid = true;
1821
1822 CipMessage* cip_msg = ¤t_data->cip_msg;
1823
1824 cip_msg->is_cip_request = is_service_request(*data);
1825 if (cip_msg->is_cip_request)
1826 {
1827 cip_msg->request.request_type = CipRequestTypeOther;
1828 valid = parse_message_router_request(data,
1829 data_length,
1830 &cip_msg->request,
1831 global_data);
1832
1833 cip_request_add(&global_data->unconnected_list,
1834 ¤t_data->enip_data,
1835 &cip_msg->request,
1836 &global_data->snort_packet->pkth->ts);
1837 }
1838 else
1839 {
1840 CipRequestType request_type = CipRequestTypeNoMatchFound;
1841 cip_request_remove(&global_data->unconnected_list,
1842 ¤t_data->enip_data,
1843 &request_type);
1844
1845 valid = parse_message_router_response(data,
1846 data_length,
1847 request_type,
1848 &cip_msg->response,
1849 global_data);
1850 }
1851
1852 return valid;
1853 }
1854
1855 // Returns true if this data contains valid CIP Explicit data. The data must already:
1856 // 1. Be ENIP_COMMAND_SEND_UNIT_DATA or ENIP_COMMAND_SEND_RR_DATA
1857 // 2. Have the required CPF items for that ENIP command.
parse_cip_explicit_data(CipCurrentData * current_data,CipGlobalSessionData * global_data)1858 static bool parse_cip_explicit_data(CipCurrentData* current_data, CipGlobalSessionData* global_data)
1859 {
1860 // Assume that all data values/length inside the EnipCpf are valid.
1861 const EnipCpf* enip_cpf = ¤t_data->enip_data.enip_cpf;
1862 const EnipCpfItem* cpf_item = &enip_cpf->item_list[CPF_DATA_ITEM_SLOT];
1863
1864 // Get the offset of the CIP Message Router data.
1865 size_t cpf_data_offset = 0;
1866 if (cpf_item->type == CPF_CONNECTED_DATA_ITEM_ID)
1867 {
1868 // For CIP Class 3 data, Connected Data contains: Sequence Count, then CIP Data.
1869 const size_t CPF_CONNECTED_DATA_SEQUENCE_COUNT_SIZE = sizeof(uint16_t);
1870 cpf_data_offset = CPF_CONNECTED_DATA_SEQUENCE_COUNT_SIZE;
1871 }
1872 else // CPF_UNCONNECTED_DATA_ITEM_ID
1873 {
1874 cpf_data_offset = 0;
1875 }
1876
1877 bool valid = false;
1878 if (cpf_item->length > cpf_data_offset)
1879 {
1880 const uint8_t* message_router_data = cpf_item->data + cpf_data_offset;
1881 size_t message_router_data_length = cpf_item->length - cpf_data_offset;
1882
1883 valid = parse_message_router(message_router_data,
1884 message_router_data_length,
1885 current_data,
1886 global_data);
1887 }
1888
1889 return valid;
1890 }
1891
1892 // Used for parsing SendRRData and SendUnitData Command Specific Data.
parse_enip_command_data(const uint8_t * data,size_t data_length,CipCurrentData * current_data,CipGlobalSessionData * global_data)1893 static bool parse_enip_command_data(const uint8_t* data,
1894 size_t data_length,
1895 CipCurrentData* current_data,
1896 CipGlobalSessionData* global_data)
1897 {
1898 uint32_t interface_handle;
1899
1900 // This should always contain: Interface Handle, Timeout.
1901 #define ENIP_COMMAND_HEADER_SIZE 6
1902 if (data_length < ENIP_COMMAND_HEADER_SIZE)
1903 {
1904 return false;
1905 }
1906
1907 // Interface Handle
1908 #define ENIP_OFFSET_INTERFACE_HANDLE 0
1909 interface_handle = LETOHL(&data[ENIP_OFFSET_INTERFACE_HANDLE]);
1910
1911 #define CIP_INTERFACE_HANDLE 0
1912 if (interface_handle != CIP_INTERFACE_HANDLE)
1913 {
1914 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_INTERFACE_HANDLE;
1915 }
1916
1917 // Parse the Encapsulated Data as Common Packet Format.
1918 current_data->enip_data.cpf_decoded = parse_common_packet_format(data + ENIP_COMMAND_HEADER_SIZE,
1919 data_length - ENIP_COMMAND_HEADER_SIZE,
1920 ¤t_data->enip_data.enip_cpf,
1921 current_data);
1922 if (!current_data->enip_data.cpf_decoded)
1923 {
1924 return false;
1925 }
1926
1927 // Exit early if CIP Explicit Data cannot be processed.
1928 if (!current_data->enip_data.required_cpf_items_present)
1929 {
1930 return true;
1931 }
1932
1933 current_data->cip_message_type = get_cip_message_type(current_data, global_data);
1934
1935 bool valid = true;
1936 if (current_data->cip_message_type == CipMessageTypeExplicit)
1937 {
1938 valid = parse_cip_explicit_data(current_data, global_data);
1939 }
1940
1941 return valid;
1942 }
1943
parse_enip_layer(const uint8_t * data,size_t data_length,bool is_TCP,CipCurrentData * current_data,CipGlobalSessionData * global_data)1944 bool parse_enip_layer(const uint8_t* data,
1945 size_t data_length,
1946 bool is_TCP,
1947 CipCurrentData* current_data,
1948 CipGlobalSessionData* global_data)
1949 {
1950 const EnipHeader* enip_header;
1951 current_data->enip_data.enip_decoded = parse_enip_header(data,
1952 data_length,
1953 ¤t_data->enip_data);
1954 if (!current_data->enip_data.enip_decoded)
1955 {
1956 return false;
1957 }
1958
1959 // Command Specific Data
1960 data += ENIP_HEADER_SIZE;
1961 data_length -= ENIP_HEADER_SIZE;
1962
1963 // Verify that actual data matches data length field.
1964 enip_header = ¤t_data->enip_data.enip_header;
1965 if (data_length < enip_header->length)
1966 {
1967 return false;
1968 }
1969
1970 if (enip_command_tcp_only(enip_header->command) && !is_TCP)
1971 {
1972 // Flag as an error and exit early because there would be no way to tie this data
1973 // to a particular TCP session.
1974 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_ENIP_TCP_ONLY;
1975
1976 return true;
1977 }
1978
1979 if (enip_header->status != ENIP_STATUS_SUCCESS)
1980 {
1981 if (current_data->direction == CIP_FROM_CLIENT)
1982 {
1983 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_STATUS;
1984 }
1985 else if (current_data->direction == CIP_FROM_SERVER)
1986 {
1987 // Remove any outstanding request.
1988 CipRequestType request_type = CipRequestTypeNoMatchFound;
1989 cip_request_remove(&global_data->unconnected_list,
1990 ¤t_data->enip_data,
1991 &request_type);
1992 }
1993
1994 // No more processing after a non-success status.
1995 return true;
1996 }
1997
1998 bool valid = true;
1999
2000 switch (enip_header->command)
2001 {
2002 case ENIP_COMMAND_REGISTER_SESSION:
2003 {
2004 if (data_length < REGISTER_SESSION_DATA_SIZE)
2005 {
2006 valid = false;
2007 break;
2008 }
2009
2010 // Check that there is no active ENIP session.
2011 if (current_data->direction == CIP_FROM_CLIENT)
2012 {
2013 if (global_data->enip_session.active)
2014 {
2015 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_DUPLICATE_SESSION;
2016 }
2017 }
2018
2019 // Add ENIP session to the current TCP session.
2020 if (current_data->direction == CIP_FROM_SERVER)
2021 {
2022 if (!enip_session_add(&global_data->enip_session,
2023 enip_header->session_handle))
2024 {
2025 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_DUPLICATE_SESSION;
2026 }
2027 }
2028 }
2029 break;
2030
2031 case ENIP_COMMAND_SEND_RR_DATA:
2032 case ENIP_COMMAND_SEND_UNIT_DATA:
2033 valid = parse_enip_command_data(data, data_length, current_data, global_data);
2034
2035 // Check that the Session Handle matches the active ENIP session.
2036 if (!enip_session_handle_valid(&global_data->enip_session, enip_header->session_handle))
2037 {
2038 current_data->enip_data.enip_invalid_nonfatal |= ENIP_INVALID_SESSION_HANDLE;
2039 }
2040 break;
2041 case ENIP_COMMAND_NOP:
2042 break;
2043 case ENIP_COMMAND_LIST_SERVICES:
2044 case ENIP_COMMAND_LIST_IDENTITY:
2045 case ENIP_COMMAND_LIST_INTERFACES:
2046 if (current_data->direction == CIP_FROM_SERVER)
2047 {
2048 current_data->enip_data.cpf_decoded = parse_common_packet_format(data,
2049 data_length,
2050 ¤t_data->enip_data.enip_cpf,
2051 current_data);
2052 if (!current_data->enip_data.cpf_decoded)
2053 {
2054 valid = false;
2055 }
2056 }
2057 break;
2058 case ENIP_COMMAND_UNREGISTER_SESSION:
2059 // Remove ENIP session from the current TCP session.
2060 enip_session_remove(&global_data->enip_session, enip_header->session_handle);
2061 break;
2062 default:
2063 // Ignore legacy cases.
2064 break;
2065 }
2066
2067 return valid;
2068 }
2069
pack_cip_request_event(const CipRequest * request,CipEventData * cip_event_data)2070 void pack_cip_request_event(const CipRequest* request, CipEventData* cip_event_data)
2071 {
2072 cip_event_data->service_id = request->service;
2073
2074 if (request->is_forward_open_request)
2075 {
2076 cip_event_data->type = CIP_DATA_TYPE_CONNECTION;
2077 cip_event_data->class_id = request->connection_path_class_id;
2078 }
2079 else if (request->request_path.primary_segment_type == CipSegment_Type_LOGICAL_CLASS)
2080 {
2081 // Publish Set Attribute Single services separately than other requests.
2082 if (cip_event_data->service_id == SERVICE_SET_ATTRIBUTE_SINGLE
2083 && request->request_path.has_instance_id
2084 && request->request_path.has_attribute_id)
2085 {
2086 cip_event_data->instance_id = request->request_path.instance_id;
2087 cip_event_data->attribute_id = request->request_path.attribute_id;
2088
2089 cip_event_data->type = CIP_DATA_TYPE_SET_ATTRIBUTE;
2090 }
2091 else
2092 {
2093 cip_event_data->type = CIP_DATA_TYPE_PATH_CLASS;
2094 }
2095
2096 cip_event_data->class_id = request->request_path.class_id;
2097 }
2098 else if (request->request_path.primary_segment_type == CipSegment_Type_DATA_EXT_SYMBOL)
2099 {
2100 cip_event_data->type = CIP_DATA_TYPE_PATH_EXT_SYMBOL;
2101 }
2102 else
2103 {
2104 cip_event_data->type = CIP_DATA_TYPE_OTHER;
2105 }
2106 }
2107
2108