sec_vt_header: dissect drep
[wireshark-wip.git] / wiretap / netmon.c
blob4b41f351684b684391ac39ff20c0a97427436e4f
1 /* netmon.c
3 * $Id$
5 * Wiretap Library
6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "config.h"
24 #include <errno.h>
25 #include <string.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include "buffer.h"
29 #include "atm.h"
30 #include "pcap-encap.h"
31 #include "netmon.h"
33 /* The file at
35 * ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
37 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
38 * for the header of a Microsoft Network Monitor 1.x capture file.
40 * The help files for Network Monitor 3.x document the 2.x file format.
43 /* Capture file header, *including* magic number, is padded to 128 bytes. */
44 #define CAPTUREFILE_HEADER_SIZE 128
46 /* Magic number size, for both 1.x and 2.x. */
47 #define MAGIC_SIZE 4
49 /* Magic number in Network Monitor 1.x files. */
50 static const char netmon_1_x_magic[MAGIC_SIZE] = {
51 'R', 'T', 'S', 'S'
54 /* Magic number in Network Monitor 2.x files. */
55 static const char netmon_2_x_magic[MAGIC_SIZE] = {
56 'G', 'M', 'B', 'U'
59 /* Network Monitor file header (minus magic number). */
60 struct netmon_hdr {
61 guint8 ver_minor; /* minor version number */
62 guint8 ver_major; /* major version number */
63 guint16 network; /* network type */
64 guint16 ts_year; /* year of capture start */
65 guint16 ts_month; /* month of capture start (January = 1) */
66 guint16 ts_dow; /* day of week of capture start (Sun = 0) */
67 guint16 ts_day; /* day of month of capture start */
68 guint16 ts_hour; /* hour of capture start */
69 guint16 ts_min; /* minute of capture start */
70 guint16 ts_sec; /* second of capture start */
71 guint16 ts_msec; /* millisecond of capture start */
72 guint32 frametableoffset; /* frame index table offset */
73 guint32 frametablelength; /* frame index table size */
74 guint32 userdataoffset; /* user data offset */
75 guint32 userdatalength; /* user data size */
76 guint32 commentdataoffset; /* comment data offset */
77 guint32 commentdatalength; /* comment data size */
78 guint32 statisticsoffset; /* offset to statistics structure */
79 guint32 statisticslength; /* length of statistics structure */
80 guint32 networkinfooffset; /* offset to network info structure */
81 guint32 networkinfolength; /* length of network info structure */
84 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
85 * looking at capture files. */
86 struct netmonrec_1_x_hdr {
87 guint32 ts_delta; /* time stamp - msecs since start of capture */
88 guint16 orig_len; /* actual length of packet */
89 guint16 incl_len; /* number of octets captured in file */
93 * Network Monitor 2.x record header, as documented in NetMon 3.x's
94 * help files.
96 struct netmonrec_2_x_hdr {
97 guint64 ts_delta; /* time stamp - usecs since start of capture */
98 guint32 orig_len; /* actual length of packet */
99 guint32 incl_len; /* number of octets captured in file */
103 * Network Monitor 2.1 and later record trailers; documented in the Network
104 * Monitor 3.x help files, for 3.3 and later, although they don't clearly
105 * state how the trailer format changes from version to version.
107 * Some fields are multi-byte integers, but they're not aligned on their
108 * natural boundaries.
110 struct netmonrec_2_1_trlr {
111 guint8 network[2]; /* network type for this packet */
114 struct netmonrec_2_2_trlr {
115 guint8 network[2]; /* network type for this packet */
116 guint8 process_info_index[4]; /* index into the process info table */
119 struct netmonrec_2_3_trlr {
120 guint8 network[2]; /* network type for this packet */
121 guint8 process_info_index[4]; /* index into the process info table */
122 guint8 utc_timestamp[8]; /* packet time stamp, as .1 us units since January 1, 1601, 00:00:00 UTC */
123 guint8 timezone_index; /* index of time zone information */
127 * The link-layer header on ATM packets.
129 struct netmon_atm_hdr {
130 guint8 dest[6]; /* "Destination address" - what is it? */
131 guint8 src[6]; /* "Source address" - what is it? */
132 guint16 vpi; /* VPI */
133 guint16 vci; /* VCI */
136 typedef struct {
137 time_t start_secs;
138 guint32 start_nsecs;
139 guint8 version_major;
140 guint8 version_minor;
141 guint32 *frame_table;
142 guint32 frame_table_size;
143 guint current_frame;
144 } netmon_t;
147 * XXX - at least in some NetMon 3.4 VPN captures, the per-packet
148 * link-layer type is 0, but the packets have Ethernet headers.
149 * We handle this by mapping 0 to WTAP_ENCAP_ETHERNET; should we,
150 * instead, use the per-file link-layer type?
152 static const int netmon_encap[] = {
153 WTAP_ENCAP_ETHERNET,
154 WTAP_ENCAP_ETHERNET,
155 WTAP_ENCAP_TOKEN_RING,
156 WTAP_ENCAP_FDDI_BITSWAPPED,
157 WTAP_ENCAP_ATM_PDUS, /* NDIS WAN - this is what's used for ATM */
158 WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk, but format 2.x uses it for IP-over-IEEE 1394 */
159 WTAP_ENCAP_IEEE_802_11_NETMON,
160 /* NDIS "DIX", but format 2.x uses it for 802.11 */
161 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET raw, but format 2.x uses it for "Tunneling interfaces" */
162 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET 878.2, but format 2.x uses it for "Wireless WAN" */
163 WTAP_ENCAP_RAW_IP, /* NDIS ATM (no, this is NOT used for ATM); format 2.x uses it for "Raw IP Frames" */
164 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
165 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
167 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
170 * Special link-layer types.
172 #define NETMON_NET_PCAP_BASE 0xE000
173 #define NETMON_NET_NETEVENT 0xFFE0
174 #define NETMON_NET_NETWORK_INFO_EX 0xFFFB
175 #define NETMON_NET_PAYLOAD_HEADER 0xFFFC
176 #define NETMON_NET_NETWORK_INFO 0xFFFD
177 #define NETMON_NET_DNS_CACHE 0xFFFE
178 #define NETMON_NET_NETMON_FILTER 0xFFFF
180 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
181 gint64 *data_offset);
182 static gboolean netmon_seek_read(wtap *wth, gint64 seek_off,
183 struct wtap_pkthdr *phdr, Buffer *buf, int length,
184 int *err, gchar **err_info);
185 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
186 union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
187 static int netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err,
188 gchar **err_info);
189 static void netmon_sequential_close(wtap *wth);
190 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
191 const guint8 *pd, int *err);
192 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
194 int netmon_open(wtap *wth, int *err, gchar **err_info)
196 int bytes_read;
197 char magic[MAGIC_SIZE];
198 struct netmon_hdr hdr;
199 int file_type;
200 struct tm tm;
201 guint32 frame_table_offset;
202 guint32 frame_table_length;
203 guint32 frame_table_size;
204 guint32 *frame_table;
205 #ifdef WORDS_BIGENDIAN
206 unsigned int i;
207 #endif
208 netmon_t *netmon;
210 /* Read in the string that should be at the start of a Network
211 * Monitor file */
212 errno = WTAP_ERR_CANT_READ;
213 bytes_read = file_read(magic, MAGIC_SIZE, wth->fh);
214 if (bytes_read != MAGIC_SIZE) {
215 *err = file_error(wth->fh, err_info);
216 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
217 return -1;
218 return 0;
221 if (memcmp(magic, netmon_1_x_magic, MAGIC_SIZE) != 0 &&
222 memcmp(magic, netmon_2_x_magic, MAGIC_SIZE) != 0) {
223 return 0;
226 /* Read the rest of the header. */
227 errno = WTAP_ERR_CANT_READ;
228 bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
229 if (bytes_read != sizeof hdr) {
230 *err = file_error(wth->fh, err_info);
231 if (*err == 0)
232 *err = WTAP_ERR_SHORT_READ;
233 return -1;
236 switch (hdr.ver_major) {
238 case 1:
239 file_type = WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x;
240 break;
242 case 2:
243 file_type = WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x;
244 break;
246 default:
247 *err = WTAP_ERR_UNSUPPORTED;
248 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
249 return -1;
252 hdr.network = pletohs(&hdr.network);
253 if (hdr.network >= NUM_NETMON_ENCAPS
254 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
255 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
256 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
257 hdr.network);
258 return -1;
261 /* This is a netmon file */
262 wth->file_type_subtype = file_type;
263 netmon = (netmon_t *)g_malloc(sizeof(netmon_t));
264 wth->priv = (void *)netmon;
265 wth->subtype_read = netmon_read;
266 wth->subtype_seek_read = netmon_seek_read;
267 wth->subtype_sequential_close = netmon_sequential_close;
269 /* NetMon capture file formats v2.1+ use per-packet encapsulation types. NetMon 3 sets the value in
270 * the header to 1 (Ethernet) for backwards compability. */
271 if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
272 wth->file_encap = WTAP_ENCAP_PER_PACKET;
273 else
274 wth->file_encap = netmon_encap[hdr.network];
276 wth->snapshot_length = 0; /* not available in header */
278 * Convert the time stamp to a "time_t" and a number of
279 * milliseconds.
281 tm.tm_year = pletohs(&hdr.ts_year) - 1900;
282 tm.tm_mon = pletohs(&hdr.ts_month) - 1;
283 tm.tm_mday = pletohs(&hdr.ts_day);
284 tm.tm_hour = pletohs(&hdr.ts_hour);
285 tm.tm_min = pletohs(&hdr.ts_min);
286 tm.tm_sec = pletohs(&hdr.ts_sec);
287 tm.tm_isdst = -1;
288 netmon->start_secs = mktime(&tm);
290 * XXX - what if "secs" is -1? Unlikely, but if the capture was
291 * done in a time zone that switches between standard and summer
292 * time sometime other than when we do, and thus the time was one
293 * that doesn't exist here because a switch from standard to summer
294 * time zips over it, it could happen.
296 * On the other hand, if the capture was done in a different time
297 * zone, this won't work right anyway; unfortunately, the time
298 * zone isn't stored in the capture file (why the hell didn't
299 * they stuff a FILETIME, which is the number of 100-nanosecond
300 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
301 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
303 netmon->start_nsecs = pletohs(&hdr.ts_msec)*1000000;
305 netmon->version_major = hdr.ver_major;
306 netmon->version_minor = hdr.ver_minor;
309 * No frame table allocated yet; initialize these in case we
310 * get an error before allocating it or when trying to allocate
311 * it, so that the attempt to release the private data on failure
312 * doesn't crash.
314 netmon->frame_table_size = 0;
315 netmon->frame_table = NULL;
318 * Get the offset of the frame index table.
320 frame_table_offset = pletohl(&hdr.frametableoffset);
323 * It appears that some NetMon 2.x files don't have the
324 * first packet starting exactly 128 bytes into the file.
326 * Furthermore, it also appears that there are "holes" in
327 * the file, i.e. frame N+1 doesn't always follow immediately
328 * after frame N.
330 * Therefore, we must read the frame table, and use the offsets
331 * in it as the offsets of the frames.
333 frame_table_length = pletohl(&hdr.frametablelength);
334 frame_table_size = frame_table_length / (guint32)sizeof (guint32);
335 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
336 *err = WTAP_ERR_BAD_FILE;
337 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
338 frame_table_length);
339 return -1;
341 if (frame_table_size == 0) {
342 *err = WTAP_ERR_BAD_FILE;
343 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
344 frame_table_length);
345 return -1;
348 * XXX - clamp the size of the frame table, so that we don't
349 * attempt to allocate a huge frame table and fail.
351 * Given that file offsets in the frame table are 32-bit,
352 * a NetMon file cannot be bigger than 2^32 bytes.
353 * Given that a NetMon 1.x-format packet header is 8 bytes,
354 * that means a NetMon file cannot have more than
355 * 512*2^20 packets. We'll pick that as the limit for
356 * now; it's 1/8th of a 32-bit address space, which is
357 * probably not going to exhaust the address space all by
358 * itself, and probably won't exhaust the backing store.
360 if (frame_table_size > 512*1024*1024) {
361 *err = WTAP_ERR_BAD_FILE;
362 *err_info = g_strdup_printf("netmon: frame table length is %u, which is larger than we support",
363 frame_table_length);
364 return -1;
366 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
367 return -1;
369 frame_table = (guint32 *)g_try_malloc(frame_table_length);
370 if (frame_table_length != 0 && frame_table == NULL) {
371 *err = ENOMEM; /* we assume we're out of memory */
372 return -1;
374 errno = WTAP_ERR_CANT_READ;
375 bytes_read = file_read(frame_table, frame_table_length, wth->fh);
376 if ((guint32)bytes_read != frame_table_length) {
377 *err = file_error(wth->fh, err_info);
378 if (*err == 0)
379 *err = WTAP_ERR_SHORT_READ;
380 g_free(frame_table);
381 return -1;
383 netmon->frame_table_size = frame_table_size;
384 netmon->frame_table = frame_table;
386 #ifdef WORDS_BIGENDIAN
388 * OK, now byte-swap the frame table.
390 for (i = 0; i < frame_table_size; i++)
391 frame_table[i] = pletohl(&frame_table[i]);
392 #endif
394 /* Set up to start reading at the first frame. */
395 netmon->current_frame = 0;
396 switch (netmon->version_major) {
398 case 1:
400 * Version 1.x of the file format supports
401 * millisecond precision.
403 wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
404 break;
406 case 2:
408 * Version 1.x of the file format supports
409 * 100-nanosecond precision; we don't
410 * currently support that, so say
411 * "nanosecond precision" for now.
413 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
414 break;
416 return 1;
419 static size_t
420 netmon_trailer_size(netmon_t *netmon)
422 if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
423 netmon->version_major > 2) {
424 if (netmon->version_major > 2) {
426 * Asssume 2.3 format, for now.
428 return sizeof (struct netmonrec_2_3_trlr);
429 } else {
430 switch (netmon->version_minor) {
432 case 1:
433 return sizeof (struct netmonrec_2_1_trlr);
435 case 2:
436 return sizeof (struct netmonrec_2_2_trlr);
438 default:
439 return sizeof (struct netmonrec_2_3_trlr);
443 return 0; /* no trailer */
446 static void
447 netmon_set_pseudo_header_info(int pkt_encap,
448 union wtap_pseudo_header *pseudo_header, Buffer *buf, int length)
450 guint8 *pd = buffer_start_ptr(buf);
452 switch (pkt_encap) {
454 case WTAP_ENCAP_ATM_PDUS:
456 * Attempt to guess from the packet data, the VPI, and
457 * the VCIinformation about the type of traffic.
459 atm_guess_traffic_type(pd, length, pseudo_header);
460 break;
462 case WTAP_ENCAP_ETHERNET:
464 * We assume there's no FCS in this frame.
466 pseudo_header->eth.fcs_len = 0;
467 break;
469 case WTAP_ENCAP_IEEE_802_11_NETMON:
471 * It appears to be the case that management
472 * frames have an FCS and data frames don't;
473 * I'm not sure about control frames. An
474 * "FCS length" of -2 means "NetMon weirdness".
476 pseudo_header->ieee_802_11.fcs_len = -2;
477 pseudo_header->ieee_802_11.decrypted = FALSE;
478 break;
482 static gboolean netmon_process_rec_header(wtap *wth, FILE_T fh,
483 struct wtap_pkthdr *phdr, int *err, gchar **err_info)
485 netmon_t *netmon = (netmon_t *)wth->priv;
486 int hdr_size = 0;
487 union {
488 struct netmonrec_1_x_hdr hdr_1_x;
489 struct netmonrec_2_x_hdr hdr_2_x;
490 } hdr;
491 int bytes_read;
492 gint64 delta = 0; /* signed - frame times can be before the nominal start */
493 gint64 t;
494 time_t secs;
495 guint32 nsecs;
496 guint32 packet_size = 0;
497 guint32 orig_size = 0;
499 /* Read record header. */
500 switch (netmon->version_major) {
502 case 1:
503 hdr_size = sizeof (struct netmonrec_1_x_hdr);
504 break;
506 case 2:
507 hdr_size = sizeof (struct netmonrec_2_x_hdr);
508 break;
510 errno = WTAP_ERR_CANT_READ;
512 bytes_read = file_read(&hdr, hdr_size, fh);
513 if (bytes_read != hdr_size) {
514 *err = file_error(fh, err_info);
515 if (*err == 0 && bytes_read != 0) {
516 *err = WTAP_ERR_SHORT_READ;
518 return FALSE;
521 switch (netmon->version_major) {
523 case 1:
524 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
525 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
526 break;
528 case 2:
529 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
530 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
531 break;
533 if (packet_size > WTAP_MAX_PACKET_SIZE) {
535 * Probably a corrupt capture file; don't blow up trying
536 * to allocate space for an immensely-large packet.
538 *err = WTAP_ERR_BAD_FILE;
539 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
540 packet_size, WTAP_MAX_PACKET_SIZE);
541 return FALSE;
545 * If this is an ATM packet, the first
546 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
547 * source addresses (6 bytes - MAC addresses of some sort?)
548 * and the VPI and VCI; read them and generate the pseudo-header
549 * from them.
551 switch (wth->file_encap) {
553 case WTAP_ENCAP_ATM_PDUS:
554 if (packet_size < sizeof (struct netmon_atm_hdr)) {
556 * Uh-oh, the packet isn't big enough to even
557 * have a pseudo-header.
559 *err = WTAP_ERR_BAD_FILE;
560 *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
561 packet_size);
562 return FALSE;
564 if (!netmon_read_atm_pseudoheader(fh, &phdr->pseudo_header,
565 err, err_info))
566 return FALSE; /* Read error */
569 * Don't count the pseudo-header as part of the packet.
571 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
572 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
573 break;
575 default:
576 break;
579 switch (netmon->version_major) {
581 case 1:
583 * According to Paul Long, this offset is unsigned.
584 * It's 32 bits, so the maximum value will fit in
585 * a gint64 such as delta, even after multiplying
586 * it by 1000000.
588 * pletohl() returns a guint32; we cast it to gint64
589 * before multiplying, so that the product doesn't
590 * overflow a guint32.
592 delta = ((gint64)pletohl(&hdr.hdr_1_x.ts_delta))*1000000;
593 break;
595 case 2:
597 * OK, this is weird. Microsoft's documentation
598 * says this is in microseconds and is a 64-bit
599 * unsigned number, but it can be negative; they
600 * say what appears to amount to "treat it as an
601 * unsigned number, multiply it by 10, and then
602 * interpret the resulting 64-bit quantity as a
603 * signed number". That operation can turn a
604 * value with the uppermost bit 0 to a value with
605 * the uppermost bit 1, hence turning a large
606 * positive number-of-microseconds into a small
607 * negative number-of-100-nanosecond-increments.
609 delta = pletohll(&hdr.hdr_2_x.ts_delta)*10;
612 * OK, it's now a signed value in 100-nanosecond
613 * units. Now convert it to nanosecond units.
615 delta *= 100;
616 break;
618 secs = 0;
619 t = netmon->start_nsecs + delta;
620 while (t < 0) {
622 * Propagate a borrow into the seconds.
623 * The seconds is a time_t, and can be < 0
624 * (unlikely, as Windows didn't exist before
625 * January 1, 1970, 00:00:00 UTC), while the
626 * nanoseconds should be positive, as in
627 * "nanoseconds since the instant of time
628 * represented by the seconds".
630 * We do not want t to be negative, as, according
631 * to the C90 standard, "if either operand [of /
632 * or %] is negative, whether the result of the
633 * / operator is the largest integer less than or
634 * equal to the algebraic quotient or the smallest
635 * greater than or equal to the algebraic quotient
636 * is implementation-defined, as is the sign of
637 * the result of the % operator", and we want
638 * the result of the division and remainder
639 * operations to be the same on all platforms.
641 t += 1000000000;
642 secs--;
644 secs += (time_t)(t/1000000000);
645 nsecs = (guint32)(t%1000000000);
646 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
647 phdr->ts.secs = netmon->start_secs + secs;
648 phdr->ts.nsecs = nsecs;
649 phdr->caplen = packet_size;
650 phdr->len = orig_size;
652 return TRUE;
655 typedef enum {
656 SUCCESS,
657 FAILURE,
658 RETRY
659 } process_trailer_retval;
661 static process_trailer_retval netmon_process_rec_trailer(netmon_t *netmon,
662 FILE_T fh, struct wtap_pkthdr *phdr, int *err, gchar **err_info)
664 int trlr_size;
666 trlr_size = (int)netmon_trailer_size(netmon);
667 if (trlr_size != 0) {
669 * I haz a trailer.
671 phdr->pkt_encap = netmon_read_rec_trailer(fh,
672 trlr_size, err, err_info);
673 if (phdr->pkt_encap == -1)
674 return FAILURE; /* error */
675 if (phdr->pkt_encap == 0)
676 return RETRY;
679 return SUCCESS;
682 /* Read the next packet */
683 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
684 gint64 *data_offset)
686 netmon_t *netmon = (netmon_t *)wth->priv;
687 gint64 rec_offset;
689 again:
690 /* Have we reached the end of the packet data? */
691 if (netmon->current_frame >= netmon->frame_table_size) {
692 /* Yes. We won't need the frame table any more;
693 free it. */
694 g_free(netmon->frame_table);
695 netmon->frame_table = NULL;
696 *err = 0; /* it's just an EOF, not an error */
697 return FALSE;
700 /* Seek to the beginning of the current record, if we're
701 not there already (seeking to the current position
702 may still cause a seek and a read of the underlying file,
703 so we don't want to do it unconditionally).
705 Yes, the current record could be before the previous
706 record. At least some captures put the trailer record
707 with statistics as the first physical record in the
708 file, but set the frame table up so it's the last
709 record in sequence. */
710 rec_offset = netmon->frame_table[netmon->current_frame];
711 if (file_tell(wth->fh) != rec_offset) {
712 if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
713 return FALSE;
715 netmon->current_frame++;
717 *data_offset = file_tell(wth->fh);
719 if (!netmon_process_rec_header(wth, wth->fh, &wth->phdr,
720 err, err_info))
721 return FALSE;
723 if (!wtap_read_packet_bytes(wth->fh, wth->frame_buffer,
724 wth->phdr.caplen, err, err_info))
725 return FALSE; /* Read error */
728 * For version 2.1 and later, there's additional information
729 * after the frame data.
731 switch (netmon_process_rec_trailer(netmon, wth->fh, &wth->phdr,
732 err, err_info)) {
734 case RETRY:
735 goto again;
737 case SUCCESS:
738 break;
740 case FAILURE:
741 return FALSE;
744 netmon_set_pseudo_header_info(wth->phdr.pkt_encap,
745 &wth->phdr.pseudo_header, wth->frame_buffer, wth->phdr.caplen);
746 return TRUE;
749 static gboolean
750 netmon_seek_read(wtap *wth, gint64 seek_off,
751 struct wtap_pkthdr *phdr, Buffer *buf, int length,
752 int *err, gchar **err_info)
754 netmon_t *netmon = (netmon_t *)wth->priv;
756 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
757 return FALSE;
759 if (!netmon_process_rec_header(wth, wth->random_fh, phdr,
760 err, err_info))
761 return FALSE;
764 * Read the packet data.
766 if (!wtap_read_packet_bytes(wth->random_fh, buf, length, err, err_info))
767 return FALSE;
770 * For version 2.1 and later, there's additional information
771 * after the frame data.
773 switch (netmon_process_rec_trailer(netmon, wth->random_fh, phdr,
774 err, err_info)) {
776 case RETRY:
778 * This should not happen.
780 *err = WTAP_ERR_BAD_FILE;
781 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
782 return FALSE;
784 case SUCCESS:
785 break;
787 case FAILURE:
788 return FALSE;
791 netmon_set_pseudo_header_info(phdr->pkt_encap,
792 &phdr->pseudo_header, buf, phdr->caplen);
794 return TRUE;
797 static gboolean
798 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
799 int *err, gchar **err_info)
801 struct netmon_atm_hdr atm_phdr;
802 int bytes_read;
803 guint16 vpi, vci;
805 errno = WTAP_ERR_CANT_READ;
806 bytes_read = file_read(&atm_phdr, sizeof (struct netmon_atm_hdr), fh);
807 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
808 *err = file_error(fh, err_info);
809 if (*err == 0)
810 *err = WTAP_ERR_SHORT_READ;
811 return FALSE;
814 vpi = g_ntohs(atm_phdr.vpi);
815 vci = g_ntohs(atm_phdr.vci);
817 pseudo_header->atm.vpi = vpi;
818 pseudo_header->atm.vci = vci;
820 /* We don't have this information */
821 pseudo_header->atm.flags = 0;
822 pseudo_header->atm.channel = 0;
823 pseudo_header->atm.cells = 0;
824 pseudo_header->atm.aal5t_u2u = 0;
825 pseudo_header->atm.aal5t_len = 0;
826 pseudo_header->atm.aal5t_chksum = 0;
828 return TRUE;
832 * Read a record trailer.
833 * On success, returns the packet encapsulation type.
834 * On error, returns -1 (which is WTAP_ENCAP_PER_PACKET, but we'd
835 * never return that on success).
836 * For metadata packets, returns 0 (which is WTAP_ENCAP_UNKNOWN, but
837 * we'd never return that on success).
839 static int
840 netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err, gchar **err_info)
842 int bytes_read;
843 union {
844 struct netmonrec_2_1_trlr trlr_2_1;
845 struct netmonrec_2_2_trlr trlr_2_2;
846 struct netmonrec_2_3_trlr trlr_2_3;
847 } trlr;
848 guint16 network;
849 int pkt_encap;
851 errno = WTAP_ERR_CANT_READ;
852 bytes_read = file_read(&trlr, trlr_size, fh);
853 if (bytes_read != trlr_size) {
854 *err = file_error(fh, err_info);
855 if (*err == 0 && bytes_read != 0) {
856 *err = WTAP_ERR_SHORT_READ;
858 return -1; /* error */
861 network = pletohs(trlr.trlr_2_1.network);
862 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
864 * Converted pcap file - the LINKTYPE_ value
865 * is the network value with 0xF000 masked off.
867 network &= 0x0FFF;
868 pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
869 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
870 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
871 *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
872 network);
873 return -1; /* error */
875 } else if (network < NUM_NETMON_ENCAPS) {
877 * Regular NetMon encapsulation.
879 pkt_encap = netmon_encap[network];
880 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
881 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
882 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
883 network);
884 return -1; /* error */
886 } else {
888 * Special packet type for metadata.
890 switch (network) {
892 case NETMON_NET_NETEVENT:
893 case NETMON_NET_NETWORK_INFO_EX:
894 case NETMON_NET_PAYLOAD_HEADER:
895 case NETMON_NET_NETWORK_INFO:
896 case NETMON_NET_DNS_CACHE:
897 case NETMON_NET_NETMON_FILTER:
899 * Just ignore those record types, for
900 * now. Tell our caller to read the next
901 * record.
903 return 0;
905 default:
906 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
907 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
908 network);
909 return -1; /* error */
913 return pkt_encap; /* success */
916 /* Throw away the frame table used by the sequential I/O stream. */
917 static void
918 netmon_sequential_close(wtap *wth)
920 netmon_t *netmon = (netmon_t *)wth->priv;
922 if (netmon->frame_table != NULL) {
923 g_free(netmon->frame_table);
924 netmon->frame_table = NULL;
928 typedef struct {
929 gboolean got_first_record_time;
930 nstime_t first_record_time;
931 guint32 frame_table_offset;
932 guint32 *frame_table;
933 guint frame_table_index;
934 guint frame_table_size;
935 gboolean no_more_room; /* TRUE if no more records can be written */
936 } netmon_dump_t;
938 static const int wtap_encap[] = {
939 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
940 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
941 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
942 -1, /* WTAP_ENCAP_SLIP -> unsupported */
943 -1, /* WTAP_ENCAP_PPP -> unsupported */
944 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
945 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
946 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
947 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
948 -1, /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
949 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
950 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
951 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
952 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
954 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
956 /* Returns 0 if we could write the specified encapsulation type,
957 an error indication otherwise. */
958 int netmon_dump_can_write_encap_1_x(int encap)
961 * Per-packet encapsulations are *not* supported in NetMon 1.x
962 * format.
964 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
965 return WTAP_ERR_UNSUPPORTED_ENCAP;
967 return 0;
970 int netmon_dump_can_write_encap_2_x(int encap)
973 * Per-packet encapsulations are supported in NetMon 2.1
974 * format.
976 if (encap == WTAP_ENCAP_PER_PACKET)
977 return 0;
979 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
980 return WTAP_ERR_UNSUPPORTED_ENCAP;
982 return 0;
985 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
986 failure */
987 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
989 netmon_dump_t *netmon;
991 /* We can't fill in all the fields in the file header, as we
992 haven't yet written any packets. As we'll have to rewrite
993 the header when we've written out all the packets, we just
994 skip over the header for now. */
995 if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
996 return FALSE;
998 wdh->subtype_write = netmon_dump;
999 wdh->subtype_close = netmon_dump_close;
1001 netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
1002 wdh->priv = (void *)netmon;
1003 netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
1004 netmon->got_first_record_time = FALSE;
1005 netmon->frame_table = NULL;
1006 netmon->frame_table_index = 0;
1007 netmon->frame_table_size = 0;
1008 netmon->no_more_room = FALSE;
1010 return TRUE;
1013 /* Write a record for a packet to a dump file.
1014 Returns TRUE on success, FALSE on failure. */
1015 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1016 const guint8 *pd, int *err)
1018 const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
1019 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1020 struct netmonrec_1_x_hdr rec_1_x_hdr;
1021 struct netmonrec_2_x_hdr rec_2_x_hdr;
1022 void *hdrp;
1023 size_t rec_size;
1024 struct netmonrec_2_1_trlr rec_2_x_trlr;
1025 size_t hdr_size;
1026 struct netmon_atm_hdr atm_hdr;
1027 int atm_hdrsize;
1028 gint64 secs;
1029 gint32 nsecs;
1031 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1033 * Is this network type supported?
1035 if (phdr->pkt_encap < 0 ||
1036 (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
1037 wtap_encap[phdr->pkt_encap] == -1) {
1039 * No. Fail.
1041 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
1042 return FALSE;
1046 * Fill in the trailer with the network type.
1048 phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
1052 * Will the file offset of this frame fit in a 32-bit unsigned
1053 * integer?
1055 if (netmon->no_more_room) {
1057 * No, so the file is too big for NetMon format to
1058 * handle.
1060 *err = EFBIG;
1061 return FALSE;
1065 * NetMon files have a capture start time in the file header,
1066 * and have times relative to that in the packet headers;
1067 * pick the time of the first packet as the capture start
1068 * time.
1070 * That time has millisecond resolution, so chop any
1071 * sub-millisecond part of the time stamp off.
1073 if (!netmon->got_first_record_time) {
1074 netmon->first_record_time.secs = phdr->ts.secs;
1075 netmon->first_record_time.nsecs =
1076 (phdr->ts.nsecs/1000000)*1000000;
1077 netmon->got_first_record_time = TRUE;
1080 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
1081 atm_hdrsize = sizeof (struct netmon_atm_hdr);
1082 else
1083 atm_hdrsize = 0;
1084 secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
1085 nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
1086 while (nsecs < 0) {
1088 * Propagate a borrow into the seconds.
1089 * The seconds is a time_t, and can be < 0
1090 * (unlikely, as neither UN*X nor DOS
1091 * nor the original Mac System existed
1092 * before January 1, 1970, 00:00:00 UTC),
1093 * while the nanoseconds should be positive,
1094 * as in "nanoseconds since the instant of time
1095 * represented by the seconds".
1097 * We do not want t to be negative, as, according
1098 * to the C90 standard, "if either operand [of /
1099 * or %] is negative, whether the result of the
1100 * / operator is the largest integer less than or
1101 * equal to the algebraic quotient or the smallest
1102 * greater than or equal to the algebraic quotient
1103 * is implementation-defined, as is the sign of
1104 * the result of the % operator", and we want
1105 * the result of the division and remainder
1106 * operations to be the same on all platforms.
1108 nsecs += 1000000000;
1109 secs--;
1111 switch (wdh->file_type_subtype) {
1113 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1114 rec_1_x_hdr.ts_delta = htolel(secs*1000 + (nsecs + 500000)/1000000);
1115 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
1116 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
1117 hdrp = &rec_1_x_hdr;
1118 hdr_size = sizeof rec_1_x_hdr;
1119 break;
1121 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1122 rec_2_x_hdr.ts_delta = htolell(secs*1000000 + (nsecs + 500)/1000);
1123 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
1124 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
1125 hdrp = &rec_2_x_hdr;
1126 hdr_size = sizeof rec_2_x_hdr;
1127 break;
1129 default:
1130 /* We should never get here - our open routine
1131 should only get called for the types above. */
1132 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1133 return FALSE;
1137 * Keep track of the record size, as we need to update
1138 * the current file offset.
1140 rec_size = 0;
1142 if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1143 return FALSE;
1144 rec_size += hdr_size;
1146 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
1148 * Write the ATM header.
1149 * We supply all-zero destination and source addresses.
1151 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1152 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1153 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1154 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1155 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1156 return FALSE;
1157 rec_size += sizeof atm_hdr;
1160 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1161 return FALSE;
1162 rec_size += phdr->caplen;
1164 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1166 * Write out the trailer.
1168 if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1169 sizeof rec_2_x_trlr, err))
1170 return FALSE;
1171 rec_size += sizeof rec_2_x_trlr;
1175 * Stash the file offset of this frame.
1177 if (netmon->frame_table_size == 0) {
1179 * Haven't yet allocated the buffer for the frame table.
1181 netmon->frame_table = (guint32 *)g_malloc(1024 * sizeof *netmon->frame_table);
1182 netmon->frame_table_size = 1024;
1183 } else {
1185 * We've allocated it; are we at the end?
1187 if (netmon->frame_table_index >= netmon->frame_table_size) {
1189 * Yes - double the size of the frame table.
1191 netmon->frame_table_size *= 2;
1192 netmon->frame_table = (guint32 *)g_realloc(netmon->frame_table,
1193 netmon->frame_table_size * sizeof *netmon->frame_table);
1197 netmon->frame_table[netmon->frame_table_index] =
1198 htolel(netmon->frame_table_offset);
1201 * Is this the last record we can write?
1202 * I.e., will the frame table offset of the next record not fit
1203 * in a 32-bit frame table offset entry?
1205 * (We don't bother checking whether the number of frames
1206 * will fit in a 32-bit value, as, even if each record were
1207 * 1 byte, if there were more than 2^32-1 packets, the frame
1208 * table offset of at least one of those packets will be >
1209 * 2^32 - 1.)
1211 * Note: this also catches the unlikely possibility that
1212 * the record itself is > 2^32 - 1 bytes long.
1214 if ((guint64)netmon->frame_table_offset + rec_size > G_MAXUINT32) {
1216 * Yup, too big.
1218 netmon->no_more_room = TRUE;
1220 netmon->frame_table_index++;
1221 netmon->frame_table_offset += (guint32) rec_size;
1223 return TRUE;
1226 /* Finish writing to a dump file.
1227 Returns TRUE on success, FALSE on failure. */
1228 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
1230 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1231 size_t n_to_write;
1232 struct netmon_hdr file_hdr;
1233 const char *magicp;
1234 size_t magic_size;
1235 struct tm *tm;
1237 /* Write out the frame table. "netmon->frame_table_index" is
1238 the number of entries we've put into it. */
1239 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1240 if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1241 return FALSE;
1243 /* Now go fix up the file header. */
1244 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1245 return FALSE;
1246 memset(&file_hdr, '\0', sizeof file_hdr);
1247 switch (wdh->file_type_subtype) {
1249 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1250 magicp = netmon_1_x_magic;
1251 magic_size = sizeof netmon_1_x_magic;
1252 /* NetMon file version, for 1.x, is 1.1 */
1253 file_hdr.ver_major = 1;
1254 file_hdr.ver_minor = 1;
1255 break;
1257 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1258 magicp = netmon_2_x_magic;
1259 magic_size = sizeof netmon_2_x_magic;
1261 * NetMon file version, for 2.x, is 2.0;
1262 * for 3.0, it's 2.1.
1264 * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1265 * we need version 2.1.
1267 * XXX - version 2.3 supports UTC time stamps; when
1268 * should we use it? According to the file format
1269 * documentation, NetMon 3.3 "cannot properly
1270 * interpret" the UTC timestamp information; does
1271 * that mean it ignores it and uses the local-time
1272 * start time and time deltas, or mishandles them?
1273 * Also, NetMon 3.1 and earlier can't read version
1274 * 2.2, much less version 2.3.
1276 file_hdr.ver_major = 2;
1277 file_hdr.ver_minor =
1278 (wdh->encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1279 break;
1281 default:
1282 /* We should never get here - our open routine
1283 should only get called for the types above. */
1284 if (err != NULL)
1285 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1286 return FALSE;
1288 if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1289 return FALSE;
1291 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1293 * We're writing NetMon 2.1 format, so the media
1294 * type in the file header is irrelevant. Set it
1295 * to 1, just as Network Monitor does.
1297 file_hdr.network = htoles(1);
1298 } else
1299 file_hdr.network = htoles(wtap_encap[wdh->encap]);
1300 tm = localtime(&netmon->first_record_time.secs);
1301 if (tm != NULL) {
1302 file_hdr.ts_year = htoles(1900 + tm->tm_year);
1303 file_hdr.ts_month = htoles(tm->tm_mon + 1);
1304 file_hdr.ts_dow = htoles(tm->tm_wday);
1305 file_hdr.ts_day = htoles(tm->tm_mday);
1306 file_hdr.ts_hour = htoles(tm->tm_hour);
1307 file_hdr.ts_min = htoles(tm->tm_min);
1308 file_hdr.ts_sec = htoles(tm->tm_sec);
1309 } else {
1310 file_hdr.ts_year = htoles(1900 + 0);
1311 file_hdr.ts_month = htoles(0 + 1);
1312 file_hdr.ts_dow = htoles(0);
1313 file_hdr.ts_day = htoles(0);
1314 file_hdr.ts_hour = htoles(0);
1315 file_hdr.ts_min = htoles(0);
1316 file_hdr.ts_sec = htoles(0);
1318 file_hdr.ts_msec = htoles(netmon->first_record_time.nsecs/1000000);
1319 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
1320 file_hdr.frametablelength =
1321 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
1322 if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1323 return FALSE;
1325 return TRUE;