summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-mtp3.c153
-rw-r--r--epan/dissectors/packet-sccp.c181
-rw-r--r--epan/dissectors/packet-sccp.h1
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