From df490a7085f382fbf4867fe9811af2653af91c17 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Wed, 18 Aug 1999 04:17:38 +0000 Subject: [PATCH] Add to Wiretap the ability to write capture files; for now, it can only write them in "libpcap" format, but the mechanism can have other formats added. When creating the temporary file for a capture, use "create_tempfile()", to close a security hole opened by the fact that "tempnam()" creates a temporary file, but doesn't open it, and we open the file with the name it gives us - somebody could remove the file and plant a link to some file, and, if as may well be the case when Ethereal is capturing packets, it's running as "root", that means we write a capture on top of that file.... (The aforementioned changes to Wiretap let you open a capture file for writing given an file descriptor, "fdopen()"-style, which this change requires.) svn path=/trunk/; revision=509 --- capture.c | 102 ++++++++++++++++++++---------- ethereal.c | 19 ++++-- file.h | 8 +-- wiretap/file.c | 106 +++++++++++++++++++++++++++++-- wiretap/libpcap.c | 154 ++++++++++++++++++++++++++++++++++++++-------- wiretap/libpcap.h | 4 +- wiretap/netmon.c | 7 ++- wiretap/netxray.c | 8 ++- wiretap/wtap.c | 26 +++++--- wiretap/wtap.h | 69 ++++++++++++++++++--- 10 files changed, 410 insertions(+), 93 deletions(-) diff --git a/capture.c b/capture.c index 7fef47e3e9..bbfd0c99c7 100644 --- a/capture.c +++ b/capture.c @@ -1,7 +1,7 @@ /* capture.c * Routines for packet capture windows * - * $Id: capture.c,v 1.52 1999/08/15 22:31:22 guy Exp $ + * $Id: capture.c,v 1.53 1999/08/18 04:17:26 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -309,8 +309,8 @@ capture_prep_cb(GtkWidget *w, gpointer d) { static void capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) { GtkWidget *if_cb, *filter_te, *count_cb, *snap_sb; - gchar *filter_text; + char tmpname[128+1]; if_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_IFACE_KEY); filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILT_KEY); @@ -341,23 +341,27 @@ capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) { unlink(cf.save_file); /* silently ignore error */ g_free(cf.save_file); } - cf.save_file = tempnam(NULL, "ether"); + cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether"); + cf.save_file = strdup(tmpname); cf.user_saved = 0; if( fork_mode ){ /* use fork() for capture */ int fork_child; char ssnap[24]; char scount[24]; /* need a constant for len of numbers */ + char save_file_fd[24]; int err; - sprintf(ssnap,"%d",cf.snap); /* in liu of itoa */ + sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */ sprintf(scount,"%d",cf.count); + sprintf(save_file_fd,"%d",cf.save_file_fd); signal(SIGCHLD, SIG_IGN); if (sync_mode) pipe(sync_pipe); if((fork_child = fork()) == 0){ /* args: -k -- capture * -i interface specification * -w file to write + * -W file descriptor to write * -c count to capture * -Q quit after capture (forces -k) * -s snaplen @@ -369,18 +373,22 @@ capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) { close(1); dup(sync_pipe[1]); close(sync_pipe[0]); - execlp(ethereal_path,"ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file, + execlp(ethereal_path, "ethereal", "-k", "-Q", "-i", cf.iface, + "-w", cf.save_file, "-W", save_file_fd, "-c", scount, "-s", ssnap, "-S", "-m", medium_font, "-b", bold_font, - (cf.cfilter == NULL)? 0 : "-f", (cf.cfilter == NULL)? 0 : cf.cfilter, - 0); + (cf.cfilter == NULL)? 0 : "-f", + (cf.cfilter == NULL)? 0 : cf.cfilter, + (const char *)NULL); } else { - execlp(ethereal_path,"ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file, + execlp(ethereal_path, "ethereal", "-k", "-Q", "-i", cf.iface, + "-w", cf.save_file, "-W", save_file_fd, "-c", scount, "-s", ssnap, "-m", medium_font, "-b", bold_font, - (cf.cfilter == NULL)? 0 : "-f", (cf.cfilter == NULL)? 0 : cf.cfilter, - 0); + (cf.cfilter == NULL)? 0 : "-f", + (cf.cfilter == NULL)? 0 : cf.cfilter, + (const char *)NULL); } } else { @@ -419,9 +427,10 @@ typedef struct _loop_data { gint go; gint max; gint linktype; + gint wtap_linktype; gint sync_packets; packet_counts counts; - pcap_dumper_t *pdh; + wtap_dumper *pdh; } loop_data; void @@ -434,6 +443,8 @@ capture(void) { bpf_u_int32 netnum, netmask; time_t upd_time, cur_time; int err, inpkts; + char *errmsg; + char errmsg_errno[1024+1]; ld.go = TRUE; ld.counts.total = 0; @@ -454,42 +465,60 @@ capture(void) { pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str); if (pch) { - /* save the old new umask and set the new one to readable only by the user */ - mode_t old_umask = umask(0066); - - /* Have libpcap create the empty dumpfile */ - ld.pdh = pcap_dump_open(pch, cf.save_file); - - /* reset the umask to the original value */ - (void) umask(old_umask); + ld.linktype = pcap_datalink(pch); + ld.wtap_linktype = wtap_pcap_encap_to_wtap_encap(ld.linktype); + ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP, + ld.wtap_linktype, pcap_snapshot(pch), &err); if (ld.pdh == NULL) { /* We have an error */ - snprintf(err_str, PCAP_ERRBUF_SIZE, "Error trying to save capture to " - "file:\n%s", pcap_geterr(pch)); + switch (err) { + + case WTAP_ERR_CANT_OPEN: + errmsg = "The file to which the capture would be saved" + " couldn't be created for some unknown reason."; + break; + + case WTAP_ERR_SHORT_WRITE: + errmsg = "A full header couldn't be written to the file" + " to which the capture would be saved."; + break; + + default: + if (err < 0) { + sprintf(errmsg_errno, "The file to which the capture would be" + " saved (\"%%s\") could not be opened: Error %d.", + err); + } else { + sprintf(errmsg_errno, "The file to which the capture would be" + " saved (\"%%s\") could not be opened: %s.", + strerror(err)); + } + errmsg = errmsg_errno; + break; + } + snprintf(err_str, PCAP_ERRBUF_SIZE, errmsg, cf.save_file); simple_dialog(ESD_TYPE_WARN, NULL, err_str); pcap_close(pch); return; } - ld.linktype = pcap_datalink(pch); - if (cf.cfilter) { if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) { simple_dialog(ESD_TYPE_WARN, NULL, "Can't use filter: Couldn't obtain netmask info."); - pcap_dump_close(ld.pdh); + wtap_dump_close(ld.pdh); unlink(cf.save_file); /* silently ignore error */ pcap_close(pch); return; } else if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) { simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string."); - pcap_dump_close(ld.pdh); + wtap_dump_close(ld.pdh); unlink(cf.save_file); /* silently ignore error */ pcap_close(pch); return; } else if (pcap_setfilter(pch, &cf.fcode) < 0) { simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter."); - pcap_dump_close(ld.pdh); + wtap_dump_close(ld.pdh); unlink(cf.save_file); /* silently ignore error */ pcap_close(pch); return; @@ -501,7 +530,7 @@ capture(void) { system, and signal our parent so that they'll open the capture file and update its windows to indicate that we have a live capture in progress. */ - fflush((FILE *)ld.pdh); + fflush(wtap_dump_file(ld.pdh)); kill(getppid(), SIGUSR2); } @@ -603,7 +632,7 @@ capture(void) { gtk_label_set(GTK_LABEL(other_lb), label_str); /* do sync here, too */ - fflush((FILE *)ld.pdh); + fflush(wtap_dump_file(ld.pdh)); if (sync_mode && ld.sync_packets) { char tmp[20]; sprintf(tmp, "%d*", ld.sync_packets); @@ -613,7 +642,7 @@ capture(void) { } } - if (ld.pdh) pcap_dump_close(ld.pdh); + if (ld.pdh) wtap_dump_close(ld.pdh); pcap_close(pch); gtk_grab_remove(GTK_WIDGET(cap_w)); @@ -664,15 +693,22 @@ capture_stop_cb(GtkWidget *w, gpointer data) { static void capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr, const u_char *pd) { - + struct wtap_pkthdr whdr; loop_data *ld = (loop_data *) user; - + if ((++ld->counts.total >= ld->max) && (ld->max > 0)) { ld->go = FALSE; } - /* Currently, pcap_dumper_t is a FILE *. Let's hope that doesn't change. */ - if (ld->pdh) pcap_dump((u_char *) ld->pdh, phdr, pd); + if (ld->pdh) { + whdr.ts = phdr->ts; + whdr.caplen = phdr->caplen; + whdr.len = phdr->len; + whdr.pkt_encap = ld->wtap_linktype; + + /* XXX - check for errors */ + wtap_dump(ld->pdh, &whdr, pd); + } switch (ld->linktype) { case DLT_EN10MB : diff --git a/ethereal.c b/ethereal.c index cc168fe4e4..82414c2991 100644 --- a/ethereal.c +++ b/ethereal.c @@ -1,6 +1,6 @@ /* ethereal.c * - * $Id: ethereal.c,v 1.94 1999/08/18 02:59:04 guy Exp $ + * $Id: ethereal.c,v 1.95 1999/08/18 04:17:27 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -536,7 +536,7 @@ file_save_cmd_cb(GtkWidget *w, gpointer data) { void file_save_as_cmd_cb(GtkWidget *w, gpointer data) { - file_sel = gtk_file_selection_new ("Ethereal: Save Capture File as"); + file_sel = gtk_file_selection_new ("Ethereal: Save Capture File As"); /* Connect the ok_button to file_save_as_ok_cb function and pass along a pointer to the file selection box widget */ @@ -1122,6 +1122,7 @@ main(int argc, char *argv[]) #endif cf.iface = NULL; cf.save_file = NULL; + cf.save_file_fd = -1; cf.user_saved = 0; cf.snap = MAX_PACKET_SIZE; cf.count = 0; @@ -1149,7 +1150,7 @@ main(int argc, char *argv[]) #ifndef WIN32 /* Now get our args */ - while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:R:Ss:t:T:w:v")) != EOF) { + while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) { switch (opt) { case 'b': /* Bold font */ bold_font = g_strdup(optarg); @@ -1233,9 +1234,12 @@ main(int argc, char *argv[]) exit(0); break; #ifdef HAVE_LIBPCAP - case 'w': /* Write capture file xxx */ + case 'w': /* Write to capture file xxx */ cf.save_file = g_strdup(optarg); break; + case 'W': /* Write to capture file FD xxx */ + cf.save_file_fd = atoi(optarg); + break; #endif } } @@ -1250,6 +1254,13 @@ main(int argc, char *argv[]) fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-w\" flag\n"); exit(1); } + if (fork_mode) { + if (cf.save_file_fd == -1) { + fprintf(stderr, "ethereal: \"-k\" flag was specified with \"-%c\" flag but without \"-W\" flag\n", + (sync_mode ? 'S' : 'F')); + exit(1); + } + } } #ifdef HAVE_LIBPCAP diff --git a/file.h b/file.h index 8326c3f2a2..03dcf5d2d7 100644 --- a/file.h +++ b/file.h @@ -1,7 +1,7 @@ /* file.h * Definitions for file structures and routines * - * $Id: file.h,v 1.36 1999/08/15 19:18:46 guy Exp $ + * $Id: file.h,v 1.37 1999/08/18 04:17:28 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -55,7 +55,7 @@ typedef struct _capture_file { gchar *filename; /* filename */ long f_len; /* File length */ guint16 cd_t; /* Capture data type */ - const gchar *cd_t_desc;/* Description of that data type */ + const gchar *cd_t_desc; /* Description of that data type */ guint32 vers; /* Version. For tcpdump minor is appended to major */ guint32 count; /* Packet count */ gfloat unfiltered_count; /* used for dfilter progress bar */ @@ -65,6 +65,7 @@ typedef struct _capture_file { guint32 snap; /* Captured packet length */ gchar *iface; /* Interface */ gchar *save_file; /* File that user saved capture to */ + int save_file_fd; /* File descriptor for saved file */ gint user_saved;/* Was capture file saved by user yet? */ wtap *wth; /* Wiretap session */ dfilter *rfcode; /* Compiled read filter program */ @@ -114,6 +115,3 @@ char *file_read_error_message(int); char *file_write_error_message(int); #endif /* file.h */ - - - diff --git a/wiretap/file.c b/wiretap/file.c index 1e08ffb821..0d10aa62b4 100644 --- a/wiretap/file.c +++ b/wiretap/file.c @@ -1,6 +1,6 @@ /* file.c * - * $Id: file.c,v 1.13 1999/08/15 06:59:13 guy Exp $ + * $Id: file.c,v 1.14 1999/08/18 04:17:37 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -100,16 +100,15 @@ wtap* wtap_open_offline(const char *filename, int *err) if ((wth->file_type = iptrace_open(wth)) != WTAP_FILE_UNKNOWN) { goto success; } - /* WTAP_FILE_NETMON */ + /* WTAP_FILE_NETMON_xxx */ if ((wth->file_type = netmon_open(wth)) != WTAP_FILE_UNKNOWN) { goto success; } - /* WTAP_FILE_NETXRAY */ + /* WTAP_FILE_NETXRAY_xxx */ if ((wth->file_type = netxray_open(wth)) != WTAP_FILE_UNKNOWN) { goto success; } - /* failure: */ fclose(wth->fh); free(wth); @@ -121,3 +120,102 @@ success: buffer_init(wth->frame_buffer, 1500); return wth; } + + +static wtap_dumper* wtap_dump_open_common(FILE *fh, int filetype, + int encap, int snaplen, int *err); + +wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, + int snaplen, int *err) +{ + FILE *fh; + + /* In case "fopen()" fails but doesn't set "errno", set "errno" + to a generic "the open failed" error. */ + errno = WTAP_ERR_CANT_OPEN; + fh = fopen(filename, "w"); + if (fh == NULL) { + *err = errno; + return NULL; /* can't create file */ + } + return wtap_dump_open_common(fh, filetype, encap, snaplen, err); +} + +wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, + int *err) +{ + FILE *fh; + + /* In case "fopen()" fails but doesn't set "errno", set "errno" + to a generic "the open failed" error. */ + errno = WTAP_ERR_CANT_OPEN; + fh = fdopen(fd, "w"); + if (fh == NULL) { + *err = errno; + return NULL; /* can't create standard I/O stream */ + } + return wtap_dump_open_common(fh, filetype, encap, snaplen, err); +} + +static wtap_dumper* wtap_dump_open_common(FILE *fh, int filetype, int encap, + int snaplen, int *err) +{ + wtap_dumper *wdh; + + wdh = malloc(sizeof (wtap_dumper)); + if (wdh == NULL) { + *err = errno; + /* NOTE: this means the FD handed to "wtap_dump_fdopen()" + will be closed if the malloc fails. */ + fclose(fh); + return NULL; + } + wdh->fh = fh; + wdh->file_type = filetype; + wdh->snaplen = snaplen; + wdh->encap = encap; + + switch (filetype) { + + case WTAP_FILE_PCAP: + if (!libpcap_dump_open(wdh, err)) + goto fail; + break; + + default: + /* We currently only support dumping "libpcap" files */ + *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE; + goto fail; + } + return wdh; + +fail: + free(wdh); + fclose(fh); + return NULL; /* XXX - provide a reason why we failed */ +} + +FILE* wtap_dump_file(wtap_dumper *wdh) +{ + return wdh->fh; +} + +int wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, + const u_char *pd) +{ + return (wdh->subtype_write)(wdh, phdr, pd); +} + +int wtap_dump_close(wtap_dumper *wdh) +{ + int ret = 1; + + if (!(wdh->subtype_close)(wdh)) + ret = 0; + ret = fclose(wdh->fh); + if (ret == EOF) + ret = 0; + free(wdh); + return ret; +} + diff --git a/wiretap/libpcap.c b/wiretap/libpcap.c index 34232712de..c44eeee62e 100644 --- a/wiretap/libpcap.c +++ b/wiretap/libpcap.c @@ -1,6 +1,6 @@ /* libpcap.c * - * $Id: libpcap.c,v 1.6 1999/07/28 23:16:42 guy Exp $ + * $Id: libpcap.c,v 1.7 1999/08/18 04:17:35 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -23,6 +23,8 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include +#include #include "wtap.h" #include "buffer.h" #include "libpcap.h" @@ -64,39 +66,45 @@ struct pcap_hdr { struct pcaprec_hdr { guint32 ts_sec; /* timestamp seconds */ guint32 ts_usec; /* timestamp microseconds */ - guint32 incl_len; /* number of octets captured in file */ + guint32 incl_len; /* number of octets of packet saved in file */ guint32 orig_len; /* actual length of packet */ }; +static int libpcap_read(wtap *wth); +static int libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, + const u_char *pd); +static int libpcap_dump_close(wtap_dumper *wdh); + +static const int pcap_encap[] = { + WTAP_ENCAP_NONE, /* no encapsulation */ + WTAP_ENCAP_ETHERNET, + WTAP_ENCAP_NONE, /* 3Mb experimental Ethernet */ + WTAP_ENCAP_NONE, /* Amateur Radio AX.25 */ + WTAP_ENCAP_NONE, /* Proteon ProNET Token Ring */ + WTAP_ENCAP_NONE, /* Chaos */ + WTAP_ENCAP_TR, /* IEEE 802 Networks - assume token ring */ + WTAP_ENCAP_ARCNET, + WTAP_ENCAP_SLIP, + WTAP_ENCAP_PPP, + WTAP_ENCAP_FDDI, + WTAP_ENCAP_ATM_RFC1483, + WTAP_ENCAP_RAW_IP, + WTAP_ENCAP_NONE, + WTAP_ENCAP_NONE, + WTAP_ENCAP_NONE, + WTAP_ENCAP_NONE, + WTAP_ENCAP_NONE, + WTAP_ENCAP_NONE, + WTAP_ENCAP_LINUX_ATM_CLIP +}; +#define NUM_PCAP_ENCAPS (sizeof pcap_encap / sizeof pcap_encap[0]) + /* Returns WTAP_FILE_PCAP on success, WTAP_FILE_UNKNOWN on failure */ int libpcap_open(wtap *wth) { int bytes_read; guint32 magic; struct pcap_hdr hdr; - static const int pcap_encap[] = { - WTAP_ENCAP_NONE, /* no encapsulation */ - WTAP_ENCAP_ETHERNET, - WTAP_ENCAP_NONE, /* 3Mb experimental Ethernet */ - WTAP_ENCAP_NONE, /* Amateur Radio AX.25 */ - WTAP_ENCAP_NONE, /* Proteon ProNET Token Ring */ - WTAP_ENCAP_NONE, /* Chaos */ - WTAP_ENCAP_TR, /* IEEE 802 Networks - assume token ring */ - WTAP_ENCAP_ARCNET, - WTAP_ENCAP_SLIP, - WTAP_ENCAP_PPP, - WTAP_ENCAP_FDDI, - WTAP_ENCAP_ATM_RFC1483, - WTAP_ENCAP_RAW_IP, - WTAP_ENCAP_NONE, - WTAP_ENCAP_NONE, - WTAP_ENCAP_NONE, - WTAP_ENCAP_NONE, - WTAP_ENCAP_NONE, - WTAP_ENCAP_NONE, - WTAP_ENCAP_LINUX_ATM_CLIP - }; - #define NUM_PCAP_ENCAPS (sizeof pcap_encap / sizeof pcap_encap[0]) int byte_swapped = 0; /* Read in the number that should be at the start of a "libpcap" file */ @@ -151,7 +159,7 @@ int libpcap_open(wtap *wth) } /* Read the next packet */ -int libpcap_read(wtap *wth) +static int libpcap_read(wtap *wth) { int packet_size; int bytes_read; @@ -220,3 +228,97 @@ int libpcap_read(wtap *wth) return data_offset; } + +int wtap_pcap_encap_to_wtap_encap(int encap) +{ + if (encap < 0 || encap >= NUM_PCAP_ENCAPS) + return WTAP_FILE_UNKNOWN; + return pcap_encap[encap]; +} + +/* Returns 1 on success, 0 on failure; sets "*err" to an error code on + failure */ +int libpcap_dump_open(wtap_dumper *wdh, int *err) +{ + static const guint32 pcap_magic = PCAP_MAGIC; + struct pcap_hdr file_hdr; + static const int wtap_encap[] = { + 0, /* WTAP_ENCAP_NONE */ + 1, /* WTAP_ENCAP_ETHERNET */ + 6, /* WTAP_ENCAP_TR */ + 8, /* WTAP_ENCAP_SLIP */ + 9, /* WTAP_ENCAP_PPP */ + 10, /* WTAP_ENCAP_FDDI */ + 12, /* WTAP_ENCAP_RAW_IP */ + 7, /* WTAP_ENCAP_ARCNET */ + 11, /* WTAP_ENCAP_ATM_RFC1483 */ + 19 /* WTAP_ENCAP_LINUX_ATM_CLIP */ + }; + int nwritten; + + /* Per-packet encapsulations aren't supported. */ + if (wdh->encap == WTAP_ENCAP_PER_PACKET) { + *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED; + return 0; + } + + /* This is a libpcap file */ + wdh->subtype_write = libpcap_dump; + wdh->subtype_close = libpcap_dump_close; + + /* Write the file header. */ + nwritten = fwrite(&pcap_magic, 1, sizeof pcap_magic, wdh->fh); + if (nwritten != sizeof pcap_magic) { + if (nwritten < 0) + *err = errno; + else + *err = WTAP_ERR_SHORT_WRITE; + return 0; + } + + /* current "libpcap" format is 2.4 */ + file_hdr.version_major = 2; + file_hdr.version_minor = 4; + file_hdr.thiszone = 0; /* XXX - current offset? */ + file_hdr.sigfigs = 0; /* unknown, but also apparently unused */ + file_hdr.snaplen = wdh->snaplen; + file_hdr.network = wtap_encap[wdh->encap]; + nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh); + if (nwritten != sizeof file_hdr) { + if (nwritten < 0) + *err = errno; + else + *err = WTAP_ERR_SHORT_WRITE; + return 0; + } + + return 1; +} + +/* Write a record for a packet to a dump file. + Returns 1 on success, 0 on failure. */ +static int libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, + const u_char *pd) +{ + struct pcaprec_hdr rec_hdr; + int nwritten; + + rec_hdr.ts_sec = phdr->ts.tv_sec; + rec_hdr.ts_usec = phdr->ts.tv_usec; + rec_hdr.incl_len = phdr->caplen; + rec_hdr.orig_len = phdr->len; + nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, wdh->fh); + if (nwritten != sizeof rec_hdr) + return 0; /* failed (XXX - save reason why) */ + nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh); + if (nwritten != phdr->caplen) + return 0; /* failed (XXX - save reason why) */ + return 1; +} + +/* Close a dump file. + Returns 1 on success, 0 on failure. */ +static int libpcap_dump_close(wtap_dumper *wdh) +{ + return 1; +} diff --git a/wiretap/libpcap.h b/wiretap/libpcap.h index 5de0a34e71..2bd1449996 100644 --- a/wiretap/libpcap.h +++ b/wiretap/libpcap.h @@ -1,6 +1,6 @@ /* libpcap.h * - * $Id: libpcap.h,v 1.1 1998/11/15 05:29:12 guy Exp $ + * $Id: libpcap.h,v 1.2 1999/08/18 04:17:36 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -22,4 +22,4 @@ */ int libpcap_open(wtap *wth); -int libpcap_read(wtap *wth); +int libpcap_dump_open(wtap_dumper *wdh, int *err); diff --git a/wiretap/netmon.c b/wiretap/netmon.c index dba0cf5784..32ce63e1b1 100644 --- a/wiretap/netmon.c +++ b/wiretap/netmon.c @@ -1,6 +1,6 @@ /* netmon.c * - * $Id: netmon.c,v 1.8 1999/07/13 02:53:24 gram Exp $ + * $Id: netmon.c,v 1.9 1999/08/18 04:17:38 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -95,6 +95,7 @@ int netmon_open(wtap *wth) int bytes_read; char magic[sizeof netmon_1_x_magic]; struct netmon_hdr hdr; + int file_type; static const int netmon_encap[] = { WTAP_ENCAP_NONE, WTAP_ENCAP_ETHERNET, @@ -135,9 +136,11 @@ int netmon_open(wtap *wth) switch (hdr.ver_major) { case 1: + file_type = WTAP_FILE_NETMON_1_x; break; case 2: + file_type = WTAP_FILE_NETMON_2_x; break; default: @@ -195,7 +198,7 @@ int netmon_open(wtap *wth) /* Seek to the beginning of the data records. */ fseek(wth->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET); - return WTAP_FILE_NETMON; + return file_type; } /* Read the next packet */ diff --git a/wiretap/netxray.c b/wiretap/netxray.c index 92fe34a398..17ce354b43 100644 --- a/wiretap/netxray.c +++ b/wiretap/netxray.c @@ -1,6 +1,6 @@ /* netxray.c * - * $Id: netxray.c,v 1.8 1999/07/13 02:53:25 gram Exp $ + * $Id: netxray.c,v 1.9 1999/08/18 04:17:37 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -94,6 +94,7 @@ int netxray_open(wtap *wth) struct netxray_hdr hdr; double timeunit; int version_major; + int file_type; double t; static const int netxray_encap[] = { WTAP_ENCAP_ETHERNET, @@ -139,12 +140,15 @@ int netxray_open(wtap *wth) if (memcmp(hdr.version, vers_1_0, sizeof vers_1_0) == 0) { timeunit = 1000.0; version_major = 1; + file_type = WTAP_FILE_NETXRAY_1_0; } else if (memcmp(hdr.version, vers_1_1, sizeof vers_1_1) == 0) { timeunit = 1000000.0; version_major = 1; + file_type = WTAP_FILE_NETXRAY_1_1; } else if (memcmp(hdr.version, vers_2_001, sizeof vers_2_001) == 0) { timeunit = 1000000.0; version_major = 2; + file_type = WTAP_FILE_NETXRAY_2_001; } else { return WTAP_FILE_UNKNOWN; } @@ -179,7 +183,7 @@ int netxray_open(wtap *wth) /* Seek to the beginning of the data records. */ fseek(wth->fh, pletohl(&hdr.start_offset), SEEK_SET); - return WTAP_FILE_NETXRAY; + return file_type; } /* Read the next packet */ diff --git a/wiretap/wtap.c b/wiretap/wtap.c index aae8794639..49f9312f42 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -1,6 +1,6 @@ /* wtap.c * - * $Id: wtap.c,v 1.13 1999/08/02 02:35:57 guy Exp $ + * $Id: wtap.c,v 1.14 1999/08/18 04:17:37 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -62,11 +62,20 @@ const char *wtap_file_type_string(wtap *wth) case WTAP_FILE_IPTRACE: return "iptrace"; - case WTAP_FILE_NETMON: - return "Microsoft Network Monitor"; + case WTAP_FILE_NETMON_1_x: + return "Microsoft Network Monitor 1.x"; - case WTAP_FILE_NETXRAY: - return "Cinco Networks NetXRay/Network Associates Sniffer (Windows-based)"; + case WTAP_FILE_NETMON_2_x: + return "Microsoft Network Monitor 2.x"; + + case WTAP_FILE_NETXRAY_1_0: + return "Cinco Networks NetXRay"; + + case WTAP_FILE_NETXRAY_1_1: + return "Network Associates Sniffer (Windows-based) 1.1"; + + case WTAP_FILE_NETXRAY_2_001: + return "Network Associates Sniffer (Windows-based) 2.001"; case WTAP_FILE_RADCOM: return "RADCOM WAN/LAN analyzer"; @@ -100,11 +109,14 @@ void wtap_close(wtap *wth) g_free(wth->capture.radcom); break; - case WTAP_FILE_NETMON: + case WTAP_FILE_NETMON_1_x: + case WTAP_FILE_NETMON_2_x: g_free(wth->capture.netmon); break; - case WTAP_FILE_NETXRAY: + case WTAP_FILE_NETXRAY_1_0: + case WTAP_FILE_NETXRAY_1_1: + case WTAP_FILE_NETXRAY_2_001: g_free(wth->capture.netxray); break; diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 9664d2a427..e1a7465460 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1,6 +1,6 @@ /* wtap.h * - * $Id: wtap.h,v 1.23 1999/08/15 06:59:13 guy Exp $ + * $Id: wtap.h,v 1.24 1999/08/18 04:17:36 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -32,7 +32,13 @@ * that code adds a DLT_ATM_CLIP DLT_ code of 19, and that * encapsulation isn't the same as the DLT_ATM_RFC1483 encapsulation * presumably used on some BSD systems, which we turn into - * WTAP_ENCAP_ATM_RFC1483. */ + * WTAP_ENCAP_ATM_RFC1483. + * + * WTAP_ENCAP_PER_PACKET is a value passed to "wtap_dump_open()" or + * "wtap_dump_fdopen()" to indicate that there is no single encapsulation + * type for all packets in the file; this may cause those routines to + * fail if the capture file format being written can't support that. */ +#define WTAP_ENCAP_PER_PACKET -1 #define WTAP_ENCAP_NONE 0 #define WTAP_ENCAP_ETHERNET 1 #define WTAP_ENCAP_TR 2 @@ -48,7 +54,9 @@ /* last WTAP_ENCAP_ value + 1 */ #define WTAP_NUM_ENCAP_TYPES 11 -/* File types that can be read by wiretap */ +/* File types that can be read by wiretap. + We may eventually support writing some or all of these file types, + too, so we distinguish between different versions of them. */ #define WTAP_FILE_UNKNOWN 0 #define WTAP_FILE_WTAP 1 #define WTAP_FILE_PCAP 2 @@ -56,9 +64,12 @@ #define WTAP_FILE_NGSNIFFER 4 #define WTAP_FILE_SNOOP 6 #define WTAP_FILE_IPTRACE 7 -#define WTAP_FILE_NETMON 8 -#define WTAP_FILE_NETXRAY 9 -#define WTAP_FILE_RADCOM 10 +#define WTAP_FILE_NETMON_1_x 8 +#define WTAP_FILE_NETMON_2_x 9 +#define WTAP_FILE_NETXRAY_1_0 10 +#define WTAP_FILE_NETXRAY_1_1 11 +#define WTAP_FILE_NETXRAY_2_001 12 +#define WTAP_FILE_RADCOM 13 /* Filter types that wiretap can create. An 'offline' filter is really * a BPF filter, but it is treated specially because wiretap might not know @@ -162,12 +173,25 @@ typedef struct wtap { types */ } wtap; +struct wtap_dumper; + +typedef int (*subtype_write_func)(struct wtap_dumper*, + const struct wtap_pkthdr*, const u_char*); +typedef int (*subtype_close_func)(struct wtap_dumper *); +typedef struct wtap_dumper { + FILE* fh; + int file_type; + int snaplen; + int encap; + + subtype_write_func subtype_write; + subtype_close_func subtype_close; +} wtap_dumper; + /* * On failure, "wtap_open_offline()" returns NULL, and puts into the * "int" pointed to by its second argument: * - * 0 on success; - * * a positive "errno" value if the capture file can't be opened; * * a negative number, indicating the type of error, on other failures. @@ -184,6 +208,35 @@ int wtap_file_type(wtap *wth); const char *wtap_file_type_string(wtap *wth); void wtap_close(wtap *wth); +/* + * On failure, "wtap_dump_open()" and "wtap_dump_fdopen()" return NULL, + * and put into the "int" pointed to by its second argument: + * + * a positive "errno" value if the capture file can't be created, or + * some other failure that sets "errno" occurs; + * + * a negative number, indicating the type of error, on other failures. + */ +#define WTAP_ERR_CANT_OPEN -1 + /* couldn't open, reason unknown */ +#define WTAP_ERR_UNSUPPORTED_FILE_TYPE -2 + /* can't save files in that format */ +#define WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED -3 + /* that format doesn't support per-packet encapsulations */ +#define WTAP_ERR_SHORT_WRITE -4 + /* write wrote less data than it should have */ + +wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, + int snaplen, int *err); +wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, + int *err); +int wtap_dump(wtap_dumper *, const struct wtap_pkthdr *, const u_char *); +FILE* wtap_dump_file(wtap_dumper *); +int wtap_dump_close(wtap_dumper *); + +/* XXX - needed until "wiretap" can do live packet captures */ +int wtap_pcap_encap_to_wtap_encap(int encap); + /* Pointer versions of ntohs and ntohl. Given a pointer to a member of a * byte array, returns the value of the two or four bytes at the pointer. * The pletoh[sl] versions return the little-endian representation. -- 2.34.1