wireshark/epan/dissectors/packet-logcat.c

315 lines
10 KiB
C
Raw Normal View History

/* packet-logcat.c
* Routines for Android Logcat binary format v1 and v2
*
* Copyright 2014, Michal Labedzki for Tieto Corporation
*
* 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 <epan/packet.h>
#include <epan/expert.h>
#include <epan/exported_pdu.h>
#include <epan/tap.h>
#include <epan/prefs.h>
#include <wiretap/wtap.h>
static int proto_logcat = -1;
static int hf_logcat_version = -1;
static int hf_logcat_length = -1;
static int hf_logcat_padding = -1;
static int hf_logcat_header_size = -1;
static int hf_logcat_pid = -1;
static int hf_logcat_tid = -1;
static int hf_logcat_timestamp = -1;
static int hf_logcat_timestamp_seconds = -1;
static int hf_logcat_timestamp_nanoseconds = -1;
static int hf_logcat_euid = -1;
static int hf_logcat_priority = -1;
static int hf_logcat_tag = -1;
static int hf_logcat_log = -1;
static gint ett_logcat = -1;
static gint ett_logcat_timestamp = -1;
static gint ett_logcat_log = -1;
static dissector_handle_t logcat_handle;
static dissector_handle_t data_text_lines_handle;
static gint exported_pdu_tap = -1;
static expert_field ei_invalid_payload_length = EI_INIT;
static gboolean pref_one_line_info_column = TRUE;
const value_string priority_vals[] = {
{ 0x00, "Unknown" },
{ 0x01, "Default" },
{ 0x02, "Verbose" },
{ 0x03, "Debug" },
{ 0x04, "Info" },
{ 0x05, "Warning" },
{ 0x06, "Error" },
{ 0x07, "Fatal" },
{ 0x08, "Silent" },
{ 0, NULL }
};
void proto_register_logcat(void);
void proto_reg_handoff_logcat(void);
static gint detect_version(tvbuff_t *tvb, gint offset) {
guint16 payload_length;
guint16 try_header_size;
payload_length = tvb_get_letohs(tvb, offset);
try_header_size = tvb_get_letohs(tvb, offset + 2);
if (try_header_size != 24)
return 1;
if (tvb_reported_length_remaining(tvb, offset + 24 + payload_length) >= 0)
return 2;
return 1;
}
static int
dissect_logcat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
gint offset = 0;
proto_tree *maintree;
proto_item *mainitem;
proto_tree *subtree;
proto_item *subitem;
guint16 length;
guint16 check_length;
guint32 string_length;
gint logger_version;
guint8 *log;
gchar *c;
tvbuff_t *next_tvb;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Logcat");
col_clear(pinfo->cinfo, COL_INFO);
mainitem = proto_tree_add_item(tree, proto_logcat, tvb, offset, -1, ENC_NA);
maintree = proto_item_add_subtree(mainitem, ett_logcat);
logger_version = detect_version(tvb, offset);
subitem = proto_tree_add_uint(maintree, hf_logcat_version, tvb, offset, 0, logger_version);
proto_item_set_generated(subitem);
proto_tree_add_item(maintree, hf_logcat_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
length = tvb_get_letohs(tvb, offset);
offset += 2;
if (logger_version == 1) {
proto_tree_add_item(maintree, hf_logcat_padding, tvb, offset, 2, ENC_LITTLE_ENDIAN);
} else {
proto_tree_add_item(maintree, hf_logcat_header_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
}
offset += 2;
proto_tree_add_item(maintree, hf_logcat_pid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
proto_tree_add_item(maintree, hf_logcat_tid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
subitem = proto_tree_add_item(maintree, hf_logcat_timestamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
subtree = proto_item_add_subtree(subitem, ett_logcat_timestamp);
proto_tree_add_item(subtree, hf_logcat_timestamp_seconds, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
proto_tree_add_item(subtree, hf_logcat_timestamp_nanoseconds, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
if (logger_version >= 2) {
proto_tree_add_item(maintree, hf_logcat_euid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
}
/* payload */
proto_tree_add_item(maintree, hf_logcat_priority, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
check_length = 1;
string_length = tvb_strsize(tvb, offset);
proto_tree_add_item(maintree, hf_logcat_tag, tvb, offset, string_length, ENC_UTF_8 | ENC_NA);
set_address_tvb(&pinfo->src, AT_STRINGZ, string_length + 1, tvb, offset);
set_address(&pinfo->dst, AT_STRINGZ, 7, "Logcat");
offset += string_length;
check_length += string_length;
string_length = length - string_length - 1;
log = tvb_get_string_enc(pinfo->pool, tvb, offset, string_length, ENC_UTF_8);
/* New line characters convert to spaces to ensure column Info display one line */
if (pref_one_line_info_column) {
while ((c = g_utf8_strchr(log, string_length, '\n')))
*c = ' ';
while ((c = g_utf8_strchr(log, string_length, '\r')))
*c = ' ';
}
subitem = proto_tree_add_item(maintree, hf_logcat_log, tvb, offset, string_length, ENC_UTF_8 | ENC_NA);
subtree = proto_item_add_subtree(subitem, ett_logcat_log);
next_tvb = tvb_new_subset_length(tvb, offset, string_length - 1);
call_dissector(data_text_lines_handle, next_tvb, pinfo, subtree);
col_add_str(pinfo->cinfo, COL_INFO, log);
offset += string_length;
check_length += string_length;
if (length != check_length)
proto_tree_add_expert(maintree, pinfo, &ei_invalid_payload_length, tvb, offset, tvb_reported_length_remaining(tvb, offset));
if (have_tap_listener(exported_pdu_tap)) {
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
exp_pdu_data_t *exp_pdu_data = export_pdu_create_tags(pinfo, "logcat", EXP_PDU_TAG_DISSECTOR_NAME, NULL);
exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
exp_pdu_data->pdu_tvb = tvb;
tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
}
return offset;
}
void
proto_register_logcat(void)
{
module_t *module;
expert_module_t *expert_module;
static hf_register_info hf[] = {
{ &hf_logcat_version,
{ "Logger Version", "logcat.logger_version",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_logcat_length,
{ "Payload Length", "logcat.length",
FT_UINT16, BASE_DEC, NULL, 0x00,
"Payload start after nanoseconds or euid", HFILL }
},
{ &hf_logcat_padding,
{ "Padding", "logcat.padding",
FT_UINT16, BASE_HEX, NULL, 0x00,
"No matter what, we get 2 bytes of padding", HFILL }
},
{ &hf_logcat_header_size,
{ "Header Size", "logcat.header_size",
FT_UINT16, BASE_HEX, NULL, 0x00,
"Size of struct logger_entry_v2", HFILL }
},
{ &hf_logcat_pid,
{ "PID", "logcat.pid",
FT_INT32, BASE_DEC, NULL, 0x00,
"Process ID", HFILL }
},
{ &hf_logcat_tid,
{ "TID", "logcat.tid",
FT_INT32, BASE_DEC, NULL, 0x00,
"Thread ID", HFILL }
},
{ &hf_logcat_timestamp,
{ "Timestamp", "logcat.timestamp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
NULL, HFILL }
},
{ &hf_logcat_timestamp_seconds,
{ "Timestamp in seconds", "logcat.timestamp.seconds",
FT_INT32, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_logcat_timestamp_nanoseconds,
{ "Nanoseconds Timestamp", "logcat.timestamp.nanoseconds",
FT_INT32, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_logcat_euid,
{ "EUID", "logcat.euid",
FT_UINT32, BASE_DEC, NULL, 0x00,
"Effective UID of logger", HFILL }
},
{ &hf_logcat_priority,
{ "Priority", "logcat.priority",
FT_UINT8, BASE_DEC, VALS(priority_vals), 0x00,
NULL, HFILL }
},
{ &hf_logcat_tag,
{ "Tag", "logcat.tag",
FT_STRINGZ, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_logcat_log,
{ "Log", "logcat.log",
FT_STRINGZ, BASE_NONE, NULL, 0x00,
NULL, HFILL }
}
};
static gint *ett[] = {
&ett_logcat,
&ett_logcat_timestamp,
&ett_logcat_log
};
static ei_register_info ei[] = {
{ &ei_invalid_payload_length, { "logcat.expert.invalid_payload_length", PI_PROTOCOL, PI_WARN, "Payload length does not meet sum of payload data length", EXPFILL }},
};
proto_logcat = proto_register_protocol("Android Logcat", "Logcat", "logcat");
proto_register_field_array(proto_logcat, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
logcat_handle = register_dissector("logcat", dissect_logcat, proto_logcat);
expert_module = expert_register_protocol(proto_logcat);
expert_register_field_array(expert_module, ei, array_length(ei));
exported_pdu_tap = register_export_pdu_tap("Logcat");
module = prefs_register_protocol(proto_logcat, NULL);
prefs_register_bool_preference(module, "oneline_info_column",
"Use oneline info column",
"Use oneline info column by replace all new line characters by spaces",
&pref_one_line_info_column);
}
void
proto_reg_handoff_logcat(void)
{
data_text_lines_handle = find_dissector_add_dependency("data-text-lines", proto_logcat);
dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT, logcat_handle);
dissector_add_for_decode_as_with_preference("tcp.port", logcat_handle);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/