NGAP: fix dissection of multiple NGAP messages in the same HTTP2 packet

Also add dissection for more containers
This commit is contained in:
Pascal Quantin 2021-06-19 20:01:27 +02:00 committed by Wireshark GitLab Utility
parent 6912666568
commit 3ea51dba87
5 changed files with 269 additions and 149 deletions

View File

@ -123,6 +123,9 @@ libwsutil.so.0 libwsutil0 #MINVER#
json_dumper_value_string@Base 2.9.0
json_dumper_value_va_list@Base 2.9.1
json_dumper_write_base64@Base 2.9.1
json_get_array@Base 3.5.0
json_get_array_index@Base 3.5.0
json_get_array_len@Base 3.5.0
json_get_double@Base 3.1.0
json_get_object@Base 3.1.0
json_get_string@Base 3.1.0

View File

@ -589,15 +589,42 @@ dissect_ngap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
return dissect_NGAP_PDU_PDU(tvb, pinfo, ngap_tree, NULL);
}
static gboolean
find_n2_info_content(char *json_data, jsmntok_t *token, const char *n2_info_content,
const char *content_id, dissector_handle_t *subdissector)
{
jsmntok_t *n2_info_content_token, *ngap_data_token;
char *str;
gdouble ngap_msg_type;
n2_info_content_token = json_get_object(json_data, token, n2_info_content);
if (!n2_info_content_token)
return FALSE;
ngap_data_token = json_get_object(json_data, n2_info_content_token, "ngapData");
if (!ngap_data_token)
return FALSE;
str = json_get_string(json_data, ngap_data_token, "contentId");
if (!str || strcmp(str, content_id))
return FALSE;
str = json_get_string(json_data, n2_info_content_token, "ngapIeType");
if (str)
*subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
else if (json_get_double(json_data, n2_info_content_token, "ngapMessageType", &ngap_msg_type))
*subdissector = ngap_handle;
else
*subdissector = NULL;
return TRUE;
}
/* 3GPP TS 29.502 chapter 6.1.6.4.3 and 29.518 chapter 6.1.6.4.3 */
static int
dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
int ret;
char *json_data;
const char *n2_info_class, *str, *content_id_str;
jsmntok_t *tokens, *cur_tok, *n2_info_content_tok;
dissector_handle_t subdissector;
const char *n2_info_class;
jsmntok_t *tokens, *cur_tok;
dissector_handle_t subdissector = NULL;
tvbuff_t* json_tvb = (tvbuff_t*)p_get_proto_data(pinfo->pool, pinfo, proto_json, 0);
http_message_info_t *message_info = (http_message_info_t *)data;
@ -618,81 +645,85 @@ dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
}
if (cur_tok) {
n2_info_class = json_get_string(json_data, cur_tok, "n2InformationClass");
if (!n2_info_class)
return 0;
if (!strcmp(n2_info_class, "SM")) {
cur_tok = json_get_object(json_data, cur_tok, "smInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent");
if (!n2_info_content_tok)
return 0;
str = json_get_string(json_data, n2_info_content_tok, "ngapIeType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else if (!strcmp(n2_info_class, "RAN")) {
cur_tok = json_get_object(json_data, cur_tok, "ranInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent");
if (!n2_info_content_tok)
return 0;
str = json_get_string(json_data, n2_info_content_tok, "ngapIeType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else if (!strcmp(n2_info_class, "NRPPa")) {
cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "nrppaPdu");
if (!n2_info_content_tok)
return 0;
str = json_get_string(json_data, n2_info_content_tok, "ngapIeType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else if (!strcmp(n2_info_class, "PWS") ||
!strcmp(n2_info_class, "PWS-BCAL") ||
!strcmp(n2_info_class, "PWS-RF")) {
cur_tok = json_get_object(json_data, cur_tok, "pwsInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "pwsContainer");
if (!n2_info_content_tok)
return 0;
subdissector = ngap_handle;
} else {
return 0;
}
cur_tok = json_get_object(json_data, n2_info_content_tok, "ngapData");
if (!cur_tok)
return 0;
content_id_str = json_get_string(json_data, cur_tok, "contentId");
} else {
cur_tok = json_get_object(json_data, tokens, "n2SmInfo");
if (cur_tok) {
content_id_str = json_get_string(json_data, cur_tok, "contentId");
str = json_get_string(json_data, tokens, "n2SmInfoType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else {
return 0;
if (n2_info_class) {
if (!strcmp(n2_info_class, "SM")) {
cur_tok = json_get_object(json_data, cur_tok, "smInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent",
message_info->content_id, &subdissector))
goto found;
}
if (!strcmp(n2_info_class, "RAN")) {
cur_tok = json_get_object(json_data, cur_tok, "ranInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent",
message_info->content_id, &subdissector))
goto found;
}
if (!strcmp(n2_info_class, "NRPPa")) {
cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "nrppaPdu",
message_info->content_id, &subdissector))
goto found;
}
if (!strcmp(n2_info_class, "PWS") ||
!strcmp(n2_info_class, "PWS-BCAL") ||
!strcmp(n2_info_class, "PWS-RF")) {
cur_tok = json_get_object(json_data, cur_tok, "pwsInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "pwsContainer",
message_info->content_id, &subdissector))
goto found;
}
}
}
cur_tok = json_get_object(json_data, tokens, "n2SmInfo");
if (cur_tok) {
const char *content_id_str = json_get_string(json_data, cur_tok, "contentId");
if (content_id_str && !strcmp(content_id_str, message_info->content_id)) {
const char *str = json_get_string(json_data, tokens, "n2SmInfoType");
if (str)
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
else
subdissector = NULL;
goto found;
}
}
cur_tok = json_get_array(json_data, tokens, "pduSessionList");
if (cur_tok) {
int i, count;
count = json_get_array_len(cur_tok);
for (i = 0; i < count; i++) {
jsmntok_t *array_tok = json_get_array_index(cur_tok, i);
if (find_n2_info_content(json_data, array_tok, "n2InfoContent",
message_info->content_id, &subdissector))
goto found;
}
}
if (find_n2_info_content(json_data, tokens, "sourceToTargetData",
message_info->content_id, &subdissector))
goto found;
if (find_n2_info_content(json_data, tokens, "targetToSourceData",
message_info->content_id, &subdissector))
goto found;
if (find_n2_info_content(json_data, tokens, "targetToSourceFailureData",
message_info->content_id, &subdissector))
goto found;
if (find_n2_info_content(json_data, tokens, "ueRadioCapability",
message_info->content_id, &subdissector))
goto found;
found:
if (subdissector) {
proto_item *ngap_item;
proto_tree *ngap_tree;
gboolean save_writable;
if (!content_id_str || strcmp(content_id_str, message_info->content_id))
return 0;
col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "NGAP");
ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA);
ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap);
gboolean save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL);
if (subdissector != ngap_handle) {
ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA);
ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap);
} else {
ngap_tree = tree;
}
save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL);
col_set_writable(pinfo->cinfo, COL_PROTOCOL, FALSE);
call_dissector_with_data(subdissector, tvb, pinfo, ngap_tree, NULL);
col_set_writable(pinfo->cinfo, COL_PROTOCOL, save_writable);

