summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-gquic.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-gquic.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-gquic.c')
-rw-r--r--epan/dissectors/packet-gquic.c3302
1 files changed, 3302 insertions, 0 deletions
diff --git a/epan/dissectors/packet-gquic.c b/epan/dissectors/packet-gquic.c
new file mode 100644
index 00000000..36053c01
--- /dev/null
+++ b/epan/dissectors/packet-gquic.c
@@ -0,0 +1,3302 @@
+/* packet-gquic.c
+ * Routines for (Google) Quick UDP Internet Connections dissection
+ * Copyright 2013, Alexis La Goutte <alexis.lagoutte at gmail dot com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+QUIC Wire Layout Specification : https://docs.google.com/document/d/1WJvyZflAO2pq77yOLbp9NsGjC1CHetAXV8I0fQe-B_U/
+
+QUIC Crypto : https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/
+
+QUIC source code in Chromium : https://code.google.com/p/chromium/codesearch#chromium/src/net/quic/quic_utils.h&sq=package:chromium
+
+*/
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/expert.h>
+#include <epan/conversation.h>
+#include "packet-http2.h"
+#include "packet-quic.h"
+#include <wsutil/strtoi.h>
+
+void proto_register_gquic(void);
+void proto_reg_handoff_gquic(void);
+
+static dissector_handle_t gquic_handle;
+static dissector_handle_t tls13_handshake_handle;
+static dissector_handle_t quic_handle;
+
+static int proto_gquic = -1;
+static int hf_gquic_header_form = -1;
+static int hf_gquic_fixed_bit = -1;
+static int hf_gquic_long_packet_type = -1;
+static int hf_gquic_long_reserved = -1;
+static int hf_gquic_packet_number_length = -1;
+static int hf_gquic_dcil = -1;
+static int hf_gquic_scil = -1;
+static int hf_gquic_puflags = -1;
+static int hf_gquic_puflags_vrsn = -1;
+static int hf_gquic_puflags_rst = -1;
+static int hf_gquic_puflags_dnonce = -1;
+static int hf_gquic_puflags_cid = -1;
+static int hf_gquic_puflags_cid_old = -1;
+static int hf_gquic_puflags_pkn = -1;
+static int hf_gquic_puflags_mpth = -1;
+static int hf_gquic_puflags_rsv = -1;
+static int hf_gquic_cid = -1;
+static int hf_gquic_version = -1;
+static int hf_gquic_diversification_nonce = -1;
+static int hf_gquic_packet_number = -1;
+static int hf_gquic_prflags = -1;
+static int hf_gquic_prflags_entropy = -1;
+static int hf_gquic_prflags_fecg = -1;
+static int hf_gquic_prflags_fec = -1;
+static int hf_gquic_prflags_rsv = -1;
+static int hf_gquic_message_authentication_hash = -1;
+static int hf_gquic_frame = -1;
+static int hf_gquic_frame_type = -1;
+static int hf_gquic_frame_type_padding_length = -1;
+static int hf_gquic_frame_type_padding = -1;
+static int hf_gquic_frame_type_rsts_stream_id = -1;
+static int hf_gquic_frame_type_rsts_byte_offset = -1;
+static int hf_gquic_frame_type_rsts_error_code = -1;
+static int hf_gquic_frame_type_cc_error_code = -1;
+static int hf_gquic_frame_type_cc_reason_phrase_length = -1;
+static int hf_gquic_frame_type_cc_reason_phrase = -1;
+static int hf_gquic_frame_type_goaway_error_code = -1;
+static int hf_gquic_frame_type_goaway_last_good_stream_id = -1;
+static int hf_gquic_frame_type_goaway_reason_phrase_length = -1;
+static int hf_gquic_frame_type_goaway_reason_phrase = -1;
+static int hf_gquic_frame_type_wu_stream_id = -1;
+static int hf_gquic_frame_type_wu_byte_offset = -1;
+static int hf_gquic_frame_type_blocked_stream_id = -1;
+static int hf_gquic_frame_type_sw_send_entropy = -1;
+static int hf_gquic_frame_type_sw_least_unacked_delta = -1;
+static int hf_gquic_crypto_offset = -1;
+static int hf_gquic_crypto_length = -1;
+static int hf_gquic_crypto_crypto_data = -1;
+static int hf_gquic_frame_type_stream = -1;
+static int hf_gquic_frame_type_stream_f = -1;
+static int hf_gquic_frame_type_stream_d = -1;
+static int hf_gquic_frame_type_stream_ooo = -1;
+static int hf_gquic_frame_type_stream_ss = -1;
+/* ACK */
+static int hf_gquic_frame_type_ack = -1;
+static int hf_gquic_frame_type_ack_n = -1;
+static int hf_gquic_frame_type_ack_u = -1;
+static int hf_gquic_frame_type_ack_t = -1;
+static int hf_gquic_frame_type_ack_ll = -1;
+static int hf_gquic_frame_type_ack_mm = -1;
+/* ACK Before Q034 */
+static int hf_gquic_frame_type_ack_received_entropy = -1;
+static int hf_gquic_frame_type_ack_largest_observed = -1;
+static int hf_gquic_frame_type_ack_ack_delay_time = -1;
+static int hf_gquic_frame_type_ack_num_timestamp = -1;
+static int hf_gquic_frame_type_ack_delta_largest_observed = -1;
+static int hf_gquic_frame_type_ack_first_timestamp = -1;
+static int hf_gquic_frame_type_ack_time_since_previous_timestamp = -1;
+static int hf_gquic_frame_type_ack_num_ranges = -1;
+static int hf_gquic_frame_type_ack_missing_packet = -1;
+static int hf_gquic_frame_type_ack_range_length = -1;
+static int hf_gquic_frame_type_ack_num_revived = -1;
+static int hf_gquic_frame_type_ack_revived_packet = -1;
+/* ACK After Q034 */
+static int hf_gquic_frame_type_ack_largest_acked = -1;
+static int hf_gquic_frame_type_ack_largest_acked_delta_time = -1;
+static int hf_gquic_frame_type_ack_num_blocks = -1;
+static int hf_gquic_frame_type_ack_first_ack_block_length = -1;
+static int hf_gquic_frame_type_ack_gap_to_next_block = -1;
+static int hf_gquic_frame_type_ack_ack_block_length = -1;
+static int hf_gquic_frame_type_ack_delta_largest_acked = -1;
+static int hf_gquic_frame_type_ack_time_since_largest_acked = -1;
+static int hf_gquic_stream_id = -1;
+static int hf_gquic_offset = -1;
+static int hf_gquic_data_len = -1;
+static int hf_gquic_tag = -1;
+static int hf_gquic_tags = -1;
+static int hf_gquic_tag_number = -1;
+static int hf_gquic_tag_value = -1;
+static int hf_gquic_tag_type = -1;
+static int hf_gquic_tag_offset_end = -1;
+static int hf_gquic_tag_length = -1;
+static int hf_gquic_tag_sni = -1;
+static int hf_gquic_tag_pad = -1;
+static int hf_gquic_tag_ver = -1;
+static int hf_gquic_tag_ccs = -1;
+static int hf_gquic_tag_pdmd = -1;
+static int hf_gquic_tag_uaid = -1;
+static int hf_gquic_tag_stk = -1;
+static int hf_gquic_tag_sno = -1;
+static int hf_gquic_tag_prof = -1;
+static int hf_gquic_tag_scfg = -1;
+static int hf_gquic_tag_scfg_number = -1;
+static int hf_gquic_tag_rrej = -1;
+static int hf_gquic_tag_crt = -1;
+static int hf_gquic_tag_aead = -1;
+static int hf_gquic_tag_scid = -1;
+static int hf_gquic_tag_pubs = -1;
+static int hf_gquic_tag_kexs = -1;
+static int hf_gquic_tag_obit = -1;
+static int hf_gquic_tag_expy = -1;
+static int hf_gquic_tag_nonc = -1;
+static int hf_gquic_tag_mspc = -1;
+static int hf_gquic_tag_tcid = -1;
+static int hf_gquic_tag_srbf = -1;
+static int hf_gquic_tag_icsl = -1;
+static int hf_gquic_tag_scls = -1;
+static int hf_gquic_tag_copt = -1;
+static int hf_gquic_tag_ccrt = -1;
+static int hf_gquic_tag_irtt = -1;
+static int hf_gquic_tag_cfcw = -1;
+static int hf_gquic_tag_sfcw = -1;
+static int hf_gquic_tag_cetv = -1;
+static int hf_gquic_tag_xlct = -1;
+static int hf_gquic_tag_nonp = -1;
+static int hf_gquic_tag_csct = -1;
+static int hf_gquic_tag_ctim = -1;
+static int hf_gquic_tag_mids = -1;
+static int hf_gquic_tag_fhol = -1;
+static int hf_gquic_tag_sttl = -1;
+static int hf_gquic_tag_smhl = -1;
+static int hf_gquic_tag_tbkp = -1;
+static int hf_gquic_tag_mad0 = -1;
+static int hf_gquic_tag_qlve = -1;
+static int hf_gquic_tag_cgst = -1;
+static int hf_gquic_tag_epid = -1;
+static int hf_gquic_tag_srst = -1;
+
+/* Public Reset Tags */
+static int hf_gquic_tag_rnon = -1;
+static int hf_gquic_tag_rseq = -1;
+static int hf_gquic_tag_cadr_addr_type = -1;
+static int hf_gquic_tag_cadr_addr_ipv4 = -1;
+static int hf_gquic_tag_cadr_addr_ipv6 = -1;
+static int hf_gquic_tag_cadr_addr = -1;
+static int hf_gquic_tag_cadr_port = -1;
+
+static int hf_gquic_tag_unknown = -1;
+
+static int hf_gquic_padding = -1;
+static int hf_gquic_stream_data = -1;
+static int hf_gquic_payload = -1;
+
+#define QUIC_PORT_RANGE "80,443"
+static gboolean g_gquic_debug = FALSE;
+
+static gint ett_gquic = -1;
+static gint ett_gquic_puflags = -1;
+static gint ett_gquic_prflags = -1;
+static gint ett_gquic_ft = -1;
+static gint ett_gquic_ftflags = -1;
+static gint ett_gquic_tag_value = -1;
+
+static expert_field ei_gquic_tag_undecoded = EI_INIT;
+static expert_field ei_gquic_tag_length = EI_INIT;
+static expert_field ei_gquic_tag_unknown = EI_INIT;
+static expert_field ei_gquic_version_invalid = EI_INIT;
+static expert_field ei_gquic_invalid_parameter = EI_INIT;
+static expert_field ei_gquic_length_invalid = EI_INIT;
+static expert_field ei_gquic_data_invalid = EI_INIT;
+
+static const value_string gquic_short_long_header_vals[] = {
+ { 0, "Short Header" },
+ { 1, "Long Header" },
+ { 0, NULL }
+};
+static const value_string gquic_long_packet_type_vals[] = {
+ { 0, "Initial" },
+ { 2, "Handshake" },
+ { 1, "0-RTT" },
+ { 0, NULL }
+};
+static const value_string gquic_packet_number_lengths[] = {
+ { 0, "1 bytes" },
+ { 1, "2 bytes" },
+ { 2, "3 bytes" },
+ { 3, "4 bytes" },
+ { 0, NULL }
+};
+static const value_string quic_cid_lengths[] = {
+ { 0, "0 bytes" },
+ { 5, "8 bytes" },
+ { 0, NULL }
+};
+
+#define GQUIC_MIN_LENGTH 3
+#define GQUIC_MAGIC2 0x513032
+#define GQUIC_MAGIC3 0x513033
+#define GQUIC_MAGIC4 0x513034
+
+#define GQUIC_VERSION_Q046 0x51303436
+
+/**************************************************************************/
+/* Public Flags */
+/**************************************************************************/
+#define PUFLAGS_VRSN 0x01
+#define PUFLAGS_RST 0x02
+#define PUFLAGS_DNONCE 0x04
+#define PUFLAGS_CID 0x08
+#define PUFLAGS_CID_OLD 0x0C
+#define PUFLAGS_PKN 0x30
+#define PUFLAGS_MPTH 0x40
+#define PUFLAGS_RSV 0x80
+
+static const true_false_string puflags_cid_tfs = {
+ "8 Bytes",
+ "0 Byte"
+};
+
+static const value_string puflags_cid_old_vals[] = {
+ { 0, "0 Byte" },
+ { 1, "1 Bytes" },
+ { 2, "4 Bytes" },
+ { 3, "8 Bytes" },
+ { 0, NULL }
+};
+
+static const value_string puflags_pkn_vals[] = {
+ { 0, "1 Byte" },
+ { 1, "2 Bytes" },
+ { 2, "4 Bytes" },
+ { 3, "6 Bytes" },
+ { 0, NULL }
+};
+
+/**************************************************************************/
+/* Private Flags */
+/**************************************************************************/
+#define PRFLAGS_ENTROPY 0x01
+#define PRFLAGS_FECG 0x02
+#define PRFLAGS_FEC 0x04
+#define PRFLAGS_RSV 0xF8
+
+
+/**************************************************************************/
+/* Frame Type Regular */
+/**************************************************************************/
+#define FT_PADDING 0x00
+#define FT_RST_STREAM 0x01
+#define FT_CONNECTION_CLOSE 0x02
+#define FT_GOAWAY 0x03
+#define FT_WINDOW_UPDATE 0x04
+#define FT_BLOCKED 0x05
+#define FT_STOP_WAITING 0x06
+#define FT_PING 0x07
+/* CRYPTO is not a real GQUIC frame, but a QUIC one. Since some GQUIC flows
+ * have this kind of frame, try handling it like all the others */
+#define FT_CRYPTO 0x08
+
+/**************************************************************************/
+/* Frame Type Special */
+/**************************************************************************/
+#define FTFLAGS_SPECIAL 0xE0
+
+#define FTFLAGS_STREAM 0x80
+#define FTFLAGS_STREAM_F 0x40
+#define FTFLAGS_STREAM_D 0x20
+#define FTFLAGS_STREAM_OOO 0x1C
+#define FTFLAGS_STREAM_SS 0x03
+
+#define FTFLAGS_ACK 0x40
+#define FTFLAGS_ACK_N 0x20
+#define FTFLAGS_ACK_U 0x10
+#define FTFLAGS_ACK_T 0x10
+#define FTFLAGS_ACK_LL 0x0C
+#define FTFLAGS_ACK_MM 0x03
+
+static const range_string frame_type_vals[] = {
+ { 0,0, "PADDING" },
+ { 1,1, "RST_STREAM" },
+ { 2,2, "CONNECTION_CLOSE" },
+ { 3,3, "GOAWAY" },
+ { 4,4, "WINDOW_UPDATE" },
+ { 5,5, "BLOCKED" },
+ { 6,6, "STOP_WAITING" },
+ { 7,7, "PING" },
+ { 8,8, "CRYPTO" },
+ { 9,31, "Unknown" },
+ { 32,63, "CONGESTION_FEEDBACK (Special Frame Type)" },
+ { 64,127, "ACK (Special Frame Type)" },
+ { 128,256, "STREAM (Special Frame Type)" },
+ { 0,0, NULL }
+};
+
+static const value_string len_offset_vals[] = {
+ { 0, "0 Byte" },
+ { 1, "2 Bytes" },
+ { 2, "3 Bytes" },
+ { 3, "4 Bytes" },
+ { 4, "5 Bytes" },
+ { 5, "6 Bytes" },
+ { 6, "7 Bytes" },
+ { 7, "8 Bytes" },
+ { 0, NULL }
+};
+
+static const value_string len_stream_vals[] = {
+ { 0, "1 Byte" },
+ { 1, "2 Bytes" },
+ { 2, "3 Bytes" },
+ { 3, "4 Bytes" },
+ { 0, NULL }
+};
+
+static const true_false_string len_data_vals = {
+ "2 Bytes",
+ "0 Byte"
+};
+
+static const value_string len_largest_observed_vals[] = {
+ { 0, "1 Byte" },
+ { 1, "2 Bytes" },
+ { 2, "4 Bytes" },
+ { 3, "6 Bytes" },
+ { 0, NULL }
+};
+
+static const value_string len_missing_packet_vals[] = {
+ { 0, "1 Byte" },
+ { 1, "2 Bytes" },
+ { 2, "4 Bytes" },
+ { 3, "6 Bytes" },
+ { 0, NULL }
+};
+
+
+/**************************************************************************/
+/* Message tag */
+/**************************************************************************/
+
+#define MTAG_CHLO 0x43484C4F
+#define MTAG_SHLO 0x53484C4F
+#define MTAG_REJ 0x52454A00
+#define MTAG_PRST 0x50525354
+
+static const value_string message_tag_vals[] = {
+ { MTAG_CHLO, "Client Hello" },
+ { MTAG_SHLO, "Server Hello" },
+ { MTAG_REJ, "Rejection" },
+ { MTAG_PRST, "Public Reset" },
+ { 0, NULL }
+};
+
+/**************************************************************************/
+/* Tag */
+/**************************************************************************/
+/* See https://chromium.googlesource.com/chromium/src.git/+/master/net/third_party/quic/core/crypto/crypto_protocol.h */
+
+#define TAG_PAD 0x50414400
+#define TAG_SNI 0x534E4900
+#define TAG_VER 0x56455200
+#define TAG_CCS 0x43435300
+#define TAG_UAID 0x55414944
+#define TAG_PDMD 0x50444d44
+#define TAG_STK 0x53544b00
+#define TAG_SNO 0x534E4F00
+#define TAG_PROF 0x50524F46
+#define TAG_SCFG 0x53434647
+#define TAG_RREJ 0x5252454A
+#define TAG_CRT 0x435254FF
+#define TAG_AEAD 0x41454144
+#define TAG_SCID 0x53434944
+#define TAG_PUBS 0x50554253
+#define TAG_KEXS 0x4B455853
+#define TAG_OBIT 0x4F424954
+#define TAG_EXPY 0x45585059
+#define TAG_NONC 0x4E4F4E43
+#define TAG_MSPC 0x4D535043
+#define TAG_TCID 0x54434944
+#define TAG_SRBF 0x53524246
+#define TAG_ICSL 0x4943534C
+#define TAG_SCLS 0x53434C53
+#define TAG_COPT 0x434F5054
+#define TAG_CCRT 0x43435254
+#define TAG_IRTT 0x49525454
+#define TAG_CFCW 0x43464357
+#define TAG_SFCW 0x53464357
+#define TAG_CETV 0x43455456
+#define TAG_XLCT 0x584C4354
+#define TAG_NONP 0x4E4F4E50
+#define TAG_CSCT 0x43534354
+#define TAG_CTIM 0x4354494D
+#define TAG_MIDS 0x4D494453
+#define TAG_FHOL 0x46484F4C
+#define TAG_STTL 0x5354544C
+#define TAG_SMHL 0x534D484C
+#define TAG_TBKP 0x54424B50
+#define TAG_MAD0 0x4d414400
+#define TAG_QLVE 0x514C5645
+#define TAG_CGST 0x43475354
+#define TAG_EPID 0x45504944
+#define TAG_SRST 0x53525354
+
+/* Public Reset Tag */
+#define TAG_RNON 0x524E4F4E
+#define TAG_RSEQ 0x52534551
+#define TAG_CADR 0x43414452
+
+static const value_string tag_vals[] = {
+ { TAG_PAD, "Padding" },
+ { TAG_SNI, "Server Name Indication" },
+ { TAG_VER, "Version" },
+ { TAG_CCS, "Common Certificate Sets" },
+ { TAG_UAID, "Client's User Agent ID" },
+ { TAG_PDMD, "Proof Demand" },
+ { TAG_STK, "Source Address Token" },
+ { TAG_SNO, "Server nonce" },
+ { TAG_PROF, "Proof (Signature)" },
+ { TAG_SCFG, "Server Config" },
+ { TAG_RREJ, "Reasons for server sending" },
+ { TAG_CRT, "Certificate chain" },
+ { TAG_AEAD, "Authenticated encryption algorithms" },
+ { TAG_SCID, "Server config ID" },
+ { TAG_PUBS, "Public value" },
+ { TAG_KEXS, "Key exchange algorithms" },
+ { TAG_OBIT, "Server Orbit" },
+ { TAG_EXPY, "Expiry" },
+ { TAG_NONC, "Client Nonce" },
+ { TAG_MSPC, "Max streams per connection" },
+ { TAG_TCID, "Connection ID truncation" },
+ { TAG_SRBF, "Socket receive buffer" },
+ { TAG_ICSL, "Idle connection state" },
+ { TAG_SCLS, "Silently close on timeout" },
+ { TAG_COPT, "Connection options" },
+ { TAG_CCRT, "Cached certificates" },
+ { TAG_IRTT, "Estimated initial RTT" },
+ { TAG_CFCW, "Initial session/connection" },
+ { TAG_SFCW, "Initial stream flow control" },
+ { TAG_CETV, "Client encrypted tag-value" },
+ { TAG_XLCT, "Expected leaf certificate" },
+ { TAG_NONP, "Client Proof Nonce" },
+ { TAG_CSCT, "Signed cert timestamp (RFC6962) of leaf cert" },
+ { TAG_CTIM, "Client Timestamp" },
+ { TAG_MIDS, "Max incoming dynamic streams" },
+ { TAG_FHOL, "Force Head Of Line blocking" },
+ { TAG_STTL, "Server Config TTL" },
+ { TAG_SMHL, "Support Max Header List (size)" },
+ { TAG_TBKP, "Token Binding Key Params" },
+ { TAG_MAD0, "Max Ack Delay (IETF QUIC)" },
+ { TAG_QLVE, "Legacy Version Encapsulation" },
+ { TAG_CGST, "Congestion Control Feedback Type" },
+ { TAG_EPID, "Endpoint Identifier" },
+ { TAG_SRST, "Stateless Reset Token" },
+
+ { TAG_RNON, "Public Reset Nonce Proof" },
+ { TAG_RSEQ, "Rejected Packet Number" },
+ { TAG_CADR, "Client Address" },
+ { 0, NULL }
+};
+
+
+/**************************************************************************/
+/* AEAD Tag */
+/**************************************************************************/
+
+#define AEAD_AESG 0x41455347
+#define AEAD_S20P 0x53323050
+#define AEAD_CC12 0x43433132
+
+static const value_string tag_aead_vals[] = {
+ { AEAD_AESG, "AES-GCM with a 12-byte tag and IV" },
+ { AEAD_S20P, "Salsa20 with Poly1305" },
+ { AEAD_CC12, "Salsa20 with Poly1305" },
+ { 0, NULL }
+};
+
+/**************************************************************************/
+/* KEXS Tag */
+/**************************************************************************/
+
+#define KEXS_C255 0x43323535
+#define KEXS_P256 0x50323536
+
+static const value_string tag_kexs_vals[] = {
+ { KEXS_C255, "Curve25519" },
+ { KEXS_P256, "P-256" },
+ { 0, NULL }
+};
+
+/**************************************************************************/
+/* Client Address Type */
+/**************************************************************************/
+
+static const value_string cadr_type_vals[] = {
+ { 2, "IPv4" },
+ { 10, "IPv6" },
+ { 0, NULL }
+};
+
+/**************************************************************************/
+/* Error Code */
+/**************************************************************************/
+/* See https://chromium.googlesource.com/chromium/src.git/+/master/net/third_party/quic/core/quic_error_codes.h */
+
+enum QuicErrorCode {
+ QUIC_NO_ERROR = 0,
+ /* Connection has reached an invalid state. */
+ QUIC_INTERNAL_ERROR = 1,
+ /* There were data frames after the a fin or reset. */
+ QUIC_STREAM_DATA_AFTER_TERMINATION = 2,
+ /* Control frame is malformed. */
+ QUIC_INVALID_PACKET_HEADER = 3,
+ /* Frame data is malformed. */
+ QUIC_INVALID_FRAME_DATA = 4,
+ /* The packet contained no payload. */
+ QUIC_MISSING_PAYLOAD = 48,
+ /* FEC data is malformed. */
+ QUIC_INVALID_FEC_DATA = 5,
+ /* STREAM frame data is malformed. */
+ QUIC_INVALID_STREAM_DATA = 46,
+ /* STREAM frame data overlaps with buffered data. */
+ QUIC_OVERLAPPING_STREAM_DATA = 87,
+ /* STREAM frame data is not encrypted. */
+ QUIC_UNENCRYPTED_STREAM_DATA = 61,
+ /* Attempt to send unencrypted STREAM frame. */
+ QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA = 88,
+ /* Received a frame which is likely the result of memory corruption. */
+ QUIC_MAYBE_CORRUPTED_MEMORY = 89,
+ /* FEC frame data is not encrypted. */
+ QUIC_UNENCRYPTED_FEC_DATA = 77,
+ /* RST_STREAM frame data is malformed. */
+ QUIC_INVALID_RST_STREAM_DATA = 6,
+ /* CONNECTION_CLOSE frame data is malformed. */
+ QUIC_INVALID_CONNECTION_CLOSE_DATA = 7,
+ /* GOAWAY frame data is malformed. */
+ QUIC_INVALID_GOAWAY_DATA = 8,
+ /* WINDOW_UPDATE frame data is malformed. */
+ QUIC_INVALID_WINDOW_UPDATE_DATA = 57,
+ /* BLOCKED frame data is malformed. */
+ QUIC_INVALID_BLOCKED_DATA = 58,
+ /* STOP_WAITING frame data is malformed. */
+ QUIC_INVALID_STOP_WAITING_DATA = 60,
+ /* PATH_CLOSE frame data is malformed. */
+ QUIC_INVALID_PATH_CLOSE_DATA = 78,
+ /* ACK frame data is malformed. */
+ QUIC_INVALID_ACK_DATA = 9,
+ /* deprecated: */
+ QUIC_INVALID_CONGESTION_FEEDBACK_DATA = 47,
+ /* Version negotiation packet is malformed. */
+ QUIC_INVALID_VERSION_NEGOTIATION_PACKET = 10,
+ /* Public RST packet is malformed. */
+ QUIC_INVALID_PUBLIC_RST_PACKET = 11,
+ /* There was an error decrypting. */
+ QUIC_DECRYPTION_FAILURE = 12,
+ /* There was an error encrypting. */
+ QUIC_ENCRYPTION_FAILURE = 13,
+ /* The packet exceeded kMaxPacketSize. */
+ QUIC_PACKET_TOO_LARGE = 14,
+ /* Data was sent for a stream which did not exist. */
+ QUIC_PACKET_FOR_NONEXISTENT_STREAM = 15,
+ /* The peer is going away. May be a client or server. */
+ QUIC_PEER_GOING_AWAY = 16,
+ /* A stream ID was invalid. */
+ QUIC_INVALID_STREAM_ID = 17,
+ /* A priority was invalid. */
+ QUIC_INVALID_PRIORITY = 49,
+ /* Too many streams already open. */
+ QUIC_TOO_MANY_OPEN_STREAMS = 18,
+ /* The peer created too many available streams. */
+ QUIC_TOO_MANY_AVAILABLE_STREAMS = 76,
+ /* The peer must send a FIN/RST for each stream, and has not been doing so. */
+ QUIC_TOO_MANY_UNFINISHED_STREAMS = 66,
+ /* Received public reset for this connection. */
+ QUIC_PUBLIC_RESET = 19,
+ /* Invalid protocol version. */
+ QUIC_INVALID_VERSION = 20,
+ /* deprecated: */
+ QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED = 21,
+ /* The Header ID for a stream was too far from the previous. */
+ QUIC_INVALID_HEADER_ID = 22,
+ /* Negotiable parameter received during handshake had invalid value. */
+ QUIC_INVALID_NEGOTIATED_VALUE = 23,
+ /* There was an error decompressing data. */
+ QUIC_DECOMPRESSION_FAILURE = 24,
+ /* We hit our prenegotiated (or default) timeout */
+ QUIC_CONNECTION_TIMED_OUT = 25,
+ /* We hit our overall connection timeout */
+ QUIC_CONNECTION_OVERALL_TIMED_OUT = 67,
+ /* There was an error encountered migrating addresses */
+ QUIC_ERROR_MIGRATING_ADDRESS = 26,
+ /* There was an error encountered migrating port only. */
+ QUIC_ERROR_MIGRATING_PORT = 86,
+ /* There was an error while writing to the socket. */
+ QUIC_PACKET_WRITE_ERROR = 27,
+ /* There was an error while reading from the socket. */
+ QUIC_PACKET_READ_ERROR = 51,
+ /* We received a STREAM_FRAME with no data and no fin flag set. */
+ QUIC_INVALID_STREAM_FRAME = 50,
+ /* We received invalid data on the headers stream. */
+ QUIC_INVALID_HEADERS_STREAM_DATA = 56,
+ /* Invalid data on the headers stream received because of decompression failure. */
+ QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE = 97,
+ /* The peer received too much data, violating flow control. */
+ QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 59,
+ /* The peer sent too much data, violating flow control. */
+ QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA = 63,
+ /* The peer received an invalid flow control window. */
+ QUIC_FLOW_CONTROL_INVALID_WINDOW = 64,
+ /* The connection has been IP pooled into an existing connection. */
+ QUIC_CONNECTION_IP_POOLED = 62,
+ /* The connection has too many outstanding sent packets. */
+ QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS = 68,
+ /* The connection has too many outstanding received packets. */
+ QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS = 69,
+ /* The quic connection job to load server config is cancelled. */
+ QUIC_CONNECTION_CANCELLED = 70,
+ /* Disabled QUIC because of high packet loss rate. */
+ QUIC_BAD_PACKET_LOSS_RATE = 71,
+ /* Disabled QUIC because of too many PUBLIC_RESETs post handshake. */
+ QUIC_PUBLIC_RESETS_POST_HANDSHAKE = 73,
+ /* Disabled QUIC because of too many timeouts with streams open. */
+ QUIC_TIMEOUTS_WITH_OPEN_STREAMS = 74,
+ /* Closed because we failed to serialize a packet. */
+ QUIC_FAILED_TO_SERIALIZE_PACKET = 75,
+ /* QUIC timed out after too many RTOs. */
+ QUIC_TOO_MANY_RTOS = 85,
+
+ /* Crypto errors. */
+ /* Handshake failed. */
+ QUIC_HANDSHAKE_FAILED = 28,
+ /* Handshake message contained out of order tags. */
+ QUIC_CRYPTO_TAGS_OUT_OF_ORDER = 29,
+ /* Handshake message contained too many entries. */
+ QUIC_CRYPTO_TOO_MANY_ENTRIES = 30,
+ /* Handshake message contained an invalid value length. */
+ QUIC_CRYPTO_INVALID_VALUE_LENGTH = 31,
+ /* A crypto message was received after the handshake was complete. */
+ QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE = 32,
+ /* A crypto message was received with an illegal message tag. */
+ QUIC_INVALID_CRYPTO_MESSAGE_TYPE = 33,
+ /* A crypto message was received with an illegal parameter. */
+ QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER = 34,
+ /* An invalid channel id signature was supplied. */
+ QUIC_INVALID_CHANNEL_ID_SIGNATURE = 52,
+ /* A crypto message was received with a mandatory parameter missing. */
+ QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND = 35,
+ /* A crypto message was received with a parameter that has no overlap
+ with the local parameter. */
+ QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP = 36,
+ /* A crypto message was received that contained a parameter with too few
+ values. */
+ QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND = 37,
+ /* A demand for an unsupport proof type was received. */
+ QUIC_UNSUPPORTED_PROOF_DEMAND = 94,
+ /* An internal error occurred in crypto processing. */
+ QUIC_CRYPTO_INTERNAL_ERROR = 38,
+ /* A crypto handshake message specified an unsupported version. */
+ QUIC_CRYPTO_VERSION_NOT_SUPPORTED = 39,
+ /* A crypto handshake message resulted in a stateless reject. */
+ QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT = 72,
+ /* There was no intersection between the crypto primitives supported by the
+ peer and ourselves. */
+ QUIC_CRYPTO_NO_SUPPORT = 40,
+ /* The server rejected our client hello messages too many times. */
+ QUIC_CRYPTO_TOO_MANY_REJECTS = 41,
+ /* The client rejected the server's certificate chain or signature. */
+ QUIC_PROOF_INVALID = 42,
+ /* A crypto message was received with a duplicate tag. */
+ QUIC_CRYPTO_DUPLICATE_TAG = 43,
+ /* A crypto message was received with the wrong encryption level (i.e. it
+ should have been encrypted but was not. ) */
+ QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT = 44,
+ /* The server config for a server has expired. */
+ QUIC_CRYPTO_SERVER_CONFIG_EXPIRED = 45,
+ /* We failed to setup the symmetric keys for a connection. */
+ QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED = 53,
+ /* A handshake message arrived, but we are still validating the
+ previous handshake message. */
+ QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO = 54,
+ /* A server config update arrived before the handshake is complete. */
+ QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE = 65,
+ /* CHLO cannot fit in one packet. */
+ QUIC_CRYPTO_CHLO_TOO_LARGE = 90,
+ /* This connection involved a version negotiation which appears to have been
+ tampered with. */
+ QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
+
+ /* Multipath is not enabled, but a packet with multipath flag on is received. */
+ QUIC_BAD_MULTIPATH_FLAG = 79,
+ /* A path is supposed to exist but does not. */
+ QUIC_MULTIPATH_PATH_DOES_NOT_EXIST = 91,
+ /* A path is supposed to be active but is not. */
+ QUIC_MULTIPATH_PATH_NOT_ACTIVE = 92,
+
+ /* IP address changed causing connection close. */
+ QUIC_IP_ADDRESS_CHANGED = 80,
+
+ /* Connection migration errors. */
+ /* Network changed, but connection had no migratable streams. */
+ QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS = 81,
+ /* Connection changed networks too many times. */
+ QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES = 82,
+ /* Connection migration was attempted, but there was no new network to migrate to. */
+ QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK = 83,
+ /* Network changed, but connection had one or more non-migratable streams. */
+ QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM = 84,
+ /* Network changed, but connection migration was disabled by config. */
+ QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG = 99,
+ /* Network changed, but error was encountered on the alternative network. */
+ QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR = 100,
+
+ /* Stream frames arrived too discontiguously so that stream sequencer buffer maintains too many gaps. */
+ QUIC_TOO_MANY_FRAME_GAPS = 93,
+
+ /* Sequencer buffer get into weird state where continuing read/write will lead
+ to crash. */
+ QUIC_STREAM_SEQUENCER_INVALID_STATE = 95,
+ /* Connection closed because of server hits max number of sessions allowed. */
+ QUIC_TOO_MANY_SESSIONS_ON_SERVER = 96,
+
+ /* Receive a RST_STREAM with offset larger than kMaxStreamLength. */
+ QUIC_STREAM_LENGTH_OVERFLOW = 98,
+
+ /* No error. Used as bound while iterating. */
+ QUIC_LAST_ERROR = 101
+};
+
+
+static const value_string error_code_vals[] = {
+ { QUIC_NO_ERROR, "There was no error" },
+ { QUIC_INTERNAL_ERROR, "Connection has reached an invalid state" },
+ { QUIC_STREAM_DATA_AFTER_TERMINATION, "There were data frames after the a fin or reset" },
+ { QUIC_INVALID_PACKET_HEADER, "Control frame is malformed" },
+ { QUIC_INVALID_FRAME_DATA, "Frame data is malformed" },
+ { QUIC_INVALID_FEC_DATA, "FEC data is malformed" },
+ { QUIC_INVALID_RST_STREAM_DATA, "RST_STREAM frame data is malformed" },
+ { QUIC_INVALID_CONNECTION_CLOSE_DATA, "CONNECTION_CLOSE frame data is malformed" },
+ { QUIC_INVALID_GOAWAY_DATA, "GOAWAY frame data is malformed" },
+ { QUIC_INVALID_ACK_DATA, "ACK frame data is malformed" },
+ { QUIC_INVALID_VERSION_NEGOTIATION_PACKET, "Version negotiation packet is malformed" },
+ { QUIC_INVALID_PUBLIC_RST_PACKET, "Public RST packet is malformed" },
+ { QUIC_DECRYPTION_FAILURE, "There was an error decrypting" },
+ { QUIC_ENCRYPTION_FAILURE, "There was an error encrypting" },
+ { QUIC_PACKET_TOO_LARGE, "The packet exceeded kMaxPacketSize" },
+ { QUIC_PACKET_FOR_NONEXISTENT_STREAM, "Data was sent for a stream which did not exist" },
+ { QUIC_PEER_GOING_AWAY, "The peer is going away. May be a client or server" },
+ { QUIC_INVALID_STREAM_ID, "A stream ID was invalid" },
+ { QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams already open" },
+ { QUIC_PUBLIC_RESET, "Received public reset for this connection" },
+ { QUIC_INVALID_VERSION, "Invalid protocol version" },
+ { QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED, "Stream RST before Headers decompressed (Deprecated)" },
+ { QUIC_INVALID_HEADER_ID, "The Header ID for a stream was too far from the previous" },
+ { QUIC_INVALID_NEGOTIATED_VALUE, "Negotiable parameter received during handshake had invalid value" },
+ { QUIC_DECOMPRESSION_FAILURE, "There was an error decompressing data" },
+ { QUIC_CONNECTION_TIMED_OUT, "We hit our prenegotiated (or default) timeout" },
+ { QUIC_ERROR_MIGRATING_ADDRESS, "There was an error encountered migrating addresses" },
+ { QUIC_PACKET_WRITE_ERROR, "There was an error while writing to the socket" },
+ { QUIC_HANDSHAKE_FAILED, "Handshake failed" },
+ { QUIC_CRYPTO_TAGS_OUT_OF_ORDER, "Handshake message contained out of order tags" },
+ { QUIC_CRYPTO_TOO_MANY_ENTRIES, "Handshake message contained too many entries" },
+ { QUIC_CRYPTO_INVALID_VALUE_LENGTH, "Handshake message contained an invalid value length" },
+ { QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, "A crypto message was received after the handshake was complete" },
+ { QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "A crypto message was received with an illegal message tag" },
+ { QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "A crypto message was received with an illegal parameter" },
+ { QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, "A crypto message was received with a mandatory parameter missing" },
+ { QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP, "A crypto message was received with a parameter that has no overlap with the local parameter" },
+ { QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND, "A crypto message was received that contained a parameter with too few values" },
+ { QUIC_CRYPTO_INTERNAL_ERROR, "An internal error occurred in crypto processing" },
+ { QUIC_CRYPTO_VERSION_NOT_SUPPORTED, "A crypto handshake message specified an unsupported version" },
+
+ { QUIC_CRYPTO_NO_SUPPORT, "There was no intersection between the crypto primitives supported by the peer and ourselves" },
+ { QUIC_CRYPTO_TOO_MANY_REJECTS, "The server rejected our client hello messages too many times" },
+ { QUIC_PROOF_INVALID, "The client rejected the server's certificate chain or signature" },
+ { QUIC_CRYPTO_DUPLICATE_TAG, "A crypto message was received with a duplicate tag" },
+ { QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, "A crypto message was received with the wrong encryption level (i.e. it should have been encrypted but was not" },
+ { QUIC_CRYPTO_SERVER_CONFIG_EXPIRED, "The server config for a server has expired" },
+ { QUIC_INVALID_STREAM_DATA, "STREAM frame data is malformed" },
+ { QUIC_INVALID_CONGESTION_FEEDBACK_DATA, "Invalid congestion Feedback data (Deprecated)" },
+ { QUIC_MISSING_PAYLOAD, "The packet contained no payload" },
+ { QUIC_INVALID_PRIORITY, "A priority was invalid" },
+ { QUIC_INVALID_STREAM_FRAME, "We received a STREAM_FRAME with no data and no fin flag set" },
+ { QUIC_PACKET_READ_ERROR, "There was an error while reading from the socket" },
+ { QUIC_INVALID_CHANNEL_ID_SIGNATURE, "An invalid channel id signature was supplied" },
+ { QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED, "We failed to setup the symmetric keys for a connection" },
+ { QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO, "A handshake message arrived, but we are still validating the previous handshake message" },
+ { QUIC_VERSION_NEGOTIATION_MISMATCH, "This connection involved a version negotiation which appears to have been tampered with" },
+ { QUIC_INVALID_HEADERS_STREAM_DATA, "We received invalid data on the headers stream" },
+ { QUIC_INVALID_WINDOW_UPDATE_DATA, "WINDOW_UPDATE frame data is malformed" },
+ { QUIC_INVALID_BLOCKED_DATA, "BLOCKED frame data is malformed" },
+
+ { QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, "The peer received too much data, violating flow control" },
+ { QUIC_INVALID_STOP_WAITING_DATA, "STOP_WAITING frame data is malformed" },
+ { QUIC_UNENCRYPTED_STREAM_DATA, "STREAM frame data is not encrypted" },
+ { QUIC_CONNECTION_IP_POOLED, "The connection has been IP pooled into an existing connection" },
+ { QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, "The peer sent too much data, violating flow control" },
+ { QUIC_FLOW_CONTROL_INVALID_WINDOW, "The peer received an invalid flow control window" },
+ { QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, "A server config update arrived before the handshake is complete" },
+ { QUIC_TOO_MANY_UNFINISHED_STREAMS, "The peer must send a FIN/RST for each stream, and has not been doing so" },
+ { QUIC_CONNECTION_OVERALL_TIMED_OUT, "We hit our overall connection timeout" },
+ { QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS, "The connection has too many outstanding sent packets" },
+ { QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS, "The connection has too many outstanding received packets" },
+ { QUIC_CONNECTION_CANCELLED, "The quic connection job to load server config is cancelled" },
+ { QUIC_BAD_PACKET_LOSS_RATE, "Disabled QUIC because of high packet loss rate" },
+ { QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "A crypto handshake message resulted in a stateless reject" },
+ { QUIC_PUBLIC_RESETS_POST_HANDSHAKE, "Disabled QUIC because of too many PUBLIC_RESETs post handshake" },
+ { QUIC_TIMEOUTS_WITH_OPEN_STREAMS, "Disabled QUIC because of too many timeouts with streams open" },
+ { QUIC_FAILED_TO_SERIALIZE_PACKET, "Closed because we failed to serialize a packet" },
+ { QUIC_TOO_MANY_AVAILABLE_STREAMS, "The peer created too many available streams" },
+ { QUIC_UNENCRYPTED_FEC_DATA, "FEC frame data is not encrypted" },
+ { QUIC_INVALID_PATH_CLOSE_DATA, "PATH_CLOSE frame data is malformed" },
+ { QUIC_BAD_MULTIPATH_FLAG, "Multipath is not enabled, but a packet with multipath flag on is received" },
+ { QUIC_IP_ADDRESS_CHANGED, "IP address changed causing connection close" },
+ { QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS, "Network changed, but connection had no migratable stream" },
+ { QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES, "Connection changed networks too many times" },
+ { QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK, "Connection migration was attempted, but there was no new network to migrate to" },
+ { QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM, "Network changed, but connection had one or more non-migratable streams" },
+ { QUIC_TOO_MANY_RTOS, "QUIC timed out after too many RTOs" },
+ { QUIC_ERROR_MIGRATING_PORT, "There was an error encountered migrating port only" },
+ { QUIC_OVERLAPPING_STREAM_DATA, "STREAM frame data overlaps with buffered data" },
+ { QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, "Attempt to send unencrypted STREAM frame" },
+ { QUIC_MAYBE_CORRUPTED_MEMORY, "Received a frame which is likely the result of memory corruption" },
+ { QUIC_CRYPTO_CHLO_TOO_LARGE, "CHLO cannot fit in one packet" },
+ { QUIC_MULTIPATH_PATH_DOES_NOT_EXIST, "A path is supposed to exist but does not" },
+ { QUIC_MULTIPATH_PATH_NOT_ACTIVE, "A path is supposed to be active but is not" },
+ { QUIC_TOO_MANY_FRAME_GAPS, "Stream frames arrived too discontiguously so that stream sequencer buffer maintains too many gaps" },
+ { QUIC_UNSUPPORTED_PROOF_DEMAND, "A demand for an unsupport proof type was received" },
+ { QUIC_STREAM_SEQUENCER_INVALID_STATE, "Sequencer buffer get into weird state where continuing read/write will lead to crash" },
+ { QUIC_TOO_MANY_SESSIONS_ON_SERVER, "Connection closed because of server hits max number of sessions allowed" },
+ { QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, "Invalid data on the headers stream received because of decompression failure" },
+ { QUIC_STREAM_LENGTH_OVERFLOW, "Receive a RST_STREAM with offset larger than kMaxStreamLength" },
+ { QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG, "Network changed, but connection migration was disabled by config" },
+ { QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR, "Network changed, but error was encountered on the alternative network" },
+ { QUIC_LAST_ERROR, "No error. Used as bound while iterating" },
+ { 0, NULL }
+};
+
+static value_string_ext error_code_vals_ext = VALUE_STRING_EXT_INIT(error_code_vals);
+
+/**************************************************************************/
+/* RST Stream Error Code */
+/**************************************************************************/
+/* See https://chromium.googlesource.com/chromium/src.git/+/master/net/third_party/quic/core/quic_error_codes.h (enum QuicRstStreamErrorCode) */
+
+enum QuicRstStreamErrorCode {
+ /* Complete response has been sent, sending a RST to ask the other endpoint to stop sending request data without discarding the response. */
+
+ QUIC_STREAM_NO_ERROR = 0,
+ /* There was some error which halted stream processing.*/
+ QUIC_ERROR_PROCESSING_STREAM,
+ /* We got two fin or reset offsets which did not match.*/
+ QUIC_MULTIPLE_TERMINATION_OFFSETS,
+ /* We got bad payload and can not respond to it at the protocol level. */
+ QUIC_BAD_APPLICATION_PAYLOAD,
+ /* Stream closed due to connection error. No reset frame is sent when this happens. */
+ QUIC_STREAM_CONNECTION_ERROR,
+ /* GoAway frame sent. No more stream can be created. */
+ QUIC_STREAM_PEER_GOING_AWAY,
+ /* The stream has been cancelled. */
+ QUIC_STREAM_CANCELLED,
+ /* Closing stream locally, sending a RST to allow for proper flow control accounting. Sent in response to a RST from the peer. */
+ QUIC_RST_ACKNOWLEDGEMENT,
+ /* Receiver refused to create the stream (because its limit on open streams has been reached). The sender should retry the request later (using another stream). */
+ QUIC_REFUSED_STREAM,
+ /* Invalid URL in PUSH_PROMISE request header. */
+ QUIC_INVALID_PROMISE_URL,
+ /* Server is not authoritative for this URL. */
+ QUIC_UNAUTHORIZED_PROMISE_URL,
+ /* Can't have more than one active PUSH_PROMISE per URL. */
+ QUIC_DUPLICATE_PROMISE_URL,
+ /* Vary check failed. */
+ QUIC_PROMISE_VARY_MISMATCH,
+ /* Only GET and HEAD methods allowed. */
+ QUIC_INVALID_PROMISE_METHOD,
+ /* The push stream is unclaimed and timed out. */
+ QUIC_PUSH_STREAM_TIMED_OUT,
+ /* Received headers were too large. */
+ QUIC_HEADERS_TOO_LARGE,
+ /* The data is not likely arrive in time. */
+ QUIC_STREAM_TTL_EXPIRED,
+ /* No error. Used as bound while iterating. */
+ QUIC_STREAM_LAST_ERROR,
+};
+
+static const value_string rststream_error_code_vals[] = {
+ { QUIC_STREAM_NO_ERROR, "Complete response has been sent, sending a RST to ask the other endpoint to stop sending request data without discarding the response." },
+ { QUIC_ERROR_PROCESSING_STREAM, "There was some error which halted stream processing" },
+ { QUIC_MULTIPLE_TERMINATION_OFFSETS, "We got two fin or reset offsets which did not match" },
+ { QUIC_BAD_APPLICATION_PAYLOAD, "We got bad payload and can not respond to it at the protocol level" },
+ { QUIC_STREAM_CONNECTION_ERROR, "Stream closed due to connection error. No reset frame is sent when this happens" },
+ { QUIC_STREAM_PEER_GOING_AWAY, "GoAway frame sent. No more stream can be created" },
+ { QUIC_STREAM_CANCELLED, "The stream has been cancelled" },
+ { QUIC_RST_ACKNOWLEDGEMENT, "Closing stream locally, sending a RST to allow for proper flow control accounting. Sent in response to a RST from the peer" },
+ { QUIC_REFUSED_STREAM, "Receiver refused to create the stream (because its limit on open streams has been reached). The sender should retry the request later (using another stream)" },
+ { QUIC_INVALID_PROMISE_URL, "Invalid URL in PUSH_PROMISE request header" },
+ { QUIC_UNAUTHORIZED_PROMISE_URL, "Server is not authoritative for this URL" },
+ { QUIC_DUPLICATE_PROMISE_URL, "Can't have more than one active PUSH_PROMISE per URL" },
+ { QUIC_PROMISE_VARY_MISMATCH, "Vary check failed" },
+ { QUIC_INVALID_PROMISE_METHOD, "Only GET and HEAD methods allowed" },
+ { QUIC_PUSH_STREAM_TIMED_OUT, "The push stream is unclaimed and timed out" },
+ { QUIC_HEADERS_TOO_LARGE, "Received headers were too large" },
+ { QUIC_STREAM_TTL_EXPIRED, "The data is not likely arrive in time" },
+ { QUIC_STREAM_LAST_ERROR, "No error. Used as bound while iterating" },
+ { 0, NULL }
+};
+static value_string_ext rststream_error_code_vals_ext = VALUE_STRING_EXT_INIT(rststream_error_code_vals);
+
+/**************************************************************************/
+/* Handshake Failure Reason */
+/**************************************************************************/
+/* See https://chromium.googlesource.com/chromium/src.git/+/master/net/third_party/quic/core/crypto/crypto_handshake.h */
+
+enum HandshakeFailureReason {
+ HANDSHAKE_OK = 0,
+
+ /* Failure reasons for an invalid client nonce in CHLO. */
+
+ /* The default error value for nonce verification failures from strike register (covers old strike registers and unknown failures). */
+ CLIENT_NONCE_UNKNOWN_FAILURE = 1,
+ /* Client nonce had incorrect length. */
+ CLIENT_NONCE_INVALID_FAILURE = 2,
+ /* Client nonce is not unique. */
+ CLIENT_NONCE_NOT_UNIQUE_FAILURE = 3,
+ /* Client orbit is invalid or incorrect. */
+ CLIENT_NONCE_INVALID_ORBIT_FAILURE = 4,
+ /* Client nonce's timestamp is not in the strike register's valid time range. */
+ CLIENT_NONCE_INVALID_TIME_FAILURE = 5,
+ /* Strike register's RPC call timed out, client nonce couldn't be verified. */
+ CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT = 6,
+ /* Strike register is down, client nonce couldn't be verified. */
+ CLIENT_NONCE_STRIKE_REGISTER_FAILURE = 7,
+
+ /* Failure reasons for an invalid server nonce in CHLO. */
+
+ /* Unbox of server nonce failed. */
+ SERVER_NONCE_DECRYPTION_FAILURE = 8,
+ /* Decrypted server nonce had incorrect length. */
+ SERVER_NONCE_INVALID_FAILURE = 9,
+ /* Server nonce is not unique. */
+ SERVER_NONCE_NOT_UNIQUE_FAILURE = 10,
+ /* Server nonce's timestamp is not in the strike register's valid time range. */
+ SERVER_NONCE_INVALID_TIME_FAILURE = 11,
+ /* The server requires handshake confirmation. */
+ SERVER_NONCE_REQUIRED_FAILURE = 20,
+
+ /* Failure reasons for an invalid server config in CHLO. */
+
+ /* Missing Server config id (kSCID) tag. */
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 12,
+ /* Couldn't find the Server config id (kSCID). */
+ SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE = 13,
+
+ /* Failure reasons for an invalid source-address token. */
+
+ /* Missing Source-address token (kSourceAddressTokenTag) tag. */
+ SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 14,
+ /* Unbox of Source-address token failed. */
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE = 15,
+ /* Couldn't parse the unbox'ed Source-address token. */
+ SOURCE_ADDRESS_TOKEN_PARSE_FAILURE = 16,
+ /* Source-address token is for a different IP address. */
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE = 17,
+ /* The source-address token has a timestamp in the future. */
+ SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE = 18,
+ /* The source-address token has expired. */
+ SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE = 19,
+
+ /* The expected leaf certificate hash could not be validated. */
+ INVALID_EXPECTED_LEAF_CERTIFICATE = 21,
+
+ MAX_FAILURE_REASON = 22
+};
+
+static const value_string handshake_failure_reason_vals[] = {
+ { HANDSHAKE_OK, "Handshake OK" },
+ { CLIENT_NONCE_UNKNOWN_FAILURE, "The default error value for nonce verification failures from strike register (covers old strike registers and unknown failures)" },
+ { CLIENT_NONCE_INVALID_FAILURE, "Client nonce had incorrect length" },
+ { CLIENT_NONCE_NOT_UNIQUE_FAILURE, "Client nonce is not unique" },
+ { CLIENT_NONCE_INVALID_ORBIT_FAILURE, "Client orbit is invalid or incorrect" },
+ { CLIENT_NONCE_INVALID_TIME_FAILURE, "Client nonce's timestamp is not in the strike register's valid time range" },
+ { CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT, "Strike register's RPC call timed out, client nonce couldn't be verified" },
+ { CLIENT_NONCE_STRIKE_REGISTER_FAILURE, "Strike register is down, client nonce couldn't be verified" },
+ { SERVER_NONCE_DECRYPTION_FAILURE, "Unbox of server nonce failed" },
+ { SERVER_NONCE_INVALID_FAILURE, "Decrypted server nonce had incorrect length" },
+ { SERVER_NONCE_NOT_UNIQUE_FAILURE, "Server nonce is not unique" },
+ { SERVER_NONCE_INVALID_TIME_FAILURE, "Server nonce's timestamp is not in the strike register's valid time range" },
+ { SERVER_CONFIG_INCHOATE_HELLO_FAILURE, "Missing Server config id (kSCID) tag" },
+ { SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE, "Couldn't find the Server config id (kSCID)" },
+ { SOURCE_ADDRESS_TOKEN_INVALID_FAILURE, "Missing Source-address token (kSourceAddressTokenTag) tag" },
+ { SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, "Unbox of Source-address token failed" },
+ { SOURCE_ADDRESS_TOKEN_PARSE_FAILURE, "Couldn't parse the unbox'ed Source-address token" },
+ { SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, "Source-address token is for a different IP address" },
+ { SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE, "The source-address token has a timestamp in the future" },
+ { SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE, "The source-address token has expired" },
+ { SERVER_NONCE_REQUIRED_FAILURE, "The server requires handshake confirmation" },
+ { INVALID_EXPECTED_LEAF_CERTIFICATE, "The expected leaf certificate hash could not be validated" },
+ { 0, NULL }
+};
+static value_string_ext handshake_failure_reason_vals_ext = VALUE_STRING_EXT_INIT(handshake_failure_reason_vals);
+
+
+static guint32 get_len_offset(guint8 frame_type){
+
+ switch((frame_type & FTFLAGS_STREAM_OOO) >> 2){
+ case 0:
+ return 0;
+ break;
+ case 1:
+ return 2;
+ break;
+ case 2:
+ return 3;
+ break;
+ case 3:
+ return 4;
+ break;
+ case 4:
+ return 5;
+ break;
+ case 5:
+ return 6;
+ break;
+ case 6:
+ return 7;
+ break;
+ case 7:
+ return 8;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+static guint32 get_len_stream(guint8 frame_type){
+
+ switch(frame_type & FTFLAGS_STREAM_SS){
+ case 0:
+ return 1;
+ break;
+ case 1:
+ return 2;
+ break;
+ case 2:
+ return 3;
+ break;
+ case 3:
+ return 4;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+static guint32 get_len_largest_observed(guint8 frame_type){
+
+ switch((frame_type & FTFLAGS_ACK_LL) >> 2){
+ case 0:
+ return 1;
+ break;
+ case 1:
+ return 2;
+ break;
+ case 2:
+ return 4;
+ break;
+ case 3:
+ return 6;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+static guint32 get_len_missing_packet(guint8 frame_type){
+
+ switch(frame_type & FTFLAGS_ACK_MM){
+ case 0:
+ return 1;
+ break;
+ case 1:
+ return 2;
+ break;
+ case 2:
+ return 4;
+ break;
+ case 3:
+ return 6;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+static guint32 get_len_packet_number(guint8 puflags){
+
+ switch((puflags & PUFLAGS_PKN) >> 4){
+ case 0:
+ return 1;
+ break;
+ case 1:
+ return 2;
+ break;
+ case 2:
+ return 4;
+ break;
+ case 3:
+ return 6;
+ break;
+ default:
+ break;
+ }
+ return 6;
+}
+
+static
+gboolean is_gquic_unencrypt(tvbuff_t *tvb, packet_info *pinfo, guint offset, guint16 len_pkn, gquic_info_data_t *gquic_info){
+ guint8 frame_type;
+ guint8 num_ranges, num_revived, num_blocks = 0, num_timestamp;
+ guint32 len_stream = 0, len_offset = 0, len_data = 0, len_largest_observed = 1, len_missing_packet = 1;
+ guint32 message_tag;
+
+
+ if(tvb_captured_length_remaining(tvb, offset) <= 13){
+ return FALSE;
+ }
+ /* Message Authentication Hash */
+ offset += 12;
+
+ if(gquic_info->version_valid && gquic_info->version < 34){ /* No longer Private Flags after Q034 */
+ /* Private Flags */
+ offset += 1;
+ }
+
+ while(tvb_reported_length_remaining(tvb, offset) > 0){
+
+ if (tvb_captured_length_remaining(tvb, offset) <= 1){
+ return FALSE;
+ }
+ /* Frame type */
+ frame_type = tvb_get_guint8(tvb, offset);
+ if((frame_type & FTFLAGS_SPECIAL) == 0){
+ offset += 1;
+ switch(frame_type){
+ case FT_PADDING:
+ return FALSE; /* Pad on rest of packet.. */
+ break;
+ case FT_RST_STREAM:
+ /* Stream ID */
+ offset += 4;
+ /* Byte Offset */
+ offset += 8;
+ /* Error Code */
+ offset += 4;
+ break;
+ case FT_CONNECTION_CLOSE:{
+ guint16 len_reason;
+
+ /* Error Code */
+ offset += 4;
+ /* Reason Phrase Length */
+ if (tvb_captured_length_remaining(tvb, offset) <= 2){
+ return FALSE;
+ }
+ len_reason = tvb_get_guint16(tvb, offset, gquic_info->encoding);
+ offset += 2;
+ /* Reason Phrase */
+ /* If length remaining == len_reason, it is Connection Close */
+ if (tvb_captured_length_remaining(tvb, offset) == len_reason){
+ return TRUE;
+ }
+ }
+ break;
+ case FT_GOAWAY:{
+ guint16 len_reason;
+
+ /* Error Code */
+ offset += 4;
+ /* Last Good Stream ID */
+ offset += 4;
+ /* Reason Phrase Length */
+ if (tvb_captured_length_remaining(tvb, offset) <= 2){
+ return FALSE;
+ }
+ len_reason = tvb_get_guint16(tvb, offset, gquic_info->encoding);
+ offset += 2;
+ /* Reason Phrase */
+ offset += len_reason;
+ }
+ break;
+ case FT_WINDOW_UPDATE:
+ /* Stream ID */
+ offset += 4;
+ /* Byte Offset */
+ offset += 8;
+ break;
+ case FT_BLOCKED:
+ /* Stream ID */
+ offset += 4;
+ break;
+ case FT_STOP_WAITING:
+ if(gquic_info->version_valid && gquic_info->version < 34){ /* No longer Entropy after Q034 */
+ /* Send Entropy */
+ offset += 1;
+ }
+ /* Least Unacked Delta */
+ offset += len_pkn;
+ break;
+ case FT_PING: /* No Payload */
+ default: /* No default */
+ break;
+ }
+ } else {
+ /* Special Frame Type */
+ if(frame_type & FTFLAGS_STREAM){ /* Stream */
+
+ if(frame_type & FTFLAGS_STREAM_D){
+ len_data = 2;
+ }
+ len_offset = get_len_offset(frame_type);
+ len_stream = get_len_stream(frame_type);
+
+ /* Frame Type */
+ offset += 1;
+
+ /* Stream */
+ offset += len_stream;
+
+ /* Offset */
+ offset += len_offset;
+
+ /* Data length */
+ offset += len_data;
+
+ if (tvb_captured_length_remaining(tvb, offset) <= 4){
+ return FALSE;
+ }
+
+ /* Check if the Message Tag is CHLO (Client Hello) or SHLO (Server Hello) or REJ (Rejection) */
+ message_tag = tvb_get_ntohl(tvb, offset);
+ if (message_tag == MTAG_CHLO|| message_tag == MTAG_SHLO || message_tag == MTAG_REJ) {
+ if(message_tag == MTAG_CHLO && pinfo->srcport != 443) { /* Found */
+ gquic_info->server_port = pinfo->destport;
+ }
+ return TRUE;
+ }
+
+
+ } else if (frame_type & FTFLAGS_ACK) {
+ /* ACK Flags */
+
+ len_largest_observed = get_len_largest_observed(frame_type);
+ len_missing_packet = get_len_missing_packet(frame_type);
+
+ /* Frame Type */
+ offset += 1;
+
+ if(gquic_info->version_valid && gquic_info->version < 34){ /* No longer Entropy after Q034 */
+ /* Received Entropy */
+ offset += 1;
+
+ /* Largest Observed */
+ offset += len_largest_observed;
+
+ /* Ack Delay Time */
+ offset += 2;
+
+ /* Num Timestamp */
+ if (tvb_captured_length_remaining(tvb, offset) <= 1){
+ return FALSE;
+ }
+ num_timestamp = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ if(num_timestamp > 0){
+ /* Delta Largest Observed */
+ offset += 1;
+
+ /* First Timestamp */
+ offset += 4;
+
+ /* Num Timestamp (-1)x (Delta Largest Observed + Time Since Previous Timestamp) */
+ offset += (num_timestamp - 1)*(1+2);
+ }
+
+ if(frame_type & FTFLAGS_ACK_N){
+ /* Num Ranges */
+ if (tvb_captured_length_remaining(tvb, offset) <= 1){
+ return FALSE;
+ }
+ num_ranges = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ /* Num Range x (Missing Packet + Range Length) */
+ offset += num_ranges*(len_missing_packet+1);
+
+ /* Num Revived */
+ if (tvb_captured_length_remaining(tvb, offset) <= 1){
+ return FALSE;
+ }
+ num_revived = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ /* Num Revived x Length Largest Observed */
+ offset += num_revived*len_largest_observed;
+
+ }
+ } else {
+
+ /* Largest Acked */
+ offset += len_largest_observed;
+
+ /* Largest Acked Delta Time*/
+ offset += 2;
+
+ /* Ack Block */
+ if(frame_type & FTFLAGS_ACK_N){
+ if (tvb_captured_length_remaining(tvb, offset) <= 1){
+ return FALSE;
+ }
+ num_blocks = tvb_get_guint8(tvb, offset);
+ offset += 1;
+ }
+
+ /* First Ack Block Length */
+ offset += len_missing_packet;
+ if(num_blocks){
+ offset += (num_blocks)*(1 + len_missing_packet);
+ }
+
+ /* Timestamp */
+ if (tvb_captured_length_remaining(tvb, offset) <= 1){
+ return FALSE;
+ }
+ num_timestamp = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ if(num_timestamp > 0){
+
+ /* Delta Largest Acked */
+ offset += 1;
+
+ /* Time Since Largest Acked */
+ offset += 4;
+
+ /* Num Timestamp x (Delta Largest Acked + Time Since Previous Timestamp) */
+ offset += (num_timestamp - 1)*(1+2);
+ }
+
+ }
+ } else { /* Other Special Frame type */
+ offset += 1;
+ }
+ }
+ }
+
+ return FALSE;
+
+}
+
+static guint32
+dissect_gquic_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *gquic_tree, guint offset, guint32 tag_number){
+ guint32 tag_offset_start = offset + tag_number*4*2;
+ guint32 tag_offset = 0, total_tag_len = 0;
+ gint32 tag_len;
+
+ while(tag_number){
+ proto_tree *tag_tree, *ti_len, *ti_tag, *ti_type;
+ guint32 offset_end, tag, num_iter;
+ const guint8* tag_str;
+
+ ti_tag = proto_tree_add_item(gquic_tree, hf_gquic_tags, tvb, offset, 8, ENC_NA);
+ tag_tree = proto_item_add_subtree(ti_tag, ett_gquic_tag_value);
+ ti_type = proto_tree_add_item_ret_string(tag_tree, hf_gquic_tag_type, tvb, offset, 4, ENC_ASCII|ENC_NA, pinfo->pool, &tag_str);
+ tag = tvb_get_ntohl(tvb, offset);
+ proto_item_append_text(ti_type, " (%s)", val_to_str_const(tag, tag_vals, "Unknown"));
+ proto_item_append_text(ti_tag, ": %s (%s)", tag_str, val_to_str_const(tag, tag_vals, "Unknown"));
+ offset += 4;
+
+ proto_tree_add_item(tag_tree, hf_gquic_tag_offset_end, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset_end = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN);
+
+ tag_len = offset_end - tag_offset;
+ ti_len = proto_tree_add_uint(tag_tree, hf_gquic_tag_length, tvb, offset, 4, tag_len);
+ proto_item_append_text(ti_tag, " (l=%u)", tag_len);
+ proto_item_set_generated(ti_len);
+ offset += 4;
+
+ /* Fix issue with CRT.. (Fragmentation ?) */
+ if( tag_len > tvb_reported_length_remaining(tvb, tag_offset_start + tag_offset)){
+ tag_len = tvb_reported_length_remaining(tvb, tag_offset_start + tag_offset);
+ offset_end = tag_offset + tag_len;
+ expert_add_info(pinfo, ti_len, &ei_gquic_tag_length);
+ }
+
+ total_tag_len += tag_len;
+
+ proto_tree_add_item(tag_tree, hf_gquic_tag_value, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+
+ switch(tag){
+ case TAG_PAD:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_pad, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_SNI:
+ proto_tree_add_item_ret_string(tag_tree, hf_gquic_tag_sni, tvb, tag_offset_start + tag_offset, tag_len, ENC_ASCII|ENC_NA, pinfo->pool, &tag_str);
+ proto_item_append_text(ti_tag, ": %s", tag_str);
+ tag_offset += tag_len;
+ break;
+ case TAG_VER:
+ num_iter = 1;
+ while(offset_end - tag_offset >= 4){
+ proto_tree_add_item_ret_string(tag_tree, hf_gquic_tag_ver, tvb, tag_offset_start + tag_offset, 4, ENC_ASCII|ENC_NA, pinfo->pool, &tag_str);
+ proto_item_append_text(ti_tag, "%s %s", num_iter == 1 ? ":" : ",", tag_str);
+ tag_offset += 4;
+ num_iter++;
+ }
+ break;
+ case TAG_CCS:
+ while(offset_end - tag_offset >= 8){
+ proto_tree_add_item(tag_tree, hf_gquic_tag_ccs, tvb, tag_offset_start + tag_offset, 8, ENC_NA);
+ tag_offset += 8;
+ }
+ break;
+ case TAG_PDMD:
+ proto_tree_add_item_ret_string(tag_tree, hf_gquic_tag_pdmd, tvb, tag_offset_start + tag_offset, tag_len, ENC_ASCII|ENC_NA, pinfo->pool, &tag_str);
+ proto_item_append_text(ti_tag, ": %s", tag_str);
+ tag_offset += tag_len;
+ break;
+ case TAG_UAID:
+ proto_tree_add_item_ret_string(tag_tree, hf_gquic_tag_uaid, tvb, tag_offset_start + tag_offset, tag_len, ENC_ASCII|ENC_NA, pinfo->pool, &tag_str);
+ proto_item_append_text(ti_tag, ": %s", tag_str);
+ tag_offset += tag_len;
+ break;
+ case TAG_STK:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_stk, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_SNO:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_sno, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_PROF:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_prof, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_SCFG:{
+ guint32 scfg_tag_number;
+
+ proto_tree_add_item(tag_tree, hf_gquic_tag_scfg, tvb, tag_offset_start + tag_offset, 4, ENC_ASCII);
+ tag_offset += 4;
+ proto_tree_add_item(tag_tree, hf_gquic_tag_scfg_number, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ scfg_tag_number = tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN);
+ tag_offset += 4;
+
+ dissect_gquic_tag(tvb, pinfo, tag_tree, tag_offset_start + tag_offset, scfg_tag_number);
+ tag_offset += tag_len - 4 - 4;
+ }
+ break;
+ case TAG_RREJ:
+ while(offset_end - tag_offset >= 4){
+ proto_tree_add_item(tag_tree, hf_gquic_tag_rrej, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ", Code %s", val_to_str_ext_const(tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN),
+ &handshake_failure_reason_vals_ext,
+ "Unknown"));
+ tag_offset += 4;
+ }
+ break;
+ case TAG_CRT:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_crt, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_AEAD:
+ while(offset_end - tag_offset >= 4){
+ proto_tree *ti_aead;
+ ti_aead = proto_tree_add_item(tag_tree, hf_gquic_tag_aead, tvb, tag_offset_start + tag_offset, 4, ENC_ASCII);
+ proto_item_append_text(ti_aead, " (%s)", val_to_str_const(tvb_get_ntohl(tvb, tag_offset_start + tag_offset), tag_aead_vals, "Unknown"));
+ proto_item_append_text(ti_tag, ", %s", val_to_str_const(tvb_get_ntohl(tvb, tag_offset_start + tag_offset), tag_aead_vals, "Unknown"));
+ tag_offset += 4;
+ }
+ break;
+ case TAG_SCID:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_scid, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_PUBS:
+ /*TODO FIX: 24 Length + Pubs key?.. ! */
+ proto_tree_add_item(tag_tree, hf_gquic_tag_pubs, tvb, tag_offset_start + tag_offset, 2, ENC_LITTLE_ENDIAN);
+ tag_offset += 2;
+ while(offset_end - tag_offset >= 3){
+ proto_tree_add_item(tag_tree, hf_gquic_tag_pubs, tvb, tag_offset_start + tag_offset, 3, ENC_LITTLE_ENDIAN);
+ tag_offset += 3;
+ }
+ break;
+ case TAG_KEXS:
+ while(offset_end - tag_offset >= 4){
+ proto_tree *ti_kexs;
+ ti_kexs = proto_tree_add_item(tag_tree, hf_gquic_tag_kexs, tvb, tag_offset_start + tag_offset, 4, ENC_ASCII);
+ proto_item_append_text(ti_kexs, " (%s)", val_to_str_const(tvb_get_ntohl(tvb, tag_offset_start + tag_offset), tag_kexs_vals, "Unknown"));
+ proto_item_append_text(ti_tag, ", %s", val_to_str_const(tvb_get_ntohl(tvb, tag_offset_start + tag_offset), tag_kexs_vals, "Unknown"));
+ tag_offset += 4;
+ }
+ break;
+ case TAG_OBIT:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_obit, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_EXPY:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_expy, tvb, tag_offset_start + tag_offset, 8, ENC_LITTLE_ENDIAN);
+ tag_offset += 8;
+ break;
+ case TAG_NONC:
+ /*TODO: Enhance display: 32 bytes consisting of 4 bytes of timestamp (big-endian, UNIX epoch seconds), 8 bytes of server orbit and 20 bytes of random data. */
+ proto_tree_add_item(tag_tree, hf_gquic_tag_nonc, tvb, tag_offset_start + tag_offset, 32, ENC_NA);
+ tag_offset += 32;
+ break;
+ case TAG_MSPC:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_mspc, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_TCID:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_tcid, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ tag_offset += 4;
+ break;
+ case TAG_SRBF:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_srbf, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ tag_offset += 4;
+ break;
+ case TAG_ICSL:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_icsl, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ tag_offset += 4;
+ break;
+ case TAG_SCLS:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_scls, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ tag_offset += 4;
+ break;
+ case TAG_COPT:
+ while(offset_end - tag_offset >= 4){
+ proto_tree_add_item(tag_tree, hf_gquic_tag_copt, tvb, tag_offset_start + tag_offset, 4, ENC_ASCII);
+ tag_offset += 4;
+ }
+ break;
+ case TAG_CCRT:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_ccrt, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_IRTT:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_irtt, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_CFCW:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_cfcw, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_SFCW:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_sfcw, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_CETV:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_cetv, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_XLCT:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_xlct, tvb, tag_offset_start + tag_offset, 8, ENC_NA);
+ tag_offset += 8;
+ break;
+ case TAG_NONP:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_nonp, tvb, tag_offset_start + tag_offset, 32, ENC_NA);
+ tag_offset += 32;
+ break;
+ case TAG_CSCT:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_csct, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_CTIM:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_ctim, tvb, tag_offset_start + tag_offset, 8, ENC_LITTLE_ENDIAN|ENC_TIME_SECS_NSECS);
+ tag_offset += 8;
+ break;
+ case TAG_RNON: /* Public Reset Tag */
+ proto_tree_add_item(tag_tree, hf_gquic_tag_rnon, tvb, tag_offset_start + tag_offset, 8, ENC_LITTLE_ENDIAN);
+ tag_offset += 8;
+ break;
+ case TAG_RSEQ: /* Public Reset Tag */
+ proto_tree_add_item(tag_tree, hf_gquic_tag_rseq, tvb, tag_offset_start + tag_offset, 8, ENC_LITTLE_ENDIAN);
+ tag_offset += 8;
+ break;
+ case TAG_CADR: /* Public Reset Tag */{
+ guint32 addr_type;
+ proto_tree_add_item_ret_uint(tag_tree, hf_gquic_tag_cadr_addr_type, tvb, tag_offset_start + tag_offset, 2, ENC_LITTLE_ENDIAN, &addr_type);
+ tag_offset += 2;
+ switch(addr_type){
+ case 2: /* IPv4 */
+ proto_tree_add_item(tag_tree, hf_gquic_tag_cadr_addr_ipv4, tvb, tag_offset_start + tag_offset, 4, ENC_NA);
+ tag_offset += 4;
+ break;
+ case 10: /* IPv6 */
+ proto_tree_add_item(tag_tree, hf_gquic_tag_cadr_addr_ipv6, tvb, tag_offset_start + tag_offset, 16, ENC_NA);
+ tag_offset += 16;
+ break;
+ default: /* Unknown */
+ proto_tree_add_item(tag_tree, hf_gquic_tag_cadr_addr, tvb, tag_offset_start + tag_offset, tag_len - 2 - 2, ENC_NA);
+ tag_offset += tag_len + 2 + 2 ;
+ break;
+ }
+ proto_tree_add_item(tag_tree, hf_gquic_tag_cadr_port, tvb, tag_offset_start + tag_offset, 2, ENC_LITTLE_ENDIAN);
+ tag_offset += 2;
+ }
+ break;
+ case TAG_MIDS:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_mids, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_FHOL:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_fhol, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_STTL:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_sttl, tvb, tag_offset_start + tag_offset, 8, ENC_LITTLE_ENDIAN);
+ tag_offset += 8;
+ break;
+ case TAG_SMHL:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_smhl, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_TBKP:
+ proto_tree_add_item_ret_string(tag_tree, hf_gquic_tag_tbkp, tvb, tag_offset_start + tag_offset, 4, ENC_ASCII|ENC_NA, pinfo->pool, &tag_str);
+ proto_item_append_text(ti_tag, ": %s", tag_str);
+ tag_offset += 4;
+ break;
+ case TAG_MAD0:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_mad0, tvb, tag_offset_start + tag_offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti_tag, ": %u", tvb_get_guint32(tvb, tag_offset_start + tag_offset, ENC_LITTLE_ENDIAN));
+ tag_offset += 4;
+ break;
+ case TAG_QLVE:
+ {
+ proto_tree_add_item(tag_tree, hf_gquic_tag_qlve, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+
+ /* Newest GQUIC versions (usually Q050) encapsulate their first flight in Q043 packets.
+ * (Q050 is handled by QUIC dissector) */
+ tvbuff_t *next_tvb = tvb_new_subset_length(tvb, tag_offset_start + tag_offset, tag_len);
+ call_dissector_with_data(quic_handle, next_tvb, pinfo, tag_tree, NULL);
+
+ tag_offset += tag_len;
+ }
+ break;
+ case TAG_CGST:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_cgst, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ case TAG_EPID:
+ proto_tree_add_item_ret_string(tag_tree, hf_gquic_tag_epid, tvb, tag_offset_start + tag_offset, tag_len, ENC_ASCII|ENC_NA, pinfo->pool, &tag_str);
+ proto_item_append_text(ti_tag, ": %s", tag_str);
+ tag_offset += tag_len;
+ break;
+ case TAG_SRST:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_srst, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ tag_offset += tag_len;
+ break;
+ default:
+ proto_tree_add_item(tag_tree, hf_gquic_tag_unknown, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
+ expert_add_info_format(pinfo, ti_tag, &ei_gquic_tag_undecoded,
+ "Dissector for (Google) QUIC Tag"
+ " %s (%s) code not implemented, Contact"
+ " Wireshark developers if you want this supported",
+ tvb_get_string_enc(pinfo->pool, tvb, offset-8, 4, ENC_ASCII|ENC_NA),
+ val_to_str_const(tag, tag_vals, "Unknown"));
+ tag_offset += tag_len;
+ break;
+ }
+ if(tag_offset != offset_end){
+ /* Wrong Tag len... */
+ proto_tree_add_expert(tag_tree, pinfo, &ei_gquic_tag_unknown, tvb, tag_offset_start + tag_offset, tag_len);
+ tag_offset = offset_end;
+ }
+
+ tag_number--;
+ }
+
+ if (offset + total_tag_len <= offset) {
+ expert_add_info_format(pinfo, gquic_tree, &ei_gquic_length_invalid,
+ "Invalid total tag length: %u", total_tag_len);
+ return offset + tvb_reported_length_remaining(tvb, offset);
+ }
+ return offset + total_tag_len;
+
+}
+
+guint32
+dissect_gquic_tags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ft_tree, guint offset){
+ guint32 tag_number;
+
+ proto_tree_add_item(ft_tree, hf_gquic_tag_number, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ tag_number = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(ft_tree, hf_gquic_padding, tvb, offset, 2, ENC_NA);
+ offset += 2;
+
+ offset = dissect_gquic_tag(tvb, pinfo, ft_tree, offset, tag_number);
+
+ return offset;
+}
+
+int
+dissect_gquic_frame_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *gquic_tree, guint offset, guint8 len_pkn, gquic_info_data_t *gquic_info){
+ if (!gquic_info) {
+ expert_add_info(pinfo, gquic_tree, &ei_gquic_data_invalid);
+ return offset + tvb_reported_length_remaining(tvb, offset);
+ }
+
+ proto_item *ti, *ti_ft, *ti_ftflags /*, *expert_ti*/;
+ proto_tree *ft_tree, *ftflags_tree;
+ guint8 frame_type;
+ guint8 num_ranges, num_revived, num_blocks = 0, num_timestamp;
+ guint32 len_stream = 0, len_offset = 0, len_data = 0, len_largest_observed = 1, len_missing_packet = 1;
+
+ ti_ft = proto_tree_add_item(gquic_tree, hf_gquic_frame, tvb, offset, 1, ENC_NA);
+ ft_tree = proto_item_add_subtree(ti_ft, ett_gquic_ft);
+
+ /* Frame type */
+ ti_ftflags = proto_tree_add_item(ft_tree, hf_gquic_frame_type, tvb, offset, 1, ENC_NA);
+ frame_type = tvb_get_guint8(tvb, offset);
+ proto_item_set_text(ti_ft, "%s", rval_to_str_const(frame_type, frame_type_vals, "Unknown"));
+
+ if((frame_type & FTFLAGS_SPECIAL) == 0 && frame_type != FT_CRYPTO){ /* Regular Stream Flags */
+ offset += 1;
+ switch(frame_type){
+ case FT_PADDING:{
+ proto_item *ti_pad_len;
+ guint32 pad_len = tvb_reported_length_remaining(tvb, offset);
+
+ ti_pad_len = proto_tree_add_uint(ft_tree, hf_gquic_frame_type_padding_length, tvb, offset, 0, pad_len);
+ proto_item_set_generated(ti_pad_len);
+ proto_item_append_text(ti_ft, " Length: %u", pad_len);
+ if(pad_len > 0) /* Avoid Malformed Exception with pad_len == 0 */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_padding, tvb, offset, -1, ENC_NA);
+ offset += pad_len;
+ }
+ break;
+ case FT_RST_STREAM:{
+ guint32 stream_id, error_code;
+ proto_tree_add_item_ret_uint(ft_tree, hf_gquic_frame_type_rsts_stream_id, tvb, offset, 4, gquic_info->encoding, &stream_id);
+ offset += 4;
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_rsts_byte_offset, tvb, offset, 8, gquic_info->encoding);
+ offset += 8;
+ proto_tree_add_item_ret_uint(ft_tree, hf_gquic_frame_type_rsts_error_code, tvb, offset, 4, gquic_info->encoding, &error_code);
+ offset += 4;
+ proto_item_append_text(ti_ft, " Stream ID: %u, Error code: %s", stream_id, val_to_str_ext(error_code, &rststream_error_code_vals_ext, "Unknown (%d)"));
+ col_set_str(pinfo->cinfo, COL_INFO, "RST STREAM");
+ }
+ break;
+ case FT_CONNECTION_CLOSE:{
+ guint16 len_reason;
+ guint32 error_code;
+
+ proto_tree_add_item_ret_uint(ft_tree, hf_gquic_frame_type_cc_error_code, tvb, offset, 4, gquic_info->encoding, &error_code);
+ offset += 4;
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_cc_reason_phrase_length, tvb, offset, 2, gquic_info->encoding);
+ len_reason = tvb_get_guint16(tvb, offset, gquic_info->encoding);
+ offset += 2;
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_cc_reason_phrase, tvb, offset, len_reason, ENC_ASCII);
+ offset += len_reason;
+ proto_item_append_text(ti_ft, " Error code: %s", val_to_str_ext(error_code, &error_code_vals_ext, "Unknown (%d)"));
+ col_set_str(pinfo->cinfo, COL_INFO, "Connection Close");
+ }
+ break;
+ case FT_GOAWAY:{
+ guint16 len_reason;
+ guint32 error_code, last_good_stream_id;
+
+ proto_tree_add_item_ret_uint(ft_tree, hf_gquic_frame_type_goaway_error_code, tvb, offset, 4, gquic_info->encoding, &error_code);
+ offset += 4;
+ proto_tree_add_item_ret_uint(ft_tree, hf_gquic_frame_type_goaway_last_good_stream_id, tvb, offset, 4, gquic_info->encoding, &last_good_stream_id);
+ offset += 4;
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_goaway_reason_phrase_length, tvb, offset, 2, gquic_info->encoding);
+ len_reason = tvb_get_guint16(tvb, offset, gquic_info->encoding);
+ offset += 2;
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_goaway_reason_phrase, tvb, offset, len_reason, ENC_ASCII);
+ offset += len_reason;
+ proto_item_append_text(ti_ft, " Stream ID: %u, Error code: %s", last_good_stream_id, val_to_str_ext(error_code, &error_code_vals_ext, "Unknown (%d)"));
+ col_set_str(pinfo->cinfo, COL_INFO, "GOAWAY");
+ }
+ break;
+ case FT_WINDOW_UPDATE:{
+ guint32 stream_id;
+
+ proto_tree_add_item_ret_uint(ft_tree, hf_gquic_frame_type_wu_stream_id, tvb, offset, 4, gquic_info->encoding, &stream_id);
+ offset += 4;
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_wu_byte_offset, tvb, offset, 8, gquic_info->encoding);
+ offset += 8;
+ proto_item_append_text(ti_ft, " Stream ID: %u", stream_id);
+ }
+ break;
+ case FT_BLOCKED:{
+ guint32 stream_id;
+
+ proto_tree_add_item_ret_uint(ft_tree, hf_gquic_frame_type_blocked_stream_id, tvb, offset, 4, gquic_info->encoding, &stream_id);
+ offset += 4;
+ proto_item_append_text(ti_ft, " Stream ID: %u", stream_id);
+ }
+ break;
+ case FT_STOP_WAITING:{
+ guint8 send_entropy;
+ if(gquic_info->version_valid && gquic_info->version < 34){ /* No longer Entropy after Q034 */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_sw_send_entropy, tvb, offset, 1, ENC_NA);
+ send_entropy = tvb_get_guint8(tvb, offset);
+ proto_item_append_text(ti_ft, " Send Entropy: %u", send_entropy);
+ offset += 1;
+ }
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_sw_least_unacked_delta, tvb, offset, len_pkn, gquic_info->encoding);
+ offset += len_pkn;
+
+ }
+ break;
+ case FT_PING: /* No Payload */
+ default: /* No default */
+ break;
+ }
+ }
+ else { /* Special Frame Types */
+ guint32 stream_id, message_tag;
+ const guint8* message_tag_str;
+ proto_item *ti_stream;
+
+ ftflags_tree = proto_item_add_subtree(ti_ftflags, ett_gquic_ftflags);
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_stream , tvb, offset, 1, ENC_NA);
+
+ if(frame_type == FT_CRYPTO) {
+ guint64 crypto_offset, crypto_length;
+ gint32 lenvar;
+
+ DISSECTOR_ASSERT(gquic_info->version_valid && gquic_info->version >= 50);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", CRYPTO");
+ offset += 1;
+ proto_tree_add_item_ret_varint(ft_tree, hf_gquic_crypto_offset, tvb, offset, -1, ENC_VARINT_QUIC, &crypto_offset, &lenvar);
+ offset += lenvar;
+ proto_tree_add_item_ret_varint(ft_tree, hf_gquic_crypto_length, tvb, offset, -1, ENC_VARINT_QUIC, &crypto_length, &lenvar);
+ offset += lenvar;
+ proto_tree_add_item(ft_tree, hf_gquic_crypto_crypto_data, tvb, offset, (guint32)crypto_length, ENC_NA);
+
+ if (gquic_info->version == 50) {
+ message_tag = tvb_get_ntohl(tvb, offset);
+ ti = proto_tree_add_item_ret_string(ft_tree, hf_gquic_tag, tvb, offset, 4, ENC_ASCII|ENC_NA, pinfo->pool, &message_tag_str);
+ proto_item_append_text(ti, " (%s)", val_to_str_const(message_tag, message_tag_vals, "Unknown Tag"));
+ col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const(message_tag, message_tag_vals, "Unknown"));
+ offset += 4;
+
+ offset = dissect_gquic_tags(tvb, pinfo, ft_tree, offset);
+ } else { /* T050 and T051 */
+ tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, (int)crypto_length);
+ col_set_writable(pinfo->cinfo, -1, FALSE);
+ call_dissector_with_data(tls13_handshake_handle, next_tvb, pinfo, ft_tree, GUINT_TO_POINTER(crypto_offset));
+ col_set_writable(pinfo->cinfo, -1, TRUE);
+ offset += (guint32)crypto_length;
+ }
+
+ } else if(frame_type & FTFLAGS_STREAM){ /* Stream Flags */
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_stream_f, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_stream_d, tvb, offset, 1, ENC_NA);
+ if(frame_type & FTFLAGS_STREAM_D){
+ len_data = 2;
+ }
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_stream_ooo, tvb, offset, 1, ENC_NA);
+
+ len_offset = get_len_offset(frame_type);
+
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_stream_ss, tvb, offset, 1, ENC_NA);
+ len_stream = get_len_stream(frame_type);
+ offset += 1;
+
+ ti_stream = proto_tree_add_item_ret_uint(ft_tree, hf_gquic_stream_id, tvb, offset, len_stream, gquic_info->encoding, &stream_id);
+ offset += len_stream;
+
+ proto_item_append_text(ti_ft, " Stream ID: %u", stream_id);
+
+ if(len_offset) {
+ proto_tree_add_item(ft_tree, hf_gquic_offset, tvb, offset, len_offset, gquic_info->encoding);
+ offset += len_offset;
+ }
+
+ if(len_data) {
+ proto_tree_add_item(ft_tree, hf_gquic_data_len, tvb, offset, len_data, gquic_info->encoding);
+ offset += len_data;
+ }
+
+ /* Check if there is some reserved streams (Chapiter 6.1 of draft-shade-gquic-http2-mapping-00) */
+
+ switch(stream_id) {
+ case 1: { /* Reserved (G)QUIC (handshake, crypto, config updates...) */
+ message_tag = tvb_get_ntohl(tvb, offset);
+ ti = proto_tree_add_item_ret_string(ft_tree, hf_gquic_tag, tvb, offset, 4, ENC_ASCII|ENC_NA, pinfo->pool, &message_tag_str);
+
+ proto_item_append_text(ti_stream, " (Reserved for (G)QUIC handshake, crypto, config updates...)");
+ proto_item_append_text(ti, " (%s)", val_to_str_const(message_tag, message_tag_vals, "Unknown Tag"));
+ proto_item_append_text(ti_ft, ", Type: %s (%s)", message_tag_str, val_to_str_const(message_tag, message_tag_vals, "Unknown Tag"));
+ col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const(message_tag, message_tag_vals, "Unknown"));
+ offset += 4;
+
+ offset = dissect_gquic_tags(tvb, pinfo, ft_tree, offset);
+ break;
+ }
+ case 3: { /* Reserved H2 HEADERS (or PUSH_PROMISE..) */
+ tvbuff_t* tvb_h2;
+
+ proto_item_append_text(ti_stream, " (Reserved for H2 HEADERS)");
+
+ col_add_str(pinfo->cinfo, COL_INFO, "H2");
+
+ tvb_h2 = tvb_new_subset_remaining(tvb, offset);
+
+ offset += dissect_http2_pdu(tvb_h2, pinfo, ft_tree, NULL);
+ }
+ break;
+ default: { /* Data... */
+ int data_len = tvb_reported_length_remaining(tvb, offset);
+
+ col_add_str(pinfo->cinfo, COL_INFO, "DATA");
+
+ proto_tree_add_item(ft_tree, hf_gquic_stream_data, tvb, offset, data_len, ENC_NA);
+ offset += data_len;
+ }
+ break;
+ }
+ } else if (frame_type & FTFLAGS_ACK) { /* ACK Flags */
+
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_ack, tvb, offset, 1, ENC_NA);
+
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_ack_n, tvb, offset, 1, ENC_NA);
+
+ if(gquic_info->version_valid && gquic_info->version < 34){ /* No longer NACK after Q034 */
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_ack_t, tvb, offset, 1, ENC_NA);
+ } else {
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_ack_u, tvb, offset, 1, ENC_NA);
+ }
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_ack_ll, tvb, offset, 1, ENC_NA);
+
+ len_largest_observed = get_len_largest_observed(frame_type);
+
+ proto_tree_add_item(ftflags_tree, hf_gquic_frame_type_ack_mm, tvb, offset, 1, ENC_NA);
+ len_missing_packet = get_len_missing_packet(frame_type);
+ offset += 1;
+
+ if(gquic_info->version_valid && gquic_info->version < 34){ /* Big change after Q034 */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_received_entropy, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_largest_observed, tvb, offset, len_largest_observed, gquic_info->encoding);
+ offset += len_largest_observed;
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_ack_delay_time, tvb, offset, 2, gquic_info->encoding);
+ offset += 2;
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_num_timestamp, tvb, offset, 1, ENC_NA);
+ num_timestamp = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ if(num_timestamp){
+
+ /* Delta Largest Observed */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_delta_largest_observed, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ /* First Timestamp */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_first_timestamp, tvb, offset, 4, gquic_info->encoding);
+ offset += 4;
+
+ num_timestamp -= 1;
+ /* Num Timestamp (-1) x (Delta Largest Observed + Time Since Previous Timestamp) */
+ while(num_timestamp){
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_delta_largest_observed, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_time_since_previous_timestamp, tvb, offset, 2, gquic_info->encoding);
+ offset += 2;
+
+ num_timestamp--;
+ }
+ }
+
+ if(frame_type & FTFLAGS_ACK_N){
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_num_ranges, tvb, offset, 1, ENC_NA);
+ num_ranges = tvb_get_guint8(tvb, offset);
+ offset += 1;
+ while(num_ranges){
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_missing_packet, tvb, offset, len_missing_packet, gquic_info->encoding);
+ offset += len_missing_packet;
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_range_length, tvb, offset, 1, ENC_NA);
+ offset += 1;
+ num_ranges--;
+ }
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_num_revived, tvb, offset, 1, ENC_NA);
+ num_revived = tvb_get_guint8(tvb, offset);
+ offset += 1;
+ while(num_revived){
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_revived_packet, tvb, offset, len_largest_observed, gquic_info->encoding);
+ offset += len_largest_observed;
+ num_revived--;
+
+ }
+
+ }
+
+ } else {
+
+ /* Largest Acked */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_largest_acked, tvb, offset, len_largest_observed, gquic_info->encoding);
+ offset += len_largest_observed;
+
+ /* Largest Acked Delta Time*/
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_largest_acked_delta_time, tvb, offset, 2, gquic_info->encoding);
+ offset += 2;
+
+ /* Ack Block */
+ if(frame_type & FTFLAGS_ACK_N){
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_num_blocks, tvb, offset, 1, ENC_NA);
+ num_blocks = tvb_get_guint8(tvb, offset);
+ offset += 1;
+ }
+
+ /* First Ack Block Length */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_first_ack_block_length, tvb, offset, len_missing_packet, gquic_info->encoding);
+ offset += len_missing_packet;
+
+ while(num_blocks){
+ /* Gap to next block */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_gap_to_next_block, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ /* Ack Block Length */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_ack_block_length, tvb, offset, len_missing_packet, gquic_info->encoding);
+ offset += len_missing_packet;
+
+ num_blocks--;
+ }
+
+ /* Timestamp */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_num_timestamp, tvb, offset, 1, ENC_NA);
+ num_timestamp = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ if(num_timestamp){
+
+ /* Delta Largest Acked */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_delta_largest_acked, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ /* Time Since Largest Acked */
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_time_since_largest_acked, tvb, offset, 4, gquic_info->encoding);
+ offset += 4;
+
+ num_timestamp -= 1;
+ /* Num Timestamp x (Delta Largest Acked + Time Since Previous Timestamp) */
+ while(num_timestamp){
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_delta_largest_acked, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ proto_tree_add_item(ft_tree, hf_gquic_frame_type_ack_time_since_previous_timestamp, tvb, offset, 2, gquic_info->encoding);
+ offset += 2;
+
+ num_timestamp--;
+ }
+ }
+
+ }
+
+ } else { /* Other ...*/
+ offset += 1;
+ }
+ }
+ return offset;
+
+}
+
+static int
+dissect_gquic_unencrypt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *gquic_tree, guint offset, guint8 len_pkn, gquic_info_data_t *gquic_info){
+ proto_item *ti_prflags;
+ proto_tree *prflags_tree;
+
+ /* Message Authentication Hash */
+ proto_tree_add_item(gquic_tree, hf_gquic_message_authentication_hash, tvb, offset, 12, ENC_NA);
+ offset += 12;
+
+ if(gquic_info->version_valid && gquic_info->version < 34){ /* No longer Private Flags after Q034 */
+ /* Private Flags */
+ ti_prflags = proto_tree_add_item(gquic_tree, hf_gquic_prflags, tvb, offset, 1, ENC_NA);
+ prflags_tree = proto_item_add_subtree(ti_prflags, ett_gquic_prflags);
+ proto_tree_add_item(prflags_tree, hf_gquic_prflags_entropy, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(prflags_tree, hf_gquic_prflags_fecg, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(prflags_tree, hf_gquic_prflags_fec, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(prflags_tree, hf_gquic_prflags_rsv, tvb, offset, 1, ENC_NA);
+ offset += 1;
+ }
+
+ while(tvb_reported_length_remaining(tvb, offset) > 0){
+ offset = dissect_gquic_frame_type(tvb, pinfo, gquic_tree, offset, len_pkn, gquic_info);
+ }
+
+ return offset;
+
+}
+
+static int
+dissect_gquic_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
+{
+ proto_item *ti, *ti_puflags; /*, *expert_ti*/
+ proto_tree *gquic_tree, *puflags_tree;
+ guint offset = 0;
+ guint8 puflags, len_cid = 0, len_pkn;
+ guint64 cid = 0, pkn;
+ conversation_t *conv;
+ gquic_info_data_t *gquic_info;
+
+ if (tvb_captured_length(tvb) < GQUIC_MIN_LENGTH)
+ return 0;
+
+
+ /* get conversation, create if necessary*/
+ conv = find_or_create_conversation(pinfo);
+
+ /* get associated state information, create if necessary */
+ gquic_info = (gquic_info_data_t *)conversation_get_proto_data(conv, proto_gquic);
+
+ if (!gquic_info) {
+ gquic_info = wmem_new(wmem_file_scope(), gquic_info_data_t);
+ gquic_info->version = 0;
+ gquic_info->encoding = ENC_LITTLE_ENDIAN;
+ gquic_info->version_valid = TRUE;
+ gquic_info->server_port = 443;
+ conversation_add_proto_data(conv, proto_gquic, gquic_info);
+ }
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "GQUIC");
+
+ ti = proto_tree_add_item(tree, proto_gquic, tvb, 0, -1, ENC_NA);
+ gquic_tree = proto_item_add_subtree(ti, ett_gquic);
+
+ /* Public Flags */
+ puflags = tvb_get_guint8(tvb, offset);
+
+ /* Get len of CID */
+ if(puflags & PUFLAGS_CID){
+ len_cid = 8;
+ }
+ /* check and get (and store) version */
+ if(puflags & PUFLAGS_VRSN){
+ gquic_info->version_valid = ws_strtou8(tvb_get_string_enc(pinfo->pool, tvb,
+ offset + 1 + len_cid + 1, 3, ENC_ASCII), NULL, &gquic_info->version);
+ if (!gquic_info->version_valid)
+ expert_add_info(pinfo, gquic_tree, &ei_gquic_version_invalid);
+ }
+
+ if(gquic_info->version >= 39){ /* After Q039, Integers and floating numbers are written in big endian*/
+ gquic_info->encoding = ENC_BIG_ENDIAN;
+ }
+ ti_puflags = proto_tree_add_item(gquic_tree, hf_gquic_puflags, tvb, offset, 1, ENC_NA);
+ puflags_tree = proto_item_add_subtree(ti_puflags, ett_gquic_puflags);
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_vrsn, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_rst, tvb, offset, 1, ENC_NA);
+ if (gquic_info->version_valid) {
+ if(gquic_info->version < 33){
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_cid_old, tvb, offset, 1, ENC_NA);
+ } else {
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_dnonce, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_cid, tvb, offset, 1, ENC_NA);
+ }
+ }
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_pkn, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_mpth, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(puflags_tree, hf_gquic_puflags_rsv, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ /* CID */
+ if (len_cid) {
+ cid = tvb_get_guint64(tvb, offset, gquic_info->encoding);
+ proto_tree_add_item(gquic_tree, hf_gquic_cid, tvb, offset, len_cid, gquic_info->encoding);
+ offset += len_cid;
+ }
+
+ /* Version */
+ if(puflags & PUFLAGS_VRSN){
+ if(pinfo->srcport == gquic_info->server_port){ /* Version Negotiation Packet */
+ while(tvb_reported_length_remaining(tvb, offset) > 0){
+ proto_tree_add_item(gquic_tree, hf_gquic_version, tvb, offset, 4, ENC_ASCII);
+ offset += 4;
+ }
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Version Negotiation, CID: %" PRIu64, cid);
+ return offset;
+ }
+ else{
+ proto_tree_add_item(gquic_tree, hf_gquic_version, tvb, offset, 4, ENC_ASCII);
+ offset += 4;
+ }
+ }
+
+ /* Public Reset Packet */
+ if(puflags & PUFLAGS_RST){
+ guint32 tag_number, message_tag;
+
+ ti = proto_tree_add_item(gquic_tree, hf_gquic_tag, tvb, offset, 4, ENC_ASCII);
+ message_tag = tvb_get_ntohl(tvb, offset);
+ proto_item_append_text(ti, " (%s)", val_to_str_const(message_tag, message_tag_vals, "Unknown Tag"));
+ offset += 4;
+
+ proto_tree_add_item(gquic_tree, hf_gquic_tag_number, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ tag_number = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(gquic_tree, hf_gquic_padding, tvb, offset, 2, ENC_NA);
+ offset += 2;
+
+ offset = dissect_gquic_tag(tvb, pinfo, gquic_tree, offset, tag_number);
+
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Public Reset, CID: %" PRIu64, cid);
+
+ return offset;
+ }
+
+ /* Diversification Nonce */
+ if(gquic_info->version_valid && (puflags & PUFLAGS_DNONCE) && (gquic_info->version >= 33)){
+ if(pinfo->srcport == gquic_info->server_port){ /* Diversification nonce is only present from server to client */
+ proto_tree_add_item(gquic_tree, hf_gquic_diversification_nonce, tvb, offset, 32, ENC_NA);
+ offset += 32;
+ }
+ }
+
+ /* Packet Number */
+
+ /* Get len of packet number */
+ len_pkn = get_len_packet_number(puflags);
+ proto_tree_add_item_ret_uint64(gquic_tree, hf_gquic_packet_number, tvb, offset, len_pkn, gquic_info->encoding, &pkn);
+ offset += len_pkn;
+
+ /* Unencrypt Message (Handshake or Connection Close...) */
+ if (is_gquic_unencrypt(tvb, pinfo, offset, len_pkn, gquic_info) || g_gquic_debug){
+ offset = dissect_gquic_unencrypt(tvb, pinfo, gquic_tree, offset, len_pkn, gquic_info);
+ }else { /* Payload... (encrypted... TODO FIX !) */
+ col_add_str(pinfo->cinfo, COL_INFO, "Payload (Encrypted)");
+ proto_tree_add_item(gquic_tree, hf_gquic_payload, tvb, offset, -1, ENC_NA);
+
+ }
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", PKN: %" PRIu64, pkn);
+
+ if(cid){
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", CID: %" PRIu64, cid);
+ }
+
+
+ return offset;
+}
+
+static int
+dissect_gquic_q046(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
+{
+ proto_item *ti, *ti_firstbyte; /*, *expert_ti*/
+ proto_tree *gquic_tree, *firstbyte_tree;
+ guint offset = 0;
+ guint8 first_byte, len_cid, cil, len_pkn;
+ guint64 cid = 0, pkn = 0;
+ conversation_t *conv;
+ gquic_info_data_t *gquic_info;
+
+ /* get conversation, create if necessary*/
+ conv = find_or_create_conversation(pinfo);
+
+ /* get associated state information, create if necessary */
+ gquic_info = (gquic_info_data_t *)conversation_get_proto_data(conv, proto_gquic);
+
+ if (!gquic_info) {
+ gquic_info = wmem_new(wmem_file_scope(), gquic_info_data_t);
+ gquic_info->version = 0;
+ gquic_info->encoding = ENC_BIG_ENDIAN;
+ gquic_info->version_valid = TRUE;
+ gquic_info->server_port = 443;
+ conversation_add_proto_data(conv, proto_gquic, gquic_info);
+ }
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "GQUIC");
+
+ ti = proto_tree_add_item(tree, proto_gquic, tvb, 0, -1, ENC_NA);
+ gquic_tree = proto_item_add_subtree(ti, ett_gquic);
+
+ /* First byte */
+ first_byte = tvb_get_guint8(tvb, offset);
+ len_pkn = (first_byte & 0x03) + 1;
+
+ ti_firstbyte = proto_tree_add_item(gquic_tree, hf_gquic_puflags, tvb, offset, 1, ENC_NA);
+ firstbyte_tree = proto_item_add_subtree(ti_firstbyte, ett_gquic_puflags);
+ proto_tree_add_item(firstbyte_tree, hf_gquic_header_form, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(firstbyte_tree, hf_gquic_fixed_bit, tvb, offset, 1, ENC_NA);
+
+ if((first_byte & PUFLAGS_MPTH) && (first_byte & PUFLAGS_RSV)) {
+ /* Long Header. We handle only Q046 */
+
+ gquic_info->version_valid = ws_strtou8(tvb_get_string_enc(pinfo->pool, tvb,
+ offset + 2, 3, ENC_ASCII), NULL, &gquic_info->version);
+ if (!gquic_info->version_valid) {
+ expert_add_info(pinfo, gquic_tree, &ei_gquic_version_invalid);
+ }
+
+ cil = tvb_get_guint8(tvb, offset + 5);
+ if(pinfo->srcport == gquic_info->server_port) { /* Server to client */
+ len_cid = (cil & 0x0F) + 3;
+ } else {
+ len_cid = ((cil & 0xF0) >> 4) + 3;
+ }
+ if (len_cid != 8) {
+ expert_add_info(pinfo, gquic_tree, &ei_gquic_invalid_parameter);
+ }
+
+ proto_tree_add_item(firstbyte_tree, hf_gquic_long_packet_type, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(firstbyte_tree, hf_gquic_long_reserved, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(firstbyte_tree, hf_gquic_packet_number_length, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ proto_tree_add_item(gquic_tree, hf_gquic_version, tvb, offset, 4, ENC_ASCII);
+ offset += 4;
+
+ proto_tree_add_item(gquic_tree, hf_gquic_dcil, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(gquic_tree, hf_gquic_scil, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ /* CID */
+ if (len_cid > 0) {
+ cid = tvb_get_guint64(tvb, offset, gquic_info->encoding);
+ proto_tree_add_item(gquic_tree, hf_gquic_cid, tvb, offset, len_cid, gquic_info->encoding);
+ }
+ offset += len_cid;
+
+ } else {
+ /* Short Header. We handle only Q046 */
+
+ proto_tree_add_uint(firstbyte_tree, hf_gquic_packet_number_length, tvb, offset, 1, first_byte);
+
+ offset += 1;
+
+ if(pinfo->srcport == gquic_info->server_port) { /* Server to client */
+ len_cid = 0;
+ } else {
+ len_cid = 8;
+ cid = tvb_get_guint64(tvb, offset, gquic_info->encoding);
+ proto_tree_add_item(gquic_tree, hf_gquic_cid, tvb, offset, len_cid, gquic_info->encoding);
+ }
+ offset += len_cid;
+ }
+
+ /* Packet Number */
+ proto_tree_add_item_ret_uint64(gquic_tree, hf_gquic_packet_number, tvb, offset, len_pkn, gquic_info->encoding, &pkn);
+ offset += len_pkn;
+
+ /* Unencrypt Message (Handshake or Connection Close...) */
+ if (is_gquic_unencrypt(tvb, pinfo, offset, len_pkn, gquic_info) || g_gquic_debug){
+ offset = dissect_gquic_unencrypt(tvb, pinfo, gquic_tree, offset, len_pkn, gquic_info);
+ }else { /* Payload... (encrypted... TODO FIX !) */
+ col_add_str(pinfo->cinfo, COL_INFO, "Payload (Encrypted)");
+ proto_tree_add_item(gquic_tree, hf_gquic_payload, tvb, offset, -1, ENC_NA);
+
+ }
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", PKN: %" PRIu64, pkn);
+
+ if(cid){
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", CID: %" PRIu64, cid);
+ }
+
+ return offset;
+}
+
+static int
+dissect_gquic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
+{
+ guint8 flags;
+
+ flags = tvb_get_guint8(tvb, 0);
+ if((flags & PUFLAGS_RSV) == 0 && (flags & PUFLAGS_MPTH) == 0)
+ return dissect_gquic_common(tvb, pinfo, tree, NULL);
+ return dissect_gquic_q046(tvb, pinfo, tree, NULL);
+}
+
+static gboolean dissect_gquic_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+
+ conversation_t *conversation = NULL;
+ int offset = 0;
+ guint8 flags;
+ guint32 version;
+
+ if (tvb_captured_length(tvb) < 1) {
+ return FALSE;
+ }
+ flags = tvb_get_guint8(tvb, offset);
+ offset += 1;
+
+ if((flags & PUFLAGS_RSV) == 0 && (flags & PUFLAGS_MPTH) == 0) {
+ /* It may be <= Q043 */
+
+ /* Verify packet size (Flag (1 byte) + Connection ID (8 bytes) + Version (4 bytes)) */
+ if (tvb_captured_length(tvb) < 13) {
+ return FALSE;
+ }
+
+ /* Check if flags version is set */
+ if((flags & PUFLAGS_VRSN) == 0) {
+ return FALSE;
+ }
+
+ /* Connection ID is always set to "long" (8bytes) too */
+ if((flags & PUFLAGS_CID) == 0){
+ return FALSE;
+ }
+ offset += 8;
+
+ /* Check if version start with Q02... (0x51 0x30 0x32), Q03... (0x51 0x30 0x33) or Q04... (0x51 0x30 0x34) */
+ version = tvb_get_ntoh24(tvb, offset);
+ if ( version == GQUIC_MAGIC2 || version == GQUIC_MAGIC3 || version == GQUIC_MAGIC4) {
+ conversation = find_or_create_conversation(pinfo);
+ conversation_set_dissector(conversation, gquic_handle);
+ dissect_gquic(tvb, pinfo, tree, data);
+ return TRUE;
+ }
+ } else if((flags & PUFLAGS_MPTH) && (flags & PUFLAGS_RSV)) {
+ /* It may be > Q043, Long Header. We handle only Q046 */
+
+ /* Verify packet size (Flag (1 byte) + Version (4) + DCIL/SCIL (1) + Dest Connection ID (8 bytes)) */
+ if (tvb_captured_length(tvb) < 14) {
+ return FALSE;
+ }
+
+ version = tvb_get_ntohl(tvb, offset);
+ if (version != GQUIC_VERSION_Q046) {
+ return FALSE;
+ }
+
+ conversation = find_or_create_conversation(pinfo);
+ conversation_set_dissector(conversation, gquic_handle);
+ dissect_gquic(tvb, pinfo, tree, data);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+proto_register_gquic(void)
+{
+ module_t *gquic_module;
+
+ static hf_register_info hf[] = {
+ /* Long/Short header for Q046 */
+ { &hf_gquic_header_form,
+ { "Header Form", "gquic.header_form",
+ FT_UINT8, BASE_DEC, VALS(gquic_short_long_header_vals), 0x80,
+ "The most significant bit (0x80) of the first octet is set to 1 for long headers and 0 for short headers.", HFILL }
+ },
+ { &hf_gquic_fixed_bit,
+ { "Fixed Bit", "gquic.fixed_bit",
+ FT_BOOLEAN, 8, NULL, 0x40,
+ "Must be 1", HFILL }
+ },
+ { &hf_gquic_long_packet_type,
+ { "Packet Type", "gquic.long.packet_type",
+ FT_UINT8, BASE_DEC, VALS(gquic_long_packet_type_vals), 0x30,
+ "Long Header Packet Type", HFILL }
+ },
+ { &hf_gquic_long_reserved,
+ { "Reserved", "gquic.long.reserved",
+ FT_UINT8, BASE_DEC, NULL, 0x0c,
+ "Reserved bits", HFILL }
+ },
+ { &hf_gquic_packet_number_length,
+ { "Packet Number Length", "gquic.packet_number_length",
+ FT_UINT8, BASE_DEC, VALS(gquic_packet_number_lengths), 0x03,
+ "Packet Number field length", HFILL }
+ },
+ { &hf_gquic_dcil,
+ { "Destination Connection ID Length", "gquic.dcil",
+ FT_UINT8, BASE_DEC, VALS(quic_cid_lengths), 0xF0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_scil,
+ { "Source Connection ID Length", "gquic.scil",
+ FT_UINT8, BASE_DEC, VALS(quic_cid_lengths), 0x0F,
+ NULL, HFILL }
+ },
+
+ /* Public header for < Q046 */
+ { &hf_gquic_puflags,
+ { "Public Flags", "gquic.puflags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Specifying per-packet public flags", HFILL }
+ },
+ { &hf_gquic_puflags_vrsn,
+ { "Version", "gquic.puflags.version",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), PUFLAGS_VRSN,
+ "Signifies that this packet also contains the version of the (Google)QUIC protocol", HFILL }
+ },
+ { &hf_gquic_puflags_rst,
+ { "Reset", "gquic.puflags.reset",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), PUFLAGS_RST,
+ "Signifies that this packet is a public reset packet", HFILL }
+ },
+ { &hf_gquic_puflags_dnonce,
+ { "Diversification nonce", "gquic.puflags.nonce",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), PUFLAGS_DNONCE,
+ "Indicates the presence of a 32 byte diversification nonce", HFILL }
+ },
+ { &hf_gquic_puflags_cid,
+ { "CID Length", "gquic.puflags.cid",
+ FT_BOOLEAN, 8, TFS(&puflags_cid_tfs), PUFLAGS_CID,
+ "Indicates the full 8 byte Connection ID is present", HFILL }
+ },
+ { &hf_gquic_puflags_cid_old,
+ { "CID Length", "gquic.puflags.cid.old",
+ FT_UINT8, BASE_HEX, VALS(puflags_cid_old_vals), PUFLAGS_CID_OLD,
+ "Signifies the Length of CID", HFILL }
+ },
+ { &hf_gquic_puflags_pkn,
+ { "Packet Number Length", "gquic.puflags.pkn",
+ FT_UINT8, BASE_HEX, VALS(puflags_pkn_vals), PUFLAGS_PKN,
+ "Signifies the Length of packet number", HFILL }
+ },
+ { &hf_gquic_puflags_mpth,
+ { "Multipath", "gquic.puflags.mpth",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), PUFLAGS_MPTH,
+ "Reserved for multipath use", HFILL }
+ },
+ { &hf_gquic_puflags_rsv,
+ { "Reserved", "gquic.puflags.rsv",
+ FT_UINT8, BASE_HEX, NULL, PUFLAGS_RSV,
+ "Must be Zero", HFILL }
+ },
+ { &hf_gquic_cid,
+ { "CID", "gquic.cid",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Connection ID 64 bit pseudo random number", HFILL }
+ },
+ { &hf_gquic_version,
+ { "Version", "gquic.version",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "32 bit opaque tag that represents the version of the (Google)QUIC", HFILL }
+ },
+ { &hf_gquic_diversification_nonce,
+ { "Diversification nonce", "gquic.diversification_nonce",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_packet_number,
+ { "Packet Number", "gquic.packet_number",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "The lower 8, 16, 32, or 48 bits of the packet number", HFILL }
+ },
+
+ { &hf_gquic_prflags,
+ { "Private Flags", "gquic.prflags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Specifying per-packet Private flags", HFILL }
+ },
+
+ { &hf_gquic_prflags_entropy,
+ { "Entropy", "gquic.prflags.entropy",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), PRFLAGS_ENTROPY,
+ "For data packets, signifies that this packet contains the 1 bit of entropy, for fec packets, contains the xor of the entropy of protected packets", HFILL }
+ },
+ { &hf_gquic_prflags_fecg,
+ { "FEC Group", "gquic.prflags.fecg",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), PRFLAGS_FECG,
+ "Indicates whether the fec byte is present.", HFILL }
+ },
+ { &hf_gquic_prflags_fec,
+ { "FEC", "gquic.prflags.fec",
+ FT_BOOLEAN, 8, TFS(&tfs_yes_no), PRFLAGS_FEC,
+ "Signifies that this packet represents an FEC packet", HFILL }
+ },
+ { &hf_gquic_prflags_rsv,
+ { "Reserved", "gquic.prflags.rsv",
+ FT_UINT8, BASE_HEX, NULL, PRFLAGS_RSV,
+ "Must be Zero", HFILL }
+ },
+
+ { &hf_gquic_message_authentication_hash,
+ { "Message Authentication Hash", "gquic.message_authentication_hash",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "The hash is an FNV1a-128 hash, serialized in little endian order", HFILL }
+ },
+ { &hf_gquic_frame,
+ { "Frame", "gquic.frame",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type,
+ { "Frame Type", "gquic.frame_type",
+ FT_UINT8 ,BASE_RANGE_STRING | BASE_HEX, RVALS(frame_type_vals), 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_padding_length,
+ { "Padding Length", "gquic.frame_type.padding.length",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_padding,
+ { "Padding", "gquic.frame_type.padding",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "Must be zero", HFILL }
+ },
+ { &hf_gquic_frame_type_rsts_stream_id,
+ { "Stream ID", "gquic.frame_type.rsts.stream_id",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Stream ID of the stream being terminated", HFILL }
+ },
+ { &hf_gquic_frame_type_rsts_byte_offset,
+ { "Byte offset", "gquic.frame_type.rsts.byte_offset",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Indicating the absolute byte offset of the end of data for this stream", HFILL }
+ },
+ { &hf_gquic_frame_type_rsts_error_code,
+ { "Error code", "gquic.frame_type.rsts.error_code",
+ FT_UINT32, BASE_DEC|BASE_EXT_STRING, &rststream_error_code_vals_ext, 0x0,
+ "Indicates why the stream is being closed", HFILL }
+ },
+ { &hf_gquic_frame_type_cc_error_code,
+ { "Error code", "gquic.frame_type.cc.error_code",
+ FT_UINT32, BASE_DEC|BASE_EXT_STRING, &error_code_vals_ext, 0x0,
+ "Indicates the reason for closing this connection", HFILL }
+ },
+ { &hf_gquic_frame_type_cc_reason_phrase_length,
+ { "Reason phrase Length", "gquic.frame_type.cc.reason_phrase.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Specifying the length of the reason phrase", HFILL }
+ },
+ { &hf_gquic_frame_type_cc_reason_phrase,
+ { "Reason phrase", "gquic.frame_type.cc.reason_phrase",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "An optional human-readable explanation for why the connection was closed", HFILL }
+ },
+ { &hf_gquic_frame_type_goaway_error_code,
+ { "Error code", "gquic.frame_type.goaway.error_code",
+ FT_UINT32, BASE_DEC|BASE_EXT_STRING, &error_code_vals_ext, 0x0,
+ "Indicates the reason for closing this connection", HFILL }
+ },
+ { &hf_gquic_frame_type_goaway_last_good_stream_id,
+ { "Last Good Stream ID", "gquic.frame_type.goaway.last_good_stream_id",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "last Stream ID which was accepted by the sender of the GOAWAY message", HFILL }
+ },
+ { &hf_gquic_frame_type_goaway_reason_phrase_length,
+ { "Reason phrase Length", "gquic.frame_type.goaway.reason_phrase.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Specifying the length of the reason phrase", HFILL }
+ },
+ { &hf_gquic_frame_type_goaway_reason_phrase,
+ { "Reason phrase", "gquic.frame_type.goaway.reason_phrase",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "An optional human-readable explanation for why the connection was closed", HFILL }
+ },
+ { &hf_gquic_frame_type_wu_stream_id,
+ { "Stream ID", "gquic.frame_type.wu.stream_id",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "ID of the stream whose flow control windows is begin updated, or 0 to specify the connection-level flow control window", HFILL }
+ },
+ { &hf_gquic_frame_type_wu_byte_offset,
+ { "Byte offset", "gquic.frame_type.wu.byte_offset",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Indicating the absolute byte offset of data which can be sent on the given stream", HFILL }
+ },
+ { &hf_gquic_frame_type_blocked_stream_id,
+ { "Stream ID", "gquic.frame_type.blocked.stream_id",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Indicating the stream which is flow control blocked", HFILL }
+ },
+ { &hf_gquic_frame_type_sw_send_entropy,
+ { "Send Entropy", "gquic.frame_type.sw.send_entropy",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the cumulative hash of entropy in all sent packets up to the packet with packet number one less than the least unacked packet", HFILL }
+ },
+ { &hf_gquic_frame_type_sw_least_unacked_delta,
+ { "Least unacked delta", "gquic.frame_type.sw.least_unacked_delta",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "A variable length packet number delta with the same length as the packet header's packet number", HFILL }
+ },
+ { &hf_gquic_crypto_offset,
+ { "Offset", "gquic.crypto.offset",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Byte offset into the stream", HFILL }
+ },
+ { &hf_gquic_crypto_length,
+ { "Length", "gquic.crypto.length",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Length of the Crypto Data field", HFILL }
+ },
+ { &hf_gquic_crypto_crypto_data,
+ { "Crypto Data", "gquic.crypto.crypto_data",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "The cryptographic message data", HFILL }
+ },
+ { &hf_gquic_frame_type_stream,
+ { "Stream", "gquic.frame_type.stream",
+ FT_BOOLEAN, 8, NULL, FTFLAGS_STREAM,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_stream_f,
+ { "FIN", "gquic.frame_type.stream.f",
+ FT_BOOLEAN, 8, NULL, FTFLAGS_STREAM_F,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_stream_d,
+ { "Data Length", "gquic.frame_type.stream.d",
+ FT_BOOLEAN, 8, TFS(&len_data_vals), FTFLAGS_STREAM_D,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_stream_ooo,
+ { "Offset Length", "gquic.frame_type.stream.ooo",
+ FT_UINT8, BASE_DEC, VALS(len_offset_vals), FTFLAGS_STREAM_OOO,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_stream_ss,
+ { "Stream Length", "gquic.frame_type.stream.ss",
+ FT_UINT8, BASE_DEC, VALS(len_stream_vals), FTFLAGS_STREAM_SS,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack,
+ { "ACK", "gquic.frame_type.ack",
+ FT_BOOLEAN, 8, NULL, FTFLAGS_ACK,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack_n,
+ { "NACK", "gquic.frame_type.ack.n",
+ FT_BOOLEAN, 8, NULL, FTFLAGS_ACK_N,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack_u,
+ { "Unused", "gquic.frame_type.ack.u",
+ FT_BOOLEAN, 8, NULL, FTFLAGS_ACK_U,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack_t,
+ { "Truncated", "gquic.frame_type.ack.t",
+ FT_BOOLEAN, 8, NULL, FTFLAGS_ACK_T,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack_ll,
+ { "Largest Observed Length", "gquic.frame_type.ack.ll",
+ FT_UINT8, BASE_DEC, VALS(len_largest_observed_vals), FTFLAGS_ACK_LL,
+ "Length of the Largest Observed field as 1, 2, 4, or 6 bytes long", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_mm,
+ { "Missing Packet Length", "gquic.frame_type.ack.mm",
+ FT_UINT8, BASE_DEC, VALS(len_missing_packet_vals), FTFLAGS_ACK_MM,
+ "Length of the Missing Packet Number Delta field as 1, 2, 4, or 6 bytes long", HFILL }
+ },
+ /* ACK before Q034 */
+ { &hf_gquic_frame_type_ack_received_entropy,
+ { "Received Entropy", "gquic.frame_type.ack.received_entropy",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the cumulative hash of entropy in all received packets up to the largest observed packet", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_largest_observed,
+ { "Largest Observed", "gquic.frame_type.ack.largest_observed",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Representing the largest packet number the peer has observed", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_ack_delay_time,
+ { "Ack Delay time", "gquic.frame_type.ack.ack_delay_time",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Specifying the time elapsed in microseconds from when largest observed was received until this Ack frame was sent", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_num_timestamp,
+ { "Num Timestamp", "gquic.frame_type.ack.num_timestamp",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the number of TCP timestamps that are included in this frame", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_delta_largest_observed,
+ { "Delta Largest Observed", "gquic.frame_type.ack.delta_largest_observed",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the packet number delta from the first timestamp to the largest observed", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_first_timestamp,
+ { "First Timestamp", "gquic.frame_type.ack.first_timestamp",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Specifying the time delta in microseconds, from the beginning of the connection of the arrival of the packet specified by Largest Observed minus Delta Largest Observed", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_time_since_previous_timestamp,
+ { "Time since Previous timestamp", "gquic.frame_type.ack.time_since_previous_timestamp",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "This is the time delta from the previous timestamp", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_num_ranges,
+ { "Num Ranges", "gquic.frame_type.ack.num_ranges",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the number of missing packet ranges between largest observed and least unacked", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_missing_packet,
+ { "Missing Packet Number Delta", "gquic.frame_type.ack.missing_packet",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack_range_length,
+ { "Range Length", "gquic.frame_type.ack.range_length",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying one less than the number of sequential nacks in the range", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_num_revived,
+ { "Num Revived", "gquic.frame_type.ack.num_revived",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the number of revived packets, recovered via FEC", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_revived_packet,
+ { "Revived Packet Number", "gquic.frame_type.ack.revived_packet",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Representing a packet the peer has revived via FEC", HFILL }
+ },
+ /* ACK after Q034 */
+ { &hf_gquic_frame_type_ack_largest_acked,
+ { "Largest Acked", "gquic.frame_type.ack.largest_acked",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Representing the largest packet number the peer has observed", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_largest_acked_delta_time,
+ { "Largest Acked Delta Time", "gquic.frame_type.ack.largest_acked_delta_time",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Specifying the time elapsed in microseconds from when largest acked was received until this Ack frame was sent", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_num_blocks,
+ { "Num blocks", "gquic.frame_type.ack.num_blocks",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying one less than the number of ack blocks", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_first_ack_block_length,
+ { "First Ack block length", "gquic.frame_type.ack.first_ack_block_length",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack_gap_to_next_block,
+ { "Gap to next block", "gquic.frame_type.ack.gap_to_next_block",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the number of packets between ack blocks", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_ack_block_length,
+ { "Ack block length", "gquic.frame_type.ack.ack_block_length",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_frame_type_ack_delta_largest_acked,
+ { "Delta Largest Observed", "gquic.frame_type.ack.delta_largest_acked",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Specifying the packet number delta from the first timestamp to the largest observed", HFILL }
+ },
+ { &hf_gquic_frame_type_ack_time_since_largest_acked,
+ { "Time Since Largest Acked", "gquic.frame_type.ack.time_since_largest_acked",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Specifying the time delta in microseconds, from the beginning of the connection of the arrival of the packet specified by Largest Observed minus Delta Largest Observed", HFILL }
+ },
+
+
+
+ { &hf_gquic_stream_id,
+ { "Stream ID", "gquic.stream_id",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_offset,
+ { "Offset", "gquic.offset",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_data_len,
+ { "Data Length", "gquic.data_len",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag,
+ { "Tag", "gquic.tag",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_number,
+ { "Tag Number", "gquic.tag_number",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tags,
+ { "Tag/value", "gquic.tags",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_type,
+ { "Tag Type", "gquic.tag_type",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_offset_end,
+ { "Tag offset end", "gquic.tag_offset_end",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_length,
+ { "Tag length", "gquic.tag_offset_length",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_value,
+ { "Tag/value", "gquic.tag_value",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_sni,
+ { "Server Name Indication", "gquic.tag.sni",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "The fully qualified DNS name of the server, canonicalised to lowercase with no trailing period", HFILL }
+ },
+ { &hf_gquic_tag_pad,
+ { "Padding", "gquic.tag.pad",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "Pad.....", HFILL }
+ },
+ { &hf_gquic_tag_ver,
+ { "Version", "gquic.tag.version",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Version of gquic supported", HFILL }
+ },
+ { &hf_gquic_tag_pdmd,
+ { "Proof demand", "gquic.tag.pdmd",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "a list of tags describing the types of proof acceptable to the client, in preference order", HFILL }
+ },
+ { &hf_gquic_tag_ccs,
+ { "Common certificate sets", "gquic.tag.ccs",
+ FT_UINT64, BASE_HEX, NULL, 0x0,
+ "A series of 64-bit, FNV-1a hashes of sets of common certificates that the client possesses", HFILL }
+ },
+ { &hf_gquic_tag_uaid,
+ { "Client's User Agent ID", "gquic.tag.uaid",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_stk,
+ { "Source-address token", "gquic.tag.stk",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_sno,
+ { "Server nonce", "gquic.tag.sno",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_prof,
+ { "Proof (Signature)", "gquic.tag.prof",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_scfg,
+ { "Server Config Tag", "gquic.tag.scfg",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_scfg_number,
+ { "Number Server Config Tag", "gquic.tag.scfg.number",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_rrej,
+ { "Reasons for server sending", "gquic.tag.rrej",
+ FT_UINT32, BASE_DEC|BASE_EXT_STRING, &handshake_failure_reason_vals_ext, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_crt,
+ { "Certificate chain", "gquic.tag.crt",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_aead,
+ { "Authenticated encryption algorithms", "gquic.tag.aead",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "A list of tags, in preference order, specifying the AEAD primitives supported by the server", HFILL }
+ },
+ { &hf_gquic_tag_scid,
+ { "Server Config ID", "gquic.tag.scid",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "An opaque, 16-byte identifier for this server config", HFILL }
+ },
+ { &hf_gquic_tag_pubs,
+ { "Public value", "gquic.tag.pubs",
+ FT_UINT24, BASE_DEC_HEX, NULL, 0x0,
+ "A list of public values, 24-bit, little-endian length prefixed", HFILL }
+ },
+ { &hf_gquic_tag_kexs,
+ { "Key exchange algorithms", "gquic.tag.kexs",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "A list of tags, in preference order, specifying the key exchange algorithms that the server supports", HFILL }
+ },
+ { &hf_gquic_tag_obit,
+ { "Server orbit", "gquic.tag.obit",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_expy,
+ { "Expiry", "gquic.tag.expy",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "a 64-bit expiry time for the server config in UNIX epoch seconds", HFILL }
+ },
+ { &hf_gquic_tag_nonc,
+ { "Client nonce", "gquic.tag.nonc",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "32 bytes consisting of 4 bytes of timestamp (big-endian, UNIX epoch seconds), 8 bytes of server orbit and 20 bytes of random data", HFILL }
+ },
+ { &hf_gquic_tag_mspc,
+ { "Max streams per connection", "gquic.tag.mspc",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_tcid,
+ { "Connection ID truncation", "gquic.tag.tcid",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_srbf,
+ { "Socket receive buffer", "gquic.tag.srbf",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_icsl,
+ { "Idle connection state", "gquic.tag.icsl",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_scls,
+ { "Silently close on timeout", "gquic.tag.scls",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_copt,
+ { "Connection options", "gquic.tag.copt",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_ccrt,
+ { "Cached certificates", "gquic.tag.ccrt",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_irtt,
+ { "Estimated initial RTT", "gquic.tag.irtt",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "in us", HFILL }
+ },
+ { &hf_gquic_tag_cfcw,
+ { "Initial session/connection", "gquic.tag.cfcw",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_sfcw,
+ { "Initial stream flow control", "gquic.tag.sfcw",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_cetv,
+ { "Client encrypted tag-value", "gquic.tag.cetv",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_xlct,
+ { "Expected leaf certificate", "gquic.tag.xlct",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_nonp,
+ { "Client Proof nonce", "gquic.tag.nonp",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_csct,
+ { "Signed cert timestamp", "gquic.tag.csct",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_ctim,
+ { "Client Timestamp", "gquic.tag.ctim",
+ FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_rnon,
+ { "Public reset nonce proof", "gquic.tag.rnon",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_rseq,
+ { "Rejected Packet Number", "gquic.tag.rseq",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "a 64-bit packet number", HFILL }
+ },
+ { &hf_gquic_tag_cadr_addr_type,
+ { "Client IP Address Type", "gquic.tag.caddr.addr.type",
+ FT_UINT16, BASE_DEC, VALS(cadr_type_vals), 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_cadr_addr_ipv4,
+ { "Client IP Address", "gquic.tag.caddr.addr.ipv4",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_cadr_addr_ipv6,
+ { "Client IP Address", "gquic.tag.caddr.addr.ipv6",
+ FT_IPv6, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_cadr_addr,
+ { "Client IP Address", "gquic.tag.caddr.addr",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_cadr_port,
+ { "Client Port (Source)", "gquic.tag.caddr.port",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_mids,
+ { "Max incoming dynamic streams", "gquic.tag.mids",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_fhol,
+ { "Force Head Of Line blocking", "gquic.tag.fhol",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_sttl,
+ { "Server Config TTL", "gquic.tag.sttl",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_smhl,
+ { "Support Max Header List (size)", "gquic.tag.smhl",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_tbkp,
+ { "Token Binding Key Params.", "gquic.tag.tbkp",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_mad0,
+ { "Max Ack Delay", "gquic.tag.mad0",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_qlve,
+ { "Legacy Version Encapsulation", "gquic.tag.qlve",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_cgst,
+ { "Congestion Control Feedback Type", "gquic.tag.cgst",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_epid,
+ { "Endpoint identifier", "gquic.tag.epid",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_tag_srst,
+ { "Stateless Reset Token", "gquic.tag.srst",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ { &hf_gquic_tag_unknown,
+ { "Unknown tag", "gquic.tag.unknown",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_padding,
+ { "Padding", "gquic.padding",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_stream_data,
+ { "Stream Data", "gquic.stream_data",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_gquic_payload,
+ { "Payload", "gquic.payload",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "(Google) QUIC Payload..", HFILL }
+ },
+ };
+
+
+ static gint *ett[] = {
+ &ett_gquic,
+ &ett_gquic_puflags,
+ &ett_gquic_prflags,
+ &ett_gquic_ft,
+ &ett_gquic_ftflags,
+ &ett_gquic_tag_value
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_gquic_tag_undecoded, { "gquic.tag.undecoded", PI_UNDECODED, PI_NOTE, "Dissector for (Google)QUIC Tag code not implemented, Contact Wireshark developers if you want this supported", EXPFILL }},
+ { &ei_gquic_tag_length, { "gquic.tag.length.truncated", PI_MALFORMED, PI_NOTE, "Truncated Tag Length...", EXPFILL }},
+ { &ei_gquic_tag_unknown, { "gquic.tag.unknown.data", PI_UNDECODED, PI_NOTE, "Unknown Data", EXPFILL }},
+ { &ei_gquic_version_invalid, { "gquic.version.invalid", PI_MALFORMED, PI_ERROR, "Invalid Version", EXPFILL }},
+ { &ei_gquic_invalid_parameter, { "gquic.invalid.parameter", PI_MALFORMED, PI_ERROR, "Invalid Parameter", EXPFILL }},
+ { &ei_gquic_length_invalid, { "gquic.length.invalid", PI_PROTOCOL, PI_WARN, "Invalid Length", EXPFILL }},
+ { &ei_gquic_data_invalid, { "gquic.data.invalid", PI_PROTOCOL, PI_WARN, "Invalid Data", EXPFILL }},
+ };
+
+ expert_module_t *expert_gquic;
+
+ proto_gquic = proto_register_protocol("GQUIC (Google Quick UDP Internet Connections)", "GQUIC", "gquic");
+
+ proto_register_field_array(proto_gquic, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ gquic_module = prefs_register_protocol(proto_gquic, NULL);
+
+ prefs_register_bool_preference(gquic_module, "debug.quic",
+ "Force decode of all (Google) QUIC Payload",
+ "Help for debug...",
+ &g_gquic_debug);
+
+ expert_gquic = expert_register_protocol(proto_gquic);
+ expert_register_field_array(expert_gquic, ei, array_length(ei));
+
+ gquic_handle = register_dissector("gquic", dissect_gquic, proto_gquic);
+}
+
+void
+proto_reg_handoff_gquic(void)
+{
+ tls13_handshake_handle = find_dissector("tls13-handshake");
+ quic_handle = find_dissector("quic");
+ dissector_add_uint_range_with_preference("udp.port", "", gquic_handle);
+ heur_dissector_add("udp", dissect_gquic_heur, "Google QUIC", "gquic", proto_gquic, HEURISTIC_ENABLE);
+}
+
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */