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_close(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 phdr->pseudo_header.ieee_802_11.presence_flags = 0; /* radio data is in the packet data */
432 phdr->pseudo_header.ieee_802_11.fcs_len = -2;
433 phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
442 } process_record_retval;
445 * Number of seconds between the UN*X epoch (January 1, 1970, 00:00:00 GMT)
446 * and the Windows NT epoch (January 1, 1601, 00:00:00 "GMT").
448 #define TIME_FIXUP_CONSTANT G_GUINT64_CONSTANT(11644473600)
451 #define TIME_T_MIN ((time_t) ((time_t)0 < (time_t) -1 ? (time_t) 0 \
452 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
455 #define TIME_T_MAX ((time_t) (~ (time_t) 0 - TIME_T_MIN))
458 static process_record_retval
459 netmon_process_record(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
460 Buffer *buf, int *err, gchar **err_info)
462 netmon_t *netmon = (netmon_t *)wth->priv;
465 struct netmonrec_1_x_hdr hdr_1_x;
466 struct netmonrec_2_x_hdr hdr_2_x;
468 gint64 delta = 0; /* signed - frame times can be before the nominal start */
472 guint32 packet_size = 0;
473 guint32 orig_size = 0;
476 struct netmonrec_2_1_trlr trlr_2_1;
477 struct netmonrec_2_2_trlr trlr_2_2;
478 struct netmonrec_2_3_trlr trlr_2_3;
483 /* Read record header. */
484 switch (netmon->version_major) {
487 hdr_size = sizeof (struct netmonrec_1_x_hdr);
491 hdr_size = sizeof (struct netmonrec_2_x_hdr);
494 if (!wtap_read_bytes_or_eof(fh, &hdr, hdr_size, err, err_info))
497 switch (netmon->version_major) {
500 orig_size = pletoh16(&hdr.hdr_1_x.orig_len);
501 packet_size = pletoh16(&hdr.hdr_1_x.incl_len);
505 orig_size = pletoh32(&hdr.hdr_2_x.orig_len);
506 packet_size = pletoh32(&hdr.hdr_2_x.incl_len);
509 if (packet_size > WTAP_MAX_PACKET_SIZE) {
511 * Probably a corrupt capture file; don't blow up trying
512 * to allocate space for an immensely-large packet.
514 *err = WTAP_ERR_BAD_FILE;
515 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
516 packet_size, WTAP_MAX_PACKET_SIZE);
520 phdr->rec_type = REC_TYPE_PACKET;
523 * If this is an ATM packet, the first
524 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
525 * source addresses (6 bytes - MAC addresses of some sort?)
526 * and the VPI and VCI; read them and generate the pseudo-header
529 switch (wth->file_encap) {
531 case WTAP_ENCAP_ATM_PDUS:
532 if (packet_size < sizeof (struct netmon_atm_hdr)) {
534 * Uh-oh, the packet isn't big enough to even
535 * have a pseudo-header.
537 *err = WTAP_ERR_BAD_FILE;
538 *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
542 if (!netmon_read_atm_pseudoheader(fh, &phdr->pseudo_header,
544 return FAILURE; /* Read error */
547 * Don't count the pseudo-header as part of the packet.
549 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
550 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
557 switch (netmon->version_major) {
561 * According to Paul Long, this offset is unsigned.
562 * It's 32 bits, so the maximum value will fit in
563 * a gint64 such as delta, even after multiplying
566 * pletoh32() returns a guint32; we cast it to gint64
567 * before multiplying, so that the product doesn't
568 * overflow a guint32.
570 delta = ((gint64)pletoh32(&hdr.hdr_1_x.ts_delta))*1000000;
575 * OK, this is weird. Microsoft's documentation
576 * says this is in microseconds and is a 64-bit
577 * unsigned number, but it can be negative; they
578 * say what appears to amount to "treat it as an
579 * unsigned number, multiply it by 10, and then
580 * interpret the resulting 64-bit quantity as a
581 * signed number". That operation can turn a
582 * value with the uppermost bit 0 to a value with
583 * the uppermost bit 1, hence turning a large
584 * positive number-of-microseconds into a small
585 * negative number-of-100-nanosecond-increments.
587 delta = pletoh64(&hdr.hdr_2_x.ts_delta)*10;
590 * OK, it's now a signed value in 100-nanosecond
591 * units. Now convert it to nanosecond units.
597 t = netmon->start_nsecs + delta;
600 * Propagate a borrow into the seconds.
601 * The seconds is a time_t, and can be < 0
602 * (unlikely, as Windows didn't exist before
603 * January 1, 1970, 00:00:00 UTC), while the
604 * nanoseconds should be positive, as in
605 * "nanoseconds since the instant of time
606 * represented by the seconds".
608 * We do not want t to be negative, as, according
609 * to the C90 standard, "if either operand [of /
610 * or %] is negative, whether the result of the
611 * / operator is the largest integer less than or
612 * equal to the algebraic quotient or the smallest
613 * greater than or equal to the algebraic quotient
614 * is implementation-defined, as is the sign of
615 * the result of the % operator", and we want
616 * the result of the division and remainder
617 * operations to be the same on all platforms.
622 secs += (time_t)(t/1000000000);
623 nsecs = (int)(t%1000000000);
624 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
625 phdr->ts.secs = netmon->start_secs + secs;
626 phdr->ts.nsecs = nsecs;
627 phdr->caplen = packet_size;
628 phdr->len = orig_size;
631 * Read the packet data.
633 if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
637 * For version 2.1 and later, there's additional information
638 * after the frame data.
640 if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
641 netmon->version_major > 2) {
642 if (netmon->version_major > 2) {
644 * Asssume 2.3 format, for now.
646 trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
648 switch (netmon->version_minor) {
651 trlr_size = (int)sizeof (struct netmonrec_2_1_trlr);
655 trlr_size = (int)sizeof (struct netmonrec_2_2_trlr);
659 trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
664 if (!wtap_read_bytes(fh, &trlr, trlr_size, err, err_info))
667 network = pletoh16(trlr.trlr_2_1.network);
668 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
670 * Converted pcap file - the LINKTYPE_ value
671 * is the network value with 0xF000 masked off.
674 pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
675 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
676 *err = WTAP_ERR_UNSUPPORTED;
677 *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
681 } else if (network < NUM_NETMON_ENCAPS) {
683 * Regular NetMon encapsulation.
685 pkt_encap = netmon_encap[network];
686 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
687 *err = WTAP_ERR_UNSUPPORTED;
688 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
694 * Special packet type for metadata.
698 case NETMON_NET_NETEVENT:
700 * Event Tracing event.
702 * http://msdn.microsoft.com/en-us/library/aa363759(VS.85).aspx
706 case NETMON_NET_NETWORK_INFO_EX:
708 * List of adapters on which the capture
713 case NETMON_NET_PAYLOAD_HEADER:
715 * Header for a fake frame constructed
720 case NETMON_NET_NETWORK_INFO:
722 * List of adapters on which the capture
727 case NETMON_NET_DNS_CACHE:
729 * List of resolved IP addresses.
733 case NETMON_NET_NETMON_FILTER:
735 * NetMon capture or display filter
741 *err = WTAP_ERR_UNSUPPORTED;
742 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
748 phdr->pkt_encap = pkt_encap;
749 if (netmon->version_major > 2 || netmon->version_minor > 2) {
751 * This code is based on the Samba code:
753 * Unix SMB/Netbios implementation.
755 * time handling functions
756 * Copyright (C) Andrew Tridgell 1992-1998
760 /* The next two lines are a fix needed for the
761 broken SCO compiler. JRA. */
762 time_t l_time_min = TIME_T_MIN;
763 time_t l_time_max = TIME_T_MAX;
765 d = pletoh64(trlr.trlr_2_3.utc_timestamp);
767 /* Split into seconds and nanoseconds. */
768 utcsecs = d / 10000000;
769 nsecs = (int)((d % 10000000)*100);
771 /* Now adjust the seconds. */
772 utcsecs -= TIME_FIXUP_CONSTANT;
774 if (!(l_time_min <= secs && secs <= l_time_max)) {
775 *err = WTAP_ERR_BAD_FILE;
776 *err_info = g_strdup_printf("netmon: time stamp outside supported range");
781 * Get the time as seconds and nanoseconds.
782 * and overwrite the time stamp obtained
783 * from the record header.
785 phdr->ts.secs = (time_t) utcsecs;
786 phdr->ts.nsecs = nsecs;
790 netmon_set_pseudo_header_info(phdr, buf);
794 /* Read the next packet */
795 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
798 netmon_t *netmon = (netmon_t *)wth->priv;
802 /* Have we reached the end of the packet data? */
803 if (netmon->current_frame >= netmon->frame_table_size) {
804 /* Yes. We won't need the frame table any more;
806 g_free(netmon->frame_table);
807 netmon->frame_table = NULL;
808 *err = 0; /* it's just an EOF, not an error */
812 /* Seek to the beginning of the current record, if we're
813 not there already (seeking to the current position
814 may still cause a seek and a read of the underlying file,
815 so we don't want to do it unconditionally).
817 Yes, the current record could be before the previous
818 record. At least some captures put the trailer record
819 with statistics as the first physical record in the
820 file, but set the frame table up so it's the last
821 record in sequence. */
822 rec_offset = netmon->frame_table[netmon->current_frame];
823 if (file_tell(wth->fh) != rec_offset) {
824 if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
827 netmon->current_frame++;
829 *data_offset = file_tell(wth->fh);
831 switch (netmon_process_record(wth, wth->fh, &wth->phdr,
832 wth->frame_buffer, err, err_info)) {
847 netmon_seek_read(wtap *wth, gint64 seek_off,
848 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
850 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
853 switch (netmon_process_record(wth, wth->random_fh, phdr, buf, err,
858 * This should not happen.
860 *err = WTAP_ERR_BAD_FILE;
861 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
873 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
874 int *err, gchar **err_info)
876 struct netmon_atm_hdr atm_phdr;
879 if (!wtap_read_bytes(fh, &atm_phdr, sizeof (struct netmon_atm_hdr),
883 vpi = g_ntohs(atm_phdr.vpi);
884 vci = g_ntohs(atm_phdr.vci);
886 pseudo_header->atm.vpi = vpi;
887 pseudo_header->atm.vci = vci;
889 /* We don't have this information */
890 pseudo_header->atm.flags = 0;
891 pseudo_header->atm.channel = 0;
892 pseudo_header->atm.cells = 0;
893 pseudo_header->atm.aal5t_u2u = 0;
894 pseudo_header->atm.aal5t_len = 0;
895 pseudo_header->atm.aal5t_chksum = 0;
900 /* Throw away the frame table used by the sequential I/O stream. */
902 netmon_sequential_close(wtap *wth)
904 netmon_t *netmon = (netmon_t *)wth->priv;
906 if (netmon->frame_table != NULL) {
907 g_free(netmon->frame_table);
908 netmon->frame_table = NULL;
913 gboolean got_first_record_time;
914 nstime_t first_record_time;
915 guint32 frame_table_offset;
916 guint32 *frame_table;
917 guint frame_table_index;
918 guint frame_table_size;
919 gboolean no_more_room; /* TRUE if no more records can be written */
922 static const int wtap_encap[] = {
923 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
924 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
925 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
926 -1, /* WTAP_ENCAP_SLIP -> unsupported */
927 -1, /* WTAP_ENCAP_PPP -> unsupported */
928 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
929 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
930 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
931 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
932 -1, /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
933 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
934 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
935 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
936 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
938 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
940 /* Returns 0 if we could write the specified encapsulation type,
941 an error indication otherwise. */
942 int netmon_dump_can_write_encap_1_x(int encap)
945 * Per-packet encapsulations are *not* supported in NetMon 1.x
948 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
949 return WTAP_ERR_UNWRITABLE_ENCAP;
954 int netmon_dump_can_write_encap_2_x(int encap)
957 * Per-packet encapsulations are supported in NetMon 2.1
960 if (encap == WTAP_ENCAP_PER_PACKET)
963 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
964 return WTAP_ERR_UNWRITABLE_ENCAP;
969 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
971 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
973 netmon_dump_t *netmon;
975 /* We can't fill in all the fields in the file header, as we
976 haven't yet written any packets. As we'll have to rewrite
977 the header when we've written out all the packets, we just
978 skip over the header for now. */
979 if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
982 wdh->subtype_write = netmon_dump;
983 wdh->subtype_close = netmon_dump_close;
985 netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
986 wdh->priv = (void *)netmon;
987 netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
988 netmon->got_first_record_time = FALSE;
989 netmon->frame_table = NULL;
990 netmon->frame_table_index = 0;
991 netmon->frame_table_size = 0;
992 netmon->no_more_room = FALSE;
997 /* Write a record for a packet to a dump file.
998 Returns TRUE on success, FALSE on failure. */
999 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1000 const guint8 *pd, int *err, gchar **err_info _U_)
1002 const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
1003 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1004 struct netmonrec_1_x_hdr rec_1_x_hdr;
1005 struct netmonrec_2_x_hdr rec_2_x_hdr;
1008 struct netmonrec_2_1_trlr rec_2_x_trlr;
1010 struct netmon_atm_hdr atm_hdr;
1015 /* We can only write packet records. */
1016 if (phdr->rec_type != REC_TYPE_PACKET) {
1017 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
1021 switch (wdh->file_type_subtype) {
1023 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1025 * The length fields are 16-bit, so there's a hard limit
1028 if (phdr->caplen > 65535) {
1029 *err = WTAP_ERR_PACKET_TOO_LARGE;
1034 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1035 /* Don't write anything we're not willing to read. */
1036 if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
1037 *err = WTAP_ERR_PACKET_TOO_LARGE;
1043 /* We should never get here - our open routine
1044 should only get called for the types above. */
1045 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1049 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1051 * Is this network type supported?
1053 if (phdr->pkt_encap < 0 ||
1054 (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
1055 wtap_encap[phdr->pkt_encap] == -1) {
1059 *err = WTAP_ERR_UNWRITABLE_ENCAP;
1064 * Fill in the trailer with the network type.
1066 phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
1070 * Will the file offset of this frame fit in a 32-bit unsigned
1073 if (netmon->no_more_room) {
1075 * No, so the file is too big for NetMon format to
1083 * NetMon files have a capture start time in the file header,
1084 * and have times relative to that in the packet headers;
1085 * pick the time of the first packet as the capture start
1088 * That time has millisecond resolution, so chop any
1089 * sub-millisecond part of the time stamp off.
1091 if (!netmon->got_first_record_time) {
1092 netmon->first_record_time.secs = phdr->ts.secs;
1093 netmon->first_record_time.nsecs =
1094 (phdr->ts.nsecs/1000000)*1000000;
1095 netmon->got_first_record_time = TRUE;
1098 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
1099 atm_hdrsize = sizeof (struct netmon_atm_hdr);
1102 secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
1103 nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
1106 * Propagate a borrow into the seconds.
1107 * The seconds is a time_t, and can be < 0
1108 * (unlikely, as neither UN*X nor DOS
1109 * nor the original Mac System existed
1110 * before January 1, 1970, 00:00:00 UTC),
1111 * while the nanoseconds should be positive,
1112 * as in "nanoseconds since the instant of time
1113 * represented by the seconds".
1115 * We do not want t to be negative, as, according
1116 * to the C90 standard, "if either operand [of /
1117 * or %] is negative, whether the result of the
1118 * / operator is the largest integer less than or
1119 * equal to the algebraic quotient or the smallest
1120 * greater than or equal to the algebraic quotient
1121 * is implementation-defined, as is the sign of
1122 * the result of the % operator", and we want
1123 * the result of the division and remainder
1124 * operations to be the same on all platforms.
1126 nsecs += 1000000000;
1129 switch (wdh->file_type_subtype) {
1131 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1132 rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
1133 rec_1_x_hdr.orig_len = GUINT16_TO_LE(phdr->len + atm_hdrsize);
1134 rec_1_x_hdr.incl_len = GUINT16_TO_LE(phdr->caplen + atm_hdrsize);
1135 hdrp = &rec_1_x_hdr;
1136 hdr_size = sizeof rec_1_x_hdr;
1139 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1140 rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
1141 rec_2_x_hdr.orig_len = GUINT32_TO_LE(phdr->len + atm_hdrsize);
1142 rec_2_x_hdr.incl_len = GUINT32_TO_LE(phdr->caplen + atm_hdrsize);
1143 hdrp = &rec_2_x_hdr;
1144 hdr_size = sizeof rec_2_x_hdr;
1148 /* We should never get here - our open routine
1149 should only get called for the types above. */
1150 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1155 * Keep track of the record size, as we need to update
1156 * the current file offset.
1160 if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1162 rec_size += hdr_size;
1164 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
1166 * Write the ATM header.
1167 * We supply all-zero destination and source addresses.
1169 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1170 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1171 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1172 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1173 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1175 rec_size += sizeof atm_hdr;
1178 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1180 rec_size += phdr->caplen;
1182 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1184 * Write out the trailer.
1186 if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1187 sizeof rec_2_x_trlr, err))
1189 rec_size += sizeof rec_2_x_trlr;
1193 * Stash the file offset of this frame.
1195 if (netmon->frame_table_size == 0) {
1197 * Haven't yet allocated the buffer for the frame table.
1199 netmon->frame_table = (guint32 *)g_malloc(1024 * sizeof *netmon->frame_table);
1200 netmon->frame_table_size = 1024;
1203 * We've allocated it; are we at the end?
1205 if (netmon->frame_table_index >= netmon->frame_table_size) {
1207 * Yes - double the size of the frame table.
1209 netmon->frame_table_size *= 2;
1210 netmon->frame_table = (guint32 *)g_realloc(netmon->frame_table,
1211 netmon->frame_table_size * sizeof *netmon->frame_table);
1215 netmon->frame_table[netmon->frame_table_index] =
1216 GUINT32_TO_LE(netmon->frame_table_offset);
1219 * Is this the last record we can write?
1220 * I.e., will the frame table offset of the next record not fit
1221 * in a 32-bit frame table offset entry?
1223 * (We don't bother checking whether the number of frames
1224 * will fit in a 32-bit value, as, even if each record were
1225 * 1 byte, if there were more than 2^32-1 packets, the frame
1226 * table offset of at least one of those packets will be >
1229 * Note: this also catches the unlikely possibility that
1230 * the record itself is > 2^32 - 1 bytes long.
1232 if ((guint64)netmon->frame_table_offset + rec_size > G_MAXUINT32) {
1236 netmon->no_more_room = TRUE;
1238 netmon->frame_table_index++;
1239 netmon->frame_table_offset += (guint32) rec_size;
1244 /* Finish writing to a dump file.
1245 Returns TRUE on success, FALSE on failure. */
1246 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
1248 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1250 struct netmon_hdr file_hdr;
1255 /* Write out the frame table. "netmon->frame_table_index" is
1256 the number of entries we've put into it. */
1257 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1258 if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1261 /* Now go fix up the file header. */
1262 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1264 memset(&file_hdr, '\0', sizeof file_hdr);
1265 switch (wdh->file_type_subtype) {
1267 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1268 magicp = netmon_1_x_magic;
1269 magic_size = sizeof netmon_1_x_magic;
1270 /* NetMon file version, for 1.x, is 1.1 */
1271 file_hdr.ver_major = 1;
1272 file_hdr.ver_minor = 1;
1275 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1276 magicp = netmon_2_x_magic;
1277 magic_size = sizeof netmon_2_x_magic;
1279 * NetMon file version, for 2.x, is 2.0;
1280 * for 3.0, it's 2.1.
1282 * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1283 * we need version 2.1.
1285 * XXX - version 2.3 supports UTC time stamps; when
1286 * should we use it? According to the file format
1287 * documentation, NetMon 3.3 "cannot properly
1288 * interpret" the UTC timestamp information; does
1289 * that mean it ignores it and uses the local-time
1290 * start time and time deltas, or mishandles them?
1291 * Also, NetMon 3.1 and earlier can't read version
1292 * 2.2, much less version 2.3.
1294 file_hdr.ver_major = 2;
1295 file_hdr.ver_minor =
1296 (wdh->encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1300 /* We should never get here - our open routine
1301 should only get called for the types above. */
1303 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1306 if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1309 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1311 * We're writing NetMon 2.1 format, so the media
1312 * type in the file header is irrelevant. Set it
1313 * to 1, just as Network Monitor does.
1315 file_hdr.network = GUINT16_TO_LE(1);
1317 file_hdr.network = GUINT16_TO_LE(wtap_encap[wdh->encap]);
1318 tm = localtime(&netmon->first_record_time.secs);
1320 file_hdr.ts_year = GUINT16_TO_LE(1900 + tm->tm_year);
1321 file_hdr.ts_month = GUINT16_TO_LE(tm->tm_mon + 1);
1322 file_hdr.ts_dow = GUINT16_TO_LE(tm->tm_wday);
1323 file_hdr.ts_day = GUINT16_TO_LE(tm->tm_mday);
1324 file_hdr.ts_hour = GUINT16_TO_LE(tm->tm_hour);
1325 file_hdr.ts_min = GUINT16_TO_LE(tm->tm_min);
1326 file_hdr.ts_sec = GUINT16_TO_LE(tm->tm_sec);
1328 file_hdr.ts_year = GUINT16_TO_LE(1900 + 0);
1329 file_hdr.ts_month = GUINT16_TO_LE(0 + 1);
1330 file_hdr.ts_dow = GUINT16_TO_LE(0);
1331 file_hdr.ts_day = GUINT16_TO_LE(0);
1332 file_hdr.ts_hour = GUINT16_TO_LE(0);
1333 file_hdr.ts_min = GUINT16_TO_LE(0);
1334 file_hdr.ts_sec = GUINT16_TO_LE(0);
1336 file_hdr.ts_msec = GUINT16_TO_LE(netmon->first_record_time.nsecs/1000000);
1337 file_hdr.frametableoffset = GUINT32_TO_LE(netmon->frame_table_offset);
1338 file_hdr.frametablelength =
1339 GUINT32_TO_LE(netmon->frame_table_index * sizeof *netmon->frame_table);
1340 if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1347 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1352 * indent-tabs-mode: t
1355 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1356 * :indentSize=8:tabSize=8:noTabs=false: