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