Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/wiretap/netmon.c
Line
Count
Source (jump to first uncovered line)
1
/* netmon.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 "netmon.h"
11
12
#include <errno.h>
13
#include <string.h>
14
#include <wsutil/unicode-utils.h>
15
#include "wtap-int.h"
16
#include "file_wrappers.h"
17
#include "atm.h"
18
#include "pcap-encap.h"
19
20
/* The file at
21
 *
22
 *  ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
23
 *
24
 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
25
 * for the header of a Microsoft Network Monitor 1.x capture file.
26
 *
27
 * The help files for Network Monitor 3.x document the 2.x file format.
28
 */
29
30
/* Capture file header, *including* magic number, is padded to 128 bytes. */
31
0
#define CAPTUREFILE_HEADER_SIZE 128
32
33
/* Magic number size, for both 1.x and 2.x. */
34
0
#define MAGIC_SIZE  4
35
36
/* Magic number in Network Monitor 1.x files. */
37
static const char netmon_1_x_magic[MAGIC_SIZE] = {
38
  'R', 'T', 'S', 'S'
39
};
40
41
/* Magic number in Network Monitor 2.x files. */
42
static const char netmon_2_x_magic[MAGIC_SIZE] = {
43
  'G', 'M', 'B', 'U'
44
};
45
46
/* Network Monitor file header (minus magic number). */
47
struct netmon_hdr {
48
  uint8_t  ver_minor; /* minor version number */
49
  uint8_t  ver_major; /* major version number */
50
  uint16_t network; /* network type */
51
  uint16_t ts_year; /* year of capture start */
52
  uint16_t ts_month;  /* month of capture start (January = 1) */
53
  uint16_t ts_dow;  /* day of week of capture start (Sun = 0) */
54
  uint16_t ts_day;  /* day of month of capture start */
55
  uint16_t ts_hour; /* hour of capture start */
56
  uint16_t ts_min;  /* minute of capture start */
57
  uint16_t ts_sec;  /* second of capture start */
58
  uint16_t ts_msec; /* millisecond of capture start */
59
  uint32_t frametableoffset;  /* frame index table offset */
60
  uint32_t frametablelength;  /* frame index table size */
61
  uint32_t userdataoffset;  /* user data offset */
62
  uint32_t userdatalength;  /* user data size */
63
  uint32_t commentdataoffset; /* comment data offset */
64
  uint32_t commentdatalength; /* comment data size */
65
  uint32_t processinfooffset; /* offset to process info structure */
66
  uint32_t processinfocount;  /* number of process info structures */
67
  uint32_t networkinfooffset; /* offset to network info structure */
68
  uint32_t networkinfolength; /* length of network info structure */
69
};
70
71
/* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
72
 * looking at capture files. */
73
struct netmonrec_1_x_hdr {
74
  uint32_t ts_delta;  /* time stamp - msecs since start of capture */
75
  uint16_t orig_len;  /* actual length of packet */
76
  uint16_t incl_len;  /* number of octets captured in file */
77
};
78
79
/*
80
 * Network Monitor 2.x record header, as documented in NetMon 3.x's
81
 * help files.
82
 */
83
struct netmonrec_2_x_hdr {
84
  uint64_t ts_delta;  /* time stamp - usecs since start of capture */
85
  uint32_t orig_len;  /* actual length of packet */
86
  uint32_t incl_len;  /* number of octets captured in file */
87
};
88
89
/*
90
 * Network Monitor 2.1 and later record trailers; documented in the Network
91
 * Monitor 3.x help files, for 3.3 and later, although they don't clearly
92
 * state how the trailer format changes from version to version.
93
 *
94
 * Some fields are multi-byte integers, but they're not aligned on their
95
 * natural boundaries.
96
 */
97
struct netmonrec_2_1_trlr {
98
  uint8_t network[2];   /* network type for this packet */
99
};
100
101
struct netmonrec_2_2_trlr {
102
  uint8_t network[2];   /* network type for this packet */
103
  uint8_t process_info_index[4];  /* index into the process info table */
104
};
105
106
struct netmonrec_2_3_trlr {
107
  uint8_t network[2];   /* network type for this packet */
108
  uint8_t process_info_index[4];  /* index into the process info table */
109
  uint8_t utc_timestamp[8]; /* packet time stamp, as .1 us units since January 1, 1601, 00:00:00 UTC */
110
  uint8_t timezone_index;   /* index of time zone information */
111
};
112
113
struct netmonrec_comment {
114
  uint32_t numFramePerComment;  /* Currently, this is always set to 1. Each comment is attached to only one frame. */
115
  uint32_t frameOffset;   /* Offset in the capture file table that indicates the beginning of the frame.  Key used to match comment with frame */
116
  uint8_t* title;     /* Comment title */
117
  uint32_t descLength;    /* Number of bytes in the comment description. Must be at least zero. */
118
  uint8_t* description;   /* Comment description */
119
};
120
121
/* Just the first few fields of netmonrec_comment so it can be read sequentially from file */
122
struct netmonrec_comment_header {
123
  uint32_t numFramePerComment;
124
  uint32_t frameOffset;
125
  uint32_t titleLength;
126
};
127
128
union ip_address {
129
  uint32_t ipv4;
130
  ws_in6_addr ipv6;
131
};
132
133
struct netmonrec_process_info {
134
  uint8_t* path;        /* A Unicode string of length PathSize */
135
  uint32_t iconSize;
136
  uint8_t* iconData;
137
  uint32_t pid;
138
  uint16_t localPort;
139
  uint16_t remotePort;
140
  bool isIPv6;
141
  union ip_address localAddr;
142
  union ip_address remoteAddr;
143
};
144
145
/*
146
 * The link-layer header on ATM packets.
147
 */
148
struct netmon_atm_hdr {
149
  uint8_t  dest[6]; /* "Destination address" - what is it? */
150
  uint8_t  src[6];  /* "Source address" - what is it? */
151
  uint16_t vpi;   /* VPI */
152
  uint16_t vci;   /* VCI */
153
};
154
155
typedef struct {
156
  time_t   start_secs;
157
  uint32_t start_nsecs;
158
  uint8_t  version_major;
159
  uint8_t  version_minor;
160
  uint32_t *frame_table;
161
  uint32_t frame_table_size;
162
  GHashTable* comment_table;
163
  GHashTable* process_info_table;
164
  unsigned current_frame;
165
} netmon_t;
166
167
/*
168
 * Maximum pathname length supported in the process table; the length
169
 * is in a 32-bit field, so we impose a limit to prevent attempts to
170
 * allocate too much memory.
171
 *
172
 * See
173
 *
174
 *    https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
175
 *
176
 * The NetMon 3.4 "Capture File Format" documentation says "PathSize must be
177
 * greater than 0, and less than MAX_PATH (260 characters)", but, as per that
178
 * link above, that limit has been raised in more recent systems.
179
 *
180
 * We pick a limit of 65536, as that should handle a path length of 32767
181
 * UTF-16 octet pairs plus a trailing NUL octet pair.
182
 */
183
0
#define MATH_PROCINFO_PATH_SIZE   65536
184
185
/*
186
 * XXX - at least in some NetMon 3.4 VPN captures, the per-packet
187
 * link-layer type is 0, but the packets have Ethernet headers.
188
 * We handle this by mapping 0 to WTAP_ENCAP_ETHERNET; should we,
189
 * instead, use the per-file link-layer type?
190
 */
191
static const int netmon_encap[] = {
192
  WTAP_ENCAP_ETHERNET,
193
  WTAP_ENCAP_ETHERNET,
194
  WTAP_ENCAP_TOKEN_RING,
195
  WTAP_ENCAP_FDDI_BITSWAPPED,
196
  WTAP_ENCAP_ATM_PDUS,  /* NDIS WAN - this is what's used for ATM */
197
  WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk, but format 2.x uses it for IP-over-IEEE 1394 */
198
  WTAP_ENCAP_IEEE_802_11_NETMON,
199
        /* NDIS "DIX", but format 2.x uses it for 802.11 */
200
  WTAP_ENCAP_RAW_IP,  /* NDIS ARCNET raw, but format 2.x uses it for "Tunneling interfaces" */
201
  WTAP_ENCAP_RAW_IP,  /* NDIS ARCNET 878.2, but format 2.x uses it for "Wireless WAN" */
202
  WTAP_ENCAP_RAW_IP,  /* NDIS ATM (no, this is NOT used for ATM); format 2.x uses it for "Raw IP Frames" */
203
  WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
204
  WTAP_ENCAP_UNKNOWN  /* NDIS IrDA */
205
};
206
0
#define NUM_NETMON_ENCAPS array_length(netmon_encap)
207
208
/*
209
 * Special link-layer types.
210
 */
211
0
#define NETMON_NET_PCAP_BASE    0xE000
212
0
#define NETMON_NET_NETEVENT   0xFFE0
213
0
#define NETMON_NET_NETWORK_INFO_EX  0xFFFB
214
0
#define NETMON_NET_PAYLOAD_HEADER 0xFFFC
215
0
#define NETMON_NET_NETWORK_INFO   0xFFFD
216
0
#define NETMON_NET_DNS_CACHE    0xFFFE
217
0
#define NETMON_NET_NETMON_FILTER  0xFFFF
218
219
static bool netmon_read(wtap *wth, wtap_rec *rec,
220
    int *err, char **err_info, int64_t *data_offset);
221
static bool netmon_seek_read(wtap *wth, int64_t seek_off,
222
    wtap_rec *rec, int *err, char **err_info);
223
static bool netmon_read_atm_pseudoheader(FILE_T fh,
224
    union wtap_pseudo_header *pseudo_header, int *err, char **err_info);
225
static void netmon_close(wtap *wth);
226
static bool netmon_dump(wtap_dumper *wdh, const wtap_rec *rec,
227
    const uint8_t *pd, int *err, char **err_info);
228
static bool netmon_dump_finish(wtap_dumper *wdh, int *err,
229
    char **err_info);
230
231
static int netmon_1_x_file_type_subtype = -1;
232
static int netmon_2_x_file_type_subtype = -1;
233
234
void register_netmon(void);
235
236
/*
237
 * Convert a counted UTF-16 string, which is probably also null-terminated
238
 * but is not guaranteed to be null-terminated (as it came from a file),
239
 * to a null-terminated UTF-8 string.
240
 */
