/src/wireshark/wiretap/i4btrace.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* i4btrace.c |
2 | | * |
3 | | * Wiretap Library |
4 | | * Copyright (c) 1999 by Bert Driehuis <driehuis@playbeing.org> |
5 | | * |
6 | | * SPDX-License-Identifier: GPL-2.0-or-later |
7 | | */ |
8 | | |
9 | | #include "config.h" |
10 | | #include "i4btrace.h" |
11 | | |
12 | | #include <stdlib.h> |
13 | | #include <string.h> |
14 | | #include "wtap-int.h" |
15 | | #include "file_wrappers.h" |
16 | | #include "i4b_trace.h" |
17 | | |
18 | | typedef struct { |
19 | | bool byte_swapped; |
20 | | } i4btrace_t; |
21 | | |
22 | | static bool i4btrace_read(wtap *wth, wtap_rec *rec, |
23 | | int *err, char **err_info, int64_t *offset); |
24 | | static bool i4btrace_seek_read(wtap *wth, int64_t seek_off, |
25 | | wtap_rec *rec, int *err, char **err_info); |
26 | | static bool i4b_read_rec(wtap *wth, FILE_T fh, wtap_rec *rec, |
27 | | int *err, char **err_info); |
28 | | |
29 | | static int i4btrace_file_type_subtype = -1; |
30 | | |
31 | | void register_i4btrace(void); |
32 | | |
33 | | /* |
34 | | * Byte-swap the header. |
35 | | */ |
36 | | #define I4B_BYTESWAP_HEADER(hdr) \ |
37 | 0 | { \ |
38 | 0 | hdr.length = GUINT32_SWAP_LE_BE(hdr.length); \ |
39 | 0 | hdr.unit = GUINT32_SWAP_LE_BE(hdr.unit); \ |
40 | 0 | hdr.type = GUINT32_SWAP_LE_BE(hdr.type); \ |
41 | 0 | hdr.dir = GUINT32_SWAP_LE_BE(hdr.dir); \ |
42 | 0 | hdr.trunc = GUINT32_SWAP_LE_BE(hdr.trunc); \ |
43 | 0 | hdr.count = GUINT32_SWAP_LE_BE(hdr.count); \ |
44 | 0 | hdr.ts_sec = GUINT32_SWAP_LE_BE(hdr.ts_sec); \ |
45 | 0 | hdr.ts_usec = GUINT32_SWAP_LE_BE(hdr.ts_usec); \ |
46 | 0 | } |
47 | | |
48 | | /* |
49 | | * Test some fields in the header to see if they make sense. |
50 | | */ |
51 | | #define I4B_HDR_IS_OK(hdr) \ |
52 | 0 | (!(hdr.length < sizeof(hdr) || \ |
53 | 0 | hdr.length > 16384 || \ |
54 | 0 | hdr.unit > 4 || \ |
55 | 0 | hdr.type > TRC_CH_B2 || \ |
56 | 0 | hdr.dir > FROM_NT || \ |
57 | 0 | hdr.trunc > 2048 || \ |
58 | 0 | hdr.ts_usec >= 1000000)) |
59 | | |
60 | | /* |
61 | | * Number of packets to try reading. |
62 | | */ |
63 | 0 | #define PACKETS_TO_CHECK 5 |
64 | | |
65 | | wtap_open_return_val i4btrace_open(wtap *wth, int *err, char **err_info) |
66 | 0 | { |
67 | 0 | i4b_trace_hdr_t hdr; |
68 | 0 | bool byte_swapped = false; |
69 | 0 | i4btrace_t *i4btrace; |
70 | | |
71 | | /* I4B trace files have no magic in the header... Sigh */ |
72 | 0 | if (!wtap_read_bytes(wth->fh, &hdr, sizeof(hdr), err, err_info)) { |
73 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
74 | 0 | return WTAP_OPEN_ERROR; |
75 | 0 | return WTAP_OPEN_NOT_MINE; |
76 | 0 | } |
77 | | |
78 | | /* Silly heuristic... */ |
79 | 0 | if (!I4B_HDR_IS_OK(hdr)) { |
80 | | /* |
81 | | * OK, try byte-swapping the header fields. |
82 | | */ |
83 | 0 | I4B_BYTESWAP_HEADER(hdr); |
84 | 0 | if (!I4B_HDR_IS_OK(hdr)) { |
85 | | /* |
86 | | * It doesn't look valid in either byte order. |
87 | | */ |
88 | 0 | return WTAP_OPEN_NOT_MINE; |
89 | 0 | } |
90 | | |
91 | | /* |
92 | | * It looks valid byte-swapped, so assume it's a |
93 | | * trace written in the opposite byte order. |
94 | | */ |
95 | 0 | byte_swapped = true; |
96 | 0 | } |
97 | | |
98 | | /* |
99 | | * Now try to read past the packet bytes; if that fails with |
100 | | * a short read, we don't fail, so that we can report |
101 | | * the file as a truncated I4B file. |
102 | | */ |
103 | 0 | if (!wtap_read_bytes(wth->fh, NULL, hdr.length - (uint32_t)sizeof(hdr), |
104 | 0 | err, err_info)) { |
105 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
106 | 0 | return WTAP_OPEN_ERROR; |
107 | 0 | } else { |
108 | | /* |
109 | | * Now try reading a few more packets. |
110 | | */ |
111 | 0 | for (int i = 1; i < PACKETS_TO_CHECK; i++) { |
112 | | /* |
113 | | * Read and check the file header; we've already |
114 | | * decided whether this would be a byte-swapped file |
115 | | * or not, so we swap iff we decided it was. |
116 | | */ |
117 | 0 | if (!wtap_read_bytes_or_eof(wth->fh, &hdr, sizeof(hdr), err, |
118 | 0 | err_info)) { |
119 | 0 | if (*err == 0) { |
120 | | /* EOF; no more packets to try. */ |
121 | 0 | break; |
122 | 0 | } |
123 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
124 | 0 | return WTAP_OPEN_ERROR; |
125 | 0 | return WTAP_OPEN_NOT_MINE; |
126 | 0 | } |
127 | | |
128 | 0 | if (byte_swapped) |
129 | 0 | I4B_BYTESWAP_HEADER(hdr); |
130 | 0 | if (!I4B_HDR_IS_OK(hdr)) { |
131 | | /* |
132 | | * It doesn't look valid. |
133 | | */ |
134 | 0 | return WTAP_OPEN_NOT_MINE; |
135 | 0 | } |
136 | | |
137 | | /* |
138 | | * Now try to read past the packet bytes; if that |
139 | | * fails with a short read, we don't fail, so that |
140 | | * we can report the file as a truncated I4B file. |
141 | | */ |
142 | 0 | if (!wtap_read_bytes(wth->fh, NULL, |
143 | 0 | hdr.length - (uint32_t)sizeof(hdr), err, err_info)) { |
144 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
145 | 0 | return WTAP_OPEN_ERROR; |
146 | | |
147 | | /* |
148 | | * Probably a truncated file, so just quit. |
149 | | */ |
150 | 0 | break; |
151 | 0 | } |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | 0 | if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) |
156 | 0 | return WTAP_OPEN_ERROR; |
157 | | |
158 | | /* Get capture start time */ |
159 | | |
160 | 0 | wth->file_type_subtype = i4btrace_file_type_subtype; |
161 | 0 | i4btrace = g_new(i4btrace_t, 1); |
162 | 0 | wth->priv = (void *)i4btrace; |
163 | 0 | wth->subtype_read = i4btrace_read; |
164 | 0 | wth->subtype_seek_read = i4btrace_seek_read; |
165 | 0 | wth->snapshot_length = 0; /* not known */ |
166 | |
|
167 | 0 | i4btrace->byte_swapped = byte_swapped; |
168 | |
|
169 | 0 | wth->file_encap = WTAP_ENCAP_ISDN; |
170 | 0 | wth->file_tsprec = WTAP_TSPREC_USEC; |
171 | | |
172 | | /* |
173 | | * Add an IDB; we don't know how many interfaces were |
174 | | * involved, so we just say one interface, about which |
175 | | * we only know the link-layer type, snapshot length, |
176 | | * and time stamp resolution. |
177 | | */ |
178 | 0 | wtap_add_generated_idb(wth); |
179 | |
|
180 | 0 | return WTAP_OPEN_MINE; |
181 | 0 | } |
182 | | |
183 | | /* Read the next packet */ |
184 | | static bool i4btrace_read(wtap *wth, wtap_rec *rec, |
185 | | int *err, char **err_info, int64_t *data_offset) |
186 | 0 | { |
187 | 0 | *data_offset = file_tell(wth->fh); |
188 | |
|
189 | 0 | return i4b_read_rec(wth, wth->fh, rec, err, err_info); |
190 | 0 | } |
191 | | |
192 | | static bool |
193 | | i4btrace_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, |
194 | | int *err, char **err_info) |
195 | 0 | { |
196 | 0 | if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) |
197 | 0 | return false; |
198 | | |
199 | 0 | if (!i4b_read_rec(wth, wth->random_fh, rec, err, err_info)) { |
200 | | /* Read error or EOF */ |
201 | 0 | if (*err == 0) { |
202 | | /* EOF means "short read" in random-access mode */ |
203 | 0 | *err = WTAP_ERR_SHORT_READ; |
204 | 0 | } |
205 | 0 | return false; |
206 | 0 | } |
207 | 0 | return true; |
208 | 0 | } |
209 | | |
210 | | static bool |
211 | | i4b_read_rec(wtap *wth, FILE_T fh, wtap_rec *rec, int *err, char **err_info) |
212 | 0 | { |
213 | 0 | i4btrace_t *i4btrace = (i4btrace_t *)wth->priv; |
214 | 0 | i4b_trace_hdr_t hdr; |
215 | 0 | uint32_t length; |
216 | |
|
217 | 0 | if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info)) |
218 | 0 | return false; |
219 | | |
220 | 0 | if (i4btrace->byte_swapped) { |
221 | | /* |
222 | | * Byte-swap the header. |
223 | | */ |
224 | 0 | I4B_BYTESWAP_HEADER(hdr); |
225 | 0 | } |
226 | |
|
227 | 0 | if (hdr.length < sizeof(hdr)) { |
228 | 0 | *err = WTAP_ERR_BAD_FILE; /* record length < header! */ |
229 | 0 | *err_info = ws_strdup_printf("i4btrace: record length %u < header length %lu", |
230 | 0 | hdr.length, (unsigned long)sizeof(hdr)); |
231 | 0 | return false; |
232 | 0 | } |
233 | 0 | length = hdr.length - (uint32_t)sizeof(hdr); |
234 | 0 | if (length > WTAP_MAX_PACKET_SIZE_STANDARD) { |
235 | | /* |
236 | | * Probably a corrupt capture file; don't blow up trying |
237 | | * to allocate space for an immensely-large packet. |
238 | | */ |
239 | 0 | *err = WTAP_ERR_BAD_FILE; |
240 | 0 | *err_info = ws_strdup_printf("i4btrace: File has %u-byte packet, bigger than maximum of %u", |
241 | 0 | length, WTAP_MAX_PACKET_SIZE_STANDARD); |
242 | 0 | return false; |
243 | 0 | } |
244 | | |
245 | 0 | rec->rec_type = REC_TYPE_PACKET; |
246 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
247 | 0 | rec->presence_flags = WTAP_HAS_TS; |
248 | |
|
249 | 0 | rec->rec_header.packet_header.len = length; |
250 | 0 | rec->rec_header.packet_header.caplen = length; |
251 | |
|
252 | 0 | rec->ts.secs = hdr.ts_sec; |
253 | 0 | rec->ts.nsecs = hdr.ts_usec * 1000; |
254 | |
|
255 | 0 | switch (hdr.type) { |
256 | | |
257 | 0 | case TRC_CH_I: |
258 | | /* |
259 | | * XXX - what is it? It's probably not WTAP_ENCAP_NULL, |
260 | | * as that means it has a 4-byte AF_ type as the |
261 | | * encapsulation header. |
262 | | */ |
263 | 0 | rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_NULL; |
264 | 0 | break; |
265 | | |
266 | 0 | case TRC_CH_D: |
267 | | /* |
268 | | * D channel, so it's LAPD; set "p2p.sent". |
269 | | */ |
270 | 0 | rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ISDN; |
271 | 0 | rec->rec_header.packet_header.pseudo_header.isdn.channel = 0; |
272 | 0 | break; |
273 | | |
274 | 0 | case TRC_CH_B1: |
275 | | /* |
276 | | * B channel 1. |
277 | | */ |
278 | 0 | rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ISDN; |
279 | 0 | rec->rec_header.packet_header.pseudo_header.isdn.channel = 1; |
280 | 0 | break; |
281 | | |
282 | 0 | case TRC_CH_B2: |
283 | | /* |
284 | | * B channel 2. |
285 | | */ |
286 | 0 | rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ISDN; |
287 | 0 | rec->rec_header.packet_header.pseudo_header.isdn.channel = 2; |
288 | 0 | break; |
289 | 0 | } |
290 | | |
291 | 0 | rec->rec_header.packet_header.pseudo_header.isdn.uton = (hdr.dir == FROM_TE); |
292 | | |
293 | | /* |
294 | | * Read the packet data. |
295 | | */ |
296 | 0 | return wtap_read_bytes_buffer(fh, &rec->data, length, err, err_info); |
297 | 0 | } |
298 | | |
299 | | static const struct supported_block_type i4btrace_blocks_supported[] = { |
300 | | /* |
301 | | * We support packet blocks, with no comments or other options. |
302 | | */ |
303 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
304 | | }; |
305 | | |
306 | | static const struct file_type_subtype_info i4btrace_info = { |
307 | | "I4B ISDN trace", "i4btrace", NULL, NULL, |
308 | | false, BLOCKS_SUPPORTED(i4btrace_blocks_supported), |
309 | | NULL, NULL, NULL |
310 | | }; |
311 | | |
312 | | void register_i4btrace(void) |
313 | 2 | { |
314 | 2 | i4btrace_file_type_subtype = wtap_register_file_type_subtype(&i4btrace_info); |
315 | | |
316 | | /* |
317 | | * Register name for backwards compatibility with the |
318 | | * wtap_filetypes table in Lua. |
319 | | */ |
320 | 2 | wtap_register_backwards_compatibility_lua_name("I4BTRACE", |
321 | 2 | i4btrace_file_type_subtype); |
322 | 2 | } |
323 | | |
324 | | /* |
325 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
326 | | * |
327 | | * Local variables: |
328 | | * c-basic-offset: 8 |
329 | | * tab-width: 8 |
330 | | * indent-tabs-mode: t |
331 | | * End: |
332 | | * |
333 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
334 | | * :indentSize=8:tabSize=8:noTabs=false: |
335 | | */ |