forked from osmocom/wireshark
Qt, http2: Add Follow HTTP/2 Stream functionality
The HTTP/2 protocol multiplexes a single TCP connection into multiple independent streams. The Follow TCP output can interleave multiple HTTP/2 streams, making it harder to analyze a single HTTP/2 stream. Add the ability to select HTTP/2 Streams within a TCP stream. Internally, the HTTP/2 dissector now stores the known Stream IDs in a set for every TCP session which allows an amortized O(n) lookup time for the previous/next/max Stream ID. [Peter: make the dissector responsible for clamping the HTTP/2 Stream ID instead of the Qt code, that should permit future optimizations.] Change-Id: I5d78f29904ae8f227ae36e1a883155c0ed719200 Reviewed-on: https://code.wireshark.org/review/32221 Reviewed-by: Peter Wu <peter@lekensteyn.nl> Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot Reviewed-by: Alexander Gryanko <xpahos@gmail.com> Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
This commit is contained in:
parent
893a2d9c62
commit
9fff62e2a8
|
@ -898,6 +898,8 @@ libwireshark.so.0 libwireshark0 #MINVER#
|
|||
hfinfo_bitshift@Base 1.12.0~rc1
|
||||
host_name_lookup_process@Base 1.9.1
|
||||
hostlist_table_set_gui_info@Base 1.99.0
|
||||
http2_get_stream_id_ge@Base 3.1.1
|
||||
http2_get_stream_id_le@Base 3.1.1
|
||||
http_tcp_dissector_add@Base 2.1.0
|
||||
http_tcp_dissector_delete@Base 2.3.0
|
||||
http_tcp_port_add@Base 2.1.0
|
||||
|
|
|
@ -1219,7 +1219,7 @@ Example: B<-z flow,tcp,network> will show data flow for all TCP frames
|
|||
|
||||
=item B<-z> follow,I<prot>,I<mode>,I<filter>[I<,range>]
|
||||
|
||||
Displays the contents of a TCP or UDP stream between two nodes. The data
|
||||
Displays the contents of a TCP or UDP stream between two nodes. The data
|
||||
sent by the second node is prefixed with a tab to differentiate it from the
|
||||
data sent by the first node.
|
||||
|
||||
|
@ -1241,10 +1241,12 @@ of each section of output plus a newline precedes each section of output.
|
|||
|
||||
I<filter> specifies the stream to be displayed. UDP/TCP streams are selected
|
||||
with either the stream index or IP address plus port pairs. TLS streams are
|
||||
selected with the stream index. For example:
|
||||
selected with the stream index. HTTP/2 streams are selected by combination of
|
||||
UDP/TCP and HTTP/2 streams indices. For example:
|
||||
|
||||
ip-addr0:port0,ip-addr1:port1
|
||||
stream-index
|
||||
stream-index,substream-index
|
||||
|
||||
I<range> optionally specifies which "chunks" of the stream should be displayed.
|
||||
|
||||
|
@ -1277,6 +1279,23 @@ display the contents of a TCP stream between 200.57.7.197 port 32891 and
|
|||
4
|
||||
....
|
||||
|
||||
Example: B<-z "follow,http2,hex,0,1"> will display the contents of a HTTP/2
|
||||
stream on the first TCP session (index 0) with HTTP/2 Stream ID 1.
|
||||
|
||||
===================================================================
|
||||
Follow: http2,hex
|
||||
Filter: tcp.stream eq 0 and http2.streamid eq 1
|
||||
Node 0: 172.16.5.1:49178
|
||||
Node 1: 172.16.5.10:8443
|
||||
00000000 00 00 2c 01 05 00 00 00 01 82 04 8b 63 c1 ac 2a ..,..... ....c..*
|
||||
00000010 27 1d 9d 57 ae a9 bf 87 41 8c 0b a2 5c 2e 2e da '..W.... A...\...
|
||||
00000020 e1 05 c7 9a 69 9f 7a 88 25 b6 50 c3 ab b6 25 c3 ....i.z. %.P...%.
|
||||
00000030 53 03 2a 2f 2a S.*/*
|
||||
00000000 00 00 22 01 04 00 00 00 01 88 5f 87 35 23 98 ac .."..... .._.5#..
|
||||
00000010 57 54 df 61 96 c3 61 be 94 03 8a 61 2c 6a 08 2f WT.a..a. ...a,j./
|
||||
00000020 34 a0 5b b8 21 5c 0b ea 62 d1 bf 4.[.!\.. b..
|
||||
0000002B 00 40 00 00 00 00 00 00 01 89 50 4e 47 0d 0a 1a .@...... ..PNG...
|
||||
|
||||
=item B<-z> h225,counter[I<,filter>]
|
||||
|
||||
Count ITU-T H.225 messages and their reasons. In the first column you get a
|
||||
|
|
|
@ -163,6 +163,7 @@ set(WSUG_GRAPHICS
|
|||
wsug_graphics/ws-filters.png
|
||||
wsug_graphics/ws-find-packet.png
|
||||
wsug_graphics/ws-follow-stream.png
|
||||
wsug_graphics/ws-follow-http2-stream.png
|
||||
wsug_graphics/ws-go-menu.png
|
||||
wsug_graphics/ws-goto-packet.png
|
||||
wsug_graphics/ws-gui-colors-preferences.png
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
|
@ -101,6 +101,15 @@ You can switch between streams using the “Stream” selector.
|
|||
You can search for text by entering it in the “Find” entry box and
|
||||
pressing btn:[Find Next].
|
||||
|
||||
.The “Follow HTTP/2 Stream” dialog box
|
||||
image::wsug_graphics/ws-follow-http2-stream.png[{screenshot-attrs}]
|
||||
|
||||
The HTTP/2 Stream dialog is similar to the "Follow TCP Stream" dialog, except
|
||||
for an additional "Substream" dialog field. HTTP/2 Streams are identified by
|
||||
a HTTP/2 Stream Index (field name `http2.streamid`) which are unique within a
|
||||
TCP connection. The “Stream” selector determines the TCP connection whereas the
|
||||
“Substream” selector is used to pick the HTTP/2 Stream ID.
|
||||
|
||||
[[ChAdvShowPacketBytes]]
|
||||
|
||||
=== Show Packet Bytes
|
||||
|
|
|
@ -36,16 +36,16 @@
|
|||
|
||||
#ifdef HAVE_NGHTTP2
|
||||
#include <epan/uat.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "packet-tcp.h"
|
||||
#include <epan/tap.h>
|
||||
#include <epan/stats_tree.h>
|
||||
#include <epan/reassemble.h>
|
||||
#include <epan/follow.h>
|
||||
#include <epan/addr_resolv.h>
|
||||
|
||||
#include "packet-tcp.h"
|
||||
#include "wsutil/pint.h"
|
||||
#include "wsutil/strtoi.h"
|
||||
|
||||
|
@ -199,11 +199,13 @@ typedef struct {
|
|||
nghttp2_hd_inflater *hd_inflater[2];
|
||||
http2_header_repr_info_t header_repr_info[2];
|
||||
wmem_map_t *per_stream_info;
|
||||
guint32 current_stream_id;
|
||||
#endif
|
||||
guint32 current_stream_id;
|
||||
tcp_flow_t *fwd_flow;
|
||||
} http2_session_t;
|
||||
|
||||
static GHashTable* streamid_hash = NULL;
|
||||
|
||||
void proto_register_http2(void);
|
||||
void proto_reg_handoff_http2(void);
|
||||
|
||||
|
@ -212,6 +214,7 @@ struct HTTP2Tap {
|
|||
};
|
||||
|
||||
static int http2_tap = -1;
|
||||
static int http2_follow_tap = -1;
|
||||
|
||||
static const guint8* st_str_http2 = "HTTP2";
|
||||
static const guint8* st_str_http2_type = "Type";
|
||||
|
@ -884,6 +887,8 @@ http2_init_protocol(void)
|
|||
proto_register_field_array(proto_http2, hf_uat, num_header_fields);
|
||||
}
|
||||
#endif
|
||||
/* Init hash table with mapping of stream id -> frames count for Follow HTTP2 */
|
||||
streamid_hash = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_hash_table_destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -895,6 +900,7 @@ http2_cleanup_protocol(void) {
|
|||
proto_add_deregistered_data(hf_uat);
|
||||
proto_free_deregistered_fields();
|
||||
#endif
|
||||
g_hash_table_destroy(streamid_hash);
|
||||
}
|
||||
|
||||
static dissector_handle_t http2_handle;
|
||||
|
@ -1881,6 +1887,109 @@ inflate_http2_header_block(tvbuff_t *tvb, packet_info *pinfo, guint offset,
|
|||
}
|
||||
#endif
|
||||
|
||||
static gchar*
|
||||
http2_follow_conv_filter(packet_info *pinfo, guint *stream, guint *sub_stream)
|
||||
{
|
||||
http2_session_t *h2session;
|
||||
struct tcp_analysis *tcpd;
|
||||
|
||||
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)))
|
||||
{
|
||||
h2session = get_http2_session(pinfo);
|
||||
tcpd = get_tcp_conversation_data(NULL, pinfo);
|
||||
|
||||
if (tcpd == NULL)
|
||||
return NULL;
|
||||
if (h2session == NULL)
|
||||
return NULL;
|
||||
|
||||
*stream = tcpd->stream;
|
||||
*sub_stream = h2session->current_stream_id;
|
||||
return g_strdup_printf("tcp.stream eq %u and http2.streamid eq %u", tcpd->stream, h2session->current_stream_id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_http2_stream_count(guint streamid)
|
||||
{
|
||||
guint32 result = 0;
|
||||
guint32 key;
|
||||
GHashTable *entry;
|
||||
GList *entry_set, *it;
|
||||
|
||||
entry = (GHashTable*)g_hash_table_lookup(streamid_hash, GUINT_TO_POINTER(streamid));
|
||||
if (entry != NULL) {
|
||||
entry_set = g_hash_table_get_keys(entry);
|
||||
|
||||
/* this is a doubly-linked list, g_list_sort has the same time complexity */
|
||||
for (it = entry_set; it != NULL; it = it->next) {
|
||||
key = GPOINTER_TO_UINT(it->data);
|
||||
result = key > result ? key : result;
|
||||
}
|
||||
g_list_free(entry_set);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_http2_stream_contains(guint streamid, gint sub_stream_id)
|
||||
{
|
||||
GHashTable *entry;
|
||||
|
||||
entry = (GHashTable*)g_hash_table_lookup(streamid_hash, GUINT_TO_POINTER(streamid));
|
||||
if (entry == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_hash_table_contains(entry, GINT_TO_POINTER(sub_stream_id))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
http2_get_stream_id_le(guint streamid, guint sub_stream_id, guint *sub_stream_id_out)
|
||||
{
|
||||
// HTTP/2 Stream IDs are always 31 bit.
|
||||
gint max_id = (gint)get_http2_stream_count(streamid);
|
||||
gint id = (gint)(sub_stream_id & MASK_HTTP2_STREAMID);
|
||||
if (id > max_id) {
|
||||
id = max_id;
|
||||
}
|
||||
for (; id >= 0; id--) {
|
||||
if (is_http2_stream_contains(streamid, id)) {
|
||||
*sub_stream_id_out = (guint)id;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
http2_get_stream_id_ge(guint streamid, guint sub_stream_id, guint *sub_stream_id_out)
|
||||
{
|
||||
// HTTP/2 Stream IDs are always 31 bit.
|
||||
gint max_id = (gint)get_http2_stream_count(streamid);
|
||||
for (gint id = (gint)(sub_stream_id & MASK_HTTP2_STREAMID); id <= max_id; id++) {
|
||||
if (is_http2_stream_contains(streamid, id)) {
|
||||
*sub_stream_id_out = (guint)id;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gchar*
|
||||
http2_follow_index_filter(guint stream, guint sub_stream)
|
||||
{
|
||||
return g_strdup_printf("tcp.stream eq %u and http2.streamid eq %u", stream, sub_stream);
|
||||
}
|
||||
|
||||
static guint8
|
||||
dissect_http2_header_flags(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *http2_tree, guint offset, guint8 type)
|
||||
{
|
||||
|
@ -2645,6 +2754,8 @@ dissect_http2_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
|
|||
guint16 length;
|
||||
guint32 streamid;
|
||||
struct HTTP2Tap *http2_stats;
|
||||
GHashTable* entry;
|
||||
struct tcp_analysis* tcpd;
|
||||
|
||||
if(!p_get_proto_data(wmem_file_scope(), pinfo, proto_http2, 0)) {
|
||||
http2_header_data_t *header_data;
|
||||
|
@ -2702,6 +2813,12 @@ dissect_http2_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
|
|||
proto_tree_add_item(http2_tree, hf_http2_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
type = tvb_get_guint8(tvb, offset);
|
||||
|
||||
gint type_idx;
|
||||
const gchar *type_str = try_val_to_str_idx(type, http2_type_vals, &type_idx);
|
||||
if (type_str == NULL) {
|
||||
type_str = wmem_strdup_printf(wmem_packet_scope(), "Unknown type (%d)", type);
|
||||
}
|
||||
|
||||
offset += 1;
|
||||
|
||||
flags = dissect_http2_header_flags(tvb, pinfo, http2_tree, offset, type);
|
||||
|
@ -2710,17 +2827,27 @@ dissect_http2_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
|
|||
proto_tree_add_item(http2_tree, hf_http2_r, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||
proto_tree_add_item(http2_tree, hf_http2_streamid, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||
streamid = tvb_get_ntohl(tvb, offset) & MASK_HTTP2_STREAMID;
|
||||
proto_item_append_text(ti, ": %s, Stream ID: %u, Length %u", val_to_str(type, http2_type_vals, "Unknown type (%d)"), streamid, length);
|
||||
proto_item_append_text(ti, ": %s, Stream ID: %u, Length %u", type_str, streamid, length);
|
||||
offset += 4;
|
||||
|
||||
/* append stream id after frame type on info column, like: HEADERS[1], DATA[1], HEADERS[3], DATA[3] */
|
||||
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s[%u]", val_to_str(type, http2_type_vals, "Unknown type (%d)"), streamid);
|
||||
col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s[%u]", type_str, streamid);
|
||||
|
||||
/* fill hash table with stream ids and skip all unknown frames */
|
||||
tcpd = get_tcp_conversation_data(NULL, pinfo);
|
||||
if (tcpd != NULL && type_idx != -1) {
|
||||
entry = (GHashTable*)g_hash_table_lookup(streamid_hash, GUINT_TO_POINTER(tcpd->stream));
|
||||
if (entry == NULL) {
|
||||
entry = g_hash_table_new(NULL, NULL);
|
||||
g_hash_table_insert(streamid_hash, GUINT_TO_POINTER(tcpd->stream), entry);
|
||||
}
|
||||
|
||||
g_hash_table_add(entry, GUINT_TO_POINTER(streamid));
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGHTTP2
|
||||
/* Mark the current stream, used for per-stream processing later in the dissection */
|
||||
http2_session_t *http2_session = get_http2_session(pinfo);
|
||||
http2_session->current_stream_id = streamid;
|
||||
#endif
|
||||
|
||||
/* Collect stats */
|
||||
http2_stats = wmem_new0(wmem_packet_scope(), struct HTTP2Tap);
|
||||
|
@ -2779,9 +2906,11 @@ dissect_http2_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
|
|||
proto_tree_add_item(http2_tree, hf_http2_unknown, tvb, offset, -1, ENC_NA);
|
||||
break;
|
||||
}
|
||||
|
||||
tap_queue_packet(http2_tap, pinfo, http2_stats);
|
||||
|
||||
if (have_tap_listener(http2_follow_tap)) {
|
||||
tap_queue_packet(http2_follow_tap, pinfo, tvb);
|
||||
}
|
||||
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
@ -3386,6 +3515,10 @@ proto_register_http2(void)
|
|||
&addresses_ports_reassembly_table_functions);
|
||||
|
||||
http2_tap = register_tap("http2");
|
||||
http2_follow_tap = register_tap("http2_follow");
|
||||
|
||||
register_follow_stream(proto_http2, "http2_follow", http2_follow_conv_filter, http2_follow_index_filter, tcp_follow_address_filter,
|
||||
tcp_port_to_display, follow_tvb_tap_listener);
|
||||
}
|
||||
|
||||
static void http2_stats_tree_init(stats_tree* st)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* packet-http2.h
|
||||
* Routines for HTTP2 dissection
|
||||
* Routines for HTTP/2 dissection
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
|
@ -10,6 +10,10 @@
|
|||
#ifndef __PACKET_HTTP2_H__
|
||||
#define __PACKET_HTTP2_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int dissect_http2_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ );
|
||||
|
||||
/** Get header value from current or the other direction stream.
|
||||
|
@ -26,12 +30,30 @@ int dissect_http2_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
|
|||
const gchar* http2_get_header_value(packet_info *pinfo, const gchar* name, gboolean the_other_direction);
|
||||
|
||||
/**
|
||||
* Get the HTTP2 Stream ID for the current PDU (typically the DATA frame).
|
||||
* Get the HTTP/2 Stream ID for the current PDU (typically the DATA frame).
|
||||
* Only valid when called from a HTTP/2 subdissector.
|
||||
* Returns 0 if no HTTP/2 session was found.
|
||||
*/
|
||||
guint32 http2_get_stream_id(packet_info *pinfo);
|
||||
|
||||
/**
|
||||
* Retrieves the HTTP/2 Stream ID which is smaller than or equal to the provided
|
||||
* ID. If available, sub_stream_id_out will be set and TRUE is returned.
|
||||
*/
|
||||
WS_DLL_PUBLIC gboolean
|
||||
http2_get_stream_id_le(guint streamid, guint sub_stream_id, guint *sub_stream_id_out);
|
||||
|
||||
/**
|
||||
* Retrieves the HTTP/2 Stream ID which is greater than or equal to the provided
|
||||
* ID. If available, sub_stream_id_out will be set and TRUE is returned.
|
||||
*/
|
||||
WS_DLL_PUBLIC gboolean
|
||||
http2_get_stream_id_ge(guint streamid, guint sub_stream_id, guint *sub_stream_id_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -904,7 +904,7 @@ tcp_seq_analysis_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_,
|
|||
}
|
||||
|
||||
|
||||
gchar *tcp_follow_conv_filter(packet_info *pinfo, guint *stream)
|
||||
gchar *tcp_follow_conv_filter(packet_info *pinfo, guint *stream, guint *sub_stream _U_)
|
||||
{
|
||||
conversation_t *conv;
|
||||
struct tcp_analysis *tcpd;
|
||||
|
@ -925,7 +925,7 @@ gchar *tcp_follow_conv_filter(packet_info *pinfo, guint *stream)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
gchar *tcp_follow_index_filter(guint stream)
|
||||
gchar *tcp_follow_index_filter(guint stream, guint sub_stream _U_)
|
||||
{
|
||||
return g_strdup_printf("tcp.stream eq %u", stream);
|
||||
}
|
||||
|
|
|
@ -509,8 +509,8 @@ WS_DLL_PUBLIC guint32 get_tcp_stream_count(void);
|
|||
WS_DLL_PUBLIC guint32 get_mptcp_stream_count(void);
|
||||
|
||||
/* Follow Stream functionality shared with HTTP (and SSL?) */
|
||||
extern gchar *tcp_follow_conv_filter(packet_info *pinfo, guint *stream);
|
||||
extern gchar *tcp_follow_index_filter(guint stream);
|
||||
extern gchar *tcp_follow_conv_filter(packet_info *pinfo, guint *stream, guint *sub_stream);
|
||||
extern gchar *tcp_follow_index_filter(guint stream, guint sub_stream);
|
||||
extern gchar *tcp_follow_address_filter(address *src_addr, address *dst_addr, int src_port, int dst_port);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -425,7 +425,7 @@ udp_build_filter(packet_info *pinfo)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static gchar *udp_follow_conv_filter(packet_info *pinfo, guint *stream)
|
||||
static gchar *udp_follow_conv_filter(packet_info *pinfo, guint *stream, guint *sub_stream _U_)
|
||||
{
|
||||
conversation_t *conv;
|
||||
struct udp_analysis *udpd;
|
||||
|
@ -446,7 +446,7 @@ static gchar *udp_follow_conv_filter(packet_info *pinfo, guint *stream)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static gchar *udp_follow_index_filter(guint stream)
|
||||
static gchar *udp_follow_index_filter(guint stream, guint sub_stream _U_)
|
||||
{
|
||||
return g_strdup_printf("udp.stream eq %u", stream);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@ typedef enum {
|
|||
FOLLOW_TCP,
|
||||
FOLLOW_TLS,
|
||||
FOLLOW_UDP,
|
||||
FOLLOW_HTTP
|
||||
FOLLOW_HTTP,
|
||||
FOLLOW_HTTP2
|
||||
} follow_type_t;
|
||||
|
||||
/* Show Type */
|
||||
|
@ -99,8 +100,8 @@ typedef struct _follow_info {
|
|||
struct register_follow;
|
||||
typedef struct register_follow register_follow_t;
|
||||
|
||||
typedef gchar* (*follow_conv_filter_func)(packet_info *pinfo, guint *stream);
|
||||
typedef gchar* (*follow_index_filter_func)(guint stream);
|
||||
typedef gchar* (*follow_conv_filter_func)(packet_info *pinfo, guint *stream, guint *sub_stream);
|
||||
typedef gchar* (*follow_index_filter_func)(guint stream, guint sub_stream);
|
||||
typedef gchar* (*follow_address_filter_func)(address* src_addr, address* dst_addr, int src_port, int dst_port);
|
||||
typedef gchar* (*follow_port_to_display_func)(wmem_allocator_t *allocator, guint port);
|
||||
|
||||
|
|
|
@ -2740,13 +2740,14 @@ sharkd_follower_visit_layers_cb(const void *key _U_, void *value, void *user_dat
|
|||
const int proto_id = get_follow_proto_id(follower);
|
||||
|
||||
guint32 ignore_stream;
|
||||
guint32 ignore_sub_stream;
|
||||
|
||||
if (proto_is_frame_protocol(pi->layers, proto_get_protocol_filter_name(proto_id)))
|
||||
{
|
||||
const char *layer_proto = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
|
||||
char *follow_filter;
|
||||
|
||||
follow_filter = get_follow_conv_func(follower)(pi, &ignore_stream);
|
||||
follow_filter = get_follow_conv_func(follower)(pi, &ignore_stream, &ignore_sub_stream);
|
||||
|
||||
json_dumper_begin_array(&dumper);
|
||||
json_dumper_value_string(&dumper, layer_proto);
|
||||
|
|
|
@ -57,6 +57,33 @@ class case_dissect_http2(subprocesstest.SubprocessTestCase):
|
|||
))
|
||||
self.assertTrue(self.grepOutput('DATA'))
|
||||
|
||||
def test_http2_follow_0(self, cmd_tshark, features, dirs, capture_file):
|
||||
'''Follow HTTP/2 Stream ID 0 test'''
|
||||
if not features.have_nghttp2:
|
||||
self.skipTest('Requires nghttp2.')
|
||||
key_file = os.path.join(dirs.key_dir, 'http2-data-reassembly.keys')
|
||||
self.assertRun((cmd_tshark,
|
||||
'-r', capture_file('http2-data-reassembly.pcap'),
|
||||
'-o', 'tls.keylog_file: {}'.format(key_file),
|
||||
'-z', 'follow,http2,hex,0,0'
|
||||
))
|
||||
self.assertTrue(self.grepOutput('00000000 00 00 12 04 00 00 00 00'))
|
||||
self.assertFalse(self.grepOutput('00000000 00 00 2c 01 05 00 00 00'))
|
||||
|
||||
def test_http2_follow_1(self, cmd_tshark, features, dirs, capture_file):
|
||||
'''Follow HTTP/2 Stream ID 1 test'''
|
||||
if not features.have_nghttp2:
|
||||
self.skipTest('Requires nghttp2.')
|
||||
key_file = os.path.join(dirs.key_dir, 'http2-data-reassembly.keys')
|
||||
self.assertRun((cmd_tshark,
|
||||
'-r', capture_file('http2-data-reassembly.pcap'),
|
||||
'-o', 'tls.keylog_file: {}'.format(key_file),
|
||||
'-z', 'follow,http2,hex,0,1'
|
||||
))
|
||||
self.assertFalse(self.grepOutput('00000000 00 00 12 04 00 00 00 00'))
|
||||
self.assertTrue(self.grepOutput('00000000 00 00 2c 01 05 00 00 00'))
|
||||
|
||||
|
||||
@fixtures.mark_usefixtures('test_env')
|
||||
@fixtures.uses_fixtures
|
||||
class case_dissect_tcp(subprocesstest.SubprocessTestCase):
|
||||
|
|
|
@ -37,6 +37,7 @@ typedef struct _cli_follow_info {
|
|||
|
||||
/* filter */
|
||||
int stream_index;
|
||||
int sub_stream_index;
|
||||
int port[2];
|
||||
address addr[2];
|
||||
union {
|
||||
|
@ -338,6 +339,13 @@ follow_arg_filter(const char **opt_argp, follow_info_t *follow_info)
|
|||
((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
|
||||
{
|
||||
*opt_argp += len;
|
||||
|
||||
/* if it's HTTP2 protocol we should read substream id otherwise it's a range parameter from follow_arg_range */
|
||||
if (cli_follow_info->sub_stream_index == -1 && sscanf(*opt_argp, ",%d%n", &cli_follow_info->sub_stream_index, &len) == 1 &&
|
||||
((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
|
||||
{
|
||||
*opt_argp += len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -438,11 +446,20 @@ static void follow_stream(const char *opt_argp, void *userdata)
|
|||
register_follow_t* follower = (register_follow_t*)userdata;
|
||||
follow_index_filter_func index_filter;
|
||||
follow_address_filter_func address_filter;
|
||||
int proto_id = get_follow_proto_id(follower);
|
||||
const char* proto_filter_name = proto_get_protocol_filter_name(proto_id);
|
||||
|
||||
opt_argp += strlen(STR_FOLLOW);
|
||||
opt_argp += strlen(proto_get_protocol_filter_name(get_follow_proto_id(follower)));
|
||||
opt_argp += strlen(proto_filter_name);
|
||||
|
||||
cli_follow_info = g_new0(cli_follow_info_t, 1);
|
||||
cli_follow_info->stream_index = -1;
|
||||
/* use second parameter only for HTTP2 substream */
|
||||
if (strncmp(proto_filter_name, "http2", 5) == 0) {
|
||||
cli_follow_info->sub_stream_index = -1;
|
||||
} else {
|
||||
cli_follow_info->sub_stream_index = 0;
|
||||
}
|
||||
follow_info = g_new0(follow_info_t, 1);
|
||||
follow_info->gui_data = cli_follow_info;
|
||||
cli_follow_info->follower = follower;
|
||||
|
@ -455,8 +472,8 @@ static void follow_stream(const char *opt_argp, void *userdata)
|
|||
if (cli_follow_info->stream_index >= 0)
|
||||
{
|
||||
index_filter = get_follow_index_func(follower);
|
||||
follow_info->filter_out_filter = index_filter(cli_follow_info->stream_index);
|
||||
if (follow_info->filter_out_filter == NULL)
|
||||
follow_info->filter_out_filter = index_filter(cli_follow_info->stream_index, cli_follow_info->sub_stream_index);
|
||||
if (follow_info->filter_out_filter == NULL || cli_follow_info->sub_stream_index < 0)
|
||||
{
|
||||
follow_exit("Error creating filter for this stream.");
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "epan/follow.h"
|
||||
#include "epan/dissectors/packet-tcp.h"
|
||||
#include "epan/dissectors/packet-udp.h"
|
||||
#include "epan/dissectors/packet-http2.h"
|
||||
#include "epan/prefs.h"
|
||||
#include "epan/addr_resolv.h"
|
||||
#include "epan/charsets.h"
|
||||
|
@ -75,7 +76,8 @@ FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_
|
|||
last_from_server_(0),
|
||||
turns_(0),
|
||||
use_regex_find_(false),
|
||||
terminating_(false)
|
||||
terminating_(false),
|
||||
previous_sub_stream_num_(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
loadGeometry(parent.width() * 2 / 3, parent.height());
|
||||
|
@ -94,6 +96,9 @@ FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_
|
|||
case FOLLOW_HTTP:
|
||||
follower_ = get_follow_by_name("HTTP");
|
||||
break;
|
||||
case FOLLOW_HTTP2:
|
||||
follower_ = get_follow_by_name("HTTP2");
|
||||
break;
|
||||
default :
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -369,8 +374,47 @@ void FollowStreamDialog::on_streamNumberSpinBox_valueChanged(int stream_num)
|
|||
{
|
||||
if (file_closed_) return;
|
||||
|
||||
int sub_stream_num = 0;
|
||||
ui->subStreamNumberSpinBox->blockSignals(true);
|
||||
sub_stream_num = ui->subStreamNumberSpinBox->value();
|
||||
ui->subStreamNumberSpinBox->blockSignals(false);
|
||||
|
||||
if (sub_stream_num < 0) {
|
||||
sub_stream_num = 0;
|
||||
}
|
||||
|
||||
if (stream_num >= 0) {
|
||||
follow(previous_filter_, true, stream_num);
|
||||
follow(previous_filter_, true, stream_num, sub_stream_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FollowStreamDialog::on_subStreamNumberSpinBox_valueChanged(int sub_stream_num)
|
||||
{
|
||||
if (file_closed_) return;
|
||||
|
||||
int stream_num = 0;
|
||||
ui->streamNumberSpinBox->blockSignals(true);
|
||||
stream_num = ui->streamNumberSpinBox->value();
|
||||
ui->streamNumberSpinBox->blockSignals(false);
|
||||
|
||||
guint sub_stream_num_new = static_cast<guint>(sub_stream_num);
|
||||
gboolean ok;
|
||||
/* previous_sub_stream_num_ is a hack to track which buttons was pressed without event handling */
|
||||
if (sub_stream_num < 0) {
|
||||
// Stream ID 0 should always exist as it is used for control messages.
|
||||
sub_stream_num_new = 0;
|
||||
ok = TRUE;
|
||||
} else if (previous_sub_stream_num_ < sub_stream_num){
|
||||
ok = http2_get_stream_id_ge(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
} else {
|
||||
ok = http2_get_stream_id_le(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
}
|
||||
sub_stream_num = static_cast<gint>(sub_stream_num_new);
|
||||
|
||||
if (ok) {
|
||||
follow(previous_filter_, true, stream_num, sub_stream_num);
|
||||
previous_sub_stream_num_ = sub_stream_num;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,6 +432,8 @@ void FollowStreamDialog::removeStreamControls()
|
|||
ui->horizontalLayout->removeItem(ui->streamNumberSpacer);
|
||||
ui->streamNumberLabel->setVisible(false);
|
||||
ui->streamNumberSpinBox->setVisible(false);
|
||||
ui->subStreamNumberLabel->setVisible(false);
|
||||
ui->subStreamNumberSpinBox->setVisible(false);
|
||||
}
|
||||
|
||||
void FollowStreamDialog::resetStream()
|
||||
|
@ -455,6 +501,7 @@ FollowStreamDialog::readStream()
|
|||
case FOLLOW_TCP :
|
||||
case FOLLOW_UDP :
|
||||
case FOLLOW_HTTP :
|
||||
case FOLLOW_HTTP2:
|
||||
case FOLLOW_TLS :
|
||||
ret = readFollowStream();
|
||||
break;
|
||||
|
@ -771,7 +818,7 @@ FollowStreamDialog::showBuffer(char *buffer, size_t nchars, gboolean is_from_ser
|
|||
return FRS_OK;
|
||||
}
|
||||
|
||||
bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index, guint stream_num)
|
||||
bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index, guint stream_num, guint sub_stream_num)
|
||||
{
|
||||
QString follow_filter;
|
||||
const char *hostname0 = NULL, *hostname1 = NULL;
|
||||
|
@ -815,9 +862,9 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
|
|||
/* Create a new filter that matches all packets in the TCP stream,
|
||||
and set the display filter entry accordingly */
|
||||
if (use_stream_index) {
|
||||
follow_filter = gchar_free_to_qstring(get_follow_index_func(follower_)(stream_num));
|
||||
follow_filter = gchar_free_to_qstring(get_follow_index_func(follower_)(stream_num, sub_stream_num));
|
||||
} else {
|
||||
follow_filter = gchar_free_to_qstring(get_follow_conv_func(follower_)(&cap_file_.capFile()->edt->pi, &stream_num));
|
||||
follow_filter = gchar_free_to_qstring(get_follow_conv_func(follower_)(&cap_file_.capFile()->edt->pi, &stream_num, &sub_stream_num));
|
||||
}
|
||||
if (follow_filter.isEmpty()) {
|
||||
QMessageBox::warning(this,
|
||||
|
@ -844,6 +891,15 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* disable substream spin box for all protocols except HTTP2 */
|
||||
ui->subStreamNumberSpinBox->blockSignals(true);
|
||||
ui->subStreamNumberSpinBox->setEnabled(false);
|
||||
ui->subStreamNumberSpinBox->setValue(0);
|
||||
ui->subStreamNumberSpinBox->setKeyboardTracking(false);
|
||||
ui->subStreamNumberSpinBox->blockSignals(false);
|
||||
ui->subStreamNumberSpinBox->setVisible(false);
|
||||
ui->subStreamNumberLabel->setVisible(false);
|
||||
|
||||
switch (follow_type_)
|
||||
{
|
||||
case FOLLOW_TCP:
|
||||
|
@ -870,6 +926,31 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
|
|||
|
||||
break;
|
||||
}
|
||||
case FOLLOW_HTTP2:
|
||||
{
|
||||
int stream_count = get_tcp_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());
|
||||
|
||||
guint substream_max_id = 0;
|
||||
http2_get_stream_id_le(static_cast<guint>(stream_num), G_MAXINT32, &substream_max_id);
|
||||
stream_count = static_cast<gint>(substream_max_id);
|
||||
ui->subStreamNumberSpinBox->blockSignals(true);
|
||||
ui->subStreamNumberSpinBox->setEnabled(true);
|
||||
ui->subStreamNumberSpinBox->setMaximum(stream_count);
|
||||
ui->subStreamNumberSpinBox->setValue(sub_stream_num);
|
||||
ui->subStreamNumberSpinBox->blockSignals(false);
|
||||
ui->subStreamNumberSpinBox->setToolTip(tr("%Ln total sub stream(s).", "", stream_count));
|
||||
ui->subStreamNumberSpinBox->setToolTip(ui->subStreamNumberSpinBox->toolTip());
|
||||
ui->subStreamNumberSpinBox->setVisible(true);
|
||||
ui->subStreamNumberLabel->setVisible(true);
|
||||
|
||||
break;
|
||||
}
|
||||
case FOLLOW_TLS:
|
||||
case FOLLOW_HTTP:
|
||||
/* No extra handling */
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
explicit FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_type_t type = FOLLOW_TCP);
|
||||
~FollowStreamDialog();
|
||||
|
||||
bool follow(QString previous_filter = QString(), bool use_stream_index = false, guint stream_num = 0);
|
||||
bool follow(QString previous_filter = QString(), bool use_stream_index = false, guint stream_num = 0, guint sub_stream_num = 0);
|
||||
|
||||
public slots:
|
||||
void captureEvent(CaptureEvent e);
|
||||
|
@ -69,6 +69,7 @@ private slots:
|
|||
void goToPacketForTextPos(int text_pos);
|
||||
|
||||
void on_streamNumberSpinBox_valueChanged(int stream_num);
|
||||
void on_subStreamNumberSpinBox_valueChanged(int sub_stream_num);
|
||||
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
|
@ -122,6 +123,8 @@ private:
|
|||
bool use_regex_find_;
|
||||
|
||||
bool terminating_;
|
||||
|
||||
int previous_sub_stream_num_;
|
||||
};
|
||||
|
||||
#endif // FOLLOW_STREAM_DIALOG_H
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>594</width>
|
||||
<height>620</height>
|
||||
<width>609</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -41,7 +41,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,0,0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,0,0,0,0">
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbDirections">
|
||||
<property name="sizeAdjustPolicy">
|
||||
|
@ -99,6 +99,16 @@
|
|||
<item>
|
||||
<widget class="QSpinBox" name="streamNumberSpinBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="subStreamNumberLabel">
|
||||
<property name="text">
|
||||
<string>Substream</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="subStreamNumberSpinBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -543,12 +543,14 @@ private slots:
|
|||
void on_actionAnalyzeDecodeAs_triggered();
|
||||
void on_actionAnalyzeReloadLuaPlugins_triggered();
|
||||
|
||||
void openFollowStreamDialog(follow_type_t type, guint stream_num, bool use_stream_index = true);
|
||||
void openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index = true);
|
||||
void openFollowStreamDialogForType(follow_type_t type);
|
||||
void on_actionAnalyzeFollowTCPStream_triggered();
|
||||
void on_actionAnalyzeFollowUDPStream_triggered();
|
||||
void on_actionAnalyzeFollowTLSStream_triggered();
|
||||
void on_actionAnalyzeFollowHTTPStream_triggered();
|
||||
void on_actionAnalyzeFollowHTTP2Stream_triggered();
|
||||
|
||||
void statCommandExpertInfo(const char *, void *);
|
||||
void on_actionAnalyzeExpertInfo_triggered();
|
||||
|
||||
|
|
|
@ -415,6 +415,7 @@
|
|||
<addaction name="actionAnalyzeFollowUDPStream"/>
|
||||
<addaction name="actionAnalyzeFollowTLSStream"/>
|
||||
<addaction name="actionAnalyzeFollowHTTPStream"/>
|
||||
<addaction name="actionAnalyzeFollowHTTP2Stream"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuConversationFilter">
|
||||
<property name="title">
|
||||
|
@ -1711,6 +1712,14 @@
|
|||
<string notr="true">Ctrl+Alt+Shift+H</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAnalyzeFollowHTTP2Stream">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>HTTP/2 Stream</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStatisticsTcpStreamTcptrace">
|
||||
<property name="text">
|
||||
<string>Time Sequence (tcptrace)</string>
|
||||
|
|
|
@ -1114,7 +1114,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, is_http = FALSE;
|
||||
gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_tls = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE, is_http = FALSE, is_http2 = FALSE;
|
||||
|
||||
/* Making the menu context-sensitive allows for easier selection of the
|
||||
desired item and has the added benefit, with large captures, of
|
||||
|
@ -1173,6 +1173,7 @@ void MainWindow::setMenusForSelectedPacket()
|
|||
&is_ip, &is_tcp, &is_udp, &is_sctp,
|
||||
&is_tls, &is_rtp, &is_lte_rlc);
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1205,6 +1206,7 @@ void MainWindow::setMenusForSelectedPacket()
|
|||
main_ui_->actionAnalyzeFollowUDPStream->setEnabled(is_udp);
|
||||
main_ui_->actionAnalyzeFollowTLSStream->setEnabled(is_tls);
|
||||
main_ui_->actionAnalyzeFollowHTTPStream->setEnabled(is_http);
|
||||
main_ui_->actionAnalyzeFollowHTTP2Stream->setEnabled(is_http2);
|
||||
|
||||
foreach(QAction *cc_action, cc_actions) {
|
||||
cc_action->setEnabled(frame_selected);
|
||||
|
@ -2697,7 +2699,7 @@ void MainWindow::on_actionAnalyzeReloadLuaPlugins_triggered()
|
|||
reloadLuaPlugins();
|
||||
}
|
||||
|
||||
void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, bool use_stream_index) {
|
||||
void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index) {
|
||||
FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type);
|
||||
connect(fsd, SIGNAL(updateFilter(QString, bool)), this, SLOT(filterPackets(QString, bool)));
|
||||
connect(fsd, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
|
||||
|
@ -2706,14 +2708,14 @@ void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, bo
|
|||
if (use_stream_index) {
|
||||
// If a specific conversation was requested, then ignore any previous
|
||||
// display filters and display all related packets.
|
||||
fsd->follow("", true, stream_num);
|
||||
fsd->follow("", true, stream_num, sub_stream_num);
|
||||
} else {
|
||||
fsd->follow(getFilter());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::openFollowStreamDialogForType(follow_type_t type) {
|
||||
openFollowStreamDialog(type, 0, false);
|
||||
openFollowStreamDialog(type, 0, 0, false);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAnalyzeFollowTCPStream_triggered()
|
||||
|
@ -2736,6 +2738,11 @@ void MainWindow::on_actionAnalyzeFollowHTTPStream_triggered()
|
|||
openFollowStreamDialogForType(FOLLOW_HTTP);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAnalyzeFollowHTTP2Stream_triggered()
|
||||
{
|
||||
openFollowStreamDialogForType(FOLLOW_HTTP2);
|
||||
}
|
||||
|
||||
void MainWindow::openSCTPAllAssocsDialog()
|
||||
{
|
||||
SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile());
|
||||
|
|
|
@ -543,6 +543,7 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
|
|||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
|
||||
|
||||
ctx_menu->addSeparator();
|
||||
|
||||
|
|
|
@ -285,6 +285,7 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
|
|||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
|
||||
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
|
||||
ctx_menu.addSeparator();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>850</width>
|
||||
<width>969</width>
|
||||
<height>640</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -90,12 +90,12 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="graphTypeComboBox">
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -119,19 +119,19 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="maWindowSizeSpinBox" />
|
||||
<widget class="QDoubleSpinBox" name="maWindowSizeSpinBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="selectSACKsCheckBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Allow SACK segments as well as data packets to be selected by clicking on the graph</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select SACKs</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -180,6 +180,9 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="dragRadioButton">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Drag using the mouse button.</string>
|
||||
</property>
|
||||
|
@ -189,9 +192,6 @@
|
|||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">mouseButtonGroup</string>
|
||||
</attribute>
|
||||
|
@ -199,6 +199,9 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="zoomRadioButton">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select using the mouse button.</string>
|
||||
</property>
|
||||
|
@ -208,9 +211,6 @@
|
|||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">mouseButtonGroup</string>
|
||||
</attribute>
|
||||
|
@ -231,80 +231,80 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="bySeqNumberCheckBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display Round Trip Time vs Sequence Number</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>RTT By Sequence Number</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showSegLengthCheckBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display graph of Segment Length vs Time</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Segment Length</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showThroughputCheckBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display graph of Mean Transmitted Bytes vs Time</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Throughput</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showGoodputCheckBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display graph of Mean ACKed Bytes vs Time</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Goodput</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showRcvWinCheckBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display graph of Receive Window Size vs Time</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rcv Win</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showBytesOutCheckBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display graph of Outstanding Bytes vs Time</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bytes Out</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
Loading…
Reference in New Issue