Coverage Report

Created: 2025-12-27 06:52

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_hash_table_destroy(comment_table);
747
0
        return WTAP_OPEN_ERROR;
748
0
      }
749
0
      comment_table_size -= title_length;
750
751
      /*
752
       * Now convert it to UTF-8 for internal use.
753
       */
754
0
      comment_rec->title = utf_16_to_utf_8(utf16_str,
755
0
          title_length);
756
0
      g_free(utf16_str);
757
758
0
      if (comment_table_size < 4) {
759
0
        *err = WTAP_ERR_BAD_FILE;
760
0
        *err_info = g_strdup("netmon: corrupt comment section");
761
0
        g_hash_table_destroy(comment_table);
762
0
        return WTAP_OPEN_ERROR;
763
0
      }
764
765
0
      if (!wtap_read_bytes(wth->fh, &desc_length, 4, err, err_info)) {
766
0
        g_hash_table_destroy(comment_table);
767
0
        return WTAP_OPEN_ERROR;
768
0
      }
769
0
      comment_table_size -= 4;
770
771
0
      comment_rec->descLength = pletohu32(&desc_length);
772
0
      if (comment_rec->descLength > 0) {
773
        /* Make sure comment size is sane */
774
0
        if (comment_rec->descLength > comment_table_size) {
775
0
          *err = WTAP_ERR_BAD_FILE;
776
0
          *err_info = ws_strdup_printf("netmon: comment description size is %u, which is larger than the amount remaining in the comment section (%u)",
777
0
                comment_rec->descLength, comment_table_size);
778
0
          g_hash_table_destroy(comment_table);
779
0
          return WTAP_OPEN_ERROR;
780
0
        }
781
782
0
        comment_rec->description = (uint8_t*)g_malloc(comment_rec->descLength);
783
784
        /* Read the comment description */
785
0
        if (!wtap_read_bytes(wth->fh, comment_rec->description, comment_rec->descLength, err, err_info)) {
786
0
          g_hash_table_destroy(comment_table);
787
0
          return WTAP_OPEN_ERROR;
788
0
        }
789
790
0
        comment_table_size -= comment_rec->descLength;
791
0
      }
792
0
    }
793
0
    netmon->comment_table = comment_table;
794
0
  }
795
796
0
  if ((process_info_table_offset > 0) && (process_info_table_count > 0)) {
797
0
    uint16_t version;
798
799
    /* Go to the process table offset */
800
0
    if (file_seek(wth->fh, process_info_table_offset, SEEK_SET, err) == -1) {
801
0
      return WTAP_OPEN_ERROR;
802
0
    }
803
804
0
    process_info_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, netmonrec_process_info_destroy);
805
0
    if (process_info_table == NULL) {
806
0
      *err = ENOMEM; /* we assume we're out of memory */
807
0
      return WTAP_OPEN_ERROR;
808
0
    }
809
810
    /* Read the version (ignored for now) */
811
0
    if (!wtap_read_bytes(wth->fh, &version, 2, err, err_info)) {
812
0
      g_hash_table_destroy(process_info_table);
813
0
      return WTAP_OPEN_ERROR;
814
0
    }
815
816
0
    while (process_info_table_count > 0)
817
0
    {
818
0
      struct netmonrec_process_info* process_info;
819
0
      uint32_t tmp32;
820
0
      uint16_t tmp16;
821
0
      uint32_t path_size;
822
0
      uint8_t *utf16_str;
823
824
0
      process_info = g_new0(struct netmonrec_process_info, 1);
825
826
      /* Read path */
827
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
828
0
        g_free(process_info);
829
0
        g_hash_table_destroy(process_info_table);
830
0
        return WTAP_OPEN_ERROR;
831
0
      }
832
833
0
      path_size = pletohu32(&tmp32);
834
0
      if (path_size > MATH_PROCINFO_PATH_SIZE) {
835
0
        *err = WTAP_ERR_BAD_FILE;
836
0
        *err_info = ws_strdup_printf("netmon: Path size for process info record is %u, which is larger than allowed max value (%u)",
837
0
            path_size, MATH_PROCINFO_PATH_SIZE);
838
0
        g_free(process_info);
839
0
        g_hash_table_destroy(process_info_table);
840
0
        return WTAP_OPEN_ERROR;
841
0
      }
842
843
      /*
844
       * Read in the path string.
845
       *
846
       * It is in UTF-16-encoded Unicode, and the path
847
       * size is a count of octets, not octet pairs or
848
       * Unicode characters.
849
       */
850
0
      utf16_str = (uint8_t*)g_malloc(path_size);
851
0
      if (!wtap_read_bytes(wth->fh, utf16_str, path_size,
852
0
          err, err_info)) {
853
0
        g_free(process_info);
854
0
        g_hash_table_destroy(process_info_table);
855
0
        return WTAP_OPEN_ERROR;
856
0
      }
857
858
      /*
859
       * Now convert it to UTF-8 for internal use.
860
       */
861
0
      process_info->path = utf_16_to_utf_8(utf16_str,
862
0
          path_size);
863
0
      g_free(utf16_str);
864
865
      /* Read icon (currently not saved) */
866
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
867
0
        g_free(process_info);
868
0
        g_hash_table_destroy(process_info_table);
869
0
        return WTAP_OPEN_ERROR;
870
0
      }
871
872
0
      process_info->iconSize = pletohu32(&tmp32);
873
874
      /* XXX - skip the icon for now */
875
0
      if (file_seek(wth->fh, process_info->iconSize, SEEK_CUR, err) == -1) {
876
0
        g_free(process_info);
877
0
        g_hash_table_destroy(process_info_table);
878
0
        return WTAP_OPEN_ERROR;
879
0
      }
880
0
      process_info->iconSize = 0;
881
882
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
883
0
        g_free(process_info);
884
0
        g_hash_table_destroy(process_info_table);
885
0
        return WTAP_OPEN_ERROR;
886
0
      }
887
0
      process_info->pid = pletohu32(&tmp32);
888
889
      /* XXX - Currently index process information by PID */
890
0
      g_hash_table_insert(process_info_table, GUINT_TO_POINTER(process_info->pid), process_info);
891
892
      /* Read local port */
893
0
      if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
894
0
        g_hash_table_destroy(process_info_table);
895
0
        return WTAP_OPEN_ERROR;
896
0
      }
897
0
      process_info->localPort = pletohu16(&tmp16);
898
899
      /* Skip padding */
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
905
      /* Read remote port */
906
0
      if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
907
0
        g_hash_table_destroy(process_info_table);
908
0
        return WTAP_OPEN_ERROR;
909
0
      }
910
0
      process_info->remotePort = pletohu16(&tmp16);
911
912
      /* Skip padding */
913
0
      if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