View File

@ -21605,15 +21605,42 @@ dissect_ngap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
return dissect_NGAP_PDU_PDU(tvb, pinfo, ngap_tree, NULL);
}
static gboolean
find_n2_info_content(char *json_data, jsmntok_t *token, const char *n2_info_content,
const char *content_id, dissector_handle_t *subdissector)
{
jsmntok_t *n2_info_content_token, *ngap_data_token;
char *str;
gdouble ngap_msg_type;
n2_info_content_token = json_get_object(json_data, token, n2_info_content);
if (!n2_info_content_token)
return FALSE;
ngap_data_token = json_get_object(json_data, n2_info_content_token, "ngapData");
if (!ngap_data_token)
return FALSE;
str = json_get_string(json_data, ngap_data_token, "contentId");
if (!str || strcmp(str, content_id))
return FALSE;
str = json_get_string(json_data, n2_info_content_token, "ngapIeType");
if (str)
*subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
else if (json_get_double(json_data, n2_info_content_token, "ngapMessageType", &ngap_msg_type))
*subdissector = ngap_handle;
else
*subdissector = NULL;
return TRUE;
}
/* 3GPP TS 29.502 chapter 6.1.6.4.3 and 29.518 chapter 6.1.6.4.3 */
static int
dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
int ret;
char *json_data;
const char *n2_info_class, *str, *content_id_str;
jsmntok_t *tokens, *cur_tok, *n2_info_content_tok;
dissector_handle_t subdissector;
const char *n2_info_class;
jsmntok_t *tokens, *cur_tok;
dissector_handle_t subdissector = NULL;
tvbuff_t* json_tvb = (tvbuff_t*)p_get_proto_data(pinfo->pool, pinfo, proto_json, 0);
http_message_info_t *message_info = (http_message_info_t *)data;
@ -21634,81 +21661,85 @@ dissect_ngap_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
}
if (cur_tok) {
n2_info_class = json_get_string(json_data, cur_tok, "n2InformationClass");
if (!n2_info_class)
return 0;
if (!strcmp(n2_info_class, "SM")) {
cur_tok = json_get_object(json_data, cur_tok, "smInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent");
if (!n2_info_content_tok)
return 0;
str = json_get_string(json_data, n2_info_content_tok, "ngapIeType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else if (!strcmp(n2_info_class, "RAN")) {
cur_tok = json_get_object(json_data, cur_tok, "ranInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "n2InfoContent");
if (!n2_info_content_tok)
return 0;
str = json_get_string(json_data, n2_info_content_tok, "ngapIeType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else if (!strcmp(n2_info_class, "NRPPa")) {
cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "nrppaPdu");
if (!n2_info_content_tok)
return 0;
str = json_get_string(json_data, n2_info_content_tok, "ngapIeType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else if (!strcmp(n2_info_class, "PWS") ||
!strcmp(n2_info_class, "PWS-BCAL") ||
!strcmp(n2_info_class, "PWS-RF")) {
cur_tok = json_get_object(json_data, cur_tok, "pwsInfo");
if (!cur_tok)
return 0;
n2_info_content_tok = json_get_object(json_data, cur_tok, "pwsContainer");
if (!n2_info_content_tok)
return 0;
subdissector = ngap_handle;
} else {
return 0;
}
cur_tok = json_get_object(json_data, n2_info_content_tok, "ngapData");
if (!cur_tok)
return 0;
content_id_str = json_get_string(json_data, cur_tok, "contentId");
} else {
cur_tok = json_get_object(json_data, tokens, "n2SmInfo");
if (cur_tok) {
content_id_str = json_get_string(json_data, cur_tok, "contentId");
str = json_get_string(json_data, tokens, "n2SmInfoType");
if (!str)
return 0;
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
} else {
return 0;
if (n2_info_class) {
if (!strcmp(n2_info_class, "SM")) {
cur_tok = json_get_object(json_data, cur_tok, "smInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent",
message_info->content_id, &subdissector))
goto found;
}
if (!strcmp(n2_info_class, "RAN")) {
cur_tok = json_get_object(json_data, cur_tok, "ranInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "n2InfoContent",
message_info->content_id, &subdissector))
goto found;
}
if (!strcmp(n2_info_class, "NRPPa")) {
cur_tok = json_get_object(json_data, cur_tok, "nrppaInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "nrppaPdu",
message_info->content_id, &subdissector))
goto found;
}
if (!strcmp(n2_info_class, "PWS") ||
!strcmp(n2_info_class, "PWS-BCAL") ||
!strcmp(n2_info_class, "PWS-RF")) {
cur_tok = json_get_object(json_data, cur_tok, "pwsInfo");
if (cur_tok && find_n2_info_content(json_data, cur_tok, "pwsContainer",
message_info->content_id, &subdissector))
goto found;
}
}
}
cur_tok = json_get_object(json_data, tokens, "n2SmInfo");
if (cur_tok) {
const char *content_id_str = json_get_string(json_data, cur_tok, "contentId");
if (content_id_str && !strcmp(content_id_str, message_info->content_id)) {
const char *str = json_get_string(json_data, tokens, "n2SmInfoType");
if (str)
subdissector = dissector_get_string_handle(ngap_n2_ie_type_dissector_table, str);
else
subdissector = NULL;
goto found;
}
}
cur_tok = json_get_array(json_data, tokens, "pduSessionList");
if (cur_tok) {
int i, count;
count = json_get_array_len(cur_tok);
for (i = 0; i < count; i++) {
jsmntok_t *array_tok = json_get_array_index(cur_tok, i);
if (find_n2_info_content(json_data, array_tok, "n2InfoContent",
message_info->content_id, &subdissector))
goto found;
}
}
if (find_n2_info_content(json_data, tokens, "sourceToTargetData",
message_info->content_id, &subdissector))
goto found;
if (find_n2_info_content(json_data, tokens, "targetToSourceData",
message_info->content_id, &subdissector))
goto found;
if (find_n2_info_content(json_data, tokens, "targetToSourceFailureData",
message_info->content_id, &subdissector))
goto found;
if (find_n2_info_content(json_data, tokens, "ueRadioCapability",
message_info->content_id, &subdissector))
goto found;
found:
if (subdissector) {
proto_item *ngap_item;
proto_tree *ngap_tree;
gboolean save_writable;
if (!content_id_str || strcmp(content_id_str, message_info->content_id))
return 0;
col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "NGAP");
ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA);
ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap);
gboolean save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL);
if (subdissector != ngap_handle) {
ngap_item = proto_tree_add_item(tree, proto_ngap, tvb, 0, -1, ENC_NA);
ngap_tree = proto_item_add_subtree(ngap_item, ett_ngap);
} else {
ngap_tree = tree;
}
save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL);
col_set_writable(pinfo->cinfo, COL_PROTOCOL, FALSE);
call_dissector_with_data(subdissector, tvb, pinfo, ngap_tree, NULL);
col_set_writable(pinfo->cinfo, COL_PROTOCOL, save_writable);
@ -22151,7 +22182,7 @@ proto_reg_handoff_ngap(void)
/*--- End of included file: packet-ngap-dis-tab.c ---*/
#line 724 "./asn1/ngap/packet-ngap-template.c"
#line 755 "./asn1/ngap/packet-ngap-template.c"
dissector_add_string("media_type", "application/vnd.3gpp.ngap", ngap_media_type_handle);
} else {
@ -26820,7 +26851,7 @@ void proto_register_ngap(void) {
"UnsuccessfulOutcome_value", HFILL }},
/*--- End of included file: packet-ngap-hfarr.c ---*/
#line 992 "./asn1/ngap/packet-ngap-template.c"
#line 1023 "./asn1/ngap/packet-ngap-template.c"
};
/* List of subtrees */
@ -27475,7 +27506,7 @@ void proto_register_ngap(void) {
&ett_ngap_UnsuccessfulOutcome,
/*--- End of included file: packet-ngap-ettarr.c ---*/
#line 1039 "./asn1/ngap/packet-ngap-template.c"
#line 1070 "./asn1/ngap/packet-ngap-template.c"
};
static ei_register_info ei[] = {

View File

@ -99,7 +99,7 @@ jsmntok_t *json_get_next_object(jsmntok_t *cur)
return next;
}
jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const gchar* name)
jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const char *name)
{
int i;
jsmntok_t *cur = parent+1;
@ -116,7 +116,44 @@ jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const gchar* name
return NULL;
}
char *json_get_string(char *buf, jsmntok_t *parent, const gchar* name)
jsmntok_t *json_get_array(const char *buf, jsmntok_t *parent, const char *name)
{
int i;
jsmntok_t *cur = parent+1;
for (i = 0; i < parent->size; i++) {
if (cur->type == JSMN_STRING &&
!strncmp(&buf[cur->start], name, cur->end - cur->start)
&& strlen(name) == (size_t)(cur->end - cur->start) &&
cur->size == 1 && (cur+1)->type == JSMN_ARRAY) {
return cur+1;
}
cur = json_get_next_object(cur);
}
return NULL;
}
int json_get_array_len(jsmntok_t *array)
{
if (array->type != JSMN_ARRAY)
return -1;
return array->size;
}
jsmntok_t *json_get_array_index(jsmntok_t *array, int idx)
{
int i;
jsmntok_t *cur = array+1;
if (array->type != JSMN_ARRAY || idx < 0 || idx >= array->size)
return NULL;
for (i = 0; i < idx; i++)
cur = json_get_next_object(cur);
return cur;
}
char *json_get_string(char *buf, jsmntok_t *parent, const char *name)
{
int i;
jsmntok_t *cur = parent+1;
@ -136,7 +173,7 @@ char *json_get_string(char *buf, jsmntok_t *parent, const gchar* name)
return NULL;
}
gboolean json_get_double(char *buf, jsmntok_t *parent, const gchar* name, gdouble *val)
gboolean json_get_double(char *buf, jsmntok_t *parent, const char *name, gdouble *val)
{
int i;
jsmntok_t *cur = parent+1;

View File

@ -33,20 +33,38 @@ WS_DLL_PUBLIC int json_parse(const char *buf, jsmntok_t *tokens, unsigned int ma
* Get the pointer to an object belonging to parent object and named as the name variable.
* Returns NULL if not found.
*/
WS_DLL_PUBLIC jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const gchar* name);
WS_DLL_PUBLIC jsmntok_t *json_get_object(const char *buf, jsmntok_t *parent, const char *name);
/**
* Get the pointer to an array belonging to parent object and named as the name variable.
* Returns NULL if not found.
*/
WS_DLL_PUBLIC jsmntok_t *json_get_array(const char *buf, jsmntok_t *parent, const char *name);
/**
* Get the number of elements of an array.
* Returns -1 if the JSON objecct is not an array.
*/
WS_DLL_PUBLIC int json_get_array_len(jsmntok_t *array);
/**
* Get the pointer to idx element of an array.
* Returns NULL if not found.
*/
WS_DLL_PUBLIC jsmntok_t *json_get_array_index(jsmntok_t *parent, int idx);
/**
* Get the unescaped value of a string object belonging to parent object and named as the name variable.
* Returns NULL if not found. Caution: it modifies input buffer.
*/
WS_DLL_PUBLIC char *json_get_string(char *buf, jsmntok_t *parent, const gchar* name);
WS_DLL_PUBLIC char *json_get_string(char *buf, jsmntok_t *parent, const char *name);
/**
* Get the value of a number object belonging to parent object and named as the name variable.
* Returns FALSE if not found. Caution: it modifies input buffer.
* Scientific notation not supported yet.
*/
WS_DLL_PUBLIC gboolean json_get_double(char *buf, jsmntok_t *parent, const gchar* name, gdouble *val);
WS_DLL_PUBLIC gboolean json_get_double(char *buf, jsmntok_t *parent, const char *name, gdouble *val);
/**
* Decode the contents of a JSON string value by overwriting the input data.