Coverage Report

Created: 2026-03-30 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/iptrace.c
Line
Count
Source
1
/* iptrace.c
2
 *
3
 * Wiretap Library
4
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5
 *
6
 * SPDX-License-Identifier: GPL-2.0-or-later
7
 *
8
 */
9
#include "config.h"
10
#include "iptrace.h"
11
12
#include <stdlib.h>
13
#include <string.h>
14
15
#include <wsutil/array.h>
16
#include <wsutil/pint.h>
17
18
#include "wtap_module.h"
19
#include "file_wrappers.h"
20
#include "atm.h"
21
22
/*
23
 * iptrace is the capture program that comes with AIX 3.x and 4.x.  AIX 3 uses
24
 * the iptrace 1.0 file format, while AIX4 uses iptrace 2.0.  iptrace has
25
 * an undocumented, yet very simple, file format.  The interesting thing
26
 * about iptrace is that it will record packets coming in from all network
27
 * interfaces; a single iptrace file can contain multiple datalink types.
28
*/
29
30
/*
31
 * Private per-wtap_t data needed to read a file.
32
 */
33
typedef struct {
34
  GHashTable *interface_ids;  /* map name/description/link-layer type to interface ID */
35
  unsigned num_interface_ids; /* Number of interface IDs assigned */
36
} iptrace_t;
37
38
0
#define IPTRACE_IFT_HF  0x3d    /* Support for PERCS IP-HFI*/
39
0
#define IPTRACE_IFT_IB  0xc7    /* IP over Infiniband. Number by IANA */
40
41
static void iptrace_close(wtap *wth);
42
43
static bool iptrace_read_1_0(wtap *wth, wtap_rec *rec,
44
    int *err, char **err_info, int64_t *data_offset);
45
static bool iptrace_seek_read_1_0(wtap *wth, int64_t seek_off,
46
    wtap_rec *rec, int *err, char **err_info);
47
48
static bool iptrace_read_2_0(wtap *wth, wtap_rec *rec,
49
    int *err, char **err_info, int64_t *data_offset);
50
static bool iptrace_seek_read_2_0(wtap *wth, int64_t seek_off,
51
    wtap_rec *rec, int *err, char **err_info);
52
53
static bool iptrace_read_rec_data(FILE_T fh,
54
    wtap_rec *rec, int *err, char **err_info);
55
static void fill_in_pseudo_header(int encap,
56
    union wtap_pseudo_header *pseudo_header, const char *pkt_text);
57
static int wtap_encap_ift(unsigned int  ift);
58
59
/*
60
 * Size of the version string in the file header.
61
 */
62
0
#define VERSION_STRING_SIZE 11
63
64
/*
65
 * Hash table to map interface name and description, and link-layer
66
 * type, to interface ID.
67
 */
68
0
#define PREFIX_SIZE   4
69
70
typedef struct {
71
  char prefix[PREFIX_SIZE+1];
72
  uint8_t unit;
73
  uint8_t if_type;
74
} if_info;
75
76
static int iptrace_1_0_file_type_subtype = -1;
77
static int iptrace_2_0_file_type_subtype = -1;
78
79
void register_iptrace(void);
80
81
static gboolean destroy_if_info(void *key, void *value _U_,
82
    void *user_data _U_)
83
0
{
84
0
  if_info *info = (if_info *)key;
85
86
0
  g_free(info);
87
88
0
  return true;
89
0
}
90
91
static unsigned if_info_hash(const void *info_arg)
92
0
{
93
0
  if_info *info = (if_info *)info_arg;
94
95
0
  return g_str_hash(info->prefix) + info->unit + info->if_type;
96
0
}
97
98
static gboolean if_info_equal(const void *info1_arg, const void *info2_arg)
99
0
{
100
0
  if_info *info1 = (if_info *)info1_arg;
101
0
  if_info *info2 = (if_info *)info2_arg;
102
103
0
  return strcmp(info1->prefix, info2->prefix) == 0 &&
104
0
         info1->unit == info2->unit &&
105
0
         info1->if_type == info2->if_type;
106
0
}
107
108
wtap_open_return_val iptrace_open(wtap *wth, int *err, char **err_info)
109
0
{
110
0
  char version_string[VERSION_STRING_SIZE+1];
111
0
  iptrace_t *iptrace;
112
113
0
  if (!wtap_read_bytes(wth->fh, version_string, VERSION_STRING_SIZE,
114
0
      err, err_info)) {
115
0
    if (*err != WTAP_ERR_SHORT_READ)
116
0
      return WTAP_OPEN_ERROR;
117
0
    return WTAP_OPEN_NOT_MINE;
118
0
  }
119
0
  version_string[VERSION_STRING_SIZE] = '\0';
120
121
0
  if (strcmp(version_string, "iptrace 1.0") == 0) {
122
0
    wth->file_type_subtype = iptrace_1_0_file_type_subtype;
123
0
    wth->subtype_read = iptrace_read_1_0;
124
0
    wth->subtype_seek_read = iptrace_seek_read_1_0;
125
0
    wth->file_tsprec = WTAP_TSPREC_SEC;
126
0
  }
127
0
  else if (strcmp(version_string, "iptrace 2.0") == 0) {
128
0
    wth->file_type_subtype = iptrace_2_0_file_type_subtype;
129
0
    wth->subtype_read = iptrace_read_2_0;
130
0
    wth->subtype_seek_read = iptrace_seek_read_2_0;
131
0
    wth->file_tsprec = WTAP_TSPREC_NSEC;
132
0
  }
133
0
  else {
134
0
    return WTAP_OPEN_NOT_MINE;
135
0
  }
136
137
  /* This is an iptrace file */
138
0
  wth->subtype_close = iptrace_close;
139
0
  iptrace = g_new(iptrace_t, 1);
140
0
  iptrace->interface_ids = g_hash_table_new(if_info_hash, if_info_equal);
141
0
  iptrace->num_interface_ids = 0;
142
0
  wth->priv = (void *)iptrace;
143
144
0
  return WTAP_OPEN_MINE;
145
0
}
146
147
static void iptrace_close(wtap *wth)
148
0
{
149
0
  iptrace_t *iptrace = (iptrace_t *)wth->priv;
150
151
0
  g_hash_table_foreach_remove(iptrace->interface_ids, destroy_if_info, NULL);
152
0
  g_hash_table_destroy(iptrace->interface_ids);
153
0
}
154
155
static void add_new_if_info(iptrace_t *iptrace, if_info *info, void * *result)
156
0
{
157
0
  if_info *new_info = g_new(if_info, 1);
158
0
  *new_info = *info;
159
0
  *result = GUINT_TO_POINTER(iptrace->num_interface_ids);
160
0
  g_hash_table_insert(iptrace->interface_ids, (void *)new_info, *result);
161
0
  iptrace->num_interface_ids++;
162
0
}
163
164
/***********************************************************
165
 * iptrace 1.0                                             *
166
 ***********************************************************/
