1214455Srpaulo/* 2214455Srpaulo * Copyright (c) 1993, 1994, 1995, 1996, 1997 3214455Srpaulo * The Regents of the University of California. All rights reserved. 4214455Srpaulo * 5214455Srpaulo * Redistribution and use in source and binary forms, with or without 6214455Srpaulo * modification, are permitted provided that: (1) source code distributions 7214455Srpaulo * retain the above copyright notice and this paragraph in its entirety, (2) 8214455Srpaulo * distributions including binary code include the above copyright notice and 9214455Srpaulo * this paragraph in its entirety in the documentation or other materials 10214455Srpaulo * provided with the distribution, and (3) all advertising materials mentioning 11214455Srpaulo * features or use of this software display the following acknowledgement: 12214455Srpaulo * ``This product includes software developed by the University of California, 13214455Srpaulo * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14214455Srpaulo * the University nor the names of its contributors may be used to endorse 15214455Srpaulo * or promote products derived from this software without specific prior 16214455Srpaulo * written permission. 17214455Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18214455Srpaulo * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19214455Srpaulo * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20214455Srpaulo * 21214455Srpaulo * sf-pcap.c - libpcap-file-format-specific code from savefile.c 22214455Srpaulo * Extraction/creation by Jeffrey Mogul, DECWRL 23214455Srpaulo * Modified by Steve McCanne, LBL. 24214455Srpaulo * 25214455Srpaulo * Used to save the received packet headers, after filtering, to 26214455Srpaulo * a file, and then read them later. 27214455Srpaulo * The first record in the file contains saved values for the machine 28214455Srpaulo * dependent values so we can print the dump file on any architecture. 29214455Srpaulo */ 30214455Srpaulo 31214455Srpaulo#ifndef lint 32214455Srpaulostatic const char rcsid[] _U_ = 33214455Srpaulo "@(#) $Header$ (LBL)"; 34214455Srpaulo#endif 35214455Srpaulo 36214455Srpaulo#ifdef HAVE_CONFIG_H 37214455Srpaulo#include "config.h" 38214455Srpaulo#endif 39214455Srpaulo 40214455Srpaulo#ifdef WIN32 41214455Srpaulo#include <pcap-stdinc.h> 42214455Srpaulo#else /* WIN32 */ 43214455Srpaulo#if HAVE_INTTYPES_H 44214455Srpaulo#include <inttypes.h> 45214455Srpaulo#elif HAVE_STDINT_H 46214455Srpaulo#include <stdint.h> 47214455Srpaulo#endif 48214455Srpaulo#ifdef HAVE_SYS_BITYPES_H 49214455Srpaulo#include <sys/bitypes.h> 50214455Srpaulo#endif 51214455Srpaulo#include <sys/types.h> 52214455Srpaulo#endif /* WIN32 */ 53214455Srpaulo 54214455Srpaulo#include <errno.h> 55214455Srpaulo#include <memory.h> 56214455Srpaulo#include <stdio.h> 57214455Srpaulo#include <stdlib.h> 58214455Srpaulo#include <string.h> 59214455Srpaulo 60214455Srpaulo#include "pcap-int.h" 61214455Srpaulo 62214455Srpaulo#include "pcap-common.h" 63214455Srpaulo 64214455Srpaulo#ifdef HAVE_OS_PROTO_H 65214455Srpaulo#include "os-proto.h" 66214455Srpaulo#endif 67214455Srpaulo 68214455Srpaulo#include "sf-pcap.h" 69214455Srpaulo 70214455Srpaulo/* 71214455Srpaulo * Setting O_BINARY on DOS/Windows is a bit tricky 72214455Srpaulo */ 73214455Srpaulo#if defined(WIN32) 74214455Srpaulo #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) 75214455Srpaulo#elif defined(MSDOS) 76214455Srpaulo #if defined(__HIGHC__) 77214455Srpaulo #define SET_BINMODE(f) setmode(f, O_BINARY) 78214455Srpaulo #else 79214455Srpaulo #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) 80214455Srpaulo #endif 81214455Srpaulo#endif 82214455Srpaulo 83214455Srpaulo/* 84214455Srpaulo * Standard libpcap format. 85214455Srpaulo */ 86214455Srpaulo#define TCPDUMP_MAGIC 0xa1b2c3d4 87214455Srpaulo 88214455Srpaulo/* 89214455Srpaulo * Alexey Kuznetzov's modified libpcap format. 90214455Srpaulo */ 91214455Srpaulo#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 92214455Srpaulo 93214455Srpaulo/* 94214455Srpaulo * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt> 95214455Srpaulo * for another modified format. 96214455Srpaulo */ 97214455Srpaulo#define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd 98214455Srpaulo 99214455Srpaulo/* 100214455Srpaulo * Navtel Communcations' format, with nanosecond timestamps, 101214455Srpaulo * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>. 102214455Srpaulo */ 103214455Srpaulo#define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d 104214455Srpaulo 105214455Srpaulo/* 106214455Srpaulo * Normal libpcap format, except for seconds/nanoseconds timestamps, 107214455Srpaulo * as per a request by Ulf Lamping <ulf.lamping@web.de> 108214455Srpaulo */ 109214455Srpaulo#define NSEC_TCPDUMP_MAGIC 0xa1b23c4d 110214455Srpaulo 111214455Srpaulo/* 112214455Srpaulo * Mechanism for storing information about a capture in the upper 113214455Srpaulo * 6 bits of a linktype value in a capture file. 114214455Srpaulo * 115214455Srpaulo * LT_LINKTYPE_EXT(x) extracts the additional information. 116214455Srpaulo * 117214455Srpaulo * The rest of the bits are for a value describing the link-layer 118214455Srpaulo * value. LT_LINKTYPE(x) extracts that value. 119214455Srpaulo */ 120214455Srpaulo#define LT_LINKTYPE(x) ((x) & 0x03FFFFFF) 121214455Srpaulo#define LT_LINKTYPE_EXT(x) ((x) & 0xFC000000) 122214455Srpaulo 123214455Srpaulostatic int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); 124214455Srpaulo 125214455Srpaulo/* 126214455Srpaulo * Check whether this is a pcap savefile and, if it is, extract the 127214455Srpaulo * relevant information from the header. 128214455Srpaulo */ 129214455Srpauloint 130214455Srpaulopcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) 131214455Srpaulo{ 132214455Srpaulo struct pcap_file_header hdr; 133214455Srpaulo size_t amt_read; 134214455Srpaulo 135214455Srpaulo /* 136214455Srpaulo * Check whether the first 4 bytes of the file are the magic 137214455Srpaulo * number for a pcap savefile, or for a byte-swapped pcap 138214455Srpaulo * savefile. 139214455Srpaulo */ 140214455Srpaulo if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) { 141214455Srpaulo magic = SWAPLONG(magic); 142214455Srpaulo if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) 143214455Srpaulo return (0); /* nope */ 144214455Srpaulo p->sf.swapped = 1; 145214455Srpaulo } 146214455Srpaulo 147214455Srpaulo /* 148214455Srpaulo * They are. Put the magic number in the header, and read 149214455Srpaulo * the rest of the header. 150214455Srpaulo */ 151214455Srpaulo hdr.magic = magic; 152214455Srpaulo amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, 153214455Srpaulo sizeof(hdr) - sizeof(hdr.magic), fp); 154214455Srpaulo if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { 155214455Srpaulo if (ferror(fp)) { 156214455Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, 157214455Srpaulo "error reading dump file: %s", 158214455Srpaulo pcap_strerror(errno)); 159214455Srpaulo } else { 160214455Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, 161214455Srpaulo "truncated dump file; tried to read %lu file header bytes, only got %lu", 162214455Srpaulo (unsigned long)sizeof(hdr), 163214455Srpaulo (unsigned long)amt_read); 164214455Srpaulo } 165214455Srpaulo return (-1); 166214455Srpaulo } 167214455Srpaulo 168214455Srpaulo /* 169214455Srpaulo * If it's a byte-swapped capture file, byte-swap the header. 170214455Srpaulo */ 171214455Srpaulo if (p->sf.swapped) { 172214455Srpaulo hdr.version_major = SWAPSHORT(hdr.version_major); 173214455Srpaulo hdr.version_minor = SWAPSHORT(hdr.version_minor); 174214455Srpaulo hdr.thiszone = SWAPLONG(hdr.thiszone); 175214455Srpaulo hdr.sigfigs = SWAPLONG(hdr.sigfigs); 176214455Srpaulo hdr.snaplen = SWAPLONG(hdr.snaplen); 177214455Srpaulo hdr.linktype = SWAPLONG(hdr.linktype); 178214455Srpaulo } 179214455Srpaulo 180214455Srpaulo if (hdr.version_major < PCAP_VERSION_MAJOR) { 181214455Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, 182214455Srpaulo "archaic pcap savefile format"); 183214455Srpaulo return (-1); 184214455Srpaulo } 185214455Srpaulo p->sf.version_major = hdr.version_major; 186214455Srpaulo p->sf.version_minor = hdr.version_minor; 187214455Srpaulo p->tzoff = hdr.thiszone; 188214455Srpaulo p->snapshot = hdr.snaplen; 189214455Srpaulo p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); 190214455Srpaulo p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); 191214455Srpaulo 192214455Srpaulo p->sf.next_packet_op = pcap_next_packet; 193214455Srpaulo 194214455Srpaulo /* 195214455Srpaulo * We interchanged the caplen and len fields at version 2.3, 196214455Srpaulo * in order to match the bpf header layout. But unfortunately 197214455Srpaulo * some files were written with version 2.3 in their headers 198214455Srpaulo * but without the interchanged fields. 199214455Srpaulo * 200214455Srpaulo * In addition, DG/UX tcpdump writes out files with a version 201214455Srpaulo * number of 543.0, and with the caplen and len fields in the 202214455Srpaulo * pre-2.3 order. 203214455Srpaulo */ 204214455Srpaulo switch (hdr.version_major) { 205214455Srpaulo 206214455Srpaulo case 2: 207214455Srpaulo if (hdr.version_minor < 3) 208214455Srpaulo p->sf.lengths_swapped = SWAPPED; 209214455Srpaulo else if (hdr.version_minor == 3) 210214455Srpaulo p->sf.lengths_swapped = MAYBE_SWAPPED; 211214455Srpaulo else 212214455Srpaulo p->sf.lengths_swapped = NOT_SWAPPED; 213214455Srpaulo break; 214214455Srpaulo 215214455Srpaulo case 543: 216214455Srpaulo p->sf.lengths_swapped = SWAPPED; 217214455Srpaulo break; 218214455Srpaulo 219214455Srpaulo default: 220214455Srpaulo p->sf.lengths_swapped = NOT_SWAPPED; 221214455Srpaulo break; 222214455Srpaulo } 223214455Srpaulo 224214455Srpaulo if (magic == KUZNETZOV_TCPDUMP_MAGIC) { 225214455Srpaulo /* 226214455Srpaulo * XXX - the patch that's in some versions of libpcap 227214455Srpaulo * changes the packet header but not the magic number, 228214455Srpaulo * and some other versions with this magic number have 229214455Srpaulo * some extra debugging information in the packet header; 230214455Srpaulo * we'd have to use some hacks^H^H^H^H^Hheuristics to 231214455Srpaulo * detect those variants. 232214455Srpaulo * 233214455Srpaulo * Ethereal does that, but it does so by trying to read 234214455Srpaulo * the first two packets of the file with each of the 235214455Srpaulo * record header formats. That currently means it seeks 236214455Srpaulo * backwards and retries the reads, which doesn't work 237214455Srpaulo * on pipes. We want to be able to read from a pipe, so 238214455Srpaulo * that strategy won't work; we'd have to buffer some 239214455Srpaulo * data ourselves and read from that buffer in order to 240214455Srpaulo * make that work. 241214455Srpaulo */ 242214455Srpaulo p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr); 243214455Srpaulo 244214455Srpaulo if (p->linktype == DLT_EN10MB) { 245214455Srpaulo /* 246214455Srpaulo * This capture might have been done in raw mode 247214455Srpaulo * or cooked mode. 248214455Srpaulo * 249214455Srpaulo * If it was done in cooked mode, p->snapshot was 250214455Srpaulo * passed to recvfrom() as the buffer size, meaning 251214455Srpaulo * that the most packet data that would be copied 252214455Srpaulo * would be p->snapshot. However, a faked Ethernet 253214455Srpaulo * header would then have been added to it, so the 254214455Srpaulo * most data that would be in a packet in the file 255214455Srpaulo * would be p->snapshot + 14. 256214455Srpaulo * 257214455Srpaulo * We can't easily tell whether the capture was done 258214455Srpaulo * in raw mode or cooked mode, so we'll assume it was 259214455Srpaulo * cooked mode, and add 14 to the snapshot length. 260214455Srpaulo * That means that, for a raw capture, the snapshot 261214455Srpaulo * length will be misleading if you use it to figure 262214455Srpaulo * out why a capture doesn't have all the packet data, 263214455Srpaulo * but there's not much we can do to avoid that. 264214455Srpaulo */ 265214455Srpaulo p->snapshot += 14; 266214455Srpaulo } 267214455Srpaulo } else 268214455Srpaulo p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr); 269214455Srpaulo 270214455Srpaulo /* 271214455Srpaulo * Allocate a buffer for the packet data. 272214455Srpaulo */ 273214455Srpaulo p->bufsize = p->snapshot; 274235426Sdelphij if (p->bufsize <= 0) { 275235426Sdelphij /* 276235426Sdelphij * Bogus snapshot length; use 64KiB as a fallback. 277235426Sdelphij */ 278235426Sdelphij p->bufsize = 65536; 279235426Sdelphij } 280214455Srpaulo p->buffer = malloc(p->bufsize); 281214455Srpaulo if (p->buffer == NULL) { 282214455Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); 283214455Srpaulo return (-1); 284214455Srpaulo } 285214455Srpaulo 286214455Srpaulo return (1); 287214455Srpaulo} 288214455Srpaulo 289214455Srpaulo/* 290214455Srpaulo * Read and return the next packet from the savefile. Return the header 291214455Srpaulo * in hdr and a pointer to the contents in data. Return 0 on success, 1 292214455Srpaulo * if there were no more packets, and -1 on an error. 293214455Srpaulo */ 294214455Srpaulostatic int 295214455Srpaulopcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) 296214455Srpaulo{ 297214455Srpaulo struct pcap_sf_patched_pkthdr sf_hdr; 298214455Srpaulo FILE *fp = p->sf.rfile; 299214455Srpaulo size_t amt_read; 300214455Srpaulo bpf_u_int32 t; 301214455Srpaulo 302214455Srpaulo /* 303214455Srpaulo * Read the packet header; the structure we use as a buffer 304214455Srpaulo * is the longer structure for files generated by the patched 305214455Srpaulo * libpcap, but if the file has the magic number for an 306214455Srpaulo * unpatched libpcap we only read as many bytes as the regular 307214455Srpaulo * header has. 308214455Srpaulo */ 309214455Srpaulo amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp); 310214455Srpaulo if (amt_read != p->sf.hdrsize) { 311214455Srpaulo if (ferror(fp)) { 312214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 313214455Srpaulo "error reading dump file: %s", 314214455Srpaulo pcap_strerror(errno)); 315214455Srpaulo return (-1); 316214455Srpaulo } else { 317214455Srpaulo if (amt_read != 0) { 318214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 319214455Srpaulo "truncated dump file; tried to read %lu header bytes, only got %lu", 320214455Srpaulo (unsigned long)p->sf.hdrsize, 321214455Srpaulo (unsigned long)amt_read); 322214455Srpaulo return (-1); 323214455Srpaulo } 324214455Srpaulo /* EOF */ 325214455Srpaulo return (1); 326214455Srpaulo } 327214455Srpaulo } 328214455Srpaulo 329214455Srpaulo if (p->sf.swapped) { 330214455Srpaulo /* these were written in opposite byte order */ 331214455Srpaulo hdr->caplen = SWAPLONG(sf_hdr.caplen); 332214455Srpaulo hdr->len = SWAPLONG(sf_hdr.len); 333214455Srpaulo hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); 334214455Srpaulo hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); 335214455Srpaulo } else { 336214455Srpaulo hdr->caplen = sf_hdr.caplen; 337214455Srpaulo hdr->len = sf_hdr.len; 338214455Srpaulo hdr->ts.tv_sec = sf_hdr.ts.tv_sec; 339214455Srpaulo hdr->ts.tv_usec = sf_hdr.ts.tv_usec; 340214455Srpaulo } 341214455Srpaulo /* Swap the caplen and len fields, if necessary. */ 342214455Srpaulo switch (p->sf.lengths_swapped) { 343214455Srpaulo 344214455Srpaulo case NOT_SWAPPED: 345214455Srpaulo break; 346214455Srpaulo 347214455Srpaulo case MAYBE_SWAPPED: 348214455Srpaulo if (hdr->caplen <= hdr->len) { 349214455Srpaulo /* 350214455Srpaulo * The captured length is <= the actual length, 351214455Srpaulo * so presumably they weren't swapped. 352214455Srpaulo */ 353214455Srpaulo break; 354214455Srpaulo } 355214455Srpaulo /* FALLTHROUGH */ 356214455Srpaulo 357214455Srpaulo case SWAPPED: 358214455Srpaulo t = hdr->caplen; 359214455Srpaulo hdr->caplen = hdr->len; 360214455Srpaulo hdr->len = t; 361214455Srpaulo break; 362214455Srpaulo } 363214455Srpaulo 364214455Srpaulo if (hdr->caplen > p->bufsize) { 365214455Srpaulo /* 366214455Srpaulo * This can happen due to Solaris 2.3 systems tripping 367214455Srpaulo * over the BUFMOD problem and not setting the snapshot 368214455Srpaulo * correctly in the savefile header. If the caplen isn't 369214455Srpaulo * grossly wrong, try to salvage. 370214455Srpaulo */ 371214455Srpaulo static u_char *tp = NULL; 372214455Srpaulo static size_t tsize = 0; 373214455Srpaulo 374214455Srpaulo if (hdr->caplen > 65535) { 375214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 376214455Srpaulo "bogus savefile header"); 377214455Srpaulo return (-1); 378214455Srpaulo } 379214455Srpaulo 380214455Srpaulo if (tsize < hdr->caplen) { 381214455Srpaulo tsize = ((hdr->caplen + 1023) / 1024) * 1024; 382214455Srpaulo if (tp != NULL) 383214455Srpaulo free((u_char *)tp); 384214455Srpaulo tp = (u_char *)malloc(tsize); 385214455Srpaulo if (tp == NULL) { 386214455Srpaulo tsize = 0; 387214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 388214455Srpaulo "BUFMOD hack malloc"); 389214455Srpaulo return (-1); 390214455Srpaulo } 391214455Srpaulo } 392214455Srpaulo amt_read = fread((char *)tp, 1, hdr->caplen, fp); 393214455Srpaulo if (amt_read != hdr->caplen) { 394214455Srpaulo if (ferror(fp)) { 395214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 396214455Srpaulo "error reading dump file: %s", 397214455Srpaulo pcap_strerror(errno)); 398214455Srpaulo } else { 399214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 400214455Srpaulo "truncated dump file; tried to read %u captured bytes, only got %lu", 401214455Srpaulo hdr->caplen, (unsigned long)amt_read); 402214455Srpaulo } 403214455Srpaulo return (-1); 404214455Srpaulo } 405214455Srpaulo /* 406214455Srpaulo * We can only keep up to p->bufsize bytes. Since 407214455Srpaulo * caplen > p->bufsize is exactly how we got here, 408214455Srpaulo * we know we can only keep the first p->bufsize bytes 409214455Srpaulo * and must drop the remainder. Adjust caplen accordingly, 410214455Srpaulo * so we don't get confused later as to how many bytes we 411214455Srpaulo * have to play with. 412214455Srpaulo */ 413214455Srpaulo hdr->caplen = p->bufsize; 414214455Srpaulo memcpy(p->buffer, (char *)tp, p->bufsize); 415214455Srpaulo } else { 416214455Srpaulo /* read the packet itself */ 417214455Srpaulo amt_read = fread(p->buffer, 1, hdr->caplen, fp); 418214455Srpaulo if (amt_read != hdr->caplen) { 419214455Srpaulo if (ferror(fp)) { 420214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 421214455Srpaulo "error reading dump file: %s", 422214455Srpaulo pcap_strerror(errno)); 423214455Srpaulo } else { 424214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 425214455Srpaulo "truncated dump file; tried to read %u captured bytes, only got %lu", 426214455Srpaulo hdr->caplen, (unsigned long)amt_read); 427214455Srpaulo } 428214455Srpaulo return (-1); 429214455Srpaulo } 430214455Srpaulo } 431214455Srpaulo *data = p->buffer; 432214455Srpaulo 433214455Srpaulo if (p->sf.swapped) { 434214455Srpaulo /* 435214455Srpaulo * Convert pseudo-headers from the byte order of 436214455Srpaulo * the host on which the file was saved to our 437214455Srpaulo * byte order, as necessary. 438214455Srpaulo */ 439214455Srpaulo switch (p->linktype) { 440214455Srpaulo 441214455Srpaulo case DLT_USB_LINUX: 442214455Srpaulo swap_linux_usb_header(hdr, *data, 0); 443214455Srpaulo break; 444214455Srpaulo 445214455Srpaulo case DLT_USB_LINUX_MMAPPED: 446214455Srpaulo swap_linux_usb_header(hdr, *data, 1); 447214455Srpaulo break; 448214455Srpaulo } 449214455Srpaulo } 450214455Srpaulo 451214455Srpaulo return (0); 452214455Srpaulo} 453214455Srpaulo 454214455Srpaulostatic int 455214455Srpaulosf_write_header(FILE *fp, int linktype, int thiszone, int snaplen) 456214455Srpaulo{ 457214455Srpaulo struct pcap_file_header hdr; 458214455Srpaulo 459214455Srpaulo hdr.magic = TCPDUMP_MAGIC; 460214455Srpaulo hdr.version_major = PCAP_VERSION_MAJOR; 461214455Srpaulo hdr.version_minor = PCAP_VERSION_MINOR; 462214455Srpaulo 463214455Srpaulo hdr.thiszone = thiszone; 464214455Srpaulo hdr.snaplen = snaplen; 465214455Srpaulo hdr.sigfigs = 0; 466214455Srpaulo hdr.linktype = linktype; 467214455Srpaulo 468214455Srpaulo if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) 469214455Srpaulo return (-1); 470214455Srpaulo 471214455Srpaulo return (0); 472214455Srpaulo} 473214455Srpaulo 474214455Srpaulo/* 475214455Srpaulo * Output a packet to the initialized dump file. 476214455Srpaulo */ 477214455Srpaulovoid 478214455Srpaulopcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) 479214455Srpaulo{ 480214455Srpaulo register FILE *f; 481214455Srpaulo struct pcap_sf_pkthdr sf_hdr; 482214455Srpaulo 483214455Srpaulo f = (FILE *)user; 484214455Srpaulo sf_hdr.ts.tv_sec = h->ts.tv_sec; 485214455Srpaulo sf_hdr.ts.tv_usec = h->ts.tv_usec; 486214455Srpaulo sf_hdr.caplen = h->caplen; 487214455Srpaulo sf_hdr.len = h->len; 488214455Srpaulo /* XXX we should check the return status */ 489214455Srpaulo (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f); 490214455Srpaulo (void)fwrite(sp, h->caplen, 1, f); 491214455Srpaulo} 492214455Srpaulo 493214455Srpaulostatic pcap_dumper_t * 494214455Srpaulopcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) 495214455Srpaulo{ 496214455Srpaulo 497214455Srpaulo#if defined(WIN32) || defined(MSDOS) 498214455Srpaulo /* 499214455Srpaulo * If we're writing to the standard output, put it in binary 500214455Srpaulo * mode, as savefiles are binary files. 501214455Srpaulo * 502214455Srpaulo * Otherwise, we turn off buffering. 503214455Srpaulo * XXX - why? And why not on the standard output? 504214455Srpaulo */ 505214455Srpaulo if (f == stdout) 506214455Srpaulo SET_BINMODE(f); 507214455Srpaulo else 508214455Srpaulo setbuf(f, NULL); 509214455Srpaulo#endif 510214455Srpaulo if (sf_write_header(f, linktype, p->tzoff, p->snapshot) == -1) { 511214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", 512214455Srpaulo fname, pcap_strerror(errno)); 513214455Srpaulo if (f != stdout) 514214455Srpaulo (void)fclose(f); 515214455Srpaulo return (NULL); 516214455Srpaulo } 517214455Srpaulo return ((pcap_dumper_t *)f); 518214455Srpaulo} 519214455Srpaulo 520214455Srpaulo/* 521214455Srpaulo * Initialize so that sf_write() will output to the file named 'fname'. 522214455Srpaulo */ 523214455Srpaulopcap_dumper_t * 524214455Srpaulopcap_dump_open(pcap_t *p, const char *fname) 525214455Srpaulo{ 526214455Srpaulo FILE *f; 527214455Srpaulo int linktype; 528214455Srpaulo 529214455Srpaulo /* 530214455Srpaulo * If this pcap_t hasn't been activated, it doesn't have a 531214455Srpaulo * link-layer type, so we can't use it. 532214455Srpaulo */ 533214455Srpaulo if (!p->activated) { 534214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 535214455Srpaulo "%s: not-yet-activated pcap_t passed to pcap_dump_open", 536214455Srpaulo fname); 537214455Srpaulo return (NULL); 538214455Srpaulo } 539214455Srpaulo linktype = dlt_to_linktype(p->linktype); 540214455Srpaulo if (linktype == -1) { 541214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 542214455Srpaulo "%s: link-layer type %d isn't supported in savefiles", 543214455Srpaulo fname, p->linktype); 544214455Srpaulo return (NULL); 545214455Srpaulo } 546214455Srpaulo linktype |= p->linktype_ext; 547214455Srpaulo 548214455Srpaulo if (fname[0] == '-' && fname[1] == '\0') { 549214455Srpaulo f = stdout; 550214455Srpaulo fname = "standard output"; 551214455Srpaulo } else { 552214455Srpaulo#if !defined(WIN32) && !defined(MSDOS) 553214455Srpaulo f = fopen(fname, "w"); 554214455Srpaulo#else 555214455Srpaulo f = fopen(fname, "wb"); 556214455Srpaulo#endif 557214455Srpaulo if (f == NULL) { 558214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 559214455Srpaulo fname, pcap_strerror(errno)); 560214455Srpaulo return (NULL); 561214455Srpaulo } 562214455Srpaulo } 563214455Srpaulo return (pcap_setup_dump(p, linktype, f, fname)); 564214455Srpaulo} 565214455Srpaulo 566214455Srpaulo/* 567214455Srpaulo * Initialize so that sf_write() will output to the given stream. 568214455Srpaulo */ 569214455Srpaulopcap_dumper_t * 570214455Srpaulopcap_dump_fopen(pcap_t *p, FILE *f) 571214455Srpaulo{ 572214455Srpaulo int linktype; 573214455Srpaulo 574214455Srpaulo linktype = dlt_to_linktype(p->linktype); 575214455Srpaulo if (linktype == -1) { 576214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 577214455Srpaulo "stream: link-layer type %d isn't supported in savefiles", 578214455Srpaulo p->linktype); 579214455Srpaulo return (NULL); 580214455Srpaulo } 581214455Srpaulo linktype |= p->linktype_ext; 582214455Srpaulo 583214455Srpaulo return (pcap_setup_dump(p, linktype, f, "stream")); 584214455Srpaulo} 585214455Srpaulo 586214455SrpauloFILE * 587214455Srpaulopcap_dump_file(pcap_dumper_t *p) 588214455Srpaulo{ 589214455Srpaulo return ((FILE *)p); 590214455Srpaulo} 591214455Srpaulo 592214455Srpaulolong 593214455Srpaulopcap_dump_ftell(pcap_dumper_t *p) 594214455Srpaulo{ 595214455Srpaulo return (ftell((FILE *)p)); 596214455Srpaulo} 597214455Srpaulo 598214455Srpauloint 599214455Srpaulopcap_dump_flush(pcap_dumper_t *p) 600214455Srpaulo{ 601214455Srpaulo 602214455Srpaulo if (fflush((FILE *)p) == EOF) 603214455Srpaulo return (-1); 604214455Srpaulo else 605214455Srpaulo return (0); 606214455Srpaulo} 607214455Srpaulo 608214455Srpaulovoid 609214455Srpaulopcap_dump_close(pcap_dumper_t *p) 610214455Srpaulo{ 611214455Srpaulo 612214455Srpaulo#ifdef notyet 613214455Srpaulo if (ferror((FILE *)p)) 614214455Srpaulo return-an-error; 615214455Srpaulo /* XXX should check return from fclose() too */ 616214455Srpaulo#endif 617214455Srpaulo (void)fclose((FILE *)p); 618214455Srpaulo} 619