forked from osmocom/wireshark
follow: Add function for sub stream id to registration
When dissectors register for Follow Stream, have them register a function for finding the next valid sub stream id for a given stream and substream id pair. This function is NULL if the dissector does not use sub stream IDs. Use this function in follow_stream_dialog to update the sub stream id widget (and use the absence of the function to disable and hide the widget.) Use this function in the CLI tap-follow to determine whether to parse a sub stream id from the command line options. This removes the dependencies on epan/dissectors from the Qt follow_stream_dialog, and gets us closer to having dissectors being able to register for Follow Stream without having to update anything in the common source code.
This commit is contained in:
parent
3120e64570
commit
0e93070745
|
@ -1990,7 +1990,7 @@ proto_register_dccp(void)
|
|||
register_conversation_table(proto_dccp, FALSE, dccpip_conversation_packet, dccpip_endpoint_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, get_dccp_stream_count);
|
||||
dccp_port_to_display, follow_tvb_tap_listener, get_dccp_stream_count, NULL);
|
||||
|
||||
register_init_routine(dccp_init);
|
||||
}
|
||||
|
|
|
@ -4513,7 +4513,7 @@ proto_register_http(void)
|
|||
|
||||
register_follow_stream(proto_http, "http_follow", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
|
||||
tcp_port_to_display, follow_tvb_tap_listener,
|
||||
get_tcp_stream_count);
|
||||
get_tcp_stream_count, NULL);
|
||||
http_eo_tap = register_export_object(proto_http, http_eo_packet, NULL);
|
||||
|
||||
/* compile patterns, exluding "/" */
|
||||
|
|
|
@ -2489,6 +2489,16 @@ http2_get_stream_id_ge(guint streamid, guint sub_stream_id, guint *sub_stream_id
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
http2_get_sub_stream_id(guint streamid, guint sub_stream_id, gboolean le, guint *sub_stream_id_out)
|
||||
{
|
||||
if (le) {
|
||||
return http2_get_stream_id_le(streamid, sub_stream_id, sub_stream_id_out);
|
||||
} else {
|
||||
return http2_get_stream_id_ge(streamid, sub_stream_id, sub_stream_id_out);
|
||||
}
|
||||
}
|
||||
|
||||
static gchar*
|
||||
http2_follow_index_filter(guint stream, guint sub_stream)
|
||||
{
|
||||
|
@ -4635,7 +4645,8 @@ proto_register_http2(void)
|
|||
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_http2_tap_listener, get_tcp_stream_count);
|
||||
tcp_port_to_display, follow_http2_tap_listener, get_tcp_stream_count,
|
||||
http2_get_sub_stream_id);
|
||||
}
|
||||
|
||||
static void http2_stats_tree_init(stats_tree* st)
|
||||
|
|
|
@ -4551,6 +4551,16 @@ quic_get_stream_id_ge(guint streamid, guint sub_stream_id, guint *sub_stream_id_
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
quic_get_sub_stream_id(guint streamid, guint sub_stream_id, gboolean le, guint *sub_stream_id_out)
|
||||
{
|
||||
if (le) {
|
||||
return quic_get_stream_id_le(streamid, sub_stream_id, sub_stream_id_out);
|
||||
} else {
|
||||
return quic_get_stream_id_ge(streamid, sub_stream_id, sub_stream_id_out);
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
quic_follow_conv_filter(epan_dissect_t *edt _U_, packet_info *pinfo, guint *stream, guint *sub_stream)
|
||||
{
|
||||
|
@ -5409,7 +5419,8 @@ proto_register_quic(void)
|
|||
register_cleanup_routine(quic_cleanup);
|
||||
|
||||
register_follow_stream(proto_quic, "quic_follow", quic_follow_conv_filter, quic_follow_index_filter, quic_follow_address_filter,
|
||||
udp_port_to_display, follow_quic_tap_listener, get_quic_connections_count);
|
||||
udp_port_to_display, follow_quic_tap_listener, get_quic_connections_count,
|
||||
quic_get_sub_stream_id);
|
||||
|
||||
// TODO implement custom reassembly functions that uses the QUIC Connection
|
||||
// ID instead of address and port numbers.
|
||||
|
|
|
@ -7759,7 +7759,7 @@ void proto_register_sip(void)
|
|||
ws_mempbrk_compile(&pbrk_via_param_end, "\t;, ");
|
||||
|
||||
register_follow_stream(proto_sip, "sip_follow", sip_follow_conv_filter, sip_follow_index_filter, sip_follow_address_filter,
|
||||
udp_port_to_display, follow_tvb_tap_listener, NULL);
|
||||
udp_port_to_display, follow_tvb_tap_listener, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -9742,7 +9742,7 @@ proto_register_tcp(void)
|
|||
|
||||
register_conversation_table(proto_mptcp, FALSE, mptcpip_conversation_packet, tcpip_endpoint_packet);
|
||||
register_follow_stream(proto_tcp, "tcp_follow", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
|
||||
tcp_port_to_display, follow_tcp_tap_listener, get_tcp_stream_count);
|
||||
tcp_port_to_display, follow_tcp_tap_listener, get_tcp_stream_count, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -4766,7 +4766,7 @@ proto_register_tls(void)
|
|||
"tls", tls_tap);
|
||||
|
||||
register_follow_stream(proto_tls, "tls", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
|
||||
tcp_port_to_display, ssl_follow_tap_listener, get_tcp_stream_count);
|
||||
tcp_port_to_display, ssl_follow_tap_listener, get_tcp_stream_count, NULL);
|
||||
secrets_register_type(SECRETS_TYPE_TLS, tls_secrets_block_callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -1476,7 +1476,7 @@ proto_register_udp(void)
|
|||
register_conversation_table(proto_udp, FALSE, udpip_conversation_packet, udpip_endpoint_packet);
|
||||
register_conversation_filter("udp", "UDP", udp_filter_valid, udp_build_filter);
|
||||
register_follow_stream(proto_udp, "udp_follow", udp_follow_conv_filter, udp_follow_index_filter, udp_follow_address_filter,
|
||||
udp_port_to_display, follow_tvb_tap_listener, get_udp_stream_count);
|
||||
udp_port_to_display, follow_tvb_tap_listener, get_udp_stream_count, NULL);
|
||||
|
||||
register_init_routine(udp_init);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ struct register_follow {
|
|||
follow_port_to_display_func port_to_display; /* port to name resolution for follow type */
|
||||
tap_packet_cb tap_handler; /* tap listener handler */
|
||||
follow_stream_count_func stream_count; /* maximum stream count, used for UI */
|
||||
follow_sub_stream_id_func sub_stream_id; /* sub-stream id, used for UI */
|
||||
};
|
||||
|
||||
static wmem_tree_t *registered_followers = NULL;
|
||||
|
@ -36,7 +37,7 @@ static wmem_tree_t *registered_followers = NULL;
|
|||
void register_follow_stream(const int proto_id, const char* tap_listener,
|
||||
follow_conv_filter_func conv_filter, follow_index_filter_func index_filter, follow_address_filter_func address_filter,
|
||||
follow_port_to_display_func port_to_display, tap_packet_cb tap_handler,
|
||||
follow_stream_count_func stream_count)
|
||||
follow_stream_count_func stream_count, follow_sub_stream_id_func sub_stream_id)
|
||||
{
|
||||
register_follow_t *follower;
|
||||
DISSECTOR_ASSERT(tap_listener);
|
||||
|
@ -56,6 +57,7 @@ void register_follow_stream(const int proto_id, const char* tap_listener,
|
|||
follower->port_to_display = port_to_display;
|
||||
follower->tap_handler = tap_handler;
|
||||
follower->stream_count = stream_count;
|
||||
follower->sub_stream_id = sub_stream_id;
|
||||
|
||||
if (registered_followers == NULL)
|
||||
registered_followers = wmem_tree_new(wmem_epan_scope());
|
||||
|
@ -109,6 +111,11 @@ follow_stream_count_func get_follow_stream_count_func(register_follow_t* followe
|
|||
return follower->stream_count;
|
||||
}
|
||||
|
||||
follow_sub_stream_id_func get_follow_sub_stream_id_func(register_follow_t* follower)
|
||||
{
|
||||
return follower->sub_stream_id;
|
||||
}
|
||||
|
||||
register_follow_t* get_follow_by_name(const char* proto_short_name)
|
||||
{
|
||||
return (register_follow_t*)wmem_tree_lookup_string(registered_followers, proto_short_name, 0);
|
||||
|
|
|
@ -111,12 +111,13 @@ 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);
|
||||
typedef guint32 (*follow_stream_count_func)(void);
|
||||
typedef gboolean (*follow_sub_stream_id_func)(guint stream, guint sub_stream, gboolean le, guint *sub_stream_out);
|
||||
|
||||
WS_DLL_PUBLIC
|
||||
void register_follow_stream(const int proto_id, const char* tap_listener,
|
||||
follow_conv_filter_func conv_filter, follow_index_filter_func index_filter, follow_address_filter_func address_filter,
|
||||
follow_port_to_display_func port_to_display, tap_packet_cb tap_handler,
|
||||
follow_stream_count_func stream_count);
|
||||
follow_stream_count_func stream_count, follow_sub_stream_id_func sub_stream_id);
|
||||
|
||||
/** Get protocol ID from registered follower
|
||||
*
|
||||
|
@ -182,6 +183,19 @@ WS_DLL_PUBLIC tap_packet_cb get_follow_tap_handler(register_follow_t* follower);
|
|||
*/
|
||||
WS_DLL_PUBLIC follow_stream_count_func get_follow_stream_count_func(register_follow_t* follower);
|
||||
|
||||
/** Provide function that, for given stream and sub stream ids, searches for
|
||||
* the first sub stream id less than or equal (or greater than or equal) the
|
||||
* given sub stream id present on the given stream id. Returns TRUE and the
|
||||
* sub stream id found, or FALSE.
|
||||
* This is used by the GUI to select valid sub stream numbers, e.g. when
|
||||
* incrementing or decrementing the sub stream ID widget.
|
||||
* This function should be NULL if the follower does not have sub streams.
|
||||
*
|
||||
* @param follower [in] Registered follower
|
||||
* @return A sub stream id function handler
|
||||
*/
|
||||
WS_DLL_PUBLIC follow_sub_stream_id_func get_follow_sub_stream_id_func(register_follow_t* follower);
|
||||
|
||||
/** Tap function handler when dissector's tap provides follow data as a tvb.
|
||||
* Used by TCP, UDP and HTTP followers
|
||||
*/
|
||||
|
|
|
@ -513,9 +513,9 @@ static void follow_stream(const char *opt_argp, void *userdata)
|
|||
|
||||
cli_follow_info = g_new0(cli_follow_info_t, 1);
|
||||
cli_follow_info->stream_index = -1;
|
||||
/* use second parameter only for HTTP2 or QUIC substream */
|
||||
if (g_str_equal(proto_filter_name, "http2") ||
|
||||
g_str_equal(proto_filter_name, "quic")) {
|
||||
/* use second parameter only for followers that have sub streams
|
||||
* (currently HTTP2 or QUIC) */
|
||||
if (get_follow_sub_stream_id_func(follower)) {
|
||||
cli_follow_info->sub_stream_index = -1;
|
||||
} else {
|
||||
cli_follow_info->sub_stream_index = 0;
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
|
||||
#include "frame_tvbuff.h"
|
||||
#include "epan/follow.h"
|
||||
#include "epan/dissectors/packet-http2.h"
|
||||
#include "epan/dissectors/packet-quic.h"
|
||||
#include "epan/prefs.h"
|
||||
#include "epan/addr_resolv.h"
|
||||
#include "epan/charsets.h"
|
||||
|
@ -256,7 +254,7 @@ void FollowStreamDialog::updateWidgets(bool follow_in_progress)
|
|||
ui->cbDirections->setEnabled(enable);
|
||||
ui->cbCharset->setEnabled(enable);
|
||||
ui->streamNumberSpinBox->setEnabled(enable);
|
||||
if (follow_type_ == FOLLOW_HTTP2 || follow_type_ == FOLLOW_QUIC) {
|
||||
if (get_follow_sub_stream_id_func(follower_) != NULL) {
|
||||
ui->subStreamNumberSpinBox->setEnabled(enable);
|
||||
}
|
||||
ui->leFind->setEnabled(enable);
|
||||
|
@ -413,24 +411,32 @@ void FollowStreamDialog::on_streamNumberSpinBox_valueChanged(int stream_num)
|
|||
gboolean ok;
|
||||
if (ui->subStreamNumberSpinBox->isVisible()) {
|
||||
/* We need to find a suitable sub stream for the new stream */
|
||||
follow_sub_stream_id_func sub_stream_func;
|
||||
sub_stream_func = get_follow_sub_stream_id_func(follower_);
|
||||
|
||||
if (sub_stream_func == NULL) {
|
||||
// Should not happen, this field is only visible for suitable protocols.
|
||||
return;
|
||||
}
|
||||
|
||||
guint sub_stream_num_new = static_cast<guint>(sub_stream_num);
|
||||
if (sub_stream_num < 0) {
|
||||
// Stream ID 0 should always exist as it is used for control messages.
|
||||
// XXX: That is only guaranteed for HTTP2. For example, in QUIC,
|
||||
// stream ID 0 is a normal stream used by the first standard client-
|
||||
// initiated bidirectional stream (if it exists, and it might not)
|
||||
// and we might have a stream (connection) but only the CRYPTO
|
||||
// stream, which does not have a (sub) stream ID.
|
||||
// What should we do if there is a stream with no substream to
|
||||
// follow? Right now the substream spinbox is left active and
|
||||
// the user can change the value to no effect.
|
||||
sub_stream_num_new = 0;
|
||||
ok = TRUE;
|
||||
} else if (follow_type_ == FOLLOW_HTTP2) {
|
||||
ok = http2_get_stream_id_ge(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
if (!ok) {
|
||||
ok = http2_get_stream_id_le(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
}
|
||||
} else if (follow_type_ == FOLLOW_QUIC) {
|
||||
ok = quic_get_stream_id_ge(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
if (!ok) {
|
||||
ok = quic_get_stream_id_le(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
}
|
||||
} else {
|
||||
// Should not happen, this field is only visible for suitable protocols.
|
||||
return;
|
||||
ok = sub_stream_func(static_cast<guint>(stream_num), sub_stream_num_new, FALSE, &sub_stream_num_new);
|
||||
if (!ok) {
|
||||
ok = sub_stream_func(static_cast<guint>(stream_num), sub_stream_num_new, TRUE, &sub_stream_num_new);
|
||||
}
|
||||
}
|
||||
sub_stream_num = static_cast<gint>(sub_stream_num_new);
|
||||
} else {
|
||||
|
@ -457,28 +463,26 @@ void FollowStreamDialog::on_subStreamNumberSpinBox_valueChanged(int sub_stream_n
|
|||
stream_num = ui->streamNumberSpinBox->value();
|
||||
ui->streamNumberSpinBox->blockSignals(false);
|
||||
|
||||
follow_sub_stream_id_func sub_stream_func;
|
||||
sub_stream_func = get_follow_sub_stream_id_func(follower_);
|
||||
|
||||
if (sub_stream_func == NULL) {
|
||||
// Should not happen, this field is only visible for suitable protocols.
|
||||
return;
|
||||
}
|
||||
|
||||
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.
|
||||
// XXX: That is only guaranteed for HTTP2, see above.
|
||||
sub_stream_num_new = 0;
|
||||
ok = TRUE;
|
||||
} else if (follow_type_ == FOLLOW_HTTP2) {
|
||||
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);
|
||||
}
|
||||
} else if (follow_type_ == FOLLOW_QUIC) {
|
||||
if (previous_sub_stream_num_ < sub_stream_num) {
|
||||
ok = quic_get_stream_id_ge(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
} else {
|
||||
ok = quic_get_stream_id_le(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
|
||||
}
|
||||
} else if (previous_sub_stream_num_ < sub_stream_num) {
|
||||
ok = sub_stream_func(static_cast<guint>(stream_num), sub_stream_num_new, FALSE, &sub_stream_num_new);
|
||||
} else {
|
||||
// Should not happen, this field is only visible for suitable protocols.
|
||||
return;
|
||||
ok = sub_stream_func(static_cast<guint>(stream_num), sub_stream_num_new, TRUE, &sub_stream_num_new);
|
||||
}
|
||||
sub_stream_num = static_cast<gint>(sub_stream_num_new);
|
||||
|
||||
|
@ -1023,15 +1027,6 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* disable substream spin box for all protocols except HTTP2 and QUIC */
|
||||
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);
|
||||
|
||||
stream_count_func = get_follow_stream_count_func(follower_);
|
||||
|
||||
if (stream_count_func == NULL) {
|
||||
|
@ -1046,45 +1041,30 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
|
|||
ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());
|
||||
}
|
||||
|
||||
switch (follow_type_)
|
||||
{
|
||||
case FOLLOW_HTTP2:
|
||||
{
|
||||
follow_sub_stream_id_func sub_stream_func;
|
||||
sub_stream_func = get_follow_sub_stream_id_func(follower_);
|
||||
if (sub_stream_func != NULL) {
|
||||
guint substream_max_id = 0;
|
||||
http2_get_stream_id_le(static_cast<guint>(stream_num), G_MAXINT32, &substream_max_id);
|
||||
sub_stream_func(static_cast<guint>(stream_num), G_MAXINT32, TRUE, &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(tr("Max sub stream ID for the selected stream: %Ln", "", stream_count));
|
||||
ui->subStreamNumberSpinBox->setToolTip(ui->subStreamNumberSpinBox->toolTip());
|
||||
ui->subStreamNumberSpinBox->setVisible(true);
|
||||
ui->subStreamNumberLabel->setVisible(true);
|
||||
|
||||
break;
|
||||
}
|
||||
case FOLLOW_QUIC:
|
||||
{
|
||||
guint substream_max_id = 0;
|
||||
quic_get_stream_id_le(static_cast<guint>(stream_num), G_MAXINT32, &substream_max_id);
|
||||
stream_count = static_cast<gint>(substream_max_id);
|
||||
} else {
|
||||
/* disable substream spin box for protocols without substreams */
|
||||
ui->subStreamNumberSpinBox->blockSignals(true);
|
||||
ui->subStreamNumberSpinBox->setEnabled(true);
|
||||
ui->subStreamNumberSpinBox->setMaximum(stream_count);
|
||||
ui->subStreamNumberSpinBox->setValue(sub_stream_num);
|
||||
ui->subStreamNumberSpinBox->setEnabled(false);
|
||||
ui->subStreamNumberSpinBox->setValue(0);
|
||||
ui->subStreamNumberSpinBox->setKeyboardTracking(false);
|
||||
ui->subStreamNumberSpinBox->blockSignals(false);
|
||||
ui->subStreamNumberSpinBox->setToolTip(tr("Max QUIC Stream ID for the selected connection: %Ln", "", stream_count));
|
||||
ui->subStreamNumberSpinBox->setToolTip(ui->subStreamNumberSpinBox->toolTip());
|
||||
ui->subStreamNumberSpinBox->setVisible(true);
|
||||
ui->subStreamNumberLabel->setVisible(true);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* No extra handling */
|
||||
break;
|
||||
ui->subStreamNumberSpinBox->setVisible(false);
|
||||
ui->subStreamNumberLabel->setVisible(false);
|
||||
}
|
||||
|
||||
beginRetapPackets();
|
||||
|
|
Loading…
Reference in New Issue