167
168
/*
169
 * iptrace 1.0, discovered through inspection
170
 *
171
 * Packet record contains:
172
 *
173
 *  an initial header, with a length field and a time stamp, in
174
 *  seconds since the Epoch;
175
 *
176
 *  data, with the specified length.
177
 *
178
 * The data contains:
179
 *
180
 *  a bunch of information about the packet;
181
 *
182
 *  padding, at least for FDDI;
183
 *
184
 *  the raw packet data.
185
 */
186
187
/*
188
 * Offsets of fields in the initial header.
189
 */
190
0
#define IPTRACE_1_0_REC_LENGTH_OFFSET 0  /* 0-3: size of record data */
191
0
#define IPTRACE_1_0_TV_SEC_OFFSET 4  /* 4-7: time stamp, seconds since the Epoch */
192
193
0
#define IPTRACE_1_0_PHDR_SIZE 8  /* initial header */
194
195
/*
196
 * Offsets of fields in the packet information.
197
 */
198
/* Bytes 0-2 unknown */
199
0
#define IPTRACE_1_0_UNIT_OFFSET   3  /* 3: interface unit number */
200
0
#define IPTRACE_1_0_PREFIX_OFFSET 4  /* 4-7: null-terminated name prefix */
201
0
#define IPTRACE_1_0_PKT_TEXT_OFFSET 8  /* 8-19: text in 2.0; what is it in 1.0? */
202
0
#define IPTRACE_1_0_IF_TYPE_OFFSET  20  /* 20: SNMP ifType value */
203
0
#define IPTRACE_1_0_TX_FLAGS_OFFSET 21  /* 21: 0=receive, 1=transmit */
204
205
0
#define IPTRACE_1_0_PINFO_SIZE  22  /* packet information */
206
207
static bool
208
iptrace_read_rec_1_0(wtap *wth, FILE_T fh, wtap_rec *rec,
209
    int *err, char **err_info)
210
0
{
211
0
  iptrace_t   *iptrace = (iptrace_t *)wth->priv;
212
0
  uint8_t     header[IPTRACE_1_0_PHDR_SIZE];
213
0
  uint32_t    record_length;
214
0
  uint8_t     pkt_info[IPTRACE_1_0_PINFO_SIZE];
215
0
  if_info     info;
216
0
  uint32_t    packet_size;
217
0
  void      *result;
218
219
0
  if (!wtap_read_bytes_or_eof(fh, header, IPTRACE_1_0_PHDR_SIZE, err,
220
0
      err_info)) {
221
    /* Read error or EOF */
222
0
    return false;
223
0
  }
224
225
  /* Get the record length */
226
0
  record_length = pntohu32(&header[IPTRACE_1_0_REC_LENGTH_OFFSET]);
227
0
  if (record_length < IPTRACE_1_0_PINFO_SIZE) {
228
    /*
229
     * Uh-oh, the record isn't big enough to even have a
230
     * packet information header.
231
     */
232
0
    *err = WTAP_ERR_BAD_FILE;
233
0
    *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet information header",
234
0
        record_length);
235
0
    return false;
236
0
  }
237
238
  /*
239
   * Get the packet information.
240
   */
241
0
  if (!wtap_read_bytes(fh, pkt_info, IPTRACE_1_0_PINFO_SIZE, err,
242
0
      err_info)) {
243
    /* Read error or EOF */
244
0
    return false;
245
0
  }