241
static uint8_t *
242
utf_16_to_utf_8(const uint8_t *in, uint32_t length)
243
0
{
244
0
  uint8_t *result, *out;
245
0
  gunichar2 uchar2;
246
0
  gunichar uchar;
247
0
  size_t n_bytes;
248
0
  uint32_t i;
249
250
  /*
251
   * Get the length of the resulting UTF-8 string, and validate
252
   * the input string in the process.
253
   */
254
0
  n_bytes = 0;
255
0
  for (i = 0; i + 1 < length && (uchar2 = pletoh16(in + i)) != '\0';
256
0
      i += 2) {
257
0
    if (IS_LEAD_SURROGATE(uchar2)) {
258
      /*
259
       * Lead surrogate.  Must be followed by a trail
260
       * surrogate.
261
       */
262
0
      gunichar2 lead_surrogate;
263
264
0
      i += 2;
265
0
      if (i + 1 >= length) {
266
        /*
267
         * Oops, string ends with a lead surrogate.
268
         * Ignore this for now.
269
         * XXX - insert "substitute" character?
270
         * Report the error in some other fashion?
271
         */
272
0
        break;
273
0
      }
274
0
      lead_surrogate = uchar2;
275
0
      uchar2 = pletoh16(in + i);
276
0
      if (uchar2 == '\0') {
277
        /*
278
         * Oops, string ends with a lead surrogate.
279
         * Ignore this for now.
280
         * XXX - insert "substitute" character?
281
         * Report the error in some other fashion?
282
         */
283
0
        break;
284
0
      }
285
0
      if (IS_TRAIL_SURROGATE(uchar2)) {
286
        /* Trail surrogate. */
287
0
        uchar = SURROGATE_VALUE(lead_surrogate, uchar2);
288
0
        n_bytes += g_unichar_to_utf8(uchar, NULL);
289
0
      } else {
290
        /*
291
         * Not a trail surrogate.
292
         * Ignore the entire pair.
293
         * XXX - insert "substitute" character?
294
         * Report the error in some other fashion?
295
         */
296
0
        ;
297
0
      }
298
0
    } else {
299
0
      if (IS_TRAIL_SURROGATE(uchar2)) {
300
        /*
301
         * Trail surrogate without a preceding
302
         * lead surrogate.  Ignore it.
303
         * XXX - insert "substitute" character?
304
         * Report the error in some other fashion?
305
         */
306
0
        ;
307
0
      } else {
308
        /*
309
         * Non-surrogate; just count it.
310
         */
311
0
        n_bytes += g_unichar_to_utf8(uchar2, NULL);
312
0
      }
313
0
    }
314
0
  }
315
316
  /*
317
   * Now allocate a buffer big enough for the UTF-8 string plus a
318
   * trailing NUL, and generate the string.
319
   */
320
0
  result = (uint8_t *)g_malloc(n_bytes + 1);
321
322
0
  out = result;
323
0
  for (i = 0; i + 1 < length && (uchar2 = pletoh16(in + i)) != '\0';
324
0
      i += 2) {
325
0
    if (IS_LEAD_SURROGATE(uchar2)) {
326
      /*
327
       * Lead surrogate.  Must be followed by a trail
328
       * surrogate.
329
       */
330
0
      gunichar2 lead_surrogate;
331
332
0
      i += 2;
333
0
      if (i + 1 >= length) {
334
        /*
335
         * Oops, string ends with a lead surrogate.
336
         * Ignore this for now.
337
         * XXX - insert "substitute" character?
338
         * Report the error in some other fashion?
339
         */
340
0
        break;
341
0
      }
342
0
      lead_surrogate = uchar2;
343
0
      uchar2 = pletoh16(in + i);
344
0
      if (uchar2 == '\0') {
345
        /*
346
         * Oops, string ends with a lead surrogate.
347
         * Ignore this for now.
348
         * XXX - insert "substitute" character?
349
         * Report the error in some other fashion?
350
         */
351
0
        break;
352
0
      }
353
0
      if (IS_TRAIL_SURROGATE(uchar2)) {
354
        /* Trail surrogate. */
355
0
        uchar = SURROGATE_VALUE(lead_surrogate, uchar2);
356
0
        out += g_unichar_to_utf8(uchar, out);
357
0
      } else {
358
        /*
359
         * Not a trail surrogate.
360
         * Ignore the entire pair.
361
         * XXX - insert "substitute" character?
362
         * Report the error in some other fashion?
363
         */
364
0
        ;
365
0
      }
366
0
    } else {
367
0
      if (IS_TRAIL_SURROGATE(uchar2)) {
368
        /*
369
         * Trail surrogate without a preceding
370
         * lead surrogate.  Ignore it.
371
         * XXX - insert "substitute" character?
372
         * Report the error in some other fashion?
373
         */
374
0
        ;
375
0
      } else {
376
        /*
377
         * Non-surrogate; just count it.
378
         */
379
0
        out += g_unichar_to_utf8(uchar2, out);
380
0
      }
381
0
    }
382
0
  }
383
0
  *out = '\0';
384
385
  /*
386
   * XXX - if i < length, this means we were handed an odd
387
   * number of bytes, so it was not a valid UTF-16 string.
388
   */
389
0
  return result;
390
0
}
391
392
393
0
static void netmonrec_comment_destroy(void *key) {
394
0
  struct netmonrec_comment *comment = (struct netmonrec_comment*) key;
395
396
0
  g_free(comment->title);
397
0
  g_free(comment->description);
398
0
  g_free(comment);
399
0
}
400
401
0
static void netmonrec_process_info_destroy(void *key) {
402
0
  struct netmonrec_process_info *process_info = (struct netmonrec_process_info*) key;
403
404
0
  g_free(process_info->path);
405
0
  g_free(process_info->iconData);
406
0
  g_free(process_info);
407
0
}
408
409
wtap_open_return_val netmon_open(wtap *wth, int *err, char **err_info)
410
0
{
411
0
  char magic[MAGIC_SIZE];
412
0
  struct netmon_hdr hdr;
413
0
  int file_type;
414
0
  struct tm tm;
415
0
  uint32_t frame_table_offset;
416
0
  uint32_t frame_table_length;
417
0
  uint32_t frame_table_size;
418
0
  uint32_t *frame_table;
419
0
  uint32_t comment_table_offset, process_info_table_offset;
420
0
  uint32_t comment_table_size, process_info_table_count;
421
0
  GHashTable *comment_table, *process_info_table;
422
0
  struct netmonrec_comment* comment_rec;
423
0
  int64_t file_size = wtap_file_size(wth, err);
424
#if G_BYTE_ORDER == G_BIG_ENDIAN
425
  unsigned int i;
426
#endif
427
0
  netmon_t *netmon;
428
429
  /* Read in the string that should be at the start of a Network
430
   * Monitor file */
431
0
  if (!wtap_read_bytes(wth->fh, magic, MAGIC_SIZE, err, err_info)) {
432
0
    if (*err != WTAP_ERR_SHORT_READ)
433
0
      return WTAP_OPEN_ERROR;
434
0
    return WTAP_OPEN_NOT_MINE;
435
0
  }
436
437
0
  if (memcmp(magic, netmon_1_x_magic, MAGIC_SIZE) != 0 &&
438
0
      memcmp(magic, netmon_2_x_magic, MAGIC_SIZE) != 0) {
439
0
    return WTAP_OPEN_NOT_MINE;
440
0
  }
441
442
  /* Read the rest of the header. */
443
0
  if (!wtap_read_bytes(wth->fh, &hdr, sizeof hdr, err, err_info))
444
0
    return WTAP_OPEN_ERROR;
445
446
0
  switch (hdr.ver_major) {
447
448
0
  case 1:
449
0
    file_type = netmon_1_x_file_type_subtype;
450
0
    break;
451
452
0
  case 2:
453
0
    file_type = netmon_2_x_file_type_subtype;
454
0
    break;
455
456
0
  default:
457
0
    *err = WTAP_ERR_UNSUPPORTED;
458
0
    *err_info = ws_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
459
0
    return WTAP_OPEN_ERROR;
460
0
  }
461
462
0
  hdr.network = pletoh16(&hdr.network);
463
0
  if (hdr.network >= NUM_NETMON_ENCAPS
464
0
      || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
465
0
    *err = WTAP_ERR_UNSUPPORTED;
466
0
    *err_info = ws_strdup_printf("netmon: network type %u unknown or unsupported",
467
0
        hdr.network);
468
0
    return WTAP_OPEN_ERROR;
469
0
  }
470
471
  /* This is a netmon file */
472
0
  wth->file_type_subtype = file_type;
473
0
  netmon = g_new0(netmon_t, 1);
474
0
  wth->priv = (void *)netmon;
475
0
  wth->subtype_read = netmon_read;
476
0
  wth->subtype_seek_read = netmon_seek_read;
477
0
  wth->subtype_close = netmon_close;
478
479
  /* NetMon capture file formats v2.1+ use per-packet encapsulation types.  NetMon 3 sets the value in
480
   * the header to 1 (Ethernet) for backwards compatibility. */
481
0
  if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
482
0
    wth->file_encap = WTAP_ENCAP_PER_PACKET;
483
0
  else
484
0
    wth->file_encap = netmon_encap[hdr.network];
485
486
0
  wth->snapshot_length = 0; /* not available in header */
487
  /*
488
   * Convert the time stamp to a "time_t" and a number of
489
   * milliseconds.
490
   */
491
0
  tm.tm_year = pletoh16(&hdr.ts_year) - 1900;
492
0
  tm.tm_mon = pletoh16(&hdr.ts_month) - 1;
493
0
  tm.tm_mday = pletoh16(&hdr.ts_day);
494
0
  tm.tm_hour = pletoh16(&hdr.ts_hour);
495
0
  tm.tm_min = pletoh16(&hdr.ts_min);
496
0
  tm.tm_sec = pletoh16(&hdr.ts_sec);
497
0
  tm.tm_isdst = -1;
498
0
  netmon->start_secs = mktime(&tm);
499
  /*
500
   * XXX - what if "secs" is -1?  Unlikely, but if the capture was
501
   * done in a time zone that switches between standard and summer
502
   * time sometime other than when we do, and thus the time was one
503
   * that doesn't exist here because a switch from standard to summer
504
   * time zips over it, it could happen.
505
   *
506
   * On the other hand, if the capture was done in a different time
507
   * zone, this won't work right anyway; unfortunately, the time
508
   * zone isn't stored in the capture file (why the hell didn't
509
   * they stuff a FILETIME, which is the number of 100-nanosecond
510
   * intervals since 1601-01-01 00:00:00 "UTC", there, instead
511
   * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
512
   *
513
   * Eventually they went with per-packet FILETIMEs in a later
514
   * version.
515
   */
516
0
  netmon->start_nsecs = pletoh16(&hdr.ts_msec)*1000000;
517
518
0
  netmon->version_major = hdr.ver_major;
519
0
  netmon->version_minor = hdr.ver_minor;
520
521
  /*
522
   * Get the offset of the frame index table.
523
   */
524
0
  frame_table_offset = pletoh32(&hdr.frametableoffset);
525
526
  /*
527
   * For NetMon 2.2 format and later, get the offset and length of
528
   * the comment index table and process info table.
529
   *
530
   * For earlier versions, set them to zero; they appear to be
531
   * uninitialized, so they're not necessarily zero.
532
   */
533
0
  if ((netmon->version_major == 2 && netmon->version_minor >= 2) ||
534
0
      netmon->version_major > 2) {
535
0
    comment_table_offset = pletoh32(&hdr.commentdataoffset);
536
0
    comment_table_size = pletoh32(&hdr.commentdatalength);
537
0
    process_info_table_offset = pletoh32(&hdr.processinfooffset);
538
0
    process_info_table_count = pletoh32(&hdr.processinfocount);
539
0
  } else {
540
0
    comment_table_offset = 0;
541
0
    comment_table_size = 0;
542
0
    process_info_table_offset = 0;
543
0
    process_info_table_count = 0;
544
0
  }
545
546
  /*
547
   * It appears that some NetMon 2.x files don't have the
548
   * first packet starting exactly 128 bytes into the file.
549
   *
550
   * Furthermore, it also appears that there are "holes" in
551
   * the file, i.e. frame N+1 doesn't always follow immediately
552
   * after frame N.
553
   *
554
   * Therefore, we must read the frame table, and use the offsets
555
   * in it as the offsets of the frames.
556
   */
557
0
  frame_table_length = pletoh32(&hdr.frametablelength);
558
0
  frame_table_size = frame_table_length / (uint32_t)sizeof (uint32_t);
559
0
  if ((frame_table_size * sizeof (uint32_t)) != frame_table_length) {
560
0
    *err = WTAP_ERR_BAD_FILE;
561
0
    *err_info = ws_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
562
0
        frame_table_length);
563
0
    return WTAP_OPEN_ERROR;
564
0
  }