914
0
        g_hash_table_destroy(process_info_table);
915
0
        return WTAP_OPEN_ERROR;
916
0
      }
917
918
      /* Determine IP version */
919
0
      if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
920
0
        g_hash_table_destroy(process_info_table);
921
0
        return WTAP_OPEN_ERROR;
922
0
      }
923
0
      process_info->isIPv6 = ((pletohu32(&tmp32) == 0) ? false : true);
924
925
0
      if (process_info->isIPv6) {
926
0
        if (!wtap_read_bytes(wth->fh, &process_info->localAddr.ipv6, 16, err, err_info)) {
927
0
          g_hash_table_destroy(process_info_table);
928
0
          return WTAP_OPEN_ERROR;
929
0
        }
930
0
        if (!wtap_read_bytes(wth->fh, &process_info->remoteAddr.ipv6, 16, err, err_info)) {
931
0
          g_hash_table_destroy(process_info_table);
932
0
          return WTAP_OPEN_ERROR;
933
0
        }
934
0
      } else {
935
0
        uint8_t ipbuffer[16];
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->localAddr.ipv4 = pletohu32(ipbuffer);
941
942
0
        if (!wtap_read_bytes(wth->fh, ipbuffer, 16, err, err_info)) {
943
0
          g_hash_table_destroy(process_info_table);
944
0
          return WTAP_OPEN_ERROR;
945
0
        }
946
0
        process_info->remoteAddr.ipv4 = pletohu32(ipbuffer);
947
0
      }
948
949
0
      process_info_table_count--;
950
0
    }
951
952
0
    netmon->process_info_table = process_info_table;
953
0
  }
954
955
#if G_BYTE_ORDER == G_BIG_ENDIAN
956
  /*
957
   * OK, now byte-swap the frame table.
958
   */
959
  for (i = 0; i < frame_table_size; i++)
960
    frame_table[i] = pletohu32(&frame_table[i]);
961
#endif
962
963
  /* Set up to start reading at the first frame. */
964
0
  netmon->current_frame = 0;
965
0
  switch (netmon->version_major) {
966
967
0
  case 1:
968
    /*
969
     * Version 1.x of the file format supports
970
     * millisecond precision.
971
     */
972
0
    wth->file_tsprec = WTAP_TSPREC_MSEC;
973
0
    break;
974
975
0
  case 2:
976
    /*
977
     * Versions 2.0 through 2.2 support microsecond
978
     * precision; version 2.3 supports 100-nanosecond
979
     * precision (2.3 was the last version).
980
     */
981
0
    if (netmon->version_minor >= 3)
982
0
      wth->file_tsprec = WTAP_TSPREC_100_NSEC;
983
0
    else
984
0
      wth->file_tsprec = WTAP_TSPREC_USEC;
985
0
    break;
986
0
  }
987
0
  return WTAP_OPEN_MINE;
988
0
}
989
990
static void
991
netmon_set_pseudo_header_info(wtap_rec *rec)
992
0
{
993
0
  switch (rec->rec_header.packet_header.pkt_encap) {
994
995
0
  case WTAP_ENCAP_ATM_PDUS:
996
    /*
997
     * Attempt to guess from the packet data, the VPI, and
998
     * the VCI information about the type of traffic.
999
     */
1000
0
    atm_guess_traffic_type(rec);
1001
0
    break;
1002
1003
0
  case WTAP_ENCAP_ETHERNET:
1004
    /*
1005
     * We assume there's no FCS in this frame.
1006
     */
1007
0
    rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
1008
0
    break;
1009
1010
0
  case WTAP_ENCAP_IEEE_802_11_NETMON:
1011
    /*
1012
     * The 802.11 metadata at the beginning of the frame data
1013
     * is processed by a dissector, which fills in a pseudo-
1014
     * header and passes it to the 802.11 radio dissector,
1015
     * just as is done with other 802.11 radio metadata headers
1016
     * that are part of the packet data, such as radiotap.
1017
     */
1018
0
    break;
1019
0
  }
1020
0
}
1021
1022
typedef enum {
1023
  SUCCESS,
1024
  FAILURE,
1025
  RETRY
1026
} process_record_retval;
1027
1028
static process_record_retval
1029
netmon_process_record(wtap *wth, FILE_T fh, wtap_rec *rec,
1030
    int *err, char **err_info)
1031
0
{
1032
0
  netmon_t *netmon = (netmon_t *)wth->priv;
1033
0
  int  hdr_size = 0;
1034
0
  union {
1035
0
    struct netmonrec_1_x_hdr hdr_1_x;
1036
0
    struct netmonrec_2_x_hdr hdr_2_x;
1037
0
  } hdr;
1038
0
  int64_t  delta = 0; /* signed - frame times can be before the nominal start */
1039
0
  int64_t  t;
1040
0
  time_t   secs;
1041
0
  int  nsecs;
1042
0
  uint32_t packet_size = 0;
1043
0
  uint32_t orig_size = 0;
1044
0
  int  trlr_size;
1045
0
  union {
1046
0
    struct netmonrec_2_1_trlr trlr_2_1;
1047
0
    struct netmonrec_2_2_trlr trlr_2_2;
1048
0
    struct netmonrec_2_3_trlr trlr_2_3;
1049
0
  } trlr;
1050
0
  uint16_t network;
1051
0
  int  pkt_encap;
1052
0
  struct netmonrec_comment* comment_rec = NULL;
1053
1054
  /* Read record header. */
1055
0
  switch (netmon->version_major) {
1056
1057
0
  case 1:
1058
0
    hdr_size = sizeof (struct netmonrec_1_x_hdr);
1059
0
    break;
1060
1061
0
  case 2:
1062
0
    hdr_size = sizeof (struct netmonrec_2_x_hdr);
1063
0
    break;
1064
0
  }
1065
0
  if (!wtap_read_bytes_or_eof(fh, &hdr, hdr_size, err, err_info))
1066
0
    return FAILURE;
1067
1068
0
  switch (netmon->version_major) {
1069
1070
0
  case 1:
1071
0
    orig_size = pletohu16(&hdr.hdr_1_x.orig_len);
1072
0
    packet_size = pletohu16(&hdr.hdr_1_x.incl_len);
1073
0
    break;
1074
1075
0
  case 2:
1076
0
    orig_size = pletohu32(&hdr.hdr_2_x.orig_len);
1077
0
    packet_size = pletohu32(&hdr.hdr_2_x.incl_len);
1078
0
    break;
1079
0
  }
1080
0
  if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
1081
    /*
1082
     * Probably a corrupt capture file; don't blow up trying
1083
     * to allocate space for an immensely-large packet.
1084
     */
1085
0
    *err = WTAP_ERR_BAD_FILE;
1086
0
    *err_info = ws_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
1087
0
        packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
1088
0
    return FAILURE;
1089
0
  }