246
247
0
  wtap_setup_packet_rec(rec, wth->file_encap);
248
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
249
250
  /*
251
   * The if_type field of the frame header appears to be an SNMP
252
   * ifType value giving the type of the interface.  Check out the
253
   * <net/if_types.h> header file.
254
   */
255
0
  info.if_type = pkt_info[IPTRACE_1_0_IF_TYPE_OFFSET];
256
0
  rec->rec_header.packet_header.pkt_encap = wtap_encap_ift(info.if_type);
257
0
  if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_UNKNOWN) {
258
0
    *err = WTAP_ERR_UNSUPPORTED;
259
0
    *err_info = ws_strdup_printf("iptrace: interface type IFT=0x%02x unknown or unsupported",
260
0
        info.if_type);
261
0
    return false;
262
0
  }
263
264
  /* Get the packet data size */
265
0
  packet_size = record_length - IPTRACE_1_0_PINFO_SIZE;
266
267
  /*
268
   * AIX appears to put 3 bytes of padding in front of FDDI
269
   * frames; strip that crap off.
270
   */
271
0
  if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_FDDI_BITSWAPPED) {
272
    /*
273
     * The packet size is really a record size and includes
274
     * the padding.
275
     */
276
0
    if (packet_size < 3) {
277
      /*
278
       * Uh-oh, the record isn't big enough to even have
279
       * the padding.
280
       */
281
0
      *err = WTAP_ERR_BAD_FILE;
282
0
      *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet meta-data header",
283
0
          record_length);
284
0
      return false;
285
0
    }
286
0
    packet_size -= 3;
287
288
    /*
289
     * Skip the padding.
290
     */
291
0
    if (!wtap_read_bytes(fh, NULL, 3, err, err_info))
292
0
      return false;
293
0
  }
294
0
  if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
295
    /*
296
     * Probably a corrupt capture file; don't blow up trying
297
     * to allocate space for an immensely-large packet.
298
     */
299
0
    *err = WTAP_ERR_BAD_FILE;
300
0
    *err_info = ws_strdup_printf("iptrace: File has %u-byte packet, bigger than maximum of %u",
301
0
        packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
302
0
    return false;
303
0
  }
304
305
0
  rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_INTERFACE_ID;
306
0
  rec->rec_header.packet_header.len = packet_size;
307
0
  rec->rec_header.packet_header.caplen = packet_size;
308
0
  rec->ts.secs = pntohu32(&header[IPTRACE_1_0_TV_SEC_OFFSET]);
309
0
  rec->ts.nsecs = 0;
310
0
  wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS,
311
0
      pkt_info[IPTRACE_1_0_TX_FLAGS_OFFSET] ?
312
0
        (PACK_FLAGS_DIRECTION_OUTBOUND << PACK_FLAGS_DIRECTION_SHIFT) :
313
0
        (PACK_FLAGS_DIRECTION_INBOUND << PACK_FLAGS_DIRECTION_SHIFT));
314
315
  /* Fill in the pseudo-header. */
316
0
  fill_in_pseudo_header(rec->rec_header.packet_header.pkt_encap,
317
0
      &rec->rec_header.packet_header.pseudo_header,
318
0
      (const char *)&pkt_info[IPTRACE_1_0_PKT_TEXT_OFFSET]);
319
320
  /* Get the packet data */
321
0
  if (!iptrace_read_rec_data(fh, rec, err, err_info))
322
0
    return false;
323
324
  /*
325
   * No errors - get the interface ID.
326
   *
327
   * We do *not* trust the name to be null-terminated.
328
   */
329
0
  memcpy(info.prefix, &pkt_info[IPTRACE_1_0_PREFIX_OFFSET],
330
0
      sizeof info.prefix);
331
0
  info.prefix[PREFIX_SIZE] = '\0';
332
0
  info.unit = pkt_info[IPTRACE_1_0_UNIT_OFFSET];
333
334
  /*
335
   * Try to find the entry with that name, description, and
336
   * interface type.
337
   */
338
0
  if (!g_hash_table_lookup_extended(iptrace->interface_ids,
339
0
      (const void *)&info, NULL, &result)) {
340
0
    wtap_block_t int_data;
341
0
    wtapng_if_descr_mandatory_t *int_data_mand;
342
343
    /*
344
     * Not found; make a new entry.
345
     */
346
0
    add_new_if_info(iptrace, &info, &result);
347
348
    /*
349
     * Now make a new IDB and add it.
350
     */
351
0
    int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
352
0
    int_data_mand = (wtapng_if_descr_mandatory_t *)wtap_block_get_mandatory_data(int_data);
353
354
0
    int_data_mand->wtap_encap = rec->rec_header.packet_header.pkt_encap;
355
0
    int_data_mand->tsprecision = WTAP_TSPREC_SEC;
356
0
    int_data_mand->time_units_per_second = 1; /* No fractional time stamp */
357
0
    int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD; /* XXX - not known */
358
359
0
    wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL, 0); /* 1-second resolution */
360
    /* Interface statistics */
361
0
    int_data_mand->num_stat_entries = 0;
