Add to Wiretap the ability to write capture files; for now, it can only
authorGuy Harris <guy@alum.mit.edu>
Wed, 18 Aug 1999 04:17:38 +0000 (04:17 -0000)
committerGuy Harris <guy@alum.mit.edu>
Wed, 18 Aug 1999 04:17:38 +0000 (04:17 -0000)
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
ethereal.c
file.h
wiretap/file.c
wiretap/libpcap.c
wiretap/libpcap.h
wiretap/netmon.c
wiretap/netxray.c
wiretap/wtap.c
wiretap/wtap.h

index 7fef47e3e94b9807c5275f85582a541cd314a1f8..bbfd0c99c757160cb13c8baa55c7217a08536c4d 100644 (file)
--- 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 <gerald@zing.org>
@@ -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 :
index cc168fe4e4f81a928e8109bd8a20ec931bb0f438..82414c299122ec5f0ccc371e18f7bcfcd188f0aa 100644 (file)
@@ -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 <gerald@zing.org>
@@ -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 8326c3f2a271dc79202eeabec3e6d484c8cdbffd..03dcf5d2d7c50b8be5ca91d0b72c3b500ca4eec0 100644 (file)
--- 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 <gerald@zing.org>
@@ -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 */
-
-
-
index 1e08ffb8210d42ea7027644b8e4476a29c0e1b50..0d10aa62b420acaeed412d9ab592b008009c683c 100644 (file)
@@ -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 <gram@verdict.uthscsa.edu>
@@ -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;
+}
+
index 34232712de2b88e5a71f95b237b0460bd1df91fc..c44eeee62ec56509c5511f433661f42f65e4096e 100644 (file)
@@ -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 <gram@verdict.uthscsa.edu>
@@ -23,6 +23,8 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+#include <stdlib.h>
+#include <errno.h>
 #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;
+}
index 5de0a34e7142fee1439deece93546ebc550d019a..2bd1449996ef5aea4daad158e7f09d223c563cb1 100644 (file)
@@ -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 <gram@verdict.uthscsa.edu>
@@ -22,4 +22,4 @@
  */
 
 int libpcap_open(wtap *wth);
-int libpcap_read(wtap *wth);
+int libpcap_dump_open(wtap_dumper *wdh, int *err);
index dba0cf5784f03e07a94d55e2ccbf7e8f0508a982..32ce63e1b10fe36929588a1d38ff07a3a378ab3d 100644 (file)
@@ -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 <gram@verdict.uthscsa.edu>
@@ -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 */
index 92fe34a398ce5c298cc4f2f531577d120bf36d22..17ce354b43115765b690507ccdb80ab45fd85a42 100644 (file)
@@ -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 <gram@verdict.uthscsa.edu>
@@ -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 */
index aae879463970fc196041170e64f2f7ca50ba5689..49f9312f42a91686779355011e0c51d644a448ea 100644 (file)
@@ -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 <gram@verdict.uthscsa.edu>
@@ -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;
 
index 9664d2a4275b024244d9417a0ed81012b760dee9..e1a7465460ab0b8100684fd453ead3dfbc58e745 100644 (file)
@@ -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 <gram@verdict.uthscsa.edu>
  * 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
 #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.