savefile.c revision 235426
117683Spst/* 239291Sfenner * Copyright (c) 1993, 1994, 1995, 1996, 1997 317683Spst * The Regents of the University of California. All rights reserved. 417683Spst * 517683Spst * Redistribution and use in source and binary forms, with or without 617683Spst * modification, are permitted provided that: (1) source code distributions 717683Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817683Spst * distributions including binary code include the above copyright notice and 917683Spst * this paragraph in its entirety in the documentation or other materials 1017683Spst * provided with the distribution, and (3) all advertising materials mentioning 1117683Spst * features or use of this software display the following acknowledgement: 1217683Spst * ``This product includes software developed by the University of California, 1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417683Spst * the University nor the names of its contributors may be used to endorse 1517683Spst * or promote products derived from this software without specific prior 1617683Spst * written permission. 1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2026175Sfenner * 2117683Spst * savefile.c - supports offline use of tcpdump 2217683Spst * Extraction/creation by Jeffrey Mogul, DECWRL 2317683Spst * Modified by Steve McCanne, LBL. 2417683Spst * 2517683Spst * Used to save the received packet headers, after filtering, to 2617683Spst * a file, and then read them later. 2717683Spst * The first record in the file contains saved values for the machine 2817683Spst * dependent values so we can print the dump file on any architecture. 2917683Spst */ 3017683Spst 3126175Sfenner#ifndef lint 32127664Sbmsstatic const char rcsid[] _U_ = 33214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.183 2008-12-23 20:13:29 guy Exp $ (LBL)"; 3426175Sfenner#endif 3526175Sfenner 3675107Sfenner#ifdef HAVE_CONFIG_H 3775107Sfenner#include "config.h" 3875107Sfenner#endif 3975107Sfenner 40214518Srpaulo#ifdef WIN32 41214518Srpaulo#include <pcap-stdinc.h> 42214518Srpaulo#else /* WIN32 */ 43214518Srpaulo#if HAVE_INTTYPES_H 44214518Srpaulo#include <inttypes.h> 45214518Srpaulo#elif HAVE_STDINT_H 46214518Srpaulo#include <stdint.h> 47214518Srpaulo#endif 48214518Srpaulo#ifdef HAVE_SYS_BITYPES_H 49214518Srpaulo#include <sys/bitypes.h> 50214518Srpaulo#endif 51214518Srpaulo#include <sys/types.h> 52214518Srpaulo#endif /* WIN32 */ 53214518Srpaulo 5417683Spst#include <errno.h> 5517683Spst#include <memory.h> 5617683Spst#include <stdio.h> 5717683Spst#include <stdlib.h> 5875107Sfenner#include <string.h> 5917683Spst 6017683Spst#include "pcap-int.h" 61190225Srpaulo#include "pcap/usb.h" 6217683Spst 6317683Spst#ifdef HAVE_OS_PROTO_H 6417683Spst#include "os-proto.h" 6517683Spst#endif 6617683Spst 67214518Srpaulo#include "sf-pcap.h" 68214518Srpaulo#include "sf-pcap-ng.h" 6917683Spst 7017683Spst/* 71146768Ssam * Setting O_BINARY on DOS/Windows is a bit tricky 72146768Ssam */ 73146768Ssam#if defined(WIN32) 74147894Ssam #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) 75146768Ssam#elif defined(MSDOS) 76146768Ssam #if defined(__HIGHC__) 77146768Ssam #define SET_BINMODE(f) setmode(f, O_BINARY) 78146768Ssam #else 79146768Ssam #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) 80146768Ssam #endif 81146768Ssam#endif 82146768Ssam 8317683Spststatic int 84127664Sbmssf_getnonblock(pcap_t *p, char *errbuf) 85127664Sbms{ 86127664Sbms /* 87127664Sbms * This is a savefile, not a live capture file, so never say 88127664Sbms * it's in non-blocking mode. 89127664Sbms */ 90127664Sbms return (0); 91127664Sbms} 92127664Sbms 93127664Sbmsstatic int 94127664Sbmssf_setnonblock(pcap_t *p, int nonblock, char *errbuf) 95127664Sbms{ 96127664Sbms /* 97235426Sdelphij * This is a savefile, not a live capture file, so reject 98235426Sdelphij * requests to put it in non-blocking mode. (If it's a 99235426Sdelphij * pipe, it could be put in non-blocking mode, but that 100235426Sdelphij * would significantly complicate the code to read packets, 101235426Sdelphij * as it would have to handle reading partial packets and 102235426Sdelphij * keeping the state of the read.) 103127664Sbms */ 104235426Sdelphij snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 105235426Sdelphij "Savefiles cannot be put into non-blocking mode"); 106235426Sdelphij return (-1); 107127664Sbms} 108127664Sbms 109127664Sbmsstatic int 110127664Sbmssf_stats(pcap_t *p, struct pcap_stat *ps) 111127664Sbms{ 112127664Sbms snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 113127664Sbms "Statistics aren't available from savefiles"); 114127664Sbms return (-1); 115127664Sbms} 116127664Sbms 117190225Srpaulo#ifdef WIN32 118146768Ssamstatic int 119190225Srpaulosf_setbuff(pcap_t *p, int dim) 120190225Srpaulo{ 121190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 122190225Srpaulo "The kernel buffer size cannot be set while reading from a file"); 123190225Srpaulo return (-1); 124190225Srpaulo} 125190225Srpaulo 126190225Srpaulostatic int 127190225Srpaulosf_setmode(pcap_t *p, int mode) 128190225Srpaulo{ 129190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 130190225Srpaulo "impossible to set mode while reading from a file"); 131190225Srpaulo return (-1); 132190225Srpaulo} 133190225Srpaulo 134190225Srpaulostatic int 135190225Srpaulosf_setmintocopy(pcap_t *p, int size) 136190225Srpaulo{ 137190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 138190225Srpaulo "The mintocopy parameter cannot be set while reading from a file"); 139190225Srpaulo return (-1); 140190225Srpaulo} 141190225Srpaulo#endif 142190225Srpaulo 143190225Srpaulostatic int 144146768Ssamsf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 145146768Ssam{ 146146768Ssam strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", 147146768Ssam PCAP_ERRBUF_SIZE); 148146768Ssam return (-1); 149146768Ssam} 150146768Ssam 151147894Ssam/* 152147894Ssam * Set direction flag: Which packets do we accept on a forwarding 153147894Ssam * single device? IN, OUT or both? 154147894Ssam */ 155147894Ssamstatic int 156162012Ssamsf_setdirection(pcap_t *p, pcap_direction_t d) 157147894Ssam{ 158147894Ssam snprintf(p->errbuf, sizeof(p->errbuf), 159147894Ssam "Setting direction is not supported on savefiles"); 160147894Ssam return (-1); 161147894Ssam} 162147894Ssam 163127664Sbmsstatic void 164190225Srpaulosf_cleanup(pcap_t *p) 165127664Sbms{ 166127664Sbms if (p->sf.rfile != stdin) 167127664Sbms (void)fclose(p->sf.rfile); 168214518Srpaulo if (p->buffer != NULL) 169214518Srpaulo free(p->buffer); 170235426Sdelphij pcap_freecode(&p->fcode); 171127664Sbms} 172127664Sbms 17317683Spstpcap_t * 17439291Sfennerpcap_open_offline(const char *fname, char *errbuf) 17517683Spst{ 176146768Ssam FILE *fp; 177146768Ssam pcap_t *p; 178146768Ssam 179146768Ssam if (fname[0] == '-' && fname[1] == '\0') 180147894Ssam { 181146768Ssam fp = stdin; 182147894Ssam#if defined(WIN32) || defined(MSDOS) 183147894Ssam /* 184147894Ssam * We're reading from the standard input, so put it in binary 185147894Ssam * mode, as savefiles are binary files. 186147894Ssam */ 187147894Ssam SET_BINMODE(fp); 188147894Ssam#endif 189147894Ssam } 190146768Ssam else { 191146768Ssam#if !defined(WIN32) && !defined(MSDOS) 192146768Ssam fp = fopen(fname, "r"); 193146768Ssam#else 194146768Ssam fp = fopen(fname, "rb"); 195146768Ssam#endif 196146768Ssam if (fp == NULL) { 197146768Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, 198146768Ssam pcap_strerror(errno)); 199146768Ssam return (NULL); 200146768Ssam } 201146768Ssam } 202146768Ssam p = pcap_fopen_offline(fp, errbuf); 203146768Ssam if (p == NULL) { 204146768Ssam if (fp != stdin) 205146768Ssam fclose(fp); 206146768Ssam } 207146768Ssam return (p); 208146768Ssam} 209146768Ssam 210190225Srpaulo#ifdef WIN32 211190225Srpaulopcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) 212190225Srpaulo{ 213190225Srpaulo int fd; 214190225Srpaulo FILE *file; 215190225Srpaulo 216190225Srpaulo fd = _open_osfhandle(osfd, _O_RDONLY); 217190225Srpaulo if ( fd < 0 ) 218190225Srpaulo { 219190225Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); 220190225Srpaulo return NULL; 221190225Srpaulo } 222190225Srpaulo 223190225Srpaulo file = _fdopen(fd, "rb"); 224190225Srpaulo if ( file == NULL ) 225190225Srpaulo { 226190225Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); 227190225Srpaulo return NULL; 228190225Srpaulo } 229190225Srpaulo 230190225Srpaulo return pcap_fopen_offline(file, errbuf); 231190225Srpaulo} 232190225Srpaulo#endif 233190225Srpaulo 234214518Srpaulostatic int (*check_headers[])(pcap_t *, bpf_u_int32, FILE *, char *) = { 235214518Srpaulo pcap_check_header, 236214518Srpaulo pcap_ng_check_header 237214518Srpaulo}; 238214518Srpaulo 239214518Srpaulo#define N_FILE_TYPES (sizeof check_headers / sizeof check_headers[0]) 240214518Srpaulo 241190225Srpaulo#ifdef WIN32 242190225Srpaulostatic 243190225Srpaulo#endif 244146768Ssampcap_t * 245146768Ssampcap_fopen_offline(FILE *fp, char *errbuf) 246146768Ssam{ 24717683Spst register pcap_t *p; 248214518Srpaulo bpf_u_int32 magic; 249146768Ssam size_t amt_read; 250214518Srpaulo u_int i; 25117683Spst 252214518Srpaulo p = pcap_create_common("(savefile)", errbuf); 253214518Srpaulo if (p == NULL) 25417683Spst return (NULL); 25517683Spst 256214518Srpaulo /* 257214518Srpaulo * Read the first 4 bytes of the file; the network analyzer dump 258214518Srpaulo * file formats we support (pcap and pcap-ng), and several other 259214518Srpaulo * formats we might support in the future (such as snoop, DOS and 260214518Srpaulo * Windows Sniffer, and Microsoft Network Monitor) all have magic 261214518Srpaulo * numbers that are unique in their first 4 bytes. 262214518Srpaulo */ 263214518Srpaulo amt_read = fread((char *)&magic, 1, sizeof(magic), fp); 264214518Srpaulo if (amt_read != sizeof(magic)) { 265146768Ssam if (ferror(fp)) { 266146768Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, 267146768Ssam "error reading dump file: %s", 26875107Sfenner pcap_strerror(errno)); 269146768Ssam } else { 270146768Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, 271146768Ssam "truncated dump file; tried to read %lu file header bytes, only got %lu", 272214518Srpaulo (unsigned long)sizeof(magic), 273146768Ssam (unsigned long)amt_read); 27417683Spst } 27517683Spst goto bad; 27617683Spst } 277214518Srpaulo 278214518Srpaulo /* 279214518Srpaulo * Try all file types. 280214518Srpaulo */ 281214518Srpaulo for (i = 0; i < N_FILE_TYPES; i++) { 282214518Srpaulo switch ((*check_headers[i])(p, magic, fp, errbuf)) { 283214518Srpaulo 284214518Srpaulo case -1: 285214518Srpaulo /* 286214518Srpaulo * Error trying to read the header. 287214518Srpaulo */ 28817683Spst goto bad; 289214518Srpaulo 290214518Srpaulo case 1: 291214518Srpaulo /* 292214518Srpaulo * Yup, that's it. 293214518Srpaulo */ 294214518Srpaulo goto found; 29517683Spst } 29617683Spst } 29717683Spst 298214518Srpaulo /* 299214518Srpaulo * Well, who knows what this mess is.... 300214518Srpaulo */ 301214518Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format"); 302214518Srpaulo goto bad; 30317683Spst 304214518Srpaulofound: 305214518Srpaulo p->sf.rfile = fp; 30617683Spst 30717683Spst#ifdef PCAP_FDDIPAD 308146768Ssam /* Padding only needed for live capture fcode */ 309146768Ssam p->fddipad = 0; 31017683Spst#endif 31117683Spst 312146768Ssam#if !defined(WIN32) && !defined(MSDOS) 313127664Sbms /* 314127664Sbms * You can do "select()" and "poll()" on plain files on most 315127664Sbms * platforms, and should be able to do so on pipes. 316127664Sbms * 317127664Sbms * You can't do "select()" on anything other than sockets in 318127664Sbms * Windows, so, on Win32 systems, we don't have "selectable_fd". 319127664Sbms */ 320127664Sbms p->selectable_fd = fileno(fp); 321127664Sbms#endif 322127664Sbms 323127664Sbms p->read_op = pcap_offline_read; 324146768Ssam p->inject_op = sf_inject; 325127664Sbms p->setfilter_op = install_bpf_program; 326147894Ssam p->setdirection_op = sf_setdirection; 327127664Sbms p->set_datalink_op = NULL; /* we don't support munging link-layer headers */ 328127664Sbms p->getnonblock_op = sf_getnonblock; 329127664Sbms p->setnonblock_op = sf_setnonblock; 330127664Sbms p->stats_op = sf_stats; 331190225Srpaulo#ifdef WIN32 332190225Srpaulo p->setbuff_op = sf_setbuff; 333190225Srpaulo p->setmode_op = sf_setmode; 334190225Srpaulo p->setmintocopy_op = sf_setmintocopy; 335190225Srpaulo#endif 336190225Srpaulo p->cleanup_op = sf_cleanup; 337190225Srpaulo p->activated = 1; 338127664Sbms 33917683Spst return (p); 34017683Spst bad: 34117683Spst free(p); 34217683Spst return (NULL); 34317683Spst} 34417683Spst 34517683Spst/* 346214518Srpaulo * Read packets from a capture file, and call the callback for each 347214518Srpaulo * packet. 34817683Spst * If cnt > 0, return after 'cnt' packets, otherwise continue until eof. 34917683Spst */ 35017683Spstint 35117683Spstpcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 35217683Spst{ 353146768Ssam struct bpf_insn *fcode; 35417683Spst int status = 0; 35517683Spst int n = 0; 356214518Srpaulo u_char *data; 35717683Spst 35817683Spst while (status == 0) { 35917683Spst struct pcap_pkthdr h; 36017683Spst 361127664Sbms /* 362127664Sbms * Has "pcap_breakloop()" been called? 363127664Sbms * If so, return immediately - if we haven't read any 364127664Sbms * packets, clear the flag and return -2 to indicate 365127664Sbms * that we were told to break out of the loop, otherwise 366127664Sbms * leave the flag set, so that the *next* call will break 367127664Sbms * out of the loop without having read any packets, and 368127664Sbms * return the number of packets we've processed so far. 369127664Sbms */ 370127664Sbms if (p->break_loop) { 371127664Sbms if (n == 0) { 372127664Sbms p->break_loop = 0; 373127664Sbms return (-2); 374127664Sbms } else 375127664Sbms return (n); 376127664Sbms } 377127664Sbms 378214518Srpaulo status = p->sf.next_packet_op(p, &h, &data); 37917683Spst if (status) { 38017683Spst if (status == 1) 38117683Spst return (0); 38217683Spst return (status); 38317683Spst } 38417683Spst 385146768Ssam if ((fcode = p->fcode.bf_insns) == NULL || 386235426Sdelphij bpf_filter(fcode, data, h.len, h.caplen)) { 387214518Srpaulo (*callback)(user, &h, data); 38817683Spst if (++n >= cnt && cnt > 0) 38917683Spst break; 39017683Spst } 39117683Spst } 39217683Spst /*XXX this breaks semantics tcpslice expects */ 39317683Spst return (n); 39417683Spst} 395