aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/libwireshark0.symbols1
-rw-r--r--doc/tshark.pod6
-rw-r--r--docbook/wsug_src/WSUG_chapter_advanced.adoc3
-rw-r--r--epan/dissectors/CMakeLists.txt1
-rw-r--r--epan/dissectors/packet-quic.c101
-rw-r--r--epan/dissectors/packet-quic.h26
-rw-r--r--epan/follow.h3
-rw-r--r--ui/cli/tap-follow.c7
-rw-r--r--ui/qt/follow_stream_dialog.cpp45
-rw-r--r--ui/qt/main_window.h1
-rw-r--r--ui/qt/main_window.ui9
-rw-r--r--ui/qt/main_window_slots.cpp10
-rw-r--r--ui/qt/packet_list.cpp1
-rw-r--r--ui/qt/proto_tree.cpp1
14 files changed, 202 insertions, 13 deletions
diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols
index bcb243932e..f46f929fc2 100644
--- a/debian/libwireshark0.symbols
+++ b/debian/libwireshark0.symbols
@@ -852,6 +852,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
get_utf_16_string@Base 1.12.0~rc1
get_vlan_hash_table@Base 2.1.0
get_wka_hashtable@Base 1.12.0~rc1
+ get_quic_connections_count@Base 3.1.1
giop_add_CDR_string@Base 3.0.1
golay_decode@Base 1.9.1
golay_encode@Base 1.9.1
diff --git a/doc/tshark.pod b/doc/tshark.pod
index afcacf332e..625cb19976 100644
--- a/doc/tshark.pod
+++ b/doc/tshark.pod
@@ -1228,6 +1228,8 @@ I<prot> specifies the transport protocol. It can be one of:
tcp TCP
udp UDP
tls TLS or SSL
+ http2 HTTP/2 streams
+ quic QUIC streams
I<mode> specifies the output mode. It can be one of:
@@ -1296,6 +1298,10 @@ stream on the first TCP session (index 0) with HTTP/2 Stream ID 1.
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...
+QUIC streams can be selected through B<-z "follow,quic,hex,3,0">, the first
+number indicates the UDP stream index whereas the second number selects the QUIC
+Stream ID.
+
=item B<-z> h225,counter[I<,filter>]
Count ITU-T H.225 messages and their reasons. In the first column you get a
diff --git a/docbook/wsug_src/WSUG_chapter_advanced.adoc b/docbook/wsug_src/WSUG_chapter_advanced.adoc
index 6eb53fc329..5d943d5f53 100644
--- a/docbook/wsug_src/WSUG_chapter_advanced.adoc
+++ b/docbook/wsug_src/WSUG_chapter_advanced.adoc
@@ -110,6 +110,9 @@ 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.
+The QUIC protocol is similar, the first number selects the UDP stream index
+while the "Substream" field selects the QUIC Stream ID.
+
[[ChAdvShowPacketBytes]]
=== Show Packet Bytes
diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt
index b64f8b1b14..bf14d37fd1 100644
--- a/epan/dissectors/CMakeLists.txt
+++ b/epan/dissectors/CMakeLists.txt
@@ -501,6 +501,7 @@ set(DISSECTOR_PUBLIC_HEADERS
packet-q931.h
packet-q932.h
packet-qsig.h
+ packet-quic.h
packet-radius.h
packet-raknet.h
packet-ranap.h
diff --git a/epan/dissectors/packet-quic.c b/epan/dissectors/packet-quic.c
index e373c8887c..ffdc83861c 100644
--- a/epan/dissectors/packet-quic.c
+++ b/epan/dissectors/packet-quic.c
@@ -34,9 +34,14 @@
#include <epan/to_str.h>
#include "packet-tls-utils.h"
#include "packet-tls.h"
+#include "packet-quic.h"
#include <epan/prefs.h>
#include <wsutil/pint.h>
+#include <epan/tap.h>
+#include <epan/follow.h>
+#include <epan/addr_resolv.h>
+
#if GCRYPT_VERSION_NUMBER >= 0x010600 /* 1.6.0 */
/* Whether to provide support for authentication in addition to decryption. */
#define HAVE_LIBGCRYPT_AEAD
@@ -50,6 +55,8 @@
void proto_reg_handoff_quic(void);
void proto_register_quic(void);
+static int quic_follow_tap = -1;
+
/* Initialize the protocol and registered fields */
static int proto_quic = -1;
static int hf_quic_connection_number = -1;
@@ -229,6 +236,17 @@ struct quic_cid_item {
};
/**
+ * Per-STREAM state, identified by QUIC Stream ID.
+ *
+ * Assume that every QUIC Short Header packet has no STREAM frames that overlap
+ * each other in the same QUIC packet (identified by "frame_num"). Thus, the
+ * Stream ID and offset uniquely identifies the STREAM Frame info in per packet.
+ */
+typedef struct _quic_stream_state {
+ guint64 stream_id;
+} quic_stream_state;
+
+/**
* State for a single QUIC connection, identified by one or more Destination
* Connection IDs (DCID).
*/
@@ -253,6 +271,8 @@ typedef struct quic_info_data {
quic_cid_item_t client_cids; /**< SCID of client from first Initial Packet. */
quic_cid_item_t server_cids; /**< SCID of server from first Retry/Handshake. */
quic_cid_t client_dcid_initial; /**< DCID from Initial Packet. */
+ wmem_map_t *client_streams; /**< Map from Stream ID -> STREAM info (guint64 -> quic_stream_state), sent by the client. */
+ wmem_map_t *server_streams; /**< Map from Stream ID -> STREAM info (guint64 -> quic_stream_state), sent by the server. */
} quic_info_data_t;
/** Per-packet information about QUIC, populated on the first pass. */
@@ -642,6 +662,21 @@ quic_cids_is_known_length(const quic_cid_t *cid)
}
/**
+ * Returns the QUIC connection for the current UDP stream. This may return NULL
+ * after connection migration if the new UDP association was not properly linked
+ * via a match based on the Connection ID.
+ */
+static quic_info_data_t *
+quic_connection_from_conv(packet_info *pinfo)
+{
+ conversation_t *conv = find_conversation_pinfo(pinfo, 0);
+ if (conv) {
+ return (quic_info_data_t *)conversation_get_proto_data(conv, proto_quic);
+ }
+ return NULL;
+}
+
+/**
* Tries to lookup a matching connection (Connection ID is optional).
* If connection is found, "from_server" is set accordingly.
*/
@@ -676,10 +711,9 @@ quic_connection_find_dcid(packet_info *pinfo, const quic_cid_t *dcid, gboolean *
}
}
} else {
- conversation_t *conv = find_conversation_pinfo(pinfo, 0);
- if (conv) {
- conn = (quic_info_data_t *)conversation_get_proto_data(conv, proto_quic);
- check_ports = !!conn;
+ conn = quic_connection_from_conv(pinfo);
+ if (conn) {
+ check_ports = TRUE;
}
}
@@ -1087,6 +1121,9 @@ dissect_quic_frame_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree
proto_item_append_text(ti_ft, " len=%" G_GINT64_MODIFIER "u uni=%d", length, !!(stream_id & 2U));
proto_tree_add_item(ft_tree, hf_quic_stream_data, tvb, offset, (int)length, ENC_NA);
+ if (have_tap_listener(quic_follow_tap)) {
+ tap_queue_packet(quic_follow_tap, pinfo, tvb_new_subset_length(tvb, offset, (int)length));
+ }
offset += (int)length;
}
break;
@@ -2417,6 +2454,58 @@ quic_cleanup(void)
quic_server_connections = NULL;
}
+/* Follow QUIC Stream functionality {{{ */
+
+static gchar *
+quic_follow_conv_filter(packet_info *pinfo, guint *stream, guint *sub_stream)
+{
+ 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))) {
+ gboolean from_server;
+ quic_info_data_t *conn = quic_connection_find_dcid(pinfo, NULL, &from_server);
+ if (!conn) {
+ return NULL;
+ }
+ // XXX Look up stream ID for the current packet.
+ guint stream_id = 0;
+ *stream = conn->number;
+ *sub_stream = stream_id;
+ return g_strdup_printf("quic.connection.number eq %u and quic.stream.stream_id eq %u", conn->number, stream_id);
+ }
+
+ return NULL;
+}
+
+static gchar *
+quic_follow_index_filter(guint stream, guint sub_stream)
+{
+ return g_strdup_printf("quic.connection.number eq %u and quic.stream.stream_id eq %u", stream, sub_stream);
+}
+
+static gchar *
+quic_follow_address_filter(address *src_addr _U_, address *dst_addr _U_, int src_port _U_, int dst_port _U_)
+{
+ // This appears to be solely used for tshark. Let's not support matching by
+ // IP addresses and UDP ports for now since that fails after connection
+ // migration. If necessary, use udp_follow_address_filter.
+ return NULL;
+}
+
+static tap_packet_status
+follow_quic_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
+{
+ // TODO fix filtering for multiple streams, see
+ // https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=16093
+ follow_tvb_tap_listener(tapdata, pinfo, NULL, data);
+ return TAP_PACKET_DONT_REDRAW;
+}
+
+guint32 get_quic_connections_count(void)
+{
+ return quic_connections_count;
+}
+/* Follow QUIC Stream functionality }}} */
+
void
proto_register_quic(void)
{
@@ -2885,6 +2974,9 @@ proto_register_quic(void)
register_init_routine(quic_init);
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);
}
void
@@ -2893,6 +2985,7 @@ proto_reg_handoff_quic(void)
tls13_handshake_handle = find_dissector("tls13-handshake");
dissector_add_uint_with_preference("udp.port", 0, quic_handle);
heur_dissector_add("udp", dissect_quic_heur, "QUIC", "quic", proto_quic, HEURISTIC_ENABLE);
+ quic_follow_tap = register_tap("quic_follow");
}
/*
diff --git a/epan/dissectors/packet-quic.h b/epan/dissectors/packet-quic.h
new file mode 100644
index 0000000000..5e91881fb0
--- /dev/null
+++ b/epan/dissectors/packet-quic.h
@@ -0,0 +1,26 @@
+/* packet-quic.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __PACKET_QUIC_H__
+#define __PACKET_QUIC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "ws_symbol_export.h"
+
+/** Returns the number of items for quic.connection.number. */
+WS_DLL_PUBLIC guint32 get_quic_connections_count(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __PACKET_QUIC_H__ */
diff --git a/epan/follow.h b/epan/follow.h
index aaa366e0e8..c0df89c0ce 100644
--- a/epan/follow.h
+++ b/epan/follow.h
@@ -43,7 +43,8 @@ typedef enum {
FOLLOW_TLS,
FOLLOW_UDP,
FOLLOW_HTTP,
- FOLLOW_HTTP2
+ FOLLOW_HTTP2,
+ FOLLOW_QUIC,
} follow_type_t;
/* Show Type */
diff --git a/ui/cli/tap-follow.c b/ui/cli/tap-follow.c
index c4d7399fd1..f905e59add 100644
--- a/ui/cli/tap-follow.c
+++ b/ui/cli/tap-follow.c
@@ -340,7 +340,7 @@ follow_arg_filter(const char **opt_argp, follow_info_t *follow_info)
{
*opt_argp += len;
- /* if it's HTTP2 protocol we should read substream id otherwise it's a range parameter from follow_arg_range */
+ /* if it's HTTP2 or QUIC 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] == ','))
{
@@ -454,8 +454,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 substream */
- if (strncmp(proto_filter_name, "http2", 5) == 0) {
+ /* use second parameter only for HTTP2 or QUIC substream */
+ if (g_str_equal(proto_filter_name, "http2") ||
+ g_str_equal(proto_filter_name, "quic")) {
cli_follow_info->sub_stream_index = -1;
} else {
cli_follow_info->sub_stream_index = 0;
diff --git a/ui/qt/follow_stream_dialog.cpp b/ui/qt/follow_stream_dialog.cpp
index c845830420..cf6e08e559 100644
--- a/ui/qt/follow_stream_dialog.cpp
+++ b/ui/qt/follow_stream_dialog.cpp
@@ -17,6 +17,7 @@
#include "epan/dissectors/packet-tcp.h"
#include "epan/dissectors/packet-udp.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"
@@ -99,6 +100,9 @@ FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_
case FOLLOW_HTTP2:
follower_ = get_follow_by_name("HTTP2");
break;
+ case FOLLOW_QUIC:
+ follower_ = get_follow_by_name("QUIC");
+ break;
default :
g_assert_not_reached();
}
@@ -405,10 +409,18 @@ void FollowStreamDialog::on_subStreamNumberSpinBox_valueChanged(int sub_stream_n
// 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 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) {
+ // TODO clamp the stream IDs correctly for QUIC
+ ok = TRUE;
} else {
- ok = http2_get_stream_id_le(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
+ // Should not happen, this field is only visible for suitable protocols.
+ return;
}
sub_stream_num = static_cast<gint>(sub_stream_num_new);
@@ -502,6 +514,7 @@ FollowStreamDialog::readStream()
case FOLLOW_UDP :
case FOLLOW_HTTP :
case FOLLOW_HTTP2:
+ case FOLLOW_QUIC:
case FOLLOW_TLS :
ret = readFollowStream();
break;
@@ -891,7 +904,7 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
return false;
}
- /* disable substream spin box for all protocols except HTTP2 */
+ /* disable substream spin box for all protocols except HTTP2 and QUIC */
ui->subStreamNumberSpinBox->blockSignals(true);
ui->subStreamNumberSpinBox->setEnabled(false);
ui->subStreamNumberSpinBox->setValue(0);
@@ -951,6 +964,30 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
break;
}
+ case FOLLOW_QUIC:
+ {
+ int stream_count = get_quic_connections_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());
+
+ // TODO extract number of QUIC streams?
+ stream_count = G_MAXINT32;
+ 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 */
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index 21ad5cc762..60f145f20e 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -554,6 +554,7 @@ private slots:
void on_actionAnalyzeFollowTLSStream_triggered();
void on_actionAnalyzeFollowHTTPStream_triggered();
void on_actionAnalyzeFollowHTTP2Stream_triggered();
+ void on_actionAnalyzeFollowQUICStream_triggered();
void statCommandExpertInfo(const char *, void *);
void on_actionAnalyzeExpertInfo_triggered();
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index 06ffdd1df4..d61882fc21 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -416,6 +416,7 @@
<addaction name="actionAnalyzeFollowTLSStream"/>
<addaction name="actionAnalyzeFollowHTTPStream"/>
<addaction name="actionAnalyzeFollowHTTP2Stream"/>
+ <addaction name="actionAnalyzeFollowQUICStream"/>
</widget>
<widget class="QMenu" name="menuConversationFilter">
<property name="title">
@@ -1720,6 +1721,14 @@
<string>HTTP/2 Stream</string>
</property>
</action>
+ <action name="actionAnalyzeFollowQUICStream">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>QUIC Stream</string>
+ </property>
+ </action>
<action name="actionStatisticsTcpStreamTcptrace">
<property name="text">
<string>Time Sequence (tcptrace)</string>
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index ccf8f1af2e..ec2288addd 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -1115,7 +1115,8 @@ 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, is_http2 = 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, is_quic = FALSE;
/* Making the menu context-sensitive allows for easier selection of the
desired item and has the added benefit, with large captures, of
@@ -1175,6 +1176,7 @@ void MainWindow::setMenusForSelectedPacket()
&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");
+ is_quic = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "quic");
}
}
@@ -1208,6 +1210,7 @@ void MainWindow::setMenusForSelectedPacket()
main_ui_->actionAnalyzeFollowTLSStream->setEnabled(is_tls);
main_ui_->actionAnalyzeFollowHTTPStream->setEnabled(is_http);
main_ui_->actionAnalyzeFollowHTTP2Stream->setEnabled(is_http2);
+ main_ui_->actionAnalyzeFollowQUICStream->setEnabled(is_quic);
foreach(QAction *cc_action, cc_actions) {
cc_action->setEnabled(frame_selected);
@@ -2774,6 +2777,11 @@ void MainWindow::on_actionAnalyzeFollowHTTP2Stream_triggered()
openFollowStreamDialogForType(FOLLOW_HTTP2);
}
+void MainWindow::on_actionAnalyzeFollowQUICStream_triggered()
+{
+ openFollowStreamDialogForType(FOLLOW_QUIC);
+}
+
void MainWindow::openSCTPAllAssocsDialog()
{
SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile());
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index 79063c1051..20d34b5cf7 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -544,6 +544,7 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
+ submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowQUICStream"));
ctx_menu->addSeparator();
diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp
index bc72ca7b3d..e18314ac19 100644
--- a/ui/qt/proto_tree.cpp
+++ b/ui/qt/proto_tree.cpp
@@ -286,6 +286,7 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
+ submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowQUICStream"));
ctx_menu.addSeparator();
}