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.