This commit contains support for reading capture files compressed using
[obnox/wireshark/wip.git] / wiretap / netmon.c
1 /* netmon.c
2  *
3  * $Id: netmon.c,v 1.14 1999/09/22 01:26:47 ashokn Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@verdict.uthscsa.edu>
7  * 
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.
12  * 
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.
17  * 
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <errno.h>
27 #include <time.h>
28 #include "file.h"
29 #include "wtap.h"
30 #include "buffer.h"
31 #include "netmon.h"
32
33 /* The file at
34  *
35  *      ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
36  *
37  * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
38  * for the header of a Microsoft Network Monitor capture file.
39  */
40
41 /* Capture file header, *including* magic number, is padded to 128 bytes. */
42 #define CAPTUREFILE_HEADER_SIZE 128
43
44 /* Magic number in Network Monitor 1.x files. */
45 static const char netmon_1_x_magic[] = {
46         'R', 'T', 'S', 'S'
47 };
48
49 /* Magic number in Network Monitor 2.x files. */
50 static const char netmon_2_x_magic[] = {
51         'G', 'M', 'B', 'U'
52 };
53
54 /* Network Monitor file header (minus magic number). */
55 struct netmon_hdr {
56         guint8  ver_minor;      /* minor version number */
57         guint8  ver_major;      /* major version number */
58         guint16 network;        /* network type */
59         guint16 ts_year;        /* year of capture start */
60         guint16 ts_month;       /* month of capture start (January = 1) */
61         guint16 ts_dow;         /* day of week of capture start (Sun = 0) */
62         guint16 ts_day;         /* day of month of capture start */
63         guint16 ts_hour;        /* hour of capture start */
64         guint16 ts_min;         /* minute of capture start */
65         guint16 ts_sec;         /* second of capture start */
66         guint16 ts_msec;        /* millisecond of capture start */
67         guint32 frametableoffset;       /* frame index table offset */
68         guint32 frametablelength;       /* frame index table size */
69         guint32 userdataoffset;         /* user data offset */
70         guint32 userdatalength;         /* user data size */
71         guint32 commentdataoffset;      /* comment data offset */
72         guint32 commentdatalength;      /* comment data size */
73         guint32 statisticsoffset;       /* offset to statistics structure */
74         guint32 statisticslength;       /* length of statistics structure */
75         guint32 networkinfooffset;      /* offset to network info structure */
76         guint32 networkinfolength;      /* length of network info structure */
77 };
78
79 /* Network Monitor record header; not defined in STRUCT.H, but deduced by
80  * looking at capture files. */
81 struct netmonrec_1_x_hdr {
82         guint32 ts_delta;       /* time stamp - msecs since start of capture */
83         guint16 orig_len;       /* actual length of packet */
84         guint16 incl_len;       /* number of octets captured in file */
85 };
86
87 struct netmonrec_2_x_hdr {
88         guint32 ts_delta_lo;    /* time stamp - usecs since start of capture */
89         guint32 ts_delta_hi;    /* time stamp - usecs since start of capture */
90         guint32 orig_len;       /* actual length of packet */
91         guint32 incl_len;       /* number of octets captured in file */
92 };
93
94 static int netmon_read(wtap *wth, int *err);
95
96 int netmon_open(wtap *wth, int *err)
97 {
98         int bytes_read;
99         char magic[sizeof netmon_1_x_magic];
100         struct netmon_hdr hdr;
101         int file_type;
102         static const int netmon_encap[] = {
103                 WTAP_ENCAP_UNKNOWN,
104                 WTAP_ENCAP_ETHERNET,
105                 WTAP_ENCAP_TR,
106                 WTAP_ENCAP_FDDI_BITSWAPPED,
107                 WTAP_ENCAP_UNKNOWN,     /* WAN */
108                 WTAP_ENCAP_UNKNOWN,     /* LocalTalk */
109                 WTAP_ENCAP_UNKNOWN,     /* "DIX" - should not occur */
110                 WTAP_ENCAP_UNKNOWN,     /* ARCNET raw */
111                 WTAP_ENCAP_UNKNOWN,     /* ARCNET 878.2 */
112                 WTAP_ENCAP_UNKNOWN,     /* ATM */
113                 WTAP_ENCAP_UNKNOWN,     /* Wireless WAN */
114                 WTAP_ENCAP_UNKNOWN      /* IrDA */
115         };
116         #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
117         struct tm tm;
118
119         /* Read in the string that should be at the start of a Network
120          * Monitor file */
121         file_seek(wth->fh, 0, SEEK_SET);
122         errno = WTAP_ERR_CANT_READ;
123         bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
124         if (bytes_read != sizeof magic) {
125                 if (file_error(wth->fh)) {
126                         *err = errno;
127                         return -1;
128                 }
129                 return 0;
130         }
131
132         if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
133          && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
134                 return 0;
135         }
136
137         /* Read the rest of the header. */
138         errno = WTAP_ERR_CANT_READ;
139         bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
140         if (bytes_read != sizeof hdr) {
141                 if (file_error(wth->fh)) {
142                         *err = errno;
143                         return -1;
144                 }
145                 return 0;
146         }
147
148         switch (hdr.ver_major) {
149
150         case 1:
151                 file_type = WTAP_FILE_NETMON_1_x;
152                 break;
153
154         case 2:
155                 file_type = WTAP_FILE_NETMON_2_x;
156                 break;
157
158         default:
159                 g_message("netmon: major version %u unsupported", hdr.ver_major);
160                 *err = WTAP_ERR_UNSUPPORTED;
161                 return -1;
162         }
163
164         hdr.network = pletohs(&hdr.network);
165         if (hdr.network >= NUM_NETMON_ENCAPS
166             || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
167                 g_message("netmon: network type %u unknown or unsupported",
168                     hdr.network);
169                 *err = WTAP_ERR_UNSUPPORTED;
170                 return -1;
171         }
172
173         /* This is a netmon file */
174         wth->file_type = file_type;
175         wth->capture.netmon = g_malloc(sizeof(netmon_t));
176         wth->subtype_read = netmon_read;
177         wth->file_encap = netmon_encap[hdr.network];
178         wth->snapshot_length = 16384;   /* XXX - not available in header */
179         /*
180          * Convert the time stamp to a "time_t" and a number of
181          * milliseconds.
182          */
183         tm.tm_year = pletohs(&hdr.ts_year) - 1900;
184         tm.tm_mon = pletohs(&hdr.ts_month) - 1;
185         tm.tm_mday = pletohs(&hdr.ts_day);
186         tm.tm_hour = pletohs(&hdr.ts_hour);
187         tm.tm_min = pletohs(&hdr.ts_min);
188         tm.tm_sec = pletohs(&hdr.ts_sec);
189         tm.tm_isdst = -1;
190         wth->capture.netmon->start_secs = mktime(&tm);
191         /*
192          * XXX - what if "secs" is -1?  Unlikely, but if the capture was
193          * done in a time zone that switches between standard and summer
194          * time sometime other than when we do, and thus the time was one
195          * that doesn't exist here because a switch from standard to summer
196          * time zips over it, it could happen.
197          *
198          * On the other hand, if the capture was done in a different time
199          * zone, this won't work right anyway; unfortunately, the time
200          * zone isn't stored in the capture file (why the hell didn't
201          * they stuff a FILETIME, which is the number of 100-nanosecond
202          * intervals since 1601-01-01 00:00:00 "UTC", there, instead
203          * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
204          */
205         wth->capture.netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
206
207         wth->capture.netmon->version_major = hdr.ver_major;
208
209         /*
210          * The "frame index table" appears to come after the last
211          * packet; remember its offset, so we know when we have no
212          * more packets to read.
213          */
214         wth->capture.netmon->end_offset = pletohl(&hdr.frametableoffset);
215
216         /* Seek to the beginning of the data records. */
217         file_seek(wth->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET);
218         wth->data_offset = CAPTUREFILE_HEADER_SIZE;
219
220         return 1;
221 }
222
223 /* Read the next packet */
224 static int netmon_read(wtap *wth, int *err)
225 {
226         guint32 packet_size = 0;
227         int     bytes_read;
228         union {
229                 struct netmonrec_1_x_hdr hdr_1_x;
230                 struct netmonrec_2_x_hdr hdr_2_x;
231         }       hdr;
232         int     hdr_size = 0;
233         int     data_offset;
234         time_t  secs;
235         guint32 usecs;
236         double  t;
237
238         /* Have we reached the end of the packet data? */
239         if (wth->data_offset >= wth->capture.netmon->end_offset) {
240                 /* Yes. */
241                 return 0;
242         }
243         /* Read record header. */
244         switch (wth->capture.netmon->version_major) {
245
246         case 1:
247                 hdr_size = sizeof (struct netmonrec_1_x_hdr);
248                 break;
249
250         case 2:
251                 hdr_size = sizeof (struct netmonrec_2_x_hdr);
252                 break;
253         }
254         errno = WTAP_ERR_CANT_READ;
255         bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
256         if (bytes_read != hdr_size) {
257                 if (file_error(wth->fh)) {
258                         *err = errno;
259                         return -1;
260                 }
261                 if (bytes_read != 0) {
262                         *err = WTAP_ERR_SHORT_READ;
263                         return -1;
264                 }
265                 return 0;
266         }
267         wth->data_offset += hdr_size;
268
269         switch (wth->capture.netmon->version_major) {
270
271         case 1:
272                 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
273                 break;
274
275         case 2:
276                 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
277                 break;
278         }
279         if (packet_size > WTAP_MAX_PACKET_SIZE) {
280                 /*
281                  * Probably a corrupt capture file; don't blow up trying
282                  * to allocate space for an immensely-large packet.
283                  */
284                 g_message("netmon: File has %u-byte packet, bigger than maximum of %u",
285                     packet_size, WTAP_MAX_PACKET_SIZE);
286                 *err = WTAP_ERR_BAD_RECORD;
287                 return -1;
288         }
289         buffer_assure_space(wth->frame_buffer, packet_size);
290         data_offset = wth->data_offset;
291         errno = WTAP_ERR_CANT_READ;
292         bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
293                         packet_size, wth->fh);
294
295         if (bytes_read != packet_size) {
296                 if (file_error(wth->fh))
297                         *err = errno;
298                 else
299                         *err = WTAP_ERR_SHORT_READ;
300                 return -1;
301         }
302         wth->data_offset += packet_size;
303
304         t = (double)wth->capture.netmon->start_usecs;
305         switch (wth->capture.netmon->version_major) {
306
307         case 1:
308                 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
309                 break;
310
311         case 2:
312                 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
313                     + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
314                 break;
315         }
316         secs = (time_t)(t/1000000);
317         usecs = (guint32)(t - secs*1000000);
318         wth->phdr.ts.tv_sec = wth->capture.netmon->start_secs + secs;
319         wth->phdr.ts.tv_usec = usecs;
320         wth->phdr.caplen = packet_size;
321         switch (wth->capture.netmon->version_major) {
322
323         case 1:
324                 wth->phdr.len = pletohs(&hdr.hdr_1_x.orig_len);
325                 break;
326
327         case 2:
328                 wth->phdr.len = pletohl(&hdr.hdr_2_x.orig_len);
329                 break;
330         }
331         wth->phdr.pkt_encap = wth->file_encap;
332
333         return data_offset;
334 }