362
0
    int_data_mand->interface_statistics = NULL;
363
364
0
    wtap_block_set_string_option_value_format(int_data,
365
0
        OPT_IDB_NAME, "%s%u", info.prefix, info.unit);
366
0
    wtap_add_idb(wth, int_data);
367
0
  }
368
0
  rec->rec_header.packet_header.interface_id = GPOINTER_TO_UINT(result);
369
0
  return true;
370
0
}
371
372
/* Read the next packet */
373
static bool iptrace_read_1_0(wtap *wth, wtap_rec *rec,
374
    int *err, char **err_info, int64_t *data_offset)
375
0
{
376
0
  *data_offset = file_tell(wth->fh);
377
378
  /* Read the packet */
379
0
  if (!iptrace_read_rec_1_0(wth, wth->fh, rec, err, err_info)) {
380
    /* Read error or EOF */
381
0
    return false;
382
0
  }
383
384
  /* If the per-file encapsulation isn't known, set it to this
385
     packet's encapsulation.
386
387
     If it *is* known, and it isn't this packet's encapsulation,
388
     set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
389
     have a single encapsulation for all packets in the file. */
390
0
  if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
391
0
    wth->file_encap = rec->rec_header.packet_header.pkt_encap;
392
0
  else {
393
0
    if (wth->file_encap != rec->rec_header.packet_header.pkt_encap)
394
0
      wth->file_encap = WTAP_ENCAP_PER_PACKET;
395
0
  }
396
397
0
  return true;
398
0
}
399
400
static bool iptrace_seek_read_1_0(wtap *wth, int64_t seek_off,
401
    wtap_rec *rec, int *err, char **err_info)
402
0
{
403
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
404
0
    return false;
405
406
  /* Read the packet */
407
0
  if (!iptrace_read_rec_1_0(wth, wth->random_fh, rec, err,
408
0
      err_info)) {
409
0
    if (*err == 0)
410
0
      *err = WTAP_ERR_SHORT_READ;
411
0
    return false;
412
0
  }
413
0
  return true;
414
0
}
415
416
/***********************************************************
417
 * iptrace 2.0                                             *
418
 ***********************************************************/
419
420
/*
421
 * iptrace 2.0, discovered through inspection
422
 *
423
 * Packet record contains:
424
 *
425
 *  an initial header, with a length field and a time stamp, in
426
 *  seconds since the Epoch;
427
 *
428
 *  data, with the specified length.
429
 *
430
 * The data contains:
431
 *
432
 *  a bunch of information about the packet;
433
 *
434
 *  padding, at least for FDDI;
435
 *
436
 *  the raw packet data.
437
 */
438
439
/*
440
 * Offsets of fields in the initial header.
441
 */
442
0
#define IPTRACE_2_0_REC_LENGTH_OFFSET 0  /* 0-3: size of record data */
443
#define IPTRACE_2_0_TV_SEC0_OFFSET  4 /* 4-7: time stamp, seconds since the Epoch */
444
445
0
#define IPTRACE_2_0_PHDR_SIZE 8  /* initial header */
446
447
/*
448
 * Offsets of fields in the packet information.
449
 */
450
/* Bytes 0-2 unknown */
451
0
#define IPTRACE_2_0_UNIT_OFFSET   3  /* 3: interface unit number */
452
0
#define IPTRACE_2_0_PREFIX_OFFSET 4  /* 4-7: null-terminated name prefix */
453
#define IPTRACE_2_0_PKT_TEXT_OFFSET 8 /* 8-19: text stuff */
454
0
#define IPTRACE_2_0_IF_TYPE_OFFSET  20  /* 20: SNMP ifType value */
455
0
#define IPTRACE_2_0_TX_FLAGS_OFFSET 21  /* 21: 0=receive, 1=transmit */
456
/* Bytes 22-23 unknown */
457
0
#define IPTRACE_2_0_TV_SEC_OFFSET 24  /* 24-27: time stamp, seconds since the Epoch */
458
0
#define IPTRACE_2_0_TV_NSEC_OFFSET  28  /* 28-31: nanoseconds since that second */
459
460
0
#define IPTRACE_2_0_PINFO_SIZE  32  /* packet information */
461
462
static bool
463
iptrace_read_rec_2_0(wtap *wth, FILE_T fh, wtap_rec *rec,
464
    int *err, char **err_info)
465
0
{
466
0
  iptrace_t   *iptrace = (iptrace_t *)wth->priv;
467
0
  uint8_t     header[IPTRACE_2_0_PHDR_SIZE];
468
0
  uint32_t    record_length;
469
0
  uint8_t     pkt_info[IPTRACE_2_0_PINFO_SIZE];
470
0
  if_info     info;
471
0
  uint32_t    packet_size;
472
0
  void      *result;
473
474
0
  if (!wtap_read_bytes_or_eof(fh, header, IPTRACE_2_0_PHDR_SIZE, err,
475
0
      err_info)) {
476
    /* Read error or EOF */
477
0
    return false;
478
0
  }
479
480
  /* Get the record length */
481
0
  record_length = pntohu32(&header[IPTRACE_2_0_REC_LENGTH_OFFSET]);
482
0
  if (record_length < IPTRACE_2_0_PINFO_SIZE) {
483
    /*
484
     * Uh-oh, the record isn't big enough to even have a
485
     * packet information header.
486
     */
487
0
    *err = WTAP_ERR_BAD_FILE;
488
0
    *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet information header",
489
0
        record_length);
490
0
    return false;
491
0
  }
