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