From 3f76684f916504be350de87a3fe84e374bf340c8 Mon Sep 17 00:00:00 2001 From: Nardi Ivan Date: Mon, 12 Oct 2020 11:33:03 +0200 Subject: [PATCH] CLASSIC-STUN: dissect the entire packet on first-pass Request-response tracking of STUN messages encapsulated in CLASSIC-STUN packets (via DATA attribute) doesn't work right now. The reason for this is that req-resp tracking is usually performed on first-pass, but CLASSIC-STUN attributes are not dissected on first-pass (on wireshark, at least). So the encapsulated STUN messages are never elaborated on first pass, either. --- epan/dissectors/packet-classicstun.c | 398 +++++++++++++-------------- 1 file changed, 198 insertions(+), 200 deletions(-) diff --git a/epan/dissectors/packet-classicstun.c b/epan/dissectors/packet-classicstun.c index c1cbca3788..ff224cf453 100644 --- a/epan/dissectors/packet-classicstun.c +++ b/epan/dissectors/packet-classicstun.c @@ -313,229 +313,227 @@ dissect_classicstun(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d col_add_fstr(pinfo->cinfo, COL_INFO, "Message: %s", msg_type_str); - if (tree) { - guint transaction_id_first_word; + guint transaction_id_first_word; - ti = proto_tree_add_item(tree, proto_classicstun, tvb, 0, -1, ENC_NA); + ti = proto_tree_add_item(tree, proto_classicstun, tvb, 0, -1, ENC_NA); - classicstun_tree = proto_item_add_subtree(ti, ett_classicstun); + classicstun_tree = proto_item_add_subtree(ti, ett_classicstun); - if (((msg_type & CLASS_MASK) >> 4) == REQUEST) { - if (classicstun_trans->rep_frame) { - proto_item *it; - it=proto_tree_add_uint(classicstun_tree, hf_classicstun_response_in, - tvb, 0, 0, - classicstun_trans->rep_frame); - proto_item_set_generated(it); - } + if (((msg_type & CLASS_MASK) >> 4) == REQUEST) { + if (classicstun_trans->rep_frame) { + proto_item *it; + it=proto_tree_add_uint(classicstun_tree, hf_classicstun_response_in, + tvb, 0, 0, + classicstun_trans->rep_frame); + proto_item_set_generated(it); } - else if ((((msg_type & CLASS_MASK) >> 4) == RESPONSE) || - (((msg_type & CLASS_MASK) >> 4) == ERROR_RESPONSE)) { - /* This is a response */ - if(classicstun_trans->req_frame){ - proto_item *it; - nstime_t ns; + } + else if ((((msg_type & CLASS_MASK) >> 4) == RESPONSE) || + (((msg_type & CLASS_MASK) >> 4) == ERROR_RESPONSE)) { + /* This is a response */ + if(classicstun_trans->req_frame){ + proto_item *it; + nstime_t ns; - it=proto_tree_add_uint(classicstun_tree, hf_classicstun_response_to, tvb, 0, 0, classicstun_trans->req_frame); - proto_item_set_generated(it); - - nstime_delta(&ns, &pinfo->abs_ts, &classicstun_trans->req_time); - it=proto_tree_add_time(classicstun_tree, hf_classicstun_time, tvb, 0, 0, &ns); - proto_item_set_generated(it); - } + it=proto_tree_add_uint(classicstun_tree, hf_classicstun_response_to, tvb, 0, 0, classicstun_trans->req_frame); + proto_item_set_generated(it); + nstime_delta(&ns, &pinfo->abs_ts, &classicstun_trans->req_time); + it=proto_tree_add_time(classicstun_tree, hf_classicstun_time, tvb, 0, 0, &ns); + proto_item_set_generated(it); } - proto_tree_add_uint(classicstun_tree, hf_classicstun_type, tvb, 0, 2, msg_type); - proto_tree_add_uint(classicstun_tree, hf_classicstun_length, tvb, 2, 2, msg_length); - proto_tree_add_item(classicstun_tree, hf_classicstun_id, tvb, 4, 16, ENC_NA); + } - /* Remember this (in host order) so we can show clear xor'd addresses */ - transaction_id_first_word = tvb_get_ntohl(tvb, 4); + proto_tree_add_uint(classicstun_tree, hf_classicstun_type, tvb, 0, 2, msg_type); + proto_tree_add_uint(classicstun_tree, hf_classicstun_length, tvb, 2, 2, msg_length); + proto_tree_add_item(classicstun_tree, hf_classicstun_id, tvb, 4, 16, ENC_NA); - if (msg_length > 0) { - ta = proto_tree_add_item(classicstun_tree, hf_classicstun_att, tvb, CLASSICSTUN_HDR_LEN, msg_length, ENC_NA); - att_type_tree = proto_item_add_subtree(ta, ett_classicstun_att_type); + /* Remember this (in host order) so we can show clear xor'd addresses */ + transaction_id_first_word = tvb_get_ntohl(tvb, 4); - offset = CLASSICSTUN_HDR_LEN; + if (msg_length > 0) { + ta = proto_tree_add_item(classicstun_tree, hf_classicstun_att, tvb, CLASSICSTUN_HDR_LEN, msg_length, ENC_NA); + att_type_tree = proto_item_add_subtree(ta, ett_classicstun_att_type); - while( msg_length > 0) { - att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */ - att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */ + offset = CLASSICSTUN_HDR_LEN; - att_tree = proto_tree_add_subtree_format(att_type_tree, tvb, offset, - ATTR_HDR_LEN+att_length, ett_classicstun_att, NULL, - "Attribute: %s", - val_to_str(att_type, attributes, "Unknown (0x%04x)")); + while( msg_length > 0) { + att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */ + att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */ - proto_tree_add_uint(att_tree, classicstun_att_type, tvb, - offset, 2, att_type); - offset += 2; - if (ATTR_HDR_LEN+att_length > msg_length) { - proto_tree_add_uint_format_value(att_tree, - classicstun_att_length, tvb, offset, 2, - att_length, - "%u (bogus, goes past the end of the message)", - att_length); + att_tree = proto_tree_add_subtree_format(att_type_tree, tvb, offset, + ATTR_HDR_LEN+att_length, ett_classicstun_att, NULL, + "Attribute: %s", + val_to_str(att_type, attributes, "Unknown (0x%04x)")); + + proto_tree_add_uint(att_tree, classicstun_att_type, tvb, + offset, 2, att_type); + offset += 2; + if (ATTR_HDR_LEN+att_length > msg_length) { + proto_tree_add_uint_format_value(att_tree, + classicstun_att_length, tvb, offset, 2, + att_length, + "%u (bogus, goes past the end of the message)", + att_length); + break; + } + proto_tree_add_uint(att_tree, classicstun_att_length, tvb, + offset, 2, att_length); + offset += 2; + switch( att_type ){ + case MAPPED_ADDRESS: + case RESPONSE_ADDRESS: + case SOURCE_ADDRESS: + case CHANGED_ADDRESS: + case REFLECTED_FROM: + case ALTERNATE_SERVER: + case DESTINATION_ADDRESS: + case REMOTE_ADDRESS: + if (att_length < 2) + break; + proto_tree_add_item(att_tree, classicstun_att_family, tvb, offset+1, 1, ENC_BIG_ENDIAN); + if (att_length < 4) + break; + proto_tree_add_item(att_tree, classicstun_att_port, tvb, offset+2, 2, ENC_BIG_ENDIAN); + switch( tvb_get_guint8(tvb, offset+1) ){ + case 1: + if (att_length < 8) + break; + proto_tree_add_item(att_tree, classicstun_att_ipv4, tvb, offset+4, 4, ENC_BIG_ENDIAN); + break; + + case 2: + if (att_length < 20) + break; + proto_tree_add_item(att_tree, classicstun_att_ipv6, tvb, offset+4, 16, ENC_NA); + break; + } break; - } - proto_tree_add_uint(att_tree, classicstun_att_length, tvb, - offset, 2, att_length); - offset += 2; - switch( att_type ){ - case MAPPED_ADDRESS: - case RESPONSE_ADDRESS: - case SOURCE_ADDRESS: - case CHANGED_ADDRESS: - case REFLECTED_FROM: - case ALTERNATE_SERVER: - case DESTINATION_ADDRESS: - case REMOTE_ADDRESS: - if (att_length < 2) - break; - proto_tree_add_item(att_tree, classicstun_att_family, tvb, offset+1, 1, ENC_BIG_ENDIAN); - if (att_length < 4) - break; - proto_tree_add_item(att_tree, classicstun_att_port, tvb, offset+2, 2, ENC_BIG_ENDIAN); - switch( tvb_get_guint8(tvb, offset+1) ){ - case 1: - if (att_length < 8) - break; - proto_tree_add_item(att_tree, classicstun_att_ipv4, tvb, offset+4, 4, ENC_BIG_ENDIAN); + + case CHANGE_REQUEST: + if (att_length < 4) + break; + proto_tree_add_item(att_tree, classicstun_att_change_ip, tvb, offset, 4, ENC_BIG_ENDIAN); + proto_tree_add_item(att_tree, classicstun_att_change_port, tvb, offset, 4, ENC_BIG_ENDIAN); + break; + + case USERNAME: + case PASSWORD: + case MESSAGE_INTEGRITY: + case NONCE: + case REALM: + if (att_length < 1) + break; + proto_tree_add_item(att_tree, classicstun_att_value, tvb, offset, att_length, ENC_NA); + break; + + case ERROR_CODE: + if (att_length < 3) + break; + proto_tree_add_item(att_tree, classicstun_att_error_class, tvb, offset+2, 1, ENC_BIG_ENDIAN); + if (att_length < 4) + break; + proto_tree_add_item(att_tree, classicstun_att_error_number, tvb, offset+3, 1, ENC_BIG_ENDIAN); + if (att_length < 5) + break; + proto_tree_add_item(att_tree, classicstun_att_error_reason, tvb, offset+4, (att_length-4), ENC_UTF_8|ENC_NA); + break; + + case LIFETIME: + if (att_length < 4) + break; + proto_tree_add_item(att_tree, classicstun_att_lifetime, tvb, offset, 4, ENC_BIG_ENDIAN); + break; + + case MAGIC_COOKIE: + if (att_length < 4) + break; + proto_tree_add_item(att_tree, classicstun_att_magic_cookie, tvb, offset, 4, ENC_BIG_ENDIAN); + break; + + case BANDWIDTH: + if (att_length < 4) + break; + proto_tree_add_item(att_tree, classicstun_att_bandwidth, tvb, offset, 4, ENC_BIG_ENDIAN); + break; + + case DATA: + proto_tree_add_item(att_tree, classicstun_att_data, tvb, offset, att_length, ENC_NA); + + tvbuff_t *next_tvb; + heur_dtbl_entry_t *hdtbl_entry; + next_tvb = tvb_new_subset_length(tvb, offset, att_length); + + if (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, att_tree, &hdtbl_entry, NULL)) { + call_dissector_only(data_handle, next_tvb, pinfo, att_tree, NULL); + } + + break; + + case UNKNOWN_ATTRIBUTES: + for (i = 0; i < att_length; i += 4) { + proto_tree_add_item(att_tree, classicstun_att_unknown, tvb, offset+i, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(att_tree, classicstun_att_unknown, tvb, offset+i+2, 2, ENC_BIG_ENDIAN); + } + break; + + case SERVER: + proto_tree_add_item(att_tree, classicstun_att_server_string, tvb, offset, att_length, ENC_UTF_8|ENC_NA); + break; + + case XOR_MAPPED_ADDRESS: + if (att_length < 2) + break; + proto_tree_add_item(att_tree, classicstun_att_family, tvb, offset+1, 1, ENC_BIG_ENDIAN); + if (att_length < 4) + break; + proto_tree_add_item(att_tree, classicstun_att_xor_port, tvb, offset+2, 2, ENC_BIG_ENDIAN); + + /* Show the port 'in the clear' + XOR (host order) transid with (host order) xor-port. + Add host-order port into tree. */ + clear_port = tvb_get_ntohs(tvb, offset+2) ^ (transaction_id_first_word >> 16); + ti = proto_tree_add_uint(att_tree, classicstun_att_port, tvb, offset+2, 2, clear_port); + proto_item_set_generated(ti); + + switch( tvb_get_guint8(tvb, offset+1) ){ + case 1: + if (att_length < 8) break; + proto_tree_add_item(att_tree, classicstun_att_xor_ipv4, tvb, offset+4, 4, ENC_BIG_ENDIAN); - case 2: - if (att_length < 20) - break; - proto_tree_add_item(att_tree, classicstun_att_ipv6, tvb, offset+4, 16, ENC_NA); + /* Show the address 'in the clear'. + XOR (host order) transid with (host order) xor-address. + Add in network order tree. */ + clear_ip = tvb_get_ipv4(tvb, offset+4) ^ g_htonl(transaction_id_first_word); + ti = proto_tree_add_ipv4(att_tree, classicstun_att_ipv4, tvb, offset+4, 4, clear_ip); + proto_item_set_generated(ti); + break; + + case 2: + if (att_length < 20) break; - } - break; - - case CHANGE_REQUEST: - if (att_length < 4) + proto_tree_add_item(att_tree, classicstun_att_xor_ipv6, tvb, offset+4, 16, ENC_NA); break; - proto_tree_add_item(att_tree, classicstun_att_change_ip, tvb, offset, 4, ENC_BIG_ENDIAN); - proto_tree_add_item(att_tree, classicstun_att_change_port, tvb, offset, 4, ENC_BIG_ENDIAN); + } + break; + + case REQUESTED_ADDRESS_TYPE: + if (att_length < 2) break; + proto_tree_add_item(att_tree, classicstun_att_family, tvb, offset+1, 1, ENC_BIG_ENDIAN); + break; - case USERNAME: - case PASSWORD: - case MESSAGE_INTEGRITY: - case NONCE: - case REALM: - if (att_length < 1) - break; - proto_tree_add_item(att_tree, classicstun_att_value, tvb, offset, att_length, ENC_NA); - break; + case CONNECTION_REQUEST_BINDING: + proto_tree_add_item(att_tree, classicstun_att_connection_request_binding, tvb, offset, att_length, ENC_UTF_8|ENC_NA); + break; - case ERROR_CODE: - if (att_length < 3) - break; - proto_tree_add_item(att_tree, classicstun_att_error_class, tvb, offset+2, 1, ENC_BIG_ENDIAN); - if (att_length < 4) - break; - proto_tree_add_item(att_tree, classicstun_att_error_number, tvb, offset+3, 1, ENC_BIG_ENDIAN); - if (att_length < 5) - break; - proto_tree_add_item(att_tree, classicstun_att_error_reason, tvb, offset+4, (att_length-4), ENC_UTF_8|ENC_NA); - break; - - case LIFETIME: - if (att_length < 4) - break; - proto_tree_add_item(att_tree, classicstun_att_lifetime, tvb, offset, 4, ENC_BIG_ENDIAN); - break; - - case MAGIC_COOKIE: - if (att_length < 4) - break; - proto_tree_add_item(att_tree, classicstun_att_magic_cookie, tvb, offset, 4, ENC_BIG_ENDIAN); - break; - - case BANDWIDTH: - if (att_length < 4) - break; - proto_tree_add_item(att_tree, classicstun_att_bandwidth, tvb, offset, 4, ENC_BIG_ENDIAN); - break; - - case DATA: - proto_tree_add_item(att_tree, classicstun_att_data, tvb, offset, att_length, ENC_NA); - - tvbuff_t *next_tvb; - heur_dtbl_entry_t *hdtbl_entry; - next_tvb = tvb_new_subset_length(tvb, offset, att_length); - - if (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, att_tree, &hdtbl_entry, NULL)) { - call_dissector_only(data_handle, next_tvb, pinfo, att_tree, NULL); - } - - break; - - case UNKNOWN_ATTRIBUTES: - for (i = 0; i < att_length; i += 4) { - proto_tree_add_item(att_tree, classicstun_att_unknown, tvb, offset+i, 2, ENC_BIG_ENDIAN); - proto_tree_add_item(att_tree, classicstun_att_unknown, tvb, offset+i+2, 2, ENC_BIG_ENDIAN); - } - break; - - case SERVER: - proto_tree_add_item(att_tree, classicstun_att_server_string, tvb, offset, att_length, ENC_UTF_8|ENC_NA); - break; - - case XOR_MAPPED_ADDRESS: - if (att_length < 2) - break; - proto_tree_add_item(att_tree, classicstun_att_family, tvb, offset+1, 1, ENC_BIG_ENDIAN); - if (att_length < 4) - break; - proto_tree_add_item(att_tree, classicstun_att_xor_port, tvb, offset+2, 2, ENC_BIG_ENDIAN); - - /* Show the port 'in the clear' - XOR (host order) transid with (host order) xor-port. - Add host-order port into tree. */ - clear_port = tvb_get_ntohs(tvb, offset+2) ^ (transaction_id_first_word >> 16); - ti = proto_tree_add_uint(att_tree, classicstun_att_port, tvb, offset+2, 2, clear_port); - proto_item_set_generated(ti); - - switch( tvb_get_guint8(tvb, offset+1) ){ - case 1: - if (att_length < 8) - break; - proto_tree_add_item(att_tree, classicstun_att_xor_ipv4, tvb, offset+4, 4, ENC_BIG_ENDIAN); - - /* Show the address 'in the clear'. - XOR (host order) transid with (host order) xor-address. - Add in network order tree. */ - clear_ip = tvb_get_ipv4(tvb, offset+4) ^ g_htonl(transaction_id_first_word); - ti = proto_tree_add_ipv4(att_tree, classicstun_att_ipv4, tvb, offset+4, 4, clear_ip); - proto_item_set_generated(ti); - break; - - case 2: - if (att_length < 20) - break; - proto_tree_add_item(att_tree, classicstun_att_xor_ipv6, tvb, offset+4, 16, ENC_NA); - break; - } - break; - - case REQUESTED_ADDRESS_TYPE: - if (att_length < 2) - break; - proto_tree_add_item(att_tree, classicstun_att_family, tvb, offset+1, 1, ENC_BIG_ENDIAN); - break; - - case CONNECTION_REQUEST_BINDING: - proto_tree_add_item(att_tree, classicstun_att_connection_request_binding, tvb, offset, att_length, ENC_UTF_8|ENC_NA); - break; - - default: - break; - } - offset += att_length; - msg_length -= ATTR_HDR_LEN+att_length; + default: + break; } + offset += att_length; + msg_length -= ATTR_HDR_LEN+att_length; } } return tvb_reported_length(tvb);