1090
1091
0
  wtap_setup_packet_rec(rec, wth->file_encap);
1092
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
1093
1094
  /*
1095
   * If this is an ATM packet, the first
1096
   * "sizeof (struct netmon_atm_hdr)" bytes have destination and
1097
   * source addresses (6 bytes - MAC addresses of some sort?)
1098
   * and the VPI and VCI; read them and generate the pseudo-header
1099
   * from them.
1100
   */
1101
0
  switch (wth->file_encap) {
1102
1103
0
  case WTAP_ENCAP_ATM_PDUS:
1104
0
    if (packet_size < sizeof (struct netmon_atm_hdr)) {
1105
      /*
1106
       * Uh-oh, the packet isn't big enough to even
1107
       * have a pseudo-header.
1108
       */
1109
0
      *err = WTAP_ERR_BAD_FILE;
1110
0
      *err_info = ws_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
1111
0
          packet_size);
1112
0
      return FAILURE;
1113
0
    }
1114
0
    if (!netmon_read_atm_pseudoheader(fh, &rec->rec_header.packet_header.pseudo_header,
1115
0
        err, err_info))
1116
0
      return FAILURE; /* Read error */
1117
1118
    /*
1119
     * Don't count the pseudo-header as part of the packet.
1120
     */
1121
0
    orig_size -= (unsigned)sizeof (struct netmon_atm_hdr);
1122
0
    packet_size -= (unsigned)sizeof (struct netmon_atm_hdr);
1123
0
    break;
1124
1125
0
  default:
1126
0
    break;
1127
0
  }
1128
1129
0
  switch (netmon->version_major) {
1130
1131
0
  case 1:
1132
    /*
1133
     * According to Paul Long, this offset is unsigned.
1134
     * It's 32 bits, so the maximum value will fit in
1135
     * a int64_t such as delta, even after multiplying
1136
     * it by 1000000.
1137
     *
1138
     * pletohu32() returns a uint32_t; we cast it to int64_t
1139
     * before multiplying, so that the product doesn't
1140
     * overflow a uint32_t.
1141
     */
1142
0
    delta = ((int64_t)pletohu32(&hdr.hdr_1_x.ts_delta))*1000000;
1143
0
    break;
1144
1145
0
  case 2:
1146
    /*
1147
     * OK, this is weird.  Microsoft's documentation
1148
     * says this is in microseconds and is a 64-bit
1149
     * unsigned number, but it can be negative; they
1150
     * say what appears to amount to "treat it as an
1151
     * unsigned number, multiply it by 10, and then
1152
     * interpret the resulting 64-bit quantity as a
1153
     * signed number".  That operation can turn a
1154
     * value with the uppermost bit 0 to a value with
1155
     * the uppermost bit 1, hence turning a large
1156
     * positive number-of-microseconds into a small
1157
     * negative number-of-100-nanosecond-increments.
1158
     */
1159
0
    delta = pletohu64(&hdr.hdr_2_x.ts_delta)*10;
1160
1161
    /*
1162
     * OK, it's now a signed value in 100-nanosecond
1163
     * units.  Now convert it to nanosecond units.
1164
     */
1165
0
    delta *= 100;
1166
0
    break;
1167
0
  }
1168
0
  secs = 0;
1169
0
  t = netmon->start_nsecs + delta;
1170
0
  while (t < 0) {
1171
    /*
1172
     * Propagate a borrow into the seconds.
1173
     * The seconds is a time_t, and can be < 0
1174
     * (unlikely, as Windows didn't exist before
1175
     * January 1, 1970, 00:00:00 UTC), while the
1176
     * nanoseconds should be positive, as in
1177
     * "nanoseconds since the instant of time
1178
     * represented by the seconds".
1179
     *
1180
     * We do not want t to be negative, as, according
1181
     * to the C90 standard, "if either operand [of /
1182
     * or %] is negative, whether the result of the
1183
     * / operator is the largest integer less than or
1184
     * equal to the algebraic quotient or the smallest
1185
     * greater than or equal to the algebraic quotient
1186
     * is implementation-defined, as is the sign of
1187
     * the result of the % operator", and we want
1188
     * the result of the division and remainder
1189
     * operations to be the same on all platforms.
1190
     */
1191
0
    t += 1000000000;
1192
0
    secs--;
1193
0
  }
1194
0
  secs += (time_t)(t/1000000000);
1195
0
  nsecs = (int)(t%1000000000);
1196
0
  rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
1197
0
  rec->ts.secs = netmon->start_secs + secs;
1198
0
  rec->ts.nsecs = nsecs;
1199
0
  rec->rec_header.packet_header.caplen = packet_size;
1200
0
  rec->rec_header.packet_header.len = orig_size;
1201
1202
  /*
1203
   * Read the packet data.
1204
   */
1205
0
  if (!wtap_read_bytes_buffer(fh, &rec->data, rec->rec_header.packet_header.caplen, err, err_info))
1206
0
    return FAILURE;
1207
1208
  /*
1209
   * For version 2.1 and later, there's additional information
1210
   * after the frame data.
1211
   */
1212
0
  if (netmon->version_major == 2 && netmon->version_minor >= 1) {
1213
0
    switch (netmon->version_minor) {
1214
1215
0
    case 1:
1216
0
      trlr_size = (int)sizeof (struct netmonrec_2_1_trlr);
1217
0
      break;
1218
1219
0
    case 2:
1220
0
      trlr_size = (int)sizeof (struct netmonrec_2_2_trlr);
1221
0
      break;
1222
1223
0
    default:
1224
0
      trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
1225
0
      break;
1226
0
    }
1227
1228
0
    if (!wtap_read_bytes(fh, &trlr, trlr_size, err, err_info))
1229
0
      return FAILURE;
1230
1231
0
    network = pletohu16(trlr.trlr_2_1.network);
1232
0
    if ((network >= 0xE080) && (network <= 0xE08A)) {
1233
      /* These values "violate" the LINKTYPE_ media type values
1234
       * in Microsoft Analyzer and are considered a MAExportedMediaType,
1235
       * so they need their own WTAP_ types
1236
       */
1237
0
      switch (network)
1238
0
      {
1239
0
      case 0xE080:    // "WiFi Message"
1240
0
        pkt_encap = WTAP_ENCAP_IEEE_802_11;
1241
0
        break;
1242
0
      case 0xE081:    // "Ndis Etw WiFi Channel Message"
1243
0
      case 0xE082:    // "Fiddler Netmon Message"
1244
0
      case 0xE089:    // "Pef Ndis Msg";
1245
0
      case 0xE08A:    // "Pef Ndis Wifi Meta Msg";
1246
0
        *err = WTAP_ERR_UNSUPPORTED;
1247
0
        *err_info = ws_strdup_printf("netmon: network type %u unknown or unsupported", network);
1248
0
        return FAILURE;
1249
0
      case 0xE083:
1250
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_V4;
1251
0
        break;
1252
0
      case 0xE084:
1253
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_V6;
1254
0
        break;
1255
0
      case 0xE085:
1256
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_2V4;
1257
0
        break;
1258
0
      case 0xE086:
1259
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_2V6;
1260
0
        break;
1261
0
      case 0xE087:
1262
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_AUTH_V4;
1263
0
        break;
1264
0
      case 0xE088:
1265
0
        pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_AUTH_V6;
1266
0
        break;
1267
0
      default:
1268
0
        pkt_encap = WTAP_ENCAP_UNKNOWN;
1269
0
        break;
1270
0
      }
1271
0
    } else if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
1272
      /*
1273
       * Converted pcap file - the LINKTYPE_ value
1274
       * is the network value with 0xF000 masked off.
1275
       */
1276
0
      network &= 0x0FFF;
1277
0
      pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
1278
0
      if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
1279
0
        *err = WTAP_ERR_UNSUPPORTED;
1280
0
        *err_info = ws_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
1281
0
            network);
1282
0
        return FAILURE;
1283
0
      }
1284
0
    } else if (network < NUM_NETMON_ENCAPS) {
1285
      /*
1286
       * Regular NetMon encapsulation.
1287
       */
1288
0
      pkt_encap = netmon_encap[network];
1289
0
      if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
1290
0
        *err = WTAP_ERR_UNSUPPORTED;
1291
0
        *err_info = ws_strdup_printf("netmon: network type %u unknown or unsupported",
1292
0
            network);
1293
0
        return FAILURE;
1294
0
      }
1295
0
    } else {
1296
      /*
1297
       * Special packet type for metadata.
1298
       */
1299
0
      switch (network) {
1300
1301
0
      case NETMON_NET_NETEVENT:
1302
        /*
1303
         * Event Tracing event.
1304
         *
1305
         * https://docs.microsoft.com/en-us/windows/win32/api/evntcons/ns-evntcons-event_header
1306
         */
1307
0
        pkt_encap = WTAP_ENCAP_NETMON_NET_NETEVENT;
1308
0
        break;
1309
1310
0
      case NETMON_NET_NETWORK_INFO_EX:
1311
        /*
1312
         * List of adapters on which the capture
1313
         * was done.
1314
         * XXX - this could be translated into pcapng
1315
         * blocks but for now, just treat as a frame.
1316
         */
1317
0
        pkt_encap = WTAP_ENCAP_NETMON_NETWORK_INFO_EX;
1318
0
        break;
1319
1320
0
      case NETMON_NET_PAYLOAD_HEADER:
1321
        /*
1322
         * Header for a fake frame constructed
1323
         * by reassembly.
1324
         */
1325
0
        return RETRY;
1326
1327
0
      case NETMON_NET_NETWORK_INFO:
1328
        /*
1329
         * List of adapters on which the capture
1330
         * was done.
1331
         */
1332
0
        return RETRY;
1333
1334
0
      case NETMON_NET_DNS_CACHE:
1335
        /*
1336
         * List of resolved IP addresses.
1337
         */
1338
0
        return RETRY;
1339
1340
0
      case NETMON_NET_NETMON_FILTER:
1341
        /*
1342
         * NetMon capture or display filter
1343
         * string.
1344
         */
1345
0
        pkt_encap = WTAP_ENCAP_NETMON_NET_FILTER;
1346
0
        break;
1347
1348
0
      default:
1349
0
        *err = WTAP_ERR_UNSUPPORTED;
1350
0
        *err_info = ws_strdup_printf("netmon: network type %u unknown or unsupported",
1351
0
            network);
1352
0
        return FAILURE;
1353
0
      }
1354
0
    }
1355
1356
0
    rec->rec_header.packet_header.pkt_encap = pkt_encap;
1357
0
    if (netmon->version_minor >= 3) {
1358
      /*
1359
       * This is a 2.3 or later file.  That format
1360
       * contains a UTC per-packet time stamp; use
1361
       * that instead of the start time and offset.
1362
       */
1363
0
      uint64_t d;
1364
1365
0
      d = pletohu64(trlr.trlr_2_3.utc_timestamp);
1366
1367
      /*
1368
       * Get the time as seconds and nanoseconds.
1369
       * and overwrite the time stamp obtained
1370
       * from the record header.
1371
       */
1372
0
      if (!filetime_to_nstime(&rec->ts, d)) {
1373
0
        *err = WTAP_ERR_BAD_FILE;
1374
0
        *err_info = g_strdup("netmon: time stamp outside supported range");
1375
0
        return FAILURE;
1376
0
      }
1377
0
    }
1378
0
  }
1379
1380
0
  netmon_set_pseudo_header_info(rec);
1381
1382
  /* If any header specific information is present, set it as pseudo header data
1383
   * and set the encapsulation type, so it can be handled to the netmon_header
1384
   * dissector for further processing
1385
   */
1386
0
  if (netmon->comment_table != NULL) {
1387
0
    comment_rec = (struct netmonrec_comment*)g_hash_table_lookup(netmon->comment_table, GUINT_TO_POINTER(netmon->frame_table[netmon->current_frame-1]));
1388
0
  }
1389
1390
0
  if (comment_rec != NULL) {
1391
0
    union wtap_pseudo_header temp_header;
1392
1393
    /* These are the current encapsulation types that NetMon uses.
1394
     * Save them off so they can be copied to the NetMon pseudoheader
1395
     */
1396
0
    switch (rec->rec_header.packet_header.pkt_encap)
1397
0
    {
1398
0
    case WTAP_ENCAP_ATM_PDUS:
1399
0
      memcpy(&temp_header.atm, &rec->rec_header.packet_header.pseudo_header.atm, sizeof(temp_header.atm));
1400
0
      break;
1401
0
    case WTAP_ENCAP_ETHERNET:
1402
0
      memcpy(&temp_header.eth, &rec->rec_header.packet_header.pseudo_header.eth, sizeof(temp_header.eth));
1403
0
      break;
1404
0
    case WTAP_ENCAP_IEEE_802_11_NETMON:
1405
0
      memcpy(&temp_header.ieee_802_11, &rec->rec_header.packet_header.pseudo_header.ieee_802_11, sizeof(temp_header.ieee_802_11));
1406
0
      break;
1407
0
    }
1408
0
    memset(&rec->rec_header.packet_header.pseudo_header.netmon, 0, sizeof(rec->rec_header.packet_header.pseudo_header.netmon));
1409
1410
    /* Save the current encapsulation type to the NetMon pseudoheader */
1411
0
    rec->rec_header.packet_header.pseudo_header.netmon.sub_encap = rec->rec_header.packet_header.pkt_encap;
1412
1413
    /* Copy the comment data */
1414
0
    rec->rec_header.packet_header.pseudo_header.netmon.title = comment_rec->title;
1415
0
    rec->rec_header.packet_header.pseudo_header.netmon.descLength = comment_rec->descLength;
1416
0
    rec->rec_header.packet_header.pseudo_header.netmon.description = comment_rec->description;
1417
1418
    /* Copy the saved pseudoheaders to the netmon pseudoheader structure */
1419
0
    switch (rec->rec_header.packet_header.pkt_encap)
1420
0
    {
1421
0
    case WTAP_ENCAP_ATM_PDUS:
1422
0
      memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.atm, &temp_header.atm, sizeof(temp_header.atm));
1423
0
      break;
1424
0
    case WTAP_ENCAP_ETHERNET:
1425
0
      memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.eth, &temp_header.eth, sizeof(temp_header.eth));
