4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "file_wrappers.h"
27 #include "pcap-encap.h"
32 * ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
34 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
35 * for the header of a Microsoft Network Monitor 1.x capture file.
37 * The help files for Network Monitor 3.x document the 2.x file format.
40 /* Capture file header, *including* magic number, is padded to 128 bytes. */
41 #define CAPTUREFILE_HEADER_SIZE 128
43 /* Magic number size, for both 1.x and 2.x. */
46 /* Magic number in Network Monitor 1.x files. */
47 static const char netmon_1_x_magic[MAGIC_SIZE] = {
51 /* Magic number in Network Monitor 2.x files. */
52 static const char netmon_2_x_magic[MAGIC_SIZE] = {
56 /* Network Monitor file header (minus magic number). */
58 guint8 ver_minor; /* minor version number */
59 guint8 ver_major; /* major version number */
60 guint16 network; /* network type */
61 guint16 ts_year; /* year of capture start */
62 guint16 ts_month; /* month of capture start (January = 1) */
63 guint16 ts_dow; /* day of week of capture start (Sun = 0) */
64 guint16 ts_day; /* day of month of capture start */
65 guint16 ts_hour; /* hour of capture start */
66 guint16 ts_min; /* minute of capture start */
67 guint16 ts_sec; /* second of capture start */
68 guint16 ts_msec; /* millisecond of capture start */
69 guint32 frametableoffset; /* frame index table offset */
70 guint32 frametablelength; /* frame index table size */
71 guint32 userdataoffset; /* user data offset */
72 guint32 userdatalength; /* user data size */
73 guint32 commentdataoffset; /* comment data offset */
74 guint32 commentdatalength; /* comment data size */
75 guint32 statisticsoffset; /* offset to statistics structure */
76 guint32 statisticslength; /* length of statistics structure */
77 guint32 networkinfooffset; /* offset to network info structure */
78 guint32 networkinfolength; /* length of network info structure */
81 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
82 * looking at capture files. */
83 struct netmonrec_1_x_hdr {
84 guint32 ts_delta; /* time stamp - msecs since start of capture */
85 guint16 orig_len; /* actual length of packet */
86 guint16 incl_len; /* number of octets captured in file */
90 * Network Monitor 2.x record header, as documented in NetMon 3.x's
93 struct netmonrec_2_x_hdr {
94 guint64 ts_delta; /* time stamp - usecs since start of capture */
95 guint32 orig_len; /* actual length of packet */
96 guint32 incl_len; /* number of octets captured in file */
100 * Network Monitor 2.1 and later record trailers; documented in the Network
101 * Monitor 3.x help files, for 3.3 and later, although they don't clearly
102 * state how the trailer format changes from version to version.
104 * Some fields are multi-byte integers, but they're not aligned on their
105 * natural boundaries.
107 struct netmonrec_2_1_trlr {
108 guint8 network[2]; /* network type for this packet */
111 struct netmonrec_2_2_trlr {
112 guint8 network[2]; /* network type for this packet */
113 guint8 process_info_index[4]; /* index into the process info table */
116 struct netmonrec_2_3_trlr {
117 guint8 network[2]; /* network type for this packet */
118 guint8 process_info_index[4]; /* index into the process info table */
119 guint8 utc_timestamp[8]; /* packet time stamp, as .1 us units since January 1, 1601, 00:00:00 UTC */
120 guint8 timezone_index; /* index of time zone information */
124 * The link-layer header on ATM packets.
126 struct netmon_atm_hdr {
127 guint8 dest[6]; /* "Destination address" - what is it? */
128 guint8 src[6]; /* "Source address" - what is it? */
129 guint16 vpi; /* VPI */
130 guint16 vci; /* VCI */
136 guint8 version_major;
137 guint8 version_minor;
138 guint32 *frame_table;
139 guint32 frame_table_size;
144 * XXX - at least in some NetMon 3.4 VPN captures, the per-packet
145 * link-layer type is 0, but the packets have Ethernet headers.
146 * We handle this by mapping 0 to WTAP_ENCAP_ETHERNET; should we,
147 * instead, use the per-file link-layer type?
149 static const int netmon_encap[] = {
152 WTAP_ENCAP_TOKEN_RING,
153 WTAP_ENCAP_FDDI_BITSWAPPED,
154 WTAP_ENCAP_ATM_PDUS, /* NDIS WAN - this is what's used for ATM */
155 WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk, but format 2.x uses it for IP-over-IEEE 1394 */
156 WTAP_ENCAP_IEEE_802_11_NETMON,
157 /* NDIS "DIX", but format 2.x uses it for 802.11 */
158 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET raw, but format 2.x uses it for "Tunneling interfaces" */
159 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET 878.2, but format 2.x uses it for "Wireless WAN" */
160 WTAP_ENCAP_RAW_IP, /* NDIS ATM (no, this is NOT used for ATM); format 2.x uses it for "Raw IP Frames" */
161 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
162 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
164 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
167 * Special link-layer types.
169 #define NETMON_NET_PCAP_BASE 0xE000
170 #define NETMON_NET_NETEVENT 0xFFE0
171 #define NETMON_NET_NETWORK_INFO_EX 0xFFFB
172 #define NETMON_NET_PAYLOAD_HEADER 0xFFFC
173 #define NETMON_NET_NETWORK_INFO 0xFFFD
174 #define NETMON_NET_DNS_CACHE 0xFFFE
175 #define NETMON_NET_NETMON_FILTER 0xFFFF
177 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
178 gint64 *data_offset);
179 static gboolean netmon_seek_read(wtap *wth, gint64 seek_off,
180 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
181 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
182 union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
183 static void netmon_sequential_close(wtap *wth);
184 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
185 const guint8 *pd, int *err, gchar **err_info);
186 static gboolean netmon_dump_finish(wtap_dumper *wdh, int *err);
188 wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info)
190 char magic[MAGIC_SIZE];
191 struct netmon_hdr hdr;
194 guint32 frame_table_offset;
195 guint32 frame_table_length;
196 guint32 frame_table_size;
197 guint32 *frame_table;
198 #ifdef WORDS_BIGENDIAN
203 /* Read in the string that should be at the start of a Network
205 if (!wtap_read_bytes(wth->fh, magic, MAGIC_SIZE, err, err_info)) {
206 if (*err != WTAP_ERR_SHORT_READ)
207 return WTAP_OPEN_ERROR;
208 return WTAP_OPEN_NOT_MINE;
211 if (memcmp(magic, netmon_1_x_magic, MAGIC_SIZE) != 0 &&
212 memcmp(magic, netmon_2_x_magic, MAGIC_SIZE) != 0) {
213 return WTAP_OPEN_NOT_MINE;
216 /* Read the rest of the header. */
217 if (!wtap_read_bytes(wth->fh, &hdr, sizeof hdr, err, err_info))
218 return WTAP_OPEN_ERROR;
220 switch (hdr.ver_major) {
223 file_type = WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x;
227 file_type = WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x;
231 *err = WTAP_ERR_UNSUPPORTED;
232 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
233 return WTAP_OPEN_ERROR;
236 hdr.network = pletoh16(&hdr.network);
237 if (hdr.network >= NUM_NETMON_ENCAPS
238 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
239 *err = WTAP_ERR_UNSUPPORTED;
240 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
242 return WTAP_OPEN_ERROR;
245 /* This is a netmon file */
246 wth->file_type_subtype = file_type;
247 netmon = (netmon_t *)g_malloc(sizeof(netmon_t));
248 wth->priv = (void *)netmon;
249 wth->subtype_read = netmon_read;
250 wth->subtype_seek_read = netmon_seek_read;
251 wth->subtype_sequential_close = netmon_sequential_close;
253 /* NetMon capture file formats v2.1+ use per-packet encapsulation types. NetMon 3 sets the value in
254 * the header to 1 (Ethernet) for backwards compability. */
255 if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
256 wth->file_encap = WTAP_ENCAP_PER_PACKET;
258 wth->file_encap = netmon_encap[hdr.network];
260 wth->snapshot_length = 0; /* not available in header */
262 * Convert the time stamp to a "time_t" and a number of
265 tm.tm_year = pletoh16(&hdr.ts_year) - 1900;
266 tm.tm_mon = pletoh16(&hdr.ts_month) - 1;
267 tm.tm_mday = pletoh16(&hdr.ts_day);
268 tm.tm_hour = pletoh16(&hdr.ts_hour);
269 tm.tm_min = pletoh16(&hdr.ts_min);
270 tm.tm_sec = pletoh16(&hdr.ts_sec);
272 netmon->start_secs = mktime(&tm);
274 * XXX - what if "secs" is -1? Unlikely, but if the capture was
275 * done in a time zone that switches between standard and summer
276 * time sometime other than when we do, and thus the time was one
277 * that doesn't exist here because a switch from standard to summer
278 * time zips over it, it could happen.
280 * On the other hand, if the capture was done in a different time
281 * zone, this won't work right anyway; unfortunately, the time
282 * zone isn't stored in the capture file (why the hell didn't
283 * they stuff a FILETIME, which is the number of 100-nanosecond
284 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
285 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
287 netmon->start_nsecs = pletoh16(&hdr.ts_msec)*1000000;
289 netmon->version_major = hdr.ver_major;
290 netmon->version_minor = hdr.ver_minor;
293 * No frame table allocated yet; initialize these in case we
294 * get an error before allocating it or when trying to allocate
295 * it, so that the attempt to release the private data on failure
298 netmon->frame_table_size = 0;
299 netmon->frame_table = NULL;
302 * Get the offset of the frame index table.
304 frame_table_offset = pletoh32(&hdr.frametableoffset);
307 * It appears that some NetMon 2.x files don't have the
308 * first packet starting exactly 128 bytes into the file.
310 * Furthermore, it also appears that there are "holes" in
311 * the file, i.e. frame N+1 doesn't always follow immediately
314 * Therefore, we must read the frame table, and use the offsets
315 * in it as the offsets of the frames.
317 frame_table_length = pletoh32(&hdr.frametablelength);
318 frame_table_size = frame_table_length / (guint32)sizeof (guint32);
319 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
320 *err = WTAP_ERR_BAD_FILE;
321 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
323 return WTAP_OPEN_ERROR;
325 if (frame_table_size == 0) {
326 *err = WTAP_ERR_BAD_FILE;
327 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
329 return WTAP_OPEN_ERROR;
332 * XXX - clamp the size of the frame table, so that we don't
333 * attempt to allocate a huge frame table and fail.
335 * Given that file offsets in the frame table are 32-bit,
336 * a NetMon file cannot be bigger than 2^32 bytes.
337 * Given that a NetMon 1.x-format packet header is 8 bytes,
338 * that means a NetMon file cannot have more than
339 * 512*2^20 packets. We'll pick that as the limit for
340 * now; it's 1/8th of a 32-bit address space, which is
341 * probably not going to exhaust the address space all by
342 * itself, and probably won't exhaust the backing store.
344 if (frame_table_size > 512*1024*1024) {
345 *err = WTAP_ERR_BAD_FILE;
346 *err_info = g_strdup_printf("netmon: frame table length is %u, which is larger than we support",
348 return WTAP_OPEN_ERROR;
350 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
351 return WTAP_OPEN_ERROR;
353 frame_table = (guint32 *)g_try_malloc(frame_table_length);
354 if (frame_table_length != 0 && frame_table == NULL) {
355 *err = ENOMEM; /* we assume we're out of memory */
356 return WTAP_OPEN_ERROR;
358 if (!wtap_read_bytes(wth->fh, frame_table, frame_table_length,
361 return WTAP_OPEN_ERROR;
363 netmon->frame_table_size = frame_table_size;
364 netmon->frame_table = frame_table;
366 #ifdef WORDS_BIGENDIAN
368 * OK, now byte-swap the frame table.
370 for (i = 0; i < frame_table_size; i++)
371 frame_table[i] = pletoh32(&frame_table[i]);
374 /* Set up to start reading at the first frame. */
375 netmon->current_frame = 0;
376 switch (netmon->version_major) {
380 * Version 1.x of the file format supports
381 * millisecond precision.
383 wth->file_tsprec = WTAP_TSPREC_MSEC;
388 * Version 1.x of the file format supports
389 * 100-nanosecond precision; we don't
390 * currently support that, so say
391 * "nanosecond precision" for now.
393 wth->file_tsprec = WTAP_TSPREC_NSEC;
396 return WTAP_OPEN_MINE;
400 netmon_set_pseudo_header_info(struct wtap_pkthdr *phdr, Buffer *buf)
402 switch (phdr->pkt_encap) {
404 case WTAP_ENCAP_ATM_PDUS:
406 * Attempt to guess from the packet data, the VPI, and
407 * the VCI information about the type of traffic.
409 atm_guess_traffic_type(phdr, ws_buffer_start_ptr(buf));
412 case WTAP_ENCAP_ETHERNET:
414 * We assume there's no FCS in this frame.
416 phdr->pseudo_header.eth.fcs_len = 0;
419 case WTAP_ENCAP_IEEE_802_11_NETMON:
421 * It appears to be the case that management
422 * frames (and control and extension frames ?) may
423 * or may not have an FCS and data frames don't.
424 * (Netmon capture files have been seen for this
425 * encapsulation having management frames either
426 * completely with or without an FCS. Also: instances have been
427 * seen where both Management and Control frames
428 * do not have an FCS).
429 * An "FCS length" of -2 means "NetMon weirdness".
431 memset(&phdr->pseudo_header.ieee_802_11, 0, sizeof(phdr->pseudo_header.ieee_802_11));
432 phdr->pseudo_header.ieee_802_11.fcs_len = -2;
433 phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
434 phdr->pseudo_header.ieee_802_11.datapad = FALSE;
435 phdr->pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
444 } process_record_retval;
446 static process_record_retval
447 netmon_process_record(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
448 Buffer *buf, int *err, gchar **err_info)
450 netmon_t *netmon = (netmon_t *)wth->priv;
453 struct netmonrec_1_x_hdr hdr_1_x;
454 struct netmonrec_2_x_hdr hdr_2_x;
456 gint64 delta = 0; /* signed - frame times can be before the nominal start */
460 guint32 packet_size = 0;
461 guint32 orig_size = 0;
464 struct netmonrec_2_1_trlr trlr_2_1;
465 struct netmonrec_2_2_trlr trlr_2_2;
466 struct netmonrec_2_3_trlr trlr_2_3;
471 /* Read record header. */
472 switch (netmon->version_major) {
475 hdr_size = sizeof (struct netmonrec_1_x_hdr);
479 hdr_size = sizeof (struct netmonrec_2_x_hdr);
482 if (!wtap_read_bytes_or_eof(fh, &hdr, hdr_size, err, err_info))
485 switch (netmon->version_major) {
488 orig_size = pletoh16(&hdr.hdr_1_x.orig_len);
489 packet_size = pletoh16(&hdr.hdr_1_x.incl_len);
493 orig_size = pletoh32(&hdr.hdr_2_x.orig_len);
494 packet_size = pletoh32(&hdr.hdr_2_x.incl_len);
497 if (packet_size > WTAP_MAX_PACKET_SIZE) {
499 * Probably a corrupt capture file; don't blow up trying
500 * to allocate space for an immensely-large packet.
502 *err = WTAP_ERR_BAD_FILE;
503 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
504 packet_size, WTAP_MAX_PACKET_SIZE);
508 phdr->rec_type = REC_TYPE_PACKET;
511 * If this is an ATM packet, the first
512 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
513 * source addresses (6 bytes - MAC addresses of some sort?)
514 * and the VPI and VCI; read them and generate the pseudo-header
517 switch (wth->file_encap) {
519 case WTAP_ENCAP_ATM_PDUS:
520 if (packet_size < sizeof (struct netmon_atm_hdr)) {
522 * Uh-oh, the packet isn't big enough to even
523 * have a pseudo-header.
525 *err = WTAP_ERR_BAD_FILE;
526 *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
530 if (!netmon_read_atm_pseudoheader(fh, &phdr->pseudo_header,
532 return FAILURE; /* Read error */
535 * Don't count the pseudo-header as part of the packet.
537 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
538 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
545 switch (netmon->version_major) {
549 * According to Paul Long, this offset is unsigned.
550 * It's 32 bits, so the maximum value will fit in
551 * a gint64 such as delta, even after multiplying
554 * pletoh32() returns a guint32; we cast it to gint64
555 * before multiplying, so that the product doesn't
556 * overflow a guint32.
558 delta = ((gint64)pletoh32(&hdr.hdr_1_x.ts_delta))*1000000;
563 * OK, this is weird. Microsoft's documentation
564 * says this is in microseconds and is a 64-bit
565 * unsigned number, but it can be negative; they
566 * say what appears to amount to "treat it as an
567 * unsigned number, multiply it by 10, and then
568 * interpret the resulting 64-bit quantity as a
569 * signed number". That operation can turn a
570 * value with the uppermost bit 0 to a value with
571 * the uppermost bit 1, hence turning a large
572 * positive number-of-microseconds into a small
573 * negative number-of-100-nanosecond-increments.
575 delta = pletoh64(&hdr.hdr_2_x.ts_delta)*10;
578 * OK, it's now a signed value in 100-nanosecond
579 * units. Now convert it to nanosecond units.
585 t = netmon->start_nsecs + delta;
588 * Propagate a borrow into the seconds.
589 * The seconds is a time_t, and can be < 0
590 * (unlikely, as Windows didn't exist before
591 * January 1, 1970, 00:00:00 UTC), while the
592 * nanoseconds should be positive, as in
593 * "nanoseconds since the instant of time
594 * represented by the seconds".
596 * We do not want t to be negative, as, according
597 * to the C90 standard, "if either operand [of /
598 * or %] is negative, whether the result of the
599 * / operator is the largest integer less than or
600 * equal to the algebraic quotient or the smallest
601 * greater than or equal to the algebraic quotient
602 * is implementation-defined, as is the sign of
603 * the result of the % operator", and we want
604 * the result of the division and remainder
605 * operations to be the same on all platforms.
610 secs += (time_t)(t/1000000000);
611 nsecs = (int)(t%1000000000);
612 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
613 phdr->ts.secs = netmon->start_secs + secs;
614 phdr->ts.nsecs = nsecs;
615 phdr->caplen = packet_size;
616 phdr->len = orig_size;
619 * Read the packet data.
621 if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
625 * For version 2.1 and later, there's additional information
626 * after the frame data.
628 if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
629 netmon->version_major > 2) {
630 if (netmon->version_major > 2) {
632 * Asssume 2.3 format, for now.
634 trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
636 switch (netmon->version_minor) {
639 trlr_size = (int)sizeof (struct netmonrec_2_1_trlr);
643 trlr_size = (int)sizeof (struct netmonrec_2_2_trlr);
647 trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
652 if (!wtap_read_bytes(fh, &trlr, trlr_size, err, err_info))
655 network = pletoh16(trlr.trlr_2_1.network);
656 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
658 * Converted pcap file - the LINKTYPE_ value
659 * is the network value with 0xF000 masked off.
662 pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
663 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
664 *err = WTAP_ERR_UNSUPPORTED;
665 *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
669 } else if (network < NUM_NETMON_ENCAPS) {
671 * Regular NetMon encapsulation.
673 pkt_encap = netmon_encap[network];
674 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
675 *err = WTAP_ERR_UNSUPPORTED;
676 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
682 * Special packet type for metadata.
686 case NETMON_NET_NETEVENT:
688 * Event Tracing event.
690 * http://msdn.microsoft.com/en-us/library/aa363759(VS.85).aspx
694 case NETMON_NET_NETWORK_INFO_EX:
696 * List of adapters on which the capture
701 case NETMON_NET_PAYLOAD_HEADER:
703 * Header for a fake frame constructed
708 case NETMON_NET_NETWORK_INFO:
710 * List of adapters on which the capture
715 case NETMON_NET_DNS_CACHE:
717 * List of resolved IP addresses.
721 case NETMON_NET_NETMON_FILTER:
723 * NetMon capture or display filter
729 *err = WTAP_ERR_UNSUPPORTED;
730 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
736 phdr->pkt_encap = pkt_encap;
737 if (netmon->version_major > 2 || netmon->version_minor > 2) {
740 d = pletoh64(trlr.trlr_2_3.utc_timestamp);
743 * Get the time as seconds and nanoseconds.
744 * and overwrite the time stamp obtained
745 * from the record header.
747 if (!filetime_to_nstime(&phdr->ts, d)) {
748 *err = WTAP_ERR_BAD_FILE;
749 *err_info = g_strdup("netmon: time stamp outside supported range");
755 netmon_set_pseudo_header_info(phdr, buf);
759 /* Read the next packet */
760 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
763 netmon_t *netmon = (netmon_t *)wth->priv;
767 /* Have we reached the end of the packet data? */
768 if (netmon->current_frame >= netmon->frame_table_size) {
769 /* Yes. We won't need the frame table any more;
771 g_free(netmon->frame_table);
772 netmon->frame_table = NULL;
773 *err = 0; /* it's just an EOF, not an error */
777 /* Seek to the beginning of the current record, if we're
778 not there already (seeking to the current position
779 may still cause a seek and a read of the underlying file,
780 so we don't want to do it unconditionally).
782 Yes, the current record could be before the previous
783 record. At least some captures put the trailer record
784 with statistics as the first physical record in the
785 file, but set the frame table up so it's the last
786 record in sequence. */
787 rec_offset = netmon->frame_table[netmon->current_frame];
788 if (file_tell(wth->fh) != rec_offset) {
789 if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
792 netmon->current_frame++;
794 *data_offset = file_tell(wth->fh);
796 switch (netmon_process_record(wth, wth->fh, &wth->phdr,
797 wth->frame_buffer, err, err_info)) {
812 netmon_seek_read(wtap *wth, gint64 seek_off,
813 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
815 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
818 switch (netmon_process_record(wth, wth->random_fh, phdr, buf, err,
823 * This should not happen.
825 *err = WTAP_ERR_BAD_FILE;
826 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
838 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
839 int *err, gchar **err_info)
841 struct netmon_atm_hdr atm_phdr;
844 if (!wtap_read_bytes(fh, &atm_phdr, sizeof (struct netmon_atm_hdr),
848 vpi = g_ntohs(atm_phdr.vpi);
849 vci = g_ntohs(atm_phdr.vci);
851 pseudo_header->atm.vpi = vpi;
852 pseudo_header->atm.vci = vci;
854 /* We don't have this information */
855 pseudo_header->atm.flags = 0;
856 pseudo_header->atm.channel = 0;
857 pseudo_header->atm.cells = 0;
858 pseudo_header->atm.aal5t_u2u = 0;
859 pseudo_header->atm.aal5t_len = 0;
860 pseudo_header->atm.aal5t_chksum = 0;
865 /* Throw away the frame table used by the sequential I/O stream. */
867 netmon_sequential_close(wtap *wth)
869 netmon_t *netmon = (netmon_t *)wth->priv;
871 if (netmon->frame_table != NULL) {
872 g_free(netmon->frame_table);
873 netmon->frame_table = NULL;
878 gboolean got_first_record_time;
879 nstime_t first_record_time;
880 guint32 frame_table_offset;
881 guint32 *frame_table;
882 guint frame_table_index;
883 guint frame_table_size;
884 gboolean no_more_room; /* TRUE if no more records can be written */
887 static const int wtap_encap[] = {
888 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
889 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
890 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
891 -1, /* WTAP_ENCAP_SLIP -> unsupported */
892 -1, /* WTAP_ENCAP_PPP -> unsupported */
893 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
894 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
895 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
896 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
897 -1, /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
898 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
899 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
900 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
901 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
903 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
905 /* Returns 0 if we could write the specified encapsulation type,
906 an error indication otherwise. */
907 int netmon_dump_can_write_encap_1_x(int encap)
910 * Per-packet encapsulations are *not* supported in NetMon 1.x
913 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
914 return WTAP_ERR_UNWRITABLE_ENCAP;
919 int netmon_dump_can_write_encap_2_x(int encap)
922 * Per-packet encapsulations are supported in NetMon 2.1
925 if (encap == WTAP_ENCAP_PER_PACKET)
928 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
929 return WTAP_ERR_UNWRITABLE_ENCAP;
934 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
936 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
938 netmon_dump_t *netmon;
940 /* We can't fill in all the fields in the file header, as we
941 haven't yet written any packets. As we'll have to rewrite
942 the header when we've written out all the packets, we just
943 skip over the header for now. */
944 if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
947 wdh->subtype_write = netmon_dump;
948 wdh->subtype_finish = netmon_dump_finish;
950 netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
951 wdh->priv = (void *)netmon;
952 netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
953 netmon->got_first_record_time = FALSE;
954 netmon->frame_table = NULL;
955 netmon->frame_table_index = 0;
956 netmon->frame_table_size = 0;
957 netmon->no_more_room = FALSE;
962 /* Write a record for a packet to a dump file.
963 Returns TRUE on success, FALSE on failure. */
964 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
965 const guint8 *pd, int *err, gchar **err_info _U_)
967 const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
968 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
969 struct netmonrec_1_x_hdr rec_1_x_hdr;
970 struct netmonrec_2_x_hdr rec_2_x_hdr;
973 struct netmonrec_2_1_trlr rec_2_x_trlr;
975 struct netmon_atm_hdr atm_hdr;
980 /* We can only write packet records. */
981 if (phdr->rec_type != REC_TYPE_PACKET) {
982 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
986 switch (wdh->file_type_subtype) {
988 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
990 * The length fields are 16-bit, so there's a hard limit
993 if (phdr->caplen > 65535) {
994 *err = WTAP_ERR_PACKET_TOO_LARGE;
999 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1000 /* Don't write anything we're not willing to read. */
1001 if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
1002 *err = WTAP_ERR_PACKET_TOO_LARGE;
1008 /* We should never get here - our open routine
1009 should only get called for the types above. */
1010 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1014 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1016 * Is this network type supported?
1018 if (phdr->pkt_encap < 0 ||
1019 (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
1020 wtap_encap[phdr->pkt_encap] == -1) {
1024 *err = WTAP_ERR_UNWRITABLE_ENCAP;
1029 * Fill in the trailer with the network type.
1031 phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
1035 * Will the file offset of this frame fit in a 32-bit unsigned
1038 if (netmon->no_more_room) {
1040 * No, so the file is too big for NetMon format to
1048 * NetMon files have a capture start time in the file header,
1049 * and have times relative to that in the packet headers;
1050 * pick the time of the first packet as the capture start
1053 * That time has millisecond resolution, so chop any
1054 * sub-millisecond part of the time stamp off.
1056 if (!netmon->got_first_record_time) {
1057 netmon->first_record_time.secs = phdr->ts.secs;
1058 netmon->first_record_time.nsecs =
1059 (phdr->ts.nsecs/1000000)*1000000;
1060 netmon->got_first_record_time = TRUE;
1063 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
1064 atm_hdrsize = sizeof (struct netmon_atm_hdr);
1067 secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
1068 nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
1071 * Propagate a borrow into the seconds.
1072 * The seconds is a time_t, and can be < 0
1073 * (unlikely, as neither UN*X nor DOS
1074 * nor the original Mac System existed
1075 * before January 1, 1970, 00:00:00 UTC),
1076 * while the nanoseconds should be positive,
1077 * as in "nanoseconds since the instant of time
1078 * represented by the seconds".
1080 * We do not want t to be negative, as, according
1081 * to the C90 standard, "if either operand [of /
1082 * or %] is negative, whether the result of the
1083 * / operator is the largest integer less than or
1084 * equal to the algebraic quotient or the smallest
1085 * greater than or equal to the algebraic quotient
1086 * is implementation-defined, as is the sign of
1087 * the result of the % operator", and we want
1088 * the result of the division and remainder
1089 * operations to be the same on all platforms.
1091 nsecs += 1000000000;
1094 switch (wdh->file_type_subtype) {
1096 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1097 rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
1098 rec_1_x_hdr.orig_len = GUINT16_TO_LE(phdr->len + atm_hdrsize);
1099 rec_1_x_hdr.incl_len = GUINT16_TO_LE(phdr->caplen + atm_hdrsize);
1100 hdrp = &rec_1_x_hdr;
1101 hdr_size = sizeof rec_1_x_hdr;
1104 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1105 rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
1106 rec_2_x_hdr.orig_len = GUINT32_TO_LE(phdr->len + atm_hdrsize);
1107 rec_2_x_hdr.incl_len = GUINT32_TO_LE(phdr->caplen + atm_hdrsize);
1108 hdrp = &rec_2_x_hdr;
1109 hdr_size = sizeof rec_2_x_hdr;
1113 /* We should never get here - our open routine
1114 should only get called for the types above. */
1115 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1120 * Keep track of the record size, as we need to update
1121 * the current file offset.
1125 if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1127 rec_size += hdr_size;
1129 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
1131 * Write the ATM header.
1132 * We supply all-zero destination and source addresses.
1134 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1135 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1136 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1137 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1138 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1140 rec_size += sizeof atm_hdr;
1143 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1145 rec_size += phdr->caplen;
1147 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1149 * Write out the trailer.
1151 if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1152 sizeof rec_2_x_trlr, err))
1154 rec_size += sizeof rec_2_x_trlr;
1158 * Stash the file offset of this frame.
1160 if (netmon->frame_table_size == 0) {
1162 * Haven't yet allocated the buffer for the frame table.
1164 netmon->frame_table = (guint32 *)g_malloc(1024 * sizeof *netmon->frame_table);
1165 netmon->frame_table_size = 1024;
1168 * We've allocated it; are we at the end?
1170 if (netmon->frame_table_index >= netmon->frame_table_size) {
1172 * Yes - double the size of the frame table.
1174 netmon->frame_table_size *= 2;
1175 netmon->frame_table = (guint32 *)g_realloc(netmon->frame_table,
1176 netmon->frame_table_size * sizeof *netmon->frame_table);
1180 netmon->frame_table[netmon->frame_table_index] =
1181 GUINT32_TO_LE(netmon->frame_table_offset);
1184 * Is this the last record we can write?
1185 * I.e., will the frame table offset of the next record not fit
1186 * in a 32-bit frame table offset entry?
1188 * (We don't bother checking whether the number of frames
1189 * will fit in a 32-bit value, as, even if each record were
1190 * 1 byte, if there were more than 2^32-1 packets, the frame
1191 * table offset of at least one of those packets will be >
1194 * Note: this also catches the unlikely possibility that
1195 * the record itself is > 2^32 - 1 bytes long.
1197 if ((guint64)netmon->frame_table_offset + rec_size > G_MAXUINT32) {
1201 netmon->no_more_room = TRUE;
1203 netmon->frame_table_index++;
1204 netmon->frame_table_offset += (guint32) rec_size;
1209 /* Finish writing to a dump file.
1210 Returns TRUE on success, FALSE on failure. */
1211 static gboolean netmon_dump_finish(wtap_dumper *wdh, int *err)
1213 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1215 struct netmon_hdr file_hdr;
1220 /* Write out the frame table. "netmon->frame_table_index" is
1221 the number of entries we've put into it. */
1222 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1223 if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1226 /* Now go fix up the file header. */
1227 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1229 memset(&file_hdr, '\0', sizeof file_hdr);
1230 switch (wdh->file_type_subtype) {
1232 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1233 magicp = netmon_1_x_magic;
1234 magic_size = sizeof netmon_1_x_magic;
1235 /* NetMon file version, for 1.x, is 1.1 */
1236 file_hdr.ver_major = 1;
1237 file_hdr.ver_minor = 1;
1240 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1241 magicp = netmon_2_x_magic;
1242 magic_size = sizeof netmon_2_x_magic;
1244 * NetMon file version, for 2.x, is 2.0;
1245 * for 3.0, it's 2.1.
1247 * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1248 * we need version 2.1.
1250 * XXX - version 2.3 supports UTC time stamps; when
1251 * should we use it? According to the file format
1252 * documentation, NetMon 3.3 "cannot properly
1253 * interpret" the UTC timestamp information; does
1254 * that mean it ignores it and uses the local-time
1255 * start time and time deltas, or mishandles them?
1256 * Also, NetMon 3.1 and earlier can't read version
1257 * 2.2, much less version 2.3.
1259 file_hdr.ver_major = 2;
1260 file_hdr.ver_minor =
1261 (wdh->encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1265 /* We should never get here - our open routine
1266 should only get called for the types above. */
1268 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1271 if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1274 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1276 * We're writing NetMon 2.1 format, so the media
1277 * type in the file header is irrelevant. Set it
1278 * to 1, just as Network Monitor does.
1280 file_hdr.network = GUINT16_TO_LE(1);
1282 file_hdr.network = GUINT16_TO_LE(wtap_encap[wdh->encap]);
1283 tm = localtime(&netmon->first_record_time.secs);
1285 file_hdr.ts_year = GUINT16_TO_LE(1900 + tm->tm_year);
1286 file_hdr.ts_month = GUINT16_TO_LE(tm->tm_mon + 1);
1287 file_hdr.ts_dow = GUINT16_TO_LE(tm->tm_wday);
1288 file_hdr.ts_day = GUINT16_TO_LE(tm->tm_mday);
1289 file_hdr.ts_hour = GUINT16_TO_LE(tm->tm_hour);
1290 file_hdr.ts_min = GUINT16_TO_LE(tm->tm_min);
1291 file_hdr.ts_sec = GUINT16_TO_LE(tm->tm_sec);
1293 file_hdr.ts_year = GUINT16_TO_LE(1900 + 0);
1294 file_hdr.ts_month = GUINT16_TO_LE(0 + 1);
1295 file_hdr.ts_dow = GUINT16_TO_LE(0);
1296 file_hdr.ts_day = GUINT16_TO_LE(0);
1297 file_hdr.ts_hour = GUINT16_TO_LE(0);
1298 file_hdr.ts_min = GUINT16_TO_LE(0);
1299 file_hdr.ts_sec = GUINT16_TO_LE(0);
1301 file_hdr.ts_msec = GUINT16_TO_LE(netmon->first_record_time.nsecs/1000000);
1302 file_hdr.frametableoffset = GUINT32_TO_LE(netmon->frame_table_offset);
1303 file_hdr.frametablelength =
1304 GUINT32_TO_LE(netmon->frame_table_index * sizeof *netmon->frame_table);
1305 if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1312 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1317 * indent-tabs-mode: t
1320 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1321 * :indentSize=8:tabSize=8:noTabs=false: