Ethereal-dev: [Ethereal-dev] Improved VMS parser

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Marc Milgram <mmilgram@xxxxxxxxxxxx>
Date: 30 Jan 2002 09:30:37 -0500
In answering some questions for the engineer at Compaq who is
responsible for TCPtrace, I found that there were some simple bugs in
the VMS parser.  One was a memory allocation error.  When that bug was
fixed, I found that ethereal crashed on some of the traces - due to a
line of the following form (that may replace any line in the file -
including the packet header line):
	 TCPIPTRACE-W-BUFFERSFULL, TCPIPtrace could not save 2 packets. 

I reworked the parser to handle that error as best it could, and still
accept handle the packet.

If the parser can't get the timestamp for the packet, it is setting the
time to near the begining of Unix time (Jan 1, 1970).  Should I pick
some other time?

-Marc Milgram

Index: wiretap/vms.c
===================================================================
RCS file: /cvsroot/ethereal/wiretap/vms.c,v
retrieving revision 1.4
diff -u -r1.4 vms.c
--- vms.c	2002/01/15 20:18:02	1.4
+++ vms.c	2002/01/30 14:18:59
@@ -74,7 +74,7 @@
 static gboolean vms_read(wtap *wth, int *err, long *data_offset);
 static int vms_seek_read(wtap *wth, long seek_off,
     union wtap_pseudo_header *pseudo_header, guint8 *pd, int len);
-static gboolean parse_single_hex_dump_line(char* rec, guint8 *buf, long byte_offset, int remaining_bytes);
+static gboolean parse_single_hex_dump_line(char* rec, guint8 *buf, long byte_offset, int in_off, int remaining_bytes);
 static int parse_vms_hex_dump(FILE_T fh, int pkt_len, guint8* buf, int *err);
 static int parse_vms_rec_hdr(wtap *wth, FILE_T fh, int *err);
 
