aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap
diff options
context:
space:
mode:
authorBill Meier <wmeier@newsguy.com>2010-10-20 00:36:53 +0000
committerBill Meier <wmeier@newsguy.com>2010-10-20 00:36:53 +0000
commit9787a5734a75c813891ea1eba9ef8998e91ad9b2 (patch)
treebb3effb35a2e0047d5191d8777121d37a6a276d5 /wiretap
parenta75d7209f56e576ef2146026dd791d81acb1fc0b (diff)
From Hadriel Kaplan: IPFIX file format support.
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5242 svn path=/trunk/; revision=34576
Diffstat (limited to 'wiretap')
-rw-r--r--wiretap/AUTHORS11
-rw-r--r--wiretap/CMakeLists.txt1
-rw-r--r--wiretap/Makefile.common2
-rw-r--r--wiretap/file_access.c12
-rw-r--r--wiretap/ipfix.c326
-rw-r--r--wiretap/ipfix.h30
-rw-r--r--wiretap/wtap.c3
-rw-r--r--wiretap/wtap.h2
8 files changed, 378 insertions, 9 deletions
diff --git a/wiretap/AUTHORS b/wiretap/AUTHORS
index 79b4b7166b..8f3b9fd027 100644
--- a/wiretap/AUTHORS
+++ b/wiretap/AUTHORS
@@ -26,8 +26,9 @@ Martijn Schipper <mschipper[AT]globespanvirata.com>
Jeff Morriss <jeff.morriss[AT]ulticom.com>
Niels Koot <Niels.Koot[AT]logicacmg.com>
Rolf Fiedler <Rolf.Fiedler[AT]Innoventif.com>
-James Fields <jvfields [AT] tds.net>
-Kevin Johnson <kjohnson [AT] secureideas.net>
-Yoshihiro Oyama <y.oyama [AT] netagent.co.jp>
-Robert Long <rlong [AT] sandia.gov>
-Clay Jones <clay.jones [AT] email.com>
+James Fields <jvfields[AT]tds.net>
+Kevin Johnson <kjohnson[AT]secureideas.net>
+Yoshihiro Oyama <y.oyama[AT]netagent.co.jp>
+Robert Long <rlong[AT]sandia.gov>
+Clay Jones <clay.jones[AT]email.com>
+Hadriel Kaplan <hadrielk[AT]yahoo.com>
diff --git a/wiretap/CMakeLists.txt b/wiretap/CMakeLists.txt
index 6d416d2a0f..c42d95e8ba 100644
--- a/wiretap/CMakeLists.txt
+++ b/wiretap/CMakeLists.txt
@@ -44,6 +44,7 @@ set(WIRETAP_FILES
file_wrappers.c
hcidump.c
i4btrace.c
+ ipfix.c
iptrace.c
iseries.c
jpeg_jfif.c
diff --git a/wiretap/Makefile.common b/wiretap/Makefile.common
index 0a4de5d6b0..55ab781368 100644
--- a/wiretap/Makefile.common
+++ b/wiretap/Makefile.common
@@ -50,6 +50,7 @@ NONGENERATED_C_FILES = \
file_wrappers.c \
hcidump.c \
i4btrace.c \
+ ipfix.c \
iptrace.c \
iseries.c \
jpeg_jfif.c \
@@ -100,6 +101,7 @@ NONGENERATED_HEADER_FILES = \
hcidump.h \
i4btrace.h \
i4b_trace.h \
+ ipfix.h \
iptrace.h \
iseries.h \
jpeg_jfif.h \
diff --git a/wiretap/file_access.c b/wiretap/file_access.c
index 44d63a7f19..afbed01a0e 100644
--- a/wiretap/file_access.c
+++ b/wiretap/file_access.c
@@ -83,6 +83,7 @@
#include "daintree-sna.h"
#include "netscaler.h"
#include "jpeg_jfif.h"
+#include "ipfix.h"
/* The open_file_* routines should return:
@@ -145,6 +146,7 @@ static wtap_open_routine_t open_routines_base[] = {
*/
netscreen_open,
erf_open,
+ ipfix_open,
k12text_open,
etherpeek_open,
pppdump_open,
@@ -598,7 +600,7 @@ static const struct file_type_info dump_open_table_base[] = {
/* WTAP_FILE_BTSNOOP */
{ "Symbian OS btsnoop", "btsnoop", "*.log", ".log", FALSE,
btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
-
+
/* WTAP_FILE_X2E_XORAYA */
{ NULL, NULL, NULL, NULL, FALSE, NULL, NULL },
@@ -625,6 +627,9 @@ static const struct file_type_info dump_open_table_base[] = {
/* WTAP_FILE_JPEG_JFIF */
{ "JPEG/JFIF", "jpeg", "*.jpg;*.jpeg;*.jfif", ".jpg", FALSE, NULL, NULL },
+ /* WTAP_FILE_IPFIX */
+ { "IPFIX File Format", "ipfix", "*.pfx;*.ipfix", NULL, FALSE,
+ NULL, NULL }
};
gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
@@ -1024,9 +1029,8 @@ static FILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
#endif
/* internally writing raw bytes (compressed or not) */
-gboolean
-wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
- int *err)
+gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
+ int *err)
{
size_t nwritten;
#ifdef HAVE_LIBZ
diff --git a/wiretap/ipfix.c b/wiretap/ipfix.c
new file mode 100644
index 0000000000..5e15c1f1bc
--- /dev/null
+++ b/wiretap/ipfix.c
@@ -0,0 +1,326 @@
+/* ipfix.c
+ *
+ * $Id$
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * File format support for ipfix file format
+ * Copyright (c) 2010 by Hadriel Kaplan <hadrielk@yahoo.com>
+ * with generous copying from other wiretaps, such as pcapng
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* File format reference:
+ * RFC 5655 and 5101
+ * http://tools.ietf.org/rfc/rfc5655
+ * http://tools.ietf.org/rfc/rfc5101
+ *
+ * This wiretap is for an ipfix file format reader, per RFC 5655/5101.
+ * All "records" in the file are IPFIX messages, beginning with an IPFIX
+ * message header of 16 bytes as follows from RFC 5101:
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Version Number | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Export Time |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Observation Domain ID |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Figure F: IPFIX Message Header Format
+
+ * which is then followed by one or more "Sets": Data Sets, Template Sets,
+ * and Options Template Sets. Each Set then has one or more Records in
+ * it.
+ *
+ * All IPFIX files are recorded in big-endian form (network byte order),
+ * per the RFCs. That means if we're on a little-endian system, all
+ * hell will break loose if we don't g_ntohX.
+ *
+ * Since wireshark already has an IPFIX dissector (implemented in
+ * packet-netflow.c), this reader will just set that dissector upon
+ * reading each message. Thus, an IPFIX Message is treated as a packet
+ * as far as the dissector is concerned.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#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)
+#else
+#define ipfix_debug0(str)
+#define ipfix_debug1(str,p1)
+#define ipfix_debug2(str,p1,p2)
+#define ipfix_debug3(str,p1,p2,p3)
+#endif
+
+static gboolean
+ipfix_read(wtap *wth, int *err, gchar **err_info,
+ gint64 *data_offset);
+static gboolean
+ipfix_seek_read(wtap *wth, gint64 seek_off,
+ union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
+ int *err, gchar **err_info);
+static void
+ipfix_close(wtap *wth);
+
+#define IPFIX_VERSION 10
+
+/* ipfix: message header */
+typedef struct ipfix_message_header_s {
+ guint16 version;
+ guint16 message_length;
+ guint32 export_time_secs;
+ guint32 sequence_number;
+ guint32 observation_id; /* might be 0 for none */
+ /* x bytes msg_body */
+} ipfix_message_header_t;
+#define IPFIX_MSG_HDR_SIZE 16
+
+/* ipfix: common Set header for every Set type */
+typedef struct ipfix_set_header_s {
+ guint16 set_type;
+ guint16 set_length;
+ /* x bytes set_body */
+} ipfix_set_header_t;
+#define IPFIX_SET_HDR_SIZE 4
+
+
+/* Read IPFIX message header from file. 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_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);
+
+ /* fix endianess, because IPFIX files are always big-endian */
+ pfx_hdr->version = g_ntohs(pfx_hdr->version);
+ pfx_hdr->message_length = g_ntohs(pfx_hdr->message_length);
+ pfx_hdr->export_time_secs = g_ntohl(pfx_hdr->export_time_secs);
+ pfx_hdr->sequence_number = g_ntohl(pfx_hdr->sequence_number);
+ pfx_hdr->observation_id = g_ntohl(pfx_hdr->observation_id);
+
+ /* is the version number one we expect? */
+ if (pfx_hdr->version != IPFIX_VERSION) {
+ /* Not an ipfix file. */
+ *err = WTAP_ERR_BAD_RECORD;
+ return FALSE;
+ }
+
+ if (pfx_hdr->message_length < 16) {
+ *err_info = g_strdup_printf("ipfix: message length %u is too short", pfx_hdr->message_length);
+ *err = WTAP_ERR_BAD_RECORD;
+ return FALSE;
+ }
+
+ /* 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");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+/* classic wtap: open capture file. Return 1 on success, 0 on normal failure
+ * like malformed format, -1 on bad error like file system
+ */
+int
+ipfix_open(wtap *wth, int *err, gchar **err_info)
+{
+ gint i, n, records_for_ipfix_check = RECORDS_FOR_IPFIX_CHECK;
+ gchar *s;
+ guint16 checked_len = 0;
+ ipfix_message_header_t msg_hdr;
+ ipfix_set_header_t set_hdr;
+
+ ipfix_debug0("ipfix_open: opening file");
+
+ /* number of records to scan before deciding if this really is ERF */
+ if ((s = getenv("IPFIX_RECORDS_TO_CHECK")) != NULL) {
+ if ((n = atoi(s)) > 0 && n < 101) {
+ records_for_ipfix_check = n;
+ }
+ }
+
+ /*
+ * IPFIX is a little hard because there's no magic number; we look at
+ * the first few records and see if they look enough like IPFIX
+ * records.
+ */
+ 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_debug2("ipfix_open: couldn't read message header #%d with err code #%d",
+ i, *err);
+ if (*err == WTAP_ERR_BAD_RECORD) return 0;
+ if (*err != 0) return -1; /* real failure */
+ /* else it's EOF */
+ if (i < 1) {
+ /* we haven't seen enough to prove this is a ipfix file */
+ return 0;
+ }
+ /* if we got here, it's EOF and we think it's an ipfix file */
+ 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",
+ msg_hdr.message_length);
+ return 0;
+ }
+ 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);
+ 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",
+ set_hdr.set_length);
+ return 0;
+ }
+
+ 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",
+ set_hdr.set_length - IPFIX_SET_HDR_SIZE);
+ return 0;
+ }
+ checked_len += set_hdr.set_length;
+ }
+ }
+
+ /* 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->subtype_read = ipfix_read;
+ wth->subtype_seek_read = ipfix_seek_read;
+ wth->subtype_close = ipfix_close;
+ wth->file_type = WTAP_FILE_IPFIX;
+
+ /* go back to beginning of file */
+ if (file_seek (wth->fh, 0, SEEK_SET, err) != 0)
+ {
+ return -1;
+ }
+ return 1;
+}
+
+
+/* classic wtap: read packet */
+static gboolean
+ipfix_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
+{
+ ipfix_message_header_t msg_hdr;
+
+ ipfix_debug1("ipfix_read: wth->data_offset is initially %" G_GINT64_MODIFIER "u", wth->data_offset);
+ *data_offset = wth->data_offset;
+
+ if (!ipfix_read_message_header(&msg_hdr, wth->fh, err, err_info)) {
+ ipfix_debug2("ipfix_read: couldn't read message header with code: %d\n, and error '%s'",
+ *err, *err_info);
+ return FALSE;
+ }
+
+ buffer_assure_space(wth->frame_buffer, msg_hdr.message_length);
+ wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
+ msg_hdr.message_length, wth->fh, err);
+
+ wth->phdr.len = msg_hdr.message_length;
+ wth->phdr.caplen = msg_hdr.message_length;
+ wth->phdr.ts.secs = 0;
+ wth->phdr.ts.nsecs = 0;
+
+ /*ipfix_debug2("Read length: %u Packet length: %u", msg_hdr.message_length, wth->phdr.caplen);*/
+ wth->data_offset += msg_hdr.message_length;
+ ipfix_debug1("ipfix_read: wth->data_offset is finally %" G_GINT64_MODIFIER "u", wth->data_offset);
+
+ return TRUE;
+}
+
+
+/* classic wtap: seek to file position and read packet */
+static gboolean
+ipfix_seek_read(wtap *wth, gint64 seek_off,
+ union wtap_pseudo_header *pseudo_header, guchar *pd, int length _U_,
+ int *err, gchar **err_info)
+{
+ ipfix_message_header_t msg_hdr;
+
+ (void) pseudo_header; /* avoids compiler warning about unused variable */
+
+ /* 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'",
+ *err, *err_info);
+ return FALSE; /* Seek error */
+ }
+
+ ipfix_debug1("ipfix_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
+
+ if (!ipfix_read_message_header(&msg_hdr, wth->random_fh, err, err_info)) {
+ ipfix_debug0("ipfix_read: couldn't read message header");
+ return FALSE;
+ }
+
+ if(length != (int)msg_hdr.message_length) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup_printf("ipfix: record length %u doesn't match requested length %d",
+ msg_hdr.message_length, length);
+ ipfix_debug1("ipfix_seek_read: %s", *err_info);
+ return FALSE;
+ }
+
+ wtap_file_read_expected_bytes(pd, length, wth->random_fh, err);
+
+ return TRUE;
+}
+
+
+/* classic wtap: close capture file */
+static void
+ipfix_close(wtap *wth _U_)
+{
+ ipfix_debug0("ipfix_close: closing file");
+}
+
diff --git a/wiretap/ipfix.h b/wiretap/ipfix.h
new file mode 100644
index 0000000000..0f891a48fe
--- /dev/null
+++ b/wiretap/ipfix.h
@@ -0,0 +1,30 @@
+/* ipfix.h
+ *
+ * $Id$
+ *
+ * Wiretap Library
+ * Copyright (c) 2010 by Hadriel Kaplan <hadrielk@yahoo.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __W_IPFIX_H__
+#define __W_IPFIX_H__
+
+#define RECORDS_FOR_IPFIX_CHECK 20
+
+int ipfix_open(wtap *wth, int *err, gchar **err_info);
+
+#endif
diff --git a/wiretap/wtap.c b/wiretap/wtap.c
index a48ceb813b..ea2193f5fe 100644
--- a/wiretap/wtap.c
+++ b/wiretap/wtap.c
@@ -477,6 +477,9 @@ static struct encap_type_info encap_table_base[] = {
/* WTAP_ENCAP_IEEE802_15_4_NOFCS */
{ "IEEE 802.15.4 Wireless PAN with FCS not present", "wpan-nofcs" },
+
+ /* WTAP_ENCAP_RAW_IPFIX */
+ { "IPFIX", "ipfix" }
};
gint wtap_num_encap_types = sizeof(encap_table_base) / sizeof(struct encap_type_info);
diff --git a/wiretap/wtap.h b/wiretap/wtap.h
index 3a9261a1f3..e4ccc5efba 100644
--- a/wiretap/wtap.h
+++ b/wiretap/wtap.h
@@ -217,6 +217,7 @@ extern "C" {
#define WTAP_ENCAP_SOCKETCAN 125
#define WTAP_ENCAP_IEEE802_11_NETMON_RADIO 126
#define WTAP_ENCAP_IEEE802_15_4_NOFCS 127
+#define WTAP_ENCAP_RAW_IPFIX 128
#define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types()
@@ -283,6 +284,7 @@ extern "C" {
#define WTAP_FILE_NETSCALER_1_0 57
#define WTAP_FILE_NETSCALER_2_0 58
#define WTAP_FILE_JPEG_JFIF 59
+#define WTAP_FILE_IPFIX 60
#define WTAP_NUM_FILE_TYPES wtap_get_num_file_types()