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 = &current_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 = &current_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             &current_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             &current_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 = &current_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         &current_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         &current_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  = &current_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                 &current_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                 &current_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