* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
tvb = (tvbuff_t *) g_slice_alloc(size);
- tvb->next = NULL;
- tvb->ops = ops;
- tvb->initialized = FALSE;
- tvb->flags = 0;
- tvb->length = 0;
- tvb->reported_length = 0;
- tvb->real_data = NULL;
- tvb->raw_offset = -1;
- tvb->ds_tvb = NULL;
+ tvb->next = NULL;
+ tvb->ops = ops;
+ tvb->initialized = FALSE;
+ tvb->flags = 0;
+ tvb->length = 0;
+ tvb->reported_length = 0;
+ tvb->contained_length = 0;
+ tvb->real_data = NULL;
+ tvb->raw_offset = -1;
+ tvb->ds_tvb = NULL;
return tvb;
}
static inline int
validate_offset(const tvbuff_t *tvb, const guint abs_offset)
{
- if (G_LIKELY(abs_offset <= tvb->length))
+ if (G_LIKELY(abs_offset <= tvb->length)) {
+ /* It's OK. */
return 0;
- else if (abs_offset <= tvb->reported_length)
+ }
+
+ /*
+ * It's not OK, but why? Which boundaries is it
+ * past?
+ */
+ if (abs_offset <= tvb->contained_length) {
+ /*
+ * It's past the captured length, but not past
+ * the reported end of any parent tvbuffs from
+ * which this is constructed, or the reported
+ * end of this tvbuff, so it's out of bounds
+ * solely because we're past the end of the
+ * captured data.
+ */
return BoundsError;
- else if (tvb->flags & TVBUFF_FRAGMENT)
+ }
+
+ /*
+ * There's some actual packet boundary, not just the
+ * artificial boundary imposed by packet slicing, that
+ * we're past.
+ */
+ if (abs_offset <= tvb->reported_length) {
+ /*
+ * We're within the bounds of what this tvbuff
+ * purportedly contains, based on some length
+ * value, but we're not within the bounds of
+ * something from which this tvbuff was
+ * extracted, so that length value ran past
+ * the end of some parent tvbuff.
+ */
+ return ContainedBoundsError;
+ }
+
+ /*
+ * OK, we're past the bounds of what this tvbuff
+ * purportedly contains.
+ */
+ if (tvb->flags & TVBUFF_FRAGMENT) {
+ /*
+ * This tvbuff is the first fragment of a larger
+ * packet that hasn't been reassembled, so we
+ * assume that's the source of the prblem - if
+ * we'd reassembled the packet, we wouldn't
+ * have gone past the end.
+ *
+ * That might not be true, but for at least
+ * some forms of reassembly, such as IP
+ * reassembly, you don't know how big the
+ * reassembled packet is unless you reassemble
+ * it, so, in those cases, we can't determine
+ * whether we would have gone past the end
+ * had we reassembled the packet.
+ */
return FragmentBoundsError;
- else
- return ReportedBoundsError;
+ }
+
+ /*
+ * OK, it looks as if we ran past the claimed length
+ * of data.
+ */
+ return ReportedBoundsError;
}
static inline int
{
if (offset >= 0) {
/* Positive offset - relative to the beginning of the packet. */
- if ((guint) offset <= tvb->length) {
+ if (G_LIKELY((guint) offset <= tvb->length)) {
*offset_ptr = offset;
- } else if ((guint) offset <= tvb->reported_length) {
+ } else if ((guint) offset <= tvb->contained_length) {
return BoundsError;
+ } else if ((guint) offset <= tvb->reported_length) {
+ return ContainedBoundsError;
} else if (tvb->flags & TVBUFF_FRAGMENT) {
return FragmentBoundsError;
} else {
}
else {
/* Negative offset - relative to the end of the packet. */
- if ((guint) -offset <= tvb->length) {
+ if (G_LIKELY((guint) -offset <= tvb->length)) {
*offset_ptr = tvb->length + offset;
- } else if ((guint) -offset <= tvb->reported_length) {
+ } else if ((guint) -offset <= tvb->contained_length) {
return BoundsError;
+ } else if ((guint) -offset <= tvb->reported_length) {
+ return ContainedBoundsError;
} else if (tvb->flags & TVBUFF_FRAGMENT) {
return FragmentBoundsError;
} else {
/* Computes the absolute offset and length based on a possibly-negative offset
* and a length that is possible -1 (which means "to the end of the data").
* Returns integer indicating whether the offset is in bounds (0) or
- * not (exception number). The integer ptrs are modified with the new offset and length.
- * No exception is thrown.
+ * not (exception number). The integer ptrs are modified with the new offset,
+ * captured (available) length, and contained length (amount that's present
+ * in the parent tvbuff based on its reported length).
+ * No exception is thrown; on success, we return 0, otherwise we return an
+ * exception for the caller to throw if appropriate.
*
* XXX - we return success (0), if the offset is positive and right
* after the end of the tvbuff (i.e., equal to the length). We do this
static inline gint
_tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
{
- guint abs_offset, rem_length;
+ guint abs_offset = 0, rem_length;
int exception;
exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length);
gint
tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
{
- guint abs_offset, rem_length;
+ guint abs_offset = 0, rem_length;
int exception;
DISSECTOR_ASSERT(tvb && tvb->initialized);
* There aren't any bytes available, so throw the appropriate
* exception.
*/
- if (abs_offset >= tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
- } else
+ if (abs_offset < tvb->contained_length) {
THROW(BoundsError);
+ } else if (abs_offset < tvb->reported_length) {
+ THROW(ContainedBoundsError);
+ } else if (tvb->flags & TVBUFF_FRAGMENT) {
+ THROW(FragmentBoundsError);
+ } else {
+ THROW(ReportedBoundsError);
+ }
}
return rem_length;
}
gboolean
tvb_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length)
{
- guint abs_offset, abs_length;
+ guint abs_offset = 0, abs_length;
int exception;
DISSECTOR_ASSERT(tvb && tvb->initialized);
+ /*
+ * Negative lengths are not possible and indicate a bug (e.g. arithmetic
+ * error or an overly large value from packet data).
+ */
+ if (length < 0)
+ return FALSE;
+
exception = check_offset_length_no_exception(tvb, offset, length, &abs_offset, &abs_length);
if (exception)
return FALSE;
if (offset >= 0) {
/* Positive offset - relative to the beginning of the packet. */
- if ((guint) offset <= tvb->length) {
+ if (G_LIKELY((guint) offset <= tvb->length)) {
real_offset = offset;
- } else if ((guint) offset <= tvb->reported_length) {
+ } else if ((guint) offset <= tvb->contained_length) {
THROW(BoundsError);
+ } else if ((guint) offset <= tvb->reported_length) {
+ THROW(ContainedBoundsError);
} else if (tvb->flags & TVBUFF_FRAGMENT) {
THROW(FragmentBoundsError);
} else {
}
else {
/* Negative offset - relative to the end of the packet. */
- if ((guint) -offset <= tvb->length) {
+ if (G_LIKELY((guint) -offset <= tvb->length)) {
real_offset = tvb->length + offset;
- } else if ((guint) -offset <= tvb->reported_length) {
+ } else if ((guint) -offset <= tvb->contained_length) {
THROW(BoundsError);
+ } else if ((guint) -offset <= tvb->reported_length) {
+ THROW(ContainedBoundsError);
} else if (tvb->flags & TVBUFF_FRAGMENT) {
THROW(FragmentBoundsError);
} else {
if (G_LIKELY(end_offset <= tvb->length))
return;
- else if (end_offset <= tvb->reported_length)
+ else if (end_offset <= tvb->contained_length)
THROW(BoundsError);
+ else if (end_offset <= tvb->reported_length)
+ THROW(ContainedBoundsError);
else if (tvb->flags & TVBUFF_FRAGMENT)
THROW(FragmentBoundsError);
else
gboolean
tvb_offset_exists(const tvbuff_t *tvb, const gint offset)
{
- guint abs_offset;
+ guint abs_offset = 0;
int exception;
DISSECTOR_ASSERT(tvb && tvb->initialized);
gint
tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset)
{
- guint abs_offset;
+ guint abs_offset = 0;
int exception;
DISSECTOR_ASSERT(tvb && tvb->initialized);
* whose headers contain an explicit length and where the calling
* dissector's payload may include padding as well as the packet for
* this protocol.
- * Also adjusts the data length. */
+ * Also adjusts the available and contained length. */
void
tvb_set_reported_length(tvbuff_t *tvb, const guint reported_length)
{
tvb->reported_length = reported_length;
if (reported_length < tvb->length)
tvb->length = reported_length;
+ if (reported_length < tvb->contained_length)
+ tvb->contained_length = reported_length;
}
guint
return NULL;
}
+ /*
+ * Special case: if the caller (e.g. tvb_get_ptr) requested no data,
+ * then it is acceptable to have an empty tvb (!tvb->real_data).
+ */
+ if (length == 0) {
+ return NULL;
+ }
+
/*
* We know that all the data is present in the tvbuff, so
* no exceptions should be thrown.
const guint8 *p;
p = ensure_contiguous_no_exception(tvb, offset, length, &exception);
- if (p == NULL) {
+ if (p == NULL && length != 0) {
DISSECTOR_ASSERT(exception > 0);
THROW(exception);
}
u_offset = offset;
end_offset = u_offset + length;
- if (end_offset <= tvb->length) {
+ if (G_LIKELY(end_offset <= tvb->length)) {
return tvb->real_data + u_offset;
+ } else if (end_offset <= tvb->contained_length) {
+ THROW(BoundsError);
+ } else if (end_offset <= tvb->reported_length) {
+ THROW(ContainedBoundsError);
+ } else if (tvb->flags & TVBUFF_FRAGMENT) {
+ THROW(FragmentBoundsError);
+ } else {
+ THROW(ReportedBoundsError);
}
-
- if (end_offset > tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
- /* not reached */
- }
- THROW(BoundsError);
/* not reached */
return NULL;
}
{
const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint8));
+ ptr = fast_ensure_contiguous(tvb, offset, 1);
+ return *ptr;
+}
+
+gint8
+tvb_get_gint8(tvbuff_t *tvb, const gint offset)
+{
+ const guint8 *ptr;
+
+ ptr = fast_ensure_contiguous(tvb, offset, 1);
return *ptr;
}
{
const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint16));
+ ptr = fast_ensure_contiguous(tvb, offset, 2);
+ return pntoh16(ptr);
+}
+
+gint16
+tvb_get_ntohis(tvbuff_t *tvb, const gint offset)
+{
+ const guint8 *ptr;
+
+ ptr = fast_ensure_contiguous(tvb, offset, 2);
return pntoh16(ptr);
}
return pntoh24(ptr);
}
+gint32
+tvb_get_ntohi24(tvbuff_t *tvb, const gint offset)
+{
+ guint32 ret;
+
+ ret = ws_sign_ext32(tvb_get_ntoh24(tvb, offset), 24);
+
+ return (gint32)ret;
+}
+
guint32
tvb_get_ntohl(tvbuff_t *tvb, const gint offset)
{
const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
+ ptr = fast_ensure_contiguous(tvb, offset, 4);
+ return pntoh32(ptr);
+}
+
+gint32
+tvb_get_ntohil(tvbuff_t *tvb, const gint offset)
+{
+ const guint8 *ptr;
+
+ ptr = fast_ensure_contiguous(tvb, offset, 4);
return pntoh32(ptr);
}
{
const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint64));
+ ptr = fast_ensure_contiguous(tvb, offset, 8);
+ return pntoh64(ptr);
+}
+
+gint64
+tvb_get_ntohi64(tvbuff_t *tvb, const gint offset)
+{
+ const guint8 *ptr;
+
+ ptr = fast_ensure_contiguous(tvb, offset, 8);
return pntoh64(ptr);
}
}
}
+gint16
+tvb_get_gint16(tvbuff_t *tvb, const gint offset, const guint encoding) {
+ if (encoding & ENC_LITTLE_ENDIAN) {
+ return tvb_get_letohis(tvb, offset);
+ } else {
+ return tvb_get_ntohis(tvb, offset);
+ }
+}
+
guint32
tvb_get_guint24(tvbuff_t *tvb, const gint offset, const guint encoding) {
if (encoding & ENC_LITTLE_ENDIAN) {
}
}
+gint32
+tvb_get_gint24(tvbuff_t *tvb, const gint offset, const guint encoding) {
+ if (encoding & ENC_LITTLE_ENDIAN) {
+ return tvb_get_letohi24(tvb, offset);
+ } else {
+ return tvb_get_ntohi24(tvb, offset);
+ }
+}
+
guint32
tvb_get_guint32(tvbuff_t *tvb, const gint offset, const guint encoding) {
if (encoding & ENC_LITTLE_ENDIAN) {
}
}
+gint32
+tvb_get_gint32(tvbuff_t *tvb, const gint offset, const guint encoding) {
+ if (encoding & ENC_LITTLE_ENDIAN) {
+ return tvb_get_letohil(tvb, offset);
+ } else {
+ return tvb_get_ntohil(tvb, offset);
+ }
+}
+
guint64
tvb_get_guint40(tvbuff_t *tvb, const gint offset, const guint encoding) {
if (encoding & ENC_LITTLE_ENDIAN) {
}
}
+gint64
+tvb_get_gint64(tvbuff_t *tvb, const gint offset, const guint encoding) {
+ if (encoding & ENC_LITTLE_ENDIAN) {
+ return tvb_get_letohi64(tvb, offset);
+ } else {
+ return tvb_get_ntohi64(tvb, offset);
+ }
+}
+
gfloat
tvb_get_ieee_float(tvbuff_t *tvb, const gint offset, const guint encoding) {
if (encoding & ENC_LITTLE_ENDIAN) {
*
* For now, we treat only the VAX as such a platform.
*
- * XXX - other non-IEEE boxes that can run UNIX include some Crays,
- * and possibly other machines.
- *
- * It appears that the official Linux port to System/390 and
- * zArchitecture uses IEEE format floating point (not a
- * huge surprise).
- *
- * I don't know whether there are any other machines that
- * could run Wireshark and that don't use IEEE format.
- * As far as I know, all of the main commercial microprocessor
- * families on which OSes that support Wireshark can run
- * use IEEE format (x86, 68k, SPARC, MIPS, PA-RISC, Alpha,
- * IA-64, and so on).
+ * XXX - other non-IEEE boxes that can run UN*X include some Crays,
+ * and possibly other machines. However, I don't know whether there
+ * are any other machines that could run Wireshark and that don't use
+ * IEEE format. As far as I know, all of the main current and past
+ * commercial microprocessor families on which OSes that support
+ * Wireshark can run use IEEE format (x86, ARM, 68k, SPARC, MIPS,
+ * PA-RISC, Alpha, IA-64, and so on), and it appears that the official
+ * Linux port to System/390 and zArchitecture uses IEEE format floating-
+ * point rather than IBM hex floating-point (not a huge surprise), so
+ * I'm not sure that leaves any 32-bit or larger UN*X or Windows boxes,
+ * other than VAXes, that don't use IEEE format. If you're not running
+ * UN*X or Windows, the floating-point format is probably going to be
+ * the least of your problems in a port.
*/
#if defined(vax)
} ieee_fp_union;
#endif
-#ifdef WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
ieee_fp_union.w[0] = tvb_get_ntohl(tvb, offset);
ieee_fp_union.w[1] = tvb_get_ntohl(tvb, offset+4);
#else
{
const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint16));
+ ptr = fast_ensure_contiguous(tvb, offset, 2);
+ return pletoh16(ptr);
+}
+
+gint16
+tvb_get_letohis(tvbuff_t *tvb, const gint offset)
+{
+ const guint8 *ptr;
+
+ ptr = fast_ensure_contiguous(tvb, offset, 2);
return pletoh16(ptr);
}
return pletoh24(ptr);
}
+gint32
+tvb_get_letohi24(tvbuff_t *tvb, const gint offset)
+{
+ guint32 ret;
+
+ ret = ws_sign_ext32(tvb_get_letoh24(tvb, offset), 24);
+
+ return (gint32)ret;
+}
+
guint32
tvb_get_letohl(tvbuff_t *tvb, const gint offset)
{
const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
+ ptr = fast_ensure_contiguous(tvb, offset, 4);
+ return pletoh32(ptr);
+}
+
+gint32
+tvb_get_letohil(tvbuff_t *tvb, const gint offset)
+{
+ const guint8 *ptr;
+
+ ptr = fast_ensure_contiguous(tvb, offset, 4);
return pletoh32(ptr);
}
{
const guint8 *ptr;
- ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint64));
+ ptr = fast_ensure_contiguous(tvb, offset, 8);
+ return pletoh64(ptr);
+}
+
+gint64
+tvb_get_letohi64(tvbuff_t *tvb, const gint offset)
+{
+ const guint8 *ptr;
+
+ ptr = fast_ensure_contiguous(tvb, offset, 8);
return pletoh64(ptr);
}
} ieee_fp_union;
#endif
-#ifdef WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
ieee_fp_union.w[0] = tvb_get_letohl(tvb, offset+4);
ieee_fp_union.w[1] = tvb_get_letohl(tvb, offset);
#else
/* Fetch an IPv6 address. */
void
-tvb_get_ipv6(tvbuff_t *tvb, const gint offset, struct e_in6_addr *addr)
+tvb_get_ipv6(tvbuff_t *tvb, const gint offset, ws_in6_addr *addr)
{
const guint8 *ptr;
/*
* OK, we hit the end of the tvbuff, so we should throw
* an exception.
- *
- * Did we hit the end of the captured data, or the end
- * of the actual data? If there's less captured data
- * than actual data, we presumably hit the end of the
- * captured data, otherwise we hit the end of the actual
- * data.
*/
- if (tvb->length < tvb->reported_length) {
+ if (tvb->length < tvb->contained_length) {
THROW(BoundsError);
+ } else if (tvb->length < tvb->reported_length) {
+ THROW(ContainedBoundsError);
+ } else if (tvb->flags & TVBUFF_FRAGMENT) {
+ THROW(FragmentBoundsError);
} else {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
+ THROW(ReportedBoundsError);
}
}
return (nul_offset - abs_offset) + 1;
}
gint
-tvb_skip_wsp_return(tvbuff_t *tvb, const gint offset) {
+tvb_skip_wsp_return(tvbuff_t *tvb, const gint offset)
+{
gint counter = offset;
guint8 tempchar;
- for(counter = offset; counter > 0 &&
+ DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+ for (counter = offset; counter > 0 &&
((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
tempchar == '\t' || tempchar == '\n' || tempchar == '\r'); counter--);
counter++;
+
return (counter);
}
return(tvb->ds_tvb);
}
+guint
+tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value, const guint encoding)
+{
+ *value = 0;
+
+ if (encoding & ENC_VARINT_PROTOBUF) {
+ guint i;
+ guint64 b; /* current byte */
+
+ 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 */
+}
+
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*