1 /* $NetBSD: sf-pcap.c,v 1.7 2017/01/24 22:29:28 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 * sf-pcap.c - libpcap-file-format-specific code from savefile.c 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 (LBL)"; 36 #endif 37 38 #include <sys/cdefs.h> 39 __RCSID("$NetBSD: sf-pcap.c,v 1.7 2017/01/24 22:29:28 christos Exp $"); 40 41 #ifdef HAVE_CONFIG_H 42 #include "config.h" 43 #endif 44 45 #ifdef _WIN32 46 #include <pcap-stdinc.h> 47 #else /* _WIN32 */ 48 #if HAVE_INTTYPES_H 49 #include <inttypes.h> 50 #elif HAVE_STDINT_H 51 #include <stdint.h> 52 #endif 53 #ifdef HAVE_SYS_BITYPES_H 54 #include <sys/bitypes.h> 55 #endif 56 #include <sys/types.h> 57 #endif /* _WIN32 */ 58 59 #include <errno.h> 60 #include <memory.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 65 #include "pcap-int.h" 66 67 #include "pcap-common.h" 68 69 #ifdef HAVE_OS_PROTO_H 70 #include "os-proto.h" 71 #endif 72 73 #include "sf-pcap.h" 74 75 /* 76 * Setting O_BINARY on DOS/Windows is a bit tricky 77 */ 78 #if defined(_WIN32) 79 #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) 80 #elif defined(MSDOS) 81 #if defined(__HIGHC__) 82 #define SET_BINMODE(f) setmode(f, O_BINARY) 83 #else 84 #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) 85 #endif 86 #endif 87 88 /* 89 * Standard libpcap format. 90 */ 91 #define TCPDUMP_MAGIC 0xa1b2c3d4 92 93 /* 94 * Alexey Kuznetzov's modified libpcap format. 95 */ 96 #define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 97 98 /* 99 * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt> 100 * for another modified format. 101 */ 102 #define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd 103 104 /* 105 * Navtel Communcations' format, with nanosecond timestamps, 106 * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>. 107 */ 108 #define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d 109 110 /* 111 * Normal libpcap format, except for seconds/nanoseconds timestamps, 112 * as per a request by Ulf Lamping <ulf.lamping@web.de> 113 */ 114 #define NSEC_TCPDUMP_MAGIC 0xa1b23c4d 115 116 /* 117 * Mechanism for storing information about a capture in the upper 118 * 6 bits of a linktype value in a capture file. 119 * 120 * LT_LINKTYPE_EXT(x) extracts the additional information. 121 * 122 * The rest of the bits are for a value describing the link-layer 123 * value. LT_LINKTYPE(x) extracts that value. 124 */ 125 #define LT_LINKTYPE(x) ((x) & 0x03FFFFFF) 126 #define LT_LINKTYPE_EXT(x) ((x) & 0xFC000000) 127 128 static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); 129 130 /* 131 * Private data for reading pcap savefiles. 132 */ 133 typedef enum { 134 NOT_SWAPPED, 135 SWAPPED, 136 MAYBE_SWAPPED 137 } swapped_type_t; 138 139 typedef enum { 140 PASS_THROUGH, 141 SCALE_UP, 142 SCALE_DOWN 143 } tstamp_scale_type_t; 144 145 struct pcap_sf { 146 size_t hdrsize; 147 swapped_type_t lengths_swapped; 148 tstamp_scale_type_t scale_type; 149 }; 150 151 /* 152 * Check whether this is a pcap savefile and, if it is, extract the 153 * relevant information from the header. 154 */ 155 pcap_t * 156 pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, 157 int *err) 158 { 159 struct pcap_file_header hdr; 160 size_t amt_read; 161 pcap_t *p; 162 int swapped = 0; 163 struct pcap_sf *ps; 164 165 /* 166 * Assume no read errors. 167 */ 168 *err = 0; 169 170 /* 171 * Check whether the first 4 bytes of the file are the magic 172 * number for a pcap savefile, or for a byte-swapped pcap 173 * savefile. 174 */ 175 if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && 176 magic != NSEC_TCPDUMP_MAGIC) { 177 magic = SWAPLONG(magic); 178 if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && 179 magic != NSEC_TCPDUMP_MAGIC) 180 return (NULL); /* nope */ 181 swapped = 1; 182 } 183 184 /* 185 * They are. Put the magic number in the header, and read 186 * the rest of the header. 187 */ 188 hdr.magic = magic; 189 amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, 190 sizeof(hdr) - sizeof(hdr.magic), fp); 191 if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { 192 if (ferror(fp)) { 193 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 194 "error reading dump file: %s", 195 pcap_strerror(errno)); 196 } else { 197 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 198 "truncated dump file; tried to read %lu file header bytes, only got %lu", 199 (unsigned long)sizeof(hdr), 200 (unsigned long)amt_read); 201 } 202 *err = 1; 203 return (NULL); 204 } 205 206 /* 207 * If it's a byte-swapped capture file, byte-swap the header. 208 */ 209 if (swapped) { 210 hdr.version_major = SWAPSHORT(hdr.version_major); 211 hdr.version_minor = SWAPSHORT(hdr.version_minor); 212 hdr.thiszone = SWAPLONG(hdr.thiszone); 213 hdr.sigfigs = SWAPLONG(hdr.sigfigs); 214 hdr.snaplen = SWAPLONG(hdr.snaplen); 215 hdr.linktype = SWAPLONG(hdr.linktype); 216 } 217 218 if (hdr.version_major < PCAP_VERSION_MAJOR) { 219 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 220 "archaic pcap savefile format"); 221 *err = 1; 222 return (NULL); 223 } 224 225 /* 226 * currently only versions 2.[0-4] are supported with 227 * the exception of 543.0 for DG/UX tcpdump. 228 */ 229 if (! ((hdr.version_major == PCAP_VERSION_MAJOR && 230 hdr.version_minor <= PCAP_VERSION_MINOR) || 231 (hdr.version_major == 543 && 232 hdr.version_minor == 0))) { 233 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 234 "unsupported pcap savefile version %u.%u", 235 hdr.version_major, hdr.version_minor); 236 *err = 1; 237 return NULL; 238 } 239 240 if (hdr.snaplen > MAXIMUM_SNAPLEN) { 241 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 242 "invalid file capture length %u, bigger than " 243 "maximum of %u", hdr.snaplen, MAXIMUM_SNAPLEN); 244 *err = 1; 245 return NULL; 246 } 247 248 /* 249 * OK, this is a good pcap file. 250 * Allocate a pcap_t for it. 251 */ 252 p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf)); 253 if (p == NULL) { 254 /* Allocation failed. */ 255 *err = 1; 256 return (NULL); 257 } 258 p->swapped = swapped; 259 p->version_major = hdr.version_major; 260 p->version_minor = hdr.version_minor; 261 p->tzoff = hdr.thiszone; 262 p->snapshot = hdr.snaplen; 263 p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); 264 p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); 265 266 p->next_packet_op = pcap_next_packet; 267 268 ps = p->priv; 269 270 p->opt.tstamp_precision = precision; 271 272 /* 273 * Will we need to scale the timestamps to match what the 274 * user wants? 275 */ 276 switch (precision) { 277 278 case PCAP_TSTAMP_PRECISION_MICRO: 279 if (magic == NSEC_TCPDUMP_MAGIC) { 280 /* 281 * The file has nanoseconds, the user 282 * wants microseconds; scale the 283 * precision down. 284 */ 285 ps->scale_type = SCALE_DOWN; 286 } else { 287 /* 288 * The file has microseconds, the 289 * user wants microseconds; nothing to do. 290 */ 291 ps->scale_type = PASS_THROUGH; 292 } 293 break; 294 295 case PCAP_TSTAMP_PRECISION_NANO: 296 if (magic == NSEC_TCPDUMP_MAGIC) { 297 /* 298 * The file has nanoseconds, the 299 * user wants nanoseconds; nothing to do. 300 */ 301 ps->scale_type = PASS_THROUGH; 302 } else { 303 /* 304 * The file has microoseconds, the user 305 * wants nanoseconds; scale the 306 * precision up. 307 */ 308 ps->scale_type = SCALE_UP; 309 } 310 break; 311 312 default: 313 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 314 "unknown time stamp resolution %u", precision); 315 free(p); 316 *err = 1; 317 return (NULL); 318 } 319 320 /* 321 * We interchanged the caplen and len fields at version 2.3, 322 * in order to match the bpf header layout. But unfortunately 323 * some files were written with version 2.3 in their headers 324 * but without the interchanged fields. 325 * 326 * In addition, DG/UX tcpdump writes out files with a version 327 * number of 543.0, and with the caplen and len fields in the 328 * pre-2.3 order. 329 */ 330 switch (hdr.version_major) { 331 332 case 2: 333 if (hdr.version_minor < 3) 334 ps->lengths_swapped = SWAPPED; 335 else if (hdr.version_minor == 3) 336 ps->lengths_swapped = MAYBE_SWAPPED; 337 else 338 ps->lengths_swapped = NOT_SWAPPED; 339 break; 340 341 case 543: 342 ps->lengths_swapped = SWAPPED; 343 break; 344 345 default: 346 ps->lengths_swapped = NOT_SWAPPED; 347 break; 348 } 349 350 if (magic == KUZNETZOV_TCPDUMP_MAGIC) { 351 /* 352 * XXX - the patch that's in some versions of libpcap 353 * changes the packet header but not the magic number, 354 * and some other versions with this magic number have 355 * some extra debugging information in the packet header; 356 * we'd have to use some hacks^H^H^H^H^Hheuristics to 357 * detect those variants. 358 * 359 * Ethereal does that, but it does so by trying to read 360 * the first two packets of the file with each of the 361 * record header formats. That currently means it seeks 362 * backwards and retries the reads, which doesn't work 363 * on pipes. We want to be able to read from a pipe, so 364 * that strategy won't work; we'd have to buffer some 365 * data ourselves and read from that buffer in order to 366 * make that work. 367 */ 368 ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); 369 370 if (p->linktype == DLT_EN10MB) { 371 /* 372 * This capture might have been done in raw mode 373 * or cooked mode. 374 * 375 * If it was done in cooked mode, p->snapshot was 376 * passed to recvfrom() as the buffer size, meaning 377 * that the most packet data that would be copied 378 * would be p->snapshot. However, a faked Ethernet 379 * header would then have been added to it, so the 380 * most data that would be in a packet in the file 381 * would be p->snapshot + 14. 382 * 383 * We can't easily tell whether the capture was done 384 * in raw mode or cooked mode, so we'll assume it was 385 * cooked mode, and add 14 to the snapshot length. 386 * That means that, for a raw capture, the snapshot 387 * length will be misleading if you use it to figure 388 * out why a capture doesn't have all the packet data, 389 * but there's not much we can do to avoid that. 390 */ 391 p->snapshot += 14; 392 } 393 } else 394 ps->hdrsize = sizeof(struct pcap_sf_pkthdr); 395 396 /* 397 * Allocate a buffer for the packet data. 398 */ 399 p->bufsize = p->snapshot; 400 if (p->bufsize <= 0) { 401 /* 402 * Bogus snapshot length; use the maximum as a fallback. 403 */ 404 p->bufsize = MAXIMUM_SNAPLEN; 405 } 406 p->buffer = malloc(p->bufsize); 407 if (p->buffer == NULL) { 408 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); 409 free(p); 410 *err = 1; 411 return (NULL); 412 } 413 414 p->cleanup_op = sf_cleanup; 415 416 return (p); 417 } 418 419 /* 420 * Read and return the next packet from the savefile. Return the header 421 * in hdr and a pointer to the contents in data. Return 0 on success, 1 422 * if there were no more packets, and -1 on an error. 423 */ 424 static int 425 pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) 426 { 427 struct pcap_sf *ps = p->priv; 428 struct pcap_sf_patched_pkthdr sf_hdr; 429 FILE *fp = p->rfile; 430 size_t amt_read; 431 bpf_u_int32 t; 432 433 /* 434 * Read the packet header; the structure we use as a buffer 435 * is the longer structure for files generated by the patched 436 * libpcap, but if the file has the magic number for an 437 * unpatched libpcap we only read as many bytes as the regular 438 * header has. 439 */ 440 amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); 441 if (amt_read != ps->hdrsize) { 442 if (ferror(fp)) { 443 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 444 "error reading dump file: %s", 445 pcap_strerror(errno)); 446 return (-1); 447 } else { 448 if (amt_read != 0) { 449 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 450 "truncated dump file; tried to read %lu header bytes, only got %lu", 451 (unsigned long)ps->hdrsize, 452 (unsigned long)amt_read); 453 return (-1); 454 } 455 /* EOF */ 456 return (1); 457 } 458 } 459 460 if (p->swapped) { 461 /* these were written in opposite byte order */ 462 hdr->caplen = SWAPLONG(sf_hdr.caplen); 463 hdr->len = SWAPLONG(sf_hdr.len); 464 hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); 465 hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); 466 } else { 467 hdr->caplen = sf_hdr.caplen; 468 hdr->len = sf_hdr.len; 469 hdr->ts.tv_sec = sf_hdr.ts.tv_sec; 470 hdr->ts.tv_usec = sf_hdr.ts.tv_usec; 471 } 472 473 switch (ps->scale_type) { 474 475 case PASS_THROUGH: 476 /* 477 * Just pass the time stamp through. 478 */ 479 break; 480 481 case SCALE_UP: 482 /* 483 * File has microseconds, user wants nanoseconds; convert 484 * it. 485 */ 486 hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; 487 break; 488 489 case SCALE_DOWN: 490 /* 491 * File has nanoseconds, user wants microseconds; convert 492 * it. 493 */ 494 hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; 495 break; 496 } 497 498 /* Swap the caplen and len fields, if necessary. */ 499 switch (ps->lengths_swapped) { 500 501 case NOT_SWAPPED: 502 break; 503 504 case MAYBE_SWAPPED: 505 if (hdr->caplen <= hdr->len) { 506 /* 507 * The captured length is <= the actual length, 508 * so presumably they weren't swapped. 509 */ 510 break; 511 } 512 /* FALLTHROUGH */ 513 514 case SWAPPED: 515 t = hdr->caplen; 516 hdr->caplen = hdr->len; 517 hdr->len = t; 518 break; 519 } 520 521 if (hdr->caplen > p->bufsize) { 522 /* 523 * This can happen due to Solaris 2.3 systems tripping 524 * over the BUFMOD problem and not setting the snapshot 525 * correctly in the savefile header. 526 * This can also happen with a corrupted savefile or a 527 * savefile built/modified by a fuzz tester. 528 * If the caplen isn't grossly wrong, try to salvage. 529 */ 530 size_t bytes_to_discard; 531 size_t bytes_to_read, bytes_read; 532 char discard_buf[4096]; 533 534 if (hdr->caplen > MAXIMUM_SNAPLEN) { 535 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 536 "invalid packet capture length %u, bigger than " 537 "maximum of %u", hdr->caplen, MAXIMUM_SNAPLEN); 538 return (-1); 539 } 540 541 /* 542 * XXX - we don't grow the buffer here because some 543 * program might assume that it will never get packets 544 * bigger than the snapshot length; for example, it might 545 * copy data from our buffer to a buffer of its own, 546 * allocated based on the return value of pcap_snapshot(). 547 * 548 * Read the first p->bufsize bytes into the buffer. 549 */ 550 amt_read = fread(p->buffer, 1, p->bufsize, fp); 551 if (amt_read != p->bufsize) { 552 if (ferror(fp)) { 553 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 554 "error reading dump file: %s", 555 pcap_strerror(errno)); 556 } else { 557 /* 558 * Yes, this uses hdr->caplen; technically, 559 * it's true, because we would try to read 560 * and discard the rest of those bytes, and 561 * that would fail because we got EOF before 562 * the read finished. 563 */ 564 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 565 "truncated dump file; tried to read %u captured bytes, only got %lu", 566 hdr->caplen, (unsigned long)amt_read); 567 } 568 return (-1); 569 } 570 571 /* 572 * Now read and discard what's left. 573 */ 574 bytes_to_discard = hdr->caplen - p->bufsize; 575 bytes_read = amt_read; 576 while (bytes_to_discard != 0) { 577 bytes_to_read = bytes_to_discard; 578 if (bytes_to_read > sizeof (discard_buf)) 579 bytes_to_read = sizeof (discard_buf); 580 amt_read = fread(discard_buf, 1, bytes_to_read, fp); 581 bytes_read += amt_read; 582 if (amt_read != bytes_to_read) { 583 if (ferror(fp)) { 584 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 585 "error reading dump file: %s", 586 pcap_strerror(errno)); 587 } else { 588 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 589 "truncated dump file; tried to read %u captured bytes, only got %lu", 590 hdr->caplen, (unsigned long)bytes_read); 591 } 592 return (-1); 593 } 594 bytes_to_discard -= amt_read; 595 } 596 597 /* 598 * Adjust caplen accordingly, so we don't get confused later 599 * as to how many bytes we have to play with. 600 */ 601 hdr->caplen = p->bufsize; 602 } else { 603 /* read the packet itself */ 604 amt_read = fread(p->buffer, 1, hdr->caplen, fp); 605 if (amt_read != hdr->caplen) { 606 if (ferror(fp)) { 607 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 608 "error reading dump file: %s", 609 pcap_strerror(errno)); 610 } else { 611 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 612 "truncated dump file; tried to read %u captured bytes, only got %lu", 613 hdr->caplen, (unsigned long)amt_read); 614 } 615 return (-1); 616 } 617 } 618 *data = p->buffer; 619 620 if (p->swapped) 621 swap_pseudo_headers(p->linktype, hdr, *data); 622 623 return (0); 624 } 625 626 static int 627 sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen) 628 { 629 struct pcap_file_header hdr; 630 631 hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; 632 hdr.version_major = PCAP_VERSION_MAJOR; 633 hdr.version_minor = PCAP_VERSION_MINOR; 634 635 hdr.thiszone = thiszone; 636 hdr.snaplen = snaplen; 637 hdr.sigfigs = 0; 638 hdr.linktype = linktype; 639 640 if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) 641 return (-1); 642 643 return (0); 644 } 645 646 /* 647 * Output a packet to the initialized dump file. 648 */ 649 void 650 pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) 651 { 652 register FILE *f; 653 struct pcap_sf_pkthdr sf_hdr; 654 655 f = (FILE *)user; 656 sf_hdr.ts.tv_sec = h->ts.tv_sec; 657 sf_hdr.ts.tv_usec = h->ts.tv_usec; 658 sf_hdr.caplen = h->caplen; 659 sf_hdr.len = h->len; 660 /* XXX we should check the return status */ 661 (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f); 662 (void)fwrite(sp, h->caplen, 1, f); 663 } 664 665 static pcap_dumper_t * 666 pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) 667 { 668 669 #if defined(_WIN32) || defined(MSDOS) 670 /* 671 * If we're writing to the standard output, put it in binary 672 * mode, as savefiles are binary files. 673 * 674 * Otherwise, we turn off buffering. 675 * XXX - why? And why not on the standard output? 676 */ 677 if (f == stdout) 678 SET_BINMODE(f); 679 else 680 setbuf(f, NULL); 681 #endif 682 if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { 683 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", 684 fname, pcap_strerror(errno)); 685 if (f != stdout) 686 (void)fclose(f); 687 return (NULL); 688 } 689 return ((pcap_dumper_t *)f); 690 } 691 692 /* 693 * Initialize so that sf_write() will output to the file named 'fname'. 694 */ 695 pcap_dumper_t * 696 pcap_dump_open(pcap_t *p, const char *fname) 697 { 698 FILE *f; 699 int linktype; 700 701 /* 702 * If this pcap_t hasn't been activated, it doesn't have a 703 * link-layer type, so we can't use it. 704 */ 705 if (!p->activated) { 706 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 707 "%s: not-yet-activated pcap_t passed to pcap_dump_open", 708 fname); 709 return (NULL); 710 } 711 linktype = dlt_to_linktype(p->linktype); 712 if (linktype == -1) { 713 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 714 "%s: link-layer type %d isn't supported in savefiles", 715 fname, p->linktype); 716 return (NULL); 717 } 718 linktype |= p->linktype_ext; 719 720 if (fname == NULL) { 721 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 722 "A null pointer was supplied as the file name"); 723 return NULL; 724 } 725 if (fname[0] == '-' && fname[1] == '\0') { 726 f = stdout; 727 fname = "standard output"; 728 } else { 729 #if !defined(_WIN32) && !defined(MSDOS) 730 f = fopen(fname, "w"); 731 #else 732 f = fopen(fname, "wb"); 733 #endif 734 if (f == NULL) { 735 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 736 fname, pcap_strerror(errno)); 737 return (NULL); 738 } 739 } 740 return (pcap_setup_dump(p, linktype, f, fname)); 741 } 742 743 /* 744 * Initialize so that sf_write() will output to the given stream. 745 */ 746 pcap_dumper_t * 747 pcap_dump_fopen(pcap_t *p, FILE *f) 748 { 749 int linktype; 750 751 linktype = dlt_to_linktype(p->linktype); 752 if (linktype == -1) { 753 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 754 "stream: link-layer type %d isn't supported in savefiles", 755 p->linktype); 756 return (NULL); 757 } 758 linktype |= p->linktype_ext; 759 760 return (pcap_setup_dump(p, linktype, f, "stream")); 761 } 762 763 pcap_dumper_t * 764 pcap_dump_open_append(pcap_t *p, const char *fname) 765 { 766 FILE *f; 767 int linktype; 768 size_t amt_read; 769 struct pcap_file_header ph; 770 771 linktype = dlt_to_linktype(p->linktype); 772 if (linktype == -1) { 773 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 774 "%s: link-layer type %d isn't supported in savefiles", 775 fname, linktype); 776 return (NULL); 777 } 778 779 if (fname == NULL) { 780 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 781 "A null pointer was supplied as the file name"); 782 return NULL; 783 } 784 if (fname[0] == '-' && fname[1] == '\0') 785 return (pcap_setup_dump(p, linktype, stdout, "standard output")); 786 787 #if !defined(_WIN32) && !defined(MSDOS) 788 f = fopen(fname, "r+"); 789 #else 790 f = fopen(fname, "rb+"); 791 #endif 792 if (f == NULL) { 793 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 794 fname, pcap_strerror(errno)); 795 return (NULL); 796 } 797 798 /* 799 * Try to read a pcap header. 800 */ 801 amt_read = fread(&ph, 1, sizeof (ph), f); 802 if (amt_read != sizeof (ph)) { 803 if (ferror(f)) { 804 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 805 fname, pcap_strerror(errno)); 806 fclose(f); 807 return (NULL); 808 } else if (feof(f) && amt_read > 0) { 809 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 810 "%s: truncated pcap file header", fname); 811 fclose(f); 812 return (NULL); 813 } 814 } 815 816 #if defined(_WIN32) || defined(MSDOS) 817 /* 818 * We turn off buffering. 819 * XXX - why? And why not on the standard output? 820 */ 821 setbuf(f, NULL); 822 #endif 823 824 /* 825 * If a header is already present and: 826 * 827 * it's not for a pcap file of the appropriate resolution 828 * and the right byte order for this machine; 829 * 830 * the link-layer header types don't match; 831 * 832 * the snapshot lengths don't match; 833 * 834 * return an error. 835 */ 836 if (amt_read > 0) { 837 /* 838 * A header is already present. 839 * Do the checks. 840 */ 841 switch (ph.magic) { 842 843 case TCPDUMP_MAGIC: 844 if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { 845 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 846 "%s: different time stamp precision, cannot append to file", fname); 847 fclose(f); 848 return (NULL); 849 } 850 break; 851 852 case NSEC_TCPDUMP_MAGIC: 853 if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { 854 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 855 "%s: different time stamp precision, cannot append to file", fname); 856 fclose(f); 857 return (NULL); 858 } 859 break; 860 861 case SWAPLONG(TCPDUMP_MAGIC): 862 case SWAPLONG(NSEC_TCPDUMP_MAGIC): 863 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 864 "%s: different byte order, cannot append to file", fname); 865 fclose(f); 866 return (NULL); 867 868 case KUZNETZOV_TCPDUMP_MAGIC: 869 case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): 870 case NAVTEL_TCPDUMP_MAGIC: 871 case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): 872 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 873 "%s: not a pcap file to which we can append", fname); 874 fclose(f); 875 return (NULL); 876 877 default: 878 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 879 "%s: not a pcap file", fname); 880 fclose(f); 881 return (NULL); 882 } 883 884 /* 885 * Good version? 886 */ 887 if (ph.version_major != PCAP_VERSION_MAJOR || 888 ph.version_minor != PCAP_VERSION_MINOR) { 889 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 890 "%s: version is %u.%u, cannot append to file", fname, 891 ph.version_major, ph.version_minor); 892 fclose(f); 893 return (NULL); 894 } 895 if ((bpf_u_int32)linktype != ph.linktype) { 896 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 897 "%s: different linktype, cannot append to file", fname); 898 fclose(f); 899 return (NULL); 900 } 901 if ((bpf_u_int32)p->snapshot != ph.snaplen) { 902 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 903 "%s: different snaplen, cannot append to file", fname); 904 fclose(f); 905 return (NULL); 906 } 907 } else { 908 /* 909 * A header isn't present; attempt to write it. 910 */ 911 if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { 912 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", 913 fname, pcap_strerror(errno)); 914 (void)fclose(f); 915 return (NULL); 916 } 917 } 918 919 /* 920 * Start writing at the end of the file. 921 */ 922 if (fseek(f, 0, SEEK_END) == -1) { 923 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't seek to end of %s: %s", 924 fname, pcap_strerror(errno)); 925 (void)fclose(f); 926 return (NULL); 927 } 928 return ((pcap_dumper_t *)f); 929 } 930 931 FILE * 932 pcap_dump_file(pcap_dumper_t *p) 933 { 934 return ((FILE *)p); 935 } 936 937 long 938 pcap_dump_ftell(pcap_dumper_t *p) 939 { 940 return (ftell((FILE *)p)); 941 } 942 943 int 944 pcap_dump_flush(pcap_dumper_t *p) 945 { 946 947 if (fflush((FILE *)p) == EOF) 948 return (-1); 949 else 950 return (0); 951 } 952 953 void 954 pcap_dump_close(pcap_dumper_t *p) 955 { 956 957 #ifdef notyet 958 if (ferror((FILE *)p)) 959 return-an-error; 960 /* XXX should check return from fclose() too */ 961 #endif 962 (void)fclose((FILE *)p); 963 } 964