diff options
author | Michael Mann <mmann78@netscape.net> | 2014-05-26 22:58:48 -0400 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2014-05-28 00:25:18 +0000 |
commit | 0701d6170de5e02b15b1ab6fa031c239791ab595 (patch) | |
tree | 0dfa856328ac1fd547e40e5a7dae02081edc0fc4 | |
parent | c3b2b54c92e836988cf66535ff4f4b26eca8d917 (diff) |
Add EtherNet/IP connection conversation filters
Change-Id: Ia69cbe9fea364c735bde956d84a82404b46ec236
Reviewed-on: https://code.wireshark.org/review/1810
Reviewed-by: Michael Mann <mmann78@netscape.net>
-rw-r--r-- | epan/dissectors/packet-cip.c | 49 | ||||
-rw-r--r-- | epan/dissectors/packet-cip.h | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-enip.c | 141 | ||||
-rw-r--r-- | epan/dissectors/packet-enip.h | 5 |
4 files changed, 158 insertions, 38 deletions
diff --git a/epan/dissectors/packet-cip.c b/epan/dissectors/packet-cip.c index cc95c3e6db..3a2ba54be5 100644 --- a/epan/dissectors/packet-cip.c +++ b/epan/dissectors/packet-cip.c @@ -4944,23 +4944,30 @@ dissect_cip_cm_fwd_open_req(cip_req_info_t *preq_info, proto_tree *cmd_tree, tvb dissect_epath( tvb, pinfo, pi, offset+26+net_param_offset+6, conn_path_size, FALSE, FALSE, &connection_path, &safety_fwdopen); if (pinfo->fd->flags.visited) - return; - - if (preq_info != NULL) { - DISSECTOR_ASSERT(preq_info->connInfo == NULL); - preq_info->connInfo = wmem_new0(wmem_file_scope(), cip_conn_info_t); - - preq_info->connInfo->ConnSerialNumber = ConnSerialNumber; - preq_info->connInfo->VendorID = VendorID; - preq_info->connInfo->DeviceSerialNumber = DeviceSerialNumber; - preq_info->connInfo->O2T.connID = O2TConnID; - preq_info->connInfo->T2O.connID = T2OConnID; - preq_info->connInfo->TransportClass_trigger = TransportClass_trigger; - preq_info->connInfo->T2O.type = T2OType; - preq_info->connInfo->O2T.type = O2TType; - preq_info->connInfo->motion = (connection_path.iClass == 0x42) ? TRUE : FALSE; - preq_info->connInfo->safety = safety_fwdopen; + /* "Connection" is created during ForwardOpen reply (which will be after ForwardOpen request), + so ForwardOpen request can only be marked after the first pass */ + enip_mark_connection_triad(pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber); + } + else + { + if (preq_info != NULL) + { + DISSECTOR_ASSERT(preq_info->connInfo == NULL); + preq_info->connInfo = wmem_new0(wmem_file_scope(), cip_conn_info_t); + + preq_info->connInfo->ConnSerialNumber = ConnSerialNumber; + preq_info->connInfo->VendorID = VendorID; + preq_info->connInfo->DeviceSerialNumber = DeviceSerialNumber; + preq_info->connInfo->forward_open_frame = pinfo->fd->num; + preq_info->connInfo->O2T.connID = O2TConnID; + preq_info->connInfo->T2O.connID = T2OConnID; + preq_info->connInfo->TransportClass_trigger = TransportClass_trigger; + preq_info->connInfo->T2O.type = T2OType; + preq_info->connInfo->O2T.type = O2TType; + preq_info->connInfo->motion = (connection_path.iClass == 0x42) ? TRUE : FALSE; + preq_info->connInfo->safety = safety_fwdopen; + } } } @@ -5383,8 +5390,14 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_ dissect_cip_cm_timeout( cmd_data_tree, tvb, offset+2+req_path_size); proto_tree_add_item( cmd_data_tree, hf_cip_cm_conn_serial_num, tvb, offset+2+req_path_size+2, 2, ENC_LITTLE_ENDIAN); + ConnSerialNumber = tvb_get_letohs( tvb, offset+2+req_path_size+2); proto_tree_add_item( cmd_data_tree, hf_cip_cm_vendor, tvb, offset+2+req_path_size+4, 2, ENC_LITTLE_ENDIAN); + VendorID = tvb_get_letohs( tvb, offset+2+req_path_size+4 ); proto_tree_add_item( cmd_data_tree, hf_cip_cm_orig_serial_num, tvb, offset+2+req_path_size+6, 4, ENC_LITTLE_ENDIAN); + DeviceSerialNumber = tvb_get_letohl( tvb, offset+2+req_path_size+6 ); + + if (!pinfo->fd->flags.visited) + enip_mark_connection_triad(pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber); /* Add the path size */ conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2; @@ -5804,7 +5817,7 @@ dissect_cip_cco_all_attribute_common( proto_tree *cmd_tree, tvbuff_t *tvb, int o /* Connection Name */ connection_name_size = tvb_get_guint8( tvb, offset+variable_data_size); - str_connection_name = tvb_get_string(wmem_packet_scope(), tvb, offset+variable_data_size+2, connection_name_size); + str_connection_name = tvb_get_string_enc(wmem_packet_scope(), tvb, offset+variable_data_size+2, connection_name_size, ENC_ASCII); proto_tree_add_text(cmd_tree, tvb, offset+variable_data_size, connection_name_size+2, "Connection Name: %s", str_connection_name); variable_data_size += ((connection_name_size*2)+2); @@ -6349,7 +6362,7 @@ dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) col_clear(pinfo->cinfo, COL_INFO); /* Each CIP request received by ENIP gets a unique ID */ - enip_info = (enip_request_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, 0); + enip_info = (enip_request_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO); if ( enip_info ) { diff --git a/epan/dissectors/packet-cip.h b/epan/dissectors/packet-cip.h index 9c44129a82..28dfa012cc 100644 --- a/epan/dissectors/packet-cip.h +++ b/epan/dissectors/packet-cip.h @@ -288,6 +288,7 @@ typedef struct cip_conn_info { guint16 ConnSerialNumber; guint16 VendorID; guint32 DeviceSerialNumber; + guint32 forward_open_frame; cip_connID_info_t O2T; cip_connID_info_t T2O; guint8 TransportClass_trigger; diff --git a/epan/dissectors/packet-enip.c b/epan/dissectors/packet-enip.c index a70d67f8e6..7ad7d2fa77 100644 --- a/epan/dissectors/packet-enip.c +++ b/epan/dissectors/packet-enip.c @@ -40,6 +40,7 @@ #include <epan/packet.h> #include <epan/wmem/wmem.h> #include <epan/conversation.h> +#include <epan/dissector_filters.h> #include <epan/prefs.h> #include <epan/etypes.h> #include <epan/ipv6-utils.h> @@ -804,10 +805,6 @@ enip_match_request( packet_info *pinfo, proto_tree *tree, enip_request_key_t *pr return request_info; } -/* - * Connection management - */ - typedef struct enip_conn_key { guint16 ConnSerialNumber; guint16 VendorID; @@ -823,8 +820,9 @@ typedef struct enip_conn_val { guint32 O2TConnID; guint32 T2OConnID; guint8 TransportClass_trigger; - guint32 openframe; - guint32 closeframe; + guint32 open_frame; + guint32 open_reply_frame; + guint32 close_frame; guint32 connid; cip_safety_epath_info_t safety; gboolean motion; @@ -835,6 +833,74 @@ typedef struct _enip_conv_info_t { wmem_tree_t *T2OConnIDs; } enip_conv_info_t; +/* + * Conversation filter + */ +static gboolean +enip_io_conv_valid(packet_info *pinfo) +{ + enip_conn_val_t* conn = (enip_conn_val_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO); + + if (conn == NULL) + return FALSE; + + return (((conn->TransportClass_trigger & CI_TRANSPORT_CLASS_MASK) == 0) || + ((conn->TransportClass_trigger & CI_TRANSPORT_CLASS_MASK) == 1)); +} + +static const gchar * +enip_io_conv_filter(packet_info *pinfo) +{ + char *buf; + enip_conn_val_t* conn = (enip_conn_val_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO); + + if (conn == NULL) + return NULL; + + buf = g_strdup_printf( + "((frame.number == %u) || ((frame.number >= %u) && (frame.number <= %u))) && " /* Frames between ForwardOpen and ForwardClose */ + "((enip.cpf.sai.connid == 0x%08x || enip.cpf.sai.connid == 0x%08x) || " /* O->T and T->O Connection IDs */ + "((cip.cm.conn_serial_num == 0x%04x) && (cip.cm.vendor == 0x%04x) && (cip.cm.orig_serial_num == 0x%08x)))", /* Connection Triad */ + conn->open_frame, conn->open_reply_frame, conn->close_frame, + conn->O2TConnID, conn->T2OConnID, + conn->ConnSerialNumber, conn->VendorID, conn->DeviceSerialNumber); + return buf; +} + +static gboolean +enip_exp_conv_valid(packet_info *pinfo) +{ + enip_conn_val_t* conn = (enip_conn_val_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO); + + if (conn == NULL) + return FALSE; + + return (((conn->TransportClass_trigger & CI_TRANSPORT_CLASS_MASK) == 2) || + ((conn->TransportClass_trigger & CI_TRANSPORT_CLASS_MASK) == 3)); +} + +static const gchar * +enip_exp_conv_filter(packet_info *pinfo) +{ + char *buf; + enip_conn_val_t* conn = (enip_conn_val_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO); + + if (conn == NULL) + return NULL; + + buf = g_strdup_printf( + "((frame.number == %u) || ((frame.number >= %u) && (frame.number <= %u))) && " /* Frames between ForwardOpen and ForwardClose */ + "((enip.cpf.cai.connid == 0x%08x || enip.cpf.cai.connid == 0x%08x) || " /* O->T and T->O Connection IDs */ + "((cip.cm.conn_serial_num == 0x%04x) && (cip.cm.vendor == 0x%04x) && (cip.cm.orig_serial_num == 0x%08x)))", /* Connection Triad */ + conn->open_frame, conn->open_reply_frame, conn->close_frame, + conn->O2TConnID, conn->T2OConnID, + conn->ConnSerialNumber, conn->VendorID, conn->DeviceSerialNumber); + return buf; +} + +/* + * Connection management + */ static GHashTable *enip_conn_hashtable = NULL; static guint32 enip_unique_connid = 1; @@ -898,8 +964,9 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo) conn_val->TransportClass_trigger = connInfo->TransportClass_trigger; conn_val->safety = connInfo->safety; conn_val->motion = connInfo->motion; - conn_val->openframe = pinfo->fd->num; - conn_val->closeframe = 0; + conn_val->open_frame = connInfo->forward_open_frame; + conn_val->open_reply_frame = pinfo->fd->num; + conn_val->close_frame = 0; conn_val->connid = enip_unique_connid++; g_hash_table_insert(enip_conn_hashtable, conn_key, conn_val ); @@ -962,7 +1029,7 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo) /* Check if separate T->O conversation is necessary. If either side is multicast or ports aren't equal, a separate conversation must be generated */ - dest_address.data = &connInfo->T2O.ipaddress; + dest_address.data = connInfo->T2O.ipaddress.data; if ((conversationTO = find_conversation(pinfo->fd->num, &pinfo->src, &dest_address, PT_UDP, connInfo->T2O.port, 0, NO_PORT_B)) == NULL) { @@ -1004,6 +1071,10 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo) wmem_tree_insert32(enip_info->T2OConnIDs, connInfo->T2O.connID, (void *)conn_val); } } + + /* Save the connection info for the conversation filter */ + if (!pinfo->fd->flags.visited) + p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO, conn_val); } void @@ -1025,7 +1096,30 @@ enip_close_cip_connection(packet_info *pinfo, guint16 ConnSerialNumber, conn_val = (enip_conn_val_t *)g_hash_table_lookup( enip_conn_hashtable, &conn_key ); if ( conn_val ) { - conn_val->closeframe = pinfo->fd->num; + conn_val->close_frame = pinfo->fd->num; + + /* Save the connection info for the conversation filter */ + if (!pinfo->fd->flags.visited) + p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO, conn_val); + } +} + +/* Save the connection info for the conversation filter */ +void enip_mark_connection_triad( packet_info *pinfo, guint16 ConnSerialNumber, guint16 VendorID, guint32 DeviceSerialNumber ) +{ + enip_conn_key_t conn_key; + enip_conn_val_t *conn_val; + + conn_key.ConnSerialNumber = ConnSerialNumber; + conn_key.VendorID = VendorID; + conn_key.DeviceSerialNumber = DeviceSerialNumber; + conn_key.O2TConnID = 0; + conn_key.T2OConnID = 0; + + conn_val = (enip_conn_val_t *)g_hash_table_lookup( enip_conn_hashtable, &conn_key ); + if ( conn_val ) + { + p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO, conn_val); } } @@ -1077,7 +1171,7 @@ enip_get_explicit_connid(packet_info *pinfo, enip_request_key_t *prequest_key, g break; } - if ((conn_val == NULL ) || (conn_val->openframe > pinfo->fd->num)) + if ((conn_val == NULL ) || (conn_val->open_reply_frame > pinfo->fd->num)) return 0; return conn_val->connid; @@ -1125,7 +1219,7 @@ enip_get_io_connid(packet_info *pinfo, guint32 connid, enum enip_connid_type* pc *pconnid_type = ECIDT_O2T; } - if ((conn_val == NULL) || ( conn_val->openframe > pinfo->fd->num )) + if ((conn_val == NULL) || ( conn_val->open_reply_frame > pinfo->fd->num )) return NULL; return conn_val; @@ -1698,7 +1792,7 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb, /* Call dissector for interface */ next_tvb = tvb_new_subset( tvb, offset+6, item_length, item_length ); - p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, 0, request_info); + p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO, request_info); if ( tvb_length_remaining(next_tvb, 0) <= 0 || !dissector_try_uint(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, dissector_tree) ) { /* Show the undissected payload */ @@ -1726,7 +1820,7 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb, } else { - p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, 0); + p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO); } break; @@ -1753,14 +1847,14 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb, /* Call dissector for interface */ next_tvb = tvb_new_subset (tvb, offset+8, item_length-2, item_length-2); - p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, 0, request_info); + p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO, request_info); if ( tvb_length_remaining(next_tvb, 0) <= 0 || !dissector_try_uint(subdissector_sud_table, ifacehndl, next_tvb, pinfo, dissector_tree) ) { /* Show the undissected payload */ if ( tvb_length_remaining(tvb, offset) > 0 ) call_dissector( data_handle, next_tvb, pinfo, dissector_tree ); } - p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, 0); + p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO); } else { @@ -1812,6 +1906,10 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb, proto_tree_add_item(item_tree, hf_enip_connection_transport_data, tvb, offset+6+(item_length-io_length), io_length, ENC_NA); } + + /* Save the connection info for the conversation filter */ + if (!pinfo->fd->flags.visited) + p_add_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO, conn_info); } else { @@ -1922,7 +2020,7 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb, if ((FwdOpen == TRUE) || (FwdOpenReply == TRUE)) { - request_info = (enip_request_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, 0); + request_info = (enip_request_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO); if (request_info != NULL) { if (item == SOCK_ADR_INFO_OT) @@ -1992,16 +2090,16 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb, /* See if there is a CIP connection to establish */ if (FwdOpenReply == TRUE) { - request_info = (enip_request_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, 0); + request_info = (enip_request_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO); if (request_info != NULL) { enip_open_cip_connection(pinfo, request_info->cip_info->connInfo); } - p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, 0); + p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO); } else if (FwdOpen == TRUE) { - p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, 0); + p_remove_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO); } } /* end of dissect_cpf() */ @@ -3603,6 +3701,9 @@ proto_register_enip(void) proto_register_field_array(proto_dlr, hfdlr, array_length(hfdlr)); proto_register_subtree_array(ettdlr, array_length(ettdlr)); + register_dissector_filter("ENIP IO", enip_io_conv_valid, enip_io_conv_filter); + register_dissector_filter("ENIP Explicit", enip_exp_conv_valid, enip_exp_conv_filter); + } /* end of proto_register_enip() */ diff --git a/epan/dissectors/packet-enip.h b/epan/dissectors/packet-enip.h index 57e9b43b9e..03235dcb81 100644 --- a/epan/dissectors/packet-enip.h +++ b/epan/dissectors/packet-enip.h @@ -105,7 +105,12 @@ typedef struct { enum enip_connid_type {ECIDT_UNKNOWN, ECIDT_O2T, ECIDT_T2O}; +/* proto_data types */ +#define ENIP_REQUEST_INFO 0 +#define ENIP_CONNECTION_INFO 1 + void enip_close_cip_connection( packet_info *pinfo, guint16 ConnSerialNumber, guint16 VendorID, guint32 DeviceSerialNumber ); +void enip_mark_connection_triad( packet_info *pinfo, guint16 ConnSerialNumber, guint16 VendorID, guint32 DeviceSerialNumber ); extern attribute_info_t enip_attribute_vals[45]; |