492
493
  /*
494
   * Get the packet information.
495
   */
496
0
  if (!wtap_read_bytes(fh, pkt_info, IPTRACE_2_0_PINFO_SIZE, err,
497
0
      err_info)) {
498
    /* Read error or EOF */
499
0
    return false;
500
0
  }
501
502
0
  wtap_setup_packet_rec(rec, wth->file_encap);
503
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
504
505
  /*
506
   * The if_type field of the frame header appears to be an SNMP
507
   * ifType value giving the type of the interface.  Check out the
508
   * <net/if_types.h> header file.
509
   */
510
0
  info.if_type = pkt_info[IPTRACE_2_0_IF_TYPE_OFFSET];
511
0
  rec->rec_header.packet_header.pkt_encap = wtap_encap_ift(info.if_type);
512
#if 0
513
  /*
514
   * We used to error out if the interface type in iptrace was
515
   * unknown/unhandled, but an iptrace may contain packets
516
   * from a variety of interfaces, some known, and others
517
   * unknown.
518
   *
519
   * It is better to display the data even for unknown interface
520
   * types, instead of erroring out. In the future, it would be
521
   * nice to be able to flag which frames are shown as data
522
   * because their interface type is unknown, and also present
523
   * the interface type number to the user so that it can be
524
   * reported easily back to the Wireshark developer.
525
   *
526
   * XXX - what types are there that are used in files but
527
   * that we don't handle?
528
   */
529
  if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_UNKNOWN) {
530
    *err = WTAP_ERR_UNSUPPORTED;
531
    *err_info = ws_strdup_printf("iptrace: interface type IFT=0x%02x unknown or unsupported",
532
        info.if_type);
533
    return false;
534
  }
535
#endif
536
537
  /* Get the packet data size */
538
0
  packet_size = record_length - IPTRACE_2_0_PINFO_SIZE;
539
540
  /*
541
   * AIX appears to put 3 bytes of padding in front of FDDI
542
   * frames; strip that crap off.
543
   */
544
0
  if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_FDDI_BITSWAPPED) {
545
    /*
546
     * The packet size is really a record size and includes
547
     * the padding.
548
     */
549
0
    if (packet_size < 3) {
550
      /*
551
       * Uh-oh, the record isn't big enough to even have
552
       * the padding.
553
       */
554
0
      *err = WTAP_ERR_BAD_FILE;
555
0
      *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet meta-data header",
556
0
          record_length);
557
0
      return false;
558
0
    }
559
0
    packet_size -= 3;
560
561
    /*
562
     * Skip the padding.
563
     */
564
0
    if (!wtap_read_bytes(fh, NULL, 3, err, err_info))
565
0
      return false;
566
0
  }
567
0
  if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
568
    /*
569
     * Probably a corrupt capture file; don't blow up trying
570
     * to allocate space for an immensely-large packet.
571
     */
572
0
    *err = WTAP_ERR_BAD_FILE;
573
0
    *err_info = ws_strdup_printf("iptrace: File has %u-byte packet, bigger than maximum of %u",
574
0
        packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
575
0
    return false;
576
0
  }
577
578
0
  rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_INTERFACE_ID;
579
0
  rec->rec_header.packet_header.len = packet_size;
580
0
  rec->rec_header.packet_header.caplen = packet_size;
581
0
  rec->ts.secs = pntohu32(&pkt_info[IPTRACE_2_0_TV_SEC_OFFSET]);
582
0
  rec->ts.nsecs = pntohu32(&pkt_info[IPTRACE_2_0_TV_NSEC_OFFSET]);
583
0
  wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS,
584
0
      pkt_info[IPTRACE_2_0_TX_FLAGS_OFFSET] ?
585
0
        (PACK_FLAGS_DIRECTION_OUTBOUND << PACK_FLAGS_DIRECTION_SHIFT) :
586
0
        (PACK_FLAGS_DIRECTION_INBOUND << PACK_FLAGS_DIRECTION_SHIFT));
587
588
  /* Fill in the pseudo-header. */
589
0
  fill_in_pseudo_header(rec->rec_header.packet_header.pkt_encap,
590
0
      &rec->rec_header.packet_header.pseudo_header,
591
0
      (const char *)&pkt_info[IPTRACE_1_0_PKT_TEXT_OFFSET]);
592
593
  /* Get the packet data */
594
0
  if (!iptrace_read_rec_data(fh, rec, err, err_info))
595
0
    return false;
596
597
  /*
598
   * No errors - get the interface ID.
599
   *
600
   * We do *not* trust the name to be null-terminated.
601
   */
602
0
  memcpy(info.prefix, &pkt_info[IPTRACE_2_0_PREFIX_OFFSET],
603
0
      sizeof info.prefix);
604
0
  info.prefix[PREFIX_SIZE] = '\0';
