Coverage Report

Created: 2025-04-03 08:46

/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
 */