diff options
-rw-r--r-- | epan/dissectors/packet-mtp3.c | 153 | ||||
-rw-r--r-- | epan/dissectors/packet-sccp.c | 181 | ||||
-rw-r--r-- | epan/dissectors/packet-sccp.h | 1 |
3 files changed, 283 insertions, 52 deletions
diff --git a/epan/dissectors/packet-mtp3.c b/epan/dissectors/packet-mtp3.c index bdc2962ef2..d8f75370ea 100644 --- a/epan/dissectors/packet-mtp3.c +++ b/epan/dissectors/packet-mtp3.c @@ -49,6 +49,7 @@ #include <epan/prefs.h> #include <epan/emem.h> #include "packet-q708.h" +#include "packet-sccp.h" /* Initialize the protocol and registered fields */ static int proto_mtp3 = -1; @@ -120,6 +121,7 @@ gint mtp3_standard = ITU_STANDARD; static gboolean mtp3_use_ansi_5_bit_sls = FALSE; static gboolean mtp3_use_japan_5_bit_sls = FALSE; static gboolean mtp3_show_itu_priority = FALSE; +static gboolean mtp3_heuristic_standard = FALSE; static gint mtp3_addr_fmt = MTP3_ADDR_FMT_DASHED; static mtp3_addr_pc_t* mtp3_addr_dpc; static mtp3_addr_pc_t* mtp3_addr_opc; @@ -644,69 +646,127 @@ dissect_mtp3_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) call_dissector(data_handle, payload_tvb, pinfo, tree); } +#define HEURISTIC_FAILED_STANDARD 0xffff +static guint +heur_mtp3_standard(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint8 si) +{ + + guint32 len; + tvbuff_t *payload; + + len = tvb_length(tvb); + switch (si) { + case 3: + { + payload = tvb_new_subset(tvb, ITU_HEADER_LENGTH, len-ITU_HEADER_LENGTH, len-ITU_HEADER_LENGTH); + if (looks_like_valid_sccp(payload, ITU_STANDARD)) { + return ITU_STANDARD; + } + payload = tvb_new_subset(tvb, ANSI_HEADER_LENGTH, len-ANSI_HEADER_LENGTH, len-ANSI_HEADER_LENGTH); + if (looks_like_valid_sccp(payload, ANSI_STANDARD)) { + return ANSI_STANDARD; + } + payload = tvb_new_subset(tvb, ANSI_HEADER_LENGTH, len-ANSI_HEADER_LENGTH, len-ANSI_HEADER_LENGTH); + if (looks_like_valid_sccp(payload, CHINESE_ITU_STANDARD)) { + return CHINESE_ITU_STANDARD; + } + payload = tvb_new_subset(tvb, JAPAN_HEADER_LENGTH, len-JAPAN_HEADER_LENGTH, len-JAPAN_HEADER_LENGTH); + if (looks_like_valid_sccp(payload, JAPAN_STANDARD)) { + return JAPAN_STANDARD; + } + + return HEURISTIC_FAILED_STANDARD; + + } + default: + return HEURISTIC_FAILED_STANDARD; + } + +} + +static const value_string mtp3_standard_vals[] = { + { ITU_STANDARD, "ITU_STANDARD" }, + { ANSI_STANDARD, "ANSI_STANDARD" }, + { CHINESE_ITU_STANDARD, "CHINESE_ITU_STANDARD" }, + { JAPAN_STANDARD, "JAPAN_STANDARD" }, + { 0, NULL } +}; + /* Code to actually dissect the packets */ static void dissect_mtp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - void* pd_save; - mtp3_tap_rec_t* tap_rec = ep_alloc0(sizeof(mtp3_tap_rec_t)); - - /* Set up structures needed to add the protocol subtree and manage it */ - proto_item *mtp3_item = NULL; - proto_tree *mtp3_tree = NULL; + void* pd_save; + mtp3_tap_rec_t* tap_rec = ep_alloc0(sizeof(mtp3_tap_rec_t)); + guint heuristic_standard, pref_mtp3_standard; + guint8 si; + + /* Set up structures needed to add the protocol subtree and manage it */ + proto_item *mtp3_item = NULL, *gen_item; + proto_tree *mtp3_tree = NULL; + + pref_mtp3_standard = mtp3_standard; + + mtp3_item = proto_tree_add_item(tree, proto_mtp3, tvb, 0, 0, ENC_NA); + + si = tvb_get_guint8(tvb, SIO_OFFSET) & SERVICE_INDICATOR_MASK; + if (mtp3_heuristic_standard) { + heuristic_standard = heur_mtp3_standard(tvb, pinfo, tree, si); + if(heuristic_standard==HEURISTIC_FAILED_STANDARD){ + gen_item = proto_tree_add_text(tree, tvb, 0, 0, "Could not determine Heuristic using %s", val_to_str(mtp3_standard, mtp3_standard_vals, "unknown")); + }else{ + gen_item = proto_tree_add_text(tree, tvb, 0, 0, "%s", val_to_str(heuristic_standard, mtp3_standard_vals, "unknown")); + mtp3_standard = heuristic_standard; + } + PROTO_ITEM_SET_GENERATED(gen_item); + } - /* Make entries in Protocol column on summary display */ - switch(mtp3_standard) { + /* Make entries in Protocol column on summary display */ + switch(mtp3_standard) { case ITU_STANDARD: - col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (Int. ITU)"); - break; + col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (Int. ITU)"); + proto_item_set_len(mtp3_item, ITU_HEADER_LENGTH); + break; case ANSI_STANDARD: - col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (ANSI)"); - break; + col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (ANSI)"); + proto_item_set_len(mtp3_item, ANSI_HEADER_LENGTH); + break; case CHINESE_ITU_STANDARD: - col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (Chin. ITU)"); - break; + col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (Chin. ITU)"); + proto_item_set_len(mtp3_item, ANSI_HEADER_LENGTH); + break; case JAPAN_STANDARD: - col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (Japan)"); - break; + col_set_str(pinfo->cinfo, COL_PROTOCOL, "MTP3 (Japan)"); + proto_item_set_len(mtp3_item, JAPAN_HEADER_LENGTH); + break; }; - if (tree) { - /* create display subtree for the protocol */ - switch (mtp3_standard) { - case ITU_STANDARD: - mtp3_item = proto_tree_add_item(tree, proto_mtp3, tvb, 0, ITU_HEADER_LENGTH, ENC_NA); - break; - case ANSI_STANDARD: - case CHINESE_ITU_STANDARD: - mtp3_item = proto_tree_add_item(tree, proto_mtp3, tvb, 0, ANSI_HEADER_LENGTH, ENC_NA); - break; - case JAPAN_STANDARD: - mtp3_item = proto_tree_add_item(tree, proto_mtp3, tvb, 0, JAPAN_HEADER_LENGTH, ENC_NA); - break; + if (tree) { + /* create display subtree for the protocol */ + mtp3_tree = proto_item_add_subtree(mtp3_item, ett_mtp3); } - mtp3_tree = proto_item_add_subtree(mtp3_item, ett_mtp3); - } + mtp3_addr_opc = ep_alloc0(sizeof(mtp3_addr_pc_t)); + mtp3_addr_dpc = ep_alloc0(sizeof(mtp3_addr_pc_t)); + + /* Dissect the packet (even if !tree so can call sub-dissectors and update + * the source and destination address columns) */ + dissect_mtp3_sio(tvb, pinfo, mtp3_tree, &pd_save); + dissect_mtp3_routing_label(tvb, pinfo, mtp3_tree); - mtp3_addr_opc = ep_alloc0(sizeof(mtp3_addr_pc_t)); - mtp3_addr_dpc = ep_alloc0(sizeof(mtp3_addr_pc_t)); + memcpy(&(tap_rec->addr_opc),mtp3_addr_opc,sizeof(mtp3_addr_pc_t)); + memcpy(&(tap_rec->addr_dpc),mtp3_addr_dpc,sizeof(mtp3_addr_pc_t)); - /* Dissect the packet (even if !tree so can call sub-dissectors and update - * the source and destination address columns) */ - dissect_mtp3_sio(tvb, pinfo, mtp3_tree, &pd_save); - dissect_mtp3_routing_label(tvb, pinfo, mtp3_tree); + tap_rec->si_code = (tvb_get_guint8(tvb, SIO_OFFSET) & SERVICE_INDICATOR_MASK); + tap_rec->size = tvb_length(tvb); - memcpy(&(tap_rec->addr_opc),mtp3_addr_opc,sizeof(mtp3_addr_pc_t)); - memcpy(&(tap_rec->addr_dpc),mtp3_addr_dpc,sizeof(mtp3_addr_pc_t)); + tap_queue_packet(mtp3_tap, pinfo, tap_rec); - tap_rec->si_code = (tvb_get_guint8(tvb, SIO_OFFSET) & SERVICE_INDICATOR_MASK); - tap_rec->size = tvb_length(tvb); + dissect_mtp3_payload(tvb, pinfo, tree); + pinfo->private_data = pd_save; - tap_queue_packet(mtp3_tap, pinfo, tap_rec); + mtp3_standard = pref_mtp3_standard; - dissect_mtp3_payload(tvb, pinfo, tree); - pinfo->private_data = pd_save; } void @@ -806,6 +866,11 @@ proto_register_mtp3(void) mtp3_module = prefs_register_protocol(proto_mtp3, NULL); + prefs_register_bool_preference(mtp3_module, "heuristic_standard", + "Try to determine the MTP3 standard heuristically", + "This only works for SCCP traffic for now", + &mtp3_heuristic_standard); + prefs_register_enum_preference(mtp3_module, "standard", "MTP3 standard", "The SS7 standard used in MTP3 packets", &mtp3_standard, mtp3_options, FALSE); diff --git a/epan/dissectors/packet-sccp.c b/epan/dissectors/packet-sccp.c index e7c0377ec8..47f2c9e30b 100644 --- a/epan/dissectors/packet-sccp.c +++ b/epan/dissectors/packet-sccp.c @@ -818,6 +818,171 @@ static const value_string assoc_protos[] = { { 0, NULL } }; +gboolean +sccp_called_calling_looks_valid(tvbuff_t *tvb, guint8 my_mtp3_standard) +{ + guint8 ai, ri, gti, ssni, pci; + + /* TVB starts with parameter length */ + ai = tvb_get_guint8(tvb, 1); + if (my_mtp3_standard == ANSI_STANDARD && (ai & ANSI_NATIONAL_MASK) == 0) + return FALSE; + + gti = (ai & GTI_MASK) >> GTI_SHIFT; + if (my_mtp3_standard == ANSI_STANDARD) { + if (gti > 2) + return FALSE; + } else { + if (gti > 4) + return FALSE; + } + + ri = ai & ROUTING_INDICATOR_MASK >> ROUTING_INDICATOR_SHIFT; + if (my_mtp3_standard == ANSI_STANDARD) { + pci = ai & ANSI_PC_INDICATOR_MASK; + ssni = ai & ANSI_SSN_INDICATOR_MASK; + } else { + ssni = ai & ITU_SSN_INDICATOR_MASK; + pci = ai & ITU_PC_INDICATOR_MASK; + } + + /* Route on SSN with no SSN? */ + if (ri == ROUTE_ON_SSN && ssni == 0) + return FALSE; + /* Route on GT with no GT? */ + if (ri != ROUTE_ON_SSN && gti == AI_GTI_NO_GT) + return FALSE; + + return TRUE; +} + +gboolean +looks_like_valid_sccp(tvbuff_t *tvb, guint8 my_mtp3_standard) +{ + guint8 msgtype, msg_class, cause, offset; + guint16 called_ptr = 0; + guint16 calling_ptr = 0; + guint16 data_ptr = 0; + guint16 opt_ptr = 0; + guint32 len = tvb_length(tvb); + + /* Ensure we can do some basic checks without throwing an exception. + * Accesses beyond this length need to check the length first because + * we don't want to throw an exception in here... + */ + if (len < 6) + return FALSE; + + msgtype = tvb_get_guint8(tvb, SCCP_MSG_TYPE_OFFSET); + if (!match_strval(msgtype, sccp_message_type_acro_values)) { + return FALSE; + } + offset = SCCP_MSG_TYPE_LENGTH; + + /* + Still to be done: + SCCP_MSG_TYPE_RLSD + SCCP_MSG_TYPE_RLC + SCCP_MSG_TYPE_DT1 + SCCP_MSG_TYPE_DT2 + SCCP_MSG_TYPE_AK + SCCP_MSG_TYPE_UDTS + SCCP_MSG_TYPE_ED + SCCP_MSG_TYPE_EA + SCCP_MSG_TYPE_RSR + SCCP_MSG_TYPE_RSC + SCCP_MSG_TYPE_ERR + SCCP_MSG_TYPE_IT + SCCP_MSG_TYPE_XUDTS + SCCP_MSG_TYPE_LUDT + SCCP_MSG_TYPE_LUDTS + */ + + switch (msgtype) { + case SCCP_MSG_TYPE_DT1: /* 6 */ + if(len<8){ + /* Mandatory parameter(data)+ at least one data */ + return FALSE; + } + data_ptr = tvb_get_guint8(tvb, offset+DESTINATION_LOCAL_REFERENCE_LENGTH+1); + if(tvb_get_guint8(tvb, data_ptr) > len){ + return FALSE; + } + break; + case SCCP_MSG_TYPE_DT2: /* 7 */ + g_warning("Unhandled msg type %u", msgtype); + return FALSE; + break; + case SCCP_MSG_TYPE_UDT: + case SCCP_MSG_TYPE_XUDT: /* 0x11 */ + { + /* Class lower four bits */ + msg_class = tvb_get_guint8(tvb, offset)&0x0f; + if (msg_class > 1) + return FALSE; + offset += PROTOCOL_CLASS_LENGTH; + + if (msgtype == SCCP_MSG_TYPE_XUDT) + offset += HOP_COUNTER_LENGTH; + + called_ptr = tvb_get_guint8(tvb, offset) + offset; + calling_ptr = tvb_get_guint8(tvb, offset+1) + offset+1; + data_ptr = tvb_get_guint8(tvb, offset+2) + offset+2; + if (msgtype == SCCP_MSG_TYPE_XUDT) + opt_ptr = tvb_get_guint8(tvb, offset+3) + offset+3; + + /* Check that all the pointers are within bounds */ + if (called_ptr > len || calling_ptr > len || data_ptr > len || opt_ptr > len) + return FALSE; + + /* Check that the lengths of the variable parameters are within bounds */ + if (tvb_get_guint8(tvb, called_ptr) > len || + tvb_get_guint8(tvb, calling_ptr) > len || + tvb_get_guint8(tvb, data_ptr) > len) + return FALSE; + if (msgtype == SCCP_MSG_TYPE_XUDT && tvb_get_guint8(tvb, opt_ptr) > len) + return FALSE; + } + break; + case SCCP_MSG_TYPE_CR: + { + /* Class lower four bits */ + msg_class = tvb_get_guint8(tvb, SCCP_MSG_TYPE_LENGTH+3) & 0x0f; + if (msg_class != 2) + return FALSE; + } + break; + case SCCP_MSG_TYPE_CC: /* 2 */ + { + /* Class lower four bits */ + msg_class = tvb_get_guint8(tvb, SCCP_MSG_TYPE_LENGTH+6)&0x0f; + if (msg_class != 2) + return FALSE; + } + break; + case SCCP_MSG_TYPE_CREF: + { + cause = tvb_get_guint8(tvb, SCCP_MSG_TYPE_LENGTH+3); + if (!match_strval(cause, sccp_release_cause_values)) + return FALSE; + } + break; + default: + g_warning("Unhandled msg type %u", msgtype); + return FALSE; + } + + if (called_ptr) { + guint8 param_len = tvb_get_guint8(tvb, called_ptr); + tvbuff_t *param_tvb = tvb_new_subset(tvb, called_ptr, param_len, param_len); + + if (!sccp_called_calling_looks_valid(param_tvb, my_mtp3_standard)) + return FALSE; + } + + return TRUE; +} + static sccp_assoc_info_t * new_assoc(guint32 calling, guint32 called) { @@ -1546,7 +1711,7 @@ dissect_sccp_calling_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, static void dissect_sccp_class_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint length) { - guint8 class; + guint8 msg_class; proto_item *pi; gboolean invalid_class = FALSE; @@ -1557,12 +1722,12 @@ dissect_sccp_class_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu return; } - class = tvb_get_guint8(tvb, 0) & CLASS_CLASS_MASK; - pi = proto_tree_add_uint(tree, hf_sccp_class, tvb, 0, length, class); + msg_class = tvb_get_guint8(tvb, 0) & CLASS_CLASS_MASK; + pi = proto_tree_add_uint(tree, hf_sccp_class, tvb, 0, length, msg_class); switch(message_type) { case SCCP_MSG_TYPE_DT1: - if (class != 2) + if (msg_class != 2) invalid_class = TRUE; break; case SCCP_MSG_TYPE_DT2: @@ -1571,7 +1736,7 @@ dissect_sccp_class_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu case SCCP_MSG_TYPE_EA: case SCCP_MSG_TYPE_RSR: case SCCP_MSG_TYPE_RSC: - if (class != 3) + if (msg_class != 3) invalid_class = TRUE; break; case SCCP_MSG_TYPE_CR: @@ -1581,7 +1746,7 @@ dissect_sccp_class_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu case SCCP_MSG_TYPE_RLC: case SCCP_MSG_TYPE_ERR: case SCCP_MSG_TYPE_IT: - if (class != 2 && class != 3) + if (msg_class != 2 && msg_class != 3) invalid_class = TRUE; break; case SCCP_MSG_TYPE_UDT: @@ -1590,7 +1755,7 @@ dissect_sccp_class_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu case SCCP_MSG_TYPE_XUDTS: case SCCP_MSG_TYPE_LUDT: case SCCP_MSG_TYPE_LUDTS: - if (class != 0 && class != 1) + if (msg_class != 0 && msg_class != 1) invalid_class = TRUE; break; } @@ -1598,7 +1763,7 @@ dissect_sccp_class_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu if (invalid_class) expert_add_info_format(pinfo, pi, PI_MALFORMED, PI_ERROR, "Unexpected message class for this message type"); - if (class == 0 || class == 1) { + if (msg_class == 0 || msg_class == 1) { guint8 handling = tvb_get_guint8(tvb, 0) & CLASS_SPARE_HANDLING_MASK; pi = proto_tree_add_item(tree, hf_sccp_handling, tvb, 0, length, ENC_NA); diff --git a/epan/dissectors/packet-sccp.h b/epan/dissectors/packet-sccp.h index 2a8da4ef32..d8cac11553 100644 --- a/epan/dissectors/packet-sccp.h +++ b/epan/dissectors/packet-sccp.h @@ -105,6 +105,7 @@ typedef struct _sccp_assoc_info_t { extern void reset_sccp_assoc(void); extern sccp_assoc_info_t* get_sccp_assoc(packet_info* pinfo, guint offset, guint32 src_lr, guint32 dst_lr, guint msg_type); +extern gboolean looks_like_valid_sccp(tvbuff_t *tvb, guint8 my_mtp3_standard); #define GT_SIGNAL_LENGTH 1 #define GT_ODD_SIGNAL_MASK 0x0f |