605
0
  info.unit = pkt_info[IPTRACE_2_0_UNIT_OFFSET];
606
607
  /*
608
   * Try to find the entry with that name, description, and
609
   * interface type.
610
   */
611
0
  if (!g_hash_table_lookup_extended(iptrace->interface_ids,
612
0
      (const void *)&info, NULL, &result)) {
613
0
    wtap_block_t int_data;
614
0
    wtapng_if_descr_mandatory_t *int_data_mand;
615
616
    /*
617
     * Not found; make a new entry.
618
     */
619
0
    add_new_if_info(iptrace, &info, &result);
620
621
    /*
622
     * Now make a new IDB and add it.
623
     */
624
0
    int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
625
0
    int_data_mand = (wtapng_if_descr_mandatory_t *)wtap_block_get_mandatory_data(int_data);
626
627
0
    int_data_mand->wtap_encap = rec->rec_header.packet_header.pkt_encap;
628
0
    int_data_mand->tsprecision = WTAP_TSPREC_NSEC;
629
0
    int_data_mand->time_units_per_second = 1000000000; /* Nanosecond resolution */
630
0
    int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD; /* XXX - not known */
631
632
0
    wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL, 0x09); /* nanosecond resolution */
633
    /* Interface statistics */
634
0
    int_data_mand->num_stat_entries = 0;
635
0
    int_data_mand->interface_statistics = NULL;
636
637
0
    wtap_block_set_string_option_value_format(int_data,
638
0
        OPT_IDB_NAME, "%s%u", info.prefix, info.unit);
639
0
    wtap_add_idb(wth, int_data);
640
0
  }
641
0
  rec->rec_header.packet_header.interface_id = GPOINTER_TO_UINT(result);
642
0
  return true;
643
0
}
644
645
/* Read the next packet */
646
static bool iptrace_read_2_0(wtap *wth, wtap_rec *rec,
647
    int *err, char **err_info, int64_t *data_offset)
648
0
{
649
0
  *data_offset = file_tell(wth->fh);
650
651
  /* Read the packet */
652
0
  if (!iptrace_read_rec_2_0(wth, wth->fh, rec, err, err_info)) {
653
    /* Read error or EOF */
654
0
    return false;
655
0
  }
656
657
  /* If the per-file encapsulation isn't known, set it to this
658
     packet's encapsulation.
659
660
     If it *is* known, and it isn't this packet's encapsulation,
661
     set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
662
     have a single encapsulation for all packets in the file. */
663
0
  if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
664
0
    wth->file_encap = rec->rec_header.packet_header.pkt_encap;
665
0
  else {
666
0
    if (wth->file_encap != rec->rec_header.packet_header.pkt_encap)
667
0
      wth->file_encap = WTAP_ENCAP_PER_PACKET;
668
0
  }
669
670
0
  return true;
671
0
}
672
673
static bool iptrace_seek_read_2_0(wtap *wth, int64_t seek_off,
674
    wtap_rec *rec, int *err, char **err_info)
675
0
{
676
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
677
0
    return false;
678
679
  /* Read the packet */
680
0
  if (!iptrace_read_rec_2_0(wth, wth->random_fh, rec, err,
681
0
      err_info)) {
682
0
    if (*err == 0)
683
0
      *err = WTAP_ERR_SHORT_READ;
684
0
    return false;
685
0
  }
686
0
  return true;
687
0
}
688
689
static bool
690
iptrace_read_rec_data(FILE_T fh, wtap_rec *rec, int *err, char **err_info)
691
0
{
692
0
  if (!wtap_read_bytes_buffer(fh, &rec->data, rec->rec_header.packet_header.caplen, err, err_info))
693
0
    return false;
694
695
0
  if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_ATM_PDUS) {
696
    /*
697
     * Attempt to guess from the packet data, the VPI,
698
     * and the VCI information about the type of traffic.
699
     */
700
0
    atm_guess_traffic_type(rec);
701
0
  }
702
703
0
  return true;
704
0
}
705
706
/*
707
 * Fill in the pseudo-header information we can.
708
 *
709
 * For ATM traffic, "iptrace", alas, doesn't tell us what type of traffic
710
 * is in the packet - it was presumably run on a machine that was one of
711
 * the endpoints of the connection, so in theory it could presumably have
712
 * told us, but, for whatever reason, it failed to do so - perhaps the
713
 * low-level mechanism that feeds the presumably-AAL5 frames to us doesn't
714
 * have access to that information (e.g., because it's in the ATM driver,
715
 * and the ATM driver merely knows that stuff on VPI/VCI X.Y should be
716
 * handed up to some particular client, it doesn't know what that client is).
717
 *
718
 * We let our caller try to figure out what kind of traffic it is, either
719
 * by guessing based on the VPI/VCI, guessing based on the header of the
720
 * packet, seeing earlier traffic that set up the circuit and specified
721
 * in some fashion what sort of traffic it is, or being told by the user.
722
 */
723
static void
724
fill_in_pseudo_header(int encap, union wtap_pseudo_header *pseudo_header,
725
    const char *pkt_text)
