From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- frame_tvbuff.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 frame_tvbuff.c (limited to 'frame_tvbuff.c') diff --git a/frame_tvbuff.c b/frame_tvbuff.c new file mode 100644 index 00000000..1aec22c2 --- /dev/null +++ b/frame_tvbuff.c @@ -0,0 +1,331 @@ +/* frame_tvbuff.c + * Implements a tvbuff for frame + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include + +#include + +#include +#include +#include + +#include "frame_tvbuff.h" + +#include "wiretap/wtap-int.h" /* for ->random_fh */ + +struct tvb_frame { + struct tvbuff tvb; + + Buffer *buf; /* Packet data */ + + const struct packet_provider_data *prov; /* provider of packet information */ + gint64 file_off; /**< File offset */ + + guint offset; +}; + +static gboolean +frame_read(struct tvb_frame *frame_tvb, wtap_rec *rec, Buffer *buf) +{ + int err; + gchar *err_info; + gboolean ok = TRUE; + + /* XXX, what if phdr->caplen isn't equal to + * frame_tvb->tvb.length + frame_tvb->offset? + */ + if (!wtap_seek_read(frame_tvb->prov->wth, frame_tvb->file_off, rec, buf, &err, &err_info)) { + /* XXX - report error! */ + switch (err) { + case WTAP_ERR_BAD_FILE: + g_free(err_info); + ok = FALSE; + break; + } + } + return ok; +} + +static GPtrArray *buffer_cache = NULL; + +static void +frame_cache(struct tvb_frame *frame_tvb) +{ + wtap_rec rec; /* Record metadata */ + + wtap_rec_init(&rec); + + if (frame_tvb->buf == NULL) { + if (G_UNLIKELY(!buffer_cache)) buffer_cache = g_ptr_array_sized_new(1024); + + if (buffer_cache->len > 0) { + frame_tvb->buf = (struct Buffer *) g_ptr_array_remove_index(buffer_cache, buffer_cache->len - 1); + } else { + frame_tvb->buf = g_new(struct Buffer, 1); + } + + ws_buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset); + + if (!frame_read(frame_tvb, &rec, frame_tvb->buf)) + { /* TODO: THROW(???); */ } + } + + frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset; + + wtap_rec_cleanup(&rec); +} + +static void +frame_free(tvbuff_t *tvb) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + if (frame_tvb->buf) { + ws_buffer_free(frame_tvb->buf); + g_ptr_array_add(buffer_cache, frame_tvb->buf); + } +} + +static const guint8 * +frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + frame_cache(frame_tvb); + + return tvb->real_data + abs_offset; +} + +static void * +frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + frame_cache(frame_tvb); + + return memcpy(target, tvb->real_data + abs_offset, abs_length); +} + +static gint +frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + const guint8 *result; + + frame_cache(frame_tvb); + + result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit); + if (result) + return (gint) (result - tvb->real_data); + else + return -1; +} + +static gint +frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + frame_cache(frame_tvb); + + return tvb_ws_mempbrk_pattern_guint8(tvb, abs_offset, limit, pattern, found_needle); +} + +static guint +frame_offset(const tvbuff_t *tvb _U_, const guint counter) +{ + /* XXX: frame_tvb->offset */ + return counter; +} + +static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length); + +static const struct tvb_ops tvb_frame_ops = { + sizeof(struct tvb_frame), /* size */ + + frame_free, /* free */ + frame_offset, /* offset */ + frame_get_ptr, /* get_ptr */ + frame_memcpy, /* memcpy */ + frame_find_guint8, /* find_guint8 */ + frame_pbrk_guint8, /* pbrk_guint8 */ + frame_clone, /* clone */ +}; + +/* based on tvb_new_real_data() */ +tvbuff_t * +frame_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd, + const guint8 *buf) +{ + struct tvb_frame *frame_tvb; + tvbuff_t *tvb; + + tvb = tvb_new(&tvb_frame_ops); + + /* + * XXX - currently, the length arguments in + * tvbuff structure are signed, but the captured + * and reported length values are unsigned; this means + * that length values > 2^31 - 1 will appear as + * negative lengths + * + * Captured length values that large will already + * have been filtered out by the Wiretap modules + * (the file will be reported as corrupted), to + * avoid trying to allocate large chunks of data. + * + * Reported length values will not have been + * filtered out, and should not be filtered out, + * as those lengths are not necessarily invalid. + * + * For now, we clip the reported length at G_MAXINT + * + * (XXX, is this still a problem?) There was an exception when we call + * tvb_new_real_data() now there's no one + */ + + tvb->real_data = buf; + tvb->length = fd->cap_len; + tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len; + tvb->contained_length = tvb->reported_length; + tvb->initialized = TRUE; + + /* + * This is the top-level real tvbuff for this data source, + * so its data source tvbuff is itself. + */ + tvb->ds_tvb = tvb; + + frame_tvb = (struct tvb_frame *) tvb; + + /* XXX, wtap_can_seek() */ + if (prov->wth && prov->wth->random_fh) { + frame_tvb->prov = prov; + frame_tvb->file_off = fd->file_off; + frame_tvb->offset = 0; + } else + frame_tvb->prov = NULL; + + frame_tvb->buf = NULL; + + return tvb; +} + +tvbuff_t * +frame_tvbuff_new_buffer(const struct packet_provider_data *prov, + const frame_data *fd, Buffer *buf) +{ + return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf)); +} + +static tvbuff_t * +frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length) +{ + struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; + + tvbuff_t *cloned_tvb; + struct tvb_frame *cloned_frame_tvb; + + /* file not seekable */ + if (!frame_tvb->prov) + return NULL; + + abs_offset += frame_tvb->offset; + + cloned_tvb = tvb_new(&tvb_frame_ops); + + /* data will be read when needed */ + cloned_tvb->real_data = NULL; + cloned_tvb->length = abs_length; + cloned_tvb->reported_length = abs_length; /* XXX? */ + cloned_tvb->contained_length = cloned_tvb->reported_length; + cloned_tvb->initialized = TRUE; + + /* + * This is the top-level real tvbuff for this data source, + * so its data source tvbuff is itself. + */ + cloned_tvb->ds_tvb = cloned_tvb; + + cloned_frame_tvb = (struct tvb_frame *) cloned_tvb; + cloned_frame_tvb->prov = frame_tvb->prov; + cloned_frame_tvb->file_off = frame_tvb->file_off; + cloned_frame_tvb->offset = abs_offset; + cloned_frame_tvb->buf = NULL; + + return cloned_tvb; +} + + +/* based on tvb_new_real_data() */ +tvbuff_t * +file_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd, + const guint8 *buf) +{ + struct tvb_frame *frame_tvb; + tvbuff_t *tvb; + + tvb = tvb_new(&tvb_frame_ops); + + /* + * XXX - currently, the length arguments in + * tvbuff structure are signed, but the captured + * and reported length values are unsigned; this means + * that length values > 2^31 - 1 will appear as + * negative lengths + * + * Captured length values that large will already + * have been filtered out by the Wiretap modules + * (the file will be reported as corrupted), to + * avoid trying to allocate large chunks of data. + * + * Reported length values will not have been + * filtered out, and should not be filtered out, + * as those lengths are not necessarily invalid. + * + * For now, we clip the reported length at G_MAXINT + * + * (XXX, is this still a problem?) There was an exception when we call + * tvb_new_real_data() now there's no one + */ + + tvb->real_data = buf; + tvb->length = fd->cap_len; + tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len; + tvb->contained_length = tvb->reported_length; + tvb->initialized = TRUE; + + /* + * This is the top-level real tvbuff for this data source, + * so its data source tvbuff is itself. + */ + tvb->ds_tvb = tvb; + + frame_tvb = (struct tvb_frame *) tvb; + + /* XXX, wtap_can_seek() */ + if (prov->wth && prov->wth->random_fh) { + frame_tvb->prov = prov; + frame_tvb->file_off = fd->file_off; + frame_tvb->offset = 0; + } else + frame_tvb->prov = NULL; + + frame_tvb->buf = NULL; + + return tvb; +} + +tvbuff_t * +file_tvbuff_new_buffer(const struct packet_provider_data *prov, + const frame_data *fd, Buffer *buf) +{ + return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf)); +} -- cgit v1.2.3