Return the same error for too-large packets as we do for other files.
[metze/wireshark/wip.git] / wiretap / ipfix.c
index 26b2e43e49a7ae6cc0f8433a930339202a8cbc54..b43951e335a9916dbc1697333afb4d61d7dd0919 100644 (file)
@@ -1,6 +1,4 @@
 /* ipfix.c
- *
- * $Id$
  *
  * Wiretap Library
  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
 #include <errno.h>
 #include "wtap-int.h"
 #include "file_wrappers.h"
-#include "buffer.h"
-#include "libpcap.h"
-#include "pcap-common.h"
-#include "pcap-encap.h"
 #include "ipfix.h"
 
 #if 0
-#define ipfix_debug0(str) g_warning(str)
-#define ipfix_debug1(str,p1) g_warning(str,p1)
-#define ipfix_debug2(str,p1,p2) g_warning(str,p1,p2)
-#define ipfix_debug3(str,p1,p2,p3) g_warning(str,p1,p2,p3)
+#define ipfix_debug(...) g_warning(__VA_ARGS__)
 #else
-#define ipfix_debug0(str)
-#define ipfix_debug1(str,p1)
-#define ipfix_debug2(str,p1,p2)
-#define ipfix_debug3(str,p1,p2,p3)
+#define ipfix_debug(...)
 #endif
 
 #define RECORDS_FOR_IPFIX_CHECK 20
@@ -92,10 +80,7 @@ ipfix_read(wtap *wth, int *err, gchar **err_info,
     gint64 *data_offset);
 static gboolean
 ipfix_seek_read(wtap *wth, gint64 seek_off,
-    struct wtap_pkthdr *phdr, Buffer *buf, int length,
-    int *err, gchar **err_info);
-static void
-ipfix_close(wtap *wth);
+    struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
 
 #define IPFIX_VERSION 10
 
@@ -126,7 +111,8 @@ typedef struct ipfix_set_header_s {
 static gboolean
 ipfix_read_message_header(ipfix_message_header_t *pfx_hdr, FILE_T fh, int *err, gchar **err_info)
 {
-    wtap_file_read_expected_bytes(pfx_hdr, IPFIX_MSG_HDR_SIZE, fh, err, err_info);  /* macro which does a return if read fails */
+    if (!wtap_read_bytes_or_eof(fh, pfx_hdr, IPFIX_MSG_HDR_SIZE, err, err_info))
+        return FALSE;
 
     /* fix endianess, because IPFIX files are always big-endian */
     pfx_hdr->version = g_ntohs(pfx_hdr->version);
