Try to determine MTP3 Standard heuristically, original code

from Jeff Morris refactored a bit by me.

svn path=/trunk/; revision=40776
This commit is contained in:
Anders Broman 2012-01-30 19:47:35 +00:00
parent 0ee76da516
commit ed5c6cfd71
3 changed files with 282 additions and 51 deletions

View File

@ -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));
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;
proto_tree *mtp3_tree = NULL;
/* Set up structures needed to add the protocol subtree and manage it */
proto_item *mtp3_item = NULL, *gen_item;
proto_tree *mtp3_tree = NULL;
/* Make entries in Protocol column on summary display */
switch(mtp3_standard) {
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) {
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));
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);
/* 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);
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));
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_rec->si_code = (tvb_get_guint8(tvb, SIO_OFFSET) & SERVICE_INDICATOR_MASK);
tap_rec->size = tvb_length(tvb);
tap_rec->si_code = (tvb_get_guint8(tvb, SIO_OFFSET) & SERVICE_INDICATOR_MASK);
tap_rec->size = tvb_length(tvb);
tap_queue_packet(mtp3_tap, pinfo, tap_rec);
tap_queue_packet(mtp3_tap, pinfo, tap_rec);
dissect_mtp3_payload(tvb, pinfo, tree);
pinfo->private_data = pd_save;
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);

View File

@ -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);

View File

@ -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