1426
0
      break;
1427
0
    case WTAP_ENCAP_IEEE_802_11_NETMON:
1428
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));
1429
0
      break;
1430
0
    }
1431
1432
    /* Encapsulation type is now something that can be passed to netmon_header dissector */
1433
0
    rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_NETMON_HEADER;
1434
0
  }
1435
1436
0
  return SUCCESS;
1437
0
}
1438
1439
/* Read the next packet */
1440
static bool netmon_read(wtap *wth, wtap_rec *rec,
1441
    int *err, char **err_info, int64_t *data_offset)
1442
0
{
1443
0
  netmon_t *netmon = (netmon_t *)wth->priv;
1444
0
  int64_t rec_offset;
1445
1446
0
  for (;;) {
1447
    /* Have we reached the end of the packet data? */
1448
0
    if (netmon->current_frame >= netmon->frame_table_size) {
1449
0
      *err = 0; /* it's just an EOF, not an error */
1450
0
      return false;
1451
0
    }
1452
1453
    /* Seek to the beginning of the current record, if we're
1454
       not there already (seeking to the current position
1455
       may still cause a seek and a read of the underlying file,
1456
       so we don't want to do it unconditionally).
1457
1458
       Yes, the current record could be before the previous
1459
       record.  At least some captures put the trailer record
1460
       with statistics as the first physical record in the
1461
       file, but set the frame table up so it's the last
1462
       record in sequence. */
1463
0
    rec_offset = netmon->frame_table[netmon->current_frame];
1464
0
    if (file_tell(wth->fh) != rec_offset) {
1465
0
      if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
1466
0
        return false;
1467
0
    }
1468
0
    netmon->current_frame++;
1469
1470
0
    *data_offset = file_tell(wth->fh);
1471
1472
0
    switch (netmon_process_record(wth, wth->fh, rec, err, err_info)) {
1473
1474
0
    case RETRY:
1475
0
      continue;
1476
1477
0
    case SUCCESS:
1478
0
      return true;
1479
1480
0
    case FAILURE:
1481
0
      return false;
1482
0
    }
1483
0
  }
1484
0
}
1485
1486
static bool
1487
netmon_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
1488
    int *err, char **err_info)
1489
0
{
1490
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
1491
0
    return false;
1492
1493
0
  switch (netmon_process_record(wth, wth->random_fh, rec, err, err_info)) {
1494
1495
0
  default:
1496
    /*
1497
     * This should not happen.
1498
     */
1499
0
    *err = WTAP_ERR_BAD_FILE;
1500
0
    *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
1501
0
    return false;
1502
1503
0
  case SUCCESS:
1504
0
    return true;
1505
1506
0
  case FAILURE:
1507
0
    return false;
1508
0
  }
1509
0
}
1510
1511
static bool
1512
netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
1513
    int *err, char **err_info)
1514
0
{
1515
0
  struct netmon_atm_hdr atm_phdr;
1516
0
  uint16_t  vpi, vci;
1517
1518
0
  if (!wtap_read_bytes(fh, &atm_phdr, sizeof (struct netmon_atm_hdr),
1519
0
      err, err_info))
1520
0
    return false;
1521
1522
0
  vpi = g_ntohs(atm_phdr.vpi);
1523
0
  vci = g_ntohs(atm_phdr.vci);
1524
1525
0
  pseudo_header->atm.vpi = vpi;
1526
0
  pseudo_header->atm.vci = vci;
1527
1528
  /* We don't have this information */
1529
0
  pseudo_header->atm.flags = 0;
1530
0
  pseudo_header->atm.channel = 0;
1531
0
  pseudo_header->atm.cells = 0;
1532
0
  pseudo_header->atm.aal5t_u2u = 0;
1533
0
  pseudo_header->atm.aal5t_len = 0;
1534
0
  pseudo_header->atm.aal5t_chksum = 0;
1535
1536
0
  return true;
1537
0
}
1538
1539
/* Throw away the frame table used by the sequential I/O stream. */
1540
static void
1541
netmon_close(wtap *wth)
1542
0
{
1543
0
  netmon_t *netmon = (netmon_t *)wth->priv;
1544
1545
0
  if (netmon->frame_table != NULL) {
1546
0
    g_free(netmon->frame_table);
1547
0
    netmon->frame_table = NULL;
1548
0
  }
1549
1550
0
  if (netmon->comment_table != NULL) {
1551
0
    g_hash_table_destroy(netmon->comment_table);
1552
0
    netmon->comment_table = NULL;
1553
0
  }
1554
1555
0
  if (netmon->process_info_table != NULL) {
1556
0
    g_hash_table_destroy(netmon->process_info_table);
1557
0
    netmon->process_info_table = NULL;
1558
0
  }
1559
0
}
1560
1561
typedef struct {
1562
  bool is_v2;
1563
  bool got_first_record_time;
1564
  nstime_t first_record_time;
1565
  uint32_t frame_table_offset;
1566
  uint32_t *frame_table;
1567
  unsigned frame_table_index;
1568
  unsigned frame_table_size;
1569
  bool no_more_room;    /* true if no more records can be written */
1570
} netmon_dump_t;
1571
1572
static const int wtap_encap[] = {
1573
  -1,   /* WTAP_ENCAP_UNKNOWN -> unsupported */
1574
  1,    /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
1575
  2,    /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
1576
  -1,   /* WTAP_ENCAP_SLIP -> unsupported */
1577
  -1,   /* WTAP_ENCAP_PPP -> unsupported */
1578
  3,    /* WTAP_ENCAP_FDDI -> NDIS FDDI */
1579
  3,    /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
1580
  -1,   /* WTAP_ENCAP_RAW_IP -> unsupported */
1581
  -1,   /* WTAP_ENCAP_ARCNET -> unsupported */
1582
  -1,   /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
1583
  -1,   /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
1584
  -1,   /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
1585
  -1,   /* WTAP_ENCAP_LAPB -> unsupported*/
1586
  4,    /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
1587
};
1588
0
#define NUM_WTAP_ENCAPS array_length(wtap_encap)
1589
1590
/* Returns 0 if we could write the specified encapsulation type,
1591
   an error indication otherwise. */
