1 /* frame_tvbuff.c
2  * Implements a tvbuff for frame
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include <config.h>
12 
13 #include <glib.h>
14 
15 #include <epan/packet.h>
16 #include <epan/tvbuff-int.h>
17 #include <epan/tvbuff.h>
18 
19 #include "frame_tvbuff.h"
20 
21 #include "wiretap/wtap-int.h" /* for ->random_fh */
22 
23 struct tvb_frame {
24 	struct tvbuff tvb;
25 
26 	Buffer *buf;         /* Packet data */
27 
28 	const struct packet_provider_data *prov;	/* provider of packet information */
29 	gint64 file_off;     /**< File offset */
30 
31 	guint offset;
32 };
33 
34 static gboolean
frame_read(struct tvb_frame * frame_tvb,wtap_rec * rec,Buffer * buf)35 frame_read(struct tvb_frame *frame_tvb, wtap_rec *rec, Buffer *buf)
36 {
37 	int    err;
38 	gchar *err_info;
39 	gboolean ok = TRUE;
40 
41 	/* XXX, what if phdr->caplen isn't equal to
42 	 * frame_tvb->tvb.length + frame_tvb->offset?
43 	 */
44 	if (!wtap_seek_read(frame_tvb->prov->wth, frame_tvb->file_off, rec, buf, &err, &err_info)) {
45 		/* XXX - report error! */
46 		switch (err) {
47 			case WTAP_ERR_BAD_FILE:
48 				g_free(err_info);
49 				ok = FALSE;
50 				break;
51 		}
52 	}
53 	return ok;
54 }
55 
56 static GPtrArray *buffer_cache = NULL;
57 
58 static void
frame_cache(struct tvb_frame * frame_tvb)59 frame_cache(struct tvb_frame *frame_tvb)
60 {
61 	wtap_rec rec; /* Record metadata */
62 
63 	wtap_rec_init(&rec);
64 
65 	if (frame_tvb->buf == NULL) {
66 		if (G_UNLIKELY(!buffer_cache)) buffer_cache = g_ptr_array_sized_new(1024);
67 
68 		if (buffer_cache->len > 0) {
69 			frame_tvb->buf = (struct Buffer *) g_ptr_array_remove_index(buffer_cache, buffer_cache->len - 1);
70 		} else {
71 			frame_tvb->buf = g_new(struct Buffer, 1);
72 		}
73 
74 		ws_buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset);
75 
76 		if (!frame_read(frame_tvb, &rec, frame_tvb->buf))
77 			{ /* TODO: THROW(???); */ }
78 	}
79 
80 	frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset;
81 
82 	wtap_rec_cleanup(&rec);
83 }
84 
85 static void
frame_free(tvbuff_t * tvb)86 frame_free(tvbuff_t *tvb)
87 {
88 	struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
89 
90 	if (frame_tvb->buf) {
91 		ws_buffer_free(frame_tvb->buf);
92 		g_ptr_array_add(buffer_cache, frame_tvb->buf);
93 	}
94 }
95 
96 static const guint8 *
frame_get_ptr(tvbuff_t * tvb,guint abs_offset,guint abs_length _U_)97 frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_)
98 {
99 	struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
100 
101 	frame_cache(frame_tvb);
102 
103 	return tvb->real_data + abs_offset;
104 }
105 
106 static void *
frame_memcpy(tvbuff_t * tvb,void * target,guint abs_offset,guint abs_length)107 frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
108 {
109 	struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
110 
111 	frame_cache(frame_tvb);
112 
113 	return memcpy(target, tvb->real_data + abs_offset, abs_length);
114 }
115 
116 static gint
frame_find_guint8(tvbuff_t * tvb,guint abs_offset,guint limit,guint8 needle)117 frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
118 {
119 	struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
120 	const guint8 *result;
121 
122 	frame_cache(frame_tvb);
123 
124 	result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit);
125 	if (result)
126 		return (gint) (result - tvb->real_data);
127 	else
128 		return -1;
129 }
130 
131 static gint
frame_pbrk_guint8(tvbuff_t * tvb,guint abs_offset,guint limit,const ws_mempbrk_pattern * pattern,guchar * found_needle)132 frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle)
133 {
134 	struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
135 
136 	frame_cache(frame_tvb);
137 
138 	return tvb_ws_mempbrk_pattern_guint8(tvb, abs_offset, limit, pattern, found_needle);
139 }
140 
141 static guint
frame_offset(const tvbuff_t * tvb _U_,const guint counter)142 frame_offset(const tvbuff_t *tvb _U_, const guint counter)
143 {
144 	/* XXX: frame_tvb->offset */
145 	return counter;
146 }
147 
148 static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length);
149 
150 static const struct tvb_ops tvb_frame_ops = {
151 	sizeof(struct tvb_frame), /* size */
152 
153 	frame_free,           /* free */
154 	frame_offset,         /* offset */
155 	frame_get_ptr,        /* get_ptr */
156 	frame_memcpy,         /* memcpy */
157 	frame_find_guint8,    /* find_guint8 */
158 	frame_pbrk_guint8,    /* pbrk_guint8 */
159 	frame_clone,          /* clone */
160 };
161 
162 /* based on tvb_new_real_data() */
163 tvbuff_t *
frame_tvbuff_new(const struct packet_provider_data * prov,const frame_data * fd,const guint8 * buf)164 frame_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
165     const guint8 *buf)
166 {
167 	struct tvb_frame *frame_tvb;
168 	tvbuff_t *tvb;
169 
170 	tvb = tvb_new(&tvb_frame_ops);
171 
172 	/*
173 	 * XXX - currently, the length arguments in
174 	 * tvbuff structure are signed, but the captured
175 	 * and reported length values are unsigned; this means
176 	 * that length values > 2^31 - 1 will appear as
177 	 * negative lengths
178 	 *
179 	 * Captured length values that large will already
180 	 * have been filtered out by the Wiretap modules
181 	 * (the file will be reported as corrupted), to
182 	 * avoid trying to allocate large chunks of data.
183 	 *
184 	 * Reported length values will not have been
185 	 * filtered out, and should not be filtered out,
186 	 * as those lengths are not necessarily invalid.
187 	 *
188 	 * For now, we clip the reported length at G_MAXINT
189 	 *
190 	 * (XXX, is this still a problem?) There was an exception when we call
191 	 * tvb_new_real_data() now there's no one
192 	 */
193 
194 	tvb->real_data        = buf;
195 	tvb->length           = fd->cap_len;
196 	tvb->reported_length  = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
197 	tvb->contained_length = tvb->reported_length;
198 	tvb->initialized      = TRUE;
199 
200 	/*
201 	 * This is the top-level real tvbuff for this data source,
202 	 * so its data source tvbuff is itself.
203 	 */
204 	tvb->ds_tvb = tvb;
205 
206 	frame_tvb = (struct tvb_frame *) tvb;
207 
208 	/* XXX, wtap_can_seek() */
209 	if (prov->wth && prov->wth->random_fh) {
210 		frame_tvb->prov = prov;
211 		frame_tvb->file_off = fd->file_off;
212 		frame_tvb->offset = 0;
213 	} else
214 		frame_tvb->prov = NULL;
215 
216 	frame_tvb->buf = NULL;
217 
218 	return tvb;
219 }
220 
221 tvbuff_t *
frame_tvbuff_new_buffer(const struct packet_provider_data * prov,const frame_data * fd,Buffer * buf)222 frame_tvbuff_new_buffer(const struct packet_provider_data *prov,
223     const frame_data *fd, Buffer *buf)
224 {
225 	return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
226 }
227 
228 static tvbuff_t *
frame_clone(tvbuff_t * tvb,guint abs_offset,guint abs_length)229 frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
230 {
231 	struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
232 
233 	tvbuff_t *cloned_tvb;
234 	struct tvb_frame *cloned_frame_tvb;
235 
236 	/* file not seekable */
237 	if (!frame_tvb->prov)
238 		return NULL;
239 
240 	abs_offset += frame_tvb->offset;
241 
242 	cloned_tvb = tvb_new(&tvb_frame_ops);
243 
244 	/* data will be read when needed */
245 	cloned_tvb->real_data        = NULL;
246 	cloned_tvb->length           = abs_length;
247 	cloned_tvb->reported_length  = abs_length; /* XXX? */
248 	cloned_tvb->contained_length = cloned_tvb->reported_length;
249 	cloned_tvb->initialized      = TRUE;
250 
251 	/*
252 	 * This is the top-level real tvbuff for this data source,
253 	 * so its data source tvbuff is itself.
254 	 */
255 	cloned_tvb->ds_tvb = cloned_tvb;
256 
257 	cloned_frame_tvb = (struct tvb_frame *) cloned_tvb;
258 	cloned_frame_tvb->prov = frame_tvb->prov;
259 	cloned_frame_tvb->file_off = frame_tvb->file_off;
260 	cloned_frame_tvb->offset = abs_offset;
261 	cloned_frame_tvb->buf = NULL;
262 
263 	return cloned_tvb;
264 }
265 
266 
267 /* based on tvb_new_real_data() */
268 tvbuff_t *
file_tvbuff_new(const struct packet_provider_data * prov,const frame_data * fd,const guint8 * buf)269 file_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
270     const guint8 *buf)
271 {
272 	struct tvb_frame *frame_tvb;
273 	tvbuff_t *tvb;
274 
275 	tvb = tvb_new(&tvb_frame_ops);
276 
277 	/*
278 	 * XXX - currently, the length arguments in
279 	 * tvbuff structure are signed, but the captured
280 	 * and reported length values are unsigned; this means
281 	 * that length values > 2^31 - 1 will appear as
282 	 * negative lengths
283 	 *
284 	 * Captured length values that large will already
285 	 * have been filtered out by the Wiretap modules
286 	 * (the file will be reported as corrupted), to
287 	 * avoid trying to allocate large chunks of data.
288 	 *
289 	 * Reported length values will not have been
290 	 * filtered out, and should not be filtered out,
291 	 * as those lengths are not necessarily invalid.
292 	 *
293 	 * For now, we clip the reported length at G_MAXINT
294 	 *
295 	 * (XXX, is this still a problem?) There was an exception when we call
296 	 * tvb_new_real_data() now there's no one
297 	 */
298 
299 	tvb->real_data        = buf;
300 	tvb->length           = fd->cap_len;
301 	tvb->reported_length  = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
302 	tvb->contained_length = tvb->reported_length;
303 	tvb->initialized      = TRUE;
304 
305 	/*
306 	 * This is the top-level real tvbuff for this data source,
307 	 * so its data source tvbuff is itself.
308 	 */
309 	tvb->ds_tvb = tvb;
310 
311 	frame_tvb = (struct tvb_frame *) tvb;
312 
313 	/* XXX, wtap_can_seek() */
314 	if (prov->wth && prov->wth->random_fh) {
315 		frame_tvb->prov = prov;
316 		frame_tvb->file_off = fd->file_off;
317 		frame_tvb->offset = 0;
318 	} else
319 		frame_tvb->prov = NULL;
320 
321 	frame_tvb->buf = NULL;
322 
323 	return tvb;
324 }
325 
326 tvbuff_t *
file_tvbuff_new_buffer(const struct packet_provider_data * prov,const frame_data * fd,Buffer * buf)327 file_tvbuff_new_buffer(const struct packet_provider_data *prov,
328     const frame_data *fd, Buffer *buf)
329 {
330 	return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
331 }
332 
333 /*
334  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
335  *
336  * Local variables:
337  * c-basic-offset: 8
338  * tab-width: 8
339  * indent-tabs-mode: t
340  * End:
341  *
342  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
343  * :indentSize=8:tabSize=8:noTabs=false:
344  */
345