wireshark/epan/exported_pdu.c

344 lines
10 KiB
C
Raw Normal View History

/*
* exported_pdu.c
* exported_pdu helper functions
* Copyright 2013, Anders Broman <anders-broman@ericsson.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <glib.h>
#include <epan/packet.h>
#include <epan/exported_pdu.h>
#include <epan/address_types.h>
#include <epan/tap.h>
#include <wiretap/wtap.h>
#include <wsutil/pint.h>
static GSList *export_pdu_tap_name_list = NULL;
static wmem_map_t *export_pdu_encap_table = NULL;
static int exp_pdu_data_ip_size(const address* addr)
{
if (addr->type == AT_IPv4){
return 4 + EXP_PDU_TAG_IPV4_LEN;
} else if(addr->type == AT_IPv6){
return 4 + EXP_PDU_TAG_IPV6_LEN;
}
return 0;
}
static int exp_pdu_data_src_ip_size(packet_info *pinfo, void* data _U_)
{
return exp_pdu_data_ip_size(&pinfo->net_src);
}
static int exp_pdu_data_src_ip_populate_data(packet_info *pinfo, void* data _U_, guint8 *tlv_buffer, guint32 buffer_size _U_)
{
if(pinfo->net_src.type == AT_IPv4){
phton16(tlv_buffer+0, EXP_PDU_TAG_IPV4_SRC);
phton16(tlv_buffer+2, EXP_PDU_TAG_IPV4_LEN); /* tag length */
memcpy(tlv_buffer+4, pinfo->net_src.data, EXP_PDU_TAG_IPV4_LEN);
return 4 + EXP_PDU_TAG_IPV4_LEN;
}else if(pinfo->net_src.type == AT_IPv6){
phton16(tlv_buffer+0, EXP_PDU_TAG_IPV6_SRC);
phton16(tlv_buffer+2, EXP_PDU_TAG_IPV6_LEN); /* tag length */
memcpy(tlv_buffer+4, pinfo->net_src.data, EXP_PDU_TAG_IPV6_LEN);
return 4 + EXP_PDU_TAG_IPV6_LEN;
}
return 0;
}
static int exp_pdu_data_dst_ip_size(packet_info *pinfo, void* data _U_)
{
return exp_pdu_data_ip_size(&pinfo->net_dst);
}
static int exp_pdu_data_dst_ip_populate_data(packet_info *pinfo, void* data _U_, guint8 *tlv_buffer, guint32 buffer_size _U_)
{
if(pinfo->net_dst.type == AT_IPv4){
phton16(tlv_buffer+0, EXP_PDU_TAG_IPV4_DST);
phton16(tlv_buffer+2, EXP_PDU_TAG_IPV4_LEN); /* tag length */
memcpy(tlv_buffer+4, pinfo->net_dst.data, EXP_PDU_TAG_IPV4_LEN);
return 4 + EXP_PDU_TAG_IPV4_LEN;
}else if(pinfo->net_dst.type == AT_IPv6){
phton16(tlv_buffer+0, EXP_PDU_TAG_IPV6_DST);
phton16(tlv_buffer+2, EXP_PDU_TAG_IPV6_LEN); /* tag length */
memcpy(tlv_buffer+4, pinfo->net_dst.data, EXP_PDU_TAG_IPV6_LEN);
return 4 + EXP_PDU_TAG_IPV6_LEN;
}
return 0;
}
static int exp_pdu_data_port_type_size(packet_info *pinfo _U_, void* data _U_)
{
return EXP_PDU_TAG_PORT_LEN + 4;
}
static guint exp_pdu_ws_port_type_to_exp_pdu_port_type(port_type pt)
{
switch (pt)
{
case PT_NONE:
return EXP_PDU_PT_NONE;
case PT_SCTP:
return EXP_PDU_PT_SCTP;
case PT_TCP:
return EXP_PDU_PT_TCP;
case PT_UDP:
return EXP_PDU_PT_UDP;
case PT_DCCP:
return EXP_PDU_PT_DCCP;
case PT_IPX:
return EXP_PDU_PT_IPX;
case PT_DDP:
return EXP_PDU_PT_DDP;
case PT_IDP:
return EXP_PDU_PT_IDP;
case PT_USB:
return EXP_PDU_PT_USB;
case PT_I2C:
return EXP_PDU_PT_I2C;
case PT_IBQP:
return EXP_PDU_PT_IBQP;
case PT_BLUETOOTH:
return EXP_PDU_PT_BLUETOOTH;
case PT_IWARP_MPA:
return EXP_PDU_PT_IWARP_MPA;
}
DISSECTOR_ASSERT(FALSE);
return EXP_PDU_PT_NONE;
}
static int exp_pdu_data_port_type_populate_data(packet_info *pinfo, void* data, guint8 *tlv_buffer, guint32 buffer_size _U_)
{
guint pt;
phton16(tlv_buffer+0, EXP_PDU_TAG_PORT_TYPE);
phton16(tlv_buffer+2, EXP_PDU_TAG_PORT_TYPE_LEN); /* tag length */
pt = exp_pdu_ws_port_type_to_exp_pdu_port_type(pinfo->ptype);
phton32(tlv_buffer+4, pt);
return exp_pdu_data_port_type_size(pinfo, data);
}
static int exp_pdu_data_port_size(packet_info *pinfo _U_, void* data _U_)
{
return EXP_PDU_TAG_PORT_LEN + 4;
}
static int exp_pdu_data_port_populate_data(guint32 port, guint8 porttype, guint8 *tlv_buffer, guint32 buffer_size _U_)
{
phton16(tlv_buffer+0, porttype);
phton16(tlv_buffer+2, EXP_PDU_TAG_PORT_LEN); /* tag length */
phton32(tlv_buffer+4, port);
return EXP_PDU_TAG_PORT_LEN + 4;
}
static int exp_pdu_data_src_port_populate_data(packet_info *pinfo, void* data _U_, guint8 *tlv_buffer, guint32 buffer_size)
{
return exp_pdu_data_port_populate_data(pinfo->srcport, EXP_PDU_TAG_SRC_PORT, tlv_buffer, buffer_size);
}
static int exp_pdu_data_dst_port_populate_data(packet_info *pinfo, void* data _U_, guint8 *tlv_buffer, guint32 buffer_size)
{
return exp_pdu_data_port_populate_data(pinfo->destport, EXP_PDU_TAG_DST_PORT, tlv_buffer, buffer_size);
}
static int exp_pdu_data_orig_frame_num_size(packet_info *pinfo _U_, void* data _U_)
{
return EXP_PDU_TAG_ORIG_FNO_LEN + 4;
}
static int exp_pdu_data_orig_frame_num_populate_data(packet_info *pinfo, void* data, guint8 *tlv_buffer, guint32 buffer_size _U_)
{
phton16(tlv_buffer+0, EXP_PDU_TAG_ORIG_FNO);
phton16(tlv_buffer+2, EXP_PDU_TAG_ORIG_FNO_LEN); /* tag length */
phton32(tlv_buffer+4, pinfo->num);
return exp_pdu_data_orig_frame_num_size(pinfo, data);
}
WS_DLL_PUBLIC int exp_pdu_data_dissector_table_num_value_size(packet_info *pinfo _U_, void* data _U_)
{
return EXP_PDU_TAG_DISSECTOR_TABLE_NUM_VAL_LEN + 4;
}
WS_DLL_PUBLIC int exp_pdu_data_dissector_table_num_value_populate_data(packet_info *pinfo _U_, void* data, guint8 *tlv_buffer, guint32 buffer_size _U_)
{
guint32 value = GPOINTER_TO_UINT(data);
phton16(tlv_buffer+0, EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL);
phton16(tlv_buffer+2, EXP_PDU_TAG_DISSECTOR_TABLE_NUM_VAL_LEN); /* tag length */
phton32(tlv_buffer+4, value);
return exp_pdu_data_dissector_table_num_value_size(pinfo, data);
}
exp_pdu_data_item_t exp_pdu_data_src_ip = {exp_pdu_data_src_ip_size, exp_pdu_data_src_ip_populate_data, NULL};
exp_pdu_data_item_t exp_pdu_data_dst_ip = {exp_pdu_data_dst_ip_size, exp_pdu_data_dst_ip_populate_data, NULL};
exp_pdu_data_item_t exp_pdu_data_port_type = {exp_pdu_data_port_type_size, exp_pdu_data_port_type_populate_data, NULL};
exp_pdu_data_item_t exp_pdu_data_src_port = {exp_pdu_data_port_size, exp_pdu_data_src_port_populate_data, NULL};
exp_pdu_data_item_t exp_pdu_data_dst_port = {exp_pdu_data_port_size, exp_pdu_data_dst_port_populate_data, NULL};
exp_pdu_data_item_t exp_pdu_data_orig_frame_num = {exp_pdu_data_orig_frame_num_size, exp_pdu_data_orig_frame_num_populate_data, NULL};
exp_pdu_data_t *export_pdu_create_common_tags(packet_info *pinfo, const char *proto_name, guint16 tag_type)
{
const exp_pdu_data_item_t *common_exp_pdu_items[] = {
&exp_pdu_data_src_ip,
&exp_pdu_data_dst_ip,
&exp_pdu_data_port_type,
&exp_pdu_data_src_port,
&exp_pdu_data_dst_port,
&exp_pdu_data_orig_frame_num,
NULL
};
return export_pdu_create_tags(pinfo, proto_name, tag_type, common_exp_pdu_items);
}
/**
* Allocates and fills the exp_pdu_data_t struct according to the list of items
*
* The tags in the tag buffer SHOULD be added in numerical order.
*/
exp_pdu_data_t *
export_pdu_create_tags(packet_info *pinfo, const char* proto_name, guint16 tag_type, const exp_pdu_data_item_t **items_list)
{
exp_pdu_data_t *exp_pdu_data;
const exp_pdu_data_item_t **loop_items = items_list;
int tag_buf_size = 0;
int proto_str_len, proto_tag_len, buf_remaining, item_size;
guint8* buffer_data;
DISSECTOR_ASSERT(proto_name != NULL);
Dissector names are not protocol names. A given protocol's packet format may depend, for example, on which lower-level protocol is transporting the protocol in question. For example, protocols that run atop both byte-stream protocols such as TCP and TLS, and packet-oriented protocols such as UDP or DTLS, might begin the packet with a length when running atop a byte-stream protocol, to indicate where this packet ends and the next packet begins in the byte stream, but not do so when running atop a packet-oriented protocol. Dissectors can handle this in various ways: For example, the dissector could attempt to determine the protocol over which the packet was transported. Unfortunately, many of those mechanisms do so by fetching data from the packet_info structure, and many items in that structure act as global variables, so that, for example, if there are two two PDUs for protocol A inside a TCP segment, and the first protocol for PDU A contains a PDU for protocol B, and protocol B's dissector, or a dissector it calls, modifies the information in the packet_info structure so that it no longer indicates that the parent protocol is TCP, the second PDU for protocol A might not be correctly dissected. Another such mechanism is to query the previous element in the layers structure of the packet_info structure, which is a list of protocol IDs. Unfortunately, that is not a list of earlier protocols in the protocol stack, it's a list of earlier protocols in the dissection, which means that, in the above example, when the second PDU for protocol A is dissected, the list is {...,TCP,A,B,...,A}, which means that the previous element in the list is not TCP, so, again, the second PDU for protocol A will not be correctly dissected. An alternative is to have multiple dissectors for the same protocol, with the part of the protocol that's independent of the protocol transporting the PDU being dissected by common code. Protocol B might have an "over a byte-stream transport" dissector and an "over a packet transport" dissector, with the first dissector being registered for use over TCP and TLS and the other dissector being registered for use over packet protocols. This mechanism, unlike the other mechanisms, is not dependent on information in the packet_info structure that might be affected by dissectors other than the one for the protocol that transports protocol B. Furthermore, in a LINKTYPE_WIRESHARK_UPPER_PDU pcap or pcapng packet for protocol B, there might not be any information to indicate the protocol that transports protocol B, so there would have to be separate dissectors for protocol B, with separate names, so that a tag giving the protocol name would differ for B-over-byte-stream and B-over-packets. So: We rename EXP_PDU_TAG_PROTO_NAME and EXP_PDU_TAG_HEUR_PROTO_NAME to EXP_PDU_TAG_DISSECTOR_NAME and EXP_PDU_TAG_HEUR_DISSECTOR_NAME, to emphasize that they are *not* protocol names, they are dissector names (which has always been the case - if there's a protocol with that name, but no dissector with that name, Wireshark will not be able to handle the packet, as it will try to look up a dissector given that name and fail). We fix that exported PDU dissector to refer to those tags as dissector names, not protocol names. We update documentation to refer to them as DISSECTOR_NAME tags, not PROTO_NAME tags. (If there is any documentation for this outside the Wireshark source, it should be updated as well.) We add comments for calls to dissector_handle_get_dissector_name() where the dissector name is shown to the user, to indicate that it might be that the protocol name should be used. We update the TLS and DTLS dissectors to show the encapsulated protocol as the string returned by dissector_handle_get_long_name(); as the default is "Application Data", it appeaers that a descriptive name, rather than a short API name, should be used. (We continue to use the dissector name in debugging messages, to indicate which dissector was called.)
2022-09-11 05:37:11 +00:00
DISSECTOR_ASSERT((tag_type == EXP_PDU_TAG_DISSECTOR_NAME) || (tag_type == EXP_PDU_TAG_HEUR_DISSECTOR_NAME) || (tag_type == EXP_PDU_TAG_DISSECTOR_TABLE_NAME));
exp_pdu_data = wmem_new(pinfo->pool, exp_pdu_data_t);
/* Start by computing size of protocol name as a tag */
proto_str_len = (int)strlen(proto_name);
/* Ensure that tag length is a multiple of 4 bytes */
proto_tag_len = ((proto_str_len + 3) & 0xfffffffc);
/* Add Tag + length */
tag_buf_size += (proto_tag_len + 4);
/* Compute size of items */
while (*loop_items) {
tag_buf_size += (*loop_items)->size_func(pinfo, (*loop_items)->data);
loop_items++;
}
/* Add end of options length */
tag_buf_size+=4;
exp_pdu_data->tlv_buffer = (guint8 *)wmem_alloc0(pinfo->pool, tag_buf_size);
exp_pdu_data->tlv_buffer_len = tag_buf_size;
buffer_data = exp_pdu_data->tlv_buffer;
buf_remaining = exp_pdu_data->tlv_buffer_len;
/* Start by adding protocol name as a tag */
phton16(buffer_data+0, tag_type);
phton16(buffer_data+2, proto_tag_len); /* tag length */
memcpy(buffer_data+4, proto_name, proto_str_len);
buffer_data += (proto_tag_len+4);
buf_remaining -= (proto_tag_len+4);
/* Populate data */
loop_items = items_list;
while (*loop_items) {
item_size = (*loop_items)->populate_data(pinfo, (*loop_items)->data, buffer_data, buf_remaining);
buffer_data += item_size;
buf_remaining -= item_size;
loop_items++;
}
return exp_pdu_data;
}
gint
register_export_pdu_tap_with_encap(const char *name, gint encap)
{
gchar *tap_name = g_strdup(name);
export_pdu_tap_name_list = g_slist_prepend(export_pdu_tap_name_list, tap_name);
wmem_map_insert(export_pdu_encap_table, tap_name, GINT_TO_POINTER(encap));
return register_tap(tap_name);
}
gint
register_export_pdu_tap(const char *name)
{
#if 0
/* XXX: We could register it like this, but don't have to, since
* export_pdu_tap_get_encap() returns WTAP_ENCAP_WIRESHARK_UPPER_PDU
* if it's not in the encap hash table anyway.
*/
return register_export_pdu_tap_with_encap(name, WTAP_ENCAP_WIRESHARK_UPPER_PDU);
#endif
gchar *tap_name = g_strdup(name);
export_pdu_tap_name_list = g_slist_prepend(export_pdu_tap_name_list, tap_name);
return register_tap(tap_name);
}
static
gint sort_pdu_tap_name_list(gconstpointer a, gconstpointer b)
{
return g_strcmp0((const char *)a, (const char*)b);
}
GSList *
get_export_pdu_tap_list(void)
{
export_pdu_tap_name_list = g_slist_sort(export_pdu_tap_name_list, sort_pdu_tap_name_list);
return export_pdu_tap_name_list;
}
gint
export_pdu_tap_get_encap(const char* name)
{
gpointer value;
if (wmem_map_lookup_extended(export_pdu_encap_table, name, NULL, &value)) {
return GPOINTER_TO_INT(value);
}
return WTAP_ENCAP_WIRESHARK_UPPER_PDU;
}
void export_pdu_init(void)
{
export_pdu_encap_table = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal);
}
void export_pdu_cleanup(void)
{
g_slist_free_full(export_pdu_tap_name_list, g_free);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/