1592
static int netmon_dump_can_write_encap_1_x(int encap)
1593
0
{
1594
  /*
1595
   * Per-packet encapsulations are *not* supported in NetMon 1.x
1596
   * format.
1597
   */
1598
0
  if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
1599
0
    return WTAP_ERR_UNWRITABLE_ENCAP;
1600
1601
0
  return 0;
1602
0
}
1603
1604
static int netmon_dump_can_write_encap_2_x(int encap)
1605
0
{
1606
  /*
1607
   * Per-packet encapsulations are supported in NetMon 2.1
1608
   * format.
1609
   */
1610
0
  if (encap == WTAP_ENCAP_PER_PACKET)
1611
0
    return 0;
1612
1613
0
  if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
1614
0
    return WTAP_ERR_UNWRITABLE_ENCAP;
1615
1616
0
  return 0;
1617
0
}
1618
1619
/* Returns true on success, false on failure; sets "*err" to an error code on
1620
   failure */
1621
static bool netmon_dump_open(wtap_dumper *wdh, bool is_v2,
1622
                                 int *err, char **err_info _U_)
1623
0
{
1624
0
  netmon_dump_t *netmon;
1625
1626
  /* We can't fill in all the fields in the file header, as we
1627
     haven't yet written any packets.  As we'll have to rewrite
1628
     the header when we've written out all the packets, we just
1629
     skip over the header for now. */
1630
0
  if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
1631
0
    return false;
1632
1633
0
  wdh->bytes_dumped = CAPTUREFILE_HEADER_SIZE;
1634
0
  wdh->subtype_write = netmon_dump;
1635
0
  wdh->subtype_finish = netmon_dump_finish;
1636
1637
0
  netmon = g_new(netmon_dump_t, 1);
1638
0
  wdh->priv = (void *)netmon;
1639
0
  netmon->is_v2 = is_v2;
1640
0
  netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
1641
0
  netmon->got_first_record_time = false;
1642
0
  netmon->frame_table = NULL;
1643
0
  netmon->frame_table_index = 0;
1644
0
  netmon->frame_table_size = 0;
1645
0
  netmon->no_more_room = false;
1646
1647
0
  return true;
1648
0
}
1649
1650
static bool netmon_dump_open_1_x(wtap_dumper *wdh, int *err, char **err_info _U_)
1651
0
{
1652
0
  return netmon_dump_open(wdh, false, err, err_info);
1653
0
}
1654
1655
static bool netmon_dump_open_2_x(wtap_dumper *wdh, int *err, char **err_info _U_)
1656
0
{
1657
0
  return netmon_dump_open(wdh, true, err, err_info);
1658
0
}
1659
1660
/* Write a record for a packet to a dump file.
1661
   Returns true on success, false on failure. */
1662
static bool netmon_dump(wtap_dumper *wdh, const wtap_rec *rec,
1663
    int *err, char **err_info _U_)
1664
0
{
1665
0
  const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
1666
0
  netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1667
0
  struct netmonrec_1_x_hdr rec_1_x_hdr;
1668
0
  struct netmonrec_2_x_hdr rec_2_x_hdr;
1669
0
  void *hdrp;
1670
0
  size_t rec_size;
1671
0
  struct netmonrec_2_1_trlr rec_2_x_trlr;
1672
0
  size_t hdr_size;
1673
0
  struct netmon_atm_hdr atm_hdr;
1674
0
  int atm_hdrsize;
1675
0
  int64_t secs;
1676
0
  int32_t nsecs;
1677
1678
  /* We can only write packet records. */
1679
0
  if (rec->rec_type != REC_TYPE_PACKET) {
1680
0
    *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
1681
0
    *err_info = wtap_unwritable_rec_type_err_string(rec);
1682
0
    return false;
1683
0
  }
1684
1685
0
  if (netmon->is_v2) {
1686
    /* Don't write anything we're not willing to read. */
1687
0
    if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
1688
0
      *err = WTAP_ERR_PACKET_TOO_LARGE;
1689
0
      return false;
1690
0
    }
1691
0
  } else {
1692
    /*
1693
     * Make sure this packet doesn't have a link-layer type that
1694
     * differs from the one for the file.
1695
     */
1696
0
    if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
1697
0
      *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
1698
0
      return false;
1699
0
    }
1700
1701
    /*
1702
     * The length fields are 16-bit, so there's a hard limit
1703
     * of 65535.
1704
     */
1705
0
    if (rec->rec_header.packet_header.caplen > 65535) {
1706
0
      *err = WTAP_ERR_PACKET_TOO_LARGE;
1707
0
      return false;
1708
0
    }
1709
0
  }
1710
1711
0
  if (wdh->file_encap == WTAP_ENCAP_PER_PACKET) {
1712
    /*
1713
     * Is this network type supported?
1714
     */
1715
0
    if (rec->rec_header.packet_header.pkt_encap < 0 ||
1716
0
        (unsigned) rec->rec_header.packet_header.pkt_encap >= NUM_WTAP_ENCAPS ||
1717
0
        wtap_encap[rec->rec_header.packet_header.pkt_encap] == -1) {
1718
      /*
1719
       * No.  Fail.
1720
       */
1721
0
      *err = WTAP_ERR_UNWRITABLE_ENCAP;
1722
0
      return false;
1723
0
    }
1724
1725
    /*
1726
     * Fill in the trailer with the network type.
1727
     */
1728
0
    phtoleu16(rec_2_x_trlr.network, wtap_encap[rec->rec_header.packet_header.pkt_encap]);
1729
0
  }
1730
1731
  /*
1732
   * Will the file offset of this frame fit in a 32-bit unsigned
1733
   * integer?
1734
   */
1735
0
  if (netmon->no_more_room) {
1736
    /*
1737
     * No, so the file is too big for NetMon format to
1738
     * handle.
1739
     */
1740
0
    *err = EFBIG;
1741
0
    return false;
1742
0
  }
1743
1744
  /*
1745
   * NetMon files have a capture start time in the file header,
1746
   * and have times relative to that in the packet headers;
1747
   * pick the time of the first packet as the capture start
1748
   * time.
1749
   *
1750
   * That time has millisecond resolution, so chop any
1751
   * sub-millisecond part of the time stamp off.
1752
   */
