QUIC: Add Regular Frame Type...

Add also heuristic to check if it is handstake

Ping-Bug: 11494
Change-Id: I833d294a3a6fdc89cc6d6a5d72d388a3328bf802
Reviewed-on: https://code.wireshark.org/review/10566
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Alexis La Goutte 2015-09-16 12:39:21 +02:00 committed by Michael Mann
parent 30ff173a87
commit c66233c778
1 changed files with 551 additions and 223 deletions

View File

@ -54,7 +54,25 @@ static int hf_quic_prflags_fecg = -1;
static int hf_quic_prflags_fec = -1;
static int hf_quic_prflags_rsv = -1;
static int hf_quic_message_authentication_hash = -1;
static int hf_quic_frame = -1;
static int hf_quic_frame_type = -1;
static int hf_quic_frame_type_padding_length = -1;
static int hf_quic_frame_type_padding = -1;
static int hf_quic_frame_type_rsts_stream_id = -1;
static int hf_quic_frame_type_rsts_byte_offset = -1;
static int hf_quic_frame_type_rsts_error_code = -1;
static int hf_quic_frame_type_cc_error_code = -1;
static int hf_quic_frame_type_cc_reason_phrase_length = -1;
static int hf_quic_frame_type_cc_reason_phrase = -1;
static int hf_quic_frame_type_goaway_error_code = -1;
static int hf_quic_frame_type_goaway_last_good_stream_id = -1;
static int hf_quic_frame_type_goaway_reason_phrase_length = -1;
static int hf_quic_frame_type_goaway_reason_phrase = -1;
static int hf_quic_frame_type_wu_stream_id = -1;
static int hf_quic_frame_type_wu_byte_offset = -1;
static int hf_quic_frame_type_blocked_stream_id = -1;
static int hf_quic_frame_type_sw_send_entropy = -1;
static int hf_quic_frame_type_sw_least_unacked_delta = -1;
static int hf_quic_frame_type_stream = -1;
static int hf_quic_frame_type_stream_f = -1;
static int hf_quic_frame_type_stream_d = -1;
@ -117,6 +135,7 @@ static int hf_quic_tag_ccrt = -1;
static int hf_quic_tag_irtt = -1;
static int hf_quic_tag_cfcw = -1;
static int hf_quic_tag_sfcw = -1;
static int hf_quic_tag_cetv = -1;
static int hf_quic_tag_unknown = -1;
static int hf_quic_padding = -1;
@ -128,6 +147,7 @@ static guint g_quics_port = 443;
static gint ett_quic = -1;
static gint ett_quic_puflags = -1;
static gint ett_quic_prflags = -1;
static gint ett_quic_ft = -1;
static gint ett_quic_ftflags = -1;
static gint ett_quic_tag_value = -1;
@ -172,7 +192,19 @@ static const value_string puflags_seq_vals[] = {
/**************************************************************************/
/* Frame Type */
/* 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
/**************************************************************************/
/* Frame Type Special */
/**************************************************************************/
#define FTFLAGS_SPECIAL 0xE0
@ -295,6 +327,7 @@ static const value_string message_tag_vals[] = {
#define TAG_IRTT 0x49525454
#define TAG_CFCW 0x43464357
#define TAG_SFCW 0x53464357
#define TAG_CETV 0x43455456
static const value_string tag_vals[] = {
{ TAG_PAD, "Padding" },
@ -326,6 +359,7 @@ static const value_string tag_vals[] = {
{ TAG_IRTT, "Estimated initial RTT" },
{ TAG_CFCW, "Initial session/connection" },
{ TAG_SFCW, "Initial stream flow control" },
{ TAG_CETV, "Client encrypted tag-value" },
{ 0, NULL }
};
@ -357,6 +391,21 @@ static const value_string tag_kexs_vals[] = {
{ KEXS_P256, "P-256" },
{ 0, NULL }
};
/**************************************************************************/
/* Error Code */
/* See src/net/quic/quic_protocol.h from Chromium Source */
/**************************************************************************/
#define QUIC_NO_ERROR 0
static const value_string error_code_vals[] = {
{ QUIC_NO_ERROR, "There was no error" },
/*TODO Complete... */
{ 0, NULL }
};
static guint32 get_len_offset(guint8 frame_type){
guint32 len;
@ -459,14 +508,15 @@ static guint32 get_len_missing_packet(guint8 frame_type){
return len;
}
#if 0
static gboolean is_quic_handshake(tvbuff_t *tvb, guint offset){
static gboolean is_quic_handshake(tvbuff_t *tvb, guint offset, guint16 len_seq){
guint8 frame_type;
guint8 num_ranges, num_revived, 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){
if(tvb_captured_length_remaining(tvb, offset) <= 13){
return FALSE;
}
/* Message Authentication Hash */
@ -475,110 +525,176 @@ static gboolean is_quic_handshake(tvbuff_t *tvb, guint offset){
/* Private Flags */
offset += 1;
/* Frame type */
frame_type = tvb_get_guint8(tvb, offset);
if((frame_type & FTFLAGS_SPECIAL) == 0){
return FALSE;
}
if(frame_type & FTFLAGS_STREAM){
while(tvb_reported_length_remaining(tvb, offset) > 0){
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;
} 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;
/* Received Entropy */
offset += 1;
/* Largest Observed */
offset += len_largest_observed;
/* Largest Observed Delta Time */
offset += 2;
/* Num Timestamp */
if ( tvb_captured_length(tvb) <= offset){
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 */
/* 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;
/* Time Since Previous Timestamp */
offset += 4;
/* Error Code */
offset += 4;
/* Reason Phrase Length */
len_reason = tvb_get_ntohs(tvb, offset);
offset += 2;
/* Reason Phrase */
offset += len_reason;
}
break;
case FT_GOAWAY:{
guint16 len_reason;
/* Num Timestamp (-1)x (Delta Largest Observed + Time Since Largest Observed) */
offset += (num_timestamp - 1)*(1+2);
}
if(frame_type & FTFLAGS_ACK_N){
/* Num Ranges */
if ( tvb_captured_length(tvb) <= offset){
return FALSE;
/* Error Code */
offset += 4;
/* Last Good Stream ID */
offset += 4;
/* Reason Phrase Length */
len_reason = tvb_get_ntohs(tvb, offset);
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:
/* Send Entropy */
offset += 1;
/* Least Unacked Delta */
offset += len_seq;
break;
case FT_PING: /* No Payload */
default: /* No default */
break;
}
num_ranges = tvb_get_guint8(tvb, offset);
offset += 1;
} else {
/* Num Range x (Missing Packet + Range Length) */
offset += num_ranges*(len_missing_packet+1);
/* Special Frame Type */
if(frame_type & FTFLAGS_STREAM){ /* Stream */
/* Num Revived */
if ( tvb_captured_length(tvb) <= offset){
return FALSE;
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(tvb) <= offset){
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) {
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;
/* Received Entropy */
offset += 1;
/* Largest Observed */
offset += len_largest_observed;
/* Largest Observed Delta Time */
offset += 2;
/* Num Timestamp */
if ( tvb_captured_length(tvb) <= offset){
return FALSE;
}
num_timestamp = tvb_get_guint8(tvb, offset);
offset += 1;
if(num_timestamp > 0){
/* Delta Largest Observed */
offset += 1;
/* Time Since Previous Timestamp */
offset += 4;
/* Num Timestamp (-1)x (Delta Largest Observed + Time Since Largest Observed) */
offset += (num_timestamp - 1)*(1+2);
}
if(frame_type & FTFLAGS_ACK_N){
/* Num Ranges */
if ( tvb_captured_length(tvb) <= offset){
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(tvb) <= offset){
return FALSE;
}
num_revived = tvb_get_guint8(tvb, offset);
offset += 1;
/* Num Revived x Length Largest Observed */
offset += num_revived*len_largest_observed;
}
} else { /* Other Special Frame type */
offset += 1;
}
num_revived = tvb_get_guint8(tvb, offset);
offset += 1;
/* Num Revived x Length Largest Observed */
offset += num_revived*len_largest_observed;
}
} else {
return FALSE;
}
if ( tvb_captured_length(tvb) <= offset){
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) {
return TRUE;
}
return FALSE;
}
#endif
static guint32
dissect_quic_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint offset, guint32 tag_number){
guint32 tag_offset_start = offset + tag_number*4*2;
@ -800,6 +916,11 @@ dissect_quic_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint
tag_offset += 4;
tag_len -= 4;
break;
case TAG_CETV:
proto_tree_add_item(tag_tree, hf_quic_tag_cetv, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
tag_offset += tag_len;
tag_len -= tag_len;
break;
default:
proto_tree_add_item(tag_tree, hf_quic_tag_unknown, tvb, tag_offset_start + tag_offset, tag_len, ENC_NA);
expert_add_info_format(pinfo, ti_tag, &ei_quic_tag_undecoded,
@ -818,18 +939,252 @@ dissect_quic_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint
tag_number--;
}
return total_tag_len;
return offset + total_tag_len;
}
static int
dissect_quic_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint offset){
proto_item *ti, *ti_prflags, *ti_ftflags /*, *expert_ti*/;
proto_tree *prflags_tree, *ftflags_tree;
dissect_quic_frame_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint offset, guint8 len_seq){
proto_item *ti, *ti_ft, *ti_ftflags /*, *expert_ti*/;
proto_tree *ft_tree, *ftflags_tree;
guint8 frame_type;
guint8 num_ranges, num_revived, num_timestamp;
guint32 tag_number;
guint32 len_stream = 0, len_offset = 0, len_data = 0, len_largest_observed = 1, len_missing_packet = 1;
guint32 message_tag;
ti_ft = proto_tree_add_item(quic_tree, hf_quic_frame, tvb, offset, 1, ENC_NA);
ft_tree = proto_item_add_subtree(ti_ft, ett_quic_ft);
/* Frame type */
ti_ftflags = proto_tree_add_item(ft_tree, hf_quic_frame_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
frame_type = tvb_get_guint8(tvb, offset);
proto_item_set_text(ti_ft, "%s", rval_to_str(frame_type, frame_type_vals, "Unknown"));
if((frame_type & FTFLAGS_SPECIAL) == 0){ /* 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_quic_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);
proto_tree_add_item(ft_tree, hf_quic_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_quic_frame_type_rsts_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN, &stream_id);
offset += 4;
proto_tree_add_item(ft_tree, hf_quic_frame_type_rsts_byte_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
offset += 8;
proto_tree_add_item_ret_uint(ft_tree, hf_quic_frame_type_rsts_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN, &error_code);
offset += 4;
proto_item_append_text(ti_ft, " Stream ID: %u, Error code: %s", stream_id, val_to_str(error_code, error_code_vals, "Unknown (%d)"));
}
break;
case FT_CONNECTION_CLOSE:{
guint16 len_reason;
guint32 error_code;
proto_tree_add_item_ret_uint(ft_tree, hf_quic_frame_type_cc_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN, &error_code);
offset += 4;
proto_tree_add_item(ft_tree, hf_quic_frame_type_cc_reason_phrase_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
len_reason = tvb_get_ntohs(tvb, offset);
offset += 2;
proto_tree_add_item(ft_tree, hf_quic_frame_type_cc_reason_phrase, tvb, offset, len_reason, ENC_ASCII|ENC_NA);
offset += len_reason;
proto_item_append_text(ti_ft, " Error code: %s", val_to_str(error_code, error_code_vals, "Unknown (%d)"));
}
break;
case FT_GOAWAY:{
guint16 len_reason;
guint32 error_code, last_good_stream_id;
proto_tree_add_item_ret_uint(ft_tree, hf_quic_frame_type_goaway_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN, &error_code);
offset += 4;
proto_tree_add_item_ret_uint(ft_tree, hf_quic_frame_type_goaway_last_good_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN, &last_good_stream_id);
offset += 4;
proto_tree_add_item(ft_tree, hf_quic_frame_type_goaway_reason_phrase_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
len_reason = tvb_get_ntohs(tvb, offset);
offset += 2;
proto_tree_add_item(ft_tree, hf_quic_frame_type_goaway_reason_phrase, tvb, offset, len_reason, ENC_ASCII|ENC_NA);
offset += len_reason;
proto_item_append_text(ti_ft, " Stream ID: %u, Error code: %s", last_good_stream_id, val_to_str(error_code, error_code_vals, "Unknown (%d)"));
}
break;
case FT_WINDOW_UPDATE:{
guint32 stream_id;
proto_tree_add_item_ret_uint(ft_tree, hf_quic_frame_type_wu_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN, &stream_id);
offset += 4;
proto_tree_add_item(ft_tree, hf_quic_frame_type_wu_byte_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
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_quic_frame_type_blocked_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN, &stream_id);
offset += 4;
proto_item_append_text(ti_ft, " Stream ID: %u", stream_id);
}
break;
case FT_STOP_WAITING:{
guint8 send_entropy;
proto_tree_add_item(ft_tree, hf_quic_frame_type_sw_send_entropy, tvb, offset, 1, ENC_LITTLE_ENDIAN);
send_entropy = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(ft_tree, hf_quic_frame_type_sw_least_unacked_delta, tvb, offset, len_seq, ENC_LITTLE_ENDIAN);
offset += len_seq;
proto_item_append_text(ti_ft, " Send Entropy: %u", send_entropy);
}
break;
case FT_PING: /* No Payload */
default: /* No default */
break;
}
}
else { /* Special Frame Types */
guint32 stream_id = 0, message_tag;
ftflags_tree = proto_item_add_subtree(ti_ftflags, ett_quic_ftflags);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream , tvb, offset, 1, ENC_LITTLE_ENDIAN);
if(frame_type & FTFLAGS_STREAM){ /* Stream Flags */
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_f, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_d, tvb, offset, 1, ENC_LITTLE_ENDIAN);
if(frame_type & FTFLAGS_STREAM_D){
len_data = 2;
}
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_ooo, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_offset = get_len_offset(frame_type);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_ss, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_stream = get_len_stream(frame_type);
offset += 1;
if(len_stream) {
proto_tree_add_item_ret_uint(ft_tree, hf_quic_stream_id, tvb, offset, len_stream, ENC_LITTLE_ENDIAN, &stream_id);
offset += len_stream;
}
if(len_offset) {
proto_tree_add_item(ft_tree, hf_quic_offset_len, tvb, offset, len_offset, ENC_LITTLE_ENDIAN);
offset += len_offset;
}
if(len_data) {
proto_tree_add_item(ft_tree, hf_quic_data_len, tvb, offset, len_data, ENC_LITTLE_ENDIAN);
offset += len_data;
}
ti = proto_tree_add_item(ft_tree, hf_quic_tag, tvb, offset, 4, ENC_ASCII|ENC_NA);
message_tag = tvb_get_ntohl(tvb, offset);
proto_item_append_text(ti, " (%s)", val_to_str(message_tag, message_tag_vals, "Unknown Tag"));
proto_item_append_text(ti_ft, " Stream ID:%u, Type: %s (%s)", stream_id, tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 4, ENC_ASCII|ENC_NA), val_to_str(message_tag, message_tag_vals, "Unknown Tag"));
col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(message_tag, message_tag_vals, "Unknown"));
offset += 4;
proto_tree_add_item(ft_tree, hf_quic_tag_number, tvb, offset, 2, ENC_LITTLE_ENDIAN);
tag_number = tvb_get_letohs(tvb, offset);
offset += 2;
proto_tree_add_item(ft_tree, hf_quic_padding, tvb, offset, 2, ENC_NA);
offset += 2;
offset = dissect_quic_tag(tvb, pinfo, ft_tree, offset, tag_number);
} else if (frame_type & FTFLAGS_ACK) { /* ACK Flags */
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_n, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_t, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_ll, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_largest_observed = get_len_largest_observed(frame_type);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_mm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_missing_packet = get_len_missing_packet(frame_type);
offset += 1;
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_received_entropy, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_largest_observed, tvb, offset, len_largest_observed, ENC_LITTLE_ENDIAN);
offset += len_largest_observed;
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_largest_observed_delta_time, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_num_timestamp, tvb, offset, 1, ENC_LITTLE_ENDIAN);
num_timestamp = tvb_get_guint8(tvb, offset);
offset += 1;
/* Delta Largest Observed */
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_delta_largest_observed, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
/* Time Since Previous Timestamp */
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_time_since_largest_observed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
num_timestamp -= 1;
/* Num Timestamp (-1) x (Delta Largest Observed + Time Since Largest Observed) */
while(num_timestamp){
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_delta_largest_observed, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_time_since_previous_timestamp, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
num_timestamp--;
}
if(frame_type & FTFLAGS_ACK_N){
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_num_ranges, tvb, offset, 1, ENC_LITTLE_ENDIAN);
num_ranges = tvb_get_guint8(tvb, offset);
offset += 1;
while(num_ranges){
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_missing_packet, tvb, offset, len_missing_packet, ENC_LITTLE_ENDIAN);
offset += len_missing_packet;
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_range_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
num_ranges--;
}
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_num_revived, tvb, offset, 1, ENC_LITTLE_ENDIAN);
num_revived = tvb_get_guint8(tvb, offset);
offset += 1;
while(num_revived){
proto_tree_add_item(ft_tree, hf_quic_frame_type_ack_revived_packet, tvb, offset, len_largest_observed, ENC_LITTLE_ENDIAN);
offset += len_largest_observed;
num_revived--;
}
}
} else { /* Other ...*/
offset += 1;
}
}
return offset;
}
static int
dissect_quic_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree, guint offset, guint8 len_seq){
proto_item *ti_prflags;
proto_tree *prflags_tree;
/* Message Authentication Hash */
proto_tree_add_item(quic_tree, hf_quic_message_authentication_hash, tvb, offset, 12, ENC_NA);
@ -844,133 +1199,10 @@ dissect_quic_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *quic_tree,
proto_tree_add_item(prflags_tree, hf_quic_prflags_rsv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset +=1;
/* Frame type */
ti_ftflags = proto_tree_add_item(quic_tree, hf_quic_frame_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
frame_type = tvb_get_guint8(tvb, offset);
ftflags_tree = proto_item_add_subtree(ti_ftflags, ett_quic_ftflags);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream, tvb, offset, 1, ENC_LITTLE_ENDIAN);
/* Stream Flags */
if(frame_type & FTFLAGS_STREAM){
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_f, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_d, tvb, offset, 1, ENC_LITTLE_ENDIAN);
if(frame_type & FTFLAGS_STREAM_D){
len_data = 2;
}
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_ooo, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_offset = get_len_offset(frame_type);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_stream_ss, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_stream = get_len_stream(frame_type);
offset += 1;
if(len_stream) {
proto_tree_add_item(quic_tree, hf_quic_stream_id, tvb, offset, len_stream, ENC_LITTLE_ENDIAN);
offset += len_stream;
}
if(len_offset) {
proto_tree_add_item(quic_tree, hf_quic_offset_len, tvb, offset, len_offset, ENC_LITTLE_ENDIAN);
offset += len_offset;
}
if(len_data) {
proto_tree_add_item(quic_tree, hf_quic_data_len, tvb, offset, len_data, ENC_LITTLE_ENDIAN);
offset += len_data;
}
} else if (frame_type & FTFLAGS_ACK) {
/* ACK Flags */
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_n, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_t, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_ll, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_largest_observed = get_len_largest_observed(frame_type);
proto_tree_add_item(ftflags_tree, hf_quic_frame_type_ack_mm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
len_missing_packet = get_len_missing_packet(frame_type);
offset += 1;
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_received_entropy, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_largest_observed, tvb, offset, len_largest_observed, ENC_LITTLE_ENDIAN);
offset += len_largest_observed;
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_largest_observed_delta_time, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_num_timestamp, tvb, offset, 1, ENC_LITTLE_ENDIAN);
num_timestamp = tvb_get_guint8(tvb, offset);
offset += 1;
/* Delta Largest Observed */
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_delta_largest_observed, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
/* Time Since Previous Timestamp */
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_time_since_largest_observed, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
num_timestamp -= 1;
/* Num Timestamp (-1) x (Delta Largest Observed + Time Since Largest Observed) */
while(num_timestamp){
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_delta_largest_observed, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_time_since_previous_timestamp, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
num_timestamp--;
}
if(frame_type & FTFLAGS_ACK_N){
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_num_ranges, tvb, offset, 1, ENC_LITTLE_ENDIAN);
num_ranges = tvb_get_guint8(tvb, offset);
offset += 1;
while(num_ranges){
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_missing_packet, tvb, offset, len_missing_packet, ENC_LITTLE_ENDIAN);
offset += len_missing_packet;
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_range_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
num_ranges--;
}
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_num_revived, tvb, offset, 1, ENC_LITTLE_ENDIAN);
num_revived = tvb_get_guint8(tvb, offset);
offset += 1;
while(num_revived){
proto_tree_add_item(quic_tree, hf_quic_frame_type_ack_revived_packet, tvb, offset, len_largest_observed, ENC_LITTLE_ENDIAN);
offset += len_largest_observed;
num_revived--;
}
}
while(tvb_reported_length_remaining(tvb, offset) > 0){
offset = dissect_quic_frame_type(tvb, pinfo, quic_tree, offset, len_seq);
}
ti = proto_tree_add_item(quic_tree, hf_quic_tag, tvb, offset, 4, ENC_ASCII|ENC_NA);
message_tag = tvb_get_ntohl(tvb, offset);
proto_item_append_text(ti, " (%s)", val_to_str(message_tag, message_tag_vals, "Unknown Tag"));
col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(message_tag, message_tag_vals, "Unknown"));
offset += 4;
proto_tree_add_item(quic_tree, hf_quic_tag_number, tvb, offset, 2, ENC_LITTLE_ENDIAN);
tag_number = tvb_get_letohs(tvb, offset);
offset += 2;
proto_tree_add_item(quic_tree, hf_quic_padding, tvb, offset, 2, ENC_NA);
offset += 2;
dissect_quic_tag(tvb, pinfo, quic_tree, offset, tag_number);
return offset;
}
@ -1072,8 +1304,8 @@ dissect_quic_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
offset += len_seq;
/* Handshake Message */
if (seq == 1 /*|| is_quic_handshake(tvb, offset) */){
offset = dissect_quic_handshake(tvb, pinfo, quic_tree, offset);
if (is_quic_handshake(tvb, offset, len_seq)){
offset = dissect_quic_handshake(tvb, pinfo, quic_tree, offset, len_seq);
}else { /* Payload... (encrypted... TODO FIX !) */
col_add_str(pinfo->cinfo, COL_INFO, "Payload (Encrypted)");
proto_tree_add_item(quic_tree, hf_quic_payload, tvb, offset, -1, ENC_NA);
@ -1186,11 +1418,101 @@ proto_register_quic(void)
FT_BYTES, BASE_NONE, NULL, 0x0,
"The hash is an FNV1a-128 hash, serialized in little endian order", HFILL }
},
{ &hf_quic_frame,
{ "Frame", "quic.frame_type",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_quic_frame_type,
{ "Frame Type", "quic.frame_type",
FT_UINT8 ,BASE_RANGE_STRING | BASE_HEX, RVALS(frame_type_vals), 0x0,
NULL, HFILL }
},
{ &hf_quic_frame_type_padding_length,
{ "Padding Length", "quic.frame_type.padding.length",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_quic_frame_type_padding,
{ "Padding", "quic.frame_type.padding",
FT_BYTES, BASE_NONE, NULL, 0x0,
"Must be zero", HFILL }
},
{ &hf_quic_frame_type_rsts_stream_id,
{ "Stream ID", "quic.frame_type.rsts.stream_id",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Stream ID of the stream being terminated", HFILL }
},
{ &hf_quic_frame_type_rsts_byte_offset,
{ "Byte offset", "quic.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_quic_frame_type_rsts_error_code,
{ "Error code", "quic.frame_type.rsts.error_code",
FT_UINT32, BASE_DEC, VALS(error_code_vals), 0x0,
"Indicates why the stream is being closed", HFILL }
},
{ &hf_quic_frame_type_cc_error_code,
{ "Error code", "quic.frame_type.cc.error_code",
FT_UINT32, BASE_DEC, VALS(error_code_vals), 0x0,
"Stream ID of the stream being terminated", HFILL }
},
{ &hf_quic_frame_type_cc_reason_phrase_length,
{ "Reason phrase Length", "quic.frame_type.cc.reason_phrase.length",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Specifying the length of the reason phrase", HFILL }
},
{ &hf_quic_frame_type_cc_reason_phrase,
{ "Reason phrase", "quic.frame_type.cc.reason_phrase",
FT_STRING, BASE_NONE, NULL, 0x0,
"An optional human-readable explanation for why the connection was closed", HFILL }
},
{ &hf_quic_frame_type_goaway_error_code,
{ "Error code", "quic.frame_type.goaway.error_code",
FT_UINT32, BASE_DEC, VALS(error_code_vals), 0x0,
"Stream ID of the stream being terminated", HFILL }
},
{ &hf_quic_frame_type_goaway_last_good_stream_id,
{ "Error code", "quic.frame_type.goaway.error_code",
FT_UINT32, BASE_DEC, VALS(error_code_vals), 0x0,
"Stream ID of the stream being terminated", HFILL }
},
{ &hf_quic_frame_type_goaway_reason_phrase_length,
{ "Reason phrase Length", "quic.frame_type.goaway.reason_phrase.length",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Specifying the length of the reason phrase", HFILL }
},
{ &hf_quic_frame_type_goaway_reason_phrase,
{ "Reason phrase", "quic.frame_type.goaway.reason_phrase",
FT_STRING, BASE_NONE, NULL, 0x0,
"An optional human-readable explanation for why the connection was closed", HFILL }
},
{ &hf_quic_frame_type_wu_stream_id,
{ "Stream ID", "quic.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_quic_frame_type_wu_byte_offset,
{ "Byte offset", "quic.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_quic_frame_type_blocked_stream_id,
{ "Stream ID", "quic.frame_type.blocked.stream_id",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Indicating the stream which is flow control blocked", HFILL }
},
{ &hf_quic_frame_type_sw_send_entropy,
{ "Send Entropy", "quic.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 sequence number one less than the least unacked packet", HFILL }
},
{ &hf_quic_frame_type_sw_least_unacked_delta,
{ "Least unacked delta", "quic.frame_type.sw.least_unacked_delta",
FT_UINT64, BASE_DEC, NULL, 0x0,
"A variable length sequence number delta withthe same length as the packet header's sequence number", HFILL }
},
{ &hf_quic_frame_type_stream,
{ "Stream", "quic.frame_type.stream",
FT_BOOLEAN, 8, NULL, FTFLAGS_STREAM,
@ -1501,6 +1823,11 @@ proto_register_quic(void)
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_quic_tag_cetv,
{ "Client encrypted tag-value", "quic.tag.cetv",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_quic_tag_unknown,
{ "Unknown tag", "quic.tag.unknown",
FT_BYTES, BASE_NONE, NULL, 0x0,
@ -1523,6 +1850,7 @@ proto_register_quic(void)
&ett_quic,
&ett_quic_puflags,
&ett_quic_prflags,
&ett_quic_ft,
&ett_quic_ftflags,
&ett_quic_tag_value
};