1 /* $NetBSD: sf-pcap.c,v 1.6 2015/03/31 21:39:42 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.6 2015/03/31 21:39:42 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 snprintf(errbuf, PCAP_ERRBUF_SIZE, 194 "error reading dump file: %s", 195 pcap_strerror(errno)); 196 } else { 197 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 snprintf(errbuf, PCAP_ERRBUF_SIZE, 220 "archaic pcap savefile format"); 221 *err = 1; 222 return (NULL); 223 } 224 225 /* 226 * OK, this is a good pcap file. 227 * Allocate a pcap_t for it. 228 */ 229 p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf)); 230 if (p == NULL) { 231 /* Allocation failed. */ 232 *err = 1; 233 return (NULL); 234 } 235 p->swapped = swapped; 236 p->version_major = hdr.version_major; 237 p->version_minor = hdr.version_minor; 238 p->tzoff = hdr.thiszone; 239 p->snapshot = hdr.snaplen; 240 p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); 241 p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); 242 243 p->next_packet_op = pcap_next_packet; 244 245 ps = p->priv; 246 247 p->opt.tstamp_precision = precision; 248 249 /* 250 * Will we need to scale the timestamps to match what the 251 * user wants? 252 */ 253 switch (precision) { 254 255 case PCAP_TSTAMP_PRECISION_MICRO: 256 if (magic == NSEC_TCPDUMP_MAGIC) { 257 /* 258 * The file has nanoseconds, the user 259 * wants microseconds; scale the 260 * precision down. 261 */ 262 ps->scale_type = SCALE_DOWN; 263 } else { 264 /* 265 * The file has microseconds, the 266 * user wants microseconds; nothing to do. 267 */ 268 ps->scale_type = PASS_THROUGH; 269 } 270 break; 271 272 case PCAP_TSTAMP_PRECISION_NANO: 273 if (magic == NSEC_TCPDUMP_MAGIC) { 274 /* 275 * The file has nanoseconds, the 276 * user wants nanoseconds; nothing to do. 277 */ 278 ps->scale_type = PASS_THROUGH; 279 } else { 280 /* 281 * The file has microoseconds, the user 282 * wants nanoseconds; scale the 283 * precision up. 284 */ 285 ps->scale_type = SCALE_UP; 286 } 287 break; 288 289 default: 290 snprintf(errbuf, PCAP_ERRBUF_SIZE, 291 "unknown time stamp resolution %u", precision); 292 free(p); 293 *err = 1; 294 return (NULL); 295 } 296 297 /* 298 * We interchanged the caplen and len fields at version 2.3, 299 * in order to match the bpf header layout. But unfortunately 300 * some files were written with version 2.3 in their headers 301 * but without the interchanged fields. 302 * 303 * In addition, DG/UX tcpdump writes out files with a version 304 * number of 543.0, and with the caplen and len fields in the 305 * pre-2.3 order. 306 */ 307 switch (hdr.version_major) { 308 309 case 2: 310 if (hdr.version_minor < 3) 311 ps->lengths_swapped = SWAPPED; 312 else if (hdr.version_minor == 3) 313 ps->lengths_swapped = MAYBE_SWAPPED; 314 else 315 ps->lengths_swapped = NOT_SWAPPED; 316 break; 317 318 case 543: 319 ps->lengths_swapped = SWAPPED; 320 break; 321 322 default: 323 ps->lengths_swapped = NOT_SWAPPED; 324 break; 325 } 326 327 if (magic == KUZNETZOV_TCPDUMP_MAGIC) { 328 /* 329 * XXX - the patch that's in some versions of libpcap 330 * changes the packet header but not the magic number, 331 * and some other versions with this magic number have 332 * some extra debugging information in the packet header; 333 * we'd have to use some hacks^H^H^H^H^Hheuristics to 334 * detect those variants. 335 * 336 * Ethereal does that, but it does so by trying to read 337 * the first two packets of the file with each of the 338 * record header formats. That currently means it seeks 339 * backwards and retries the reads, which doesn't work 340 * on pipes. We want to be able to read from a pipe, so 341 * that strategy won't work; we'd have to buffer some 342 * data ourselves and read from that buffer in order to 343 * make that work. 344 */ 345 ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); 346 347 if (p->linktype == DLT_EN10MB) { 348 /* 349 * This capture might have been done in raw mode 350 * or cooked mode. 351 * 352 * If it was done in cooked mode, p->snapshot was 353 * passed to recvfrom() as the buffer size, meaning 354 * that the most packet data that would be copied 355 * would be p->snapshot. However, a faked Ethernet 356 * header would then have been added to it, so the 357 * most data that would be in a packet in the file 358 * would be p->snapshot + 14. 359 * 360 * We can't easily tell whether the capture was done 361 * in raw mode or cooked mode, so we'll assume it was 362 * cooked mode, and add 14 to the snapshot length. 363 * That means that, for a raw capture, the snapshot 364 * length will be misleading if you use it to figure 365 * out why a capture doesn't have all the packet data, 366 * but there's not much we can do to avoid that. 367 */ 368 p->snapshot += 14; 369 } 370 } else 371 ps->hdrsize = sizeof(struct pcap_sf_pkthdr); 372 373 /* 374 * Allocate a buffer for the packet data. 375 */ 376 p->bufsize = p->snapshot; 377 if (p->bufsize <= 0) { 378 /* 379 * Bogus snapshot length; use the maximum as a fallback. 380 */ 381 p->bufsize = MAXIMUM_SNAPLEN; 382 } 383 p->buffer = malloc(p->bufsize); 384 if (p->buffer == NULL) { 385 snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); 386 free(p); 387 *err = 1; 388 return (NULL); 389 } 390 391 p->cleanup_op = sf_cleanup; 392 393 return (p); 394 } 395 396 /* 397 * Read and return the next packet from the savefile. Return the header 398 * in hdr and a pointer to the contents in data. Return 0 on success, 1 399 * if there were no more packets, and -1 on an error. 400 */ 401 static int 402 pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) 403 { 404 struct pcap_sf *ps = p->priv; 405 struct pcap_sf_patched_pkthdr sf_hdr; 406 FILE *fp = p->rfile; 407 size_t amt_read; 408 bpf_u_int32 t; 409 410 /* 411 * Read the packet header; the structure we use as a buffer 412 * is the longer structure for files generated by the patched 413 * libpcap, but if the file has the magic number for an 414 * unpatched libpcap we only read as many bytes as the regular 415 * header has. 416 */ 417 amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); 418 if (amt_read != ps->hdrsize) { 419 if (ferror(fp)) { 420 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 421 "error reading dump file: %s", 422 pcap_strerror(errno)); 423 return (-1); 424 } else { 425 if (amt_read != 0) { 426 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 427 "truncated dump file; tried to read %lu header bytes, only got %lu", 428 (unsigned long)ps->hdrsize, 429 (unsigned long)amt_read); 430 return (-1); 431 } 432 /* EOF */ 433 return (1); 434 } 435 } 436 437 if (p->swapped) { 438 /* these were written in opposite byte order */ 439 hdr->caplen = SWAPLONG(sf_hdr.caplen); 440 hdr->len = SWAPLONG(sf_hdr.len); 441 hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); 442 hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); 443 } else { 444 hdr->caplen = sf_hdr.caplen; 445 hdr->len = sf_hdr.len; 446 hdr->ts.tv_sec = sf_hdr.ts.tv_sec; 447 hdr->ts.tv_usec = sf_hdr.ts.tv_usec; 448 } 449 450 switch (ps->scale_type) { 451 452 case PASS_THROUGH: 453 /* 454 * Just pass the time stamp through. 455 */ 456 break; 457 458 case SCALE_UP: 459 /* 460 * File has microseconds, user wants nanoseconds; convert 461 * it. 462 */ 463 hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; 464 break; 465 466 case SCALE_DOWN: 467 /* 468 * File has nanoseconds, user wants microseconds; convert 469 * it. 470 */ 471 hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; 472 break; 473 } 474 475 /* Swap the caplen and len fields, if necessary. */ 476 switch (ps->lengths_swapped) { 477 478 case NOT_SWAPPED: 479 break; 480 481 case MAYBE_SWAPPED: 482 if (hdr->caplen <= hdr->len) { 483 /* 484 * The captured length is <= the actual length, 485 * so presumably they weren't swapped. 486 */ 487 break; 488 } 489 /* FALLTHROUGH */ 490 491 case SWAPPED: 492 t = hdr->caplen; 493 hdr->caplen = hdr->len; 494 hdr->len = t; 495 break; 496 } 497 498 if ((int)hdr->caplen > p->bufsize) { 499 /* 500 * This can happen due to Solaris 2.3 systems tripping 501 * over the BUFMOD problem and not setting the snapshot 502 * correctly in the savefile header. If the caplen isn't 503 * grossly wrong, try to salvage. 504 */ 505 static u_char *tp = NULL; 506 static size_t tsize = 0; 507 508 if (hdr->caplen > MAXIMUM_SNAPLEN) { 509 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 510 "bogus savefile header"); 511 return (-1); 512 } 513 514 if (tsize < hdr->caplen) { 515 tsize = ((hdr->caplen + 1023) / 1024) * 1024; 516 if (tp != NULL) 517 free((u_char *)tp); 518 tp = (u_char *)malloc(tsize); 519 if (tp == NULL) { 520 tsize = 0; 521 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 522 "BUFMOD hack malloc"); 523 return (-1); 524 } 525 } 526 amt_read = fread((char *)tp, 1, hdr->caplen, fp); 527 if (amt_read != hdr->caplen) { 528 if (ferror(fp)) { 529 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 530 "error reading dump file: %s", 531 pcap_strerror(errno)); 532 } else { 533 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 534 "truncated dump file; tried to read %u captured bytes, only got %lu", 535 hdr->caplen, (unsigned long)amt_read); 536 } 537 return (-1); 538 } 539 /* 540 * We can only keep up to p->bufsize bytes. Since 541 * caplen > p->bufsize is exactly how we got here, 542 * we know we can only keep the first p->bufsize bytes 543 * and must drop the remainder. Adjust caplen accordingly, 544 * so we don't get confused later as to how many bytes we 545 * have to play with. 546 */ 547 hdr->caplen = p->bufsize; 548 memcpy(p->buffer, (char *)tp, p->bufsize); 549 } else { 550 /* read the packet itself */ 551 amt_read = fread(p->buffer, 1, hdr->caplen, fp); 552 if (amt_read != hdr->caplen) { 553 if (ferror(fp)) { 554 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 555 "error reading dump file: %s", 556 pcap_strerror(errno)); 557 } else { 558 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 559 "truncated dump file; tried to read %u captured bytes, only got %lu", 560 hdr->caplen, (unsigned long)amt_read); 561 } 562 return (-1); 563 } 564 } 565 *data = p->buffer; 566 567 if (p->swapped) 568 swap_pseudo_headers(p->linktype, hdr, *data); 569 570 return (0); 571 } 572 573 static int 574 sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen) 575 { 576 struct pcap_file_header hdr; 577 578 hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; 579 hdr.version_major = PCAP_VERSION_MAJOR; 580 hdr.version_minor = PCAP_VERSION_MINOR; 581 582 hdr.thiszone = thiszone; 583 hdr.snaplen = snaplen; 584 hdr.sigfigs = 0; 585 hdr.linktype = linktype; 586 587 if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) 588 return (-1); 589 590 return (0); 591 } 592 593 /* 594 * Output a packet to the initialized dump file. 595 */ 596 void 597 pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) 598 { 599 register FILE *f; 600 struct pcap_sf_pkthdr sf_hdr; 601 602 f = (FILE *)user; 603 sf_hdr.ts.tv_sec = h->ts.tv_sec; 604 sf_hdr.ts.tv_usec = h->ts.tv_usec; 605 sf_hdr.caplen = h->caplen; 606 sf_hdr.len = h->len; 607 /* XXX we should check the return status */ 608 (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f); 609 (void)fwrite(sp, h->caplen, 1, f); 610 } 611 612 static pcap_dumper_t * 613 pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) 614 { 615 616 #if defined(WIN32) || defined(MSDOS) 617 /* 618 * If we're writing to the standard output, put it in binary 619 * mode, as savefiles are binary files. 620 * 621 * Otherwise, we turn off buffering. 622 * XXX - why? And why not on the standard output? 623 */ 624 if (f == stdout) 625 SET_BINMODE(f); 626 else 627 setbuf(f, NULL); 628 #endif 629 if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { 630 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", 631 fname, pcap_strerror(errno)); 632 if (f != stdout) 633 (void)fclose(f); 634 return (NULL); 635 } 636 return ((pcap_dumper_t *)f); 637 } 638 639 /* 640 * Initialize so that sf_write() will output to the file named 'fname'. 641 */ 642 pcap_dumper_t * 643 pcap_dump_open(pcap_t *p, const char *fname) 644 { 645 FILE *f; 646 int linktype; 647 648 /* 649 * If this pcap_t hasn't been activated, it doesn't have a 650 * link-layer type, so we can't use it. 651 */ 652 if (!p->activated) { 653 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 654 "%s: not-yet-activated pcap_t passed to pcap_dump_open", 655 fname); 656 return (NULL); 657 } 658 linktype = dlt_to_linktype(p->linktype); 659 if (linktype == -1) { 660 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 661 "%s: link-layer type %d isn't supported in savefiles", 662 fname, p->linktype); 663 return (NULL); 664 } 665 linktype |= p->linktype_ext; 666 667 if (fname[0] == '-' && fname[1] == '\0') { 668 f = stdout; 669 fname = "standard output"; 670 } else { 671 #if !defined(WIN32) && !defined(MSDOS) 672 f = fopen(fname, "w"); 673 #else 674 f = fopen(fname, "wb"); 675 #endif 676 if (f == NULL) { 677 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 678 fname, pcap_strerror(errno)); 679 return (NULL); 680 } 681 } 682 return (pcap_setup_dump(p, linktype, f, fname)); 683 } 684 685 /* 686 * Initialize so that sf_write() will output to the given stream. 687 */ 688 pcap_dumper_t * 689 pcap_dump_fopen(pcap_t *p, FILE *f) 690 { 691 int linktype; 692 693 linktype = dlt_to_linktype(p->linktype); 694 if (linktype == -1) { 695 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 696 "stream: link-layer type %d isn't supported in savefiles", 697 p->linktype); 698 return (NULL); 699 } 700 linktype |= p->linktype_ext; 701 702 return (pcap_setup_dump(p, linktype, f, "stream")); 703 } 704 705 pcap_dumper_t * 706 pcap_dump_open_append(pcap_t *p, const char *fname) 707 { 708 FILE *f; 709 int linktype; 710 int amt_read; 711 struct pcap_file_header ph; 712 713 linktype = dlt_to_linktype(p->linktype); 714 if (linktype == -1) { 715 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 716 "%s: link-layer type %d isn't supported in savefiles", 717 fname, linktype); 718 return (NULL); 719 } 720 if (fname[0] == '-' && fname[1] == '\0') 721 return (pcap_setup_dump(p, linktype, stdout, "standard output")); 722 723 #if !defined(WIN32) && !defined(MSDOS) 724 f = fopen(fname, "r+"); 725 #else 726 f = fopen(fname, "rb+"); 727 #endif 728 if (f == NULL) { 729 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 730 fname, pcap_strerror(errno)); 731 return (NULL); 732 } 733 734 /* 735 * Try to read a pcap header. 736 */ 737 amt_read = fread(&ph, 1, sizeof (ph), f); 738 if (amt_read != sizeof (ph)) { 739 if (ferror(f)) { 740 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 741 fname, pcap_strerror(errno)); 742 fclose(f); 743 return (NULL); 744 } else if (feof(f) && amt_read > 0) { 745 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 746 "%s: truncated pcap file header", fname); 747 fclose(f); 748 return (NULL); 749 } 750 } 751 752 #if defined(WIN32) || defined(MSDOS) 753 /* 754 * We turn off buffering. 755 * XXX - why? And why not on the standard output? 756 */ 757 setbuf(f, NULL); 758 #endif 759 760 /* 761 * If a header is already present and: 762 * 763 * it's not for a pcap file of the appropriate resolution 764 * and the right byte order for this machine; 765 * 766 * the link-layer header types don't match; 767 * 768 * the snapshot lengths don't match; 769 * 770 * return an error. 771 */ 772 if (amt_read > 0) { 773 /* 774 * A header is already present. 775 * Do the checks. 776 */ 777 switch (ph.magic) { 778 779 case TCPDUMP_MAGIC: 780 if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { 781 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 782 "%s: different time stamp precision, cannot append to file", fname); 783 fclose(f); 784 return (NULL); 785 } 786 break; 787 788 case NSEC_TCPDUMP_MAGIC: 789 if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { 790 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 791 "%s: different time stamp precision, cannot append to file", fname); 792 fclose(f); 793 return (NULL); 794 } 795 break; 796 797 case SWAPLONG(TCPDUMP_MAGIC): 798 case SWAPLONG(NSEC_TCPDUMP_MAGIC): 799 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 800 "%s: different byte order, cannot append to file", fname); 801 fclose(f); 802 return (NULL); 803 804 case KUZNETZOV_TCPDUMP_MAGIC: 805 case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): 806 case NAVTEL_TCPDUMP_MAGIC: 807 case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): 808 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 809 "%s: not a pcap file to which we can append", fname); 810 fclose(f); 811 return (NULL); 812 813 default: 814 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 815 "%s: not a pcap file", fname); 816 fclose(f); 817 return (NULL); 818 } 819 820 /* 821 * Good version? 822 */ 823 if (ph.version_major != PCAP_VERSION_MAJOR || 824 ph.version_minor != PCAP_VERSION_MINOR) { 825 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 826 "%s: version is %u.%u, cannot append to file", fname, 827 ph.version_major, ph.version_minor); 828 fclose(f); 829 return (NULL); 830 } 831 if (linktype != (int)ph.linktype) { 832 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 833 "%s: different linktype, cannot append to file", fname); 834 fclose(f); 835 return (NULL); 836 } 837 if (p->snapshot != (int)ph.snaplen) { 838 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 839 "%s: different snaplen, cannot append to file", fname); 840 fclose(f); 841 return (NULL); 842 } 843 } else { 844 /* 845 * A header isn't present; attempt to write it. 846 */ 847 if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { 848 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", 849 fname, pcap_strerror(errno)); 850 (void)fclose(f); 851 return (NULL); 852 } 853 } 854 855 /* 856 * Start writing at the end of the file. 857 */ 858 if (fseek(f, 0, SEEK_END) == -1) { 859 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't seek to end of %s: %s", 860 fname, pcap_strerror(errno)); 861 (void)fclose(f); 862 return (NULL); 863 } 864 return ((pcap_dumper_t *)f); 865 } 866 867 FILE * 868 pcap_dump_file(pcap_dumper_t *p) 869 { 870 return ((FILE *)p); 871 } 872 873 long 874 pcap_dump_ftell(pcap_dumper_t *p) 875 { 876 return (ftell((FILE *)p)); 877 } 878 879 int 880 pcap_dump_flush(pcap_dumper_t *p) 881 { 882 883 if (fflush((FILE *)p) == EOF) 884 return (-1); 885 else 886 return (0); 887 } 888 889 void 890 pcap_dump_close(pcap_dumper_t *p) 891 { 892 893 #ifdef notyet 894 if (ferror((FILE *)p)) 895 return-an-error; 896 /* XXX should check return from fclose() too */ 897 #endif 898 (void)fclose((FILE *)p); 899 } 900