1 /* $NetBSD: savefile.c,v 1.1.1.4 2013/12/31 16:57:18 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1994, 1995, 1996, 1997 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 * 23 * savefile.c - supports offline use of tcpdump 24 * Extraction/creation by Jeffrey Mogul, DECWRL 25 * Modified by Steve McCanne, LBL. 26 * 27 * Used to save the received packet headers, after filtering, to 28 * a file, and then read them later. 29 * The first record in the file contains saved values for the machine 30 * dependent values so we can print the dump file on any architecture. 31 */ 32 33 #ifndef lint 34 static const char rcsid[] _U_ = 35 "@(#) Header: /tcpdump/master/libpcap/savefile.c,v 1.183 2008-12-23 20:13:29 guy Exp (LBL)"; 36 #endif 37 38 #ifdef HAVE_CONFIG_H 39 #include "config.h" 40 #endif 41 42 #ifdef WIN32 43 #include <pcap-stdinc.h> 44 #else /* WIN32 */ 45 #if HAVE_INTTYPES_H 46 #include <inttypes.h> 47 #elif HAVE_STDINT_H 48 #include <stdint.h> 49 #endif 50 #ifdef HAVE_SYS_BITYPES_H 51 #include <sys/bitypes.h> 52 #endif 53 #include <sys/types.h> 54 #endif /* WIN32 */ 55 56 #include <errno.h> 57 #include <memory.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 62 #include "pcap-int.h" 63 #include "pcap/usb.h" 64 65 #ifdef HAVE_OS_PROTO_H 66 #include "os-proto.h" 67 #endif 68 69 #include "sf-pcap.h" 70 #include "sf-pcap-ng.h" 71 72 /* 73 * Setting O_BINARY on DOS/Windows is a bit tricky 74 */ 75 #if defined(WIN32) 76 #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) 77 #elif defined(MSDOS) 78 #if defined(__HIGHC__) 79 #define SET_BINMODE(f) setmode(f, O_BINARY) 80 #else 81 #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) 82 #endif 83 #endif 84 85 static int 86 sf_getnonblock(pcap_t *p, char *errbuf) 87 { 88 /* 89 * This is a savefile, not a live capture file, so never say 90 * it's in non-blocking mode. 91 */ 92 return (0); 93 } 94 95 static int 96 sf_setnonblock(pcap_t *p, int nonblock, char *errbuf) 97 { 98 /* 99 * This is a savefile, not a live capture file, so reject 100 * requests to put it in non-blocking mode. (If it's a 101 * pipe, it could be put in non-blocking mode, but that 102 * would significantly complicate the code to read packets, 103 * as it would have to handle reading partial packets and 104 * keeping the state of the read.) 105 */ 106 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 107 "Savefiles cannot be put into non-blocking mode"); 108 return (-1); 109 } 110 111 static int 112 sf_stats(pcap_t *p, struct pcap_stat *ps) 113 { 114 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 115 "Statistics aren't available from savefiles"); 116 return (-1); 117 } 118 119 #ifdef WIN32 120 static int 121 sf_setbuff(pcap_t *p, int dim) 122 { 123 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 124 "The kernel buffer size cannot be set while reading from a file"); 125 return (-1); 126 } 127 128 static int 129 sf_setmode(pcap_t *p, int mode) 130 { 131 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 132 "impossible to set mode while reading from a file"); 133 return (-1); 134 } 135 136 static int 137 sf_setmintocopy(pcap_t *p, int size) 138 { 139 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 140 "The mintocopy parameter cannot be set while reading from a file"); 141 return (-1); 142 } 143 #endif 144 145 static int 146 sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 147 { 148 strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", 149 PCAP_ERRBUF_SIZE); 150 return (-1); 151 } 152 153 /* 154 * Set direction flag: Which packets do we accept on a forwarding 155 * single device? IN, OUT or both? 156 */ 157 static int 158 sf_setdirection(pcap_t *p, pcap_direction_t d) 159 { 160 snprintf(p->errbuf, sizeof(p->errbuf), 161 "Setting direction is not supported on savefiles"); 162 return (-1); 163 } 164 165 void 166 sf_cleanup(pcap_t *p) 167 { 168 if (p->rfile != stdin) 169 (void)fclose(p->rfile); 170 if (p->buffer != NULL) 171 free(p->buffer); 172 pcap_freecode(&p->fcode); 173 } 174 175 pcap_t * 176 pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision, 177 char *errbuf) 178 { 179 FILE *fp; 180 pcap_t *p; 181 182 if (fname[0] == '-' && fname[1] == '\0') 183 { 184 fp = stdin; 185 #if defined(WIN32) || defined(MSDOS) 186 /* 187 * We're reading from the standard input, so put it in binary 188 * mode, as savefiles are binary files. 189 */ 190 SET_BINMODE(fp); 191 #endif 192 } 193 else { 194 #if !defined(WIN32) && !defined(MSDOS) 195 fp = fopen(fname, "r"); 196 #else 197 fp = fopen(fname, "rb"); 198 #endif 199 if (fp == NULL) { 200 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, 201 pcap_strerror(errno)); 202 return (NULL); 203 } 204 } 205 p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf); 206 if (p == NULL) { 207 if (fp != stdin) 208 fclose(fp); 209 } 210 return (p); 211 } 212 213 pcap_t * 214 pcap_open_offline(const char *fname, char *errbuf) 215 { 216 return (pcap_open_offline_with_tstamp_precision(fname, 217 PCAP_TSTAMP_PRECISION_MICRO, errbuf)); 218 } 219 220 #ifdef WIN32 221 pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision, 222 char *errbuf) 223 { 224 int fd; 225 FILE *file; 226 227 fd = _open_osfhandle(osfd, _O_RDONLY); 228 if ( fd < 0 ) 229 { 230 snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); 231 return NULL; 232 } 233 234 file = _fdopen(fd, "rb"); 235 if ( file == NULL ) 236 { 237 snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno)); 238 return NULL; 239 } 240 241 return pcap_fopen_offline_with_tstamp_precision(file, precision, 242 errbuf); 243 } 244 245 pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) 246 { 247 return pcap_hopen_offline_with_tstamp_precision(osfd, 248 PCAP_TSTAMP_PRECISION_MICRO, errbuf); 249 } 250 #endif 251 252 static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *) = { 253 pcap_check_header, 254 pcap_ng_check_header 255 }; 256 257 #define N_FILE_TYPES (sizeof check_headers / sizeof check_headers[0]) 258 259 #ifdef WIN32 260 static 261 #endif 262 pcap_t * 263 pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, 264 char *errbuf) 265 { 266 register pcap_t *p; 267 bpf_u_int32 magic; 268 size_t amt_read; 269 u_int i; 270 int err; 271 272 /* 273 * Read the first 4 bytes of the file; the network analyzer dump 274 * file formats we support (pcap and pcap-ng), and several other 275 * formats we might support in the future (such as snoop, DOS and 276 * Windows Sniffer, and Microsoft Network Monitor) all have magic 277 * numbers that are unique in their first 4 bytes. 278 */ 279 amt_read = fread((char *)&magic, 1, sizeof(magic), fp); 280 if (amt_read != sizeof(magic)) { 281 if (ferror(fp)) { 282 snprintf(errbuf, PCAP_ERRBUF_SIZE, 283 "error reading dump file: %s", 284 pcap_strerror(errno)); 285 } else { 286 snprintf(errbuf, PCAP_ERRBUF_SIZE, 287 "truncated dump file; tried to read %lu file header bytes, only got %lu", 288 (unsigned long)sizeof(magic), 289 (unsigned long)amt_read); 290 } 291 return (NULL); 292 } 293 294 /* 295 * Try all file types. 296 */ 297 for (i = 0; i < N_FILE_TYPES; i++) { 298 p = (*check_headers[i])(magic, fp, precision, errbuf, &err); 299 if (p != NULL) { 300 /* Yup, that's it. */ 301 goto found; 302 } 303 if (err) { 304 /* 305 * Error trying to read the header. 306 */ 307 return (NULL); 308 } 309 } 310 311 /* 312 * Well, who knows what this mess is.... 313 */ 314 snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format"); 315 return (NULL); 316 317 found: 318 p->rfile = fp; 319 320 /* Padding only needed for live capture fcode */ 321 p->fddipad = 0; 322 323 #if !defined(WIN32) && !defined(MSDOS) 324 /* 325 * You can do "select()" and "poll()" on plain files on most 326 * platforms, and should be able to do so on pipes. 327 * 328 * You can't do "select()" on anything other than sockets in 329 * Windows, so, on Win32 systems, we don't have "selectable_fd". 330 */ 331 p->selectable_fd = fileno(fp); 332 #endif 333 334 p->read_op = pcap_offline_read; 335 p->inject_op = sf_inject; 336 p->setfilter_op = install_bpf_program; 337 p->setdirection_op = sf_setdirection; 338 p->set_datalink_op = NULL; /* we don't support munging link-layer headers */ 339 p->getnonblock_op = sf_getnonblock; 340 p->setnonblock_op = sf_setnonblock; 341 p->stats_op = sf_stats; 342 #ifdef WIN32 343 p->setbuff_op = sf_setbuff; 344 p->setmode_op = sf_setmode; 345 p->setmintocopy_op = sf_setmintocopy; 346 #endif 347 348 /* 349 * For offline captures, the standard one-shot callback can 350 * be used for pcap_next()/pcap_next_ex(). 351 */ 352 p->oneshot_callback = pcap_oneshot; 353 354 p->activated = 1; 355 356 return (p); 357 } 358 359 #ifdef WIN32 360 static 361 #endif 362 pcap_t * 363 pcap_fopen_offline(FILE *fp, char *errbuf) 364 { 365 return (pcap_fopen_offline_with_tstamp_precision(fp, 366 PCAP_TSTAMP_PRECISION_MICRO, errbuf)); 367 } 368 369 /* 370 * Read packets from a capture file, and call the callback for each 371 * packet. 372 * If cnt > 0, return after 'cnt' packets, otherwise continue until eof. 373 */ 374 int 375 pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 376 { 377 struct bpf_insn *fcode; 378 int status = 0; 379 int n = 0; 380 u_char *data; 381 382 while (status == 0) { 383 struct pcap_pkthdr h; 384 385 /* 386 * Has "pcap_breakloop()" been called? 387 * If so, return immediately - if we haven't read any 388 * packets, clear the flag and return -2 to indicate 389 * that we were told to break out of the loop, otherwise 390 * leave the flag set, so that the *next* call will break 391 * out of the loop without having read any packets, and 392 * return the number of packets we've processed so far. 393 */ 394 if (p->break_loop) { 395 if (n == 0) { 396 p->break_loop = 0; 397 return (-2); 398 } else 399 return (n); 400 } 401 402 status = p->next_packet_op(p, &h, &data); 403 if (status) { 404 if (status == 1) 405 return (0); 406 return (status); 407 } 408 409 if ((fcode = p->fcode.bf_insns) == NULL || 410 bpf_filter(fcode, data, h.len, h.caplen)) { 411 (*callback)(user, &h, data); 412 if (++n >= cnt && cnt > 0) 413 break; 414 } 415 } 416 /*XXX this breaks semantics tcpslice expects */ 417 return (n); 418 } 419