aboutsummaryrefslogtreecommitdiffstats
path: root/packet-netflow.c
diff options
context:
space:
mode:
authorgerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>2002-09-22 16:13:22 +0000
committergerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>2002-09-22 16:13:22 +0000
commit14cd82e00828d159af051ed836139d793c23b668 (patch)
tree06487f48f248e88d44a286ad5f1381026b689b40 /packet-netflow.c
parentdc661cc1a0a8cd2862b05fd8c5cc416e50b60aaa (diff)
Major updates from Bill Fumerola.
Remove packet-netflow.h, since it is no longer needed. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@6314 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'packet-netflow.c')
-rw-r--r--packet-netflow.c1296
1 files changed, 922 insertions, 374 deletions
diff --git a/packet-netflow.c b/packet-netflow.c
index f50875297a..89a9ca3662 100644
--- a/packet-netflow.c
+++ b/packet-netflow.c
@@ -1,26 +1,40 @@
-/* packet-netflow.c
- * Routines for Cisco NetFlow packet disassembly
- * Matthew Smart <smart@monkey.org>
- *
- * $Id: packet-netflow.c,v 1.4 2002/09/09 20:22:51 guy Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
- * Copyright 1998 Gerald Combs
- *
- * 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.
+/*
+ ** packet-netflow.c
+ **
+ *****************************************************************************
+ ** (c) 2002 bill fumerola <fumerola@yahoo-inc.com>
+ ** All rights reserved.
+ **
+ ** 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.
+ *****************************************************************************
+ **
+ ** previous netflow dissector written by Matthew Smart <smart@monkey.org>
+ **
+ *****************************************************************************
+ **
+ ** this code was written from the following documentation:
+ **
+ ** http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_6/iug/format.pdf
+ ** http://www.caida.org/tools/measurement/cflowd/configuration/configuration-9.html
+ **
+ ** some documentation is more accurate then others. in some cases, live data and
+ ** information contained in responses from vendors were also used. some fields
+ ** are dissected as vendor specific fields.
+ **
+ ** $Yahoo: //depot/fumerola/packet-netflow/packet-netflow.c#14 $
+ ** $Id: packet-netflow.c,v 1.5 2002/09/22 16:13:21 gerald Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -30,453 +44,987 @@
#include <glib.h>
#include <epan/packet.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "packet-netflow.h"
-
-static int proto_netflow = -1;
-static int hf_netflow_version = -1;
-static int hf_netflow_count = -1;
-static int hf_netflow_sys_uptime = -1;
-static int hf_netflow_unix_sec = -1;
-static int hf_netflow_unix_nsec = -1;
-static int hf_netflow_sequence = -1;
-static int hf_netflow_engine_type = -1;
-static int hf_netflow_engine_id = -1;
-static int hf_netflow_aggregation = -1;
-static int hf_netflow_agg_version = -1;
-static int hf_netflow_sample_rate = -1;
-static int hf_netflow_record = -1;
-
-static int hf_netflow_src_addr = -1;
-static int hf_netflow_dst_addr = -1;
-static int hf_netflow_next_hop = -1;
-static int hf_netflow_input_iface = -1;
-static int hf_netflow_output_iface = -1;
-static int hf_netflow_packets = -1;
-static int hf_netflow_bytes = -1;
-static int hf_netflow_start_time = -1;
-static int hf_netflow_end_time = -1;
-static int hf_netflow_src_port = -1;
-static int hf_netflow_dst_port = -1;
-static int hf_netflow_v7_flags = -1;
-static int hf_netflow_tcp_flags = -1;
-static int hf_netflow_ip_prot = -1;
-static int hf_netflow_tos = -1;
-static int hf_netflow_src_as = -1;
-static int hf_netflow_dst_as = -1;
-static int hf_netflow_src_mask = -1;
-static int hf_netflow_dst_mask = -1;
-static int hf_netflow_router_sc = -1;
-
-static gint ett_netflow = -1;
-static gint ett_netflow_rec = -1;
+#define UDP_PORT_NETFLOW 2055
+
+/*
+ * pdu identifiers & sizes
+ */
+
+#define V1PDU_SIZE (4 * 12)
+#define V5PDU_SIZE (4 * 12)
+#define V7PDU_SIZE (4 * 13)
+#define V8PDU_AS_SIZE (4 * 7)
+#define V8PDU_PROTO_SIZE (4 * 7)
+#define V8PDU_SPREFIX_SIZE (4 * 8)
+#define V8PDU_DPREFIX_SIZE (4 * 8)
+#define V8PDU_MATRIX_SIZE (4 * 10)
+#define V8PDU_DESTONLY_SIZE (4 * 8)
+#define V8PDU_SRCDEST_SIZE (4 * 10)
+#define V8PDU_FULL_SIZE (4 * 11)
+#define V8PDU_TOSAS_SIZE (V8PDU_AS_SIZE + 4)
+#define V8PDU_TOSPROTOPORT_SIZE (V8PDU_PROTO_SIZE + 4)
+#define V8PDU_TOSSRCPREFIX_SIZE V8PDU_SPREFIX_SIZE
+#define V8PDU_TOSDSTPREFIX_SIZE V8PDU_DPREFIX_SIZE
+#define V8PDU_TOSMATRIX_SIZE V8PDU_MATRIX_SIZE
+#define V8PDU_PREPORTPROTOCOL_SIZE (4 * 10)
+
+enum {
+ V8PDU_NO_METHOD = 0,
+ V8PDU_AS_METHOD,
+ V8PDU_PROTO_METHOD,
+ V8PDU_SPREFIX_METHOD,
+ V8PDU_DPREFIX_METHOD,
+ V8PDU_MATRIX_METHOD,
+ V8PDU_DESTONLY_METHOD,
+ V8PDU_SRCDEST_METHOD,
+ V8PDU_FULL_METHOD,
+ V8PDU_TOSAS_METHOD,
+ V8PDU_TOSPROTOPORT_METHOD,
+ V8PDU_TOSSRCPREFIX_METHOD,
+ V8PDU_TOSDSTPREFIX_METHOD,
+ V8PDU_TOSMATRIX_METHOD,
+ V8PDU_PREPORTPROTOCOL_METHOD
+};
+
+static const value_string v8_agg[] = {
+ {V8PDU_AS_METHOD, "V8 AS aggregation"},
+ {V8PDU_PROTO_METHOD, "V8 Proto/Port aggregation"},
+ {V8PDU_SPREFIX_METHOD, "V8 Source Prefix aggregation"},
+ {V8PDU_DPREFIX_METHOD, "V8 Destination Prefix aggregation"},
+ {V8PDU_MATRIX_METHOD, "V8 Network Matrix aggregation"},
+ {V8PDU_DESTONLY_METHOD, "V8 Destination aggregation (Cisco Catalyst)"},
+ {V8PDU_SRCDEST_METHOD, "V8 Src/Dest aggregation (Cisco Catalyst)"},
+ {V8PDU_FULL_METHOD, "V8 Full aggregation (Cisco Catalyst)"},
+ {V8PDU_TOSAS_METHOD, "V8 TOS+AS aggregation aggregation"},
+ {V8PDU_TOSPROTOPORT_METHOD, "V8 TOS+Protocol aggregation"},
+ {V8PDU_TOSSRCPREFIX_METHOD, "V8 TOS+Source Prefix aggregation"},
+ {V8PDU_TOSDSTPREFIX_METHOD, "V8 TOS+Destination Prefix aggregation"},
+ {V8PDU_TOSMATRIX_METHOD, "V8 TOS+Prefix Matrix aggregation"},
+ {V8PDU_PREPORTPROTOCOL_METHOD, "V8 Port+Protocol aggregation"},
+ {0, NULL}
+};
+
+
+/*
+ * ethereal tree identifiers
+ */
+
+static int proto_netflow = -1;
+static int ett_netflow = -1;
+static int ett_unixtime = -1;
+static int ett_flow = -1;
+
+/*
+ * cflow header
+ */
+
+static int hf_cflow_version = -1;
+static int hf_cflow_count = -1;
+static int hf_cflow_sysuptime = -1;
+static int hf_cflow_unix_secs = -1;
+static int hf_cflow_unix_nsecs = -1;
+static int hf_cflow_timestamp = -1;
+static int hf_cflow_samplerate = -1;
+
+/*
+ * cflow version specific info
+ */
+static int hf_cflow_sequence = -1;
+static int hf_cflow_engine_type = -1;
+static int hf_cflow_engine_id = -1;
+
+static int hf_cflow_aggmethod = -1;
+static int hf_cflow_aggversion = -1;
+
+/*
+ * pdu storage
+ */
+static int hf_cflow_srcaddr = -1;
+static int hf_cflow_srcnet = -1;
+static int hf_cflow_dstaddr = -1;
+static int hf_cflow_dstnet = -1;
+static int hf_cflow_nexthop = -1;
+static int hf_cflow_inputint = -1;
+static int hf_cflow_outputint = -1;
+static int hf_cflow_flows = -1;
+static int hf_cflow_packets = -1;
+static int hf_cflow_octets = -1;
+static int hf_cflow_timestart = -1;
+static int hf_cflow_timeend = -1;
+static int hf_cflow_srcport = -1;
+static int hf_cflow_dstport = -1;
+static int hf_cflow_prot = -1;
+static int hf_cflow_tos = -1;
+static int hf_cflow_flags = -1;
+static int hf_cflow_tcpflags = -1;
+static int hf_cflow_dstas = -1;
+static int hf_cflow_srcas = -1;
+static int hf_cflow_dstmask = -1;
+static int hf_cflow_srcmask = -1;
+static int hf_cflow_routersc = -1;
+
+typedef int dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+ int verspec);
+static int dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
+ int verspec);
+static int dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset, int verspec);
+static int dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset, int verspec);
+
+static gchar *getprefix(const guint32 * address, int prefix);
+static void dissect_netflow(tvbuff_t * tvb, packet_info * pinfo,
+ proto_tree * tree);
+
+static int flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset);
+static int flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset);
+static int flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset);
+static int flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset);
+static int flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset);
+static int flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb,
+ int offset, int bytes,
+ const char *text);
+
static void
-dissect_netflow_157(tvbuff_t *tvb, proto_tree *tree, guint16 version,
- guint offset)
+dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
{
- guint32 addr;
+ proto_tree *netflow_tree = NULL;
+ proto_tree *ti;
+ proto_item *timeitem, *pduitem;
+ proto_tree *timetree, *pdutree;
+ unsigned int pduret, ver = 0, pdus = 0, x = 1, vspec;
+ size_t available, pdusize, offset = 0;
+ nstime_t ts;
+ dissect_pdu_t *pduptr;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFLOW");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ if (tree) {
+ ti = proto_tree_add_item(tree, proto_netflow, tvb,
+ offset, -1, FALSE);
+ netflow_tree = proto_item_add_subtree(ti, ett_netflow);
+ }
+
+ ver = tvb_get_ntohs(tvb, offset);
+ vspec = ver;
+ switch (ver) {
+ case 1:
+ pdusize = V1PDU_SIZE;
+ pduptr = &dissect_pdu;
+ break;
+ case 5:
+ pdusize = V5PDU_SIZE;
+ pduptr = &dissect_pdu;
+ break;
+ case 7:
+ pdusize = V7PDU_SIZE;
+ pduptr = &dissect_pdu;
+ break;
+ case 8:
+ pdusize = -1; /* deferred */
+ pduptr = &dissect_v8_aggpdu;
+ break;
+ default:
+ return;
+ }
+
+ if (tree)
+ proto_tree_add_uint(netflow_tree, hf_cflow_version, tvb,
+ offset, 2, ver);
+ offset += 2;
- tvb_memcpy(tvb, (guint8 *)&addr, offset, 4);
- proto_tree_add_ipv4(tree, hf_netflow_src_addr, tvb, offset, 4, addr);
+ pdus = tvb_get_ntohs(tvb, offset);
+ if (pdus <= 0)
+ return;
+ if (tree)
+ proto_tree_add_uint(netflow_tree, hf_cflow_count, tvb,
+ offset, 2, pdus);
+ offset += 2;
+
+ /*
+ * set something interesting in the display now that we have info
+ */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "total: %u (v%u) flows",
+ pdus, ver);
+
+ /*
+ * the rest is only interesting if we're displaying/searching the
+ * packet
+ */
+ if (!tree)
+ return;
+
+ proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb,
+ offset, 4, FALSE);
offset += 4;
- tvb_memcpy(tvb, (guint8 *)&addr, offset, 4);
- proto_tree_add_ipv4(tree, hf_netflow_dst_addr, tvb, offset, 4, addr);
+ ts.secs = tvb_get_ntohl(tvb, offset);
+ ts.nsecs = tvb_get_ntohl(tvb, offset + 4);
+ timeitem = proto_tree_add_time(netflow_tree,
+ hf_cflow_timestamp, tvb, offset,
+ 8, &ts);
+ timetree = proto_item_add_subtree(timeitem, ett_unixtime);
+
+ proto_tree_add_item(timetree, hf_cflow_unix_secs, tvb,
+ offset, 4, FALSE);
offset += 4;
- tvb_memcpy(tvb, (guint8 *)&addr, offset, 4);
- proto_tree_add_ipv4(tree, hf_netflow_next_hop, tvb, offset, 4, addr);
+ proto_tree_add_item(timetree, hf_cflow_unix_nsecs, tvb,
+ offset, 4, FALSE);
offset += 4;
- proto_tree_add_item(tree, hf_netflow_input_iface,
- tvb, offset, 2, FALSE);
+ /*
+ * version specific header
+ */
+ if (ver == 5 || ver == 7 || ver == 8) {
+ proto_tree_add_item(netflow_tree, hf_cflow_sequence,
+ tvb, offset, 4, FALSE);
+ offset += 4;
+ }
+ if (ver == 5 || ver == 8) {
+ proto_tree_add_item(netflow_tree, hf_cflow_engine_type,
+ tvb, offset++, 1, FALSE);
+ proto_tree_add_item(netflow_tree, hf_cflow_engine_id,
+ tvb, offset++, 1, FALSE);
+ }
+ if (ver == 8) {
+ vspec = tvb_get_guint8(tvb, offset);
+ switch (vspec) {
+ case V8PDU_AS_METHOD:
+ pdusize = V8PDU_AS_SIZE;
+ break;
+ case V8PDU_PROTO_METHOD:
+ pdusize = V8PDU_PROTO_SIZE;
+ break;
+ case V8PDU_SPREFIX_METHOD:
+ pdusize = V8PDU_SPREFIX_SIZE;
+ break;
+ case V8PDU_DPREFIX_METHOD:
+ pdusize = V8PDU_DPREFIX_SIZE;
+ break;
+ case V8PDU_MATRIX_METHOD:
+ pdusize = V8PDU_MATRIX_SIZE;
+ break;
+ case V8PDU_DESTONLY_METHOD:
+ pdusize = V8PDU_DESTONLY_SIZE;
+ pduptr = &dissect_v8_flowpdu;
+ break;
+ case V8PDU_SRCDEST_METHOD:
+ pdusize = V8PDU_SRCDEST_SIZE;
+ pduptr = &dissect_v8_flowpdu;
+ break;
+ case V8PDU_FULL_METHOD:
+ pdusize = V8PDU_FULL_SIZE;
+ pduptr = &dissect_v8_flowpdu;
+ break;
+ case V8PDU_TOSAS_METHOD:
+ pdusize = V8PDU_TOSAS_SIZE;
+ break;
+ case V8PDU_TOSPROTOPORT_METHOD:
+ pdusize = V8PDU_TOSPROTOPORT_SIZE;
+ break;
+ case V8PDU_TOSSRCPREFIX_METHOD:
+ pdusize = V8PDU_TOSSRCPREFIX_SIZE;
+ break;
+ case V8PDU_TOSDSTPREFIX_METHOD:
+ pdusize = V8PDU_TOSDSTPREFIX_SIZE;
+ break;
+ case V8PDU_TOSMATRIX_METHOD:
+ pdusize = V8PDU_TOSMATRIX_SIZE;
+ break;
+ case V8PDU_PREPORTPROTOCOL_METHOD:
+ pdusize = V8PDU_PREPORTPROTOCOL_SIZE;
+ break;
+ default:
+ pdusize = -1;
+ vspec = 0;
+ break;
+ }
+ proto_tree_add_uint(netflow_tree, hf_cflow_aggmethod,
+ tvb, offset++, 1, vspec);
+ proto_tree_add_item(netflow_tree, hf_cflow_aggversion,
+ tvb, offset++, 1, FALSE);
+ }
+ if (ver == 7 || ver == 8)
+ offset = flow_process_textfield(netflow_tree, tvb, offset, 4,
+ "reserved");
+ else if (ver == 5) {
+ proto_tree_add_item(netflow_tree, hf_cflow_samplerate,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+ }
+
+ /*
+ * everything below here should be payload
+ */
+ for (x = 1; x < pdus + 1; x++) {
+ /*
+ * make sure we have a pdu's worth of data
+ */
+ available = tvb_length_remaining(tvb, offset);
+ if (available < pdusize)
+ break;
+
+ pduitem =
+ proto_tree_add_text(netflow_tree, tvb, offset, pdusize,
+ "pdu %u/%u", x, pdus);
+ pdutree = proto_item_add_subtree(pduitem, ett_flow);
+
+ pduret = pduptr(pdutree, tvb, offset, vspec);
+
+ /*
+ * if we came up short, stop processing
+ */
+ if (pduret == pdusize)
+ offset += pduret;
+ else
+ break;
+ }
+
+ return;
+}
+
+/*
+ * flow_process_* == common groups of fields, probably could be inline
+ */
+
+static int
+flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb, int offset)
+{
+ proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, FALSE);
offset += 2;
- proto_tree_add_item(tree, hf_netflow_output_iface,
- tvb, offset, 2, FALSE);
+ proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
+ FALSE);
offset += 2;
- proto_tree_add_item(tree, hf_netflow_packets,
- tvb, offset, 4, FALSE);
- offset += 4;
+ return offset;
+}
- proto_tree_add_item(tree, hf_netflow_bytes,
- tvb, offset, 4, FALSE);
- offset += 4;
+static int
+flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb, int offset)
+{
+ proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2, FALSE);
+ offset += 2;
- proto_tree_add_item(tree, hf_netflow_start_time,
- tvb, offset, 4, FALSE);
+ proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ return offset;
+}
+
+static int
+flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb, int offset)
+{
+ nstime_t ts;
+
+ ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
+ ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
+ proto_tree_add_time(pdutree, hf_cflow_timestart, tvb, offset, 4, &ts);
offset += 4;
- proto_tree_add_item(tree, hf_netflow_end_time,
- tvb, offset, 4, FALSE);
+ ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
+ ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
+ proto_tree_add_time(pdutree, hf_cflow_timeend, tvb, offset, 4, &ts);
offset += 4;
- proto_tree_add_item(tree, hf_netflow_src_port,
- tvb, offset, 2, FALSE);
+ return offset;
+}
+
+
+static int
+flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb, int offset)
+{
+ proto_tree_add_item(pdutree, hf_cflow_srcas, tvb, offset, 2, FALSE);
offset += 2;
- proto_tree_add_item(tree, hf_netflow_dst_port,
- tvb, offset, 2, FALSE);
+ proto_tree_add_item(pdutree, hf_cflow_dstas, tvb, offset, 2, FALSE);
offset += 2;
- if (version == 1) {
- offset += 2; /* Skip pad bytes */
+ return offset;
+}
- proto_tree_add_item(tree, hf_netflow_ip_prot,
- tvb, offset, 1, FALSE);
- offset += 1;
+static int
+flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb, int offset)
+{
+ proto_tree_add_item(pdutree, hf_cflow_packets, tvb, offset, 4, FALSE);
+ offset += 4;
- proto_tree_add_item(tree, hf_netflow_tos,
- tvb, offset, 1, FALSE);
- offset += 1;
+ proto_tree_add_item(pdutree, hf_cflow_octets, tvb, offset, 4, FALSE);
+ offset += 4;
- proto_tree_add_item(tree, hf_netflow_tcp_flags,
- tvb, offset, 1, FALSE);
- offset += 1;
- } else {
- if (version == 7) {
- proto_tree_add_item(tree, hf_netflow_v7_flags,
- tvb, offset, 1, FALSE);
- }
- offset += 1; /* v5 pad byte, v7 flags */
+ return offset;
+}
- proto_tree_add_item(tree, hf_netflow_tcp_flags,
- tvb, offset, 1, FALSE);
- offset += 1;
+static int
+flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+ int bytes, const char *text)
+{
+ proto_tree_add_text(pdutree, tvb, offset, bytes, text);
+ offset += bytes;
- proto_tree_add_item(tree, hf_netflow_ip_prot,
- tvb, offset, 1, FALSE);
- offset += 1;
+ return offset;
+}
- proto_tree_add_item(tree, hf_netflow_tos,
- tvb, offset, 1, FALSE);
- offset += 1;
+static int
+dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+ int verspec)
+{
+ int startoffset = offset;
- proto_tree_add_item(tree, hf_netflow_src_as,
- tvb, offset, 2, FALSE);
+ proto_tree_add_item(pdutree, hf_cflow_dstaddr, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ if (verspec != V8PDU_DESTONLY_METHOD) {
+ proto_tree_add_item(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
+ FALSE);
+ offset += 4;
+ }
+ if (verspec == V8PDU_FULL_METHOD) {
+ proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2,
+ FALSE);
+ offset += 2;
+ proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2,
+ FALSE);
offset += 2;
+ }
+
+ offset = flow_process_sizecount(pdutree, tvb, offset);
+ offset = flow_process_timeperiod(pdutree, tvb, offset);
- proto_tree_add_item(tree, hf_netflow_dst_as,
- tvb, offset, 2, FALSE);
+ proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
+ FALSE);
+ offset += 2;
+
+ if (verspec != V8PDU_DESTONLY_METHOD) {
+ proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2,
+ FALSE);
offset += 2;
+ }
- proto_tree_add_item(tree, hf_netflow_src_mask,
- tvb, offset, 1, FALSE);
- offset += 1;
+ proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1, FALSE);
+ if (verspec == V8PDU_FULL_METHOD)
+ proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
+ FALSE);
+ offset = flow_process_textfield(pdutree, tvb, offset, 1, "marked tos");
- proto_tree_add_item(tree, hf_netflow_dst_mask,
- tvb, offset, 1, FALSE);
- offset += 1;
+ if (verspec == V8PDU_SRCDEST_METHOD)
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 2,
+ "reserved");
+ else if (verspec == V8PDU_FULL_METHOD)
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 1, "padding");
- offset += 2; /* Skip pad bytes */
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 4, "extra packets");
- if (version == 7) {
- proto_tree_add_item(tree, hf_netflow_router_sc,
- tvb, offset, 4, FALSE);
- offset += 4;
- }
- }
+ proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE);
+ offset += 4;
+
+ return (offset - startoffset);
}
-static void
-dissect_netflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+/*
+ * dissect a version 8 pdu, returning the length of the pdu processed
+ */
+
+static int
+dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+ int verspec)
{
- proto_tree *netflow_tree = NULL;
- proto_tree *netflow_rec_tree = NULL;
- proto_item *ti = NULL, *tf = NULL;
- gint offset = 0;
- guint16 nf_version, nf_count, nf_sample_rate;
- guint32 nf_sequence;
- gint header_size, record_size;
- int i;
+ int startoffset = offset;
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "NetFlow");
- if (check_col(pinfo->cinfo, COL_INFO))
- col_clear(pinfo->cinfo, COL_INFO);
+ proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE);
+ offset += 4;
- /* Determine NetFlow version and number of records */
- nf_version = tvb_get_ntohs(tvb, offset);
- offset += sizeof(nf_version);
+ offset = flow_process_sizecount(pdutree, tvb, offset);
+ offset = flow_process_timeperiod(pdutree, tvb, offset);
- nf_count = tvb_get_ntohs(tvb, offset);
- offset += sizeof(nf_count);
+ switch (verspec) {
+ case V8PDU_AS_METHOD:
+ case V8PDU_TOSAS_METHOD:
+ offset = flow_process_aspair(pdutree, tvb, offset);
- if (check_col(pinfo->cinfo, COL_INFO))
- col_add_fstr(pinfo->cinfo, COL_INFO,
- "v%u, %u records", nf_version, nf_count);
+ if (verspec == V8PDU_TOSAS_METHOD) {
+ proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
+ offset++, 1, FALSE);
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 1,
+ "padding");
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 2,
+ "reserved");
+ }
+ break;
+ case V8PDU_PROTO_METHOD:
+ case V8PDU_TOSPROTOPORT_METHOD:
+ proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
+ FALSE);
- /* Handle version-specific issues */
- switch (nf_version) {
- case 1:
- header_size = NETFLOW_V1_HDR;
- record_size = NETFLOW_V1_REC;
+ if (verspec == V8PDU_PROTO_METHOD)
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 1,
+ "padding");
+ else if (verspec == V8PDU_TOSPROTOPORT_METHOD)
+ proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
+ offset++, 1, FALSE);
+
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 2,
+ "reserved");
+ offset = flow_process_ports(pdutree, tvb, offset);
+
+ if (verspec == V8PDU_TOSPROTOPORT_METHOD)
+ offset = flow_process_ints(pdutree, tvb, offset);
break;
- case 5:
- header_size = NETFLOW_V5_HDR;
- record_size = NETFLOW_V5_REC;
+ case V8PDU_SPREFIX_METHOD:
+ case V8PDU_DPREFIX_METHOD:
+ case V8PDU_TOSSRCPREFIX_METHOD:
+ case V8PDU_TOSDSTPREFIX_METHOD:
+ proto_tree_add_item(pdutree,
+ verspec ==
+ V8PDU_SPREFIX_METHOD ?
+ hf_cflow_srcnet : hf_cflow_dstnet, tvb,
+ offset, 4, FALSE);
+ offset += 4;
+
+ proto_tree_add_item(pdutree,
+ verspec ==
+ V8PDU_SPREFIX_METHOD ?
+ hf_cflow_srcmask : hf_cflow_dstmask, tvb,
+ offset++, 1, FALSE);
+
+ if (verspec == V8PDU_SPREFIX_METHOD
+ || verspec == V8PDU_DPREFIX_METHOD)
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 1,
+ "padding");
+ else if (verspec == V8PDU_TOSSRCPREFIX_METHOD
+ || verspec == V8PDU_TOSDSTPREFIX_METHOD)
+ proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
+ offset++, 1, FALSE);
+
+ proto_tree_add_item(pdutree,
+ verspec ==
+ V8PDU_SPREFIX_METHOD ? hf_cflow_srcas
+ : hf_cflow_dstas, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ proto_tree_add_item(pdutree,
+ verspec ==
+ V8PDU_SPREFIX_METHOD ?
+ hf_cflow_inputint : hf_cflow_outputint,
+ tvb, offset, 2, FALSE);
+ offset += 2;
+
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 2,
+ "reserved");
break;
- case 7:
- header_size = NETFLOW_V7_HDR;
- record_size = NETFLOW_V7_REC;
+ case V8PDU_MATRIX_METHOD:
+ case V8PDU_TOSMATRIX_METHOD:
+ case V8PDU_PREPORTPROTOCOL_METHOD:
+ proto_tree_add_item(pdutree, hf_cflow_srcnet, tvb, offset, 4,
+ FALSE);
+ offset += 4;
+
+ proto_tree_add_item(pdutree, hf_cflow_dstnet, tvb, offset, 4,
+ FALSE);
+ offset += 4;
+
+ proto_tree_add_item(pdutree, hf_cflow_srcmask, tvb, offset++,
+ 1, FALSE);
+
+ proto_tree_add_item(pdutree, hf_cflow_dstmask, tvb, offset++,
+ 1, FALSE);
+
+ if (verspec == V8PDU_TOSMATRIX_METHOD ||
+ verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
+ proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
+ offset++, 1, FALSE);
+ if (verspec == V8PDU_TOSMATRIX_METHOD) {
+ offset =
+ flow_process_textfield(pdutree, tvb,
+ offset, 1,
+ "padding");
+ } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
+ proto_tree_add_item(pdutree, hf_cflow_prot,
+ tvb, offset++, 1, FALSE);
+ }
+ } else {
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 2,
+ "reserved");
+ }
+
+ if (verspec == V8PDU_MATRIX_METHOD
+ || verspec == V8PDU_TOSMATRIX_METHOD) {
+ offset = flow_process_aspair(pdutree, tvb, offset);
+ } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
+ offset = flow_process_ports(pdutree, tvb, offset);
+ }
+
+ offset = flow_process_ints(pdutree, tvb, offset);
break;
- case 8:
- header_size = NETFLOW_V8_HDR;
- record_size = NETFLOW_V8_REC;
- case 9:
- default:
- return;
}
- /* Add NetFlow to the tree */
- if (tree != NULL) {
- ti = proto_tree_add_protocol_format(tree, proto_netflow, tvb,
- 0, header_size, "NetFlow, v%u, %u records",
- nf_version, nf_count);
- netflow_tree = proto_item_add_subtree(ti, ett_netflow);
- } else {
- return;
- }
- /* Start adding header information */
- offset = 0;
+ return (offset - startoffset);
+}
- proto_tree_add_uint(netflow_tree, hf_netflow_version,
- tvb, offset, sizeof(nf_version), nf_version);
- offset += sizeof(nf_version);
+/*
+ * dissect a version 1, 5, or 7 pdu and return the length of the pdu we
+ * processed
+ */
- proto_tree_add_uint(netflow_tree, hf_netflow_count,
- tvb, offset, sizeof(nf_count), nf_count);
- offset += sizeof(nf_count);
+static int
+dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
+{
+ int startoffset = offset;
+ guint32 srcaddr, dstaddr;
+ guint8 mask;
+ nstime_t ts;
+
+ memset(&ts, '\0', sizeof(ts));
- proto_tree_add_item(netflow_tree, hf_netflow_sys_uptime,
- tvb, offset, 4, FALSE);
+ /*
+ * memcpy so we can use the values later to calculate a prefix
+ */
+ tvb_memcpy(tvb, (guint8 *) & srcaddr, offset, 4);
+ proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
+ srcaddr);
offset += 4;
- proto_tree_add_item(netflow_tree, hf_netflow_unix_sec,
- tvb, offset, 4, FALSE);
+ tvb_memcpy(tvb, (guint8 *) & dstaddr, offset, 4);
+ proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr, tvb, offset, 4,
+ dstaddr);
offset += 4;
- proto_tree_add_item(netflow_tree, hf_netflow_unix_nsec,
- tvb, offset, 4, FALSE);
+ proto_tree_add_item(pdutree, hf_cflow_nexthop, tvb, offset, 4, FALSE);
offset += 4;
- /* No more version 1 header */
+ offset = flow_process_ints(pdutree, tvb, offset);
+ offset = flow_process_sizecount(pdutree, tvb, offset);
+ offset = flow_process_timeperiod(pdutree, tvb, offset);
+ offset = flow_process_ports(pdutree, tvb, offset);
- if (nf_version != 1) {
- nf_sequence = tvb_get_ntohl(tvb, offset);
- proto_tree_add_uint(netflow_tree, hf_netflow_sequence,
- tvb, offset, sizeof(nf_sequence), nf_sequence);
- offset += sizeof(nf_sequence);
+ /*
+ * and the similarities end here
+ */
+ if (ver == 1) {
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 2, "padding");
- /* Add the sequence number */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_clear(pinfo->cinfo, COL_INFO);
- col_add_fstr(pinfo->cinfo, COL_INFO,
- "v%u, %u records, sequence # %u",
- nf_version, nf_count, nf_sequence);
- }
+ proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
+ FALSE);
- /* No more version 7 header */
+ proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
+ FALSE);
- if (nf_version != 7) {
- /* Engine type and ID */
- proto_tree_add_item(netflow_tree,
- hf_netflow_engine_type, tvb, offset,
- 1, FALSE);
- offset += 1;
+ proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
+ 1, FALSE);
- proto_tree_add_item(netflow_tree,
- hf_netflow_engine_id, tvb, offset,
- 1, FALSE);
- offset += 1;
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 3, "padding");
- if (nf_version == 8) {
- /* Engine type and ID */
- proto_tree_add_item(netflow_tree,
- hf_netflow_aggregation, tvb, offset,
- 1, FALSE);
- offset += 1;
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 4,
+ "reserved");
+ } else {
+ if (ver == 5)
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 1,
+ "padding");
+ else {
+ proto_tree_add_item(pdutree, hf_cflow_flags, tvb,
+ offset++, 1, FALSE);
+ }
- proto_tree_add_item(netflow_tree,
- hf_netflow_agg_version, tvb, offset,
+ proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1, FALSE);
- offset += 1;
- }
- /*
- * On high-speed interfaces often just
- * statistical sample records are produced.
- */
- nf_sample_rate = tvb_get_ntohs(tvb, offset);
- if (nf_version == 5) {
- /*
- * Sample rate. Junipers and some Ciscos
- * include sampling rate in the reserved
- * header field. Not all the bits are used,
- * however.
- */
- if ((nf_sample_rate & 0xc000) == 0x4000) {
- nf_sample_rate &= 0x3fff;
- if (nf_sample_rate == 0)
- nf_sample_rate = 1;
- } else
- nf_sample_rate = 1;
- }
- proto_tree_add_uint_format(netflow_tree,
- hf_netflow_sample_rate, tvb, offset,
- sizeof(nf_sample_rate), nf_sample_rate,
- "Sample_rate: 1/%u", nf_sample_rate);
- offset += sizeof(nf_sample_rate);
+ proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
+ FALSE);
+
+ proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
+ FALSE);
+
+ offset = flow_process_aspair(pdutree, tvb, offset);
+
+ mask = tvb_get_guint8(tvb, offset);
+ proto_tree_add_text(pdutree, tvb, offset, 1,
+ "SrcMask: %u (prefix: %s/%u)",
+ mask, getprefix(&srcaddr, mask),
+ mask != 0 ? mask : 32);
+ proto_tree_add_uint_hidden(pdutree, hf_cflow_srcmask, tvb,
+ offset++, 1, mask);
+
+ mask = tvb_get_guint8(tvb, offset);
+ proto_tree_add_text(pdutree, tvb, offset, 1,
+ "DstMask: %u (prefix: %s/%u)",
+ mask, getprefix(&dstaddr, mask),
+ mask != 0 ? mask : 32);
+ proto_tree_add_uint_hidden(pdutree, hf_cflow_dstmask, tvb,
+ offset++, 1, mask);
+
+ offset =
+ flow_process_textfield(pdutree, tvb, offset, 2, "padding");
+
+ if (ver == 7) {
+ proto_tree_add_item(pdutree, hf_cflow_routersc, tvb,
+ offset, 4, FALSE);
+ offset += 4;
}
}
- /* XXX Doesn't support v8 records, yet */
- if (nf_version == 8)
- return;
+ return (offset - startoffset);
+}
- /* Handle the flow records */
- for (i = 0; i < nf_count; i++) {
- guint rec_offset = header_size + i * record_size;
+static gchar *
+getprefix(const guint32 * address, int prefix)
+{
+ guint32 gprefix;
- tf = proto_tree_add_uint_format(netflow_tree,
- hf_netflow_record, tvb, rec_offset, record_size,
- i, "Record %d: %u packets, %u bytes", i + 1,
- tvb_get_ntohl(tvb, rec_offset + 16),
- tvb_get_ntohl(tvb, rec_offset + 20));
- netflow_rec_tree = proto_item_add_subtree(tf,
- ett_netflow_rec);
+ gprefix = *address & htonl((0xffffffff << (32 - prefix)));
- dissect_netflow_157(tvb, netflow_rec_tree,
- nf_version, rec_offset);
- }
+ return (ip_to_str(&gprefix));
}
void
proto_register_netflow(void)
{
static hf_register_info hf[] = {
- /* Header */
- { &hf_netflow_version,
- { "Version", "netflow.version", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_count,
- { "Number of records", "netflow.count", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_sys_uptime,
- { "System uptime", "netflow.sys_uptime", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_unix_sec,
- { "Unix seconds", "netflow.unix_sec", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_unix_nsec,
- { "Unix nanonseconds", "netflow.unix_nsec", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_sequence,
- { "Sequence number", "netflow.sequence", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_engine_type,
- { "Engine type", "netflow.engine_type", FT_UINT8,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_engine_id,
- { "Engine ID", "netflow.engine_id", FT_UINT8,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_aggregation,
- { "Aggregation method", "netflow.aggregation", FT_UINT8,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_agg_version,
- { "Aggregation version", "netflow.agg_version", FT_UINT8,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_sample_rate,
- { "Sample rate", "netflow.sample_rate", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_record,
- { "Record", "netflow.record", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- /* Record */
- { &hf_netflow_src_addr,
- { "Source address", "netflow.src_addr", FT_IPv4,
- BASE_NONE, NULL, 0x0, "", HFILL }},
- { &hf_netflow_dst_addr,
- { "Destination address", "netflow.dst_addr", FT_IPv4,
- BASE_NONE, NULL, 0x0, "", HFILL }},
- { &hf_netflow_next_hop,
- { "Next hop", "netflow.next_hop", FT_IPv4,
- BASE_NONE, NULL, 0x0, "", HFILL }},
- { &hf_netflow_input_iface,
- { "Input interface", "netflow.input_iface", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_output_iface,
- { "Output interface", "netflow.output_iface", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_packets,
- { "Packets sent", "netflow.packets", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_bytes,
- { "Bytes sent", "netflow.bytes", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_start_time,
- { "Start time", "netflow.start_time", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_end_time,
- { "End time", "netflow.end_time", FT_UINT32,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_src_port,
- { "Source port", "netflow.src_port", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_dst_port,
- { "Destination port", "netflow.dst_port", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_v7_flags,
- { "Valid flags", "netflow.flags", FT_UINT8,
- BASE_HEX, NULL, 0x0, "", HFILL }},
- { &hf_netflow_tcp_flags,
- { "TCP flags", "netflow.tcp_flags", FT_UINT8,
- BASE_HEX, NULL, 0x0, "", HFILL }},
- { &hf_netflow_ip_prot,
- { "IP protocol", "netflow.ip_prot", FT_UINT8,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_tos,
- { "Type of service", "netflow.tos", FT_UINT8,
- BASE_HEX, NULL, 0x0, "", HFILL }},
- { &hf_netflow_src_as,
- { "Source AS", "netflow.src_as", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_dst_as,
- { "Destination AS", "netflow.dst_as", FT_UINT16,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_src_mask,
- { "Source mask", "netflow.src_mask", FT_UINT8,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_dst_mask,
- { "Destination mask", "netflow.dst_mask", FT_UINT8,
- BASE_DEC, NULL, 0x0, "", HFILL }},
- { &hf_netflow_router_sc,
- { "Router bypass", "netflow.router_sc", FT_IPv4,
- BASE_NONE, NULL, 0x0, "", HFILL }},
+ /*
+ * flow header
+ */
+ {&hf_cflow_version,
+ {"Version", "cflow.version",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "NetFlow Version", HFILL}
+ },
+ {&hf_cflow_count,
+ {"Count", "cflow.count",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Count of PDUs", HFILL}
+ },
+ {&hf_cflow_sysuptime,
+ {"SysUptime", "cflow.sysuptime",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Time since router booted (in milliseconds)", HFILL}
+ },
+
+ {&hf_cflow_timestamp,
+ {"Timestamp", "cflow.timestamp",
+ FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+ "Current seconds since epoch", HFILL}
+ },
+ {&hf_cflow_unix_secs,
+ {"CurrentSecs", "cflow.unix_secs",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Current seconds since epoch", HFILL}
+ },
+ {&hf_cflow_unix_nsecs,
+ {"CurrentNSecs", "cflow.unix_nsecs",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Residual nanoseconds since epoch", HFILL}
+ },
+ {&hf_cflow_samplerate,
+ {"SampleRate", "cflow.samplerate",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Sample Frequency of exporter", HFILL}
+ },
+
+ /*
+ * end version-agnostic header
+ * version-specific flow header
+ */
+ {&hf_cflow_sequence,
+ {"FlowSequence", "cflow.sequence",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Sequence number of flows seen", HFILL}
+ },
+ {&hf_cflow_engine_type,
+ {"EngineType", "cflow.engine_type",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Flow switching engine type", HFILL}
+ },
+ {&hf_cflow_engine_id,
+ {"EngineId", "cflow.engine_id",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Slot number of switching engine", HFILL}
+ },
+ {&hf_cflow_aggmethod,
+ {"AggMethod", "cflow.aggmethod",
+ FT_UINT8, BASE_DEC, VALS(v8_agg), 0x0,
+ "CFlow V8 Aggregation Method", HFILL}
+ },
+ {&hf_cflow_aggversion,
+ {"AggVersion", "cflow.aggversion",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "CFlow V8 Aggregation Version", HFILL}
+ },
+ /*
+ * end version specific header storage
+ */
+ /*
+ * begin pdu content storage
+ */
+ {&hf_cflow_srcaddr,
+ {"SrcAddr", "cflow.srcaddr",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "Flow Source Address", HFILL}
+ },
+ {&hf_cflow_srcnet,
+ {"SrcNet", "cflow.srcnet",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "Flow Source Network", HFILL}
+ },
+ {&hf_cflow_dstaddr,
+ {"DstAddr", "cflow.dstaddr",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "Flow Destination Address", HFILL}
+ },
+ {&hf_cflow_dstnet,
+ {"DstNet", "cflow.dstaddr",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "Flow Destination Network", HFILL}
+ },
+ {&hf_cflow_nexthop,
+ {"NextHop", "cflow.nexthop",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "Router nexthop", HFILL}
+ },
+ {&hf_cflow_inputint,
+ {"InputInt", "cflow.inputint",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Flow Input Interface", HFILL}
+ },
+ {&hf_cflow_outputint,
+ {"OutputInt", "cflow.outputint",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Flow Output Interface", HFILL}
+ },
+ {&hf_cflow_flows,
+ {"Flows", "cflow.flows",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Flows Aggregated in PDU", HFILL}
+ },
+ {&hf_cflow_packets,
+ {"Packets", "cflow.packets",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Count of packets", HFILL}
+ },
+ {&hf_cflow_octets,
+ {"Octets", "cflow.octets",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Count of bytes", HFILL}
+ },
+ {&hf_cflow_timestart,
+ {"StartTime", "cflow.timestart",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "Uptime at start of flow", HFILL}
+ },
+ {&hf_cflow_timeend,
+ {"EndTime", "cflow.timeend",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "Uptime at end of flow", HFILL}
+ },
+ {&hf_cflow_srcport,
+ {"SrcPort", "cflow.srcport",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Flow Source Port", HFILL}
+ },
+ {&hf_cflow_dstport,
+ {"DstPort", "cflow.dstport",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Flow Destination Port", HFILL}
+ },
+ {&hf_cflow_prot,
+ {"Protocol", "cflow.protocol",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "IP Protocol", HFILL}
+ },
+ {&hf_cflow_tos,
+ {"IP ToS", "cflow.tos",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "IP Type of Service", HFILL}
+ },
+ {&hf_cflow_flags,
+ {"Export Flags", "cflow.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "CFlow Flags", HFILL}
+ },
+ {&hf_cflow_tcpflags,
+ {"TCP Flags", "cflow.tcpflags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "TCP Flags", HFILL}
+ },
+ {&hf_cflow_srcas,
+ {"SrcAS", "cflow.srcas",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Source AS", HFILL}
+ },
+ {&hf_cflow_dstas,
+ {"DstAS", "cflow.dstas",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Destination AS", HFILL}
+ },
+ {&hf_cflow_srcmask,
+ {"SrcMask", "cflow.srcmask",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Source Prefix Mask", HFILL}
+ },
+ {&hf_cflow_dstmask,
+ {"DstMask", "cflow.dstmask",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Destination Prefix Mask", HFILL}
+ },
+ {&hf_cflow_routersc,
+ {"Router Shortcut", "cflow.routersc",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "Router shortcut by switch", HFILL}
+ }
+ /*
+ * end pdu content storage
+ */
};
- static gint *ett[] = {
+ static gint *ett[] = {
&ett_netflow,
- &ett_netflow_rec
+ &ett_unixtime,
+ &ett_flow
};
- proto_netflow = proto_register_protocol("NetFlow",
- "NetFlow", "netflow");
+ proto_netflow = proto_register_protocol("Cisco NetFlow", "CFLOW",
+ "cflow");
+
proto_register_field_array(proto_netflow, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+
+ register_dissector("cflow", dissect_netflow, proto_netflow);
}
+
+/*
+ * protocol/port association
+ */
void
proto_reg_handoff_netflow(void)
{
dissector_handle_t netflow_handle;
netflow_handle = create_dissector_handle(dissect_netflow,
- proto_netflow);
+ proto_netflow);
dissector_add("udp.port", UDP_PORT_NETFLOW, netflow_handle);
}