forked from osmocom/wireshark
Added "Follow DCCP stream" feature.
This pull request includes: * The "Follow DCCP stream" feature. * Updated docbook documentation for the "Follow DCCP stream" feature. * Test for the feature. * Corresponding packet trace for the test.
This commit is contained in:
parent
a57a32c04e
commit
2e7f2ffb7a
10
AUTHORS.src
10
AUTHORS.src
|
@ -2621,8 +2621,16 @@ Kees Cook <kees[AT]outflux.net> {
|
|||
TiVoConnect Discovery Protocol
|
||||
}
|
||||
|
||||
Thomas Dreibholz <dreibh[AT]iem.uni-due.de> {
|
||||
Thomas Dreibholz <dreibh[AT]iem.uni-due.de>/<dreibh[AT]simula.no> {
|
||||
Calculation Application Protocol support
|
||||
Component Status Protocol support
|
||||
Fractal Generator Protocol support
|
||||
DCCP dissector improvements
|
||||
Follow DCCP stream feature
|
||||
NetPerfMeter Protocol support
|
||||
Ping Pong Protocol support
|
||||
RSerPol protocol stack
|
||||
SCTP dissector improvements
|
||||
Scripting Service Protocol support
|
||||
}
|
||||
|
||||
|
|
|
@ -3462,6 +3462,7 @@ set(_test_group_list
|
|||
suite_extcaps
|
||||
suite_fileformats
|
||||
suite_follow
|
||||
suite_follow_dccp
|
||||
suite_io
|
||||
suite_mergecap
|
||||
suite_netperfmeter
|
||||
|
|
|
@ -784,6 +784,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
|
|||
get_data_source_name@Base 1.9.1
|
||||
get_data_source_tvb@Base 1.9.1
|
||||
get_data_source_tvb_by_name@Base 2.3.0
|
||||
get_dccp_stream_count@Base 3.5.0
|
||||
get_dissector_names@Base 1.12.0~rc1
|
||||
get_dissector_table_param@Base 1.99.2
|
||||
get_dissector_table_selector_type@Base 1.9.1
|
||||
|
|
|
@ -46,6 +46,8 @@ They previously shipped with Npcap 1.00.
|
|||
created to dissect DLT_ETW packets so Wireshark can display the DLT_ETW packet header, its message and packet_etw dissector
|
||||
calls packet_mbim sub_dissector if its provider matches the MBIM provider GUID.
|
||||
|
||||
* "Follow DCCP stream" feature to filter for and extract the contents of DCCP streams.
|
||||
|
||||
// === Removed Features and Support
|
||||
|
||||
//=== Removed Dissectors
|
||||
|
|
|
@ -22,7 +22,7 @@ display filter to show only the packets in a TLS or SSL stream. If so,
|
|||
Wireshark’s ability to follow protocol streams will be useful to you.
|
||||
|
||||
To filter to a particular stream,
|
||||
select a TCP, UDP, TLS, or HTTP packet in the packet list of the stream/connection you are
|
||||
select a TCP, UDP, DCCP, TLS, HTTP, HTTP/2 or QUIC packet in the packet list of the stream/connection you are
|
||||
interested in and then select the menu item menu:Analyze[Follow TCP Stream]
|
||||
(or use the context menu in the packet list). Wireshark will set an
|
||||
appropriate display filter and display a dialog box with the data from the
|
||||
|
@ -628,7 +628,7 @@ For example, a conversation containing only a three-way handshake will be found
|
|||
with the filter 'tcp.completeness==7' (1+2+4) while a complete conversation with
|
||||
data transfer will be found with a longer filter as closing a connection can be
|
||||
associated with FIN or RST packets, or even both :
|
||||
'tcp.completeness==31 or tcp.completeness==47 or tcp.completeness==63'
|
||||
'tcp.completeness==31 or tcp.completeness==47 or tcp.completeness==63'
|
||||
|
||||
[[ChAdvTimestamps]]
|
||||
|
||||
|
|
|
@ -162,6 +162,9 @@ See <<ChAdvFollowStreamSection>>.
|
|||
|menu:Follow[UDP Stream] |menu:Analyze[] |
|
||||
Same functionality as “Follow TCP Stream” but for UDP “streams”.
|
||||
|
||||
|menu:Follow[DCCP Stream] |menu:Analyze[] |
|
||||
Same functionality as “Follow TCP Stream” but for DCCP streams.
|
||||
|
||||
|menu:Follow[TLS Stream] |menu:Analyze[] |
|
||||
Same functionality as “Follow TCP Stream” but for TLS or SSL streams.
|
||||
See the wiki page on link:{wireshark-wiki-url}SSL[SSL] for instructions
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*
|
||||
* Francesco Fondelli <francesco dot fondelli, gmail dot com>
|
||||
*
|
||||
* Copyright 2020-2021 by Thomas Dreibholz <dreibh [AT] simula.no>
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
|
@ -45,8 +47,12 @@
|
|||
#include <epan/ipproto.h>
|
||||
#include <epan/in_cksum.h>
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/follow.h>
|
||||
#include <epan/expert.h>
|
||||
#include <epan/conversation.h>
|
||||
#include <epan/conversation_table.h>
|
||||
#include <epan/conversation_filter.h>
|
||||
#include <epan/exported_pdu.h>
|
||||
#include <epan/tap.h>
|
||||
#include <wsutil/str_util.h>
|
||||
#include <wsutil/utf8_entities.h>
|
||||
|
@ -181,10 +187,12 @@ static const unit_name_string units_bytes_sec = { "bytes/sec", NULL };
|
|||
|
||||
static int proto_dccp = -1;
|
||||
static int dccp_tap = -1;
|
||||
static int dccp_follow_tap = -1;
|
||||
|
||||
static int hf_dccp_srcport = -1;
|
||||
static int hf_dccp_dstport = -1;
|
||||
static int hf_dccp_port = -1;
|
||||
static int hf_dccp_stream = -1;
|
||||
static int hf_dccp_data_offset = -1;
|
||||
static int hf_dccp_ccval = -1;
|
||||
static int hf_dccp_cscov = -1;
|
||||
|
@ -246,6 +254,7 @@ static heur_dissector_list_t heur_subdissector_list;
|
|||
static gboolean dccp_summary_in_tree = TRUE;
|
||||
static gboolean try_heuristic_first = FALSE;
|
||||
static gboolean dccp_check_checksum = TRUE;
|
||||
static guint32 dccp_stream_count;
|
||||
|
||||
static void
|
||||
decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
|
||||
|
@ -257,6 +266,11 @@ decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
|
|||
|
||||
next_tvb = tvb_new_subset_remaining(tvb, offset);
|
||||
|
||||
/* If the user has a "Follow DCCP Stream" window loading, pass a pointer
|
||||
to the payload tvb through the tap system. */
|
||||
if (have_tap_listener(dccp_follow_tap))
|
||||
tap_queue_packet(dccp_follow_tap, pinfo, next_tvb);
|
||||
|
||||
/*
|
||||
* determine if this packet is part of a conversation and call dissector
|
||||
* for the conversation if available
|
||||
|
@ -322,6 +336,251 @@ decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
|
|||
call_data_dissector(next_tvb, pinfo, tree);
|
||||
}
|
||||
|
||||
/* Conversation and process code originally copied from packet-udp.c */
|
||||
static struct dccp_analysis *
|
||||
init_dccp_conversation_data(packet_info *pinfo)
|
||||
{
|
||||
struct dccp_analysis *dccpd;
|
||||
|
||||
/* Initialize the dccp protocol data structure to add to the dccp conversation */
|
||||
dccpd = wmem_new0(wmem_file_scope(), struct dccp_analysis);
|
||||
/*
|
||||
dccpd->flow1.username = NULL;
|
||||
dccpd->flow1.command = NULL;
|
||||
dccpd->flow2.username = NULL;
|
||||
dccpd->flow2.command = NULL;
|
||||
*/
|
||||
|
||||
dccpd->stream = dccp_stream_count++;
|
||||
dccpd->ts_first = pinfo->abs_ts;
|
||||
dccpd->ts_prev = pinfo->abs_ts;
|
||||
|
||||
return dccpd;
|
||||
}
|
||||
|
||||
static struct dccp_analysis *
|
||||
get_dccp_conversation_data(conversation_t *conv, packet_info *pinfo)
|
||||
{
|
||||
int direction;
|
||||
struct dccp_analysis *dccpd;
|
||||
|
||||
/* Get the data for this conversation */
|
||||
dccpd=(struct dccp_analysis *)conversation_get_proto_data(conv, proto_dccp);
|
||||
|
||||
/* If the conversation was just created or it matched a
|
||||
* conversation with template options, dccpd will not
|
||||
* have been initialized. So, initialize
|
||||
* a new dccpd structure for the conversation.
|
||||
*/
|
||||
if (!dccpd) {
|
||||
dccpd = init_dccp_conversation_data(pinfo);
|
||||
conversation_add_proto_data(conv, proto_dccp, dccpd);
|
||||
}
|
||||
|
||||
/* check direction and get ua lists */
|
||||
direction=cmp_address(&pinfo->src, &pinfo->dst);
|
||||
/* if the addresses are equal, match the ports instead */
|
||||
if (direction == 0) {
|
||||
direction= (pinfo->srcport > pinfo->destport) ? 1 : -1;
|
||||
}
|
||||
if (direction >= 0) {
|
||||
dccpd->fwd=&(dccpd->flow1);
|
||||
dccpd->rev=&(dccpd->flow2);
|
||||
} else {
|
||||
dccpd->fwd=&(dccpd->flow2);
|
||||
dccpd->rev=&(dccpd->flow1);
|
||||
}
|
||||
|
||||
return dccpd;
|
||||
}
|
||||
|
||||
static const char* dccp_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter)
|
||||
{
|
||||
if (filter == CONV_FT_SRC_PORT)
|
||||
return "dccp.srcport";
|
||||
|
||||
if (filter == CONV_FT_DST_PORT)
|
||||
return "dccp.dstport";
|
||||
|
||||
if (filter == CONV_FT_ANY_PORT)
|
||||
return "dccp.port";
|
||||
|
||||
if(!conv) {
|
||||
return CONV_FILTER_INVALID;
|
||||
}
|
||||
|
||||
if (filter == CONV_FT_SRC_ADDRESS) {
|
||||
if (conv->src_address.type == AT_IPv4)
|
||||
return "ip.src";
|
||||
if (conv->src_address.type == AT_IPv6)
|
||||
return "ipv6.src";
|
||||
}
|
||||
|
||||
if (filter == CONV_FT_DST_ADDRESS) {
|
||||
if (conv->dst_address.type == AT_IPv4)
|
||||
return "ip.dst";
|
||||
if (conv->dst_address.type == AT_IPv6)
|
||||
return "ipv6.dst";
|
||||
}
|
||||
|
||||
if (filter == CONV_FT_ANY_ADDRESS) {
|
||||
if (conv->src_address.type == AT_IPv4)
|
||||
return "ip.addr";
|
||||
if (conv->src_address.type == AT_IPv6)
|
||||
return "ipv6.addr";
|
||||
}
|
||||
|
||||
return CONV_FILTER_INVALID;
|
||||
}
|
||||
|
||||
static ct_dissector_info_t dccp_ct_dissector_info = {&dccp_conv_get_filter_type};
|
||||
|
||||
static tap_packet_status
|
||||
dccpip_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*) pct;
|
||||
const e_dccphdr *dccphdr=(const e_dccphdr *)vip;
|
||||
|
||||
add_conversation_table_data_with_conv_id(hash, &dccphdr->ip_src, &dccphdr->ip_dst, dccphdr->sport, dccphdr->dport, (conv_id_t) dccphdr->stream, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts, &dccp_ct_dissector_info, ENDPOINT_DCCP);
|
||||
|
||||
return TAP_PACKET_REDRAW;
|
||||
}
|
||||
|
||||
static const char* dccp_host_get_filter_type(hostlist_talker_t* host, conv_filter_type_e filter)
|
||||
{
|
||||
|
||||
if (filter == CONV_FT_SRC_PORT)
|
||||
return "dccp.srcport";
|
||||
|
||||
if (filter == CONV_FT_DST_PORT)
|
||||
return "dccp.dstport";
|
||||
|
||||
if (filter == CONV_FT_ANY_PORT)
|
||||
return "dccp.port";
|
||||
|
||||
if(!host) {
|
||||
return CONV_FILTER_INVALID;
|
||||
}
|
||||
|
||||
|
||||
if (filter == CONV_FT_SRC_ADDRESS) {
|
||||
if (host->myaddress.type == AT_IPv4)
|
||||
return "ip.src";
|
||||
if (host->myaddress.type == AT_IPv6)
|
||||
return "ipv6.src";
|
||||
}
|
||||
|
||||
if (filter == CONV_FT_DST_ADDRESS) {
|
||||
if (host->myaddress.type == AT_IPv4)
|
||||
return "ip.dst";
|
||||
if (host->myaddress.type == AT_IPv6)
|
||||
return "ipv6.dst";
|
||||
}
|
||||
|
||||
if (filter == CONV_FT_ANY_ADDRESS) {
|
||||
if (host->myaddress.type == AT_IPv4)
|
||||
return "ip.addr";
|
||||
if (host->myaddress.type == AT_IPv6)
|
||||
return "ipv6.addr";
|
||||
}
|
||||
|
||||
return CONV_FILTER_INVALID;
|
||||
}
|
||||
|
||||
static hostlist_dissector_info_t dccp_host_dissector_info = {&dccp_host_get_filter_type};
|
||||
|
||||
static tap_packet_status
|
||||
dccpip_hostlist_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*) pit;
|
||||
const e_dccphdr *dccphdr=(const e_dccphdr *)vip;
|
||||
|
||||
/* Take two "add" passes per packet, adding for each direction, ensures that all
|
||||
packets are counted properly (even if address is sending to itself)
|
||||
XXX - this could probably be done more efficiently inside hostlist_table */
|
||||
add_hostlist_table_data(hash, &dccphdr->ip_src, dccphdr->sport, TRUE, 1, pinfo->fd->pkt_len, &dccp_host_dissector_info, ENDPOINT_DCCP);
|
||||
add_hostlist_table_data(hash, &dccphdr->ip_dst, dccphdr->dport, FALSE, 1, pinfo->fd->pkt_len, &dccp_host_dissector_info, ENDPOINT_DCCP);
|
||||
|
||||
return TAP_PACKET_REDRAW;
|
||||
}
|
||||
|
||||
/* Return the current stream count */
|
||||
guint32 get_dccp_stream_count(void)
|
||||
{
|
||||
return dccp_stream_count;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dccp_filter_valid(packet_info *pinfo)
|
||||
{
|
||||
return proto_is_frame_protocol(pinfo->layers, "dccp");
|
||||
}
|
||||
|
||||
static gchar*
|
||||
dccp_build_filter(packet_info *pinfo)
|
||||
{
|
||||
if( pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4 ) {
|
||||
/* DCCP over IPv4 */
|
||||
return g_strdup_printf("(ip.addr eq %s and ip.addr eq %s) and (dccp.port eq %d and dccp.port eq %d)",
|
||||
address_to_str(pinfo->pool, &pinfo->net_src),
|
||||
address_to_str(pinfo->pool, &pinfo->net_dst),
|
||||
pinfo->srcport, pinfo->destport );
|
||||
}
|
||||
|
||||
if( pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6 ) {
|
||||
/* DCCP over IPv6 */
|
||||
return g_strdup_printf("(ipv6.addr eq %s and ipv6.addr eq %s) and (dccp.port eq %d and dccp.port eq %d)",
|
||||
address_to_str(pinfo->pool, &pinfo->net_src),
|
||||
address_to_str(pinfo->pool, &pinfo->net_dst),
|
||||
pinfo->srcport, pinfo->destport );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gchar *dccp_follow_conv_filter(packet_info *pinfo, guint *stream, guint *sub_stream _U_)
|
||||
{
|
||||
conversation_t *conv;
|
||||
struct dccp_analysis *dccpd;
|
||||
|
||||
if( ((pinfo->net_src.type == AT_IPv4 && pinfo->net_dst.type == AT_IPv4) ||
|
||||
(pinfo->net_src.type == AT_IPv6 && pinfo->net_dst.type == AT_IPv6))
|
||||
&& (conv=find_conversation_pinfo(pinfo, 0)) != NULL )
|
||||
{
|
||||
/* DCCP over IPv4/6 */
|
||||
dccpd = get_dccp_conversation_data(conv, pinfo);
|
||||
*stream = dccpd->stream;
|
||||
return g_strdup_printf("dccp.stream eq %u", dccpd->stream);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gchar *dccp_follow_index_filter(guint stream, guint sub_stream _U_)
|
||||
{
|
||||
return g_strdup_printf("dccp.stream eq %u", stream);
|
||||
}
|
||||
|
||||
static gchar *dccp_follow_address_filter(address *src_addr, address *dst_addr, int src_port, int dst_port)
|
||||
{
|
||||
const gchar *ip_version = src_addr->type == AT_IPv6 ? "v6" : "";
|
||||
gchar src_addr_str[WS_INET6_ADDRSTRLEN];
|
||||
gchar dst_addr_str[WS_INET6_ADDRSTRLEN];
|
||||
|
||||
address_to_str_buf(src_addr, src_addr_str, sizeof(src_addr_str));
|
||||
address_to_str_buf(dst_addr, dst_addr_str, sizeof(dst_addr_str));
|
||||
|
||||
return g_strdup_printf("((ip%s.src eq %s and dccp.srcport eq %d) and "
|
||||
"(ip%s.dst eq %s and dccp.dstport eq %d))"
|
||||
" or "
|
||||
"((ip%s.src eq %s and dccp.srcport eq %d) and "
|
||||
"(ip%s.dst eq %s and dccp.dstport eq %d))",
|
||||
ip_version, src_addr_str, src_port,
|
||||
ip_version, dst_addr_str, dst_port,
|
||||
ip_version, dst_addr_str, dst_port,
|
||||
ip_version, src_addr_str, src_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode a variable-length number of nbytes starting at offset. Based on
|
||||
* a concept by Arnaldo de Melo
|
||||
|
@ -620,6 +879,7 @@ static int
|
|||
dissect_dccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
||||
{
|
||||
proto_tree *dccp_tree;
|
||||
proto_item *item;
|
||||
proto_tree *dccp_options_tree = NULL;
|
||||
proto_item *dccp_item = NULL;
|
||||
proto_item *hidden_item, *offset_item;
|
||||
|
@ -632,6 +892,8 @@ dissect_dccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
|
|||
guint advertised_dccp_header_len = 0;
|
||||
guint options_len = 0;
|
||||
e_dccphdr *dccph;
|
||||
conversation_t *conv = NULL;
|
||||
struct dccp_analysis *dccpd;
|
||||
|
||||
dccph = wmem_new0(wmem_packet_scope(), e_dccphdr);
|
||||
dccph->sport = tvb_get_ntohs(tvb, offset);
|
||||
|
@ -669,6 +931,17 @@ dissect_dccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
|
|||
pinfo->srcport = dccph->sport;
|
||||
pinfo->destport = dccph->dport;
|
||||
|
||||
/* find (or create if needed) the conversation for this DCCP session */
|
||||
conv = find_or_create_conversation(pinfo);
|
||||
dccpd = get_dccp_conversation_data(conv, pinfo);
|
||||
item = proto_tree_add_uint(dccp_tree, hf_dccp_stream, tvb, offset, 0, dccpd->stream);
|
||||
proto_item_set_generated(item);
|
||||
|
||||
/* Copy the stream index into the header as well to make it available
|
||||
* to tap listeners.
|
||||
*/
|
||||
dccph->stream = dccpd->stream;
|
||||
|
||||
dccph->data_offset = tvb_get_guint8(tvb, offset);
|
||||
advertised_dccp_header_len = dccph->data_offset * 4;
|
||||
offset_item = proto_tree_add_uint(dccp_tree, hf_dccp_data_offset, tvb, offset, 1,
|
||||
|
@ -1028,6 +1301,12 @@ dissect_dccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
|
|||
return tvb_reported_length(tvb);
|
||||
}
|
||||
|
||||
static void
|
||||
dccp_init(void)
|
||||
{
|
||||
dccp_stream_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
proto_register_dccp(void)
|
||||
{
|
||||
|
@ -1058,6 +1337,14 @@ proto_register_dccp(void)
|
|||
NULL, HFILL
|
||||
}
|
||||
},
|
||||
{
|
||||
&hf_dccp_stream,
|
||||
{
|
||||
"Stream index", "dccp.stream",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL
|
||||
}
|
||||
},
|
||||
{
|
||||
&hf_dccp_data_offset,
|
||||
{
|
||||
|
@ -1328,6 +1615,13 @@ proto_register_dccp(void)
|
|||
"Check the validity of the DCCP checksum when possible",
|
||||
"Whether to check the validity of the DCCP checksum",
|
||||
&dccp_check_checksum);
|
||||
|
||||
register_conversation_table(proto_dccp, FALSE, dccpip_conversation_packet, dccpip_hostlist_packet);
|
||||
register_conversation_filter("dccp", "DCCP", dccp_filter_valid, dccp_build_filter);
|
||||
register_follow_stream(proto_dccp, "dccp_follow", dccp_follow_conv_filter, dccp_follow_index_filter, dccp_follow_address_filter,
|
||||
dccp_port_to_display, follow_tvb_tap_listener);
|
||||
|
||||
register_init_routine(dccp_init);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1338,6 +1632,7 @@ proto_reg_handoff_dccp(void)
|
|||
dccp_handle = create_dissector_handle(dissect_dccp, proto_dccp);
|
||||
dissector_add_uint("ip.proto", IP_PROTO_DCCP, dccp_handle);
|
||||
dccp_tap = register_tap("dccp");
|
||||
dccp_follow_tap = register_tap("dccp_follow");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*
|
||||
* Francesco Fondelli <francesco dot fondelli, gmail dot com>
|
||||
*
|
||||
* Copyright 2020-2021 by Thomas Dreibholz <dreibh [AT] simula.no>
|
||||
*
|
||||
* template taken from packet-udp.c
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
|
@ -18,6 +20,10 @@
|
|||
#ifndef __PACKET_DCCP_H__
|
||||
#define __PACKET_DCCP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* DCCP structs and definitions */
|
||||
typedef struct _e_dccphdr {
|
||||
guint16 sport;
|
||||
|
@ -44,10 +50,74 @@ typedef struct _e_dccphdr {
|
|||
guint8 data2;
|
||||
guint8 data3;
|
||||
|
||||
guint32 stream; /* this stream index field is included to help differentiate when address/port pairs are reused */
|
||||
|
||||
address ip_src;
|
||||
address ip_dst;
|
||||
} e_dccphdr;
|
||||
|
||||
/* Conversation and process structures originally copied from packet-tcp.c */
|
||||
typedef struct _dccp_flow_t {
|
||||
/* Process info, currently discovered via IPFIX */
|
||||
guint32 process_uid; /* UID of local process */
|
||||
guint32 process_pid; /* PID of local process */
|
||||
gchar *username; /* Username of the local process */
|
||||
gchar *command; /* Local process name + path + args */
|
||||
} dccp_flow_t;
|
||||
|
||||
struct dccp_analysis {
|
||||
/* These two structs are managed based on comparing the source
|
||||
* and destination addresses and, if they're equal, comparing
|
||||
* the source and destination ports.
|
||||
*
|
||||
* If the source is greater than the destination, then stuff
|
||||
* sent from src is in ual1.
|
||||
*
|
||||
* If the source is less than the destination, then stuff
|
||||
* sent from src is in ual2.
|
||||
*
|
||||
* XXX - if the addresses and ports are equal, we don't guarantee
|
||||
* the behavior.
|
||||
*/
|
||||
dccp_flow_t flow1;
|
||||
dccp_flow_t flow2;
|
||||
|
||||
/* These pointers are set by get_dccp_conversation_data()
|
||||
* fwd point in the same direction as the current packet
|
||||
* and rev in the reverse direction
|
||||
*/
|
||||
dccp_flow_t *fwd;
|
||||
dccp_flow_t *rev;
|
||||
|
||||
/* Keep track of dccp stream numbers instead of using the conversation
|
||||
* index (as how it was done before). This prevents gaps in the
|
||||
* stream index numbering
|
||||
*/
|
||||
guint32 stream;
|
||||
|
||||
/* Remember the timestamp of the first frame seen in this dccp
|
||||
* conversation to be able to calculate a relative time compared
|
||||
* to the start of this conversation
|
||||
*/
|
||||
nstime_t ts_first;
|
||||
|
||||
/* Remember the timestamp of the frame that was last seen in this
|
||||
* dccp conversation to be able to calculate a delta time compared
|
||||
* to previous frame in this conversation
|
||||
*/
|
||||
nstime_t ts_prev;
|
||||
};
|
||||
|
||||
/** Get the current number of DCCP streams
|
||||
*
|
||||
* @return The number of DCCP streams
|
||||
*/
|
||||
WS_DLL_PUBLIC guint32 get_dccp_stream_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __PACKET_DCCP_H__ */
|
||||
|
||||
/*
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef enum {
|
|||
FOLLOW_TCP,
|
||||
FOLLOW_TLS,
|
||||
FOLLOW_UDP,
|
||||
FOLLOW_DCCP,
|
||||
FOLLOW_HTTP,
|
||||
FOLLOW_HTTP2,
|
||||
FOLLOW_QUIC,
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,71 @@
|
|||
#
|
||||
# Wireshark tests
|
||||
#
|
||||
# Copyright 2020-2021 by Thomas Dreibholz <dreibh [AT] simula.no>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
'''Follow DCCP Stream tests'''
|
||||
|
||||
import subprocesstest
|
||||
import fixtures
|
||||
|
||||
|
||||
@fixtures.mark_usefixtures('test_env')
|
||||
@fixtures.uses_fixtures
|
||||
class case_follow_dccp(subprocesstest.SubprocessTestCase):
|
||||
def test_follow_dccp_bad_conditions(self, cmd_tshark, capture_file):
|
||||
'''Checks whether Follow DCCP correctly handles some tests.'''
|
||||
|
||||
# Test 1:
|
||||
# 1. Identification of DCCP Flow #9
|
||||
# 2. Selection and decoding of DCCP Flow #9
|
||||
proc = self.assertRun((cmd_tshark,
|
||||
'-r', capture_file('netperfmeter-dccp.pcapng.gz'),
|
||||
'-qz', 'follow,dccp,hex,9',
|
||||
))
|
||||
|
||||
self.assertIn("""\
|
||||
===================================================================
|
||||
Follow: dccp,hex
|
||||
Filter: dccp.stream eq 9
|
||||
Node 0: 127.0.0.1:43933
|
||||
Node 1: 127.0.0.1:9000
|
||||
00000000 04 00 00 1a 00 00 00 09 4b cd f3 aa 30 3c 67 74 ........ K...0<gt
|
||||
00000010 f2 41 ee 5f c8 10 1f 41 00 00 .A._...A ..
|
||||
0000001A 05 03 27 10 00 00 00 09 f2 41 ee 5f c8 10 1f 41 ..'..... .A._...A
|
||||
0000002A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
|
||||
0000003A 00 00 00 00 00 00 00 00 00 05 ba 0a bf 18 68 19 ........ ......h.
|
||||
0000004A 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d .. !"#$% &'()*+,-
|
||||
0000005A 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d ./012345 6789:;<=
|
||||
0000006A 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d >?@ABCDE FGHIJKLM
|
||||
0000007A 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d NOPQRSTU VWXYZ[\]
|
||||
0000008A 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d ^_`abcde fghijklm
|
||||
0000009A 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d nopqrstu vwxyz{|}
|
||||
000000AA 7e 7f 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b ~... !"# $%&'()*+
|
||||
000000BA 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b ,-./0123 456789:;
|
||||
000000CA 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b <=>?@ABC DEFGHIJK
|
||||
000000DA 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b LMNOPQRS TUVWXYZ[
|
||||
000000EA 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b \]^_`abc defghijk
|
||||
000000FA 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b lmnopqrs tuvwxyz{
|
||||
0000010A 7c 7d 7e 7f 1e 1f 20 21 22 23 24 25 26 27 28 29 |}~... ! "#$%&'()
|
||||
0000011A 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 *+,-./01 23456789
|
||||
""".replace("\r\n", "\n"),
|
||||
proc.stdout_str)
|
||||
|
||||
# Test 2:
|
||||
# Trying identification of not-existing DCCP Flow #10
|
||||
proc = self.assertRun((cmd_tshark,
|
||||
'-r', capture_file('netperfmeter-dccp.pcapng.gz'),
|
||||
'-qz', 'follow,dccp,hex,10',
|
||||
))
|
||||
|
||||
self.assertIn("""\
|
||||
===================================================================
|
||||
Follow: dccp,hex
|
||||
Filter: dccp.stream eq 10
|
||||
Node 0: :0
|
||||
Node 1: :0
|
||||
===================================================================
|
||||
""".replace("\r\n", "\n"),
|
||||
proc.stdout_str)
|
|
@ -16,6 +16,7 @@
|
|||
#include "epan/follow.h"
|
||||
#include "epan/dissectors/packet-tcp.h"
|
||||
#include "epan/dissectors/packet-udp.h"
|
||||
#include "epan/dissectors/packet-dccp.h"
|
||||
#include "epan/dissectors/packet-http2.h"
|
||||
#include "epan/dissectors/packet-quic.h"
|
||||
#include "epan/prefs.h"
|
||||
|
@ -93,6 +94,9 @@ FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_
|
|||
case FOLLOW_UDP:
|
||||
follower_ = get_follow_by_name("UDP");
|
||||
break;
|
||||
case FOLLOW_DCCP:
|
||||
follower_ = get_follow_by_name("DCCP");
|
||||
break;
|
||||
case FOLLOW_HTTP:
|
||||
follower_ = get_follow_by_name("HTTP");
|
||||
break;
|
||||
|
@ -519,6 +523,7 @@ FollowStreamDialog::readStream()
|
|||
|
||||
case FOLLOW_TCP :
|
||||
case FOLLOW_UDP :
|
||||
case FOLLOW_DCCP :
|
||||
case FOLLOW_HTTP :
|
||||
case FOLLOW_HTTP2:
|
||||
case FOLLOW_QUIC:
|
||||
|
@ -941,6 +946,18 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
|
|||
|
||||
break;
|
||||
}
|
||||
case FOLLOW_DCCP:
|
||||
{
|
||||
int stream_count = get_dccp_stream_count();
|
||||
ui->streamNumberSpinBox->blockSignals(true);
|
||||
ui->streamNumberSpinBox->setMaximum(stream_count-1);
|
||||
ui->streamNumberSpinBox->setValue(stream_num);
|
||||
ui->streamNumberSpinBox->blockSignals(false);
|
||||
ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count));
|
||||
ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());
|
||||
|
||||
break;
|
||||
}
|
||||
case FOLLOW_HTTP2:
|
||||
{
|
||||
int stream_count = get_tcp_stream_count();
|
||||
|
|
|
@ -574,6 +574,7 @@ private slots:
|
|||
void openFollowStreamDialogForType(follow_type_t type);
|
||||
void on_actionAnalyzeFollowTCPStream_triggered();
|
||||
void on_actionAnalyzeFollowUDPStream_triggered();
|
||||
void on_actionAnalyzeFollowDCCPStream_triggered();
|
||||
void on_actionAnalyzeFollowTLSStream_triggered();
|
||||
void on_actionAnalyzeFollowHTTPStream_triggered();
|
||||
void on_actionAnalyzeFollowHTTP2Stream_triggered();
|
||||
|
|
|
@ -1710,6 +1710,17 @@
|
|||
<string notr="true">Ctrl+Alt+Shift+U</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAnalyzeFollowDCCPStream">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>DCCP Stream</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string notr="true">Ctrl+Alt+Shift+E</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAnalyzeFollowTLSStream">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
|
|
|
@ -1123,7 +1123,7 @@ void MainWindow::recentActionTriggered() {
|
|||
|
||||
void MainWindow::setMenusForSelectedPacket()
|
||||
{
|
||||
gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_tls = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE,
|
||||
gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_dccp = FALSE, is_sctp = FALSE, is_tls = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE,
|
||||
is_http = FALSE, is_http2 = FALSE, is_quic = FALSE;
|
||||
|
||||
/* Making the menu context-sensitive allows for easier selection of the
|
||||
|
@ -1193,6 +1193,7 @@ void MainWindow::setMenusForSelectedPacket()
|
|||
proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers,
|
||||
&is_ip, &is_tcp, &is_udp, &is_sctp,
|
||||
&is_tls, &is_rtp, &is_lte_rlc);
|
||||
is_dccp = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "dccp");
|
||||
is_http = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http");
|
||||
is_http2 = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http2");
|
||||
is_quic = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "quic");
|
||||
|
@ -1237,6 +1238,7 @@ void MainWindow::setMenusForSelectedPacket()
|
|||
|
||||
main_ui_->actionAnalyzeFollowTCPStream->setEnabled(is_tcp);
|
||||
main_ui_->actionAnalyzeFollowUDPStream->setEnabled(is_udp);
|
||||
main_ui_->actionAnalyzeFollowDCCPStream->setEnabled(is_dccp);
|
||||
main_ui_->actionAnalyzeFollowTLSStream->setEnabled(is_tls);
|
||||
main_ui_->actionAnalyzeFollowHTTPStream->setEnabled(is_http);
|
||||
main_ui_->actionAnalyzeFollowHTTP2Stream->setEnabled(is_http2);
|
||||
|
@ -2880,6 +2882,11 @@ void MainWindow::on_actionAnalyzeFollowUDPStream_triggered()
|
|||
openFollowStreamDialogForType(FOLLOW_UDP);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAnalyzeFollowDCCPStream_triggered()
|
||||
{
|
||||
openFollowStreamDialogForType(FOLLOW_DCCP);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAnalyzeFollowTLSStream_triggered()
|
||||
{
|
||||
openFollowStreamDialogForType(FOLLOW_TLS);
|
||||
|
|
|
@ -683,6 +683,7 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
|
|||
ctx_menu->addMenu(submenu);
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTCPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowDCCPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
|
||||
|
|
|
@ -304,6 +304,7 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
|
|||
ctx_menu.addMenu(submenu);
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTCPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowDCCPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
|
||||
|
|
Loading…
Reference in New Issue