diff options
author | Alexis La Goutte <alexis.lagoutte@gmail.com> | 2017-12-24 08:29:50 +0100 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2018-01-02 05:29:39 +0000 |
commit | 0bde3e96f0c51ed141e94ae82eed24f1a38f712c (patch) | |
tree | 0518754ff0e74439b6e345eea50a0dd32ff131a5 | |
parent | af6dee35715a4079acaa7d9a413b6f7d859c8c8b (diff) |
Add ENC_VARINT_QUIC
Used to support variable length in QUIC protocol
Bug: 13881
Change-Id: Ia274b1530152376c5fb4e364fc4cf5ab246be1b3
Reviewed-on: https://code.wireshark.org/review/24990
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Craig Jackson <cejackson51@gmail.com>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r-- | epan/dissectors/file-elf.c | 6 | ||||
-rw-r--r-- | epan/dissectors/packet-mqtt.c | 6 | ||||
-rw-r--r-- | epan/dissectors/packet-netsync.c | 20 | ||||
-rw-r--r-- | epan/dissectors/packet-protobuf.c | 8 | ||||
-rw-r--r-- | epan/proto.c | 43 | ||||
-rw-r--r-- | epan/proto.h | 5 | ||||
-rw-r--r-- | epan/tvbuff.c | 43 | ||||
-rw-r--r-- | epan/tvbuff.h | 3 |
8 files changed, 93 insertions, 41 deletions
diff --git a/epan/dissectors/file-elf.c b/epan/dissectors/file-elf.c index 824c903eae..7939a185a6 100644 --- a/epan/dissectors/file-elf.c +++ b/epan/dissectors/file-elf.c @@ -908,7 +908,7 @@ dissect_eh_frame_hdr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *segment_ if (efp_length == LENGTH_ULEB128) { guint64 value; - efp_length = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &value); + efp_length = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &value, ENC_VARINT_PROTOBUF); } else if (efp_length == LENGTH_LEB128) { gint64 value; @@ -920,7 +920,7 @@ dissect_eh_frame_hdr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *segment_ if (fde_count_length == LENGTH_ULEB128) { - fde_count_length = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &fde_count); + fde_count_length = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &fde_count, ENC_VARINT_PROTOBUF); } else if (fde_count_length == LENGTH_LEB128) { gint64 value; @@ -953,7 +953,7 @@ dissect_eh_frame_hdr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *segment_ if (table_entry_length == LENGTH_ULEB128) { guint64 value; - table_entry_length = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &value); + table_entry_length = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &value, ENC_VARINT_PROTOBUF); } else if (table_entry_length == LENGTH_LEB128) { gint64 value; diff --git a/epan/dissectors/packet-mqtt.c b/epan/dissectors/packet-mqtt.c index a441066808..742ac0584a 100644 --- a/epan/dissectors/packet-mqtt.c +++ b/epan/dissectors/packet-mqtt.c @@ -588,7 +588,7 @@ static guint get_mqtt_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, guint64 msg_len; guint len_offset; - len_offset = tvb_get_varint(tvb, (offset + MQTT_HDR_SIZE_BEFORE_LEN), FT_VARINT_MAX_LEN, &msg_len); + len_offset = tvb_get_varint(tvb, (offset + MQTT_HDR_SIZE_BEFORE_LEN), FT_VARINT_MAX_LEN, &msg_len, ENC_VARINT_PROTOBUF); /* Explicitly downcast the value, because the length can never be more than 4 bytes */ return (guint)(msg_len + len_offset + MQTT_HDR_SIZE_BEFORE_LEN); @@ -753,7 +753,7 @@ static guint dissect_mqtt_properties(tvbuff_t *tvb, proto_tree *mqtt_tree, guint proto_item *ti; guint64 vbi; - const guint mqtt_prop_offset = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &vbi); + const guint mqtt_prop_offset = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &vbi, ENC_VARINT_PROTOBUF); /* Property Length field can be stored in uint32 */ const guint mqtt_prop_len = (gint)vbi; @@ -925,7 +925,7 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi conversation_add_proto_data(conv, proto_mqtt, mqtt); } - mqtt_len_offset = tvb_get_varint(tvb, (offset + MQTT_HDR_SIZE_BEFORE_LEN), FT_VARINT_MAX_LEN, &msg_len); + mqtt_len_offset = tvb_get_varint(tvb, (offset + MQTT_HDR_SIZE_BEFORE_LEN), FT_VARINT_MAX_LEN, &msg_len, ENC_VARINT_PROTOBUF); /* Explicit downcast, typically maximum length of message could be 4 bytes */ mqtt_msg_len = (gint) msg_len; diff --git a/epan/dissectors/packet-netsync.c b/epan/dissectors/packet-netsync.c index 422665a48b..23e655de18 100644 --- a/epan/dissectors/packet-netsync.c +++ b/epan/dissectors/packet-netsync.c @@ -157,7 +157,7 @@ static gint dissect_netsync_cmd_error( tvbuff_t *tvb, gint offset, proto_tree * { guint64 len = 0; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_error_msg, tvb, offset, (gint)len, ENC_ASCII|ENC_NA ); @@ -176,13 +176,13 @@ static gint dissect_netsync_cmd_hello(tvbuff_t *tvb, gint offset, proto_tree *t { guint64 len = 0; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_hello_keyname, tvb, offset, (gint)len, ENC_ASCII|ENC_NA ); offset += (gint)len; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_hello_key, tvb, offset, (gint)len, ENC_NA ); offset += (gint)len; @@ -203,7 +203,7 @@ static gint dissect_netsync_cmd_anonymous(tvbuff_t *tvb, gint offset, proto_tre offset, 1, ENC_BIG_ENDIAN ); offset += 1; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_anonymous_collection, tvb, offset, (gint)len, ENC_ASCII|ENC_NA ); offset += (gint)len; @@ -225,7 +225,7 @@ static gint dissect_netsync_cmd_auth(tvbuff_t *tvb, gint offset, proto_tree *tr offset += 1; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_auth_collection, tvb, offset, (gint)len, ENC_ASCII|ENC_NA ); offset += (gint)len; @@ -246,7 +246,7 @@ static gint dissect_netsync_cmd_auth(tvbuff_t *tvb, gint offset, proto_tree *tr offset, NETSNYC_MERKLE_HASH_LENGTH, ENC_NA ); offset += NETSNYC_MERKLE_HASH_LENGTH; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_auth_sig, tvb, offset, (gint)len, ENC_NA ); offset += (gint)len; @@ -259,7 +259,7 @@ static gint dissect_netsync_cmd_confirm(tvbuff_t *tvb, gint offset, proto_tree { guint64 len = 0; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_confirm_sig, tvb, offset, (gint)len, ENC_NA ); offset += (gint)len; @@ -344,7 +344,7 @@ static gint dissect_netsync_cmd_data(tvbuff_t *tvb, gint offset, proto_tree *tr offset, 1, ENC_BIG_ENDIAN ); offset += 1; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_data_payload, tvb, offset, (gint)len, ENC_NA ); offset += (gint)len; @@ -373,7 +373,7 @@ static gint dissect_netsync_cmd_delta(tvbuff_t *tvb, gint offset, proto_tree *t offset, 1, ENC_BIG_ENDIAN ); offset += 1; - offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len ); + offset += tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &len, ENC_VARINT_PROTOBUF ); proto_tree_add_item(tree, hf_netsync_cmd_delta_payload, tvb, offset, (gint)len, ENC_NA ); offset += (gint)len; @@ -404,7 +404,7 @@ get_netsync_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *dat /* skip version and command */ offset += 2; - size_bytes = tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &size ); + size_bytes = tvb_get_varint( tvb, offset, FT_VARINT_MAX_LEN, &size, ENC_VARINT_PROTOBUF ); /* the calculated size if for the data only, this doesn't * include the version (1 byte), command (1 byte), diff --git a/epan/dissectors/packet-protobuf.c b/epan/dissectors/packet-protobuf.c index 6a4e27de23..ee18f66f28 100644 --- a/epan/dissectors/packet-protobuf.c +++ b/epan/dissectors/packet-protobuf.c @@ -225,7 +225,7 @@ dissect_packed_repeated_field_values(proto_tree *value_tree, tvbuff_t *tvb, guin /* add varints into the packed-repeated subtree */ while (offset < max_offset) { - sub_value_length = tvb_get_varint(tvb, offset, max_offset - offset, &sub_value); + sub_value_length = tvb_get_varint(tvb, offset, max_offset - offset, &sub_value, ENC_VARINT_PROTOBUF); if (sub_value_length == 0) { /* not a valid packed repeated field */ return 0; @@ -408,7 +408,7 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in field_tree = proto_tree_add_subtree(protobuf_tree, tvb, *offset, 0, ett_protobuf_field, &ti_field, "Field"); /* parsing Tag */ - tag_length = tvb_get_varint(tvb, *offset, maxlen, &tag_value); + tag_length = tvb_get_varint(tvb, *offset, maxlen, &tag_value, ENC_VARINT_PROTOBUF); if (tag_length == 0) { /* not found a valid varint */ expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_tag); @@ -426,7 +426,7 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in { case PROTOBUF_WIRETYPE_VARINT: /* varint, format: tag + varint */ /* get value length and real value */ - value_length = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64); + value_length = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64, ENC_VARINT_PROTOBUF); if (value_length == 0) { expert_add_info(pinfo, ti_wire, &ei_protobuf_failed_parse_field); return FALSE; @@ -446,7 +446,7 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in case PROTOBUF_WIRETYPE_LENGTH_DELIMITED: /* Length-delimited, format: tag + length(varint) + bytes_value */ /* this time value_uint64 is the length of following value bytes */ - value_length_size = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64); + value_length_size = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64, ENC_VARINT_PROTOBUF); if (value_length_size == 0) { expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_length_delimited_field); return FALSE; diff --git a/epan/proto.c b/epan/proto.c index ac653c23c8..df06450336 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -2054,7 +2054,7 @@ test_length(header_field_info *hfinfo, tvbuff_t *tvb, return; if ((hfinfo->type == FT_STRINGZ) || - ((encoding & ENC_VARINT_PROTOBUF) && (IS_FT_UINT(hfinfo->type) || IS_FT_UINT(hfinfo->type)))) { + ((encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) && (IS_FT_UINT(hfinfo->type) || IS_FT_UINT(hfinfo->type)))) { /* If we're fetching until the end of the TVB, only validate * that the offset is within range. */ @@ -2121,9 +2121,12 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, case FT_UINT24: case FT_UINT32: if (encoding & ENC_VARINT_PROTOBUF) { - new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64); + new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding); new_fi->flags |= FI_VARINT; value = (guint32)value64; + } else if (encoding & ENC_VARINT_QUIC) { + new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding); + value = (guint32)value64; } else { /* * Map all non-zero values to little-endian for @@ -2143,8 +2146,10 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, case FT_UINT64: if (encoding & ENC_VARINT_PROTOBUF) { - new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64); + new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding); new_fi->flags |= FI_VARINT; + } else if (encoding & ENC_VARINT_QUIC) { + new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding); } else { /* * Map all other non-zero values to little-endian for @@ -2618,9 +2623,9 @@ proto_tree_add_item_ret_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, } /* I believe it's ok if this is called with a NULL tree */ /* XXX - modify if we ever support EBCDIC FT_CHAR */ - if (encoding & ENC_VARINT_PROTOBUF) { + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) { guint64 temp64; - tvb_get_varint(tvb, start, length, &temp64); + tvb_get_varint(tvb, start, length, &temp64, encoding); value = (guint32)temp64; } else { value = get_uint_value(tree, tvb, start, length, encoding); @@ -2904,8 +2909,8 @@ proto_tree_add_item_ret_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, REPORT_DISSECTOR_BUG("wrong encoding"); } /* I believe it's ok if this is called with a NULL tree */ - if (encoding & ENC_VARINT_PROTOBUF) { - tvb_get_varint(tvb, start, length, &value); + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) { + tvb_get_varint(tvb, start, length, &value, encoding); } else { value = get_uint64_value(tree, tvb, start, length, encoding); } @@ -2962,7 +2967,7 @@ proto_tree_add_item_ret_varint(proto_tree *tree, int hfindex, tvbuff_t *tvb, REPORT_DISSECTOR_BUG("wrong encoding"); } - length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value); + length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value, encoding); if (retval) { *retval = value; @@ -5174,7 +5179,7 @@ get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint * of the string", and if the tvbuff if short, we just * throw an exception. * - * For ENC_VARINT_PROTOBUF, it means "find the end of the string", + * For ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC, it means "find the end of the string", * and if the tvbuff if short, we just throw an exception. * * It's not valid for any other type of field. For those @@ -5192,6 +5197,22 @@ get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint */ *item_length = *length; return; + } else if (encoding & ENC_VARINT_QUIC) { + switch (tvb_get_guint8(tvb, start) >> 6) + { + case 0: /* 0b00 => 1 byte length (6 bits Usable) */ + *item_length = 1; + break; + case 1: /* 0b01 => 2 bytes length (14 bits Usable) */ + *item_length = 2; + break; + case 2: /* 0b10 => 4 bytes length (30 bits Usable) */ + *item_length = 4; + break; + case 3: /* 0b11 => 8 bytes length (62 bits Usable) */ + *item_length = 8; + break; + } } } @@ -5305,7 +5326,7 @@ get_full_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, case FT_INT48: case FT_INT56: case FT_INT64: - if (encoding & ENC_VARINT_PROTOBUF) { + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) { if (length < -1) { report_type_length_mismatch(NULL, "a FT_[U]INT", length, TRUE); } @@ -5313,7 +5334,7 @@ get_full_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, guint64 dummy; /* This can throw an exception */ /* XXX - do this without fetching the varint? */ - length = tvb_get_varint(tvb, start, FT_VARINT_MAX_LEN, &dummy); + length = tvb_get_varint(tvb, start, FT_VARINT_MAX_LEN, &dummy, encoding); if (length == 0) { THROW(ReportedBoundsError); } diff --git a/epan/proto.h b/epan/proto.h index ec688f2aaa..f732f45d64 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -534,6 +534,11 @@ WS_DLL_PUBLIC WS_NORETURN void proto_report_dissector_bug(const char *message); * https://developers.google.cn/protocol-buffers/docs/encoding */ #define ENC_VARINT_PROTOBUF 0x00000002 +/* + * Decodes a variable-length integer used in QUIC protocol + * See https://tools.ietf.org/html/draft-ietf-quic-transport-08#section-8.1 + */ +#define ENC_VARINT_QUIC 0x00000004 /* For cases where a string encoding contains hex, bit-or one or more * of these for the allowed separator(s), as well as with ENC_STR_HEX. diff --git a/epan/tvbuff.c b/epan/tvbuff.c index edd0f049a4..98e4e71748 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -3649,20 +3649,45 @@ tvb_get_ds_tvb(tvbuff_t *tvb) } guint -tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value) +tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value, const guint encoding) { - guint i; - guint64 b; /* current byte */ *value = 0; - for (i = 0; ((i < FT_VARINT_MAX_LEN) && (i < maxlen)); ++i) { - b = tvb_get_guint8(tvb, offset++); - *value |= ((b & 0x7F) << (i * 7)); /* add lower 7 bits to val */ + if (encoding & ENC_VARINT_PROTOBUF) { + guint i; + guint64 b; /* current byte */ - if (b < 0x80) { - /* end successfully becauseof last byte's msb(most significant bit) is zero */ - return i + 1; + for (i = 0; ((i < FT_VARINT_MAX_LEN) && (i < maxlen)); ++i) { + b = tvb_get_guint8(tvb, offset++); + *value |= ((b & 0x7F) << (i * 7)); /* add lower 7 bits to val */ + + if (b < 0x80) { + /* end successfully becauseof last byte's msb(most significant bit) is zero */ + return i + 1; + } } + } else if (encoding & ENC_VARINT_QUIC) { + + /* calculate variable length */ + *value = tvb_get_guint8(tvb, offset); + switch((*value) >> 6) { + case 0: /* 0b00 => 1 byte length (6 bits Usable) */ + (*value) &= 0x3F; + return 1; + case 1: /* 0b01 => 2 bytes length (14 bits Usable) */ + *value = tvb_get_ntohs(tvb, offset) & 0x3FFF; + return 2; + case 2: /* 0b10 => 4 bytes length (30 bits Usable) */ + *value = tvb_get_ntohl(tvb, offset) & 0x3FFFFFFF; + return 4; + case 3: /* 0b11 => 8 bytes length (62 bits Usable) */ + *value = tvb_get_ntoh64(tvb, offset) & G_GUINT64_CONSTANT(0x3FFFFFFFFFFFFFFF); + return 8; + default: /* No Possible */ + g_assert_not_reached(); + break; + } + } return 0; /* 10 bytes scanned, but no bytes' msb is zero */ diff --git a/epan/tvbuff.h b/epan/tvbuff.h index 8e9057e92f..52fdb3e862 100644 --- a/epan/tvbuff.h +++ b/epan/tvbuff.h @@ -896,9 +896,10 @@ extern tvbuff_t* base64_to_tvb(tvbuff_t *parent, const char *base64); * @param offset The offset in tvb from which we begin trying to extract integer. * @param maxlen The maximum distance from offset that we may try to extract integer * @param value if parsing succeeds, parsed varint will store here. + * @param encoding The ENC_* that defines the format (e.g., ENC_VARINT_PROTOBUF, ENC_VARINT_QUIC) * @return the length of this varint in tvb. 0 means parsing failed. */ -WS_DLL_PUBLIC guint tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value); +WS_DLL_PUBLIC guint tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value, const guint encoding); /************** END OF ACCESSORS ****************/ |