Ethereal-dev: [Ethereal-dev] netflow dissector patch
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Bill Fumerola <billf@xxxxxx>
Date: Fri, 20 Sep 2002 16:24:00 -0700
attached is the patch to replace most of the guts of the netflow dissector. apologies for the fiasco/pain i've caused with this. where possible, i kept the existing code the same wherever possible to minimize diff deltas. i'd be interested (but don't require or anything) reviewing any v9 dissectors. also, the only part of this dissector where i am unsure of the accuracy is in the handling of timestamps/sysuptime. cisco & juniper seem to mix and match some millisecond/second/microsecond. i have yet to be able to determine who is right. i'll have more changes coming (the sample rate info should only be dissected if its non-zero, some other stuff), but also look forward to other changes people have. finally - i'm moved! beer is on me for any ethereal developers in san francisco... thanks, -- - bill fumerola / fumerola@xxxxxxxxxxxxx / billf@xxxxxxxxxxx / billf@xxxxxx
Index: packet-netflow.c =================================================================== RCS file: /cvsroot/ethereal/packet-netflow.c,v retrieving revision 1.4 diff -u -r1.4 packet-netflow.c --- packet-netflow.c 2002/09/09 20:22:51 1.4 +++ packet-netflow.c 2002/09/20 22:53:08 @@ -1,26 +1,40 @@ -/* packet-netflow.c - * Routines for Cisco NetFlow packet disassembly - * Matthew Smart <smart@xxxxxxxxxx> - * - * $Id: packet-netflow.c,v 1.4 2002/09/09 20:22:51 guy Exp $ - * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@xxxxxxxxxxxx> - * 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@xxxxxxxxxxxxx> + ** 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@xxxxxxxxxx> + ** + ***************************************************************************** + ** + ** 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$ */ #ifdef HAVE_CONFIG_H @@ -30,453 +44,987 @@ #include <glib.h> #include <epan/packet.h> -#include <stdio.h> -#include <string.h> +#define UDP_PORT_NETFLOW 2055 -#include "packet-netflow.h" +/* + * 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; -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; +/* + * 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 gint ett_netflow = -1; -static gint ett_netflow_rec = -1; 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; + + 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; - tvb_memcpy(tvb, (guint8 *)&addr, offset, 4); - proto_tree_add_ipv4(tree, hf_netflow_src_addr, tvb, offset, 4, addr); + proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb, + offset, 4, FALSE); offset += 4; + + 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); - tvb_memcpy(tvb, (guint8 *)&addr, offset, 4); - proto_tree_add_ipv4(tree, hf_netflow_dst_addr, tvb, offset, 4, addr); + 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; + + /* + * 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 + */ - proto_tree_add_item(tree, hf_netflow_input_iface, - tvb, offset, 2, FALSE); +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(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE); + offset += 2; + + return offset; +} - proto_tree_add_item(tree, hf_netflow_start_time, - tvb, offset, 4, FALSE); +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; + + return offset; +} + - proto_tree_add_item(tree, hf_netflow_src_port, - tvb, offset, 2, FALSE); +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; - - proto_tree_add_item(tree, hf_netflow_tos, - tvb, offset, 1, FALSE); - offset += 1; - - 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 */ +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_tcp_flags, - tvb, offset, 1, FALSE); - offset += 1; - - proto_tree_add_item(tree, hf_netflow_ip_prot, - tvb, offset, 1, FALSE); - offset += 1; - - 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_src_as, - tvb, offset, 2, FALSE); - offset += 2; + return offset; +} - proto_tree_add_item(tree, hf_netflow_dst_as, - tvb, offset, 2, FALSE); - offset += 2; +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_src_mask, - tvb, offset, 1, FALSE); - offset += 1; - - proto_tree_add_item(tree, hf_netflow_dst_mask, - tvb, offset, 1, FALSE); - offset += 1; - - offset += 2; /* Skip pad bytes */ - - if (version == 7) { - proto_tree_add_item(tree, hf_netflow_router_sc, - tvb, offset, 4, FALSE); - offset += 4; - } - } + return offset; } -static void -dissect_netflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static int +dissect_v8_flowpdu(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_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; + } - /* 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); + proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2, + FALSE); + offset += 2; - 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_DESTONLY_METHOD) { + proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, + FALSE); + offset += 2; + } - /* Handle version-specific issues */ - switch (nf_version) { - case 1: - header_size = NETFLOW_V1_HDR; - record_size = NETFLOW_V1_REC; + 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"); + + 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 = + flow_process_textfield(pdutree, tvb, offset, 4, "extra packets"); + + proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE); + offset += 4; + + return (offset - startoffset); +} + +/* + * 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) +{ + int startoffset = offset; + + proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE); + offset += 4; + + offset = flow_process_sizecount(pdutree, tvb, offset); + offset = flow_process_timeperiod(pdutree, tvb, offset); + + switch (verspec) { + case V8PDU_AS_METHOD: + case V8PDU_TOSAS_METHOD: + offset = flow_process_aspair(pdutree, tvb, offset); + + 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 5: - header_size = NETFLOW_V5_HDR; - record_size = NETFLOW_V5_REC; + case V8PDU_PROTO_METHOD: + case V8PDU_TOSPROTOPORT_METHOD: + proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1, + FALSE); + + 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 7: - header_size = NETFLOW_V7_HDR; - record_size = NETFLOW_V7_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 8: - header_size = NETFLOW_V8_HDR; - record_size = NETFLOW_V8_REC; - case 9: - default: - return; - } + 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; - /* 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; + 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; } - /* Start adding header information */ - offset = 0; - proto_tree_add_uint(netflow_tree, hf_netflow_version, - tvb, offset, sizeof(nf_version), nf_version); - offset += sizeof(nf_version); + return (offset - startoffset); +} - proto_tree_add_uint(netflow_tree, hf_netflow_count, - tvb, offset, sizeof(nf_count), nf_count); - offset += sizeof(nf_count); +/* + * dissect a version 1, 5, or 7 pdu and return the length of the pdu we + * processed + */ - proto_tree_add_item(netflow_tree, hf_netflow_sys_uptime, - tvb, offset, 4, FALSE); +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)); + + /* + * 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 */ - 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); + 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); + + /* + * 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(netflow_tree, - hf_netflow_engine_id, tvb, offset, - 1, FALSE); - offset += 1; - - if (nf_version == 8) { - /* Engine type and ID */ - proto_tree_add_item(netflow_tree, - hf_netflow_aggregation, tvb, offset, + proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++, 1, FALSE); - offset += 1; + + offset = + flow_process_textfield(pdutree, tvb, offset, 3, "padding"); + + 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; - - 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); +static gchar * +getprefix(const guint32 * address, int prefix) +{ + guint32 gprefix; - dissect_netflow_157(tvb, netflow_rec_tree, - nf_version, rec_offset); - } + gprefix = *address & htonl((0xffffffff << (32 - prefix))); + + 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("Cisco NetFlow", "CFLOW", + "cflow"); - proto_netflow = proto_register_protocol("NetFlow", - "NetFlow", "netflow"); 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); }
- Follow-Ups:
- Re: [Ethereal-dev] netflow dissector patch
- From: Richard Sharpe
- Re: [Ethereal-dev] netflow dissector patch
- From: Gerald Combs
- Re: [Ethereal-dev] netflow dissector patch
- Prev by Date: RE: [Ethereal-dev] ethereal-0.9.0 compilation bug
- Next by Date: Re: [Ethereal-dev] netflow dissector patch
- Previous by thread: [Ethereal-dev] Novell NDS decodes
- Next by thread: Re: [Ethereal-dev] netflow dissector patch
- Index(es):