@@ -88,6 +88,8 @@
   unsigned int level = 0;
 
   while ((byte = file_getc(wth->fh)) != EOF) {
+    if ((level == 3) && (byte != vms_rec_magic[level]))
+      level += 2;  /* Accept TCPtrace as well as TCPIPtrace */
     if (byte == vms_rec_magic[level]) {
       level++;
       if (level >= VMS_REC_MAGIC_SIZE) {
@@ -132,6 +134,8 @@
             level = 0;
             for (i = 0; i < reclen; i++) {
                 byte = buf[i];
+		if ((level == 3) && (byte != vms_hdr_magic[level]))
+		    level += 2; /* Accept TCPIPtrace as well as TCPtrace */
                 if (byte == vms_hdr_magic[level]) {
                     level++;
                     if (level >= VMS_HDR_MAGIC_SIZE) {
@@ -185,8 +189,11 @@
     /* Parse the header */
     pkt_len = parse_vms_rec_hdr(wth, wth->fh, err);
 
+    if (pkt_len == -1)
+	return FALSE;
+
     /* Make sure we have enough room for the packet */
-    buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
+    buffer_assure_space(wth->frame_buffer, pkt_len);
     buf = buffer_start_ptr(wth->frame_buffer);
 
     /* Convert the ASCII hex dump to binary data */
@@ -244,53 +251,43 @@
 {
     char    line[VMS_LINE_LENGTH];
     int    num_items_scanned;
-    int    pkt_len, pktnum, csec;
+    int	   pkt_len = 0;
+    int	   pktnum;
+    int	   csec = 101;
     struct tm time;
-    char mon[4];
+    char mon[4] = {'J', 'A', 'N', 0};
     guchar *p;
     static guchar months[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
 
-    pkt_len = 0;
+    time.tm_year = 1970;
+    time.tm_hour = 1;
+    time.tm_min = 1;
+    time.tm_sec = 1;
 
-    /* Our file pointer should be on the first line containing the
-     * summary information for a packet. Read in that line and
-     * extract the useful information
-     */
-    if (file_gets(line, VMS_LINE_LENGTH, fh) == NULL) {
-        *err = file_error(fh);
-        if (*err == 0) {
-            *err = WTAP_ERR_SHORT_READ;
-        }
-        return -1;
-    }
 
-    p = strstr(line, "packet ");
-    if ( !p ) {
-        *err = WTAP_ERR_BAD_RECORD;
-        return 01;
-    }
-   
-    /* Find text in line starting with "packet ". */
-    num_items_scanned = sscanf(p,
-                   "packet %d at %d-%3s-%d %d:%d:%d.%d",
-                   &pktnum, &time.tm_mday, mon,
-                   &time.tm_year, &time.tm_hour, &time.tm_min,
-                   &time.tm_sec, &csec);
-
-    if (num_items_scanned != 8) {
-        *err = WTAP_ERR_BAD_RECORD;
-        return -1;
-    }
-
     /* Skip lines until one starts with a hex number */
     do {
         if (file_gets(line, VMS_LINE_LENGTH, fh) == NULL) {
             *err = file_error(fh);
-            if (*err == 0) {
-                *err = WTAP_ERR_SHORT_READ;
+	    if ((*err == 0) && (csec != 101)) {
+		*err = WTAP_ERR_SHORT_READ;
             }
             return -1;
         }
+	if ((csec == 101) && (p = strstr(line, "packet "))
+	    && (! strstr(line, "could not save "))) {
+	    /* Find text in line starting with "packet ". */
+	    num_items_scanned = sscanf(p,
+				       "packet %d at %d-%3s-%d %d:%d:%d.%d",
+				       &pktnum, &time.tm_mday, mon,
+				       &time.tm_year, &time.tm_hour,
+				       &time.tm_min, &time.tm_sec, &csec);
+
+	    if (num_items_scanned != 8) {
+	        *err = WTAP_ERR_BAD_RECORD;
+		return -1;
+	    }
+	}
         if ( (! pkt_len) && (p = strstr(line, "Length"))) {
             p += sizeof("Length ");
             while (*p && ! isdigit(*p))
@@ -328,14 +325,10 @@
 parse_vms_hex_dump(FILE_T fh, int pkt_len, guint8* buf, int *err)
 {
     guchar line[VMS_LINE_LENGTH];
-    int    i, hex_lines;
+    int    i;
     int    offset = 0;
-
-    /* Calculate the number of hex dump lines, each
-     * containing 16 bytes of data */
-    hex_lines = pkt_len / 16 + ((pkt_len % 16) ? 1 : 0);
 
-    for (i = 0; i < hex_lines; i++) {
+    for (i = 0; i < pkt_len; i += 16) {
         if (file_gets(line, VMS_LINE_LENGTH, fh) == NULL) {
             *err = file_error(fh);
             if (*err == 0) {
@@ -355,12 +348,15 @@
             while (line[offset] && !isxdigit(line[offset]))
                 offset++;
 	}
-        if (!parse_single_hex_dump_line(line, buf, i * 16,
-                        offset)) {
+	if (!parse_single_hex_dump_line(line, buf, i,
+					offset, pkt_len - i)) {
             *err = WTAP_ERR_BAD_RECORD;
             return -1;
         }
     }
+    /* Avoid TCPIPTRACE-W-BUFFERSFUL, TCPIPtrace could not save n packets.
+     * errors. */
+    file_gets(line, VMS_LINE_LENGTH, fh);
     return 0;
 }
 
@@ -379,13 +375,11 @@
  * we are passed to validate the record. We place the bytes in the buffer
  * at the specified offset.
  *
- * In the process, we're going to write all over the string.
- *
  * Returns TRUE if good hex dump, FALSE if bad.
  */
 static gboolean
 parse_single_hex_dump_line(char* rec, guint8 *buf, long byte_offset,
-               int in_off) {
+               int in_off, int remaining) {
 
     int        i;
     char        *s;
@@ -402,11 +396,14 @@
         return FALSE;
     }
 
+    if (remaining > 16)
+	remaining = 16;
+
     /* Read the octets right to left, as that is how they are displayed
      * in VMS.
      */
 
-    for (i = 0; i < 16; i++) {
+    for (i = 0; i < remaining; i++) {
         lbuf[0] = rec[offsets[i] + in_off];
         lbuf[1] = rec[offsets[i] + 1 + in_off];