@@ -151,7 +137,7 @@ ipfix_read_message_header(ipfix_message_header_t *pfx_hdr, FILE_T fh, int *err,
 
     /* go back to before header */
     if (file_seek(fh, 0 - IPFIX_MSG_HDR_SIZE, SEEK_CUR, err) == -1) {
-        ipfix_debug0("ipfix_read: couldn't go back in file before header");
+        ipfix_debug("ipfix_read: couldn't go back in file before header");
         return FALSE;
     }
 
@@ -160,33 +146,40 @@ ipfix_read_message_header(ipfix_message_header_t *pfx_hdr, FILE_T fh, int *err,
 
 
 /* Read IPFIX message header from file and fill in the struct wtap_pkthdr
- * for the packet.  Return true on success.  Set *err to 0 on EOF, any
- * other value for "real" errors (EOF is ok, since return value is still
- * FALSE)
+ * for the packet, and, if that succeeds, read the packet data.
+ * Return true on success.  Set *err to 0 on EOF, any other value for "real"
+ * errors (EOF is ok, since return value is still FALSE).
  */
 static gboolean
-ipfix_read_and_process_message_header(FILE_T fh, struct wtap_pkthdr *phdr, int *err, gchar **err_info)
+ipfix_read_message(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
 {
     ipfix_message_header_t msg_hdr;
 
     if (!ipfix_read_message_header(&msg_hdr, fh, err, err_info))
         return FALSE;
+    /*
+     * The maximum value of msg_hdr.message_length is 65535, which is
+     * less than WTAP_MAX_PACKET_SIZE will ever be, so we don't need
+     * to check it.
+     */
 
+    phdr->rec_type = REC_TYPE_PACKET;
     phdr->presence_flags = WTAP_HAS_TS;
     phdr->len = msg_hdr.message_length;
     phdr->caplen = msg_hdr.message_length;
     phdr->ts.secs = msg_hdr.export_time_secs;
     phdr->ts.nsecs = 0;
 
-    return TRUE;
+    return wtap_read_packet_bytes(fh, buf, msg_hdr.message_length, err, err_info);
 }
 
 
 
-/* classic wtap: open capture file.  Return 1 on success, 0 on normal failure
- * like malformed format, -1 on bad error like file system
+/* classic wtap: open capture file.  Return WTAP_OPEN_MINE on success,
+ * WTAP_OPEN_NOT_MINE on normal failure like malformed format,
+ * WTAP_OPEN_ERROR on bad error like file system
  */
-int
+wtap_open_return_val
 ipfix_open(wtap *wth, int *err, gchar **err_info)
 {
     gint i, n, records_for_ipfix_check = RECORDS_FOR_IPFIX_CHECK;
@@ -195,7 +188,7 @@ ipfix_open(wtap *wth, int *err, gchar **err_info)
     ipfix_message_header_t msg_hdr;
     ipfix_set_header_t set_hdr;
 
-    ipfix_debug0("ipfix_open: opening file");
+    ipfix_debug("ipfix_open: opening file");
 
     /* number of records to scan before deciding if this really is IPFIX */
     if ((s = getenv("IPFIX_RECORDS_TO_CHECK")) != NULL) {
@@ -212,20 +205,20 @@ ipfix_open(wtap *wth, int *err, gchar **err_info)
     for (i = 0; i < records_for_ipfix_check; i++) {
         /* read first message header to check version */
         if (!ipfix_read_message_header(&msg_hdr, wth->fh, err, err_info)) {
-            ipfix_debug3("ipfix_open: couldn't read message header #%d with err code #%d (%s)",
+            ipfix_debug("ipfix_open: couldn't read message header #%d with err code #%d (%s)",
                          i, *err, *err_info);
             if (*err == WTAP_ERR_BAD_FILE) {
                 *err = 0;            /* not actually an error in this case */
                 g_free(*err_info);
                 *err_info = NULL;
-                return 0;
+                return WTAP_OPEN_NOT_MINE;
             }
             if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
-                return -1; /* real failure */
+                return WTAP_OPEN_ERROR; /* real failure */
             /* else it's EOF */
             if (i < 1) {
                 /* we haven't seen enough to prove this is a ipfix file */
-                return 0;
+                return WTAP_OPEN_NOT_MINE;
             }
             /*
              * If we got here, it's EOF and we haven't yet seen anything
@@ -236,49 +229,59 @@ ipfix_open(wtap *wth, int *err, gchar **err_info)
             break;
         }
         if (file_seek(wth->fh, IPFIX_MSG_HDR_SIZE, SEEK_CUR, err) == -1) {
-            ipfix_debug1("ipfix_open: failed seek to next message in file, %d bytes away",
+            ipfix_debug("ipfix_open: failed seek to next message in file, %d bytes away",
                          msg_hdr.message_length);
-            return 0;
+            return WTAP_OPEN_NOT_MINE;
         }
         checked_len = IPFIX_MSG_HDR_SIZE;
 
         /* check each Set in IPFIX Message for sanity */
         while (checked_len < msg_hdr.message_length) {
-            wtap_file_read_expected_bytes(&set_hdr, IPFIX_SET_HDR_SIZE, wth->fh, err, err_info);
+            if (!wtap_read_bytes(wth->fh, &set_hdr, IPFIX_SET_HDR_SIZE,
+                                 err, err_info)) {
+                if (*err == WTAP_ERR_SHORT_READ) {
+                    /* Not a valid IPFIX Set, so not an IPFIX file. */
+                    ipfix_debug("ipfix_open: error %d reading set", *err);
+                    return WTAP_OPEN_NOT_MINE;
+                }
+
+                /* A real I/O error; fail. */
+                return WTAP_OPEN_ERROR;
+            }
             set_hdr.set_length = g_ntohs(set_hdr.set_length);
             if ((set_hdr.set_length < IPFIX_SET_HDR_SIZE) ||
                 ((set_hdr.set_length + checked_len) > msg_hdr.message_length))  {
-                ipfix_debug1("ipfix_open: found invalid set_length of %d",
+                ipfix_debug("ipfix_open: found invalid set_length of %d",
                              set_hdr.set_length);
-                return 0;
+                return WTAP_OPEN_NOT_MINE;
             }
 
             if (file_seek(wth->fh, set_hdr.set_length - IPFIX_SET_HDR_SIZE,
                  SEEK_CUR, err) == -1)
             {
-                ipfix_debug1("ipfix_open: failed seek to next set in file, %d bytes away",
+                ipfix_debug("ipfix_open: failed seek to next set in file, %d bytes away",
                              set_hdr.set_length - IPFIX_SET_HDR_SIZE);
-                return 0;
+                return WTAP_OPEN_ERROR;
             }
             checked_len += set_hdr.set_length;
         }
     }
 
+    /* go back to beginning of file */
+    if (file_seek (wth->fh, 0, SEEK_SET, err) != 0)
+    {
+        return WTAP_OPEN_ERROR;
+    }
+
     /* all's good, this is a IPFIX file */
     wth->file_encap = WTAP_ENCAP_RAW_IPFIX;
     wth->snapshot_length = 0;
-    wth->tsprecision = WTAP_FILE_TSPREC_SEC;
+    wth->file_tsprec = WTAP_TSPREC_SEC;
     wth->subtype_read = ipfix_read;
     wth->subtype_seek_read = ipfix_seek_read;
-    wth->subtype_close = ipfix_close;
-    wth->file_type = WTAP_FILE_IPFIX;
+    wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_IPFIX;
 
-    /* go back to beginning of file */
-    if (file_seek (wth->fh, 0, SEEK_SET, err) != 0)
-    {
-        return -1;
-    }
-    return 1;
+    return WTAP_OPEN_MINE;
 }
 
 
@@ -287,55 +290,50 @@ static gboolean
 ipfix_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
 {
     *data_offset = file_tell(wth->fh);
-    ipfix_debug1("ipfix_read: data_offset is initially %" G_GINT64_MODIFIER "d", *data_offset);
+    ipfix_debug("ipfix_read: data_offset is initially %" G_GINT64_MODIFIER "d", *data_offset);
 
-    if (!ipfix_read_and_process_message_header(wth->fh, &wth->phdr, err, err_info)) {
-        ipfix_debug2("ipfix_read: couldn't read message header with code: %d\n, and error '%s'",
+    if (!ipfix_read_message(wth->fh, &wth->phdr, wth->frame_buffer, err, err_info)) {
+        ipfix_debug("ipfix_read: couldn't read message header with code: %d\n, and error '%s'",
                      *err, *err_info);
         return FALSE;
     }
 
-    return wtap_read_packet_bytes(wth->fh, wth->frame_buffer, wth->phdr.caplen,
-                                  err, err_info);
+    return TRUE;
 }
 
 
 /* classic wtap: seek to file position and read packet */
 static gboolean
-ipfix_seek_read(wtap *wth, gint64 seek_off,
-    struct wtap_pkthdr *phdr, Buffer *buf, int length,
-    int *err, gchar **err_info)
+ipfix_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
+    Buffer *buf, int *err, gchar **err_info)
 {
     /* seek to the right file position */
     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
-        ipfix_debug2("ipfix_seek_read: couldn't read message header with code: %d\n, and error '%s'",
+        ipfix_debug("ipfix_seek_read: couldn't read message header with code: %d\n, and error '%s'",
                      *err, *err_info);
         return FALSE;   /* Seek error */
     }
 
-    ipfix_debug1("ipfix_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
-
-    if (!ipfix_read_and_process_message_header(wth->random_fh, phdr, err, err_info)) {
-        ipfix_debug0("ipfix_seek_read: couldn't read message header");
-        return FALSE;
-    }
+    ipfix_debug("ipfix_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
 
-    if(length != (int)phdr->caplen) {
-        *err = WTAP_ERR_BAD_FILE;
-        *err_info = g_strdup_printf("ipfix: record length %u doesn't match requested length %d",
-                                    phdr->caplen, length);
-        ipfix_debug1("ipfix_seek_read: %s", *err_info);
+    if (!ipfix_read_message(wth->random_fh, phdr, buf, err, err_info)) {
+        ipfix_debug("ipfix_seek_read: couldn't read message header");
+        if (*err == 0)
+            *err = WTAP_ERR_SHORT_READ;
         return FALSE;
     }
-
-    return wtap_read_packet_bytes(wth->random_fh, buf, length, err, err_info);
-}
-
-
-/* classic wtap: close capture file */
-static void
-ipfix_close(wtap *wth _U_)
-{
-    ipfix_debug0("ipfix_close: closing file");
+    return TRUE;
 }
 
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */