Coverage Report

Created: 2026-08-14 06:45

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