From c96b79f1059ff3e346a4a5ec81bd40f11a01801e Mon Sep 17 00:00:00 2001 From: Niels Widger Date: Wed, 9 Aug 2023 11:51:20 -0400 Subject: [PATCH] sharkd: Add phs tap to sharkd Add `phs` tap to `sharkd`, providing the same information as `tshark`'s `-z io,phs` option. Additionally, modify how `tshark -z io,phs` (and therefore `sharkd`'s new `phs` tap) handles packet comments (aka `pkt_comment` protocol frames). Previously, `pkt_comment` protocol frames were handled no differently from any other protocol in `io,phs`'s `tap_packet` callback `protohierstat_packet` but were skipped in its `tap_draw` callback `protohierstat_draw`. This behavior seems to have been first introduced in 80ae3708. For captures containing packet comments, this lead to surprising `tshark -z io,phs` output with multiple root-level `eth` trees. Below is example output of the old behavior for the `test/captures/protohier-with-comments.pcapng` capture in this repository with two packet comments, one on an ICMPv6 packet and another on an SSDP packet: # tshark -qz io,phs -r ./test/captures/protohier-with-comments.pcapng =================================================================== Protocol Hierarchy Statistics Filter: eth frames:113 bytes:21809 ipv6 frames:38 bytes:7456 icmpv6 frames:35 bytes:3574 udp frames:3 bytes:3882 data frames:3 bytes:3882 ip frames:69 bytes:13993 udp frames:59 bytes:13391 mdns frames:1 bytes:138 ssdp frames:29 bytes:8561 nbns frames:20 bytes:2200 nbdgm frames:1 bytes:248 smb frames:1 bytes:248 mailslot frames:1 bytes:248 browser frames:1 bytes:248 dhcp frames:4 bytes:1864 dns frames:4 bytes:380 igmp frames:10 bytes:602 arp frames:6 bytes:360 eth frames:2 bytes:377 ipv6 frames:1 bytes:110 icmpv6 frames:1 bytes:110 ip frames:1 bytes:267 udp frames:1 bytes:267 ssdp frames:1 bytes:267 =================================================================== Despite the comment in `phs_draw` in `ui/cli/tap-protohierstat.c`, this does not seem to match the behavior for PHS as shown in the GUI. The GUI seems to ignore the `pkt_comment` protocol frames and merges their children up a level. This commit tries to reproduce this behavior in the `tshark -z io,phs` output by ignoring `pkt_comment` protocol frames in `protohierstat_packet` instead of `protohierstat_draw`. The result is output like the following: # tshark -qz io,phs -r ./test/captures/protohier-with-comments.pcapng =================================================================== Protocol Hierarchy Statistics Filter: eth frames:115 bytes:22186 ipv6 frames:39 bytes:7566 icmpv6 frames:36 bytes:3684 udp frames:3 bytes:3882 data frames:3 bytes:3882 ip frames:70 bytes:14260 udp frames:60 bytes:13658 mdns frames:1 bytes:138 ssdp frames:30 bytes:8828 nbns frames:20 bytes:2200 nbdgm frames:1 bytes:248 smb frames:1 bytes:248 mailslot frames:1 bytes:248 browser frames:1 bytes:248 dhcp frames:4 bytes:1864 dns frames:4 bytes:380 igmp frames:10 bytes:602 arp frames:6 bytes:360 =================================================================== Note that there are no `pkt_comment` protocols and only a single root-level `eth` protocol. Additionally, the commented ICMPv6 and SSDP packets have been merged into the first `eth` tree, and the frame and byte counts have been incremented appropriately. --- CMakeLists.txt | 2 + sharkd_session.c | 100 +++++++++ test/captures/protohier-with-comments.pcapng | Bin 0 -> 26188 bytes .../protohier-without-comments.pcapng | Bin 0 -> 26136 bytes test/suite_sharkd.py | 189 ++++++++++++++++++ ui/cli/tap-protohierstat.c | 78 +++++--- ui/cli/tap-protohierstat.h | 51 +++++ 7 files changed, 387 insertions(+), 33 deletions(-) create mode 100644 test/captures/protohier-with-comments.pcapng create mode 100644 test/captures/protohier-without-comments.pcapng create mode 100644 ui/cli/tap-protohierstat.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 253498cdbf..d7dd4ace82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3056,6 +3056,7 @@ if(BUILD_sharkd) ${APPLE_SYSTEM_CONFIGURATION_LIBRARY} ${WIN_WS2_32_LIBRARY} ${SPEEXDSP_LIBRARIES} + ${M_LIBRARIES} ) set(sharkd_FILES # @@ -3066,6 +3067,7 @@ if(BUILD_sharkd) sharkd.c sharkd_daemon.c sharkd_session.c + ${TSHARK_TAP_SRC} ) set_executable_resources(sharkd "SharkD") add_executable(sharkd ${sharkd_FILES}) diff --git a/sharkd_session.c b/sharkd_session.c index 4f98425fce..9fcaf713f4 100644 --- a/sharkd_session.c +++ b/sharkd_session.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -1031,6 +1032,11 @@ sharkd_session_process_info(void) sharkd_json_value_string("tap", "rtp-streams"); json_dumper_end_object(&dumper); + json_dumper_begin_object(&dumper); + sharkd_json_value_string("name", "Protocol Hierarchy Statistics"); + sharkd_json_value_string("tap", "phs"); + json_dumper_end_object(&dumper); + json_dumper_begin_object(&dumper); sharkd_json_value_string("name", "Expert Information"); sharkd_json_value_string("tap", "expert"); @@ -2629,6 +2635,80 @@ sharkd_session_free_tap_srt_cb(void *arg) g_free(srt_data); } +struct sharkd_phs_req +{ + const char *tap_name; + phs_t *rs; +}; + +static void +sharkd_session_process_tap_phs_cb_aux(phs_t *rs) +{ + for (; rs; rs = rs->sibling) { + if (rs->protocol == -1) { + return; + } + sharkd_json_object_open(NULL); + sharkd_json_value_string("proto", rs->proto_name); + sharkd_json_value_anyf("frames", "%u", rs->frames); + sharkd_json_value_anyf("bytes", "%lu", rs->bytes); + if (rs->child != NULL && rs->child->protocol != -1) { + sharkd_json_array_open("protos"); + sharkd_session_process_tap_phs_cb_aux(rs->child); + sharkd_json_array_close(); + } + sharkd_json_object_close(); + } +} + +static tap_packet_status +sharkd_session_packet_tap_phs_cb(void *pphs_req, packet_info *pinfo, epan_dissect_t *edt, const void *dummy, tap_flags_t flags) +{ + struct sharkd_phs_req *phs_req = (struct sharkd_phs_req *)pphs_req; + phs_t *rs = phs_req->rs; + return protohierstat_packet(rs, pinfo, edt, dummy, flags); +} + +/** + * sharkd_session_process_tap_phs_cb() + * + * Output phs tap: + * (m) tap - tap name + * (m) type - tap output type + * (m) filter - tap filter argument + * (m) protos - array of proto objects + * + * proto object: + * (m) proto - protocol name + * (m) frames - frame count + * (m) bytes - bytes count + * (o) protos - array of proto objects + */ +static void +sharkd_session_process_tap_phs_cb(void *arg) +{ + struct sharkd_phs_req *phs_req = (struct sharkd_phs_req *)arg; + phs_t *rs = phs_req->rs; + sharkd_json_object_open(NULL); + sharkd_json_value_string("tap", phs_req->tap_name); + sharkd_json_value_string("type", "phs"); + sharkd_json_value_string("filter", rs->filter ? rs->filter : ""); + sharkd_json_array_open("protos"); + sharkd_session_process_tap_phs_cb_aux(rs); + sharkd_json_array_close(); + sharkd_json_object_close(); +} + +static void +sharkd_session_free_tap_phs_cb(void *arg) +{ + struct sharkd_phs_req *phs_req = (struct sharkd_phs_req *)arg; + phs_t *rs = phs_req->rs; + free_phs(rs); + g_free(phs_req); + +} + struct sharkd_export_object_list { struct sharkd_export_object_list *next; @@ -3247,6 +3327,26 @@ sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count) tap_data = mcaststream_tapinfo; tap_free = sharkd_session_process_free_tap_multicast_cb; } + else if (!strncmp(tok_tap, "phs", 3)) + { + phs_t *rs; + + pc_proto_id = proto_registrar_get_id_byname("pkt_comment"); + + rs = new_phs_t(NULL, tap_filter); + + struct sharkd_phs_req *phs_req; + phs_req = (struct sharkd_phs_req *)g_malloc0(sizeof(*phs_req)); + phs_req->tap_name = tok_tap; + phs_req->rs = rs; + + tap_error = register_tap_listener("frame", phs_req, tap_filter, TL_REQUIRES_PROTO_TREE, NULL, + sharkd_session_packet_tap_phs_cb, + sharkd_session_process_tap_phs_cb, NULL); + + tap_data = phs_req; + tap_free = sharkd_session_free_tap_phs_cb; + } else { sharkd_json_error( diff --git a/test/captures/protohier-with-comments.pcapng b/test/captures/protohier-with-comments.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..4a4d78e4d3cb5b6229ba7ad980d6e6c1306dc2b2 GIT binary patch literal 26188 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 literal 0 HcmV?d00001 diff --git a/test/suite_sharkd.py b/test/suite_sharkd.py index 42f63b182e..2701cd9661 100644 --- a/test/suite_sharkd.py +++ b/test/suite_sharkd.py @@ -309,6 +309,195 @@ class TestSharkd: }}, )) + def test_sharkd_req_tap_phs(self, check_sharkd_session, capture_file): + check_sharkd_session(( + {"jsonrpc":"2.0", "id":1, "method":"load", + "params":{"file": capture_file('protohier-with-comments.pcapng')} + }, + {"jsonrpc":"2.0", "id":2, "method":"tap", "params":{"tap0": "phs"}}, + {"jsonrpc":"2.0", "id":3, "method":"load", + "params":{"file": capture_file('protohier-without-comments.pcapng')} + }, + {"jsonrpc":"2.0", "id":4, "method":"tap", "params":{"tap0": "phs"}}, + ), ( + {"jsonrpc":"2.0","id":1,"result":{"status":"OK"}}, + {"jsonrpc":"2.0","id":2,"result":{ + "taps":[{ + "tap":"phs", + "type":"phs", + "filter":"", + "protos":[{ + "proto":"eth", + "frames":115, + "bytes":22186, + "protos":[{ + "proto":"ipv6", + "frames":39, + "bytes":7566, + "protos":[{ + "proto":"icmpv6", + "frames":36, + "bytes":3684 + },{ + "proto":"udp", + "frames":3, + "bytes":3882, + "protos":[{ + "proto":"data", + "frames":3, + "bytes":3882 + }] + }] + },{ + "proto":"ip", + "frames":70, + "bytes":14260, + "protos":[{ + "proto":"udp", + "frames":60, + "bytes":13658, + "protos":[{ + "proto":"mdns", + "frames":1, + "bytes":138 + },{ + "proto":"ssdp", + "frames":30, + "bytes":8828 + },{ + "proto":"nbns", + "frames":20, + "bytes":2200 + },{ + "proto":"nbdgm", + "frames":1, + "bytes":248, + "protos":[{ + "proto":"smb", + "frames":1, + "bytes":248, + "protos":[{ + "proto":"mailslot", + "frames":1, + "bytes":248, + "protos":[{ + "proto":"browser", + "frames":1, + "bytes":248 + }] + }] + }] + },{"proto":"dhcp", + "frames":4, + "bytes":1864 + },{ + "proto":"dns", + "frames":4, + "bytes":380 + }] + },{ + "proto":"igmp", + "frames":10, + "bytes":602 + }] + },{ + "proto":"arp", + "frames":6, + "bytes":360 + }] + }] + }] + }}, + {"jsonrpc":"2.0","id":3,"result":{"status":"OK"}}, + {"jsonrpc":"2.0","id":4,"result":{ + "taps":[{ + "tap":"phs", + "type":"phs", + "filter":"", + "protos":[{ + "proto":"eth", + "frames":115, + "bytes":22186, + "protos":[{ + "proto":"ipv6", + "frames":39, + "bytes":7566, + "protos":[{ + "proto":"icmpv6", + "frames":36, + "bytes":3684 + },{ + "proto":"udp", + "frames":3, + "bytes":3882, + "protos":[{ + "proto":"data", + "frames":3, + "bytes":3882 + }] + }] + },{ + "proto":"ip", + "frames":70, + "bytes":14260, + "protos":[{ + "proto":"udp", + "frames":60, + "bytes":13658, + "protos":[{ + "proto":"mdns", + "frames":1, + "bytes":138 + },{ + "proto":"ssdp", + "frames":30, + "bytes":8828 + },{ + "proto":"nbns", + "frames":20, + "bytes":2200 + },{ + "proto":"nbdgm", + "frames":1, + "bytes":248, + "protos":[{ + "proto":"smb", + "frames":1, + "bytes":248, + "protos":[{ + "proto":"mailslot", + "frames":1, + "bytes":248, + "protos":[{ + "proto":"browser", + "frames":1, + "bytes":248 + }] + }] + }] + },{"proto":"dhcp", + "frames":4, + "bytes":1864 + },{ + "proto":"dns", + "frames":4, + "bytes":380 + }] + },{ + "proto":"igmp", + "frames":10, + "bytes":602 + }] + },{ + "proto":"arp", + "frames":6, + "bytes":360 + }] + }] + }] + }}, + )) + def test_sharkd_req_follow_bad(self, check_sharkd_session, capture_file): # Unrecognized taps currently produce no output (not even err). check_sharkd_session(( diff --git a/ui/cli/tap-protohierstat.c b/ui/cli/tap-protohierstat.c index 31f748aaa8..2628fdcf3c 100644 --- a/ui/cli/tap-protohierstat.c +++ b/ui/cli/tap-protohierstat.c @@ -21,25 +21,14 @@ #include #include +#include "tap-protohierstat.h" -static int pc_proto_id = -1; +int pc_proto_id = -1; void register_tap_listener_protohierstat(void); -typedef struct _phs_t { - struct _phs_t *sibling; - struct _phs_t *child; - struct _phs_t *parent; - char *filter; - int protocol; - const char *proto_name; - guint32 frames; - guint64 bytes; -} phs_t; - - -static phs_t * -new_phs_t(phs_t *parent) +phs_t * +new_phs_t(phs_t *parent, const char *filter) { phs_t *rs; rs = g_new(phs_t, 1); @@ -47,6 +36,9 @@ new_phs_t(phs_t *parent) rs->child = NULL; rs->parent = parent; rs->filter = NULL; + if (filter != NULL) { + rs->filter = g_strdup(filter); + } rs->protocol = -1; rs->proto_name = NULL; rs->frames = 0; @@ -54,8 +46,30 @@ new_phs_t(phs_t *parent) return rs; } +void +free_phs(phs_t *rs) +{ + if (!rs) { + return; + } + if (rs->filter) { + g_free(rs->filter); + rs->filter = NULL; + } + if (rs->sibling) + { + free_phs(rs->sibling); + rs->sibling = NULL; + } + if (rs->child) + { + free_phs(rs->child); + rs->child = NULL; + } + g_free(rs); +} -static tap_packet_status +tap_packet_status protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_, tap_flags_t flags _U_) { phs_t *rs = (phs_t *)prs; @@ -76,13 +90,23 @@ protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const v for (node=edt->tree->first_child; node; node=node->next) { fi = PNODE_FINFO(node); + /* + * If the first child is a tree of comments, skip over it. + * This keeps us from having a top-level "pkt_comment" + * entry that represents a nonexistent protocol, + * and matches how the GUI treats comments. + */ + if (G_UNLIKELY(fi->hfinfo->id == pc_proto_id)) { + continue; + } + /* first time we saw a protocol at this leaf */ if (rs->protocol == -1) { rs->protocol = fi->hfinfo->id; rs->proto_name = fi->hfinfo->abbrev; rs->frames = 1; rs->bytes = pinfo->fd->pkt_len; - rs->child = new_phs_t(rs); + rs->child = new_phs_t(rs, NULL); rs = rs->child; continue; } @@ -98,7 +122,7 @@ protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const v if (!tmprs) { for (tmprs=rs; tmprs->sibling; tmprs=tmprs->sibling) ; - tmprs->sibling = new_phs_t(rs->parent); + tmprs->sibling = new_phs_t(rs->parent, NULL); rs = tmprs->sibling; rs->protocol = fi->hfinfo->id; rs->proto_name = fi->hfinfo->abbrev; @@ -110,7 +134,7 @@ protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const v rs->bytes += pinfo->fd->pkt_len; if (!rs->child) { - rs->child = new_phs_t(rs); + rs->child = new_phs_t(rs, NULL); } rs = rs->child; } @@ -127,16 +151,6 @@ phs_draw(phs_t *rs, int indentation) if (rs->protocol == -1) { return; } - /* - * If the first child is a tree of comments, skip over it. - * This keeps us from having a top-level "pkt_comment" - * entry that represents a nonexistent protocol, - * and matches how the GUI treats comments. - */ - if (G_UNLIKELY(rs->protocol == pc_proto_id)) { - phs_draw(rs->child, indentation); - continue; - } str[0] = 0; stroff = 0; for (i=0; ifilter = g_strdup(filter); + rs = new_phs_t(NULL, filter); error_string = register_tap_listener("frame", rs, filter, TL_REQUIRES_PROTO_TREE, NULL, protohierstat_packet, protohierstat_draw, NULL); if (error_string) { /* error, we failed to attach to the tap. clean up */ - g_free(rs->filter); - g_free(rs); + free_phs(rs); cmdarg_err("Couldn't register io,phs tap: %s", error_string->str); diff --git a/ui/cli/tap-protohierstat.h b/ui/cli/tap-protohierstat.h new file mode 100644 index 0000000000..3a68ff18c7 --- /dev/null +++ b/ui/cli/tap-protohierstat.h @@ -0,0 +1,51 @@ +/** @file + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __TAP_PROTO_HIER_STAT_H__ +#define __TAP_PROTO_HIER_STAT_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern int pc_proto_id; + +typedef struct _phs_t { + struct _phs_t *sibling; + struct _phs_t *child; + struct _phs_t *parent; + char *filter; + int protocol; + const char *proto_name; + guint32 frames; + guint64 bytes; +} phs_t; + +extern phs_t * new_phs_t(phs_t *parent, const char *filter); +extern void free_phs(phs_t *rs); +extern tap_packet_status protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_, tap_flags_t flags _U_); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TAP_PROTO_HIER_STAT_H__ */ + +/* + * 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: + */