sf-pcap.c revision 214455
1184610Salfred/* 2184610Salfred * Copyright (c) 1993, 1994, 1995, 1996, 1997 3184610Salfred * The Regents of the University of California. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that: (1) source code distributions 7184610Salfred * retain the above copyright notice and this paragraph in its entirety, (2) 8184610Salfred * distributions including binary code include the above copyright notice and 9184610Salfred * this paragraph in its entirety in the documentation or other materials 10184610Salfred * provided with the distribution, and (3) all advertising materials mentioning 11184610Salfred * features or use of this software display the following acknowledgement: 12184610Salfred * ``This product includes software developed by the University of California, 13184610Salfred * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14184610Salfred * the University nor the names of its contributors may be used to endorse 15184610Salfred * or promote products derived from this software without specific prior 16184610Salfred * written permission. 17184610Salfred * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18184610Salfred * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19184610Salfred * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20184610Salfred * 21184610Salfred * sf-pcap.c - libpcap-file-format-specific code from savefile.c 22184610Salfred * Extraction/creation by Jeffrey Mogul, DECWRL 23184610Salfred * Modified by Steve McCanne, LBL. 24184610Salfred * 25184610Salfred * Used to save the received packet headers, after filtering, to 26184610Salfred * a file, and then read them later. 27190754Sthompsa * The first record in the file contains saved values for the machine 28184610Salfred * dependent values so we can print the dump file on any architecture. 29194677Sthompsa */ 30194677Sthompsa 31194677Sthompsa#ifndef lint 32194677Sthompsastatic const char rcsid[] _U_ = 33194677Sthompsa "@(#) $Header$ (LBL)"; 34194677Sthompsa#endif 35194677Sthompsa 36194677Sthompsa#ifdef HAVE_CONFIG_H 37194677Sthompsa#include "config.h" 38194677Sthompsa#endif 39194677Sthompsa 40194677Sthompsa#ifdef WIN32 41194677Sthompsa#include <pcap-stdinc.h> 42194677Sthompsa#else /* WIN32 */ 43194677Sthompsa#if HAVE_INTTYPES_H 44194677Sthompsa#include <inttypes.h> 45194677Sthompsa#elif HAVE_STDINT_H 46194677Sthompsa#include <stdint.h> 47194677Sthompsa#endif 48188942Sthompsa#ifdef HAVE_SYS_BITYPES_H 49194677Sthompsa#include <sys/bitypes.h> 50194677Sthompsa#endif 51188942Sthompsa#include <sys/types.h> 52188942Sthompsa#endif /* WIN32 */ 53184610Salfred 54194228Sthompsa#include <errno.h> 55184610Salfred#include <memory.h> 56188942Sthompsa#include <stdio.h> 57188942Sthompsa#include <stdlib.h> 58188942Sthompsa#include <string.h> 59188942Sthompsa 60188942Sthompsa#include "pcap-int.h" 61188942Sthompsa 62188942Sthompsa#include "pcap-common.h" 63188942Sthompsa 64188942Sthompsa#ifdef HAVE_OS_PROTO_H 65184610Salfred#include "os-proto.h" 66188942Sthompsa#endif 67188942Sthompsa 68184610Salfred#include "sf-pcap.h" 69184610Salfred 70225000Shselasky/* 71225000Shselasky * Setting O_BINARY on DOS/Windows is a bit tricky 72225000Shselasky */ 73225000Shselasky#if defined(WIN32) 74225000Shselasky #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) 75207077Sthompsa#elif defined(MSDOS) 76194228Sthompsa #if defined(__HIGHC__) 77194228Sthompsa #define SET_BINMODE(f) setmode(f, O_BINARY) 78184610Salfred #else 79192502Sthompsa #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) 80194228Sthompsa #endif 81192502Sthompsa#endif 82194228Sthompsa 83184610Salfred/* 84208018Sthompsa * Standard libpcap format. 85208018Sthompsa */ 86208018Sthompsa#define TCPDUMP_MAGIC 0xa1b2c3d4 87208018Sthompsa 88208018Sthompsa/* 89208018Sthompsa * Alexey Kuznetzov's modified libpcap format. 90208018Sthompsa */ 91208018Sthompsa#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 92208018Sthompsa 93208018Sthompsa/* 94208018Sthompsa * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt> 95208018Sthompsa * for another modified format. 96208018Sthompsa */ 97208018Sthompsa#define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd 98208018Sthompsa 99208018Sthompsa/* 100208018Sthompsa * Navtel Communcations' format, with nanosecond timestamps, 101208018Sthompsa * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>. 102208018Sthompsa */ 103208018Sthompsa#define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d 104208018Sthompsa 105208018Sthompsa/* 106208018Sthompsa * Normal libpcap format, except for seconds/nanoseconds timestamps, 107208018Sthompsa * as per a request by Ulf Lamping <ulf.lamping@web.de> 108208018Sthompsa */ 109208018Sthompsa#define NSEC_TCPDUMP_MAGIC 0xa1b23c4d 110208018Sthompsa 111208018Sthompsa/* 112208018Sthompsa * Mechanism for storing information about a capture in the upper 113208018Sthompsa * 6 bits of a linktype value in a capture file. 114208018Sthompsa * 115208018Sthompsa * LT_LINKTYPE_EXT(x) extracts the additional information. 116208018Sthompsa * 117208018Sthompsa * The rest of the bits are for a value describing the link-layer 118208018Sthompsa * value. LT_LINKTYPE(x) extracts that value. 119208018Sthompsa */ 120208018Sthompsa#define LT_LINKTYPE(x) ((x) & 0x03FFFFFF) 121208018Sthompsa#define LT_LINKTYPE_EXT(x) ((x) & 0xFC000000) 122208018Sthompsa 123208018Sthompsastatic int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); 124208018Sthompsa 125208018Sthompsa/* 126208018Sthompsa * Check whether this is a pcap savefile and, if it is, extract the 127208018Sthompsa * relevant information from the header. 128208018Sthompsa */ 129208018Sthompsaint 130208018Sthompsapcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) 131184610Salfred{ 132208018Sthompsa struct pcap_file_header hdr; 133208018Sthompsa size_t amt_read; 134208018Sthompsa 135208018Sthompsa /* 136208018Sthompsa * Check whether the first 4 bytes of the file are the magic 137208018Sthompsa * number for a pcap savefile, or for a byte-swapped pcap 138208018Sthompsa * savefile. 139208018Sthompsa */ 140208018Sthompsa if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) { 141208018Sthompsa magic = SWAPLONG(magic); 142208018Sthompsa if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) 143208018Sthompsa return (0); /* nope */ 144208018Sthompsa p->sf.swapped = 1; 145208018Sthompsa } 146208018Sthompsa 147208018Sthompsa /* 148208018Sthompsa * They are. Put the magic number in the header, and read 149208018Sthompsa * the rest of the header. 150208018Sthompsa */ 151208018Sthompsa hdr.magic = magic; 152208018Sthompsa amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, 153208018Sthompsa sizeof(hdr) - sizeof(hdr.magic), fp); 154208018Sthompsa if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { 155208018Sthompsa if (ferror(fp)) { 156208018Sthompsa snprintf(errbuf, PCAP_ERRBUF_SIZE, 157208018Sthompsa "error reading dump file: %s", 158208018Sthompsa pcap_strerror(errno)); 159208018Sthompsa } else { 160208018Sthompsa snprintf(errbuf, PCAP_ERRBUF_SIZE, 161208018Sthompsa "truncated dump file; tried to read %lu file header bytes, only got %lu", 162208018Sthompsa (unsigned long)sizeof(hdr), 163208018Sthompsa (unsigned long)amt_read); 164208018Sthompsa } 165208018Sthompsa return (-1); 166208018Sthompsa } 167208018Sthompsa 168208018Sthompsa /* 169208018Sthompsa * If it's a byte-swapped capture file, byte-swap the header. 170208018Sthompsa */ 171208018Sthompsa if (p->sf.swapped) { 172208018Sthompsa hdr.version_major = SWAPSHORT(hdr.version_major); 173208018Sthompsa hdr.version_minor = SWAPSHORT(hdr.version_minor); 174208018Sthompsa hdr.thiszone = SWAPLONG(hdr.thiszone); 175208018Sthompsa hdr.sigfigs = SWAPLONG(hdr.sigfigs); 176208018Sthompsa hdr.snaplen = SWAPLONG(hdr.snaplen); 177208018Sthompsa hdr.linktype = SWAPLONG(hdr.linktype); 178208018Sthompsa } 179208018Sthompsa 180208018Sthompsa if (hdr.version_major < PCAP_VERSION_MAJOR) { 181208018Sthompsa snprintf(errbuf, PCAP_ERRBUF_SIZE, 182208018Sthompsa "archaic pcap savefile format"); 183208018Sthompsa return (-1); 184208018Sthompsa } 185208018Sthompsa p->sf.version_major = hdr.version_major; 186208018Sthompsa p->sf.version_minor = hdr.version_minor; 187208018Sthompsa p->tzoff = hdr.thiszone; 188208018Sthompsa p->snapshot = hdr.snaplen; 189208018Sthompsa p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); 190208018Sthompsa p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); 191208018Sthompsa 192208018Sthompsa p->sf.next_packet_op = pcap_next_packet; 193208018Sthompsa 194208018Sthompsa /* 195208018Sthompsa * We interchanged the caplen and len fields at version 2.3, 196194228Sthompsa * in order to match the bpf header layout. But unfortunately 197184610Salfred * some files were written with version 2.3 in their headers 198184610Salfred * but without the interchanged fields. 199184610Salfred * 200184610Salfred * In addition, DG/UX tcpdump writes out files with a version 201184610Salfred * number of 543.0, and with the caplen and len fields in the 202194677Sthompsa * pre-2.3 order. 203184610Salfred */ 204184610Salfred switch (hdr.version_major) { 205184610Salfred 206184610Salfred case 2: 207184610Salfred if (hdr.version_minor < 3) 208184610Salfred p->sf.lengths_swapped = SWAPPED; 209184610Salfred else if (hdr.version_minor == 3) 210194228Sthompsa p->sf.lengths_swapped = MAYBE_SWAPPED; 211184610Salfred else 212184610Salfred p->sf.lengths_swapped = NOT_SWAPPED; 213207079Sthompsa break; 214184610Salfred 215184610Salfred case 543: 216184610Salfred p->sf.lengths_swapped = SWAPPED; 217184610Salfred break; 218184610Salfred 219194228Sthompsa default: 220184610Salfred p->sf.lengths_swapped = NOT_SWAPPED; 221184610Salfred break; 222184610Salfred } 223184610Salfred 224194677Sthompsa if (magic == KUZNETZOV_TCPDUMP_MAGIC) { 225184610Salfred /* 226192984Sthompsa * XXX - the patch that's in some versions of libpcap 227192984Sthompsa * changes the packet header but not the magic number, 228193644Sthompsa * and some other versions with this magic number have 229193644Sthompsa * some extra debugging information in the packet header; 230193644Sthompsa * we'd have to use some hacks^H^H^H^H^Hheuristics to 231190731Sthompsa * detect those variants. 232184610Salfred * 233187173Sthompsa * Ethereal does that, but it does so by trying to read 234184610Salfred * the first two packets of the file with each of the 235187173Sthompsa * record header formats. That currently means it seeks 236187173Sthompsa * backwards and retries the reads, which doesn't work 237193644Sthompsa * on pipes. We want to be able to read from a pipe, so 238184610Salfred * that strategy won't work; we'd have to buffer some 239193644Sthompsa * data ourselves and read from that buffer in order to 240193644Sthompsa * make that work. 241193644Sthompsa */ 242193644Sthompsa p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr); 243193318Sthompsa 244184610Salfred if (p->linktype == DLT_EN10MB) { 245184610Salfred /* 246225000Shselasky * This capture might have been done in raw mode 247222786Shselasky * or cooked mode. 248222786Shselasky * 249222786Shselasky * If it was done in cooked mode, p->snapshot was 250193644Sthompsa * passed to recvfrom() as the buffer size, meaning 251193318Sthompsa * that the most packet data that would be copied 252193644Sthompsa * would be p->snapshot. However, a faked Ethernet 253193644Sthompsa * header would then have been added to it, so the 254193644Sthompsa * most data that would be in a packet in the file 255193644Sthompsa * would be p->snapshot + 14. 256213435Shselasky * 257213435Shselasky * We can't easily tell whether the capture was done 258184610Salfred * in raw mode or cooked mode, so we'll assume it was 259194228Sthompsa * cooked mode, and add 14 to the snapshot length. 260193644Sthompsa * That means that, for a raw capture, the snapshot 261184610Salfred * length will be misleading if you use it to figure 262193644Sthompsa * out why a capture doesn't have all the packet data, 263184610Salfred * but there's not much we can do to avoid that. 264184610Salfred */ 265184610Salfred p->snapshot += 14; 266193318Sthompsa } 267193644Sthompsa } else 268193644Sthompsa p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr); 269193644Sthompsa 270193644Sthompsa /* 271193644Sthompsa * Allocate a buffer for the packet data. 272184610Salfred */ 273184610Salfred p->bufsize = p->snapshot; 274184610Salfred if (p->bufsize <= 0) 275184610Salfred p->bufsize = BPF_MAXBUFSIZE; 276184610Salfred p->buffer = malloc(p->bufsize); 277184610Salfred if (p->buffer == NULL) { 278193644Sthompsa snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); 279184610Salfred return (-1); 280184610Salfred } 281184610Salfred 282184610Salfred return (1); 283184610Salfred} 284194228Sthompsa 285184610Salfred/* 286184610Salfred * Read and return the next packet from the savefile. Return the header 287194677Sthompsa * in hdr and a pointer to the contents in data. Return 0 on success, 1 288184610Salfred * if there were no more packets, and -1 on an error. 289187173Sthompsa */ 290184610Salfredstatic int 291194228Sthompsapcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) 292184610Salfred{ 293187173Sthompsa struct pcap_sf_patched_pkthdr sf_hdr; 294184610Salfred FILE *fp = p->sf.rfile; 295184610Salfred size_t amt_read; 296193644Sthompsa bpf_u_int32 t; 297193318Sthompsa 298193318Sthompsa /* 299184610Salfred * Read the packet header; the structure we use as a buffer 300184610Salfred * is the longer structure for files generated by the patched 301222786Shselasky * libpcap, but if the file has the magic number for an 302184610Salfred * unpatched libpcap we only read as many bytes as the regular 303222786Shselasky * header has. 304222786Shselasky */ 305225000Shselasky amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp); 306225000Shselasky if (amt_read != p->sf.hdrsize) { 307225000Shselasky if (ferror(fp)) { 308225000Shselasky snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 309225000Shselasky "error reading dump file: %s", 310225000Shselasky pcap_strerror(errno)); 311225000Shselasky return (-1); 312222786Shselasky } else { 313222786Shselasky if (amt_read != 0) { 314222786Shselasky snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 315222786Shselasky "truncated dump file; tried to read %lu header bytes, only got %lu", 316222786Shselasky (unsigned long)p->sf.hdrsize, 317222786Shselasky (unsigned long)amt_read); 318222786Shselasky return (-1); 319222786Shselasky } 320222786Shselasky /* EOF */ 321222786Shselasky return (1); 322222786Shselasky } 323222786Shselasky } 324222786Shselasky 325184610Salfred if (p->sf.swapped) { 326184610Salfred /* these were written in opposite byte order */ 327184610Salfred hdr->caplen = SWAPLONG(sf_hdr.caplen); 328184610Salfred hdr->len = SWAPLONG(sf_hdr.len); 329193644Sthompsa hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); 330193644Sthompsa hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); 331187173Sthompsa } else { 332184610Salfred hdr->caplen = sf_hdr.caplen; 333184610Salfred hdr->len = sf_hdr.len; 334193045Sthompsa hdr->ts.tv_sec = sf_hdr.ts.tv_sec; 335194228Sthompsa hdr->ts.tv_usec = sf_hdr.ts.tv_usec; 336191402Sthompsa } 337191402Sthompsa /* Swap the caplen and len fields, if necessary. */ 338192499Sthompsa switch (p->sf.lengths_swapped) { 339194228Sthompsa 340191402Sthompsa case NOT_SWAPPED: 341191402Sthompsa break; 342191402Sthompsa 343191402Sthompsa case MAYBE_SWAPPED: 344191402Sthompsa if (hdr->caplen <= hdr->len) { 345191402Sthompsa /* 346184610Salfred * The captured length is <= the actual length, 347194228Sthompsa * so presumably they weren't swapped. 348184610Salfred */ 349184610Salfred break; 350184610Salfred } 351192984Sthompsa /* FALLTHROUGH */ 352184610Salfred 353184610Salfred case SWAPPED: 354184610Salfred t = hdr->caplen; 355184610Salfred hdr->caplen = hdr->len; 356184610Salfred hdr->len = t; 357184610Salfred break; 358184610Salfred } 359184610Salfred 360184610Salfred if (hdr->caplen > p->bufsize) { 361184610Salfred /* 362184610Salfred * This can happen due to Solaris 2.3 systems tripping 363184610Salfred * over the BUFMOD problem and not setting the snapshot 364184610Salfred * correctly in the savefile header. If the caplen isn't 365184610Salfred * grossly wrong, try to salvage. 366184610Salfred */ 367184610Salfred static u_char *tp = NULL; 368184610Salfred static size_t tsize = 0; 369184610Salfred 370184610Salfred if (hdr->caplen > 65535) { 371184610Salfred snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 372184610Salfred "bogus savefile header"); 373184610Salfred return (-1); 374184610Salfred } 375184610Salfred 376184610Salfred if (tsize < hdr->caplen) { 377184610Salfred tsize = ((hdr->caplen + 1023) / 1024) * 1024; 378184610Salfred if (tp != NULL) 379184610Salfred free((u_char *)tp); 380184610Salfred tp = (u_char *)malloc(tsize); 381184610Salfred if (tp == NULL) { 382184610Salfred tsize = 0; 383184610Salfred snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 384184610Salfred "BUFMOD hack malloc"); 385184610Salfred return (-1); 386184610Salfred } 387184610Salfred } 388184610Salfred amt_read = fread((char *)tp, 1, hdr->caplen, fp); 389184610Salfred if (amt_read != hdr->caplen) { 390184610Salfred if (ferror(fp)) { 391184610Salfred snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 392184610Salfred "error reading dump file: %s", 393184610Salfred pcap_strerror(errno)); 394194228Sthompsa } else { 395184610Salfred snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 396184610Salfred "truncated dump file; tried to read %u captured bytes, only got %lu", 397184610Salfred hdr->caplen, (unsigned long)amt_read); 398184610Salfred } 399184610Salfred return (-1); 400184610Salfred } 401193045Sthompsa /* 402194228Sthompsa * We can only keep up to p->bufsize bytes. Since 403192984Sthompsa * caplen > p->bufsize is exactly how we got here, 404193045Sthompsa * we know we can only keep the first p->bufsize bytes 405184610Salfred * and must drop the remainder. Adjust caplen accordingly, 406208018Sthompsa * so we don't get confused later as to how many bytes we 407208018Sthompsa * have to play with. 408208018Sthompsa */ 409193045Sthompsa hdr->caplen = p->bufsize; 410192984Sthompsa memcpy(p->buffer, (char *)tp, p->bufsize); 411184610Salfred } else { 412184610Salfred /* read the packet itself */ 413193045Sthompsa amt_read = fread(p->buffer, 1, hdr->caplen, fp); 414193045Sthompsa if (amt_read != hdr->caplen) { 415193045Sthompsa if (ferror(fp)) { 416184610Salfred snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 417184610Salfred "error reading dump file: %s", 418208018Sthompsa pcap_strerror(errno)); 419208008Sthompsa } else { 420184610Salfred snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 421184610Salfred "truncated dump file; tried to read %u captured bytes, only got %lu", 422184610Salfred hdr->caplen, (unsigned long)amt_read); 423184610Salfred } 424184610Salfred return (-1); 425184610Salfred } 426184610Salfred } 427184610Salfred *data = p->buffer; 428184610Salfred 429184610Salfred if (p->sf.swapped) { 430184610Salfred /* 431208008Sthompsa * Convert pseudo-headers from the byte order of 432208008Sthompsa * the host on which the file was saved to our 433184610Salfred * byte order, as necessary. 434184610Salfred */ 435184610Salfred switch (p->linktype) { 436184610Salfred 437184610Salfred case DLT_USB_LINUX: 438184610Salfred swap_linux_usb_header(hdr, *data, 0); 439184610Salfred break; 440191494Sthompsa 441191494Sthompsa case DLT_USB_LINUX_MMAPPED: 442191494Sthompsa swap_linux_usb_header(hdr, *data, 1); 443191494Sthompsa break; 444191494Sthompsa } 445191494Sthompsa } 446184610Salfred 447184610Salfred return (0); 448184610Salfred} 449184610Salfred 450190735Sthompsastatic int 451184610Salfredsf_write_header(FILE *fp, int linktype, int thiszone, int snaplen) 452190735Sthompsa{ 453190180Sthompsa struct pcap_file_header hdr; 454190180Sthompsa 455190180Sthompsa hdr.magic = TCPDUMP_MAGIC; 456190180Sthompsa hdr.version_major = PCAP_VERSION_MAJOR; 457208008Sthompsa hdr.version_minor = PCAP_VERSION_MINOR; 458184610Salfred 459208008Sthompsa hdr.thiszone = thiszone; 460184610Salfred hdr.snaplen = snaplen; 461208008Sthompsa hdr.sigfigs = 0; 462184610Salfred hdr.linktype = linktype; 463208008Sthompsa 464208008Sthompsa if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) 465208008Sthompsa return (-1); 466208008Sthompsa 467208008Sthompsa return (0); 468208008Sthompsa} 469208008Sthompsa 470184610Salfred/* 471184610Salfred * Output a packet to the initialized dump file. 472184610Salfred */ 473207079Sthompsavoid 474184610Salfredpcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) 475194228Sthompsa{ 476190735Sthompsa register FILE *f; 477191402Sthompsa struct pcap_sf_pkthdr sf_hdr; 478191402Sthompsa 479190735Sthompsa f = (FILE *)user; 480191402Sthompsa sf_hdr.ts.tv_sec = h->ts.tv_sec; 481191402Sthompsa sf_hdr.ts.tv_usec = h->ts.tv_usec; 482191402Sthompsa sf_hdr.caplen = h->caplen; 483191402Sthompsa sf_hdr.len = h->len; 484190735Sthompsa /* XXX we should check the return status */ 485191402Sthompsa (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f); 486191402Sthompsa (void)fwrite(sp, h->caplen, 1, f); 487191402Sthompsa} 488191402Sthompsa 489190735Sthompsastatic pcap_dumper_t * 490190735Sthompsapcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) 491190735Sthompsa{ 492191402Sthompsa 493191402Sthompsa#if defined(WIN32) || defined(MSDOS) 494190735Sthompsa /* 495191402Sthompsa * If we're writing to the standard output, put it in binary 496190735Sthompsa * mode, as savefiles are binary files. 497190735Sthompsa * 498190735Sthompsa * Otherwise, we turn off buffering. 499190735Sthompsa * XXX - why? And why not on the standard output? 500190735Sthompsa */ 501191402Sthompsa if (f == stdout) 502190735Sthompsa SET_BINMODE(f); 503190735Sthompsa else 504190735Sthompsa setbuf(f, NULL); 505190735Sthompsa#endif 506191402Sthompsa if (sf_write_header(f, linktype, p->tzoff, p->snapshot) == -1) { 507190735Sthompsa snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", 508190735Sthompsa fname, pcap_strerror(errno)); 509190735Sthompsa if (f != stdout) 510190735Sthompsa (void)fclose(f); 511190735Sthompsa return (NULL); 512190735Sthompsa } 513190735Sthompsa return ((pcap_dumper_t *)f); 514191402Sthompsa} 515190735Sthompsa 516190735Sthompsa/* 517190735Sthompsa * Initialize so that sf_write() will output to the file named 'fname'. 518190735Sthompsa */ 519190735Sthompsapcap_dumper_t * 520191402Sthompsapcap_dump_open(pcap_t *p, const char *fname) 521190735Sthompsa{ 522191402Sthompsa FILE *f; 523190735Sthompsa int linktype; 524190735Sthompsa 525184610Salfred /* 526184610Salfred * If this pcap_t hasn't been activated, it doesn't have a 527184610Salfred * link-layer type, so we can't use it. 528207080Sthompsa */ 529184610Salfred if (!p->activated) { 530207080Sthompsa snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 531184610Salfred "%s: not-yet-activated pcap_t passed to pcap_dump_open", 532184610Salfred fname); 533184610Salfred return (NULL); 534184610Salfred } 535184610Salfred linktype = dlt_to_linktype(p->linktype); 536208018Sthompsa if (linktype == -1) { 537208018Sthompsa snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 538208018Sthompsa "%s: link-layer type %d isn't supported in savefiles", 539208018Sthompsa fname, p->linktype); 540208018Sthompsa return (NULL); 541208018Sthompsa } 542208018Sthompsa linktype |= p->linktype_ext; 543208018Sthompsa 544208018Sthompsa if (fname[0] == '-' && fname[1] == '\0') { 545184824Sthompsa f = stdout; 546184610Salfred fname = "standard output"; 547190734Sthompsa } else { 548184610Salfred#if !defined(WIN32) && !defined(MSDOS) 549190734Sthompsa f = fopen(fname, "w"); 550184610Salfred#else 551184610Salfred f = fopen(fname, "wb"); 552190734Sthompsa#endif 553190734Sthompsa if (f == NULL) { 554190734Sthompsa snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 555190734Sthompsa fname, pcap_strerror(errno)); 556190734Sthompsa return (NULL); 557184610Salfred } 558184610Salfred } 559184610Salfred return (pcap_setup_dump(p, linktype, f, fname)); 560184610Salfred} 561184610Salfred 562184610Salfred/* 563194228Sthompsa * Initialize so that sf_write() will output to the given stream. 564184610Salfred */ 565194677Sthompsapcap_dumper_t * 566184610Salfredpcap_dump_fopen(pcap_t *p, FILE *f) 567184610Salfred{ 568184610Salfred int linktype; 569208018Sthompsa 570194677Sthompsa linktype = dlt_to_linktype(p->linktype); 571184610Salfred if (linktype == -1) { 572208018Sthompsa snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 573208018Sthompsa "stream: link-layer type %d isn't supported in savefiles", 574208018Sthompsa p->linktype); 575208018Sthompsa return (NULL); 576208018Sthompsa } 577208018Sthompsa linktype |= p->linktype_ext; 578208018Sthompsa 579208018Sthompsa return (pcap_setup_dump(p, linktype, f, "stream")); 580208018Sthompsa} 581208018Sthompsa 582208018SthompsaFILE * 583208018Sthompsapcap_dump_file(pcap_dumper_t *p) 584208018Sthompsa{ 585208018Sthompsa return ((FILE *)p); 586208018Sthompsa} 587208018Sthompsa 588208018Sthompsalong 589208018Sthompsapcap_dump_ftell(pcap_dumper_t *p) 590208018Sthompsa{ 591208018Sthompsa return (ftell((FILE *)p)); 592194677Sthompsa} 593184610Salfred 594184610Salfredint 595184610Salfredpcap_dump_flush(pcap_dumper_t *p) 596190180Sthompsa{ 597184610Salfred 598184824Sthompsa if (fflush((FILE *)p) == EOF) 599194228Sthompsa return (-1); 600184610Salfred else 601184824Sthompsa return (0); 602184610Salfred} 603184610Salfred 604184610Salfredvoid 605184610Salfredpcap_dump_close(pcap_dumper_t *p) 606190180Sthompsa{ 607190180Sthompsa 608194228Sthompsa#ifdef notyet 609190180Sthompsa if (ferror((FILE *)p)) 610184610Salfred return-an-error; 611208018Sthompsa /* XXX should check return from fclose() too */ 612184610Salfred#endif 613208018Sthompsa (void)fclose((FILE *)p); 614184610Salfred} 615208018Sthompsa