726
0
{
727
0
  char  if_text[9];
728
0
  char  *decimal;
729
0
  int Vpi = 0;
730
0
  int Vci = 0;
731
732
0
  switch (encap) {
733
734
0
  case WTAP_ENCAP_ATM_PDUS:
735
    /* Rip apart the "x.y" text into Vpi/Vci numbers */
736
0
    memcpy(if_text, &pkt_text[4], 8);
737
0
    if_text[8] = '\0';
738
0
    decimal = strchr(if_text, '.');
739
0
    if (decimal) {
740
0
      *decimal = '\0';
741
0
      Vpi = (int)strtoul(if_text, NULL, 10);
742
0
      decimal++;
743
0
      Vci = (int)strtoul(decimal, NULL, 10);
744
0
    }
745
746
    /*
747
     * OK, which value means "DTE->DCE" and which value means
748
     * "DCE->DTE"?
749
     */
750
0
    pseudo_header->atm.channel = pkt_text[13];
751
752
0
    pseudo_header->atm.vpi = Vpi;
753
0
    pseudo_header->atm.vci = Vci;
754
755
    /* We don't have this information */
756
0
    pseudo_header->atm.flags = 0;
757
0
    pseudo_header->atm.cells = 0;
758
0
    pseudo_header->atm.aal5t_u2u = 0;
759
0
    pseudo_header->atm.aal5t_len = 0;
760
0
    pseudo_header->atm.aal5t_chksum = 0;
761
0
    break;
762
763
0
  case WTAP_ENCAP_ETHERNET:
764
    /* We assume there's no FCS in this frame. */
765
0
    pseudo_header->eth.fcs_len = 0;
766
0
    break;
767
0
  }
768
0
}
769
770
/* Given an RFC1573 (SNMP ifType) interface type,
771
 * return the appropriate Wiretap Encapsulation Type.
772
 */