565
0
  if (frame_table_size == 0) {
566
0
    *err = WTAP_ERR_BAD_FILE;
567
0
    *err_info = ws_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
568
0
        frame_table_length);
569
0
    return WTAP_OPEN_ERROR;
570
0
  }
571
  /*
572
   * XXX - clamp the size of the frame table, so that we don't
573
   * attempt to allocate a huge frame table and fail.
574
   *
575
   * Given that file offsets in the frame table are 32-bit,
576
   * a NetMon file cannot be bigger than 2^32 bytes.
577
   * Given that a NetMon 1.x-format packet header is 8 bytes,
578
   * that means a NetMon file cannot have more than
579
   * 512*2^20 packets.  We'll pick that as the limit for
580
   * now; it's 1/8th of a 32-bit address space, which is
581
   * probably not going to exhaust the address space all by
582
   * itself, and probably won't exhaust the backing store.
583
   */
584
0
  if (frame_table_size > 512*1024*1024) {
585
0
    *err = WTAP_ERR_BAD_FILE;
586
0
    *err_info = ws_strdup_printf("netmon: frame table length is %u, which is larger than we support",
587
0
        frame_table_length);
588
0
    return WTAP_OPEN_ERROR;
589
0
  }
590
0
  if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
591
0
    return WTAP_OPEN_ERROR;
592
0
  }
593
594
  /*
595
   * Sanity check the comment table information before we bother to allocate
596
   * large chunks of memory for the frame table
597
   */
598
0
  if (comment_table_size > 0) {
599
    /*
600
     * XXX - clamp the size of the comment table, so that we don't
601
     * attempt to allocate a huge comment table and fail.
602
     *
603
     * Just use same size requires as frame table
604
     */
605
0
    if (comment_table_size > 512*1024*1024) {
606
0
      *err = WTAP_ERR_BAD_FILE;
607
0
      *err_info = ws_strdup_printf("netmon: comment table size is %u, which is larger than we support",
608
0
        comment_table_size);
609
0
      return WTAP_OPEN_ERROR;
610
0
    }
611
612
0
    if (comment_table_size < 17) {
613
0
      *err = WTAP_ERR_BAD_FILE;
614
0
      *err_info = ws_strdup_printf("netmon: comment table size is %u, which is too small to use",
615
0
        comment_table_size);
616
0
      return WTAP_OPEN_ERROR;
617
0
    }
618
619
0
    if (comment_table_offset > file_size) {
620
0
      *err = WTAP_ERR_BAD_FILE;
621
0
      *err_info = ws_strdup_printf("netmon: comment table offset (%u) is larger than file",
622
0
        comment_table_offset);
623
0
      return WTAP_OPEN_ERROR;
624
0
    }
625
0
  }
626
627
  /*
628
   * Sanity check the process info table information before we bother to allocate
629
   * large chunks of memory for the frame table
630
   */
631
0
  if ((process_info_table_offset > 0) && (process_info_table_count > 0)) {
632
    /*
633
     * XXX - clamp the size of the process info table, so that we don't
634
     * attempt to allocate a huge process info table and fail.
635
     */
636
0
    if (process_info_table_count > 512*1024) {
637
0
      *err = WTAP_ERR_BAD_FILE;
638
0
      *err_info = ws_strdup_printf("netmon: process info table size is %u, which is larger than we support",
639
0
        process_info_table_count);
640
0
      return WTAP_OPEN_ERROR;
641
0
    }
642
643
0
    if (process_info_table_offset > file_size) {
644
0
      *err = WTAP_ERR_BAD_FILE;
645
0
      *err_info = ws_strdup_printf("netmon: process info table offset (%u) is larger than file",
646
0
        process_info_table_offset);
647
0
      return WTAP_OPEN_ERROR;
648
0
    }
649
0
  }
650
651
  /*
652
   * Return back to the frame table offset
653
   */
654
0
  if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
655
0
    return WTAP_OPEN_ERROR;
656
0
  }
657
658
  /*
659
   * Sanity check the process info table information before we bother to allocate
660
   * large chunks of memory for the frame table
661
   */
662
663
0
  frame_table = (uint32_t *)g_try_malloc(frame_table_length);
664
0
  if (frame_table_length != 0 && frame_table == NULL) {
665
0
    *err = ENOMEM;  /* we assume we're out of memory */
666
0
    return WTAP_OPEN_ERROR;
667
0
  }
668
0
  if (!wtap_read_bytes(wth->fh, frame_table, frame_table_length,
669
0
      err, err_info)) {
670
0
    g_free(frame_table);
671
0
    return WTAP_OPEN_ERROR;
672
0
  }
673
0
  netmon->frame_table_size = frame_table_size;
674
0
  netmon->frame_table = frame_table;
675
676
0
  if (comment_table_size > 0) {
677
0
    comment_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, netmonrec_comment_destroy);
678
0
    if (comment_table == NULL) {
679
0
      *err = ENOMEM;  /* we assume we're out of memory */
680
0
      return WTAP_OPEN_ERROR;
681
0
    }
682
683
    /* Make sure the file contains the full comment section */
684
0
    if (file_seek(wth->fh, comment_table_offset+comment_table_size, SEEK_SET, err) == -1) {
685
0
      g_hash_table_destroy(comment_table);
686
0
      return WTAP_OPEN_ERROR;
687
0
    }
688
689
0
    if (file_seek(wth->fh, comment_table_offset, SEEK_SET, err) == -1) {
690
      /* Shouldn't fail... */
691
0
      g_hash_table_destroy(comment_table);
692
0
      return WTAP_OPEN_ERROR;
693
0
    }
694
695
0
    while (comment_table_size > 16) {
696
0
      struct netmonrec_comment_header comment_header;
697
0
      uint32_t title_length;
698
0
      uint32_t desc_length;
699
0
      uint8_t *utf16_str;
700
701
      /* Read the first 12 bytes of the structure */
702
0
      if (!wtap_read_bytes(wth->fh, &comment_header, 12, err, err_info)) {
703
0
        g_hash_table_destroy(comment_table);
704
0
        return WTAP_OPEN_ERROR;
705
0
      }
706
0
      comment_table_size -= 12;
707
708
      /* Make sure comment size is sane */
709
0
      title_length = pletoh32(&comment_header.titleLength);
710
0
      if (title_length == 0) {
711
0
        *err = WTAP_ERR_BAD_FILE;
712
0
        *err_info = g_strdup("netmon: comment title size can't be 0");
713
0
        g_hash_table_destroy(comment_table);
714
0
        return WTAP_OPEN_ERROR;
715
0
      }
716
0
      if (title_length > comment_table_size) {
717
0
        *err = WTAP_ERR_BAD_FILE;
718
0
        *err_info = ws_strdup_printf("netmon: comment title size is %u, which is larger than the amount remaining in the comment section (%u)",
719
0
            title_length, comment_table_size);
720
0
        g_hash_table_destroy(comment_table);
721
0
        return WTAP_OPEN_ERROR;
722
0
      }
723
724
0
      comment_rec = g_new0(struct netmonrec_comment, 1);
725
0
      comment_rec->numFramePerComment = pletoh32(&comment_header.numFramePerComment);
726
0
      comment_rec->frameOffset = pletoh32(&comment_header.frameOffset);
727
728
0
      g_hash_table_insert(comment_table, GUINT_TO_POINTER(comment_rec->frameOffset), comment_rec);
729
730
      /*
731
       * Read in the comment title.
732
       *
733
       * It is in UTF-16-encoded Unicode, and the title
734
       * size is a count of octets, not octet pairs or
735
       * Unicode characters.
736
       */
737
0
      utf16_str = (uint8_t*)g_malloc(title_length);
738
0
      if (!wtap_read_bytes(wth->fh, utf16_str, title_length,
739
0
          err, err_info)) {
740
0
        g_hash_table_destroy(comment_table);
741
0
        return WTAP_OPEN_ERROR;
742
0
      }
743
0
      comment_table_size -= title_length;
744
745
      /*
746
       * Now convert it to UTF-8 for internal use.
747
       */
748
0
      comment_rec->title = utf_16_to_utf_8(utf16_str,
749
0
          title_length);
750
0
      g_free(utf16_str);
751
752
0
      if (comment_table_size < 4) {
753
0
        *err = WTAP_ERR_BAD_FILE;
754
0
        *err_info = g_strdup("netmon: corrupt comment section");
755
0
        g_hash_table_destroy(comment_table);
756
0
        return WTAP_OPEN_ERROR;
757
0
      }
758
759
0
      if (!wtap_read_bytes(wth->fh, &desc_length, 4, err, err_info)) {
760
0
        g_hash_table_destroy(comment_table);
761
0
        return WTAP_OPEN_ERROR;
762
0
      }
763
0
      comment_table_size -= 4;
764
765
0
      comment_rec->descLength = pletoh32(&desc_length);
766
0
      if (comment_rec->descLength > 0) {
767
        /* Make sure comment size is sane */
768
0
        if (comment_rec->descLength > comment_table_size) {
769
0
          *err = WTAP_ERR_BAD_FILE;
770
0
          *err_info = ws_strdup_printf("netmon: comment description size is %u, which is larger than the amount remaining in the comment section (%u)",
771
0
                comment_rec->descLength, comment_table_size);
772
0
          g_hash_table_destroy(comment_table);
773
0
          return WTAP_OPEN_ERROR;
774
0
        }
775
776
0
        comment_rec->description = (uint8_t*)g_malloc(comment_rec->descLength);
777
778
        /* Read the comment description */
779
0
        if (!wtap_read_bytes(wth->fh, comment_rec->description, comment_rec->descLength, err, err_info)) {
780
0
          g_hash_table_destroy(comment_table);
781
0
          return WTAP_OPEN_ERROR;
782
0
        }
783
784
0
        comment_table_size -= comment_rec->descLength;
785
0
      }
786
0
    }
787
0
    netmon->comment_table = comment_table;
788
0
  }
789
790
0
  if ((process_info_table_offset > 0) && (process_info_table_count > 0)) {
791
0
    uint16_t version;
792
793
    /* Go to the process table offset */
794
0
    if (file_seek(wth->fh, process_info_table_offset, SEEK_SET, err) == -1) {
795
0
      return WTAP_OPEN_ERROR;
796
0
    }
797
798
0
    process_info_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, netmonrec_process_info_destroy);
799
0
    if (process_info_table == NULL) {
800
0
      *err = ENOMEM;  /* we assume we're out of memory */
801
0
      return WTAP_OPEN_ERROR;
802
0
    }
803
804
    /* Read the version (ignored for now) */
805
0
    if (!wtap_read_bytes(wth->fh, &version, 2, err, err_info)) {
806
0
      g_hash_table_destroy(process_info_table);
807
0
      return WTAP_OPEN_ERROR;
808
0
    }
809
810
0
    while (process_info_table_count > 0)
811
0
    {
812
0
      struct netmonrec_process_info* process_info;
813
0
      uint32_t tmp32;
814
0
      uint16_t tmp16;
815
0
      uint32_t path_size;
816
0
      uint8_t *utf16_str;
817
818
0
      process_info = g_new0(struct netmonrec_process_info, 1);
819
820
      /* Read path */
821
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
822
0
        g_free(process_info);
823
0
        g_hash_table_destroy(process_info_table);
824
0
        return WTAP_OPEN_ERROR;
825
0
      }
826
827
0
      path_size = pletoh32(&tmp32);
828
0
      if (path_size > MATH_PROCINFO_PATH_SIZE) {
829
0
        *err = WTAP_ERR_BAD_FILE;
830
0
        *err_info = ws_strdup_printf("netmon: Path size for process info record is %u, which is larger than allowed max value (%u)",
831
0
            path_size, MATH_PROCINFO_PATH_SIZE);
832
0
        g_free(process_info);
833
0
        g_hash_table_destroy(process_info_table);
834
0
        return WTAP_OPEN_ERROR;
835
0
      }
836
837
      /*
838
       * Read in the path string.
839
       *
840
       * It is in UTF-16-encoded Unicode, and the path
841
       * size is a count of octets, not octet pairs or
842
       * Unicode characters.
843
       */
844
0
      utf16_str = (uint8_t*)g_malloc(path_size);
845
0
      if (!wtap_read_bytes(wth->fh, utf16_str, path_size,
846
0
          err, err_info)) {
847
0
        g_free(process_info);
848
0
        g_hash_table_destroy(process_info_table);
849
0
        return WTAP_OPEN_ERROR;
850
0
      }
851
852
      /*
853
       * Now convert it to UTF-8 for internal use.
854
       */
855
0
      process_info->path = utf_16_to_utf_8(utf16_str,
856
0
          path_size);
857
0
      g_free(utf16_str);
858
859
      /* Read icon (currently not saved) */
860
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
861
0
        g_free(process_info);
862
0
        g_hash_table_destroy(process_info_table);
863
0
        return WTAP_OPEN_ERROR;
864
0
      }
865
866
0
      process_info->iconSize = pletoh32(&tmp32);
867
868
      /* XXX - skip the icon for now */
869
0
      if (file_seek(wth->fh, process_info->iconSize, SEEK_CUR, err) == -1) {
870
0
        g_free(process_info);
871
0
        g_hash_table_destroy(process_info_table);
872
0
        return WTAP_OPEN_ERROR;
873
0
      }
874
0
      process_info->iconSize = 0;
875
876
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
877
0
        g_free(process_info);
878
0
        g_hash_table_destroy(process_info_table);
879
0
        return WTAP_OPEN_ERROR;
880
0
      }
881
0
      process_info->pid = pletoh32(&tmp32);
882
883
      /* XXX - Currently index process information by PID */
884
0
      g_hash_table_insert(process_info_table, GUINT_TO_POINTER(process_info->pid), process_info);
885
886
      /* Read local port */
887
0
      if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
888
0
        g_hash_table_destroy(process_info_table);
889
0
        return WTAP_OPEN_ERROR;
890
0
      }
891
0
      process_info->localPort = pletoh16(&tmp16);
892
893
      /* Skip padding */
894
0
      if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
895
0
        g_hash_table_destroy(process_info_table);
896
0
        return WTAP_OPEN_ERROR;
897
0
      }
898
899
      /* Read remote port */
900
0
      if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
901
0
        g_hash_table_destroy(process_info_table);
902
0
        return WTAP_OPEN_ERROR;
903
0
      }
904
0
      process_info->remotePort = pletoh16(&tmp16);
905
906
      /* Skip padding */
907
0
      if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
908
0
        g_hash_table_destroy(process_info_table);
909
0
        return WTAP_OPEN_ERROR;
910
0
      }
911
912
      /* Determine IP version */
913
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
914
0
        g_hash_table_destroy(process_info_table);
915
0
        return WTAP_OPEN_ERROR;
916
0
      }
917
0
      process_info->isIPv6 = ((pletoh32(&tmp32) == 0) ? false : true);
918
919
0
      if (process_info->isIPv6) {
920
0
        if (!wtap_read_bytes(wth->fh, &process_info->localAddr.ipv6, 16, err, err_info)) {
921
0
          g_hash_table_destroy(process_info_table);
922
0
          return WTAP_OPEN_ERROR;
923
0
        }
924
0
        if (!wtap_read_bytes(wth->fh, &process_info->remoteAddr.ipv6, 16, err, err_info)) {
925
0
          g_hash_table_destroy(process_info_table);
926
0
          return WTAP_OPEN_ERROR;
927
0
        }
928
0
      } else {
929
0
        uint8_t ipbuffer[16];
930
0
        if (!wtap_read_bytes(wth->fh, ipbuffer, 16, err, err_info)) {
931
0
          g_hash_table_destroy(process_info_table);
932
0
          return WTAP_OPEN_ERROR;
933
0
        }
934
0
        process_info->localAddr.ipv4 = pletoh32(ipbuffer);
935
936
0
        if (!wtap_read_bytes(wth->fh, ipbuffer, 16, err, err_info)) {
937
0
          g_hash_table_destroy(process_info_table);
938
0
          return WTAP_OPEN_ERROR;
939
0
        }
940
0
        process_info->remoteAddr.ipv4 = pletoh32(ipbuffer);
941
0
      }
942
943
0
      process_info_table_count--;
944
0
    }
945
946
0
    netmon->process_info_table = process_info_table;
947
0
  }
948
949
#if G_BYTE_ORDER == G_BIG_ENDIAN
950
  /*
951
   * OK, now byte-swap the frame table.
952
   */
953
  for (i = 0; i < frame_table_size; i++)
954
    frame_table[i] = pletoh32(&frame_table[i]);
955
#endif
956
957
  /* Set up to start reading at the first frame. */
958
0
  netmon->current_frame = 0;
959
0
  switch (netmon->version_major) {
960
961
0
  case 1:
962
    /*
963
     * Version 1.x of the file format supports
964
     * millisecond precision.
965
     */
966
0
    wth->file_tsprec = WTAP_TSPREC_MSEC;
967
0
    break;
968
969
0
  case 2:
970
    /*
971
     * Versions 2.0 through 2.2 support microsecond
972
     * precision; version 2.3 supports 100-nanosecond
973
     * precision (2.3 was the last version).
974
     */
975
0
    if (netmon->version_minor >= 3)
976
0
      wth->file_tsprec = WTAP_TSPREC_100_NSEC;
977
0
    else
978
0
      wth->file_tsprec = WTAP_TSPREC_USEC;
979
0
    break;
980
0
  }
981
0
  return WTAP_OPEN_MINE;
982
0
}
983
984
static void
985
netmon_set_pseudo_header_info(wtap_rec *rec)
986
0
{
987
0
  switch (rec->rec_header.packet_header.pkt_encap) {
988
989
0
  case WTAP_ENCAP_ATM_PDUS:
990
    /*
991
     * Attempt to guess from the packet data, the VPI, and
992
     * the VCI information about the type of traffic.
993
     */
994
0
    atm_guess_traffic_type(rec);
995
0
    break;
996
997
0
  case WTAP_ENCAP_ETHERNET:
998
    /*
999
     * We assume there's no FCS in this frame.
1000
     */
1001
0
    rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
1002
0
    break;
1003
1004
0
  case WTAP_ENCAP_IEEE_802_11_NETMON:
1005
    /*
1006
     * The 802.11 metadata at the beginnning of the frame data
1007
     * is processed by a dissector, which fills in a pseudo-
1008
     * header and passes it to the 802.11 radio dissector,
1009
     * just as is done with other 802.11 radio metadata headers
1010
     * that are part of the packet data, such as radiotap.
1011
     */
1012
0
    break;
1013
0
  }
1014
0
}
1015
1016
typedef enum {
1017
  SUCCESS,
1018
  FAILURE,
1019
  RETRY
1020
} process_record_retval;
1021
1022
static process_record_retval
1023
netmon_process_record(wtap *wth, FILE_T fh, wtap_rec *rec,
1024
    int *err, char **err_info)
1025
0
{
1026
0
  netmon_t *netmon = (netmon_t *)wth->priv;
1027
0
  int  hdr_size = 0;
1028
0
  union {
1029
0
    struct netmonrec_1_x_hdr hdr_1_x;
1030
0
    struct netmonrec_2_x_hdr hdr_2_x;
1031
0
  } hdr;
1032
0
  int64_t  delta = 0; /* signed - frame times can be before the nominal start */
1033
0
  int64_t  t;
1034
0
  time_t   secs;
1035
0
  int  nsecs;
1036
0
  uint32_t packet_size = 0;
1037
0
  uint32_t orig_size = 0;
1038
0
  int  trlr_size;
1039
0
  union {
1040
0
    struct netmonrec_2_1_trlr trlr_2_1;
1041
0
    struct netmonrec_2_2_trlr trlr_2_2;
1042
0
    struct netmonrec_2_3_trlr trlr_2_3;
1043
0
  } trlr;
1044
0
  uint16_t network;
1045
0
  int  pkt_encap;
1046
0
  struct netmonrec_comment* comment_rec = NULL;
1047
1048
  /* Read record header. */
1049
0
  switch (netmon->version_major) {
1050
1051
0
  case 1:
1052
0
    hdr_size = sizeof (struct netmonrec_1_x_hdr);
1053
0
    break;
1054
1055
0
  case 2:
1056
0
    hdr_size = sizeof (struct netmonrec_2_x_hdr);
1057
0
    break;
1058
0
  }
1059
0
  if (!wtap_read_bytes_or_eof(fh, &hdr, hdr_size, err, err_info))
1060
0
    return FAILURE;
1061
1062
0
  switch (netmon->version_major) {
1063
1064
0
  case 1:
1065
0
    orig_size = pletoh16(&hdr.hdr_1_x.orig_len);
1066
0
    packet_size = pletoh16(&hdr.hdr_1_x.incl_len);
1067
0
    break;
1068
1069
0
  case 2:
1070
0
    orig_size = pletoh32(&hdr.hdr_2_x.orig_len);
1071
0
    packet_size = pletoh32(&hdr.hdr_2_x.incl_len);
1072
0
    break;
1073
0
  }
1074
0
  if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
1075
    /*
1076
     * Probably a corrupt capture file; don't blow up trying
1077
     * to allocate space for an immensely-large packet.
1078
     */
1079
0
    *err = WTAP_ERR_BAD_FILE;
1080
0
    *err_info = ws_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
1081
0
        packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
1082
0
    return FAILURE;
1083
0
  }
1084
1085
0
  rec->rec_type = REC_TYPE_PACKET;
1086
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
1087
1088
  /*
1089
   * If this is an ATM packet, the first
1090
   * "sizeof (struct netmon_atm_hdr)" bytes have destination and
1091
   * source addresses (6 bytes - MAC addresses of some sort?)
1092
   * and the VPI and VCI; read them and generate the pseudo-header
1093
   * from them.
1094
   */
1095
0
  switch (wth->file_encap) {
1096
1097
0
  case WTAP_ENCAP_ATM_PDUS:
1098
0
    if (packet_size < sizeof (struct netmon_atm_hdr)) {
1099
      /*
1100
       * Uh-oh, the packet isn't big enough to even
1101
       * have a pseudo-header.
1102
       */
1103
0
      *err = WTAP_ERR_BAD_FILE;
1104
0
      *err_info = ws_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
1105
0
          packet_size);
1106
0
      return FAILURE;
1107
0
    }
1108
0
    if (!netmon_read_atm_pseudoheader(fh, &rec->rec_header.packet_header.pseudo_header,
1109
0
        err, err_info))
1110
0
      return FAILURE; /* Read error */
1111
1112
    /*
1113
     * Don't count the pseudo-header as part of the packet.
1114
     */
1115
0
    orig_size -= (unsigned)sizeof (struct netmon_atm_hdr);
1116
0
    packet_size -= (unsigned)sizeof (struct netmon_atm_hdr);
1117
0
    break;
1118
1119
0
  default:
1120
0
    break;
1121
0
  }
1122
1123
0
  switch (netmon->version_major) {
1124
1125
0
  case 1:
1126
    /*
1127
     * According to Paul Long, this offset is unsigned.
1128
     * It's 32 bits, so the maximum value will fit in
1129
     * a int64_t such as delta, even after multiplying
1130
     * it by 1000000.
1131
     *
1132
     * pletoh32() returns a uint32_t; we cast it to int64_t
1133
     * before multiplying, so that the product doesn't
1134
     * overflow a uint32_t.
1135
     */
1136
0
    delta = ((int64_t)pletoh32(&hdr.hdr_1_x.ts_delta))*1000000;
1137
0
    break;
1138
1139
0
  case 2:
1140
    /*
1141
     * OK, this is weird.  Microsoft's documentation
1142
     * says this is in microseconds and is a 64-bit
1143
     * unsigned number, but it can be negative; they
1144
     * say what appears to amount to "treat it as an
1145
     * unsigned number, multiply it by 10, and then
1146
     * interpret the resulting 64-bit quantity as a
1147
     * signed number".  That operation can turn a
1148
     * value with the uppermost bit 0 to a value with
1149
     * the uppermost bit 1, hence turning a large
1150
     * positive number-of-microseconds into a small
1151
     * negative number-of-100-nanosecond-increments.
1152
     */
1153
0
    delta = pletoh64(&hdr.hdr_2_x.ts_delta)*10;
1154
1155
    /*
1156
     * OK, it's now a signed value in 100-nanosecond
1157
     * units.  Now convert it to nanosecond units.
1158
     */
1159
0
    delta *= 100;
1160
0
    break;
1161
0
  }
1162
0
  secs = 0;
1163
0
  t = netmon->start_nsecs + delta;
1164
0
  while (t < 0) {
1165
    /*
1166
     * Propagate a borrow into the seconds.
1167
     * The seconds is a time_t, and can be < 0
1168
     * (unlikely, as Windows didn't exist before
1169
     * January 1, 1970, 00:00:00 UTC), while the
1170
     * nanoseconds should be positive, as in
1171
     * "nanoseconds since the instant of time
1172
     * represented by the seconds".
1173
     *
1174
     * We do not want t to be negative, as, according
1175
     * to the C90 standard, "if either operand [of /
1176
     * or %] is negative, whether the result of the
1177
     * / operator is the largest integer less than or
1178
     * equal to the algebraic quotient or the smallest
1179
     * greater than or equal to the algebraic quotient
1180
     * is implementation-defined, as is the sign of
1181
     * the result of the % operator", and we want
1182
     * the result of the division and remainder
1183
     * operations to be the same on all platforms.
1184
     */
1185
0
    t += 1000000000;
1186
0
    secs--;
1187
0
  }
1188
0
  secs += (time_t)(t/1000000000);
1189
0
  nsecs = (int)(t%1000000000);
1190
0
  rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
1191
0
  rec->ts.secs = netmon->start_secs + secs;
1192
0
  rec->ts.nsecs = nsecs;
1193
0
  rec->rec_header.packet_header.caplen = packet_size;
1194
0
  rec->rec_header.packet_header.len = orig_size;
1195
1196
  /*
1197
   * Read the packet data.
1198
   */
1199
0
  if (!wtap_read_bytes_buffer(fh, &rec->data, rec->rec_header.packet_header.caplen, err, err_info))
1200
0
    return FAILURE;
1201
1202
  /*
1203
   * For version 2.1 and later, there's additional information
1204
   * after the frame data.
1205
   */
1206
0
  if (netmon->version_major == 2 && netmon->version_minor >= 1) {
1207
0
    switch (netmon->version_minor) {
1208
1209
0
    case 1:
1210
0
      trlr_size = (int)sizeof (struct netmonrec_2_1_trlr);
1211
0
      break;
1212
1213
0
    case 2:
1214
0
      trlr_size = (int)sizeof (struct netmonrec_2_2_trlr);
1215
0
      break;
1216
1217
0
    default:
1218
0
      trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
1219
0
      break;
1220
0
    }
1221
1222
0
    if (!wtap_read_bytes(fh, &trlr, trlr_size, err, err_info))
1223
0
      return FAILURE;
1224
1225
0
    network = pletoh16(trlr.trlr_2_1.network);
1226
0
    if ((network >= 0xE080) && (network <= 0xE08A)) {
1227
      /* These values "violate" the LINKTYPE_ media type values
1228
       * in Microsoft Analyzer and are considered a MAExportedMediaType,
1229
       * so they need their own WTAP_ types
1230
       */
1231
0
      switch (network)
1232
0
      {
1233
0
      case 0xE080:    // "WiFi Message"
1234
0
        pkt_encap = WTAP_ENCAP_IEEE_802_11;
1235
0
        break;
1236
0
      case 0xE081:    // "Ndis Etw WiFi Channel Message"
1237
0
      case 0xE082:    // "Fiddler Netmon Message"
1238
0
      case 0xE089:    // "Pef Ndis Msg";
1239
0
      case 0xE08A:    // "Pef Ndis Wifi Meta Msg";
1240
0
        *err = WTAP_ERR_UNSUPPORTED;
1241
0
        *err_info = ws_strdup_printf("netmon: network type %u unknown or unsupported", network);
1242
0
        return FAILURE;
1243
0
      case 0xE083:
1244
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_V4;
1245
0
        break;
1246
0
      case 0xE084:
1247
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_V6;
1248
0
        break;
1249
0
      case 0xE085:
1250
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_2V4;
1251
0
        break;
1252
0
      case 0xE086:
1253
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_2V6;
1254
0
        break;
1255
0
      case 0xE087:
1256
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_AUTH_V4;
1257
0
        break;
1258
0
      case 0xE088:
1259
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_AUTH_V6;
1260
0
        break;
1261
0
      default:
1262
0
        pkt_encap = WTAP_ENCAP_UNKNOWN;
1263
0
        break;
1264
0
      }
1265
0
    } else if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
1266
      /*
1267
       * Converted pcap file - the LINKTYPE_ value
1268
       * is the network value with 0xF000 masked off.
1269
       */
1270
0
      network &= 0x0FFF;
1271
0
      pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
1272
0
      if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
1273
0
        *err = WTAP_ERR_UNSUPPORTED;
1274
0
        *err_info = ws_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
1275
0
            network);
1276
0
        return FAILURE;
1277
0
      }
1278
0
    } else if (network < NUM_NETMON_ENCAPS) {
1279
      /*
1280
       * Regular NetMon encapsulation.
1281
       */
1282
0
      pkt_encap = netmon_encap[network];
1283
0
      if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
1284
0
        *err = WTAP_ERR_UNSUPPORTED;
1285
0
        *err_info = ws_strdup_printf("netmon: network type %u unknown or unsupported",
1286
0
            network);
1287
0
        return FAILURE;
1288
0
      }
1289
0
    } else {
1290
      /*
1291
       * Special packet type for metadata.
1292
       */
1293
0
      switch (network) {
1294
1295
0
      case NETMON_NET_NETEVENT:
1296
        /*
1297
         * Event Tracing event.
1298
         *
1299
         * https://docs.microsoft.com/en-us/windows/win32/api/evntcons/ns-evntcons-event_header
1300
         */
1301
0
        pkt_encap = WTAP_ENCAP_NETMON_NET_NETEVENT;
1302
0
        break;
1303
1304
0
      case NETMON_NET_NETWORK_INFO_EX:
1305
        /*
1306
         * List of adapters on which the capture
1307
         * was done.
1308
         * XXX - this could be translated into pcapng
1309
         * blocks but for now, just treat as a frame.
1310
         */
1311
0
        pkt_encap = WTAP_ENCAP_NETMON_NETWORK_INFO_EX;
1312
0
        break;
1313
1314
0
      case NETMON_NET_PAYLOAD_HEADER:
1315
        /*
1316
         * Header for a fake frame constructed
1317
         * by reassembly.
1318
         */
1319
0
        return RETRY;
1320
1321
0
      case NETMON_NET_NETWORK_INFO:
1322
        /*
1323
         * List of adapters on which the capture
1324
         * was done.
1325
         */
1326
0
        return RETRY;
1327
1328
0
      case NETMON_NET_DNS_CACHE:
1329
        /*
1330
         * List of resolved IP addresses.
1331
         */
1332
0
        return RETRY;
1333
1334
0
      case NETMON_NET_NETMON_FILTER:
1335
        /*
1336
         * NetMon capture or display filter
1337
         * string.
1338
         */
1339
0
        pkt_encap = WTAP_ENCAP_NETMON_NET_FILTER;
1340
0
        break;
1341
1342
0
      default:
1343
0
        *err = WTAP_ERR_UNSUPPORTED;
1344
0
        *err_info = ws_strdup_printf("netmon: network type %u unknown or unsupported",
1345
0
            network);
1346
0
        return FAILURE;
1347
0
      }
1348
0
    }
1349
1350
0
    rec->rec_header.packet_header.pkt_encap = pkt_encap;
1351
0
    if (netmon->version_minor >= 3) {
1352
      /*
1353
       * This is a 2.3 or later file.  That format
1354
       * contains a UTC per-packet time stamp; use
1355
       * that instead of the start time and offset.
1356
       */
1357
0
      uint64_t d;
1358
1359
0
      d = pletoh64(trlr.trlr_2_3.utc_timestamp);
1360
1361
      /*
1362
       * Get the time as seconds and nanoseconds.
1363
       * and overwrite the time stamp obtained
1364
       * from the record header.
1365
       */
1366
0
      if (!filetime_to_nstime(&rec->ts, d)) {
1367
0
        *err = WTAP_ERR_BAD_FILE;
1368
0
        *err_info = g_strdup("netmon: time stamp outside supported range");
1369
0
        return FAILURE;
1370
0
      }
1371
0
    }
1372
0
  }
1373
1374
0
  netmon_set_pseudo_header_info(rec);
1375
1376
  /* If any header specific information is present, set it as pseudo header data
1377
   * and set the encapsulation type, so it can be handled to the netmon_header
1378
   * dissector for further processing
1379
   */
1380
0
  if (netmon->comment_table != NULL) {
1381
0
    comment_rec = (struct netmonrec_comment*)g_hash_table_lookup(netmon->comment_table, GUINT_TO_POINTER(netmon->frame_table[netmon->current_frame-1]));
1382
0
  }
1383
1384
0
  if (comment_rec != NULL) {
1385
0
    union wtap_pseudo_header temp_header;
1386
1387
    /* These are the current encapsulation types that NetMon uses.
1388
     * Save them off so they can be copied to the NetMon pseudoheader
1389
     */
1390
0
    switch (rec->rec_header.packet_header.pkt_encap)
1391
0
    {
1392
0
    case WTAP_ENCAP_ATM_PDUS:
1393
0
      memcpy(&temp_header.atm, &rec->rec_header.packet_header.pseudo_header.atm, sizeof(temp_header.atm));
1394
0
      break;
1395
0
    case WTAP_ENCAP_ETHERNET:
1396
0
      memcpy(&temp_header.eth, &rec->rec_header.packet_header.pseudo_header.eth, sizeof(temp_header.eth));
1397
0
      break;
1398
0
    case WTAP_ENCAP_IEEE_802_11_NETMON:
1399
0
      memcpy(&temp_header.ieee_802_11, &rec->rec_header.packet_header.pseudo_header.ieee_802_11, sizeof(temp_header.ieee_802_11));
1400
0
      break;
1401
0
    }
1402
0
    memset(&rec->rec_header.packet_header.pseudo_header.netmon, 0, sizeof(rec->rec_header.packet_header.pseudo_header.netmon));
1403
1404
    /* Save the current encapsulation type to the NetMon pseudoheader */
1405
0
    rec->rec_header.packet_header.pseudo_header.netmon.sub_encap = rec->rec_header.packet_header.pkt_encap;
1406
1407
    /* Copy the comment data */
1408
0
    rec->rec_header.packet_header.pseudo_header.netmon.title = comment_rec->title;
1409
0
    rec->rec_header.packet_header.pseudo_header.netmon.descLength = comment_rec->descLength;
1410
0
    rec->rec_header.packet_header.pseudo_header.netmon.description = comment_rec->description;
1411
1412
    /* Copy the saved pseudoheaders to the netmon pseudoheader structure */
1413
0
    switch (rec->rec_header.packet_header.pkt_encap)
1414
0
    {
1415
0
    case WTAP_ENCAP_ATM_PDUS:
1416
0
      memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.atm, &temp_header.atm, sizeof(temp_header.atm));
1417
0
      break;
1418
0
    case WTAP_ENCAP_ETHERNET:
1419
0
      memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.eth, &temp_header.eth, sizeof(temp_header.eth));
1420
0
      break;
1421
0
    case WTAP_ENCAP_IEEE_802_11_NETMON:
1422
0
      memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.ieee_802_11, &temp_header.ieee_802_11, sizeof(temp_header.ieee_802_11));
1423
0
      break;
1424
0
    }
1425
1426
    /* Encapsulation type is now something that can be passed to netmon_header dissector */
1427
0
    rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_NETMON_HEADER;
1428
0
  }
1429
1430
0
  return SUCCESS;
1431
0
}
1432
1433
/* Read the next packet */
1434
static bool netmon_read(wtap *wth, wtap_rec *rec,
1435
    int *err, char **err_info, int64_t *data_offset)
1436
0
{
1437
0
  netmon_t *netmon = (netmon_t *)wth->priv;
1438
0
  int64_t rec_offset;
1439
1440
0
  for (;;) {
1441
    /* Have we reached the end of the packet data? */
1442
0
    if (netmon->current_frame >= netmon->frame_table_size) {
1443
0
      *err = 0; /* it's just an EOF, not an error */
1444
0
      return false;
1445
0
    }
1446
1447
    /* Seek to the beginning of the current record, if we're
1448
       not there already (seeking to the current position
1449
       may still cause a seek and a read of the underlying file,
1450
       so we don't want to do it unconditionally).
1451
1452
       Yes, the current record could be before the previous
1453
       record.  At least some captures put the trailer record
1454
       with statistics as the first physical record in the
1455
       file, but set the frame table up so it's the last
1456
       record in sequence. */
1457
0
    rec_offset = netmon->frame_table[netmon->current_frame];
1458
0
    if (file_tell(wth->fh) != rec_offset) {
1459
0
      if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
1460
0
        return false;
1461
0
    }
1462
0
    netmon->current_frame++;
1463
1464
0
    *data_offset = file_tell(wth->fh);
1465
1466
0
    switch (netmon_process_record(wth, wth->fh, rec, err, err_info)) {
1467
1468
0
    case RETRY:
1469
0
      continue;
1470
1471
0
    case SUCCESS:
1472
0
      return true;
1473
1474
0
    case FAILURE:
1475
0
      return false;
1476
0
    }
1477
0
  }
1478
0
}
1479
1480
static bool
1481
netmon_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
1482
    int *err, char **err_info)
1483
0
{
1484
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1485
0
    return false;
1486
1487
0
  switch (netmon_process_record(wth, wth->random_fh, rec, err, err_info)) {
1488
1489
0
  default:
1490
    /*
1491
     * This should not happen.
1492
     */
1493
0
    *err = WTAP_ERR_BAD_FILE;
1494
0
    *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
1495
0
    return false;
1496
1497
0
  case SUCCESS:
1498
0
    return true;
1499
1500
0
  case FAILURE:
1501
0
    return false;
1502
0
  }
1503
0
}
1504
1505
static bool
1506
netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
1507
    int *err, char **err_info)
1508
0
{
1509
0
  struct netmon_atm_hdr atm_phdr;
1510
0
  uint16_t  vpi, vci;
1511
1512
0
  if (!wtap_read_bytes(fh, &atm_phdr, sizeof (struct netmon_atm_hdr),
1513
0
      err, err_info))
1514
0
    return false;
1515
1516
0
  vpi = g_ntohs(atm_phdr.vpi);
1517
0
  vci = g_ntohs(atm_phdr.vci);
1518
1519
0
  pseudo_header->atm.vpi = vpi;
1520
0
  pseudo_header->atm.vci = vci;
1521
1522
  /* We don't have this information */
1523
0
  pseudo_header->atm.flags = 0;
1524
0
  pseudo_header->atm.channel = 0;
1525
0
  pseudo_header->atm.cells = 0;
1526
0
  pseudo_header->atm.aal5t_u2u = 0;
1527
0
  pseudo_header->atm.aal5t_len = 0;
1528
0
  pseudo_header->atm.aal5t_chksum = 0;
1529
1530
0
  return true;
1531
0
}
1532
1533
/* Throw away the frame table used by the sequential I/O stream. */
1534
static void
1535
netmon_close(wtap *wth)
1536
0
{
1537
0
  netmon_t *netmon = (netmon_t *)wth->priv;
1538
1539
0
  if (netmon->frame_table != NULL) {
1540
0
    g_free(netmon->frame_table);
1541
0
    netmon->frame_table = NULL;
1542
0
  }
1543
1544
0
  if (netmon->comment_table != NULL) {
1545
0
    g_hash_table_destroy(netmon->comment_table);
1546
0
    netmon->comment_table = NULL;
1547
0
  }
1548
1549
0
  if (netmon->process_info_table != NULL) {
1550
0
    g_hash_table_destroy(netmon->process_info_table);
1551
0
    netmon->process_info_table = NULL;
1552
0
  }
1553
0
}
1554
1555
typedef struct {
1556
  bool is_v2;
1557
  bool got_first_record_time;
1558
  nstime_t first_record_time;
1559
  uint32_t frame_table_offset;
1560
  uint32_t *frame_table;
1561
  unsigned frame_table_index;
1562
  unsigned frame_table_size;
1563
  bool no_more_room;    /* true if no more records can be written */
1564
} netmon_dump_t;
1565
1566
static const int wtap_encap[] = {
1567
  -1,   /* WTAP_ENCAP_UNKNOWN -> unsupported */
1568
  1,    /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
1569
  2,    /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
1570
  -1,   /* WTAP_ENCAP_SLIP -> unsupported */
1571
  -1,   /* WTAP_ENCAP_PPP -> unsupported */
1572
  3,    /* WTAP_ENCAP_FDDI -> NDIS FDDI */
1573
  3,    /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
1574
  -1,   /* WTAP_ENCAP_RAW_IP -> unsupported */
1575
  -1,   /* WTAP_ENCAP_ARCNET -> unsupported */
1576
  -1,   /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
1577
  -1,   /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
1578
  -1,   /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
1579
  -1,   /* WTAP_ENCAP_LAPB -> unsupported*/
1580
  4,    /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
1581
};
1582
0
#define NUM_WTAP_ENCAPS array_length(wtap_encap)
1583
1584
/* Returns 0 if we could write the specified encapsulation type,
1585
   an error indication otherwise. */
1586
static int netmon_dump_can_write_encap_1_x(int encap)
1587
0
{
1588
  /*
1589
   * Per-packet encapsulations are *not* supported in NetMon 1.x
1590
   * format.
1591
   */
1592
0
  if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
1593
0
    return WTAP_ERR_UNWRITABLE_ENCAP;
1594
1595
0
  return 0;
1596
0
}
1597
1598
static int netmon_dump_can_write_encap_2_x(int encap)
1599
0
{
1600
  /*
1601
   * Per-packet encapsulations are supported in NetMon 2.1
1602
   * format.
1603
   */
1604
0
  if (encap == WTAP_ENCAP_PER_PACKET)
1605
0
    return 0;
1606
1607
0
  if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
1608
0
    return WTAP_ERR_UNWRITABLE_ENCAP;
1609
1610
0
  return 0;
1611
0
}
1612
1613
/* Returns true on success, false on failure; sets "*err" to an error code on
1614
   failure */
1615
static bool netmon_dump_open(wtap_dumper *wdh, bool is_v2,
1616
                                 int *err, char **err_info _U_)
1617
0
{
1618
0
  netmon_dump_t *netmon;
1619
1620
  /* We can't fill in all the fields in the file header, as we
1621
     haven't yet written any packets.  As we'll have to rewrite
1622
     the header when we've written out all the packets, we just
1623
     skip over the header for now. */
1624
0
  if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
1625
0
    return false;
1626
1627
0
  wdh->bytes_dumped = CAPTUREFILE_HEADER_SIZE;
1628
0
  wdh->subtype_write = netmon_dump;
1629
0
  wdh->subtype_finish = netmon_dump_finish;
1630
1631
0
  netmon = g_new(netmon_dump_t, 1);
1632
0
  wdh->priv = (void *)netmon;
1633
0
  netmon->is_v2 = is_v2;
1634
0
  netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
1635
0
  netmon->got_first_record_time = false;
1636
0
  netmon->frame_table = NULL;
1637
0
  netmon->frame_table_index = 0;
1638
0
  netmon->frame_table_size = 0;
1639
0
  netmon->no_more_room = false;
1640
1641
0
  return true;
1642
0
}
1643
1644
static bool netmon_dump_open_1_x(wtap_dumper *wdh, int *err, char **err_info _U_)
1645
0
{
1646
0
  return netmon_dump_open(wdh, false, err, err_info);
1647
0
}
1648
1649
static bool netmon_dump_open_2_x(wtap_dumper *wdh, int *err, char **err_info _U_)
1650
0
{
1651
0
  return netmon_dump_open(wdh, true, err, err_info);
1652
0
}
1653
1654
/* Write a record for a packet to a dump file.
1655
   Returns true on success, false on failure. */
1656
static bool netmon_dump(wtap_dumper *wdh, const wtap_rec *rec,
1657
    const uint8_t *pd, int *err, char **err_info _U_)
1658
0
{
1659
0
  const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
1660
0
  netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1661
0
  struct netmonrec_1_x_hdr rec_1_x_hdr;
1662
0
  struct netmonrec_2_x_hdr rec_2_x_hdr;
1663
0
  void *hdrp;
1664
0
  size_t rec_size;
1665
0
  struct netmonrec_2_1_trlr rec_2_x_trlr;
1666
0
  size_t hdr_size;
1667
0
  struct netmon_atm_hdr atm_hdr;
1668
0
  int atm_hdrsize;
1669
0
  int64_t secs;
1670
0
  int32_t nsecs;
1671
1672
  /* We can only write packet records. */
1673
0
  if (rec->rec_type != REC_TYPE_PACKET) {
1674
0
    *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
1675
0
    return false;
1676
0
  }
1677
1678
0
  if (netmon->is_v2) {
1679
    /* Don't write anything we're not willing to read. */
1680
0
    if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
1681
0
      *err = WTAP_ERR_PACKET_TOO_LARGE;
1682
0
      return false;
1683
0
    }
1684
0
  } else {
1685
    /*
1686
     * Make sure this packet doesn't have a link-layer type that
1687
     * differs from the one for the file.
1688
     */
1689
0
    if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
1690
0
      *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
1691
0
      return false;
1692
0
    }
1693
1694
    /*
1695
     * The length fields are 16-bit, so there's a hard limit
1696
     * of 65535.
1697
     */
1698
0
    if (rec->rec_header.packet_header.caplen > 65535) {
1699
0
      *err = WTAP_ERR_PACKET_TOO_LARGE;
1700
0
      return false;
1701
0
    }
1702
0
  }
1703
1704
0
  if (wdh->file_encap == WTAP_ENCAP_PER_PACKET) {
1705
    /*
1706
     * Is this network type supported?
1707
     */
1708
0
    if (rec->rec_header.packet_header.pkt_encap < 0 ||
1709
0
        (unsigned) rec->rec_header.packet_header.pkt_encap >= NUM_WTAP_ENCAPS ||
1710
0
        wtap_encap[rec->rec_header.packet_header.pkt_encap] == -1) {
1711
      /*
1712
       * No.  Fail.
1713
       */
1714
0
      *err = WTAP_ERR_UNWRITABLE_ENCAP;
1715
0
      return false;
1716
0
    }
1717
1718
    /*
1719
     * Fill in the trailer with the network type.
1720
     */
1721
0
    phtoles(rec_2_x_trlr.network, wtap_encap[rec->rec_header.packet_header.pkt_encap]);
1722
0
  }
1723
1724
  /*
1725
   * Will the file offset of this frame fit in a 32-bit unsigned
1726
   * integer?
1727
   */
1728
0
  if (netmon->no_more_room) {
1729
    /*
1730
     * No, so the file is too big for NetMon format to
1731
     * handle.
1732
     */
1733
0
    *err = EFBIG;
1734
0
    return false;
1735
0
  }
1736
1737
  /*
1738
   * NetMon files have a capture start time in the file header,
1739
   * and have times relative to that in the packet headers;
1740
   * pick the time of the first packet as the capture start
1741
   * time.
1742
   *
1743
   * That time has millisecond resolution, so chop any
1744
   * sub-millisecond part of the time stamp off.
1745
   */
1746
0
  if (!netmon->got_first_record_time) {
1747
0
    netmon->first_record_time.secs = rec->ts.secs;
1748
0
    netmon->first_record_time.nsecs =
1749
0
        (rec->ts.nsecs/1000000)*1000000;
1750
0
    netmon->got_first_record_time = true;
1751
0
  }
1752
1753
0
  if (wdh->file_encap == WTAP_ENCAP_ATM_PDUS)
1754
0
    atm_hdrsize = sizeof (struct netmon_atm_hdr);
1755
0
  else
1756
0
    atm_hdrsize = 0;
1757
0
  secs = (int64_t)(rec->ts.secs - netmon->first_record_time.secs);
1758
0
  nsecs = rec->ts.nsecs - netmon->first_record_time.nsecs;
1759
0
  while (nsecs < 0) {
1760
    /*
1761
     * Propagate a borrow into the seconds.
1762
     * The seconds is a time_t, and can be < 0
1763
     * (unlikely, as neither UN*X nor DOS
1764
     * nor the original Mac System existed
1765
     * before January 1, 1970, 00:00:00 UTC),
1766
     * while the nanoseconds should be positive,
1767
     * as in "nanoseconds since the instant of time
1768
     * represented by the seconds".
1769
     *
1770
     * We do not want t to be negative, as, according
1771
     * to the C90 standard, "if either operand [of /
1772
     * or %] is negative, whether the result of the
1773
     * / operator is the largest integer less than or
1774
     * equal to the algebraic quotient or the smallest
1775
     * greater than or equal to the algebraic quotient
1776
     * is implementation-defined, as is the sign of
1777
     * the result of the % operator", and we want
1778
     * the result of the division and remainder
1779
     * operations to be the same on all platforms.
1780
     */
1781
0
    nsecs += 1000000000;
1782
0
    secs--;
1783
0
  }
1784
0
  if (netmon->is_v2) {
1785
0
    rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
1786
0
    rec_2_x_hdr.orig_len = GUINT32_TO_LE(rec->rec_header.packet_header.len + atm_hdrsize);
1787
0
    rec_2_x_hdr.incl_len = GUINT32_TO_LE(rec->rec_header.packet_header.caplen + atm_hdrsize);
1788
0
    hdrp = &rec_2_x_hdr;
1789
0
    hdr_size = sizeof rec_2_x_hdr;
1790
0
  } else {
1791
0
    rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
1792
0
    rec_1_x_hdr.orig_len = GUINT16_TO_LE(rec->rec_header.packet_header.len + atm_hdrsize);
1793
0
    rec_1_x_hdr.incl_len = GUINT16_TO_LE(rec->rec_header.packet_header.caplen + atm_hdrsize);
1794
0
    hdrp = &rec_1_x_hdr;
1795
0
    hdr_size = sizeof rec_1_x_hdr;
1796
0
  }
1797
1798
  /*
1799
   * Keep track of the record size, as we need to update
1800
   * the current file offset.
1801
   */
1802
0
  rec_size = 0;
1803
1804
0
  if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1805
0
    return false;
1806
0
  rec_size += hdr_size;
1807
1808
0
  if (wdh->file_encap == WTAP_ENCAP_ATM_PDUS) {
1809
    /*
1810
     * Write the ATM header.
1811
     * We supply all-zero destination and source addresses.
1812
     */
1813
0
    memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1814
0
    memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1815
0
    atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1816
0
    atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1817
0
    if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1818
0
      return false;
1819
0
    rec_size += sizeof atm_hdr;
1820
0
  }
1821
1822
0
  if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
1823
0
    return false;
1824
0
  rec_size += rec->rec_header.packet_header.caplen;
1825
1826
0
  if (wdh->file_encap == WTAP_ENCAP_PER_PACKET) {
1827
    /*
1828
     * Write out the trailer.
1829
     */
1830
0
    if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1831
0
        sizeof rec_2_x_trlr, err))
1832
0
      return false;
1833
0
    rec_size += sizeof rec_2_x_trlr;
1834
0
  }
1835
1836
  /*
1837
   * Stash the file offset of this frame.
1838
   */
1839
0
  if (netmon->frame_table_size == 0) {
1840
    /*
1841
     * Haven't yet allocated the buffer for the frame table.
1842
     */
1843
0
    netmon->frame_table = (uint32_t *)g_malloc(1024 * sizeof *netmon->frame_table);
1844
0
    netmon->frame_table_size = 1024;
1845
0
  } else {
1846
    /*
1847
     * We've allocated it; are we at the end?
1848
     */
1849
0
    if (netmon->frame_table_index >= netmon->frame_table_size) {
1850
      /*
1851
       * Yes - double the size of the frame table.
1852
       */
1853
0
      netmon->frame_table_size *= 2;
1854
0
      netmon->frame_table = (uint32_t *)g_realloc(netmon->frame_table,
1855
0
          netmon->frame_table_size * sizeof *netmon->frame_table);
1856
0
    }
1857
0
  }
1858
1859
0
  netmon->frame_table[netmon->frame_table_index] =
1860
0
      GUINT32_TO_LE(netmon->frame_table_offset);
1861
1862
  /*
1863
   * Is this the last record we can write?
1864
   * I.e., will the frame table offset of the next record not fit
1865
   * in a 32-bit frame table offset entry?
1866
   *
1867
   * (We don't bother checking whether the number of frames
1868
   * will fit in a 32-bit value, as, even if each record were
1869
   * 1 byte, if there were more than 2^32-1 packets, the frame
1870
   * table offset of at least one of those packets will be >
1871
   * 2^32 - 1.)
1872
   *
1873
   * Note: this also catches the unlikely possibility that
1874
   * the record itself is > 2^32 - 1 bytes long.
1875
   */
1876
0
  if ((uint64_t)netmon->frame_table_offset + rec_size > UINT32_MAX) {
1877
    /*
1878
     * Yup, too big.
1879
     */
1880
0
    netmon->no_more_room = true;
1881
0
  }
1882
0
  netmon->frame_table_index++;
1883
0
  netmon->frame_table_offset += (uint32_t) rec_size;
1884
1885
0
  return true;
1886
0
}
1887
1888
/* Finish writing to a dump file.
1889
   Returns true on success, false on failure. */
1890
static bool netmon_dump_finish(wtap_dumper *wdh, int *err,
1891
    char **err_info _U_)
1892
0
{
1893
0
  netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1894
0
  size_t n_to_write;
1895
0
  struct netmon_hdr file_hdr;
1896
0
  const char *magicp;
1897
0
  size_t magic_size;
1898
0
  struct tm *tm;
1899
0
  int64_t saved_bytes_dumped;
1900
1901
  /* Write out the frame table.  "netmon->frame_table_index" is
1902
     the number of entries we've put into it. */
1903
0
  n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1904
0
  if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1905
0
    return false;
1906
1907
  /* Now go fix up the file header. */
1908
0
  if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1909
0
    return false;
1910
  /* Save bytes_dumped since following calls to wtap_dump_file_write()
1911
   * will still (mistakenly) increase it.
1912
   */
1913
0
  saved_bytes_dumped = wdh->bytes_dumped;
1914
0
  memset(&file_hdr, '\0', sizeof file_hdr);
1915
0
  if (netmon->is_v2) {
1916
0
    magicp = netmon_2_x_magic;
1917
0
    magic_size = sizeof netmon_2_x_magic;
1918
    /*
1919
     * NetMon file version, for 2.x, is 2.0;
1920
     * for 3.0, it's 2.1.
1921
     *
1922
     * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1923
     * we need version 2.1.
1924
     *
1925
     * XXX - version 2.3 supports UTC time stamps; when
1926
     * should we use it?  According to the file format
1927
     * documentation, NetMon 3.3 "cannot properly
1928
     * interpret" the UTC timestamp information; does
1929
     * that mean it ignores it and uses the local-time
1930
     * start time and time deltas, or mishandles them?
1931
     * Also, NetMon 3.1 and earlier can't read version
1932
     * 2.2, much less version 2.3.
1933
     */
1934
0
    file_hdr.ver_major = 2;
1935
0
    file_hdr.ver_minor =
1936
0
        (wdh->file_encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1937
0
  } else {
1938
0
    magicp = netmon_1_x_magic;
1939
0
    magic_size = sizeof netmon_1_x_magic;
1940
    /* NetMon file version, for 1.x, is 1.1 */
1941
0
    file_hdr.ver_major = 1;
1942
0
    file_hdr.ver_minor = 1;
1943
0
  }
1944
0
  if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1945
0
    return false;
1946
1947
0
  if (wdh->file_encap == WTAP_ENCAP_PER_PACKET) {
1948
    /*
1949
     * We're writing NetMon 2.1 format, so the media
1950
     * type in the file header is irrelevant.  Set it
1951
     * to 1, just as Network Monitor does.
1952
     */
1953
0
    file_hdr.network = GUINT16_TO_LE(1);
1954
0
  } else
1955
0
    file_hdr.network = GUINT16_TO_LE(wtap_encap[wdh->file_encap]);
1956
0
  tm = localtime(&netmon->first_record_time.secs);
1957
0
  if (tm != NULL) {
1958
0
    file_hdr.ts_year  = GUINT16_TO_LE(1900 + tm->tm_year);
1959
0
    file_hdr.ts_month = GUINT16_TO_LE(tm->tm_mon + 1);
1960
0
    file_hdr.ts_dow   = GUINT16_TO_LE(tm->tm_wday);
1961
0
    file_hdr.ts_day   = GUINT16_TO_LE(tm->tm_mday);
1962
0
    file_hdr.ts_hour  = GUINT16_TO_LE(tm->tm_hour);
1963
0
    file_hdr.ts_min   = GUINT16_TO_LE(tm->tm_min);
1964
0
    file_hdr.ts_sec   = GUINT16_TO_LE(tm->tm_sec);
1965
0
  } else {
1966
0
    file_hdr.ts_year  = GUINT16_TO_LE(1900 + 0);
1967
0
    file_hdr.ts_month = GUINT16_TO_LE(0 + 1);
1968
0
    file_hdr.ts_dow   = GUINT16_TO_LE(0);
1969
0
    file_hdr.ts_day   = GUINT16_TO_LE(0);
1970
0
    file_hdr.ts_hour  = GUINT16_TO_LE(0);
1971
0
    file_hdr.ts_min   = GUINT16_TO_LE(0);
1972
0
    file_hdr.ts_sec   = GUINT16_TO_LE(0);
1973
0
  }
1974
0
  file_hdr.ts_msec = GUINT16_TO_LE(netmon->first_record_time.nsecs/1000000);
1975
0
  file_hdr.frametableoffset = GUINT32_TO_LE(netmon->frame_table_offset);
1976
0
  file_hdr.frametablelength =
1977
0
      GUINT32_TO_LE(netmon->frame_table_index * sizeof *netmon->frame_table);
1978
0
  if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1979
0
    return false;
1980
1981
0
  wdh->bytes_dumped = saved_bytes_dumped;
1982
0
  return true;
1983
0
}
1984
1985
static const struct supported_block_type netmon_1_x_blocks_supported[] = {
1986
  /*
1987
   * We support packet blocks, with no comments or other options.
1988
   */
1989
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
1990
};
1991
1992
static const struct file_type_subtype_info netmon_1_x_info = {
1993
  "Microsoft NetMon 1.x", "netmon1", "cap", NULL,
1994
  true, BLOCKS_SUPPORTED(netmon_1_x_blocks_supported),
1995
  netmon_dump_can_write_encap_1_x, netmon_dump_open_1_x, NULL
1996
};
1997
1998
static const struct supported_block_type netmon_2_x_blocks_supported[] = {
1999
  /*
2000
   * We support packet blocks, with no comments or other options.
2001
   */
2002
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
2003
};
2004
2005
static const struct file_type_subtype_info netmon_2_x_info = {
2006
  "Microsoft NetMon 2.x", "netmon2", "cap", NULL,
2007
  true, BLOCKS_SUPPORTED(netmon_2_x_blocks_supported),
2008
  netmon_dump_can_write_encap_2_x, netmon_dump_open_2_x, NULL
2009
};
2010
2011
void register_netmon(void)
2012
14
{
2013
14
  netmon_1_x_file_type_subtype = wtap_register_file_type_subtype(&netmon_1_x_info);
2014
14
  netmon_2_x_file_type_subtype = wtap_register_file_type_subtype(&netmon_2_x_info);
2015
2016
  /*
2017
   * Register names for backwards compatibility with the
2018
   * wtap_filetypes table in Lua.
2019
   */
2020
14
  wtap_register_backwards_compatibility_lua_name("NETMON_1_x",
2021
14
      netmon_1_x_file_type_subtype);
2022
14
  wtap_register_backwards_compatibility_lua_name("NETMON_2_x",
2023
14
      netmon_2_x_file_type_subtype);
2024
14
}
2025
2026
/*
2027
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2028
 *
2029
 * Local variables:
2030
 * c-basic-offset: 8
2031
 * tab-width: 8
2032
 * indent-tabs-mode: t
2033
 * End:
2034
 *
2035
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2036
 * :indentSize=8:tabSize=8:noTabs=false:
2037
 */