This is savefile.c in view mode; [Download] [Up]
/*
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char rcsid[] =
"@(#)$Header: savefile.c,v 1.16 94/06/20 19:07:56 leres Exp $ (LBL)";
#endif
/*
* savefile.c - supports offline use of tcpdump
* Extraction/creation by Jeffrey Mogul, DECWRL
* Modified by Steve McCanne, LBL.
*
* Used to save the received packet headers, after filtering, to
* a file, and then read them later.
* The first record in the file contains saved values for the machine
* dependent values so we can print the dump file on any architecture.
*/
#include <sys/types.h>
#include <sys/time.h>
#ifdef SJP_MODS
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#endif
#include <net/bpf.h>
#include <errno.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "pcap-int.h"
#define TCPDUMP_MAGIC 0xa1b2c3d4
/*
* We use the "receiver-makes-right" approach to byte order,
* because time is at a premium when we are writing the file.
* In other words, the pcap_file_header and pcap_pkthdr,
* records are written in host byte order.
* Note that the packets are always written in network byte order.
*
* ntoh[ls] aren't sufficient because we might need to swap on a big-endian
* machine (if the file was written in little-end order).
*/
#define SWAPLONG(y) \
((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
#define SWAPSHORT(y) \
( (((y)&0xff)<<8) | (((y)&0xff00)>>8) )
#define SFERR_TRUNC 1
#define SFERR_BADVERSION 2
#define SFERR_BADF 3
#define SFERR_EOF 4 /* not really an error, just a status */
#ifdef SJP_MODS
/*
* We must snapshot original pppstat values and take
* the difference to get valid readings.
*/
struct ifpppstatsreq pre_stats;
struct ifpppcstatsreq pre_comp_stats;
int stats_sock;
#define SIOCGPPPSTATS _IOWR('i', 123, struct ifpppstatsreq)
#define SIOCGPPPCSTATS _IOWR('i', 122, struct ifpppcstatsreq)
static inline char *strdup(char *str)
{
char *tmp;
if (str == NULL)
return NULL;
if ((tmp = (char *) malloc(strlen(str) + 1)) == NULL)
{
fprintf(stderr, "Out of memory at %s %d\n", __FILE__, __LINE__);
return NULL;
}
return strcpy(tmp, str);
}
#endif
static int
sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen)
{
struct pcap_file_header hdr;
#ifdef SJP_MODS
int iodes[2];
char sysconf[4096];
char *email_name = NULL;
char *modem_speed = NULL;
time_t thetime;
#endif
#ifdef SJP_MODS
bzero((char *) &hdr, sizeof (struct pcap_file_header));
#endif
hdr.magic = TCPDUMP_MAGIC;
hdr.version_major = PCAP_VERSION_MAJOR;
#ifndef SJP_MODS
hdr.version_minor = PCAP_VERSION_MINOR;
#else
hdr.version_minor = SJP_PCAP_VERSION_MINOR;
#endif
hdr.thiszone = thiszone;
hdr.snaplen = snaplen;
hdr.sigfigs = 0;
hdr.linktype = linktype;
#ifdef SJP_MODS
if (pipe(iodes) == -1)
{
perror("Error Creating Pipes: ");
exit(1);
}
if (fork() == 0)
{
/*
* child
*/
dup2(iodes[1], 1);
if (execl("/usr/bin/hostinfo", "hostinfo", 0) == -1)
{
perror("Error getting hostinfo: ");
close(iodes[1]);
exit(1);
}
}
else
{ /*
* parent
*/
read(iodes[0], sysconf, 4096);
sysconf[4095] = (char) NULL;
close(iodes[0], iodes[1]);
}
hdr.hinfo_len = strlen(sysconf);
email_name = getenv("PPPMAILTO");
if (email_name)
hdr.email_len = strlen(email_name);
else
{
fprintf(stderr, "Please define the environment variable PPPMAILTO\n");
hdr.email_len = 0;
}
modem_speed = getenv("PPPMODEMSPEED");
if (modem_speed)
{
hdr.m_speed = atoi(modem_speed);
fprintf(stderr, "Setting modem speed to %d\n", hdr.m_speed);
}
else
{
fprintf(stderr, "Please define the environment variable PPPMODEMSPEED\n");
hdr.m_speed = 0;
}
thetime = time(NULL);
strncpy(hdr.date, ctime(&thetime), 26);
if (gettimeofday(&hdr.session_start, NULL) == -1)
perror("Setting time in libpcap/savefile.c");
#endif
if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
return (-1);
#ifdef SJP_MODS
if (fwrite(sysconf, hdr.hinfo_len, 1, fp) != 1)
return (-1);
if (hdr.email_len != 0)
if (fwrite(email_name, hdr.email_len, 1, fp) != 1)
return (-1);
#endif
return (0);
}
static void
swap_hdr(struct pcap_file_header *hp)
{
fprintf(stderr, "Inside swap_hdr %s %d\n", __FILE__, __LINE__);
hp->version_major = SWAPSHORT(hp->version_major);
hp->version_minor = SWAPSHORT(hp->version_minor);
hp->thiszone = SWAPLONG(hp->thiszone);
hp->sigfigs = SWAPLONG(hp->sigfigs);
hp->snaplen = SWAPLONG(hp->snaplen);
hp->linktype = SWAPLONG(hp->linktype);
#ifdef SJP_MODS
hp->session_start.tv_sec = SWAPLONG(hp->session_start.tv_sec);
hp->session_start.tv_usec = SWAPLONG(hp->session_start.tv_usec);
hp->session_end.tv_sec = SWAPLONG(hp->session_end.tv_sec);
hp->session_end.tv_usec = SWAPLONG(hp->session_end.tv_usec);
hp->m_speed = SWAPLONG(hp->m_speed);
hp->ps_recv = SWAPLONG(hp->ps_recv);
hp->ps_drop = SWAPLONG(hp->ps_drop);
#endif
}
pcap_t *
pcap_open_offline(char *fname, char *errbuf)
{
register pcap_t *p;
register FILE *fp;
struct pcap_file_header hdr;
int linklen;
p = (pcap_t *)malloc(sizeof(*p));
if (p == NULL) {
strcpy(errbuf, "out of swap");
return (NULL);
}
#ifdef notdef
bzero(p, sizeof(*p));
#else
memset(p, 0, sizeof(*p));
#endif
/*
* Set this field so we don't close stdin in pcap_close!
*/
p->fd = -1;
if (fname[0] == '-' && fname[1] == '\0')
fp = stdin;
else {
fp = fopen(fname, "r");
if (fp == NULL) {
sprintf(errbuf, "%s: %s", fname, pcap_strerror(errno));
goto bad;
}
}
if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
sprintf(errbuf, "fread: %s", pcap_strerror(errno));
goto bad;
}
if (hdr.magic != TCPDUMP_MAGIC) {
if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC) {
sprintf(errbuf, "bad dump file format");
goto bad;
}
p->sf.swapped = 1;
swap_hdr(&hdr);
}
if (hdr.version_major < PCAP_VERSION_MAJOR) {
sprintf(errbuf, "archaic file format");
goto bad;
}
if (hdr.version_minor == PCAP_VERSION_MINOR)
{
p->tzoff = hdr.thiszone;
p->snapshot = hdr.snaplen;
p->linktype = hdr.linktype;
p->sf.rfile = fp;
p->bufsize = hdr.snaplen;
/* Align link header as required for proper data alignment */
linklen = 14; /* XXX */
p->sf.base = (u_char *)malloc(p->bufsize + BPF_ALIGNMENT);
p->buffer = p->sf.base + BPF_ALIGNMENT - (linklen % BPF_ALIGNMENT);
p->sf.version_major = hdr.version_major;
p->sf.version_minor = hdr.version_minor;
}
#ifdef SJP_MODS
else if (hdr.version_minor == SJP_PCAP_VERSION_MINOR)
{
struct timeval tmp;
char hostinfobuf[1000],
email_buf[100];
/* fprintf(stderr, "Reading a Modified TCPDUMP file\n"); */
p->tzoff = hdr.thiszone;
p->snapshot = hdr.snaplen;
p->linktype = hdr.linktype;
p->sf.rfile = fp;
p->bufsize = hdr.snaplen;
/* Align link header as required for proper data alignment */
linklen = 14; /* XXX */
p->sf.base = (u_char *)malloc(p->bufsize + BPF_ALIGNMENT);
p->buffer = p->sf.base + BPF_ALIGNMENT - (linklen % BPF_ALIGNMENT);
p->sf.version_major = hdr.version_major;
p->sf.version_minor = hdr.version_minor;
if (fread(hostinfobuf, hdr.hinfo_len, 1, fp) != 1)
{
sprintf(errbuf, "Error reading Hostinfo: ");
goto bad;
}
hostinfobuf[hdr.hinfo_len] = (char) NULL;
hdr.hinfo = strdup(hostinfobuf);
if(hdr.email_len != 0)
{
if (fread(email_buf, hdr.email_len, 1, fp) != 1)
{
sprintf(errbuf, "Error reading Mail address: ");
goto bad;
}
}
email_buf[hdr.email_len] = (char) NULL;
hdr.email_addr = strdup(email_buf);
p->sf.hdr = (struct pcap_file_header *) malloc(sizeof(struct pcap_file_header));
if (p->sf.hdr == NULL)
{
sprintf(errbuf, "Out of memory");
return NULL;
}
bcopy(&hdr, p->sf.hdr, sizeof(struct pcap_file_header));
#if 0
printf("Dump taken on %s by %s\n\n", hdr.date, email_buf);
printf("Dump started at: ");
ts_print_copy(&hdr.session_start, 1);
printf("\nDump ended at: ");
ts_print_copy(&hdr.session_end, 1);
tmp.tv_sec = hdr.session_end.tv_sec - hdr.session_start.tv_sec;
tmp.tv_usec = 0;
printf("\nDump Duration: ");
sjpts_print(&tmp, 1);
printf("\n\n");
printf("Session Stats:\n");
printf("%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s\n",
"in", "pack", "comp", "uncomp", "err", "toss");
#define PIN(val) hdr.stats.p.val
#define PVIN(val) hdr.stats.vj.val
printf("%6d %6d %6d %6d %6d %6d\n\n",
PIN(ppp_ibytes), PIN(ppp_ipackets), PVIN(vjs_compressedin),
PVIN(vjs_uncompressedin), PVIN(vjs_errorin), PVIN(vjs_tossed));
printf("%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s\n",
"out", "pack", "comp", "uncomp", "search", "miss");
printf("%6d %6d %6d %6d %6d %6d\n\n",
PIN(ppp_obytes), PIN(ppp_opackets), PVIN(vjs_compressed),
PVIN(vjs_packets), PVIN(vjs_searches), PVIN(vjs_misses));
printf("%s\n", hostinfobuf);
#endif
}
#endif /* SJP_MODS */
else
{
fprintf(stderr, "Reading an unknown MINOR version (%d) of TCPDUMP file\n",
hdr.version_minor);
printf("Currently not supported\n");
}
return (p);
bad:
free(p);
return (NULL);
}
/*
* Read sf_readfile and return the next packet. Return the header in hdr
* and the contents in buf. Return 0 on success, SFERR_EOF if there were
* no more packets, and SFERR_TRUNC if a partial packet was encountered.
*/
int
sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen)
{
FILE *fp = p->sf.rfile;
/* read the stamp */
if (fread((char *)hdr, sizeof(struct pcap_pkthdr), 1, fp) != 1) {
/* probably an EOF, though could be a truncated packet */
return (1);
}
if (p->sf.swapped) {
/* these were written in opposite byte order */
hdr->caplen = SWAPLONG(hdr->caplen);
hdr->len = SWAPLONG(hdr->len);
hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
}
/*
* We interchanged the caplen and len fields at version 2.3,
* in order to match the bpf header layout. But unfortunately
* some files were written with version 2.3 in their headers
* but without the interchanged fields.
*/
if (p->sf.version_minor < 3 ||
(p->sf.version_minor == 3 && hdr->caplen > hdr->len)) {
int t = hdr->caplen;
hdr->caplen = hdr->len;
hdr->len = t;
}
if (hdr->caplen > buflen) {
sprintf(p->errbuf, "bad dump file format");
return (-1);
}
/* read the packet itself */
if (fread((char *)buf, hdr->caplen, 1, fp) != 1) {
sprintf(p->errbuf, "truncated dump file");
return (-1);
}
return (0);
}
/*
* Print out packets stored in the file initialized by sf_read_init().
* If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
*/
int
pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
struct bpf_insn *fcode = p->fcode.bf_insns;
int status = 0;
int n = 0;
while (status == 0) {
struct pcap_pkthdr h;
status = sf_next_packet(p, &h, p->buffer, p->bufsize);
if (status)
return (-1);
if (fcode == NULL ||
bpf_filter(fcode, p->buffer, h.len, h.caplen)) {
(*callback)(user, &h, p->buffer);
if (++n >= cnt && cnt > 0)
break;
}
}
/*XXX this breaks semantics tcpslice expects */
return (n);
}
/*
* Output a packet to the initialized dump file.
*/
void
pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
{
FILE * f = (FILE *)user;
(void)fwrite((char *)h, sizeof(*h), 1, f);
(void)fwrite((char *)sp, h->caplen, 1, f);
}
/*
* Initialize so that sf_write() will output to the file named 'fname'.
*/
pcap_dumper_t *
pcap_dump_open(pcap_t *p, char *fname)
{
FILE *f;
if (fname[0] == '-' && fname[1] == '\0')
f = stdout;
else {
#ifdef SJP_MODS
/*
* Lets collect PPP stats snapshot
*/
if ((stats_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("couldn't create IP socket");
exit(1);
}
bzero((char *)&pre_stats, sizeof(pre_stats));
bzero((char *)&pre_comp_stats, sizeof(pre_comp_stats));
sprintf(pre_stats.ifr_name, "ppp%d", 0); /* This needs to be fixed +++ */
sprintf(pre_comp_stats.ifr_name, "ppp%d", 0);
if (ioctl(stats_sock, SIOCGPPPSTATS, &pre_stats) < 0) {
if (errno == ENOTTY)
fprintf(stderr, "pppstats: kernel support missing\n");
else
perror("ioctl(SIOCGPPPSTATS)");
exit(1);
}
if (ioctl(stats_sock, SIOCGPPPCSTATS, &pre_comp_stats) < 0) {
if (errno == ENOTTY)
fprintf(stderr, "pppcstats: kernel compression support missing\n");
else
perror("ioctl(SIOCGPPPCSTATS)");
exit(1);
}
f = fopen(fname, "w+");
#else
f = fopen(fname, "w");
#endif
if (f == NULL) {
sprintf(p->errbuf, "%s: %s",
fname, pcap_strerror(errno));
return (NULL);
}
}
(void)sf_write_header(f, p->linktype, p->tzoff, p->snapshot);
return ((pcap_dumper_t *)f);
}
void
pcap_dump_close(pcap_dumper_t *p, pcap_t *pd)
{
#ifdef SJP_MODS
FILE *file = (FILE *) p;
struct pcap_file_header hdr;
struct ifpppstatsreq stats;
struct ifpppcstatsreq comp_stats;
struct pcap_stat stat;
rewind(file);
fread((void *)&hdr, sizeof(struct pcap_file_header), 1, file);
if (gettimeofday(&hdr.session_end, NULL) == -1)
perror("Setting end time in libpcap/savefile.c");
/*
* Set the session stats as the difference from the original
* snapshot.
*/
bzero((char *)&stats, sizeof(stats));
bzero((char *)&comp_stats, sizeof(comp_stats));
sprintf(stats.ifr_name, "ppp%d", 0); /* This needs to be fixed +++ */
sprintf(comp_stats.ifr_name, "ppp%d", 0);
if (ioctl(stats_sock, SIOCGPPPSTATS, &stats) < 0) {
if (errno == ENOTTY)
fprintf(stderr, "pppstats: kernel support missing\n");
else
perror("ioctl(SIOCGPPPSTATS)");
exit(1);
}
if (ioctl(stats_sock, SIOCGPPPCSTATS, &comp_stats) < 0) {
if (errno == ENOTTY)
fprintf(stderr, "pppcstats: kernel compression support missing\n");
else
perror("ioctl(SIOCGPPPCSTATS)");
exit(1);
}
#define STATS_DIFF(val) hdr.stats.p.val = stats.stats.p.val - pre_stats.stats.p.val
STATS_DIFF(ppp_ibytes);
STATS_DIFF(ppp_ipackets);
STATS_DIFF(ppp_ierrors);
STATS_DIFF(ppp_obytes);
STATS_DIFF(ppp_opackets);
STATS_DIFF(ppp_oerrors);
#define VJ_DIFF(val) hdr.stats.vj.val = stats.stats.vj.val - pre_stats.stats.vj.val
VJ_DIFF(vjs_packets);
VJ_DIFF(vjs_compressed);
VJ_DIFF(vjs_searches);
VJ_DIFF(vjs_misses);
VJ_DIFF(vjs_uncompressedin);
VJ_DIFF(vjs_compressedin);
VJ_DIFF(vjs_errorin);
VJ_DIFF(vjs_tossed);
#define RECV_COMP_DIFF(val) hdr.comp_stats.c.val = comp_stats.stats.c.val - pre_comp_stats.stats.c.val
RECV_COMP_DIFF(unc_bytes);
RECV_COMP_DIFF(unc_packets);
RECV_COMP_DIFF(comp_bytes);
RECV_COMP_DIFF(comp_packets);
RECV_COMP_DIFF(inc_bytes);
RECV_COMP_DIFF(inc_packets);
RECV_COMP_DIFF(ratio);
#define SEND_COMP_DIFF(val) hdr.comp_stats.d.val = comp_stats.stats.d.val - pre_comp_stats.stats.d.val
SEND_COMP_DIFF(unc_bytes);
SEND_COMP_DIFF(unc_packets);
SEND_COMP_DIFF(comp_bytes);
SEND_COMP_DIFF(comp_packets);
SEND_COMP_DIFF(inc_bytes);
SEND_COMP_DIFF(inc_packets);
SEND_COMP_DIFF(ratio);
if (pcap_stats(pd, &stat) < 0)
(void)fprintf(stderr, "pcap_stats: Error getting stats\n");
else {
hdr.ps_recv = stat.ps_recv;
hdr.ps_drop = stat.ps_drop;
}
/*
* Now write out the new header
*/
rewind(file);
fwrite((void *)&hdr, sizeof(struct pcap_file_header), 1, file);
/*
* There is some garbage being generated here...
* The hdr stored in the pcap dynamically allocated
* the hinfo and email address. We don't get passed
* the pcap_t to clean up with... *sigh*.
*/
#endif
fclose((FILE *)p);
}
#ifdef SJP_MODS
void
sjpts_print(register const struct timeval *tvp, int tflag)
{
register int s;
if (tflag > 0) {
/* Default */
s = (tvp->tv_sec) % 86400;
(void)printf("%02d:%02d:%02d",
s / 3600, (s % 3600) / 60, s % 60);
} else if (tflag < 0) {
/* Unix timeval style */
(void)printf("%d.%06d ", tvp->tv_sec, tvp->tv_usec);
}
}
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.