3 * $Id: libpcap.c,v 1.14 1999/08/22 19:08:40 guy Exp $
6 * Copyright (c) 1998 by Gilbert Ramirez <gram@verdict.uthscsa.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 /* See source to the "libpcap" library for information on the "libpcap"
35 /* Magic numbers in "libpcap" files.
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.
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
45 /* Macros to byte-swap 32-bit and 16-bit quantities. */
47 ((((x)&0xFF000000)>>24) | \
48 (((x)&0x00FF0000)>>8) | \
49 (((x)&0x0000FF00)<<8) | \
50 (((x)&0x000000FF)<<24))
52 ((((x)&0xFF00)>>8) | \
55 /* "libpcap" file header (minus magic number). */
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 */
65 /* "libpcap" record header. */
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 */
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);
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).
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....
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.
100 static const int pcap_encap[] = {
101 WTAP_ENCAP_NULL, /* null encapsulation */
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 */
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,
115 WTAP_ENCAP_UNKNOWN, /* In LBL BPF and FreeBSD, BSD/OS SLIP;
116 on OpenBSD, DLT_ENC; on BSD/OS,
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 */
128 WTAP_ENCAP_LINUX_ATM_CLIP
130 #define NUM_PCAP_ENCAPS (sizeof pcap_encap / sizeof pcap_encap[0])
132 int libpcap_open(wtap *wth, int *err)
137 int byte_swapped = 0;
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)) {
151 if (magic == PCAP_SWAPPED_MAGIC) {
152 /* Host that wrote it has a byte order opposite to ours. */
156 if (magic != PCAP_MAGIC) {
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)) {
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);
178 if (hdr.version_major < 2) {
179 /* We only support version 2.0 and later. */
180 g_message("pcap: major version %u unsupported",
182 *err = WTAP_ERR_UNSUPPORTED;
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",
189 *err = WTAP_ERR_UNSUPPORTED;
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;
205 /* Read the next packet */
206 static int libpcap_read(wtap *wth, int *err)
210 struct pcaprec_hdr hdr;
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)) {
221 if (bytes_read != 0) {
222 *err = WTAP_ERR_SHORT_READ;
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);
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.
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))) {
251 hdr.orig_len = hdr.incl_len;
255 packet_size = hdr.incl_len;
256 if (packet_size > WTAP_MAX_PACKET_SIZE) {
258 * Probably a corrupt capture file; don't blow up trying
259 * to allocate space for an immensely-large packet.
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;
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);
273 if (bytes_read != packet_size) {
277 *err = WTAP_ERR_SHORT_READ;
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;
290 int wtap_pcap_encap_to_wtap_encap(int encap)
292 if (encap < 0 || encap >= NUM_PCAP_ENCAPS)
293 return WTAP_ENCAP_UNKNOWN;
294 return pcap_encap[encap];
297 /* Returns 1 on success, 0 on failure; sets "*err" to an error code on
299 int libpcap_dump_open(wtap_dumper *wdh, int *err)
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 */
318 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
321 /* Per-packet encapsulations aren't supported. */
322 if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
323 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
327 if (wdh->encap < 0 || wdh->encap >= NUM_WTAP_ENCAPS
328 || wtap_encap[wdh->encap] == -1) {
329 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
333 /* This is a libpcap file */
334 wdh->subtype_write = libpcap_dump;
335 wdh->subtype_close = libpcap_dump_close;
337 /* Write the file header. */
338 nwritten = fwrite(&pcap_magic, 1, sizeof pcap_magic, wdh->fh);
339 if (nwritten != sizeof pcap_magic) {
343 *err = WTAP_ERR_SHORT_WRITE;
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) {
359 *err = WTAP_ERR_SHORT_WRITE;
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)
371 struct pcaprec_hdr rec_hdr;
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) {
383 *err = WTAP_ERR_SHORT_WRITE;
386 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
387 if (nwritten != phdr->caplen) {
391 *err = WTAP_ERR_SHORT_WRITE;
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)
401 /* Nothing to do here. */