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.
24 #include "wftap-int.h"
26 #include "file_wrappers.h"
29 #include "pcap-encap.h"
34 * ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
36 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
37 * for the header of a Microsoft Network Monitor 1.x capture file.
39 * The help files for Network Monitor 3.x document the 2.x file format.
42 /* Capture file header, *including* magic number, is padded to 128 bytes. */
43 #define CAPTUREFILE_HEADER_SIZE 128
45 /* Magic number size, for both 1.x and 2.x. */
48 /* Magic number in Network Monitor 1.x files. */
49 static const char netmon_1_x_magic[MAGIC_SIZE] = {
53 /* Magic number in Network Monitor 2.x files. */
54 static const char netmon_2_x_magic[MAGIC_SIZE] = {
58 /* Network Monitor file header (minus magic number). */
60 guint8 ver_minor; /* minor version number */
61 guint8 ver_major; /* major version number */
62 guint16 network; /* network type */
63 guint16 ts_year; /* year of capture start */
64 guint16 ts_month; /* month of capture start (January = 1) */
65 guint16 ts_dow; /* day of week of capture start (Sun = 0) */
66 guint16 ts_day; /* day of month of capture start */
67 guint16 ts_hour; /* hour of capture start */
68 guint16 ts_min; /* minute of capture start */
69 guint16 ts_sec; /* second of capture start */
70 guint16 ts_msec; /* millisecond of capture start */
71 guint32 frametableoffset; /* frame index table offset */
72 guint32 frametablelength; /* frame index table size */
73 guint32 userdataoffset; /* user data offset */
74 guint32 userdatalength; /* user data size */
75 guint32 commentdataoffset; /* comment data offset */
76 guint32 commentdatalength; /* comment data size */
77 guint32 statisticsoffset; /* offset to statistics structure */
78 guint32 statisticslength; /* length of statistics structure */
79 guint32 networkinfooffset; /* offset to network info structure */
80 guint32 networkinfolength; /* length of network info structure */
83 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
84 * looking at capture files. */
85 struct netmonrec_1_x_hdr {
86 guint32 ts_delta; /* time stamp - msecs since start of capture */
87 guint16 orig_len; /* actual length of packet */
88 guint16 incl_len; /* number of octets captured in file */
92 * Network Monitor 2.x record header, as documented in NetMon 3.x's
95 struct netmonrec_2_x_hdr {
96 guint64 ts_delta; /* time stamp - usecs since start of capture */
97 guint32 orig_len; /* actual length of packet */
98 guint32 incl_len; /* number of octets captured in file */
102 * Network Monitor 2.1 and later record trailers; documented in the Network
103 * Monitor 3.x help files, for 3.3 and later, although they don't clearly
104 * state how the trailer format changes from version to version.
106 * Some fields are multi-byte integers, but they're not aligned on their
107 * natural boundaries.
109 struct netmonrec_2_1_trlr {
110 guint8 network[2]; /* network type for this packet */
113 struct netmonrec_2_2_trlr {
114 guint8 network[2]; /* network type for this packet */
115 guint8 process_info_index[4]; /* index into the process info table */
118 struct netmonrec_2_3_trlr {
119 guint8 network[2]; /* network type for this packet */
120 guint8 process_info_index[4]; /* index into the process info table */
121 guint8 utc_timestamp[8]; /* packet time stamp, as .1 us units since January 1, 1601, 00:00:00 UTC */
122 guint8 timezone_index; /* index of time zone information */
126 * The link-layer header on ATM packets.
128 struct netmon_atm_hdr {
129 guint8 dest[6]; /* "Destination address" - what is it? */
130 guint8 src[6]; /* "Source address" - what is it? */
131 guint16 vpi; /* VPI */
132 guint16 vci; /* VCI */
138 guint8 version_major;
139 guint8 version_minor;
140 guint32 *frame_table;
141 guint32 frame_table_size;
146 * XXX - at least in some NetMon 3.4 VPN captures, the per-packet
147 * link-layer type is 0, but the packets have Ethernet headers.
148 * We handle this by mapping 0 to WTAP_ENCAP_ETHERNET; should we,
149 * instead, use the per-file link-layer type?
151 static const int netmon_encap[] = {
154 WTAP_ENCAP_TOKEN_RING,
155 WTAP_ENCAP_FDDI_BITSWAPPED,
156 WTAP_ENCAP_ATM_PDUS, /* NDIS WAN - this is what's used for ATM */
157 WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk, but format 2.x uses it for IP-over-IEEE 1394 */
158 WTAP_ENCAP_IEEE_802_11_NETMON,
159 /* NDIS "DIX", but format 2.x uses it for 802.11 */
160 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET raw, but format 2.x uses it for "Tunneling interfaces" */
161 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET 878.2, but format 2.x uses it for "Wireless WAN" */
162 WTAP_ENCAP_RAW_IP, /* NDIS ATM (no, this is NOT used for ATM); format 2.x uses it for "Raw IP Frames" */
163 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
164 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
166 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
169 * Special link-layer types.
171 #define NETMON_NET_PCAP_BASE 0xE000
172 #define NETMON_NET_NETEVENT 0xFFE0
173 #define NETMON_NET_NETWORK_INFO_EX 0xFFFB
174 #define NETMON_NET_PAYLOAD_HEADER 0xFFFC
175 #define NETMON_NET_NETWORK_INFO 0xFFFD
176 #define NETMON_NET_DNS_CACHE 0xFFFE
177 #define NETMON_NET_NETMON_FILTER 0xFFFF
179 static gboolean netmon_read(wftap *wfth, int *err, gchar **err_info,
180 gint64 *data_offset);
181 static gboolean netmon_seek_read(wftap *wth, gint64 seek_off,
182 void* header, Buffer *buf, int *err, gchar **err_info);
183 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
184 union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
185 static int netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err,
187 static void netmon_sequential_close(wftap *wth);
188 static gboolean netmon_dump(wftap_dumper *wdh, const struct wtap_pkthdr *phdr,
189 const guint8 *pd, int *err);
190 static gboolean netmon_dump_close(wftap_dumper *wdh, int *err);
192 int netmon_open(wftap *wfth, int *err, gchar **err_info)
195 char magic[MAGIC_SIZE];
196 struct netmon_hdr hdr;
199 guint32 frame_table_offset;
200 guint32 frame_table_length;
201 guint32 frame_table_size;
202 guint32 *frame_table;
203 #ifdef WORDS_BIGENDIAN
208 /* Read in the string that should be at the start of a Network
210 errno = WTAP_ERR_CANT_READ;
211 bytes_read = file_read(magic, MAGIC_SIZE, wfth->fh);
212 if (bytes_read != MAGIC_SIZE) {
213 *err = file_error(wfth->fh, err_info);
214 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
219 if (memcmp(magic, netmon_1_x_magic, MAGIC_SIZE) != 0 &&
220 memcmp(magic, netmon_2_x_magic, MAGIC_SIZE) != 0) {
224 /* Read the rest of the header. */
225 errno = WTAP_ERR_CANT_READ;
226 bytes_read = file_read(&hdr, sizeof hdr, wfth->fh);
227 if (bytes_read != sizeof hdr) {
228 *err = file_error(wfth->fh, err_info);
230 *err = WTAP_ERR_SHORT_READ;
234 switch (hdr.ver_major) {
237 file_type = WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x;
241 file_type = WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x;
245 *err = WTAP_ERR_UNSUPPORTED;
246 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
250 hdr.network = pletoh16(&hdr.network);
251 if (hdr.network >= NUM_NETMON_ENCAPS
252 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
253 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
254 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
259 /* This is a netmon file */
260 wfth->file_type_subtype = file_type;
261 netmon = (netmon_t *)g_malloc(sizeof(netmon_t));
262 wfth->priv = (void *)netmon;
263 wfth->subtype_read = netmon_read;
264 wfth->subtype_seek_read = netmon_seek_read;
265 wfth->subtype_sequential_close = netmon_sequential_close;
267 /* NetMon capture file formats v2.1+ use per-packet encapsulation types. NetMon 3 sets the value in
268 * the header to 1 (Ethernet) for backwards compability. */
269 if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
270 wfth->file_encap = WTAP_ENCAP_PER_PACKET;
272 wfth->file_encap = netmon_encap[hdr.network];
274 wfth->snapshot_length = 0; /* not available in header */
276 * Convert the time stamp to a "time_t" and a number of
279 tm.tm_year = pletoh16(&hdr.ts_year) - 1900;
280 tm.tm_mon = pletoh16(&hdr.ts_month) - 1;
281 tm.tm_mday = pletoh16(&hdr.ts_day);
282 tm.tm_hour = pletoh16(&hdr.ts_hour);
283 tm.tm_min = pletoh16(&hdr.ts_min);
284 tm.tm_sec = pletoh16(&hdr.ts_sec);
286 netmon->start_secs = mktime(&tm);
288 * XXX - what if "secs" is -1? Unlikely, but if the capture was
289 * done in a time zone that switches between standard and summer
290 * time sometime other than when we do, and thus the time was one
291 * that doesn't exist here because a switch from standard to summer
292 * time zips over it, it could happen.
294 * On the other hand, if the capture was done in a different time
295 * zone, this won't work right anyway; unfortunately, the time
296 * zone isn't stored in the capture file (why the hell didn't
297 * they stuff a FILETIME, which is the number of 100-nanosecond
298 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
299 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
301 netmon->start_nsecs = pletoh16(&hdr.ts_msec)*1000000;
303 netmon->version_major = hdr.ver_major;
304 netmon->version_minor = hdr.ver_minor;
307 * No frame table allocated yet; initialize these in case we
308 * get an error before allocating it or when trying to allocate
309 * it, so that the attempt to release the private data on failure
312 netmon->frame_table_size = 0;
313 netmon->frame_table = NULL;
316 * Get the offset of the frame index table.
318 frame_table_offset = pletoh32(&hdr.frametableoffset);
321 * It appears that some NetMon 2.x files don't have the
322 * first packet starting exactly 128 bytes into the file.
324 * Furthermore, it also appears that there are "holes" in
325 * the file, i.e. frame N+1 doesn't always follow immediately
328 * Therefore, we must read the frame table, and use the offsets
329 * in it as the offsets of the frames.
331 frame_table_length = pletoh32(&hdr.frametablelength);
332 frame_table_size = frame_table_length / (guint32)sizeof (guint32);
333 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
334 *err = WTAP_ERR_BAD_FILE;
335 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
339 if (frame_table_size == 0) {
340 *err = WTAP_ERR_BAD_FILE;
341 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
346 * XXX - clamp the size of the frame table, so that we don't
347 * attempt to allocate a huge frame table and fail.
349 * Given that file offsets in the frame table are 32-bit,
350 * a NetMon file cannot be bigger than 2^32 bytes.
351 * Given that a NetMon 1.x-format packet header is 8 bytes,
352 * that means a NetMon file cannot have more than
353 * 512*2^20 packets. We'll pick that as the limit for
354 * now; it's 1/8th of a 32-bit address space, which is
355 * probably not going to exhaust the address space all by
356 * itself, and probably won't exhaust the backing store.
358 if (frame_table_size > 512*1024*1024) {
359 *err = WTAP_ERR_BAD_FILE;
360 *err_info = g_strdup_printf("netmon: frame table length is %u, which is larger than we support",
364 if (file_seek(wfth->fh, frame_table_offset, SEEK_SET, err) == -1) {
367 frame_table = (guint32 *)g_try_malloc(frame_table_length);
368 if (frame_table_length != 0 && frame_table == NULL) {
369 *err = ENOMEM; /* we assume we're out of memory */
372 errno = WTAP_ERR_CANT_READ;
373 bytes_read = file_read(frame_table, frame_table_length, wfth->fh);
374 if ((guint32)bytes_read != frame_table_length) {
375 *err = file_error(wfth->fh, err_info);
377 *err = WTAP_ERR_SHORT_READ;
381 netmon->frame_table_size = frame_table_size;
382 netmon->frame_table = frame_table;
384 #ifdef WORDS_BIGENDIAN
386 * OK, now byte-swap the frame table.
388 for (i = 0; i < frame_table_size; i++)
389 frame_table[i] = pletoh32(&frame_table[i]);
392 /* Set up to start reading at the first frame. */
393 netmon->current_frame = 0;
394 switch (netmon->version_major) {
398 * Version 1.x of the file format supports
399 * millisecond precision.
401 wfth->tsprecision = WTAP_FILE_TSPREC_MSEC;
406 * Version 1.x of the file format supports
407 * 100-nanosecond precision; we don't
408 * currently support that, so say
409 * "nanosecond precision" for now.
411 wfth->tsprecision = WTAP_FILE_TSPREC_NSEC;
418 netmon_trailer_size(netmon_t *netmon)
420 if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
421 netmon->version_major > 2) {
422 if (netmon->version_major > 2) {
424 * Asssume 2.3 format, for now.
426 return sizeof (struct netmonrec_2_3_trlr);
428 switch (netmon->version_minor) {
431 return sizeof (struct netmonrec_2_1_trlr);
434 return sizeof (struct netmonrec_2_2_trlr);
437 return sizeof (struct netmonrec_2_3_trlr);
441 return 0; /* no trailer */
445 netmon_set_pseudo_header_info(int pkt_encap, struct wtap_pkthdr *phdr,
448 guint8 *pd = buffer_start_ptr(buf);
452 case WTAP_ENCAP_ATM_PDUS:
454 * Attempt to guess from the packet data, the VPI, and
455 * the VCI information about the type of traffic.
457 atm_guess_traffic_type(phdr, pd);
460 case WTAP_ENCAP_ETHERNET:
462 * We assume there's no FCS in this frame.
464 phdr->pseudo_header.eth.fcs_len = 0;
467 case WTAP_ENCAP_IEEE_802_11_NETMON:
469 * It appears to be the case that management
470 * frames have an FCS and data frames don't;
471 * I'm not sure about control frames. An
472 * "FCS length" of -2 means "NetMon weirdness".
474 phdr->pseudo_header.ieee_802_11.fcs_len = -2;
475 phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
480 static gboolean netmon_process_rec_header(wftap *wfth, FILE_T fh,
481 struct wtap_pkthdr *phdr, int *err, gchar **err_info)
483 netmon_t *netmon = (netmon_t *)wfth->priv;
486 struct netmonrec_1_x_hdr hdr_1_x;
487 struct netmonrec_2_x_hdr hdr_2_x;
490 gint64 delta = 0; /* signed - frame times can be before the nominal start */
494 guint32 packet_size = 0;
495 guint32 orig_size = 0;
497 /* Read record header. */
498 switch (netmon->version_major) {
501 hdr_size = sizeof (struct netmonrec_1_x_hdr);
505 hdr_size = sizeof (struct netmonrec_2_x_hdr);
508 errno = WTAP_ERR_CANT_READ;
510 bytes_read = file_read(&hdr, hdr_size, fh);
511 if (bytes_read != hdr_size) {
512 *err = file_error(fh, err_info);
513 if (*err == 0 && bytes_read != 0) {
514 *err = WTAP_ERR_SHORT_READ;
519 switch (netmon->version_major) {
522 orig_size = pletoh16(&hdr.hdr_1_x.orig_len);
523 packet_size = pletoh16(&hdr.hdr_1_x.incl_len);
527 orig_size = pletoh32(&hdr.hdr_2_x.orig_len);
528 packet_size = pletoh32(&hdr.hdr_2_x.incl_len);
531 if (packet_size > WTAP_MAX_PACKET_SIZE) {
533 * Probably a corrupt capture file; don't blow up trying
534 * to allocate space for an immensely-large packet.
536 *err = WTAP_ERR_BAD_FILE;
537 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
538 packet_size, WTAP_MAX_PACKET_SIZE);
543 * If this is an ATM packet, the first
544 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
545 * source addresses (6 bytes - MAC addresses of some sort?)
546 * and the VPI and VCI; read them and generate the pseudo-header
549 switch (wfth->file_encap) {
551 case WTAP_ENCAP_ATM_PDUS:
552 if (packet_size < sizeof (struct netmon_atm_hdr)) {
554 * Uh-oh, the packet isn't big enough to even
555 * have a pseudo-header.
557 *err = WTAP_ERR_BAD_FILE;
558 *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
562 if (!netmon_read_atm_pseudoheader(fh, &phdr->pseudo_header,
564 return FALSE; /* Read error */
567 * Don't count the pseudo-header as part of the packet.
569 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
570 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
577 switch (netmon->version_major) {
581 * According to Paul Long, this offset is unsigned.
582 * It's 32 bits, so the maximum value will fit in
583 * a gint64 such as delta, even after multiplying
586 * pletoh32() returns a guint32; we cast it to gint64
587 * before multiplying, so that the product doesn't
588 * overflow a guint32.
590 delta = ((gint64)pletoh32(&hdr.hdr_1_x.ts_delta))*1000000;
595 * OK, this is weird. Microsoft's documentation
596 * says this is in microseconds and is a 64-bit
597 * unsigned number, but it can be negative; they
598 * say what appears to amount to "treat it as an
599 * unsigned number, multiply it by 10, and then
600 * interpret the resulting 64-bit quantity as a
601 * signed number". That operation can turn a
602 * value with the uppermost bit 0 to a value with
603 * the uppermost bit 1, hence turning a large
604 * positive number-of-microseconds into a small
605 * negative number-of-100-nanosecond-increments.
607 delta = pletoh64(&hdr.hdr_2_x.ts_delta)*10;
610 * OK, it's now a signed value in 100-nanosecond
611 * units. Now convert it to nanosecond units.
617 t = netmon->start_nsecs + delta;
620 * Propagate a borrow into the seconds.
621 * The seconds is a time_t, and can be < 0
622 * (unlikely, as Windows didn't exist before
623 * January 1, 1970, 00:00:00 UTC), while the
624 * nanoseconds should be positive, as in
625 * "nanoseconds since the instant of time
626 * represented by the seconds".
628 * We do not want t to be negative, as, according
629 * to the C90 standard, "if either operand [of /
630 * or %] is negative, whether the result of the
631 * / operator is the largest integer less than or
632 * equal to the algebraic quotient or the smallest
633 * greater than or equal to the algebraic quotient
634 * is implementation-defined, as is the sign of
635 * the result of the % operator", and we want
636 * the result of the division and remainder
637 * operations to be the same on all platforms.
642 secs += (time_t)(t/1000000000);
643 nsecs = (guint32)(t%1000000000);
644 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
645 phdr->ts.secs = netmon->start_secs + secs;
646 phdr->ts.nsecs = nsecs;
647 phdr->caplen = packet_size;
648 phdr->len = orig_size;
657 } process_trailer_retval;
659 static process_trailer_retval netmon_process_rec_trailer(netmon_t *netmon,
660 FILE_T fh, struct wtap_pkthdr *phdr, int *err, gchar **err_info)
664 trlr_size = (int)netmon_trailer_size(netmon);
665 if (trlr_size != 0) {
669 phdr->pkt_encap = netmon_read_rec_trailer(fh,
670 trlr_size, err, err_info);
671 if (phdr->pkt_encap == -1)
672 return FAILURE; /* error */
673 if (phdr->pkt_encap == 0)
680 /* Read the next packet */
681 static gboolean netmon_read(wftap *wfth, int *err, gchar **err_info,
684 netmon_t *netmon = (netmon_t *)wfth->priv;
685 wtap* wth = (wtap*)wfth->tap_specific_data;
689 /* Have we reached the end of the packet data? */
690 if (netmon->current_frame >= netmon->frame_table_size) {
691 /* Yes. We won't need the frame table any more;
693 g_free(netmon->frame_table);
694 netmon->frame_table = NULL;
695 *err = 0; /* it's just an EOF, not an error */
699 /* Seek to the beginning of the current record, if we're
700 not there already (seeking to the current position
701 may still cause a seek and a read of the underlying file,
702 so we don't want to do it unconditionally).
704 Yes, the current record could be before the previous
705 record. At least some captures put the trailer record
706 with statistics as the first physical record in the
707 file, but set the frame table up so it's the last
708 record in sequence. */
709 rec_offset = netmon->frame_table[netmon->current_frame];
710 if (file_tell(wfth->fh) != rec_offset) {
711 if (file_seek(wfth->fh, rec_offset, SEEK_SET, err) == -1)
714 netmon->current_frame++;
716 *data_offset = file_tell(wfth->fh);
718 if (!netmon_process_rec_header(wfth, wfth->fh, &wth->phdr,
722 if (!wtap_read_packet_bytes(wfth->fh, wfth->frame_buffer,
723 wth->phdr.caplen, err, err_info))
724 return FALSE; /* Read error */
727 * For version 2.1 and later, there's additional information
728 * after the frame data.
730 switch (netmon_process_rec_trailer(netmon, wfth->fh, &wth->phdr,
743 netmon_set_pseudo_header_info(wth->phdr.pkt_encap, &wth->phdr,
749 netmon_seek_read(wftap *wfth, gint64 seek_off,
750 void* header, Buffer *buf, int *err, gchar **err_info)
752 struct wtap_pkthdr *phdr = (struct wtap_pkthdr *)header;
753 netmon_t *netmon = (netmon_t *)wfth->priv;
755 if (file_seek(wfth->random_fh, seek_off, SEEK_SET, err) == -1)
758 if (!netmon_process_rec_header(wfth, wfth->random_fh, phdr,
763 * Read the packet data.
765 if (!wtap_read_packet_bytes(wfth->random_fh, buf, phdr->caplen, err,
770 * For version 2.1 and later, there's additional information
771 * after the frame data.
773 switch (netmon_process_rec_trailer(netmon, wfth->random_fh, phdr,
778 * This should not happen.
780 *err = WTAP_ERR_BAD_FILE;
781 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
791 netmon_set_pseudo_header_info(phdr->pkt_encap, phdr, buf);
797 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
798 int *err, gchar **err_info)
800 struct netmon_atm_hdr atm_phdr;
804 errno = WTAP_ERR_CANT_READ;
805 bytes_read = file_read(&atm_phdr, sizeof (struct netmon_atm_hdr), fh);
806 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
807 *err = file_error(fh, err_info);
809 *err = WTAP_ERR_SHORT_READ;
813 vpi = g_ntohs(atm_phdr.vpi);
814 vci = g_ntohs(atm_phdr.vci);
816 pseudo_header->atm.vpi = vpi;
817 pseudo_header->atm.vci = vci;
819 /* We don't have this information */
820 pseudo_header->atm.flags = 0;
821 pseudo_header->atm.channel = 0;
822 pseudo_header->atm.cells = 0;
823 pseudo_header->atm.aal5t_u2u = 0;
824 pseudo_header->atm.aal5t_len = 0;
825 pseudo_header->atm.aal5t_chksum = 0;
831 * Read a record trailer.
832 * On success, returns the packet encapsulation type.
833 * On error, returns -1 (which is WTAP_ENCAP_PER_PACKET, but we'd
834 * never return that on success).
835 * For metadata packets, returns 0 (which is WTAP_ENCAP_UNKNOWN, but
836 * we'd never return that on success).
839 netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err, gchar **err_info)
843 struct netmonrec_2_1_trlr trlr_2_1;
844 struct netmonrec_2_2_trlr trlr_2_2;
845 struct netmonrec_2_3_trlr trlr_2_3;
850 errno = WTAP_ERR_CANT_READ;
851 bytes_read = file_read(&trlr, trlr_size, fh);
852 if (bytes_read != trlr_size) {
853 *err = file_error(fh, err_info);
854 if (*err == 0 && bytes_read != 0) {
855 *err = WTAP_ERR_SHORT_READ;
857 return -1; /* error */
860 network = pletoh16(trlr.trlr_2_1.network);
861 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
863 * Converted pcap file - the LINKTYPE_ value
864 * is the network value with 0xF000 masked off.
867 pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
868 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
869 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
870 *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
872 return -1; /* error */
874 } else if (network < NUM_NETMON_ENCAPS) {
876 * Regular NetMon encapsulation.
878 pkt_encap = netmon_encap[network];
879 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
880 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
881 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
883 return -1; /* error */
887 * Special packet type for metadata.
891 case NETMON_NET_NETEVENT:
892 case NETMON_NET_NETWORK_INFO_EX:
893 case NETMON_NET_PAYLOAD_HEADER:
894 case NETMON_NET_NETWORK_INFO:
895 case NETMON_NET_DNS_CACHE:
896 case NETMON_NET_NETMON_FILTER:
898 * Just ignore those record types, for
899 * now. Tell our caller to read the next
905 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
906 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
908 return -1; /* error */
912 return pkt_encap; /* success */
915 /* Throw away the frame table used by the sequential I/O stream. */
917 netmon_sequential_close(wftap *wfth)
919 netmon_t *netmon = (netmon_t *)wfth->priv;
921 if (netmon->frame_table != NULL) {
922 g_free(netmon->frame_table);
923 netmon->frame_table = NULL;
928 gboolean got_first_record_time;
929 nstime_t first_record_time;
930 guint32 frame_table_offset;
931 guint32 *frame_table;
932 guint frame_table_index;
933 guint frame_table_size;
934 gboolean no_more_room; /* TRUE if no more records can be written */
937 static const int wtap_encap[] = {
938 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
939 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
940 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
941 -1, /* WTAP_ENCAP_SLIP -> unsupported */
942 -1, /* WTAP_ENCAP_PPP -> unsupported */
943 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
944 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
945 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
946 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
947 -1, /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
948 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
949 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
950 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
951 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
953 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
955 /* Returns 0 if we could write the specified encapsulation type,
956 an error indication otherwise. */
957 int netmon_dump_can_write_encap_1_x(int encap)
960 * Per-packet encapsulations are *not* supported in NetMon 1.x
963 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
964 return WTAP_ERR_UNSUPPORTED_ENCAP;
969 int netmon_dump_can_write_encap_2_x(int encap)
972 * Per-packet encapsulations are supported in NetMon 2.1
975 if (encap == WTAP_ENCAP_PER_PACKET)
978 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
979 return WTAP_ERR_UNSUPPORTED_ENCAP;
984 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
986 gboolean netmon_dump_open(wftap_dumper *wdh, int *err)
988 netmon_dump_t *netmon;
990 /* We can't fill in all the fields in the file header, as we
991 haven't yet written any packets. As we'll have to rewrite
992 the header when we've written out all the packets, we just
993 skip over the header for now. */
994 if (wftap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
997 wdh->subtype_write = netmon_dump;
998 wdh->subtype_close = netmon_dump_close;
1000 netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
1001 wdh->priv = (void *)netmon;
1002 netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
1003 netmon->got_first_record_time = FALSE;
1004 netmon->frame_table = NULL;
1005 netmon->frame_table_index = 0;
1006 netmon->frame_table_size = 0;
1007 netmon->no_more_room = FALSE;
1012 /* Write a record for a packet to a dump file.
1013 Returns TRUE on success, FALSE on failure. */
1014 static gboolean netmon_dump(wftap_dumper *wdh, const struct wtap_pkthdr *phdr,
1015 const guint8 *pd, int *err)
1017 const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
1018 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1019 struct netmonrec_1_x_hdr rec_1_x_hdr;
1020 struct netmonrec_2_x_hdr rec_2_x_hdr;
1023 struct netmonrec_2_1_trlr rec_2_x_trlr;
1025 struct netmon_atm_hdr atm_hdr;
1030 switch (wdh->file_type_subtype) {
1032 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1034 * The length fields are 16-bit, so there's a hard limit
1037 if (phdr->caplen > 65535) {
1038 *err = WTAP_ERR_PACKET_TOO_LARGE;
1043 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1044 /* Don't write anything we're not willing to read. */
1045 if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
1046 *err = WTAP_ERR_PACKET_TOO_LARGE;
1052 /* We should never get here - our open routine
1053 should only get called for the types above. */
1054 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1058 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1060 * Is this network type supported?
1062 if (phdr->pkt_encap < 0 ||
1063 (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
1064 wtap_encap[phdr->pkt_encap] == -1) {
1068 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
1073 * Fill in the trailer with the network type.
1075 phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
1079 * Will the file offset of this frame fit in a 32-bit unsigned
1082 if (netmon->no_more_room) {
1084 * No, so the file is too big for NetMon format to
1092 * NetMon files have a capture start time in the file header,
1093 * and have times relative to that in the packet headers;
1094 * pick the time of the first packet as the capture start
1097 * That time has millisecond resolution, so chop any
1098 * sub-millisecond part of the time stamp off.
1100 if (!netmon->got_first_record_time) {
1101 netmon->first_record_time.secs = phdr->ts.secs;
1102 netmon->first_record_time.nsecs =
1103 (phdr->ts.nsecs/1000000)*1000000;
1104 netmon->got_first_record_time = TRUE;
1107 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
1108 atm_hdrsize = sizeof (struct netmon_atm_hdr);
1111 secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
1112 nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
1115 * Propagate a borrow into the seconds.
1116 * The seconds is a time_t, and can be < 0
1117 * (unlikely, as neither UN*X nor DOS
1118 * nor the original Mac System existed
1119 * before January 1, 1970, 00:00:00 UTC),
1120 * while the nanoseconds should be positive,
1121 * as in "nanoseconds since the instant of time
1122 * represented by the seconds".
1124 * We do not want t to be negative, as, according
1125 * to the C90 standard, "if either operand [of /
1126 * or %] is negative, whether the result of the
1127 * / operator is the largest integer less than or
1128 * equal to the algebraic quotient or the smallest
1129 * greater than or equal to the algebraic quotient
1130 * is implementation-defined, as is the sign of
1131 * the result of the % operator", and we want
1132 * the result of the division and remainder
1133 * operations to be the same on all platforms.
1135 nsecs += 1000000000;
1138 switch (wdh->file_type_subtype) {
1140 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1141 rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
1142 rec_1_x_hdr.orig_len = GUINT16_TO_LE(phdr->len + atm_hdrsize);
1143 rec_1_x_hdr.incl_len = GUINT16_TO_LE(phdr->caplen + atm_hdrsize);
1144 hdrp = &rec_1_x_hdr;
1145 hdr_size = sizeof rec_1_x_hdr;
1148 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1149 rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
1150 rec_2_x_hdr.orig_len = GUINT32_TO_LE(phdr->len + atm_hdrsize);
1151 rec_2_x_hdr.incl_len = GUINT32_TO_LE(phdr->caplen + atm_hdrsize);
1152 hdrp = &rec_2_x_hdr;
1153 hdr_size = sizeof rec_2_x_hdr;
1157 /* We should never get here - our open routine
1158 should only get called for the types above. */
1159 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1164 * Keep track of the record size, as we need to update
1165 * the current file offset.
1169 if (!wftap_dump_file_write(wdh, hdrp, hdr_size, err))
1171 rec_size += hdr_size;
1173 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
1175 * Write the ATM header.
1176 * We supply all-zero destination and source addresses.
1178 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1179 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1180 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1181 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1182 if (!wftap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1184 rec_size += sizeof atm_hdr;
1187 if (!wftap_dump_file_write(wdh, pd, phdr->caplen, err))
1189 rec_size += phdr->caplen;
1191 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1193 * Write out the trailer.
1195 if (!wftap_dump_file_write(wdh, &rec_2_x_trlr,
1196 sizeof rec_2_x_trlr, err))
1198 rec_size += sizeof rec_2_x_trlr;
1202 * Stash the file offset of this frame.
1204 if (netmon->frame_table_size == 0) {
1206 * Haven't yet allocated the buffer for the frame table.
1208 netmon->frame_table = (guint32 *)g_malloc(1024 * sizeof *netmon->frame_table);
1209 netmon->frame_table_size = 1024;
1212 * We've allocated it; are we at the end?
1214 if (netmon->frame_table_index >= netmon->frame_table_size) {
1216 * Yes - double the size of the frame table.
1218 netmon->frame_table_size *= 2;
1219 netmon->frame_table = (guint32 *)g_realloc(netmon->frame_table,
1220 netmon->frame_table_size * sizeof *netmon->frame_table);
1224 netmon->frame_table[netmon->frame_table_index] =
1225 GUINT32_TO_LE(netmon->frame_table_offset);
1228 * Is this the last record we can write?
1229 * I.e., will the frame table offset of the next record not fit
1230 * in a 32-bit frame table offset entry?
1232 * (We don't bother checking whether the number of frames
1233 * will fit in a 32-bit value, as, even if each record were
1234 * 1 byte, if there were more than 2^32-1 packets, the frame
1235 * table offset of at least one of those packets will be >
1238 * Note: this also catches the unlikely possibility that
1239 * the record itself is > 2^32 - 1 bytes long.
1241 if ((guint64)netmon->frame_table_offset + rec_size > G_MAXUINT32) {
1245 netmon->no_more_room = TRUE;
1247 netmon->frame_table_index++;
1248 netmon->frame_table_offset += (guint32) rec_size;
1253 /* Finish writing to a dump file.
1254 Returns TRUE on success, FALSE on failure. */
1255 static gboolean netmon_dump_close(wftap_dumper *wdh, int *err)
1257 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1259 struct netmon_hdr file_hdr;
1264 /* Write out the frame table. "netmon->frame_table_index" is
1265 the number of entries we've put into it. */
1266 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1267 if (!wftap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1270 /* Now go fix up the file header. */
1271 if (wftap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1273 memset(&file_hdr, '\0', sizeof file_hdr);
1274 switch (wdh->file_type_subtype) {
1276 case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1277 magicp = netmon_1_x_magic;
1278 magic_size = sizeof netmon_1_x_magic;
1279 /* NetMon file version, for 1.x, is 1.1 */
1280 file_hdr.ver_major = 1;
1281 file_hdr.ver_minor = 1;
1284 case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1285 magicp = netmon_2_x_magic;
1286 magic_size = sizeof netmon_2_x_magic;
1288 * NetMon file version, for 2.x, is 2.0;
1289 * for 3.0, it's 2.1.
1291 * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1292 * we need version 2.1.
1294 * XXX - version 2.3 supports UTC time stamps; when
1295 * should we use it? According to the file format
1296 * documentation, NetMon 3.3 "cannot properly
1297 * interpret" the UTC timestamp information; does
1298 * that mean it ignores it and uses the local-time
1299 * start time and time deltas, or mishandles them?
1300 * Also, NetMon 3.1 and earlier can't read version
1301 * 2.2, much less version 2.3.
1303 file_hdr.ver_major = 2;
1304 file_hdr.ver_minor =
1305 (wdh->encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1309 /* We should never get here - our open routine
1310 should only get called for the types above. */
1312 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1315 if (!wftap_dump_file_write(wdh, magicp, magic_size, err))
1318 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1320 * We're writing NetMon 2.1 format, so the media
1321 * type in the file header is irrelevant. Set it
1322 * to 1, just as Network Monitor does.
1324 file_hdr.network = GUINT16_TO_LE(1);
1326 file_hdr.network = GUINT16_TO_LE(wtap_encap[wdh->encap]);
1327 tm = localtime(&netmon->first_record_time.secs);
1329 file_hdr.ts_year = GUINT16_TO_LE(1900 + tm->tm_year);
1330 file_hdr.ts_month = GUINT16_TO_LE(tm->tm_mon + 1);
1331 file_hdr.ts_dow = GUINT16_TO_LE(tm->tm_wday);
1332 file_hdr.ts_day = GUINT16_TO_LE(tm->tm_mday);
1333 file_hdr.ts_hour = GUINT16_TO_LE(tm->tm_hour);
1334 file_hdr.ts_min = GUINT16_TO_LE(tm->tm_min);
1335 file_hdr.ts_sec = GUINT16_TO_LE(tm->tm_sec);
1337 file_hdr.ts_year = GUINT16_TO_LE(1900 + 0);
1338 file_hdr.ts_month = GUINT16_TO_LE(0 + 1);
1339 file_hdr.ts_dow = GUINT16_TO_LE(0);
1340 file_hdr.ts_day = GUINT16_TO_LE(0);
1341 file_hdr.ts_hour = GUINT16_TO_LE(0);
1342 file_hdr.ts_min = GUINT16_TO_LE(0);
1343 file_hdr.ts_sec = GUINT16_TO_LE(0);
1345 file_hdr.ts_msec = GUINT16_TO_LE(netmon->first_record_time.nsecs/1000000);
1346 file_hdr.frametableoffset = GUINT32_TO_LE(netmon->frame_table_offset);
1347 file_hdr.frametablelength =
1348 GUINT32_TO_LE(netmon->frame_table_index * sizeof *netmon->frame_table);
1349 if (!wftap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))