1753
0
  if (!netmon->got_first_record_time) {
1754
0
    netmon->first_record_time.secs = rec->ts.secs;
1755
0
    netmon->first_record_time.nsecs =
1756
0
        (rec->ts.nsecs/1000000)*1000000;
1757
0
    netmon->got_first_record_time = true;
1758
0
  }
1759
1760
0
  if (wdh->file_encap == WTAP_ENCAP_ATM_PDUS)
1761
0
    atm_hdrsize = sizeof (struct netmon_atm_hdr);
1762
0
  else
1763
0
    atm_hdrsize = 0;
1764
0
  secs = (int64_t)(rec->ts.secs - netmon->first_record_time.secs);
1765
0
  nsecs = rec->ts.nsecs - netmon->first_record_time.nsecs;
1766
0
  while (nsecs < 0) {
1767
    /*
1768
     * Propagate a borrow into the seconds.
1769
     * The seconds is a time_t, and can be < 0
1770
     * (unlikely, as neither UN*X nor DOS
1771
     * nor the original Mac System existed
1772
     * before January 1, 1970, 00:00:00 UTC),
1773
     * while the nanoseconds should be positive,
1774
     * as in "nanoseconds since the instant of time
1775
     * represented by the seconds".
1776
     *
1777
     * We do not want t to be negative, as, according
1778
     * to the C90 standard, "if either operand [of /
1779
     * or %] is negative, whether the result of the
1780
     * / operator is the largest integer less than or
1781
     * equal to the algebraic quotient or the smallest
1782
     * greater than or equal to the algebraic quotient
1783
     * is implementation-defined, as is the sign of
1784
     * the result of the % operator", and we want
1785
     * the result of the division and remainder
1786
     * operations to be the same on all platforms.
1787
     */
1788
0
    nsecs += 1000000000;
1789
0
    secs--;
1790
0
  }
1791
0
  if (netmon->is_v2) {
1792
0
    rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
1793
0
    rec_2_x_hdr.orig_len = GUINT32_TO_LE(rec->rec_header.packet_header.len + atm_hdrsize);
1794
0
    rec_2_x_hdr.incl_len = GUINT32_TO_LE(rec->rec_header.packet_header.caplen + atm_hdrsize);
1795
0
    hdrp = &rec_2_x_hdr;
1796
0
    hdr_size = sizeof rec_2_x_hdr;
1797
0
  } else {
1798
0
    rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
1799
0
    rec_1_x_hdr.orig_len = GUINT16_TO_LE(rec->rec_header.packet_header.len + atm_hdrsize);
1800
0
    rec_1_x_hdr.incl_len = GUINT16_TO_LE(rec->rec_header.packet_header.caplen + atm_hdrsize);
1801
0
    hdrp = &rec_1_x_hdr;
1802
0
    hdr_size = sizeof rec_1_x_hdr;
1803
0
  }
1804
1805
  /*
1806
   * Keep track of the record size, as we need to update
1807
   * the current file offset.
1808
   */
1809
0
  rec_size = 0;
1810
1811
0
  if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1812
0
    return false;
1813
0
  rec_size += hdr_size;
1814
1815
0
  if (wdh->file_encap == WTAP_ENCAP_ATM_PDUS) {
1816
    /*
1817
     * Write the ATM header.
1818
     * We supply all-zero destination and source addresses.
1819
     */
1820
0
    memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1821
0
    memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1822
0
    atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1823
0
    atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1824
0
    if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1825
0
      return false;
1826
0
    rec_size += sizeof atm_hdr;
1827
0
  }
1828
1829
0
  if (!wtap_dump_file_write(wdh, ws_buffer_start_ptr(&rec->data),
1830
0
      rec->rec_header.packet_header.caplen, err))
1831
0
    return false;
1832
0
  rec_size += rec->rec_header.packet_header.caplen;
1833
1834
0
  if (wdh->file_encap == WTAP_ENCAP_PER_PACKET) {
1835
    /*
1836
     * Write out the trailer.
1837
     */
1838
0
    if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1839
0
        sizeof rec_2_x_trlr, err))
1840
0
      return false;
1841
0
    rec_size += sizeof rec_2_x_trlr;
1842
0
  }
1843
1844
  /*
1845
   * Stash the file offset of this frame.
1846
   */
1847
0
  if (netmon->frame_table_size == 0) {
1848
    /*
1849
     * Haven't yet allocated the buffer for the frame table.
1850
     */
1851
0
    netmon->frame_table = (uint32_t *)g_malloc(1024 * sizeof *netmon->frame_table);
1852
0
    netmon->frame_table_size = 1024;
1853
0
  } else {
1854
    /*
1855
     * We've allocated it; are we at the end?
1856
     */
1857
0
    if (netmon->frame_table_index >= netmon->frame_table_size) {
1858
      /*
1859
       * Yes - double the size of the frame table.
1860
       */
1861
0
      netmon->frame_table_size *= 2;
1862
0
      netmon->frame_table = (uint32_t *)g_realloc(netmon->frame_table,
1863
0
          netmon->frame_table_size * sizeof *netmon->frame_table);
1864
0
    }
1865
0
  }
1866
1867
0
  netmon->frame_table[netmon->frame_table_index] =
1868
0
      GUINT32_TO_LE(netmon->frame_table_offset);
1869
1870
  /*
1871
   * Is this the last record we can write?
1872
   * I.e., will the frame table offset of the next record not fit
1873
   * in a 32-bit frame table offset entry?
1874
   *
1875
   * (We don't bother checking whether the number of frames
1876
   * will fit in a 32-bit value, as, even if each record were
1877
   * 1 byte, if there were more than 2^32-1 packets, the frame
1878
   * table offset of at least one of those packets will be >
1879
   * 2^32 - 1.)
1880
   *
1881
   * Note: this also catches the unlikely possibility that
1882
   * the record itself is > 2^32 - 1 bytes long.
1883
   */
1884
0
  if ((uint64_t)netmon->frame_table_offset + rec_size > UINT32_MAX) {
1885
    /*
1886
     * Yup, too big.
1887
     */
1888
0
    netmon->no_more_room = true;
1889
0
  }
1890
0
  netmon->frame_table_index++;
1891
0
  netmon->frame_table_offset += (uint32_t) rec_size;
1892
1893
0
  return true;
1894
0
}
1895
1896
/* Finish writing to a dump file.
1897
   Returns true on success, false on failure. */
1898
static bool netmon_dump_finish(wtap_dumper *wdh, int *err,
1899
    char **err_info _U_)
1900
0
{
1901
0
  netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1902
0
  size_t n_to_write;
1903
0
  struct netmon_hdr file_hdr;
1904
0
  const char *magicp;
1905
0
  size_t magic_size;
1906
0
  struct tm *tm;
1907
0
  int64_t saved_bytes_dumped;
1908
1909
  /* Write out the frame table.  "netmon->frame_table_index" is
1910
     the number of entries we've put into it. */
1911
0
  n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1912
0
  if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1913
0
    return false;
1914
1915
  /* Now go fix up the file header. */
1916
0
  if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1917
0
    return false;
1918
  /* Save bytes_dumped since following calls to wtap_dump_file_write()
1919
   * will still (mistakenly) increase it.
1920
   */
1921
0
  saved_bytes_dumped = wdh->bytes_dumped;
1922
0
  memset(&file_hdr, '\0', sizeof file_hdr);
1923
0
  if (netmon->is_v2) {
1924
0
    magicp = netmon_2_x_magic;
1925
0
    magic_size = sizeof netmon_2_x_magic;
1926
    /*
1927
     * NetMon file version, for 2.x, is 2.0;
1928
     * for 3.0, it's 2.1.
1929
     *
1930
     * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1931
     * we need version 2.1.
1932
     *
1933
     * XXX - version 2.3 supports UTC time stamps; when
1934
     * should we use it?  According to the file format
1935
     * documentation, NetMon 3.3 "cannot properly
1936
     * interpret" the UTC timestamp information; does
1937
     * that mean it ignores it and uses the local-time
1938
     * start time and time deltas, or mishandles them?
1939
     * Also, NetMon 3.1 and earlier can't read version
1940
     * 2.2, much less version 2.3.
1941
     */
1942
0
    file_hdr.ver_major = 2;
1943
0
    file_hdr.ver_minor =
1944
0
        (wdh->file_encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1945
0
  } else {
1946
0
    magicp = netmon_1_x_magic;
1947
0
    magic_size = sizeof netmon_1_x_magic;
1948
    /* NetMon file version, for 1.x, is 1.1 */
1949
0
    file_hdr.ver_major = 1;
1950
0
    file_hdr.ver_minor = 1;
1951
0
  }
1952
0
  if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1953
0
    return false;
1954
1955
0
  if (wdh->file_encap == WTAP_ENCAP_PER_PACKET) {
1956
    /*
1957
     * We're writing NetMon 2.1 format, so the media
1958
     * type in the file header is irrelevant.  Set it
1959
     * to 1, just as Network Monitor does.
1960
     */
1961
0
    file_hdr.network = GUINT16_TO_LE(1);
1962
0
  } else
1963
0
    file_hdr.network = GUINT16_TO_LE(wtap_encap[wdh->file_encap]);
1964
0
  tm = localtime(&netmon->first_record_time.secs);
1965
0
  if (tm != NULL) {
1966
0
    file_hdr.ts_year  = GUINT16_TO_LE(1900 + tm->tm_year);
1967
0
    file_hdr.ts_month = GUINT16_TO_LE(tm->tm_mon + 1);
1968
0
    file_hdr.ts_dow   = GUINT16_TO_LE(tm->tm_wday);
1969
0
    file_hdr.ts_day   = GUINT16_TO_LE(tm->tm_mday);
1970
0
    file_hdr.ts_hour  = GUINT16_TO_LE(tm->tm_hour);
1971
0
    file_hdr.ts_min   = GUINT16_TO_LE(tm->tm_min);
1972
0
    file_hdr.ts_sec   = GUINT16_TO_LE(tm->tm_sec);
1973
0
  } else {
1974
0
    file_hdr.ts_year  = GUINT16_TO_LE(1900 + 0);
1975
0
    file_hdr.ts_month = GUINT16_TO_LE(0 + 1);
1976
0
    file_hdr.ts_dow   = GUINT16_TO_LE(0);
1977
0
    file_hdr.ts_day   = GUINT16_TO_LE(0);
1978
0
    file_hdr.ts_hour  = GUINT16_TO_LE(0);
1979
0
    file_hdr.ts_min   = GUINT16_TO_LE(0);
1980
0
    file_hdr.ts_sec   = GUINT16_TO_LE(0);
1981
0
  }
1982
0
  file_hdr.ts_msec = GUINT16_TO_LE(netmon->first_record_time.nsecs/1000000);
1983
0
  file_hdr.frametableoffset = GUINT32_TO_LE(netmon->frame_table_offset);
1984
0
  file_hdr.frametablelength =
1985
0
      GUINT32_TO_LE(netmon->frame_table_index * sizeof *netmon->frame_table);
1986
0
  if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1987
0
    return false;
1988
1989
0
  wdh->bytes_dumped = saved_bytes_dumped;
1990
0
  return true;
1991
0
}
1992
1993
static const struct supported_block_type netmon_1_x_blocks_supported[] = {
1994
  /*
1995
   * We support packet blocks, with no comments or other options.
1996
   */
1997
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
1998
};
1999
2000
static const struct file_type_subtype_info netmon_1_x_info = {
2001
  "Microsoft NetMon 1.x", "netmon1", "cap", NULL,
2002
  true, BLOCKS_SUPPORTED(netmon_1_x_blocks_supported),
2003
  netmon_dump_can_write_encap_1_x, netmon_dump_open_1_x, NULL
2004
};
2005
2006
static const struct supported_block_type netmon_2_x_blocks_supported[] = {
2007
  /*
2008
   * We support packet blocks, with no comments or other options.
2009
   */
2010
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
2011
};
2012
2013
static const struct file_type_subtype_info netmon_2_x_info = {
2014
  "Microsoft NetMon 2.x", "netmon2", "cap", NULL,
2015
  true, BLOCKS_SUPPORTED(netmon_2_x_blocks_supported),
2016
  netmon_dump_can_write_encap_2_x, netmon_dump_open_2_x, NULL
2017
};
2018
2019
void register_netmon(void)
2020
14
{
2021
14
  netmon_1_x_file_type_subtype = wtap_register_file_type_subtype(&netmon_1_x_info);
2022
14
  netmon_2_x_file_type_subtype = wtap_register_file_type_subtype(&netmon_2_x_info);
2023
2024
  /*
2025
   * Register names for backwards compatibility with the
2026
   * wtap_filetypes table in Lua.
2027
   */
2028
14
  wtap_register_backwards_compatibility_lua_name("NETMON_1_x",
2029
14
      netmon_1_x_file_type_subtype);
2030
14
  wtap_register_backwards_compatibility_lua_name("NETMON_2_x",
2031
14
      netmon_2_x_file_type_subtype);
2032
14
}
2033
2034
/*
2035
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2036
 *
2037
 * Local variables:
2038
 * c-basic-offset: 8
2039
 * tab-width: 8
2040
 * indent-tabs-mode: t
2041
 * End:
2042
 *
2043
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2044
 * :indentSize=8:tabSize=8:noTabs=false:
2045
 */