773
static int
774
wtap_encap_ift(unsigned int  ift)
775
0
{
776
777
0
  static const int ift_encap[] = {
778
0
/* 0x0 */  WTAP_ENCAP_UNKNOWN, /* nothing */
779
0
/* 0x1 */  WTAP_ENCAP_UNKNOWN, /* IFT_OTHER */
780
0
/* 0x2 */  WTAP_ENCAP_UNKNOWN, /* IFT_1822 */
781
0
/* 0x3 */  WTAP_ENCAP_UNKNOWN, /* IFT_HDH1822 */
782
0
/* 0x4 */  WTAP_ENCAP_RAW_IP, /* IFT_X25DDN */
783
0
/* 0x5 */  WTAP_ENCAP_UNKNOWN, /* IFT_X25 */
784
0
/* 0x6 */  WTAP_ENCAP_ETHERNET, /* IFT_ETHER */
785
0
/* 0x7 */  WTAP_ENCAP_ETHERNET, /* IFT_ISO88023 */
786
0
/* 0x8 */  WTAP_ENCAP_UNKNOWN, /* IFT_ISO88024 */
787
0
/* 0x9 */  WTAP_ENCAP_TOKEN_RING, /* IFT_ISO88025 */
788
0
/* 0xa */  WTAP_ENCAP_UNKNOWN, /* IFT_ISO88026 */
789
0
/* 0xb */  WTAP_ENCAP_UNKNOWN, /* IFT_STARLAN */
790
0
/* 0xc */  WTAP_ENCAP_RAW_IP, /* IFT_P10, IBM SP switch */
791
0
/* 0xd */  WTAP_ENCAP_UNKNOWN, /* IFT_P80 */
792
0
/* 0xe */  WTAP_ENCAP_UNKNOWN, /* IFT_HY */
793
0
/* 0xf */  WTAP_ENCAP_FDDI_BITSWAPPED, /* IFT_FDDI */
794
0
/* 0x10 */  WTAP_ENCAP_LAPB, /* IFT_LAPB */  /* no data to back this up */
795
0
/* 0x11 */  WTAP_ENCAP_UNKNOWN, /* IFT_SDLC */
796
0
/* 0x12 */  WTAP_ENCAP_UNKNOWN, /* IFT_T1 */
797
0
/* 0x13 */  WTAP_ENCAP_UNKNOWN, /* IFT_CEPT */
798
0
/* 0x14 */  WTAP_ENCAP_UNKNOWN, /* IFT_ISDNBASIC */
799
0
/* 0x15 */  WTAP_ENCAP_UNKNOWN, /* IFT_ISDNPRIMARY */
800
0
/* 0x16 */  WTAP_ENCAP_UNKNOWN, /* IFT_PTPSERIAL */
801
0
/* 0x17 */  WTAP_ENCAP_UNKNOWN, /* IFT_PPP */
802
0
/* 0x18 */  WTAP_ENCAP_RAW_IP, /* IFT_LOOP */
803
0
/* 0x19 */  WTAP_ENCAP_UNKNOWN, /* IFT_EON */
804
0
/* 0x1a */  WTAP_ENCAP_UNKNOWN, /* IFT_XETHER */
805
0
/* 0x1b */  WTAP_ENCAP_UNKNOWN, /* IFT_NSIP */
806
0
/* 0x1c */  WTAP_ENCAP_UNKNOWN, /* IFT_SLIP */
807
0
/* 0x1d */  WTAP_ENCAP_UNKNOWN, /* IFT_ULTRA */
808
0
/* 0x1e */  WTAP_ENCAP_UNKNOWN, /* IFT_DS3 */
809
0
/* 0x1f */  WTAP_ENCAP_UNKNOWN, /* IFT_SIP */
810
0
/* 0x20 */  WTAP_ENCAP_UNKNOWN, /* IFT_FRELAY */
811
0
/* 0x21 */  WTAP_ENCAP_UNKNOWN, /* IFT_RS232 */
812
0
/* 0x22 */  WTAP_ENCAP_UNKNOWN, /* IFT_PARA */
813
0
/* 0x23 */  WTAP_ENCAP_UNKNOWN, /* IFT_ARCNET */
814
0
/* 0x24 */  WTAP_ENCAP_UNKNOWN, /* IFT_ARCNETPLUS */
815
0
/* 0x25 */  WTAP_ENCAP_ATM_PDUS, /* IFT_ATM */
816
0
  };
817
0
  #define NUM_IFT_ENCAPS array_length(ift_encap)
818
819
0
  if (ift < NUM_IFT_ENCAPS) {
820
0
    return ift_encap[ift];
821
0
  }
822
0
  else {
823
0
    switch(ift) {
824
      /* Infiniband*/
825
0
      case IPTRACE_IFT_IB:
826
0
        return WTAP_ENCAP_INFINIBAND;
827
828
      /* Host Fabric Interface */
829
0
      case IPTRACE_IFT_HF:
830
        /* The HFI interface on AIX provides raw IP
831
        in the packet trace. It's unclear if the HFI
832
        can be configured for any other protocol, and if
833
        any field in the iptrace header indicates what
834
        that protocol is. For now, we are hard-coding
835
        this as RAW_IP, but if we find another iptrace file
836
        using HFI that provides another protocol, we will
837
        have to figure out which field in the iptrace file
838
        encodes it. */
839
0
        return WTAP_ENCAP_RAW_IP;
840
841
0
      default:
842
0
        return WTAP_ENCAP_UNKNOWN;
843
0
    }
844
0
  }
845
0
}
846
847
/* Options for interface blocks. */
848
static const struct supported_option_type interface_block_options_supported[] = {
849
  /* No comments, just an interface name. */
850
  { OPT_IDB_NAME, ONE_OPTION_SUPPORTED }
851
};
852
853
static const struct supported_block_type iptrace_1_0_blocks_supported[] = {
854
  /*
855
   * iptrace supports multiple interfaces, with descriptions, and
856
   * supports associating packets with interfaces.  Interface
857
   * description blocks are used for that.
858
   */
859
  { WTAP_BLOCK_IF_ID_AND_INFO, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(interface_block_options_supported) },
860
861
  /*
862
   * iptrace is a capture format, so it obviously supports packets.
863
   * It supports no packet options, however.
864
   */
865
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
866
};
867
868
static const struct file_type_subtype_info iptrace_1_0_info = {
869
  "AIX iptrace 1.0", "iptrace_1", NULL, NULL,
870
  false, BLOCKS_SUPPORTED(iptrace_1_0_blocks_supported),
871
  NULL, NULL, NULL
872
};
873
874
static const struct supported_block_type iptrace_2_0_blocks_supported[] = {
875
  /*
876
   * iptrace supports multiple interfaces, with descriptions, and
877
   * supports associating packets with interfaces.  Interface
878
   * description blocks are used for that.
879
   */
880
  { WTAP_BLOCK_IF_ID_AND_INFO, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(interface_block_options_supported) },
881
882
  /*
883
   * iptrace is a capture format, so it obviously supports packets.
884
   * It supports no packet options, however.
885
   */
886
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
887
};
888
889
static const struct file_type_subtype_info iptrace_2_0_info = {
890
  "AIX iptrace 2.0", "iptrace_2", NULL, NULL,
891
  false, BLOCKS_SUPPORTED(iptrace_2_0_blocks_supported),
892
  NULL, NULL, NULL
893
};
894
895
void register_iptrace(void)
896
14
{
897
14
  iptrace_1_0_file_type_subtype = wtap_register_file_type_subtype(&iptrace_1_0_info);
898
14
  iptrace_2_0_file_type_subtype = wtap_register_file_type_subtype(&iptrace_2_0_info);
899
900
  /*
901
   * Register names for backwards compatibility with the
902
   * wtap_filetypes table in Lua.
903
   */
904
14
  wtap_register_backwards_compatibility_lua_name("IPTRACE_1_0",
905
14
      iptrace_1_0_file_type_subtype);
906
14
  wtap_register_backwards_compatibility_lua_name("IPTRACE_2_0",
907
14
      iptrace_2_0_file_type_subtype);
908
14
}
909
910
/*
911
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
912
 *
913
 * Local variables:
914
 * c-basic-offset: 8
915
 * tab-width: 8
916
 * indent-tabs-mode: t
917
 * End:
918
 *
919
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
920
 * :indentSize=8:tabSize=8:noTabs=false:
921
 */