From 5bb756e203539c7fd3bb6c16dd845e42a347a982 Mon Sep 17 00:00:00 2001 From: Brian Sipos Date: Sun, 16 Oct 2022 17:30:19 -0400 Subject: [PATCH] epan: centralize SDNV processing along other similar varint types This avoids having general-purpose decoding happening in non-DLL-exported functions defined in a dissector for #18478, and removes unused functions and avoids duplicate decoding. This also removes unnecessary early exit conditions for #18145. Unit test cases for varint decoding are added to verify this. --- epan/dissectors/packet-bpv6.c | 243 +++------------------------- epan/dissectors/packet-bpv6.h | 27 ---- epan/dissectors/packet-ltp.c | 279 ++++++++++----------------------- epan/dissectors/packet-tcpcl.c | 78 ++++----- epan/introspection-enums.c | 1 + epan/proto.c | 12 +- epan/proto.h | 7 +- epan/tvbtest.c | 92 +++++++++++ epan/tvbuff.c | 23 +++ epan/tvbuff.h | 2 +- 10 files changed, 274 insertions(+), 490 deletions(-) diff --git a/epan/dissectors/packet-bpv6.c b/epan/dissectors/packet-bpv6.c index a4e0f31cfd..ebcbc63002 100644 --- a/epan/dissectors/packet-bpv6.c +++ b/epan/dissectors/packet-bpv6.c @@ -56,8 +56,16 @@ static int dissect_admin_record(proto_tree *primary_tree, tvbuff_t *tvb, packet_ extern void dissect_amp_as_subtree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset); + +static int evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount); + +/// Return an error_info index if not valid +static int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error); + static int add_sdnv_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_sdnv_time); +static gint64 +evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount); static int proto_bundle = -1; static dissector_handle_t bundle_handle = NULL; @@ -1834,48 +1842,24 @@ display_extension_block(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int } /*3rd arg is number of bytes in field (returned)*/ -int +static int evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount) { - int value = 0; - guint8 curbyte; + guint64 value = 0; + *bytecount = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &value, ENC_VARINT_SDNV); - *bytecount = 0; - - if (!tvb_bytes_exist(tvb, offset, 1)) { + if (*bytecount == 0) { return -1; } - - /* - * Get 1st byte and continue to get them while high-order bit is 1 - */ - - while ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK) { - if (*bytecount >= (int) sizeof(int)) { - *bytecount = 0; - return -1; - } - value = value << 7; - value |= (curbyte & SDNV_MASK); - ++offset; - ++*bytecount; - - if (!tvb_bytes_exist(tvb, offset, 1)) { - return -1; - } + if (value > G_MAXINT) { + ws_warning("evaluate_sdnv decoded a value too large to fit in an int, truncating"); + return G_MAXINT; } - - /* - * Add in the byte whose high-order bit is 0 (last one) - */ - - value = value << 7; - value |= (curbyte & SDNV_MASK); - ++*bytecount; - return value; + return (int)value; } -int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error) { +static int +evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error) { int value = evaluate_sdnv(tvb, offset, bytecount); *error = (value < 0) ? &ei_bundle_sdnv_length : NULL; return value; @@ -1883,199 +1867,18 @@ int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **e /* Special Function to evaluate 64 bit SDNVs */ /*3rd arg is number of bytes in field (returned)*/ -gint64 +static gint64 evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount) { - gint64 value = 0; - guint8 curbyte; + guint64 val = 0; + *bytecount = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &val, ENC_VARINT_SDNV); - *bytecount = 0; - - if (!tvb_bytes_exist(tvb, offset, 1)) { + if (*bytecount == 0) { return -1; } - - /* - * Get 1st byte and continue to get them while high-order bit is 1 - */ - - while ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK) { - if (*bytecount >= (int) sizeof(gint64)) { - *bytecount = 0; - return -1; - } - value = value << 7; - value |= (curbyte & SDNV_MASK); - ++offset; - ++*bytecount; - - if (!tvb_bytes_exist(tvb, offset, 1)) { - return -1; - } - } - - /* - * Add in the byte whose high-order bit is 0 (last one) - */ - - value = value << 7; - value |= (curbyte & SDNV_MASK); - ++*bytecount; - return value; + return val & G_MAXINT64; } -/* Special Function to evaluate 32 bit unsigned SDNVs with error indication - * bytecount returns the number bytes consumed - * value returns the actual value - * - * result is TRUE (1) on success else FALSE (0) - */ -int -evaluate_sdnv32(tvbuff_t *tvb, int offset, int *bytecount, guint32 *value) -{ - int result; - int num_bits_in_value; - guint8 curbyte; - guint8 high_bit; - - *value = 0; - *bytecount = 0; - - result = FALSE; - num_bits_in_value = 0; - - if (tvb_bytes_exist(tvb, offset, 1)) { - /* - * Get 1st byte and continue to get them while high-order bit is 1 - */ - result = TRUE; - - /* Determine number of non-zero bits in first SDNV byte */ - /* technically 0x80 0x80 ... 0x81 is a valid inefficient representation of "1" */ - while ((0 == num_bits_in_value) && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) { - if (!tvb_bytes_exist(tvb, offset, 1)) { - result = FALSE; - break; - } else { - num_bits_in_value = 7; - high_bit = 0x40; - while ((num_bits_in_value > 0) && (!(curbyte & high_bit))) { - --num_bits_in_value; - high_bit = high_bit >> 1; - } - - *value |= (curbyte & SDNV_MASK); - ++offset; - ++*bytecount; - } - } - - - /* Process additional bytes that have the high order bit set */ - while (result && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) { - /* Since the high order bit is set there must be 7 low order bits after this byte */ - if (!tvb_bytes_exist(tvb, offset, 1) || ((num_bits_in_value + 7) > (32 - 7))) { - result = FALSE; - } else { - *value = *value << 7; - *value |= (curbyte & SDNV_MASK); - ++offset; - ++*bytecount; - } - } - - if (result) { - /* - * Add in the byte whose high-order bit is 0 (last one) - */ - *value = *value << 7; - *value |= (curbyte & SDNV_MASK); - ++*bytecount; - } else { - *bytecount = 0; - } - } - - return result; -} - - -/* Special Function to evaluate 64 bit unsigned SDNVs with error indication - * bytecount returns the number bytes consumed or zero on error - * value returns the actual value - * - * result is TRUE (1) on success else FALSE (0) - */ -int -evaluate_sdnv64(tvbuff_t *tvb, int offset, int *bytecount, guint64 *value) -{ - int result; - int num_bits_in_value; - guint8 curbyte; - guint8 high_bit; - - *value = 0; - *bytecount = 0; - - result = FALSE; - num_bits_in_value = 0; - - if (tvb_bytes_exist(tvb, offset, 1)) { - /* - * Get 1st byte and continue to get them while high-order bit is 1 - */ - result = TRUE; - - /* Determine number of non-zero bits in first SDNV byte */ - /* technically 0x80 0x80 ... 0x81 is a valid inefficient representation of "1" */ - while ((0 == num_bits_in_value) && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) { - if (!tvb_bytes_exist(tvb, offset, 1)) { - result = FALSE; - break; - } else { - num_bits_in_value = 7; - high_bit = 0x40; - while ((num_bits_in_value > 0) && (!(curbyte & high_bit))) { - --num_bits_in_value; - high_bit = high_bit >> 1; - } - - *value |= (curbyte & SDNV_MASK); - ++offset; - ++*bytecount; - } - } - - - /* Process additional bytes that have the high order bit set */ - while (result && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) { - /* Since the high order bit is set there must be 7 low order bits after this byte */ - if (!tvb_bytes_exist(tvb, offset, 1) || ((num_bits_in_value + 7) > (64 - 7))) { - result = FALSE; - } else { - *value = *value << 7; - *value |= (curbyte & SDNV_MASK); - ++offset; - ++*bytecount; - } - } - - if (result) { - /* - * Add in the byte whose high-order bit is 0 (last one) - */ - *value = *value << 7; - *value |= (curbyte & SDNV_MASK); - ++*bytecount; - } else { - *bytecount = 0; - } - } - - return result; -} - - static int dissect_bpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { diff --git a/epan/dissectors/packet-bpv6.h b/epan/dissectors/packet-bpv6.h index 03d2fbfa00..37b4d1fdf8 100644 --- a/epan/dissectors/packet-bpv6.h +++ b/epan/dissectors/packet-bpv6.h @@ -112,33 +112,6 @@ extern "C" { #define DTN_SCHEME_STR "dtn" #define IPN_SCHEME_STR "ipn" -/* - * SDNV has a zero in high-order bit position of last byte. The high-order - * bit of all preceding bytes is set to one. This returns the numeric value - * in an integer and sets the value of the second argument to the number of - * bytes used to code the SDNV. A -1 is returned if the evaluation fails - * (value exceeds maximum for signed integer). 0 is an acceptable value. - */ -#define SDNV_MASK 0x7f - -int evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount); - -/// Return an error_info index if not valid -int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error); - -gint64 evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount); - - -/* Special Functions to evaluate unsigned SDNVs with error indication - * bytecount returns the number bytes consumed - * value returns the actual value - * - * result is TRUE (1) on success else FALSE (0) - */ -int evaluate_sdnv32(tvbuff_t *tvb, int offset, int *bytecount, guint32 *value); - -int evaluate_sdnv64(tvbuff_t *tvb, int offset, int *bytecount, guint64 *value); - #ifdef __cplusplus } #endif diff --git a/epan/dissectors/packet-ltp.c b/epan/dissectors/packet-ltp.c index e2704bb7f7..c58a607db9 100644 --- a/epan/dissectors/packet-ltp.c +++ b/epan/dissectors/packet-ltp.c @@ -44,14 +44,10 @@ #include #include -#include "packet-bpv6.h" - void proto_register_ltp(void); void proto_reg_handoff_ltp(void); #define LTP_MIN_DATA_BUFFER 5 -#define LTP_MAX_HDR_EXTN 16 -#define LTP_MAX_TRL_EXTN 16 /// Unique session identifier typedef struct { @@ -333,7 +329,6 @@ static int hf_ltp_fragment_count = -1; static int hf_ltp_reassembled_in = -1; static int hf_ltp_reassembled_length = -1; -static expert_field ei_ltp_neg_reception_claim_count = EI_INIT; static expert_field ei_ltp_mal_reception_claim = EI_INIT; static expert_field ei_ltp_sdnv_length = EI_INIT; static expert_field ei_ltp_sno_larger_than_ccsds = EI_INIT; @@ -445,24 +440,16 @@ static const fragment_items ltp_frag_items = { "LTP fragments" }; -static int -add_sdnv64_to_tree(proto_tree *tree, tvbuff_t *tvb, packet_info* pinfo, int offset, int hf_sdnv, guint64 *value, proto_item** item_ret) +static proto_item * +add_sdnv64_to_tree(proto_tree *tree, tvbuff_t *tvb, packet_info* pinfo, int offset, int hf_sdnv, guint64 *retval, gint *lenretval) { - int sdnv_status; - int sdnv_length; - guint64 sdnv_value; - proto_item* ti; + proto_item *ti; + ti = proto_tree_add_item_ret_varint(tree, hf_sdnv, tvb, offset, -1, ENC_VARINT_SDNV, retval, lenretval); - sdnv_status = evaluate_sdnv64(tvb, offset, &sdnv_length, &sdnv_value); - ti = proto_tree_add_uint64(tree, hf_sdnv, tvb, offset, sdnv_length, sdnv_value); - - *value = sdnv_value; - if (NULL != *item_ret) *item_ret = ti; - - if (!sdnv_status) { + if (*lenretval <= 0) { expert_add_info(pinfo, ti, &ei_ltp_sdnv_length); } - return sdnv_length; + return ti; } /// Summary of a data segment tree item @@ -519,7 +506,6 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int unsigned segment_size = 0; int sdnv_length; - int sdnv_status; proto_tree *ltp_data_tree; proto_item *ti; @@ -531,22 +517,14 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int /* Create a subtree for data segment and add the other fields under it */ ltp_data_tree = proto_tree_add_subtree(ltp_tree, tvb, frame_offset, tvb_captured_length_remaining(tvb, frame_offset), ett_data_segm, NULL, "Data Segment"); - /* Client ID - 0 = Bundle Protocol, 1 = CCSDS LTP Service Data Aggregation */ - sdnv_status = evaluate_sdnv64(tvb, frame_offset, &sdnv_length, &client_id); - ti = proto_tree_add_uint64_format_value(ltp_data_tree, hf_ltp_data_clid, tvb, frame_offset, sdnv_length, client_id, - "%" PRIu64 " (%s)", client_id, - val64_to_str_const(client_id, client_service_id_info, "Invalid")); - if (!sdnv_status) { - expert_add_info(pinfo, ti, &ei_ltp_sdnv_length); - return 0; - } + add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_clid, &client_id, &sdnv_length); frame_offset += sdnv_length; segment_size += sdnv_length; - /* data segment offset */ - if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_offset, &data_offset, &ti)) > 0) { + add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_offset, &data_offset, &sdnv_length); + if (sdnv_length > 0) { frame_offset += sdnv_length; segment_size += sdnv_length; } else { @@ -554,7 +532,8 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int } /* data segment length */ - if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_length, &data_length, &ti)) > 0) { + add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_length, &data_length, &sdnv_length); + if (sdnv_length > 0) { frame_offset += sdnv_length; segment_size += sdnv_length; @@ -607,7 +586,8 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int if (ltp_type != 0 && ltp_type < 4) { /* checkpoint serial number - 32 bits per CCSDS */ - if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_chkp, &chkp_sno, &ti)) > 0) { + ti = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_chkp, &chkp_sno, &sdnv_length); + if (sdnv_length > 0) { frame_offset += sdnv_length; segment_size += sdnv_length; @@ -626,7 +606,8 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int } /* report serial number - 32 bits per CCSDS */ - if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_rpt, &rpt_sno, &ti)) > 0) { + ti = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_rpt, &rpt_sno, &sdnv_length); + if (sdnv_length > 0) { frame_offset += sdnv_length; segment_size += sdnv_length; @@ -734,15 +715,7 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int tvbuff_t *datatvb; if (client_id == 2) { - sdnv_status = evaluate_sdnv64(new_tvb, parse_offset, &sdnv_length, &sda_client_id); - ti = proto_tree_add_uint64_format_value(root_tree, hf_ltp_data_sda_clid, new_tvb, parse_offset, sdnv_length, sda_client_id, - "%" G_GINT64_MODIFIER "u (%s)", sda_client_id, val64_to_str_const(sda_client_id, client_service_id_info, "Invalid")); - - if (!sdnv_status) { - expert_add_info(pinfo, ti, &ei_ltp_sdnv_length); - return 0; - } - + add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset+parse_offset, hf_ltp_data_sda_clid, &sda_client_id, &sdnv_length); parse_offset += sdnv_length; if (parse_offset == parse_length) { col_set_str(pinfo->cinfo, COL_INFO, "CCSDS LTP SDA Protocol Error"); @@ -831,7 +804,7 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, gint64 chkp_sno; guint64 upper_bound; guint64 lower_bound; - int rcpt_clm_cnt; + guint64 rcpt_clm_cnt; guint64 offset; guint64 length; guint64 clm_fst, clm_lst; @@ -847,9 +820,9 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, int segment_offset = 0; int gap_count = 0; guint64 gap_total = 0; - int i; proto_item *ltp_rpt_item; + proto_item *ltp_rpt_clm_cnt; proto_item *ltp_rpt_clm_item; proto_item *item_rpt_sno, *item_chkp_sno; @@ -860,8 +833,7 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, ltp_rpt_tree = proto_tree_add_subtree(ltp_tree, tvb, frame_offset, -1, ett_rpt_segm, <p_rpt_item, "Report Segment"); /* Extract the report segment info */ - rpt_sno = evaluate_sdnv_64(tvb, frame_offset, &rpt_sno_size); - item_rpt_sno = proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_sno, tvb, frame_offset + segment_offset, rpt_sno_size, (guint64)rpt_sno); + item_rpt_sno = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_sno, &rpt_sno, &rpt_sno_size); segment_offset += rpt_sno_size; if (ltp_analyze_sequence && session) { @@ -871,8 +843,7 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, ltp_ref_use(session->rpt_datas, rpt_sno, pinfo, tree_rpt_sno, hf_ltp_rpt_sno_data, -1); } - chkp_sno = evaluate_sdnv_64(tvb, frame_offset + segment_offset, &chkp_sno_size); - item_chkp_sno = proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_chkp, tvb, frame_offset + segment_offset, chkp_sno_size, (guint64)chkp_sno); + item_chkp_sno = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_chkp, &chkp_sno, &chkp_sno_size); segment_offset += chkp_sno_size; if (ltp_analyze_sequence && session) { @@ -886,12 +857,10 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, } } - upper_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &upper_bound_size); - proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_ub, tvb, frame_offset + segment_offset, upper_bound_size, upper_bound); + add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_ub, &upper_bound, &upper_bound_size); segment_offset += upper_bound_size; - lower_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &lower_bound_size); - proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_lb, tvb, frame_offset + segment_offset, lower_bound_size, lower_bound); + add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_lb, &lower_bound, &lower_bound_size); segment_offset += lower_bound_size; PROTO_ITEM_SET_GENERATED( @@ -942,42 +911,34 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree, } tap->corr_orig = newdata; - rcpt_clm_cnt = evaluate_sdnv(tvb, frame_offset + segment_offset, &rcpt_clm_cnt_size); - if (rcpt_clm_cnt < 0){ - proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset); - expert_add_info_format(pinfo, ltp_tree, &ei_ltp_neg_reception_claim_count, - "Negative reception claim count: %d", rcpt_clm_cnt); - return 0; - } + ltp_rpt_clm_cnt = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_clm_cnt, &rcpt_clm_cnt, &rcpt_clm_cnt_size); + segment_offset += rcpt_clm_cnt_size; /* Each reception claim is at least 2 bytes, so if the count is larger than the * max number of claims we can possibly squeeze into the remaining tvbuff, then * the packet is malformed. */ - if (rcpt_clm_cnt > tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2) { - proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset); - expert_add_info_format(pinfo, ltp_tree, &ei_ltp_mal_reception_claim, - "Reception claim count impossibly large: %d > %d", rcpt_clm_cnt, + if (rcpt_clm_cnt > (guint64)tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2) { + expert_add_info_format(pinfo, ltp_rpt_clm_cnt, &ei_ltp_mal_reception_claim, + "Reception claim count impossibly large: %" G_GINT64_MODIFIER "d > %d", rcpt_clm_cnt, tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2); return 0; } - proto_tree_add_uint(ltp_rpt_tree, hf_ltp_rpt_clm_cnt, tvb, frame_offset + segment_offset, rcpt_clm_cnt_size, rcpt_clm_cnt); - segment_offset += rcpt_clm_cnt_size; clm_lst = lower_bound - 1; /* There can be multiple reception claims in the same report segment */ - for(i = 0; i tvb_captured_length(tvb)){ - return 0; - } - - /* Creating tree for the report ack segment */ - ltp_rpt_ack_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, segment_offset, - ett_rpt_ack_segm, NULL, "Report Ack Segment"); - - item_rpt_sno = proto_tree_add_uint64(ltp_rpt_ack_tree, hf_ltp_rpt_ack_sno, tvb, frame_offset,rpt_sno_size, (guint64)rpt_sno); + proto_item_set_end(ltp_rpt_ack_item, tvb, frame_offset + segment_offset); if (ltp_analyze_sequence && session) { @@ -1079,97 +1035,60 @@ dissect_cancel_segment(proto_tree * ltp_tree, tvbuff_t *tvb, int frame_offset, l static int -dissect_header_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int hdr_extn_cnt){ - guint8 extn_type[LTP_MAX_HDR_EXTN]; - gint64 length[LTP_MAX_HDR_EXTN]; +dissect_header_extn(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset,int hdr_extn_cnt){ + gint64 length; + int length_size; - int length_size[LTP_MAX_HDR_EXTN]; - - int i; int extn_offset = 0; + proto_item *ltp_hdr_extn_item; proto_tree *ltp_hdr_extn_tree; - /* There can be more than one header extensions */ - for(i = 0; i < hdr_extn_cnt; i++){ - extn_type[i] = tvb_get_guint8(tvb,frame_offset); - extn_offset++; + ltp_hdr_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1, ett_hdr_extn, <p_hdr_extn_item, "Header Extension"); - length[i] = evaluate_sdnv_64(tvb,frame_offset+1,&length_size[i]); - if((guint64)(frame_offset + extn_offset + length_size[i] + length[i]) >= (guint64)tvb_captured_length(tvb)){ - return 0; - } - - extn_offset += length_size[i]; + for(int ix = 0; ix < hdr_extn_cnt; ix++){ /* From RFC-5326, the total length of the Header Extension Tree will be length of the following: a) Extension type length (1 byte) b) The length of the 'length' field (as defined by the SDNV which handles dynamic size) c) The length of the value field which is the decoded length */ - extn_offset += (int)length[i]; + proto_tree_add_item(ltp_hdr_extn_tree, hf_ltp_hdr_extn_tag, tvb, frame_offset + extn_offset, 1, ENC_NA); + extn_offset += 1; + + add_sdnv64_to_tree(ltp_hdr_extn_tree, tvb, pinfo, frame_offset + extn_offset, hf_ltp_hdr_extn_len, &length, &length_size); + extn_offset += length_size; + + proto_tree_add_item(ltp_hdr_extn_tree, hf_ltp_hdr_extn_val, tvb, frame_offset + extn_offset, (int)length, ENC_NA); + extn_offset += (int)length; } - ltp_hdr_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, extn_offset, ett_hdr_extn, NULL, "Header Extension"); - for(i = 0; i < hdr_extn_cnt; i++){ - proto_tree_add_uint_format_value(ltp_hdr_extn_tree, hf_ltp_hdr_extn_tag, tvb, frame_offset, 1, extn_type[i], "%x (%s)", extn_type[i], val_to_str_const(extn_type[i],extn_tag_codes,"Unassigned/Reserved")); - frame_offset += 1; - - proto_tree_add_uint64_format(ltp_hdr_extn_tree, hf_ltp_hdr_extn_len, tvb, frame_offset, length_size[i],length[i], "Length [%d]: %"PRId64,i+1,length[i]); - frame_offset += length_size[i]; - - proto_tree_add_item (ltp_hdr_extn_tree, hf_ltp_hdr_extn_val, tvb, frame_offset, (int)length[i], ENC_NA); - frame_offset += (int)length[i]; - } + proto_item_set_end(ltp_hdr_extn_item, tvb, frame_offset + extn_offset); return extn_offset; } static int -dissect_trailer_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int trl_extn_cnt){ - guint8 extn_type[LTP_MAX_TRL_EXTN]; - gint64 length[LTP_MAX_TRL_EXTN]; +dissect_trailer_extn(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset,int trl_extn_cnt){ + gint64 length; + int length_size; - int length_size[LTP_MAX_TRL_EXTN]; - - int i; int extn_offset = 0; + proto_item *ltp_trl_extn_item; proto_tree *ltp_trl_extn_tree; - DISSECTOR_ASSERT(trl_extn_cnt < LTP_MAX_TRL_EXTN); + ltp_trl_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1, ett_trl_extn, <p_trl_extn_item, "Trailer Extension"); - for(i = 0; i < trl_extn_cnt; i++){ - extn_type[i] = tvb_get_guint8(tvb,frame_offset); - extn_offset++; - - if((unsigned)(frame_offset + extn_offset) >= tvb_captured_length(tvb)){ - return 0; - } - - length[i] = evaluate_sdnv_64(tvb,frame_offset+1,&length_size[i]); - extn_offset += length_size[i]; - - if((guint64)(frame_offset + extn_offset + length_size[i] + length[i]) >= tvb_captured_length(tvb)){ - return 0; - } - - /* From RFC-5326, the total length of the Trailer Extension Tree will be length of the following: - a) Extension type length (1 byte) - b) The length of the 'length' field (as defined by the SDNV which handles dynamic size) - c) The length of the value field which is the decoded length */ - extn_offset += (int)length[i]; - } - - ltp_trl_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, extn_offset, ett_trl_extn, NULL, "Trailer Extension"); - - for(i = 0; i < trl_extn_cnt; i++){ - proto_tree_add_uint_format_value(ltp_trl_extn_tree, hf_ltp_trl_extn_tag, tvb, frame_offset, 1, extn_type[i], "%x (%s)", extn_type[i], val_to_str_const(extn_type[i],extn_tag_codes,"Unassigned/Reserved")); + for(int ix = 0; ix < trl_extn_cnt; ix++){ + proto_tree_add_item(ltp_trl_extn_tree, hf_ltp_trl_extn_tag, tvb, frame_offset + extn_offset, 1, ENC_NA); frame_offset += 1; - proto_tree_add_uint64_format(ltp_trl_extn_tree, hf_ltp_trl_extn_len, tvb, frame_offset, length_size[i], length[i], "Length [%d]: %"PRId64,i+1,length[i]); - frame_offset += length_size[i]; + add_sdnv64_to_tree(ltp_trl_extn_tree, tvb, pinfo, frame_offset + extn_offset, hf_ltp_hdr_extn_len, &length, &length_size); + frame_offset += length_size; - proto_tree_add_item (ltp_trl_extn_tree, hf_ltp_trl_extn_val, tvb, frame_offset, (int)length[i], ENC_NA); - frame_offset += (int)length[i]; + proto_tree_add_item(ltp_trl_extn_tree, hf_ltp_trl_extn_val, tvb, frame_offset + extn_offset, (int)length, ENC_NA); + frame_offset += (int)length; } + + proto_item_set_end(ltp_trl_extn_item, tvb, frame_offset + extn_offset); return extn_offset; } @@ -1224,21 +1143,11 @@ dissect_ltp_segment(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t ltp_session_tree = proto_tree_add_subtree(ltp_header_tree, tvb, frame_offset, 0, ett_hdr_session, NULL, "Session ID"); ltp_session_item = proto_tree_get_parent(ltp_session_tree); - sess_id.orig_eng_id = evaluate_sdnv_64(tvb,frame_offset,&engine_id_size); - proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_orig,tvb,frame_offset,engine_id_size,sess_id.orig_eng_id); + add_sdnv64_to_tree(ltp_session_tree, tvb, pinfo, frame_offset, hf_ltp_session_orig, &sess_id.orig_eng_id, &engine_id_size); frame_offset += engine_id_size; - if((unsigned)frame_offset >= tvb_captured_length(tvb)){ - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } - sess_id.sess_num = evaluate_sdnv_64(tvb,frame_offset,&session_num_size); - proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_no, tvb, frame_offset,session_num_size,sess_id.sess_num); + add_sdnv64_to_tree(ltp_session_tree, tvb, pinfo, frame_offset, hf_ltp_session_no, &sess_id.sess_num, &session_num_size); frame_offset += session_num_size; - if((unsigned)frame_offset >= tvb_captured_length(tvb)){ - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } proto_item_set_end(ltp_session_item, tvb, frame_offset); tap->sess_id = sess_id; @@ -1303,33 +1212,12 @@ dissect_ltp_segment(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t col_add_fstr(pinfo->cinfo, COL_INFO, "Session %s, %s", sess_name, val_to_str_const(ltp_type,ltp_type_col_info,"Protocol Error")); /* Check if there are any header extensions */ - if(hdr_extn_cnt > 0){ - int hdr_extn_offset; - - if((unsigned)frame_offset >= tvb_captured_length(tvb)){ - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } - - hdr_extn_offset = dissect_header_extn(ltp_tree, tvb, frame_offset,hdr_extn_cnt); - if(hdr_extn_offset == 0){ - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } + if(hdr_extn_cnt > 0) + { + int hdr_extn_offset = dissect_header_extn(ltp_tree, tvb, pinfo, frame_offset,hdr_extn_cnt); frame_offset += hdr_extn_offset; } - if((unsigned)frame_offset > tvb_captured_length(tvb)){ - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } - else if((unsigned)frame_offset == tvb_captured_length(tvb)){ - if(ltp_type != 13 && ltp_type != 15){ - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } - } - /* Call sub routines to handle the segment content*/ if((ltp_type >= 0) && (ltp_type < 8)){ segment_offset = dissect_data_segment(ltp_tree,tvb,pinfo,frame_offset,ltp_type, &data_len, tap); @@ -1366,17 +1254,9 @@ dissect_ltp_segment(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t /* Check to see if there are any trailer extensions */ const int trl_start = frame_offset; - int trl_length = 0; - if(trl_extn_cnt > 0){ - if((unsigned)frame_offset >= tvb_captured_length(tvb)){ - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } - trl_length = dissect_trailer_extn(ltp_tree, tvb, frame_offset,trl_extn_cnt); - if(0 == trl_length) { - col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error"); - return 0; - } + if(trl_extn_cnt > 0) + { + int trl_length = dissect_trailer_extn(ltp_tree, tvb, pinfo, frame_offset,trl_extn_cnt); frame_offset += trl_length; } @@ -1717,7 +1597,7 @@ proto_register_ltp(void) }, {&hf_ltp_data_clid, {"Client service ID","ltp.data.client.id", - FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL} + FT_UINT64,BASE_DEC | BASE_VAL64_STRING, VALS64(client_service_id_info), 0x0, NULL, HFILL} }, {&hf_ltp_data_offset, {"Offset","ltp.data.offset", @@ -1818,7 +1698,7 @@ proto_register_ltp(void) }, {&hf_ltp_rpt_clm_cnt, {"Reception claim count","ltp.rpt.clm.cnt", - FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL} + FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL} }, {&hf_ltp_rpt_clm_off, {"Offset","ltp.rpt.clm.off", @@ -1876,7 +1756,7 @@ proto_register_ltp(void) }, {&hf_ltp_hdr_extn_tag, {"Extension tag","ltp.hdr.extn.tag", - FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL} + FT_UINT8,BASE_HEX,VALS(extn_tag_codes), 0x0, NULL, HFILL} }, {&hf_ltp_hdr_extn_len, {"Length","ltp.hdr.extn.len", @@ -1888,7 +1768,7 @@ proto_register_ltp(void) }, {&hf_ltp_trl_extn_tag, {"Extension tag","ltp.trl.extn.tag", - FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL} + FT_UINT8,BASE_HEX,VALS(extn_tag_codes), 0x0, NULL, HFILL} }, {&hf_ltp_trl_extn_len, {"Length","ltp.trl.extn.len", @@ -1973,7 +1853,6 @@ proto_register_ltp(void) }; static ei_register_info ei[] = { - { &ei_ltp_neg_reception_claim_count, { "ltp.neg_reception_claim_count", PI_UNDECODED, PI_ERROR, "Negative reception claim count", EXPFILL }}, { &ei_ltp_mal_reception_claim, { "ltp.mal_reception_claim", PI_MALFORMED, PI_ERROR, "Reception claim count impossibly large", EXPFILL }}, { &ei_ltp_sdnv_length, { "ltp.sdnv_length_invalid", PI_PROTOCOL, PI_ERROR, "SDNV length error", EXPFILL }}, { &ei_ltp_sno_larger_than_ccsds, { "ltp.serial_number_too_large", PI_PROTOCOL, PI_WARN, "Serial number larger than CCSDS specification", EXPFILL }}, diff --git a/epan/dissectors/packet-tcpcl.c b/epan/dissectors/packet-tcpcl.c index 134c835fa7..72b241de69 100644 --- a/epan/dissectors/packet-tcpcl.c +++ b/epan/dissectors/packet-tcpcl.c @@ -282,7 +282,7 @@ static hf_register_info hf_tcpcl[] = { {&hf_tcpclv3_xfer_id, {"Implied Transfer ID", "tcpcl.xfer_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}}, {&hf_tcpclv3_data_segment_length, {"Segment Length", "tcpcl.data.length", - FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL} + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_tcpclv3_data_segment_data, {"Segment Data", "tcpcl.data", @@ -310,7 +310,7 @@ static hf_register_info hf_tcpcl[] = { }, {&hf_tcpclv3_ack_length, {"Ack Length", "tcpcl.ack.length", - FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL} + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_tcpclv3_chdr_flags, {"Flags", "tcpcl.contact_hdr.flags", @@ -338,7 +338,7 @@ static hf_register_info hf_tcpcl[] = { }, {&hf_tcpclv3_chdr_local_eid_length, {"Local EID Length", "tcpcl.contact_hdr.local_eid_length", - FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL} + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_tcpclv4_chdr_flags, {"Contact Flags", "tcpcl.v4.chdr.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}}, @@ -532,6 +532,7 @@ static expert_field ei_invalid_version = EI_INIT; static expert_field ei_mismatch_version = EI_INIT; static expert_field ei_chdr_duplicate = EI_INIT; +static expert_field ei_tcpclv3_eid_length = EI_INIT; static expert_field ei_tcpclv3_invalid_msg_type = EI_INIT; static expert_field ei_tcpclv3_data_flags = EI_INIT; static expert_field ei_tcpclv3_segment_length = EI_INIT; @@ -564,6 +565,7 @@ static ei_register_info ei_tcpcl[] = { {&ei_mismatch_version, { "tcpcl.mismatch_contact_version", PI_PROTOCOL, PI_ERROR, "Protocol version mismatch", EXPFILL}}, {&ei_chdr_duplicate, { "tcpcl.contact_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate Contact Header", EXPFILL}}, + {&ei_tcpclv3_eid_length, { "tcpcl.eid_length_invalid", PI_PROTOCOL, PI_ERROR, "Invalid EID Length", EXPFILL }}, {&ei_tcpclv3_invalid_msg_type, { "tcpcl.unknown_message_type", PI_UNDECODED, PI_ERROR, "Message type is unknown", EXPFILL}}, {&ei_tcpclv3_data_flags, { "tcpcl.data.flags.invalid", PI_PROTOCOL, PI_WARN, "Invalid TCP CL Data Segment Flags", EXPFILL }}, {&ei_tcpclv3_segment_length, { "tcpcl.data.length.invalid", PI_PROTOCOL, PI_ERROR, "Invalid Data Length", EXPFILL }}, @@ -614,6 +616,10 @@ static const fragment_items xfer_frag_items = { "Transfer fragments" }; +static guint tvb_get_sdnv(tvbuff_t *tvb, guint offset, guint64 *value) { + return tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, value, ENC_VARINT_SDNV); +} + static void tcpcl_frame_loc_init(tcpcl_frame_loc_t *loc, const packet_info *pinfo, tvbuff_t *tvb, const gint offset) { loc->frame_num = pinfo->num; // This is a messy way to determine the index, @@ -1164,7 +1170,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, tcpcl_dissect_ctx_t *ctx _U_) { const int orig_offset = offset; - int len, bytecount; + guint64 len; + guint bytecount; guint8 conv_hdr = tvb_get_guint8(tvb, offset); offset += 1; @@ -1172,8 +1179,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, { case TCPCLV3_DATA_SEGMENT: /* get length from sdnv */ - len = evaluate_sdnv(tvb, offset, &bytecount); - if (len < 0) + bytecount = tvb_get_sdnv(tvb, offset, &len); + if (bytecount == 0) return 0; offset += bytecount+len; @@ -1181,8 +1188,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, case TCPCLV3_ACK_SEGMENT: /* get length from sdnv */ - len = evaluate_sdnv(tvb, offset, &bytecount); - if (len < 0) + bytecount = tvb_get_sdnv(tvb, offset, &len); + if (bytecount == 0) return 0; offset += bytecount; @@ -1203,8 +1210,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, case TCPCLV3_LENGTH: /* get length from sdnv */ - len = evaluate_sdnv(tvb, offset, &bytecount); - if (len < 0) + bytecount = tvb_get_sdnv(tvb, offset, &len); + if (bytecount == 0) return 0; offset += bytecount; break; @@ -1222,7 +1229,8 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const char *msgtype_name; guint8 refuse_bundle_hdr; int offset = 0; - int sdnv_length, segment_length; + gint sdnv_length; + guint64 segment_length; proto_item *conv_item, *sub_item; proto_tree *conv_tree, *sub_tree; guint64 *xfer_id = NULL; @@ -1248,19 +1256,20 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ett_tcpclv3_data_procflags, v3_data_procflags, ENC_BIG_ENDIAN ); + offset += 1; /* Only Start and End flags (bits 0 & 1) are valid in Data Segment */ if ((conv_hdr & ~(TCPCLV3_TYPE_MASK | TCPCLV3_DATA_FLAGS)) != 0) { expert_add_info(pinfo, item_flags, &ei_tcpclv3_data_flags); } - segment_length = evaluate_sdnv(tvb, 1, &sdnv_length); - sub_item = proto_tree_add_int(conv_tree, hf_tcpclv3_data_segment_length, tvb, 1, sdnv_length, segment_length); - if (segment_length < 0) { + sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_data_segment_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length); + if (sdnv_length == 0) { expert_add_info(pinfo, sub_item, &ei_tcpclv3_segment_length); - return 1; + return 0; } - offset += 1 + sdnv_length; + offset += sdnv_length; + const gint data_len_clamp = get_clamped_length(segment_length); // implied transfer ID xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc); @@ -1277,7 +1286,7 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id); proto_item_set_generated(item_xfer_id); - proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, segment_length, ENC_NA); + proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, data_len_clamp, ENC_NA); if (tcpcl_analyze_sequence) { transfer_add_segment(ctx, *xfer_id, (conv_hdr & TCPCLV3_DATA_FLAGS), segment_length, pinfo, tvb, conv_tree, conv_item, item_flags); @@ -1290,7 +1299,7 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, &xfer_reassembly_table, tvb, offset, pinfo, 0, xfer_id, - segment_length, + data_len_clamp, !(conv_hdr & TCPCLV3_DATA_END_FLAG) ); ctx->xferload = process_reassembled_data( @@ -1310,9 +1319,8 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /*No valid flags*/ offset += 1; - segment_length = evaluate_sdnv(tvb, offset, &sdnv_length); - sub_item = proto_tree_add_int(conv_tree, hf_tcpclv3_ack_length, tvb, offset, sdnv_length, segment_length); - if (segment_length < 0) { + sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_ack_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length); + if (sdnv_length == 0) { expert_add_info(pinfo, sub_item, &ei_tcpclv3_ack_length); } else { offset += sdnv_length; @@ -1889,10 +1897,10 @@ static guint get_message_len(packet_info *pinfo, tvbuff_t *tvb, int ext_offset, guint8 version = tvb_get_guint8(tvb, offset); offset += 1; if (version == 3) { - offset += 3; - int bytecount; - int len = evaluate_sdnv(tvb, offset, &bytecount); - offset += len + 1; + offset += 3; // flags + keepalive + guint64 len; + guint bytecount = tvb_get_sdnv(tvb, offset, &len); + offset += bytecount+len; } else if (version == 4) { offset += 1; @@ -1993,20 +2001,20 @@ static gint dissect_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, offset += 2; /* - * New format Contact header has length field followed by Bundle Header. + * New format Contact header has length field followed by EID. */ + guint64 eid_length; int sdnv_length; - expert_field *ei_bundle_sdnv_length; - int eid_length = evaluate_sdnv_ei(tvb, offset, &sdnv_length, &ei_bundle_sdnv_length); - proto_item *item_len = proto_tree_add_int(tree_chdr, hf_tcpclv3_chdr_local_eid_length, tvb, offset, sdnv_length, eid_length); - offset += sdnv_length; - if (ei_bundle_sdnv_length) { - expert_add_info(pinfo, item_len, ei_bundle_sdnv_length); - return offset; + proto_item *sub_item = proto_tree_add_item_ret_varint(tree_chdr, hf_tcpclv3_chdr_local_eid_length, tvb, offset, -1, ENC_VARINT_SDNV, &eid_length, &sdnv_length); + if (sdnv_length == 0) { + expert_add_info(pinfo, sub_item, &ei_tcpclv3_eid_length); + return 0; } + offset += sdnv_length; + const gint eid_len_clamp = get_clamped_length(eid_length); - proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_length, ENC_NA|ENC_ASCII); - offset += eid_length; + proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_len_clamp, ENC_NA|ENC_ASCII); + offset += eid_len_clamp; // assumed parameters ctx->tx_peer->segment_mru = G_MAXUINT64; diff --git a/epan/introspection-enums.c b/epan/introspection-enums.c index 00b9d14119..7394bd87c1 100644 --- a/epan/introspection-enums.c +++ b/epan/introspection-enums.c @@ -157,6 +157,7 @@ static ws_enum_t all_enums[] = { ENUM(ENC_VARINT_PROTOBUF), ENUM(ENC_VARINT_QUIC), ENUM(ENC_VARINT_ZIGZAG), + ENUM(ENC_VARINT_SDNV), ENUM(ENC_WINDOWS_1250), ENUM(ENC_WINDOWS_1251), ENUM(ENC_WINDOWS_1252), diff --git a/epan/proto.c b/epan/proto.c index 29f491ff3f..387b0052df 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -3199,7 +3199,7 @@ proto_tree_add_item_ret_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, proto_tree_set_uint(new_fi, value); new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN; - if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) { + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) { new_fi->flags |= FI_VARINT; } return proto_tree_add_node(tree, new_fi); @@ -3491,7 +3491,7 @@ proto_tree_add_item_ret_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, proto_tree_set_uint64(new_fi, value); new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN; - if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) { + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) { new_fi->flags |= FI_VARINT; } @@ -3551,7 +3551,7 @@ proto_tree_add_item_ret_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, proto_tree_set_int64(new_fi, value); new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN; - if (encoding & (ENC_VARINT_PROTOBUF | ENC_VARINT_ZIGZAG)) { + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) { new_fi->flags |= FI_VARINT; } @@ -3608,7 +3608,7 @@ proto_tree_add_item_ret_varint(proto_tree *tree, int hfindex, tvbuff_t *tvb, proto_tree_set_uint64(new_fi, value); new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN; - if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) { + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) { new_fi->flags |= FI_VARINT; } @@ -6062,7 +6062,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|ENC_VARINT_QUIC|ENC_VARIANT_ZIGZAG, it means "find the end of the string", + * For ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC|ENC_VARIANT_ZIGZAG|ENC_VARINT_SDNV, 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 @@ -6073,7 +6073,7 @@ get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint * Length would run past the end of the packet. */ if ((IS_FT_INT(hfinfo->type)) || (IS_FT_UINT(hfinfo->type))) { - if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) { + if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) { /* * Leave the length as -1, so our caller knows * it was -1. diff --git a/epan/proto.h b/epan/proto.h index 562e6b9593..ef58a9666d 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -639,8 +639,13 @@ void proto_report_dissector_bug(const char *format, ...) * See https://developers.google.com/protocol-buffers/docs/encoding?csw=1#types */ #define ENC_VARINT_ZIGZAG 0x00000008 +/* + * Decodes a variable-length integer used in DTN protocols + * See https://www.rfc-editor.org/rfc/rfc6256.html + */ +#define ENC_VARINT_SDNV 0x00000010 -#define ENC_VARINT_MASK (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC|ENC_VARINT_ZIGZAG) +#define ENC_VARINT_MASK (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV) /* Values for header_field_info.display */ diff --git a/epan/tvbtest.c b/epan/tvbtest.c index c418bd3b56..d77ca91a81 100644 --- a/epan/tvbtest.c +++ b/epan/tvbtest.c @@ -16,9 +16,12 @@ #include #include "tvbuff.h" +#include "proto.h" #include "exceptions.h" #include "wsutil/pint.h" +#include + gboolean failed = FALSE; typedef struct { @@ -605,6 +608,94 @@ run_tests(void) tvb_free_chain(tvb_parent); /* should free all tvb's and associated data */ } +typedef struct +{ + // Raw bytes + gint enc_len; + const guint8 *enc; + // Varint parameters + int encoding; + int maxlen; + // Results + unsigned long expect_except; + guint64 expect_val; + guint expect_len; +} varint_test_s; + +DIAG_OFF_PEDANTIC +varint_test_s varint[] = { + {0, (const guint8 *)"", 0, FT_VARINT_MAX_LEN, DissectorError, 0, 0}, // no encoding specified + // ENC_VARINT_PROTOBUF + {0, (const guint8 *)"", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, ReportedBoundsError, 0, 0}, + {1, (const guint8 *)"\x00", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0, 1}, + {1, (const guint8 *)"\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1, 1}, + {1, (const guint8 *)"\x7f", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0x7f, 1}, + {2, (const guint8 *)"\x80\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1ul<<7, 2}, + {1, (const guint8 *)"\x80", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, ReportedBoundsError, 0, 0}, // truncated data + {2, (const guint8 *)"\x80\x01", ENC_VARINT_PROTOBUF, 1, 0, 0, 0}, // truncated read + {5, (const guint8 *)"\x80\x80\x80\x80\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1ul<<28, 5}, + {10, (const guint8 *)"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1ul<<63, 10}, + {10, (const guint8 *)"\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0xfffffffffffffffful, 10}, + {10, (const guint8 *)"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x02", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0, 10}, // overflow + // ENC_VARINT_SDNV + {0, (const guint8 *)"", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, ReportedBoundsError, 0, 0}, + {1, (const guint8 *)"\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 0, 1}, + {1, (const guint8 *)"\x01", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1, 1}, + {1, (const guint8 *)"\x7f", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 0x7f, 1}, + {2, (const guint8 *)"\x81\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<7, 2}, + {1, (const guint8 *)"\x81", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, ReportedBoundsError, 1, 0}, // truncated data + {2, (const guint8 *)"\x81\x00", ENC_VARINT_SDNV, 1, 0, 1, 0}, // truncated read + {5, (const guint8 *)"\x81\x80\x80\x80\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<28, 5}, + {10, (const guint8 *)"\x81\x80\x80\x80\x80\x80\x80\x80\x80\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<63, 10}, + {10, (const guint8 *)"\x81\xff\xff\xff\xff\xff\xff\xff\xff\x7f", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 0xfffffffffffffffful, 10}, + {10, (const guint8 *)"\x82\x80\x80\x80\x80\x80\x80\x80\x80\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<57, 0}, // overflow +}; +DIAG_ON_PEDANTIC + +static void +varint_tests(void) +{ + tvbuff_t *tvb_parent, *tvb; + tvb_parent = tvb_new_real_data((const guint8*)"", 0, 0); + + for (size_t ix = 0; ix < (sizeof(varint) / sizeof(varint_test_s)); ++ix) { + const varint_test_s *vit = &varint[ix]; + tvb = tvb_new_child_real_data(tvb_parent, vit->enc, vit->enc_len, vit->enc_len); + + unsigned long got_ex = 0; + guint64 got_val = 0; + guint got_len = 0; + TRY { + got_len = tvb_get_varint(tvb, 0, vit->maxlen, &got_val, vit->encoding); + } + CATCH_ALL { + got_ex = exc->except_id.except_code; + } + ENDTRY; + if (got_ex != vit->expect_except) { + printf("Failed varint #%zu with exception=%d while expected exception=%d\n", + ix, got_ex, vit->expect_except); + failed = TRUE; + continue; + } + if (got_val != vit->expect_val) { + printf("Failed varint #%zu value=%" PRIu64 " while expected value=%" PRIu64 "\n", + ix, got_val, vit->expect_val); + failed = TRUE; + continue; + } + if (got_len != vit->expect_len) { + printf("Failed varint #%zu length=%u while expected length=%u\n", + ix, got_len, vit->expect_len); + failed = TRUE; + continue; + } + printf("Passed varint #%zu\n", ix); + } + + tvb_free_chain(tvb_parent); /* should free all tvb's and associated data */ +} + /* Note: valgrind can be used to check for tvbuff memory leaks */ int main(void) @@ -615,6 +706,7 @@ main(void) except_init(); run_tests(); + varint_tests(); except_deinit(); exit(failed?1:0); } diff --git a/epan/tvbuff.c b/epan/tvbuff.c index 81502d2531..97e60b564d 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -4563,6 +4563,29 @@ tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value, const break; } + case ENC_VARINT_SDNV: + { + /* Decodes similar to protobuf but in MSByte order */ + guint i; + guint64 b; /* current byte */ + + for (i = 0; ((i < FT_VARINT_MAX_LEN) && (i < maxlen)); ++i) { + b = tvb_get_guint8(tvb, offset++); + if ((i == 9) && (*value >= 1ul<<(64-7))) { + // guaranteed overflow, not valid SDNV + return 0; + } + *value <<= 7; + *value |= (b & 0x7F); /* add lower 7 bits to val */ + + if (b < 0x80) { + /* end successfully because of last byte's msb(most significant bit) is zero */ + return i + 1; + } + } + break; + } + case ENC_VARINT_QUIC: { /* calculate variable length */ diff --git a/epan/tvbuff.h b/epan/tvbuff.h index 4791183502..d58a88c095 100644 --- a/epan/tvbuff.h +++ b/epan/tvbuff.h @@ -1145,7 +1145,7 @@ extern tvbuff_t* base64uri_tvb_to_new_tvb(tvbuff_t* parent, int offset, int leng * @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, ENC_VARINT_ZIGZAG) + * @param encoding The ENC_* that defines the format (e.g., ENC_VARINT_PROTOBUF, ENC_VARINT_QUIC, ENC_VARINT_ZIGZAG, ENC_VARINT_SDNV) * @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, const guint encoding);