Modify the comments to show how much of a mess the different DLT_ values
[obnox/wireshark/wip.git] / wiretap / libpcap.c
1 /* libpcap.c
2  *
3  * $Id: libpcap.c,v 1.14 1999/08/22 19:08:40 guy 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 <stdlib.h>
27 #include <errno.h>
28 #include "wtap.h"
29 #include "buffer.h"
30 #include "libpcap.h"
31
32 /* See source to the "libpcap" library for information on the "libpcap"
33    file format. */
34
35 /* Magic numbers in "libpcap" files.
36
37    "libpcap" file records are written in the byte order of the host that
38    writes them, and the reader is expected to fix this up.
39
40    PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC
41    is a byte-swapped version of that.  */
42 #define PCAP_MAGIC              0xa1b2c3d4
43 #define PCAP_SWAPPED_MAGIC      0xd4c3b2a1
44
45 /* Macros to byte-swap 32-bit and 16-bit quantities. */
46 #define BSWAP32(x) \
47         ((((x)&0xFF000000)>>24) | \
48          (((x)&0x00FF0000)>>8) | \
49          (((x)&0x0000FF00)<<8) | \
50          (((x)&0x000000FF)<<24))
51 #define BSWAP16(x) \
52          ((((x)&0xFF00)>>8) | \
53           (((x)&0x00FF)<<8))
54
55 /* "libpcap" file header (minus magic number). */
56 struct pcap_hdr {
57         guint16 version_major;  /* major version number */
58         guint16 version_minor;  /* minor version number */
59         gint32  thiszone;       /* GMT to local correction */
60         guint32 sigfigs;        /* accuracy of timestamps */
61         guint32 snaplen;        /* max length of captured packets, in octets */
62         guint32 network;        /* data link type */
63 };
64
65 /* "libpcap" record header. */
66 struct pcaprec_hdr {
67         guint32 ts_sec;         /* timestamp seconds */
68         guint32 ts_usec;        /* timestamp microseconds */
69         guint32 incl_len;       /* number of octets of packet saved in file */
70         guint32 orig_len;       /* actual length of packet */
71 };
72
73 static int libpcap_read(wtap *wth, int *err);
74 static int libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
75     const u_char *pd, int *err);
76 static int libpcap_dump_close(wtap_dumper *wdh, int *err);
77
78 /*
79  * XXX - this is a bit of a mess.  OpenBSD, and perhaps NetBSD, and
80  * BSD/OS have different DLT_ codes from FreeBSD (and from the LBL
81  * BPF code), and, at least in some cases, from each other.
82  * For now, we simply treat those type values with different
83  * meanings on different platforms, except for DLT_RAW, as "unknown";
84  * this means you won't be able to capture from a network using those
85  * types in Ethereal (and that capturing from the loopback interface
86  * won't necessarily work right on OpenBSD, either, as it uses
87  * DLT_LOOP, which is the same as DLT_RAW on other platforms).
88  *
89  * Does anybody know what BSD/OS uses as DLT_ types for SLIP and
90  * PPP?  The LBL code, and the OpenBSD code, appear to disagree....
91  *
92  * Nothing in FreeBSD appears to use DLT_RAW, so it's not clear what
93  * link-layer header or fake header appears for DLT_RAW.  If it's
94  * completely unused, or if it behaves the same way OpenBSD DLT_LOOP
95  * behaves, i.e. it puts an address family in *network* byte order
96  * (as opposed to the *host* byte order that DLT_NULL uses on FreeBSD),
97  * then we should just make it WTAP_ENCAP_NULL, which we treat in
98  * such a fashion as to cause it to work with DLT_LOOP headers.
99  */
100 static const int pcap_encap[] = {
101         WTAP_ENCAP_NULL,        /* null encapsulation */
102         WTAP_ENCAP_ETHERNET,
103         WTAP_ENCAP_UNKNOWN,     /* 3Mb experimental Ethernet */
104         WTAP_ENCAP_UNKNOWN,     /* Amateur Radio AX.25 */
105         WTAP_ENCAP_UNKNOWN,     /* Proteon ProNET Token Ring */
106         WTAP_ENCAP_UNKNOWN,     /* Chaos */
107         WTAP_ENCAP_TR,          /* IEEE 802 Networks - assume token ring */
108         WTAP_ENCAP_ARCNET,
109         WTAP_ENCAP_SLIP,
110         WTAP_ENCAP_PPP,
111         WTAP_ENCAP_FDDI,
112         WTAP_ENCAP_ATM_RFC1483, /* or, on BSD/OS, Frame Relay */
113         WTAP_ENCAP_RAW_IP,      /* or, on OpenBSD, DLT_LOOP, and on BSD/OS,
114                                    Cisco HDLC */
115         WTAP_ENCAP_UNKNOWN,     /* In LBL BPF and FreeBSD, BSD/OS SLIP;
116                                    on OpenBSD, DLT_ENC; on BSD/OS,
117                                    DLT_ATM_RFC1483 */
118         WTAP_ENCAP_UNKNOWN,     /* In LBL BPF and FreeBSD, BSD/OS PPP;
119                                    on OpenBSD and BSD/OS, DLT_RAW */
120         WTAP_ENCAP_UNKNOWN,     /* In OpenBSD and BSD/OS, BSD/OS SLIP,
121                                    but the BSD/OS header says "internal
122                                    to libpcap", whatever that means */
123         WTAP_ENCAP_UNKNOWN,     /* In OpenBSD and BSD/OS, BSD/OS PPP,
124                                    but the BSD/OS header says "internal
125                                    to libpcap", whatever that means */
126         WTAP_ENCAP_UNKNOWN,
127         WTAP_ENCAP_UNKNOWN,
128         WTAP_ENCAP_LINUX_ATM_CLIP
129 };
130 #define NUM_PCAP_ENCAPS (sizeof pcap_encap / sizeof pcap_encap[0])
131
132 int libpcap_open(wtap *wth, int *err)
133 {
134         int bytes_read;
135         guint32 magic;
136         struct pcap_hdr hdr;
137         int byte_swapped = 0;
138
139         /* Read in the number that should be at the start of a "libpcap" file */
140         fseek(wth->fh, 0, SEEK_SET);
141         errno = WTAP_ERR_CANT_READ;
142         bytes_read = fread(&magic, 1, sizeof magic, wth->fh);
143         if (bytes_read != sizeof magic) {
144                 if (ferror(wth->fh)) {
145                         *err = errno;
146                         return -1;
147                 }
148                 return 0;
149         }
150
151         if (magic == PCAP_SWAPPED_MAGIC) {
152                 /* Host that wrote it has a byte order opposite to ours. */
153                 magic = PCAP_MAGIC;
154                 byte_swapped = 1;
155         }
156         if (magic != PCAP_MAGIC) {
157                 return 0;
158         }
159
160         /* Read the rest of the header. */
161         errno = WTAP_ERR_CANT_READ;
162         bytes_read = fread(&hdr, 1, sizeof hdr, wth->fh);
163         if (bytes_read != sizeof hdr) {
164                 if (ferror(wth->fh)) {
165                         *err = errno;
166                         return -1;
167                 }
168                 return 0;
169         }
170
171         if (byte_swapped) {
172                 /* Byte-swap the header fields about which we care. */
173                 hdr.version_major = BSWAP16(hdr.version_major);
174                 hdr.version_minor = BSWAP16(hdr.version_minor);
175                 hdr.snaplen = BSWAP32(hdr.snaplen);
176                 hdr.network = BSWAP32(hdr.network);
177         }
178         if (hdr.version_major < 2) {
179                 /* We only support version 2.0 and later. */
180                 g_message("pcap: major version %u unsupported",
181                     hdr.version_major);
182                 *err = WTAP_ERR_UNSUPPORTED;
183                 return -1;
184         }
185         if (hdr.network >= NUM_PCAP_ENCAPS
186             || pcap_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
187                 g_message("pcap: network type %u unknown or unsupported",
188                     hdr.network);
189                 *err = WTAP_ERR_UNSUPPORTED;
190                 return -1;
191         }
192
193         /* This is a libpcap file */
194         wth->file_type = WTAP_FILE_PCAP;
195         wth->capture.pcap = g_malloc(sizeof(libpcap_t));
196         wth->capture.pcap->byte_swapped = byte_swapped;
197         wth->capture.pcap->version_major = hdr.version_major;
198         wth->capture.pcap->version_minor = hdr.version_minor;
199         wth->subtype_read = libpcap_read;
200         wth->file_encap = pcap_encap[hdr.network];
201         wth->snapshot_length = hdr.snaplen;
202         return 1;
203 }
204
205 /* Read the next packet */
206 static int libpcap_read(wtap *wth, int *err)
207 {
208         guint   packet_size;
209         int     bytes_read;
210         struct pcaprec_hdr hdr;
211         int     data_offset;
212
213         /* Read record header. */
214         errno = WTAP_ERR_CANT_READ;
215         bytes_read = fread(&hdr, 1, sizeof hdr, wth->fh);
216         if (bytes_read != sizeof hdr) {
217                 if (ferror(wth->fh)) {
218                         *err = errno;
219                         return -1;
220                 }
221                 if (bytes_read != 0) {
222                         *err = WTAP_ERR_SHORT_READ;
223                         return -1;
224                 }
225                 return 0;
226         }
227
228         if (wth->capture.pcap->byte_swapped) {
229                 /* Byte-swap the record header fields. */
230                 hdr.ts_sec = BSWAP32(hdr.ts_sec);
231                 hdr.ts_usec = BSWAP32(hdr.ts_usec);
232                 hdr.incl_len = BSWAP32(hdr.incl_len);
233                 hdr.orig_len = BSWAP32(hdr.orig_len);
234         }
235
236         /* In file format version 2.3, the "incl_len" and "orig_len" fields
237            were swapped, in order to match the BPF header layout.
238
239            Unfortunately, some files were, according to a comment in the
240            "libpcap" source, written with version 2.3 in their headers
241            but without the interchanged fields, so if "incl_len" is
242            greater than "orig_len" - which would make no sense - we
243            assume that we need to swap them.  */
244         if (wth->capture.pcap->version_major == 2 &&
245             (wth->capture.pcap->version_minor < 3 ||
246              (wth->capture.pcap->version_minor == 3 &&
247               hdr.incl_len > hdr.orig_len))) {
248                 guint32 temp;
249
250                 temp = hdr.orig_len;
251                 hdr.orig_len = hdr.incl_len;
252                 hdr.incl_len = temp;
253         }
254
255         packet_size = hdr.incl_len;
256         if (packet_size > WTAP_MAX_PACKET_SIZE) {
257                 /*
258                  * Probably a corrupt capture file; don't blow up trying
259                  * to allocate space for an immensely-large packet.
260                  */
261                 g_message("pcap: File has %u-byte packet, bigger than maximum of %u",
262                     packet_size, WTAP_MAX_PACKET_SIZE);
263                 *err = WTAP_ERR_BAD_RECORD;
264                 return -1;
265         }
266
267         buffer_assure_space(wth->frame_buffer, packet_size);
268         data_offset = ftell(wth->fh);
269         errno = WTAP_ERR_CANT_READ;
270         bytes_read = fread(buffer_start_ptr(wth->frame_buffer), 1,
271                         packet_size, wth->fh);
272
273         if (bytes_read != packet_size) {
274                 if (ferror(wth->fh))
275                         *err = errno;
276                 else
277                         *err = WTAP_ERR_SHORT_READ;
278                 return -1;
279         }
280
281         wth->phdr.ts.tv_sec = hdr.ts_sec;
282         wth->phdr.ts.tv_usec = hdr.ts_usec;
283         wth->phdr.caplen = packet_size;
284         wth->phdr.len = hdr.orig_len;
285         wth->phdr.pkt_encap = wth->file_encap;
286
287         return data_offset;
288 }
289
290 int wtap_pcap_encap_to_wtap_encap(int encap)
291 {
292         if (encap < 0 || encap >= NUM_PCAP_ENCAPS)
293                 return WTAP_ENCAP_UNKNOWN;
294         return pcap_encap[encap];
295 }
296
297 /* Returns 1 on success, 0 on failure; sets "*err" to an error code on
298    failure */
299 int libpcap_dump_open(wtap_dumper *wdh, int *err)
300 {
301         static const guint32 pcap_magic = PCAP_MAGIC;
302         struct pcap_hdr file_hdr;
303         static const int wtap_encap[] = {
304                 -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
305                 1,              /* WTAP_ENCAP_ETHERNET -> DLT_EN10MB */
306                 6,              /* WTAP_ENCAP_TR -> DLT_IEEE802 */
307                 8,              /* WTAP_ENCAP_SLIP -> DLT_SLIP */
308                 9,              /* WTAP_ENCAP_PPP -> DLT_PPP */
309                 10,             /* WTAP_ENCAP_FDDI -> DLT_FDDI */
310                 12,             /* WTAP_ENCAP_RAW_IP -> DLT_RAW */
311                 7,              /* WTAP_ENCAP_ARCNET -> DLT_ARCNET */
312                 11,             /* WTAP_ENCAP_ATM_RFC1483 -> DLT_ATM_RFC1483 */
313                 19,             /* WTAP_ENCAP_LINUX_ATM_CLIP */
314                 -1,             /* WTAP_ENCAP_LAPB -> unsupported*/
315                 -1,             /* WTAP_ENCAP_ATM_SNIFFER -> unsupported */
316                 0               /* WTAP_ENCAP_NULL -> DLT_NULL */
317         };
318         #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
319         int nwritten;
320
321         /* Per-packet encapsulations aren't supported. */
322         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
323                 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
324                 return 0;
325         }
326
327         if (wdh->encap < 0 || wdh->encap >= NUM_WTAP_ENCAPS
328             || wtap_encap[wdh->encap] == -1) {
329                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
330                 return 0;
331         }
332
333         /* This is a libpcap file */
334         wdh->subtype_write = libpcap_dump;
335         wdh->subtype_close = libpcap_dump_close;
336
337         /* Write the file header. */
338         nwritten = fwrite(&pcap_magic, 1, sizeof pcap_magic, wdh->fh);
339         if (nwritten != sizeof pcap_magic) {
340                 if (nwritten < 0)
341                         *err = errno;
342                 else
343                         *err = WTAP_ERR_SHORT_WRITE;
344                 return 0;
345         }
346
347         /* current "libpcap" format is 2.4 */
348         file_hdr.version_major = 2;
349         file_hdr.version_minor = 4;
350         file_hdr.thiszone = 0;  /* XXX - current offset? */
351         file_hdr.sigfigs = 0;   /* unknown, but also apparently unused */
352         file_hdr.snaplen = wdh->snaplen;
353         file_hdr.network = wtap_encap[wdh->encap];
354         nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
355         if (nwritten != sizeof file_hdr) {
356                 if (nwritten < 0)
357                         *err = errno;
358                 else
359                         *err = WTAP_ERR_SHORT_WRITE;
360                 return 0;
361         }
362
363         return 1;
364 }
365
366 /* Write a record for a packet to a dump file.
367    Returns 1 on success, 0 on failure. */
368 static int libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
369     const u_char *pd, int *err)
370 {
371         struct pcaprec_hdr rec_hdr;
372         int nwritten;
373
374         rec_hdr.ts_sec = phdr->ts.tv_sec;
375         rec_hdr.ts_usec = phdr->ts.tv_usec;
376         rec_hdr.incl_len = phdr->caplen;
377         rec_hdr.orig_len = phdr->len;
378         nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, wdh->fh);
379         if (nwritten != sizeof rec_hdr) {
380                 if (nwritten < 0)
381                         *err = errno;
382                 else
383                         *err = WTAP_ERR_SHORT_WRITE;
384                 return 0;
385         }
386         nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
387         if (nwritten != phdr->caplen) {
388                 if (nwritten < 0)
389                         *err = errno;
390                 else
391                         *err = WTAP_ERR_SHORT_WRITE;
392                 return 0;
393         }
394         return 1;
395 }
396
397 /* Finish writing to a dump file.
398    Returns 1 on success, 0 on failure. */
399 static int libpcap_dump_close(wtap_dumper *wdh, int *err)
400 {
401         /* Nothing to do here. */
402         return 1;
403 }