This commit contains support for reading capture files compressed using
[obnox/wireshark/wip.git] / wiretap / snoop.c
1 /* snoop.c
2  *
3  * $Id: snoop.c,v 1.11 1999/09/22 01:26:49 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 "file.h"
28 #include "wtap.h"
29 #include "buffer.h"
30 #include "snoop.h"
31 #ifdef HAVE_NETINET_IN_H
32 #include <netinet/in.h>
33 #endif
34
35 /* See RFC 1761 for a description of the "snoop" file format. */
36
37 /* Magic number in "snoop" files. */
38 static const char snoop_magic[] = {
39         's', 'n', 'o', 'o', 'p', '\0', '\0', '\0'
40 };
41
42 /* "snoop" file header (minus magic number). */
43 struct snoop_hdr {
44         guint32 version;        /* version number (should be 2) */
45         guint32 network;        /* network type */
46 };
47
48 /* "snoop" record header. */
49 struct snooprec_hdr {
50         guint32 orig_len;       /* actual length of packet */
51         guint32 incl_len;       /* number of octets captured in file */
52         guint32 rec_len;        /* length of record */
53         guint32 cum_drops;      /* cumulative number of dropped packets */
54         guint32 ts_sec;         /* timestamp seconds */
55         guint32 ts_usec;        /* timestamp microseconds */
56 };
57
58 static int snoop_read(wtap *wth, int *err);
59
60 int snoop_open(wtap *wth, int *err)
61 {
62         int bytes_read;
63         char magic[sizeof snoop_magic];
64         struct snoop_hdr hdr;
65         static const int snoop_encap[] = {
66                 WTAP_ENCAP_UNKNOWN,     /* IEEE 802.3 */
67                 WTAP_ENCAP_UNKNOWN,     /* IEEE 802.4 Token Bus */
68                 WTAP_ENCAP_TR,
69                 WTAP_ENCAP_UNKNOWN,     /* IEEE 802.6 Metro Net */
70                 WTAP_ENCAP_ETHERNET,
71                 WTAP_ENCAP_UNKNOWN,     /* HDLC */
72                 WTAP_ENCAP_UNKNOWN,     /* Character Synchronous */
73                 WTAP_ENCAP_UNKNOWN,     /* IBM Channel-to-Channel */
74                 WTAP_ENCAP_FDDI_BITSWAPPED,
75                 WTAP_ENCAP_UNKNOWN      /* Other */
76         };
77         #define NUM_SNOOP_ENCAPS (sizeof snoop_encap / sizeof snoop_encap[0])
78
79         /* Read in the string that should be at the start of a "snoop" file */
80         file_seek(wth->fh, 0, SEEK_SET);
81         wth->data_offset = 0;
82         errno = WTAP_ERR_CANT_READ;
83         bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
84         if (bytes_read != sizeof magic) {
85                 if (file_error(wth->fh)) {
86                         *err = errno;
87                         return -1;
88                 }
89                 return 0;
90         }
91         wth->data_offset += sizeof magic;
92
93         if (memcmp(magic, snoop_magic, sizeof snoop_magic) != 0) {
94                 return 0;
95         }
96
97         /* Read the rest of the header. */
98         errno = WTAP_ERR_CANT_READ;
99         bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
100         if (bytes_read != sizeof hdr) {
101                 if (file_error(wth->fh)) {
102                         *err = errno;
103                         return -1;
104                 }
105                 return 0;
106         }
107         wth->data_offset += sizeof hdr;
108
109         hdr.version = ntohl(hdr.version);
110         if (hdr.version != 2) {
111                 /* We only support version 2. */
112                 g_message("snoop: version %u unsupported", hdr.version);
113                 *err = WTAP_ERR_UNSUPPORTED;
114                 return -1;
115         }
116         hdr.network = ntohl(hdr.network);
117         if (hdr.network >= NUM_SNOOP_ENCAPS
118             || snoop_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
119                 g_message("snoop: network type %u unknown or unsupported",
120                     hdr.network);
121                 *err = WTAP_ERR_UNSUPPORTED;
122                 return -1;
123         }
124
125         /* This is a snoop file */
126         wth->file_type = WTAP_FILE_SNOOP;
127         wth->subtype_read = snoop_read;
128         wth->file_encap = snoop_encap[hdr.network];
129         wth->snapshot_length = 16384;   /* XXX - not available in header */
130         return 1;
131 }
132
133 /* Read the next packet */
134 static int snoop_read(wtap *wth, int *err)
135 {
136         guint32 packet_size;
137         int     bytes_read;
138         struct snooprec_hdr hdr;
139         int     data_offset;
140         char    padbuf[4];
141         int     padbytes;
142         int     bytes_to_read;
143
144         /* Read record header. */
145         errno = WTAP_ERR_CANT_READ;
146         bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
147         if (bytes_read != sizeof hdr) {
148                 if (file_error(wth->fh)) {
149                         *err = errno;
150                         return -1;
151                 }
152                 if (bytes_read != 0) {
153                         *err = WTAP_ERR_SHORT_READ;
154                         return -1;
155                 }
156                 return 0;
157         }
158         wth->data_offset += sizeof hdr;
159
160         packet_size = ntohl(hdr.incl_len);
161         if (packet_size > WTAP_MAX_PACKET_SIZE) {
162                 /*
163                  * Probably a corrupt capture file; don't blow up trying
164                  * to allocate space for an immensely-large packet.
165                  */
166                 g_message("snoop: File has %u-byte packet, bigger than maximum of %u",
167                     packet_size, WTAP_MAX_PACKET_SIZE);
168                 *err = WTAP_ERR_BAD_RECORD;
169                 return -1;
170         }
171         buffer_assure_space(wth->frame_buffer, packet_size);
172         data_offset = wth->data_offset;
173         errno = WTAP_ERR_CANT_READ;
174         bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
175                         packet_size, wth->fh);
176
177         if (bytes_read != packet_size) {
178                 if (file_error(wth->fh))
179                         *err = errno;
180                 else
181                         *err = WTAP_ERR_SHORT_READ;
182                 return -1;
183         }
184         wth->data_offset += packet_size;
185
186         wth->phdr.ts.tv_sec = ntohl(hdr.ts_sec);
187         wth->phdr.ts.tv_usec = ntohl(hdr.ts_usec);
188         wth->phdr.caplen = packet_size;
189         wth->phdr.len = ntohl(hdr.orig_len);
190         wth->phdr.pkt_encap = wth->file_encap;
191
192         /*
193          * Skip over the padding (don't "fseek()", as the standard
194          * I/O library on some platforms discards buffered data if
195          * you do that, which means it does a lot more reads).
196          * There's probably not much padding (it's probably padded only
197          * to a 4-byte boundary), so we probably need only do one read.
198          */
199         padbytes = ntohl(hdr.rec_len) - (sizeof hdr + packet_size);
200         while (padbytes != 0) {
201                 bytes_to_read = padbytes;
202                 if (bytes_to_read > sizeof padbuf)
203                         bytes_to_read = sizeof padbuf;
204                 errno = WTAP_ERR_CANT_READ;
205                 bytes_read = file_read(padbuf, 1, bytes_to_read, wth->fh);
206                 if (bytes_read != bytes_to_read) {
207                         if (file_error(wth->fh))
208                                 *err = errno;
209                         else
210                                 *err = WTAP_ERR_SHORT_READ;
211                         return -1;
212                 }
213                 wth->data_offset += bytes_read;
214                 padbytes -= bytes_read;
215         }
216
217         return data_offset;
218 }