4 *****************************************************************************
5 ** (c) 2002 bill fumerola <fumerola@yahoo-inc.com>
6 ** All rights reserved.
8 ** This program is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU General Public License
10 ** as published by the Free Software Foundation; either version 2
11 ** of the License, or (at your option) any later version.
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *****************************************************************************
23 ** Previous NetFlow dissector written by Matthew Smart <smart@monkey.org>
24 ** NetFlow v9 support added by same.
28 ** http://www.cisco.com/warp/public/cc/pd/iosw/prodlit/tflow_wp.htm
30 ** for NetFlow v9 information.
32 *****************************************************************************
34 ** this code was written from the following documentation:
36 ** http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_6/iug/format.pdf
37 ** http://www.caida.org/tools/measurement/cflowd/configuration/configuration-9.html
39 ** some documentation is more accurate then others. in some cases, live data and
40 ** information contained in responses from vendors were also used. some fields
41 ** are dissected as vendor specific fields.
45 ** http://www.cisco.com/univercd/cc/td/doc/cisintwk/intsolns/netflsol/nfwhite.htm
47 ** $Yahoo: //depot/fumerola/packet-netflow/packet-netflow.c#14 $
48 ** $Id: packet-netflow.c,v 1.11 2004/03/09 20:08:26 guy Exp $
56 #include <epan/packet.h>
61 #define UDP_PORT_NETFLOW 2055
63 static guint global_netflow_udp_port = UDP_PORT_NETFLOW;
64 static guint netflow_udp_port = 0;
67 * pdu identifiers & sizes
70 #define V1PDU_SIZE (4 * 12)
71 #define V5PDU_SIZE (4 * 12)
72 #define V7PDU_SIZE (4 * 13)
73 #define V8PDU_AS_SIZE (4 * 7)
74 #define V8PDU_PROTO_SIZE (4 * 7)
75 #define V8PDU_SPREFIX_SIZE (4 * 8)
76 #define V8PDU_DPREFIX_SIZE (4 * 8)
77 #define V8PDU_MATRIX_SIZE (4 * 10)
78 #define V8PDU_DESTONLY_SIZE (4 * 8)
79 #define V8PDU_SRCDEST_SIZE (4 * 10)
80 #define V8PDU_FULL_SIZE (4 * 11)
81 #define V8PDU_TOSAS_SIZE (V8PDU_AS_SIZE + 4)
82 #define V8PDU_TOSPROTOPORT_SIZE (V8PDU_PROTO_SIZE + 4)
83 #define V8PDU_TOSSRCPREFIX_SIZE V8PDU_SPREFIX_SIZE
84 #define V8PDU_TOSDSTPREFIX_SIZE V8PDU_DPREFIX_SIZE
85 #define V8PDU_TOSMATRIX_SIZE V8PDU_MATRIX_SIZE
86 #define V8PDU_PREPORTPROTOCOL_SIZE (4 * 10)
95 V8PDU_DESTONLY_METHOD,
99 V8PDU_TOSPROTOPORT_METHOD,
100 V8PDU_TOSSRCPREFIX_METHOD,
101 V8PDU_TOSDSTPREFIX_METHOD,
102 V8PDU_TOSMATRIX_METHOD,
103 V8PDU_PREPORTPROTOCOL_METHOD
106 static const value_string v8_agg[] = {
107 {V8PDU_AS_METHOD, "V8 AS aggregation"},
108 {V8PDU_PROTO_METHOD, "V8 Proto/Port aggregation"},
109 {V8PDU_SPREFIX_METHOD, "V8 Source Prefix aggregation"},
110 {V8PDU_DPREFIX_METHOD, "V8 Destination Prefix aggregation"},
111 {V8PDU_MATRIX_METHOD, "V8 Network Matrix aggregation"},
112 {V8PDU_DESTONLY_METHOD, "V8 Destination aggregation (Cisco Catalyst)"},
113 {V8PDU_SRCDEST_METHOD, "V8 Src/Dest aggregation (Cisco Catalyst)"},
114 {V8PDU_FULL_METHOD, "V8 Full aggregation (Cisco Catalyst)"},
115 {V8PDU_TOSAS_METHOD, "V8 TOS+AS aggregation aggregation"},
116 {V8PDU_TOSPROTOPORT_METHOD, "V8 TOS+Protocol aggregation"},
117 {V8PDU_TOSSRCPREFIX_METHOD, "V8 TOS+Source Prefix aggregation"},
118 {V8PDU_TOSDSTPREFIX_METHOD, "V8 TOS+Destination Prefix aggregation"},
119 {V8PDU_TOSMATRIX_METHOD, "V8 TOS+Prefix Matrix aggregation"},
120 {V8PDU_PREPORTPROTOCOL_METHOD, "V8 Port+Protocol aggregation"},
124 /* Version 9 template cache structures */
125 #define V9TEMPLATE_CACHE_MAX_ENTRIES 100
127 struct v9_template_entry {
138 struct v9_template_entry *entries;
141 static struct v9_template v9_template_cache[V9TEMPLATE_CACHE_MAX_ENTRIES];
144 * ethereal tree identifiers
147 static int proto_netflow = -1;
148 static int ett_netflow = -1;
149 static int ett_unixtime = -1;
150 static int ett_flow = -1;
151 static int ett_template = -1;
152 static int ett_dataflowset = -1;
158 static int hf_cflow_version = -1;
159 static int hf_cflow_count = -1;
160 static int hf_cflow_sysuptime = -1;
161 static int hf_cflow_unix_secs = -1;
162 static int hf_cflow_unix_nsecs = -1;
163 static int hf_cflow_timestamp = -1;
164 static int hf_cflow_samplerate = -1;
167 * cflow version specific info
169 static int hf_cflow_sequence = -1;
170 static int hf_cflow_engine_type = -1;
171 static int hf_cflow_engine_id = -1;
172 static int hf_cflow_source_id = -1;
174 static int hf_cflow_aggmethod = -1;
175 static int hf_cflow_aggversion = -1;
179 static int hf_cflow_template_flowset_id = -1;
180 static int hf_cflow_data_flowset_id = -1;
181 static int hf_cflow_options_flowset_id = -1;
182 static int hf_cflow_flowset_id = -1;
183 static int hf_cflow_flowset_length = -1;
184 static int hf_cflow_template_id = -1;
185 static int hf_cflow_template_field_count = -1;
186 static int hf_cflow_template_field_type = -1;
187 static int hf_cflow_template_field_length = -1;
192 static int hf_cflow_srcaddr = -1;
193 static int hf_cflow_srcaddr_v6 = -1;
194 static int hf_cflow_srcnet = -1;
195 static int hf_cflow_dstaddr = -1;
196 static int hf_cflow_dstaddr_v6 = -1;
197 static int hf_cflow_dstnet = -1;
198 static int hf_cflow_nexthop = -1;
199 static int hf_cflow_nexthop_v6 = -1;
200 static int hf_cflow_bgpnexthop = -1;
201 static int hf_cflow_bgpnexthop_v6 = -1;
202 static int hf_cflow_inputint = -1;
203 static int hf_cflow_outputint = -1;
204 static int hf_cflow_flows = -1;
205 static int hf_cflow_packets = -1;
206 static int hf_cflow_packets64 = -1;
207 static int hf_cflow_packetsout = -1;
208 static int hf_cflow_octets = -1;
209 static int hf_cflow_octets64 = -1;
210 static int hf_cflow_timestart = -1;
211 static int hf_cflow_timeend = -1;
212 static int hf_cflow_srcport = -1;
213 static int hf_cflow_dstport = -1;
214 static int hf_cflow_prot = -1;
215 static int hf_cflow_tos = -1;
216 static int hf_cflow_flags = -1;
217 static int hf_cflow_tcpflags = -1;
218 static int hf_cflow_dstas = -1;
219 static int hf_cflow_srcas = -1;
220 static int hf_cflow_dstmask = -1;
221 static int hf_cflow_srcmask = -1;
222 static int hf_cflow_routersc = -1;
223 static int hf_cflow_mulpackets = -1;
224 static int hf_cflow_muloctets = -1;
225 static int hf_cflow_octets_exp = -1;
226 static int hf_cflow_packets_exp = -1;
227 static int hf_cflow_flows_exp = -1;
229 void proto_reg_handoff_netflow(void);
231 typedef int dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
233 static int dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
235 static int dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
236 int offset, int verspec);
237 static int dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
238 int offset, int verspec);
239 static int dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb,
240 int offset, int verspec);
241 static int dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb,
242 int offset, guint16 id, guint length);
243 static void dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb,
244 int offset, struct v9_template * template);
246 static int dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb,
249 static int dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb,
251 static void v9_template_add(struct v9_template * template);
252 static struct v9_template *v9_template_get(guint16 id, guint32 src_addr,
255 static gchar *getprefix(const guint32 * address, int prefix);
256 static void dissect_netflow(tvbuff_t * tvb, packet_info * pinfo,
259 static int flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb,
261 static int flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb,
263 static int flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb,
265 static int flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb,
267 static int flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb,
269 static int flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb,
270 int offset, int bytes,
275 dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
277 proto_tree *netflow_tree = NULL;
279 proto_item *timeitem, *pduitem;
280 proto_tree *timetree, *pdutree;
281 unsigned int pduret, ver = 0, pdus = 0, x = 1, vspec;
282 size_t available, pdusize, offset = 0;
284 dissect_pdu_t *pduptr;
286 if (check_col(pinfo->cinfo, COL_PROTOCOL))
287 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFLOW");
288 if (check_col(pinfo->cinfo, COL_INFO))
289 col_clear(pinfo->cinfo, COL_INFO);
292 ti = proto_tree_add_item(tree, proto_netflow, tvb,
294 netflow_tree = proto_item_add_subtree(ti, ett_netflow);
297 ver = tvb_get_ntohs(tvb, offset);
301 pdusize = V1PDU_SIZE;
302 pduptr = &dissect_pdu;
305 pdusize = V5PDU_SIZE;
306 pduptr = &dissect_pdu;
309 pdusize = V7PDU_SIZE;
310 pduptr = &dissect_pdu;
313 pdusize = -1; /* deferred */
314 pduptr = &dissect_v8_aggpdu;
317 pdusize = -1; /* deferred */
318 pduptr = &dissect_v9_flowset;
325 proto_tree_add_uint(netflow_tree, hf_cflow_version, tvb,
329 pdus = tvb_get_ntohs(tvb, offset);
333 proto_tree_add_uint(netflow_tree, hf_cflow_count, tvb,
338 * set something interesting in the display now that we have info
340 if (check_col(pinfo->cinfo, COL_INFO)) {
342 col_add_fstr(pinfo->cinfo, COL_INFO,
343 "total: %u (v%u) FlowSets", pdus, ver);
345 col_add_fstr(pinfo->cinfo, COL_INFO,
346 "total: %u (v%u) flows", pdus, ver);
351 * the rest is only interesting if we're displaying/searching the
357 proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb,
361 ts.secs = tvb_get_ntohl(tvb, offset);
362 ts.nsecs = tvb_get_ntohl(tvb, offset + 4);
363 timeitem = proto_tree_add_time(netflow_tree,
364 hf_cflow_timestamp, tvb, offset,
366 timetree = proto_item_add_subtree(timeitem, ett_unixtime);
368 proto_tree_add_item(timetree, hf_cflow_unix_secs, tvb,
373 proto_tree_add_item(timetree, hf_cflow_unix_nsecs, tvb,
379 * version specific header
381 if (ver == 5 || ver == 7 || ver == 8 || ver == 9) {
382 proto_tree_add_item(netflow_tree, hf_cflow_sequence,
383 tvb, offset, 4, FALSE);
386 if (ver == 5 || ver == 8) {
387 proto_tree_add_item(netflow_tree, hf_cflow_engine_type,
388 tvb, offset++, 1, FALSE);
389 proto_tree_add_item(netflow_tree, hf_cflow_engine_id,
390 tvb, offset++, 1, FALSE);
391 } else if (ver == 9) {
392 proto_tree_add_item(netflow_tree, hf_cflow_source_id,
393 tvb, offset, 4, FALSE);
397 vspec = tvb_get_guint8(tvb, offset);
399 case V8PDU_AS_METHOD:
400 pdusize = V8PDU_AS_SIZE;
402 case V8PDU_PROTO_METHOD:
403 pdusize = V8PDU_PROTO_SIZE;
405 case V8PDU_SPREFIX_METHOD:
406 pdusize = V8PDU_SPREFIX_SIZE;
408 case V8PDU_DPREFIX_METHOD:
409 pdusize = V8PDU_DPREFIX_SIZE;
411 case V8PDU_MATRIX_METHOD:
412 pdusize = V8PDU_MATRIX_SIZE;
414 case V8PDU_DESTONLY_METHOD:
415 pdusize = V8PDU_DESTONLY_SIZE;
416 pduptr = &dissect_v8_flowpdu;
418 case V8PDU_SRCDEST_METHOD:
419 pdusize = V8PDU_SRCDEST_SIZE;
420 pduptr = &dissect_v8_flowpdu;
422 case V8PDU_FULL_METHOD:
423 pdusize = V8PDU_FULL_SIZE;
424 pduptr = &dissect_v8_flowpdu;
426 case V8PDU_TOSAS_METHOD:
427 pdusize = V8PDU_TOSAS_SIZE;
429 case V8PDU_TOSPROTOPORT_METHOD:
430 pdusize = V8PDU_TOSPROTOPORT_SIZE;
432 case V8PDU_TOSSRCPREFIX_METHOD:
433 pdusize = V8PDU_TOSSRCPREFIX_SIZE;
435 case V8PDU_TOSDSTPREFIX_METHOD:
436 pdusize = V8PDU_TOSDSTPREFIX_SIZE;
438 case V8PDU_TOSMATRIX_METHOD:
439 pdusize = V8PDU_TOSMATRIX_SIZE;
441 case V8PDU_PREPORTPROTOCOL_METHOD:
442 pdusize = V8PDU_PREPORTPROTOCOL_SIZE;
449 proto_tree_add_uint(netflow_tree, hf_cflow_aggmethod,
450 tvb, offset++, 1, vspec);
451 proto_tree_add_item(netflow_tree, hf_cflow_aggversion,
452 tvb, offset++, 1, FALSE);
454 if (ver == 7 || ver == 8)
455 offset = flow_process_textfield(netflow_tree, tvb, offset, 4,
458 proto_tree_add_item(netflow_tree, hf_cflow_samplerate,
459 tvb, offset, 2, FALSE);
464 * everything below here should be payload
466 for (x = 1; x < pdus + 1; x++) {
468 * make sure we have a pdu's worth of data
470 available = tvb_length_remaining(tvb, offset);
471 if (ver == 9 && available >= 4) {
472 /* pdusize can be different for each v9 flowset */
473 pdusize = tvb_get_ntohs(tvb, offset + 2);
476 if (available < pdusize)
480 pduitem = proto_tree_add_text(netflow_tree, tvb,
481 offset, pdusize, "FlowSet %u/%u", x, pdus);
483 pduitem = proto_tree_add_text(netflow_tree, tvb,
484 offset, pdusize, "pdu %u/%u", x, pdus);
486 pdutree = proto_item_add_subtree(pduitem, ett_flow);
488 pduret = pduptr(pdutree, tvb, offset, vspec);
491 * if we came up short, stop processing
493 if (pduret == pdusize)
501 * flow_process_* == common groups of fields, probably could be inline
505 flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb, int offset)
507 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, FALSE);
510 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
518 flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb, int offset)
520 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2, FALSE);
523 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE);
530 flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb, int offset)
534 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
535 ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
536 proto_tree_add_time(pdutree, hf_cflow_timestart, tvb, offset, 4, &ts);
539 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
540 ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
541 proto_tree_add_time(pdutree, hf_cflow_timeend, tvb, offset, 4, &ts);
549 flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb, int offset)
551 proto_tree_add_item(pdutree, hf_cflow_srcas, tvb, offset, 2, FALSE);
554 proto_tree_add_item(pdutree, hf_cflow_dstas, tvb, offset, 2, FALSE);
561 flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb, int offset)
563 proto_tree_add_item(pdutree, hf_cflow_packets, tvb, offset, 4, FALSE);
566 proto_tree_add_item(pdutree, hf_cflow_octets, tvb, offset, 4, FALSE);
573 flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
574 int bytes, const char *text)
576 proto_tree_add_text(pdutree, tvb, offset, bytes, text);
583 dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
586 int startoffset = offset;
588 proto_tree_add_item(pdutree, hf_cflow_dstaddr, tvb, offset, 4, FALSE);
591 if (verspec != V8PDU_DESTONLY_METHOD) {
592 proto_tree_add_item(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
596 if (verspec == V8PDU_FULL_METHOD) {
597 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2,
600 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2,
605 offset = flow_process_sizecount(pdutree, tvb, offset);
606 offset = flow_process_timeperiod(pdutree, tvb, offset);
608 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
612 if (verspec != V8PDU_DESTONLY_METHOD) {
613 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2,
618 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1, FALSE);
619 if (verspec == V8PDU_FULL_METHOD)
620 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
622 offset = flow_process_textfield(pdutree, tvb, offset, 1, "marked tos");
624 if (verspec == V8PDU_SRCDEST_METHOD)
626 flow_process_textfield(pdutree, tvb, offset, 2,
628 else if (verspec == V8PDU_FULL_METHOD)
630 flow_process_textfield(pdutree, tvb, offset, 1, "padding");
633 flow_process_textfield(pdutree, tvb, offset, 4, "extra packets");
635 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE);
638 return (offset - startoffset);
642 * dissect a version 8 pdu, returning the length of the pdu processed
646 dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
649 int startoffset = offset;
651 proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE);
654 offset = flow_process_sizecount(pdutree, tvb, offset);
655 offset = flow_process_timeperiod(pdutree, tvb, offset);
658 case V8PDU_AS_METHOD:
659 case V8PDU_TOSAS_METHOD:
660 offset = flow_process_aspair(pdutree, tvb, offset);
662 if (verspec == V8PDU_TOSAS_METHOD) {
663 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
666 flow_process_textfield(pdutree, tvb, offset, 1,
669 flow_process_textfield(pdutree, tvb, offset, 2,
673 case V8PDU_PROTO_METHOD:
674 case V8PDU_TOSPROTOPORT_METHOD:
675 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
678 if (verspec == V8PDU_PROTO_METHOD)
680 flow_process_textfield(pdutree, tvb, offset, 1,
682 else if (verspec == V8PDU_TOSPROTOPORT_METHOD)
683 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
687 flow_process_textfield(pdutree, tvb, offset, 2,
689 offset = flow_process_ports(pdutree, tvb, offset);
691 if (verspec == V8PDU_TOSPROTOPORT_METHOD)
692 offset = flow_process_ints(pdutree, tvb, offset);
694 case V8PDU_SPREFIX_METHOD:
695 case V8PDU_DPREFIX_METHOD:
696 case V8PDU_TOSSRCPREFIX_METHOD:
697 case V8PDU_TOSDSTPREFIX_METHOD:
698 proto_tree_add_item(pdutree,
700 V8PDU_SPREFIX_METHOD ?
701 hf_cflow_srcnet : hf_cflow_dstnet, tvb,
705 proto_tree_add_item(pdutree,
707 V8PDU_SPREFIX_METHOD ?
708 hf_cflow_srcmask : hf_cflow_dstmask, tvb,
711 if (verspec == V8PDU_SPREFIX_METHOD
712 || verspec == V8PDU_DPREFIX_METHOD)
714 flow_process_textfield(pdutree, tvb, offset, 1,
716 else if (verspec == V8PDU_TOSSRCPREFIX_METHOD
717 || verspec == V8PDU_TOSDSTPREFIX_METHOD)
718 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
721 proto_tree_add_item(pdutree,
723 V8PDU_SPREFIX_METHOD ? hf_cflow_srcas
724 : hf_cflow_dstas, tvb, offset, 2, FALSE);
727 proto_tree_add_item(pdutree,
729 V8PDU_SPREFIX_METHOD ?
730 hf_cflow_inputint : hf_cflow_outputint,
731 tvb, offset, 2, FALSE);
735 flow_process_textfield(pdutree, tvb, offset, 2,
738 case V8PDU_MATRIX_METHOD:
739 case V8PDU_TOSMATRIX_METHOD:
740 case V8PDU_PREPORTPROTOCOL_METHOD:
741 proto_tree_add_item(pdutree, hf_cflow_srcnet, tvb, offset, 4,
745 proto_tree_add_item(pdutree, hf_cflow_dstnet, tvb, offset, 4,
749 proto_tree_add_item(pdutree, hf_cflow_srcmask, tvb, offset++,
752 proto_tree_add_item(pdutree, hf_cflow_dstmask, tvb, offset++,
755 if (verspec == V8PDU_TOSMATRIX_METHOD ||
756 verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
757 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
759 if (verspec == V8PDU_TOSMATRIX_METHOD) {
761 flow_process_textfield(pdutree, tvb,
764 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
765 proto_tree_add_item(pdutree, hf_cflow_prot,
766 tvb, offset++, 1, FALSE);
770 flow_process_textfield(pdutree, tvb, offset, 2,
774 if (verspec == V8PDU_MATRIX_METHOD
775 || verspec == V8PDU_TOSMATRIX_METHOD) {
776 offset = flow_process_aspair(pdutree, tvb, offset);
777 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
778 offset = flow_process_ports(pdutree, tvb, offset);
781 offset = flow_process_ints(pdutree, tvb, offset);
786 return (offset - startoffset);
789 /* Dissect a version 9 FlowSet and return the length we processed. */
792 dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
800 flowset_id = tvb_get_ntohs(tvb, offset);
801 if (flowset_id == 0) {
803 proto_tree_add_item(pdutree, hf_cflow_template_flowset_id, tvb,
807 length = tvb_get_ntohs(tvb, offset);
808 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
812 dissect_v9_template(pdutree, tvb, offset);
813 } else if (flowset_id == 1) {
815 proto_tree_add_item(pdutree, hf_cflow_options_flowset_id, tvb,
819 length = tvb_get_ntohs(tvb, offset);
820 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
824 /* dissect_v9_options(pdutree, tvb, offset); */
825 } else if (flowset_id >= 2 && flowset_id <= 255) {
827 proto_tree_add_item(pdutree, hf_cflow_flowset_id, tvb,
831 length = tvb_get_ntohs(tvb, offset);
832 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
837 proto_tree_add_item(pdutree, hf_cflow_data_flowset_id, tvb,
841 length = tvb_get_ntohs(tvb, offset);
842 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
847 * The length includes the length of the FlowSet ID and
848 * the length field itself.
852 dissect_v9_data(pdutree, tvb, offset, flowset_id,
861 dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
862 guint16 id, guint length)
864 struct v9_template *template;
865 proto_tree *data_tree;
866 proto_item *data_item;
868 template = v9_template_get(id, 0, 0);
869 if (template != NULL && template->length != 0) {
873 while (length >= template->length) {
874 data_item = proto_tree_add_text(pdutree, tvb,
875 offset, template->length, "pdu %d", count++);
876 data_tree = proto_item_add_subtree(data_item,
879 dissect_v9_pdu(data_tree, tvb, offset, template);
881 offset += template->length;
882 length -= template->length;
885 proto_tree_add_text(pdutree, tvb, offset, length,
886 "Padding (%u byte%s)",
887 length, plurality(length, "", "s"));
890 proto_tree_add_text(pdutree, tvb, offset, length,
891 "Data (%u byte%s), no template found",
892 length, plurality(length, "", "s"));
899 dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
900 struct v9_template * template)
904 for (i = 0; i < template->count; i++) {
907 guint16 type, length;
910 type = template->entries[i].type;
911 length = template->entries[i].length;
916 proto_tree_add_item(pdutree, hf_cflow_octets,
917 tvb, offset, length, FALSE);
918 } else if (length == 8) {
919 proto_tree_add_item(pdutree, hf_cflow_octets64,
920 tvb, offset, length, FALSE);
922 proto_tree_add_text(pdutree,
924 "Octets: length %u", length);
928 case 2: /* packets */
930 proto_tree_add_item(pdutree, hf_cflow_packets,
931 tvb, offset, length, FALSE);
932 } else if (length == 8) {
933 proto_tree_add_item(pdutree, hf_cflow_packets64,
934 tvb, offset, length, FALSE);
936 proto_tree_add_text(pdutree,
938 "Packets: length %u", length);
944 proto_tree_add_item(pdutree, hf_cflow_flows,
945 tvb, offset, length, FALSE);
947 proto_tree_add_text(pdutree,
949 "Flows: length %u", length);
954 proto_tree_add_item(pdutree, hf_cflow_prot,
955 tvb, offset, length, FALSE);
959 proto_tree_add_item(pdutree, hf_cflow_tos,
960 tvb, offset, length, FALSE);
963 case 6: /* TCP flags */
964 proto_tree_add_item(pdutree, hf_cflow_tcpflags,
965 tvb, offset, length, FALSE);
968 case 7: /* source port */
969 proto_tree_add_item(pdutree, hf_cflow_srcport,
970 tvb, offset, length, FALSE);
973 case 8: /* source IP */
975 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
977 proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr,
978 tvb, offset, length, ipv4addr);
979 } else if (length == 16) {
980 tvb_memcpy(tvb, ipv6addr, offset,
982 proto_tree_add_ipv6(pdutree, hf_cflow_srcaddr_v6,
983 tvb, offset, length, ipv6addr);
985 proto_tree_add_text(pdutree,
987 "SrcAddr: length %u", length);
991 case 9: /* source mask */
992 proto_tree_add_item(pdutree, hf_cflow_srcmask,
993 tvb, offset, length, FALSE);
996 case 10: /* input SNMP */
997 proto_tree_add_item(pdutree, hf_cflow_inputint,
998 tvb, offset, length, FALSE);
1001 case 11: /* dest port */
1002 proto_tree_add_item(pdutree, hf_cflow_dstport,
1003 tvb, offset, length, FALSE);
1006 case 12: /* dest IP */
1008 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
1010 proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr,
1011 tvb, offset, length, ipv4addr);
1012 } else if (length == 16) {
1013 tvb_memcpy(tvb, ipv6addr, offset,
1015 proto_tree_add_ipv6(pdutree, hf_cflow_dstaddr_v6,
1016 tvb, offset, length, ipv6addr);
1018 proto_tree_add_text(pdutree,
1019 tvb, offset, length,
1020 "DstAddr: length %u", length);
1024 case 13: /* dest mask */
1025 proto_tree_add_item(pdutree, hf_cflow_dstmask,
1026 tvb, offset, length, FALSE);
1029 case 14: /* output SNMP */
1030 proto_tree_add_item(pdutree, hf_cflow_outputint,
1031 tvb, offset, length, FALSE);
1034 case 15: /* nexthop IP */
1036 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
1038 proto_tree_add_ipv4(pdutree, hf_cflow_nexthop,
1039 tvb, offset, length, ipv4addr);
1040 } else if (length == 16) {
1041 tvb_memcpy(tvb, ipv6addr, offset,
1043 proto_tree_add_ipv6(pdutree, hf_cflow_nexthop_v6,
1044 tvb, offset, length, ipv6addr);
1046 proto_tree_add_text(pdutree,
1047 tvb, offset, length,
1048 "NextHop: length %u", length);
1052 case 16: /* source AS */
1053 proto_tree_add_item(pdutree, hf_cflow_srcas,
1054 tvb, offset, length, FALSE);
1057 case 17: /* dest AS */
1058 proto_tree_add_item(pdutree, hf_cflow_dstas,
1059 tvb, offset, length, FALSE);
1062 case 18: /* BGP nexthop IP */
1064 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
1066 proto_tree_add_ipv4(pdutree, hf_cflow_bgpnexthop,
1067 tvb, offset, length, ipv4addr);
1068 } else if (length == 16) {
1069 tvb_memcpy(tvb, ipv6addr, offset,
1071 proto_tree_add_ipv6(pdutree, hf_cflow_bgpnexthop_v6,
1072 tvb, offset, length, ipv6addr);
1074 proto_tree_add_text(pdutree,
1075 tvb, offset, length,
1076 "BGPNextHop: length %u", length);
1080 case 19: /* multicast packets */
1081 proto_tree_add_item(pdutree, hf_cflow_mulpackets,
1082 tvb, offset, length, FALSE);
1085 case 20: /* multicast octets */
1086 proto_tree_add_item(pdutree, hf_cflow_muloctets,
1087 tvb, offset, length, FALSE);
1090 case 21: /* last switched */
1091 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
1093 proto_tree_add_time(pdutree, hf_cflow_timeend,
1094 tvb, offset, length, &ts);
1097 case 22: /* first switched */
1098 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
1100 proto_tree_add_time(pdutree, hf_cflow_timestart,
1101 tvb, offset, length, &ts);
1104 case 40: /* bytes exported */
1105 proto_tree_add_item(pdutree, hf_cflow_octets_exp,
1106 tvb, offset, length, FALSE);
1109 case 41: /* packets exported */
1110 proto_tree_add_item(pdutree, hf_cflow_packets_exp,
1111 tvb, offset, length, FALSE);
1114 case 42: /* flows exported */
1115 proto_tree_add_item(pdutree, hf_cflow_flows_exp,
1116 tvb, offset, length, FALSE);
1120 proto_tree_add_text(pdutree, tvb, offset, length,
1131 dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb, int offset)
1138 dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb, int offset)
1140 struct v9_template template;
1141 proto_tree *template_tree;
1142 proto_item *template_item;
1146 id = tvb_get_ntohs(tvb, offset);
1147 proto_tree_add_item(pdutree, hf_cflow_template_id, tvb,
1151 count = tvb_get_ntohs(tvb, offset);
1152 proto_tree_add_item(pdutree, hf_cflow_template_field_count, tvb,
1156 /* Cache template */
1157 memset(&template, 0, sizeof(template));
1159 template.count = count;
1160 template.source_addr = 0; /* XXX */
1161 template.source_id = 0; /* XXX */
1162 template.entries = g_malloc(count * sizeof(struct v9_template_entry));
1163 tvb_memcpy(tvb, (guint8 *)template.entries, offset,
1164 count * sizeof(struct v9_template_entry));
1165 v9_template_add(&template);
1167 for (i = 1; i <= count; i++) {
1168 guint16 type, length;
1170 type = tvb_get_ntohs(tvb, offset);
1171 length = tvb_get_ntohs(tvb, offset + 2);
1173 template_item = proto_tree_add_text(pdutree, tvb,
1174 offset, 4, "Field (%u/%u)", i, count);
1175 template_tree = proto_item_add_subtree(template_item, ett_template);
1177 proto_tree_add_item(template_tree,
1178 hf_cflow_template_field_type, tvb, offset, 2, FALSE);
1181 proto_tree_add_item(template_tree,
1182 hf_cflow_template_field_length, tvb, offset, 2, FALSE);
1189 static value_string v9_template_types[] = {
1196 { 7, "L4_SRC_PORT" },
1197 { 8, "IP_SRC_ADDR" },
1199 { 10, "INPUT_SNMP" },
1200 { 11, "L4_DST_PORT" },
1201 { 12, "IP_DST_ADDR" },
1203 { 14, "OUTPUT_SNMP" },
1204 { 15, "IP_NEXT_HOP" },
1207 { 18, "BGP_NEXT_HOP" },
1208 { 19, "MUL_DPKTS" },
1209 { 20, "MUL_DOCTETS" },
1210 { 21, "LAST_SWITCHED" },
1211 { 22, "FIRST_SWITCHED" },
1213 { 40, "TOTAL_BYTES_EXP" },
1214 { 41, "TOTAL_PKTS_EXP" },
1215 { 42, "TOTAL_FLOWS_EXP" },
1220 v9_template_add(struct v9_template *template)
1224 /* Add up the actual length of the data and store in proper byte order */
1225 template->length = 0;
1226 for (i = 0; i < template->count; i++) {
1227 template->entries[i].type = g_ntohs(template->entries[i].type);
1228 template->entries[i].length = g_ntohs(template->entries[i].length);
1229 template->length += template->entries[i].length;
1232 memmove(&v9_template_cache[template->id % V9TEMPLATE_CACHE_MAX_ENTRIES],
1233 template, sizeof(*template));
1236 static struct v9_template *
1237 v9_template_get(guint16 id, guint32 src_addr, guint32 src_id)
1239 struct v9_template *template;
1242 template = &v9_template_cache[id % V9TEMPLATE_CACHE_MAX_ENTRIES];
1244 if (template->id != id ||
1245 template->source_addr != src_addr ||
1246 template->source_id != src_id) {
1254 * dissect a version 1, 5, or 7 pdu and return the length of the pdu we
1259 dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
1261 int startoffset = offset;
1262 guint32 srcaddr, dstaddr;
1266 memset(&ts, '\0', sizeof(ts));
1269 * memcpy so we can use the values later to calculate a prefix
1271 tvb_memcpy(tvb, (guint8 *) & srcaddr, offset, 4);
1272 proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
1276 tvb_memcpy(tvb, (guint8 *) & dstaddr, offset, 4);
1277 proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr, tvb, offset, 4,
1281 proto_tree_add_item(pdutree, hf_cflow_nexthop, tvb, offset, 4, FALSE);
1284 offset = flow_process_ints(pdutree, tvb, offset);
1285 offset = flow_process_sizecount(pdutree, tvb, offset);
1286 offset = flow_process_timeperiod(pdutree, tvb, offset);
1287 offset = flow_process_ports(pdutree, tvb, offset);
1290 * and the similarities end here
1294 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1296 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1299 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1302 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1306 flow_process_textfield(pdutree, tvb, offset, 3, "padding");
1309 flow_process_textfield(pdutree, tvb, offset, 4,
1314 flow_process_textfield(pdutree, tvb, offset, 1,
1317 proto_tree_add_item(pdutree, hf_cflow_flags, tvb,
1318 offset++, 1, FALSE);
1321 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1324 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1327 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1330 offset = flow_process_aspair(pdutree, tvb, offset);
1332 mask = tvb_get_guint8(tvb, offset);
1333 proto_tree_add_text(pdutree, tvb, offset, 1,
1334 "SrcMask: %u (prefix: %s/%u)",
1335 mask, getprefix(&srcaddr, mask),
1336 mask != 0 ? mask : 32);
1337 proto_tree_add_uint_hidden(pdutree, hf_cflow_srcmask, tvb,
1340 mask = tvb_get_guint8(tvb, offset);
1341 proto_tree_add_text(pdutree, tvb, offset, 1,
1342 "DstMask: %u (prefix: %s/%u)",
1343 mask, getprefix(&dstaddr, mask),
1344 mask != 0 ? mask : 32);
1345 proto_tree_add_uint_hidden(pdutree, hf_cflow_dstmask, tvb,
1349 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1352 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb,
1358 return (offset - startoffset);
1362 getprefix(const guint32 * address, int prefix)
1366 gprefix = *address & g_htonl((0xffffffff << (32 - prefix)));
1368 return (ip_to_str((const guint8 *)&gprefix));
1373 netflow_reinit(void)
1378 * Clear out the template cache.
1379 * Free the table of fields for each entry, and then zero out
1382 for (i = 0; i < V9TEMPLATE_CACHE_MAX_ENTRIES; i++)
1383 g_free(v9_template_cache[i].entries);
1384 memset(v9_template_cache, 0, sizeof v9_template_cache);
1388 proto_register_netflow(void)
1390 static hf_register_info hf[] = {
1395 {"Version", "cflow.version",
1396 FT_UINT16, BASE_DEC, NULL, 0x0,
1397 "NetFlow Version", HFILL}
1400 {"Count", "cflow.count",
1401 FT_UINT16, BASE_DEC, NULL, 0x0,
1402 "Count of PDUs", HFILL}
1404 {&hf_cflow_sysuptime,
1405 {"SysUptime", "cflow.sysuptime",
1406 FT_UINT32, BASE_DEC, NULL, 0x0,
1407 "Time since router booted (in milliseconds)", HFILL}
1410 {&hf_cflow_timestamp,
1411 {"Timestamp", "cflow.timestamp",
1412 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1413 "Current seconds since epoch", HFILL}
1415 {&hf_cflow_unix_secs,
1416 {"CurrentSecs", "cflow.unix_secs",
1417 FT_UINT32, BASE_DEC, NULL, 0x0,
1418 "Current seconds since epoch", HFILL}
1420 {&hf_cflow_unix_nsecs,
1421 {"CurrentNSecs", "cflow.unix_nsecs",
1422 FT_UINT32, BASE_DEC, NULL, 0x0,
1423 "Residual nanoseconds since epoch", HFILL}
1425 {&hf_cflow_samplerate,
1426 {"SampleRate", "cflow.samplerate",
1427 FT_UINT16, BASE_DEC, NULL, 0x0,
1428 "Sample Frequency of exporter", HFILL}
1432 * end version-agnostic header
1433 * version-specific flow header
1435 {&hf_cflow_sequence,
1436 {"FlowSequence", "cflow.sequence",
1437 FT_UINT32, BASE_DEC, NULL, 0x0,
1438 "Sequence number of flows seen", HFILL}
1440 {&hf_cflow_engine_type,
1441 {"EngineType", "cflow.engine_type",
1442 FT_UINT8, BASE_DEC, NULL, 0x0,
1443 "Flow switching engine type", HFILL}
1445 {&hf_cflow_engine_id,
1446 {"EngineId", "cflow.engine_id",
1447 FT_UINT8, BASE_DEC, NULL, 0x0,
1448 "Slot number of switching engine", HFILL}
1450 {&hf_cflow_source_id,
1451 {"SourceId", "cflow.source_id",
1452 FT_UINT32, BASE_DEC, NULL, 0x0,
1453 "Identifier for export device", HFILL}
1455 {&hf_cflow_aggmethod,
1456 {"AggMethod", "cflow.aggmethod",
1457 FT_UINT8, BASE_DEC, VALS(v8_agg), 0x0,
1458 "CFlow V8 Aggregation Method", HFILL}
1460 {&hf_cflow_aggversion,
1461 {"AggVersion", "cflow.aggversion",
1462 FT_UINT8, BASE_DEC, NULL, 0x0,
1463 "CFlow V8 Aggregation Version", HFILL}
1466 * end version specific header storage
1471 {&hf_cflow_flowset_id,
1472 {"FlowSet Id", "cflow.flowset_id",
1473 FT_UINT16, BASE_DEC, NULL, 0x0,
1474 "FlowSet Id", HFILL}
1476 {&hf_cflow_data_flowset_id,
1477 {"Data FlowSet (Template Id)", "cflow.data_flowset_id",
1478 FT_UINT16, BASE_DEC, NULL, 0x0,
1479 "Data FlowSet with corresponding to a template Id", HFILL}
1481 {&hf_cflow_options_flowset_id,
1482 {"Options FlowSet", "cflow.options_flowset_id",
1483 FT_UINT16, BASE_DEC, NULL, 0x0,
1484 "Options FlowSet", HFILL}
1486 {&hf_cflow_template_flowset_id,
1487 {"Template FlowSet", "cflow.template_flowset_id",
1488 FT_UINT16, BASE_DEC, NULL, 0x0,
1489 "Template FlowSet", HFILL}
1491 {&hf_cflow_flowset_length,
1492 {"FlowSet Length", "cflow.flowset_length",
1493 FT_UINT16, BASE_DEC, NULL, 0x0,
1494 "FlowSet length", HFILL}
1496 {&hf_cflow_template_id,
1497 {"Template Id", "cflow.template_id",
1498 FT_UINT16, BASE_DEC, NULL, 0x0,
1499 "Template Id", HFILL}
1501 {&hf_cflow_template_field_count,
1502 {"Field Count", "cflow.template_field_count",
1503 FT_UINT16, BASE_DEC, NULL, 0x0,
1504 "Template field count", HFILL}
1506 {&hf_cflow_template_field_type,
1507 {"Type", "cflow.template_field_type",
1508 FT_UINT16, BASE_DEC, VALS(v9_template_types), 0x0,
1509 "Template field type", HFILL}
1511 {&hf_cflow_template_field_length,
1512 {"Length", "cflow.template_field_length",
1513 FT_UINT16, BASE_DEC, NULL, 0x0,
1514 "Template field length", HFILL}
1517 * begin pdu content storage
1520 {"SrcAddr", "cflow.srcaddr",
1521 FT_IPv4, BASE_NONE, NULL, 0x0,
1522 "Flow Source Address", HFILL}
1524 {&hf_cflow_srcaddr_v6,
1525 {"SrcAddr", "cflow.srcaddrv6",
1526 FT_IPv6, BASE_NONE, NULL, 0x0,
1527 "Flow Source Address", HFILL}
1530 {"SrcNet", "cflow.srcnet",
1531 FT_IPv4, BASE_NONE, NULL, 0x0,
1532 "Flow Source Network", HFILL}
1535 {"DstAddr", "cflow.dstaddr",
1536 FT_IPv4, BASE_NONE, NULL, 0x0,
1537 "Flow Destination Address", HFILL}
1539 {&hf_cflow_dstaddr_v6,
1540 {"DstAddr", "cflow.dstaddrv6",
1541 FT_IPv6, BASE_NONE, NULL, 0x0,
1542 "Flow Destination Address", HFILL}
1545 {"DstNet", "cflow.dstaddr",
1546 FT_IPv4, BASE_NONE, NULL, 0x0,
1547 "Flow Destination Network", HFILL}
1550 {"NextHop", "cflow.nexthop",
1551 FT_IPv4, BASE_NONE, NULL, 0x0,
1552 "Router nexthop", HFILL}
1554 {&hf_cflow_nexthop_v6,
1555 {"NextHop", "cflow.nexthopv6",
1556 FT_IPv6, BASE_NONE, NULL, 0x0,
1557 "Router nexthop", HFILL}
1559 {&hf_cflow_bgpnexthop,
1560 {"BGPNextHop", "cflow.bgpnexthop",
1561 FT_IPv4, BASE_NONE, NULL, 0x0,
1562 "BGP Router Nexthop", HFILL}
1564 {&hf_cflow_bgpnexthop_v6,
1565 {"BGPNextHop", "cflow.bgpnexthopv6",
1566 FT_IPv6, BASE_NONE, NULL, 0x0,
1567 "BGP Router Nexthop", HFILL}
1569 {&hf_cflow_inputint,
1570 {"InputInt", "cflow.inputint",
1571 FT_UINT16, BASE_DEC, NULL, 0x0,
1572 "Flow Input Interface", HFILL}
1574 {&hf_cflow_outputint,
1575 {"OutputInt", "cflow.outputint",
1576 FT_UINT16, BASE_DEC, NULL, 0x0,
1577 "Flow Output Interface", HFILL}
1580 {"Flows", "cflow.flows",
1581 FT_UINT32, BASE_DEC, NULL, 0x0,
1582 "Flows Aggregated in PDU", HFILL}
1585 {"Packets", "cflow.packets",
1586 FT_UINT32, BASE_DEC, NULL, 0x0,
1587 "Count of packets", HFILL}
1589 {&hf_cflow_packets64,
1590 {"Packets", "cflow.packets64",
1591 FT_UINT64, BASE_DEC, NULL, 0x0,
1592 "Count of packets", HFILL}
1594 {&hf_cflow_packetsout,
1595 {"PacketsOut", "cflow.packetsout",
1596 FT_UINT64, BASE_DEC, NULL, 0x0,
1597 "Count of packets going out", HFILL}
1600 {"Octets", "cflow.octets",
1601 FT_UINT32, BASE_DEC, NULL, 0x0,
1602 "Count of bytes", HFILL}
1604 {&hf_cflow_octets64,
1605 {"Octets", "cflow.octets64",
1606 FT_UINT64, BASE_DEC, NULL, 0x0,
1607 "Count of bytes", HFILL}
1609 {&hf_cflow_timestart,
1610 {"StartTime", "cflow.timestart",
1611 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1612 "Uptime at start of flow", HFILL}
1615 {"EndTime", "cflow.timeend",
1616 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1617 "Uptime at end of flow", HFILL}
1620 {"SrcPort", "cflow.srcport",
1621 FT_UINT16, BASE_DEC, NULL, 0x0,
1622 "Flow Source Port", HFILL}
1625 {"DstPort", "cflow.dstport",
1626 FT_UINT16, BASE_DEC, NULL, 0x0,
1627 "Flow Destination Port", HFILL}
1630 {"Protocol", "cflow.protocol",
1631 FT_UINT8, BASE_DEC, NULL, 0x0,
1632 "IP Protocol", HFILL}
1635 {"IP ToS", "cflow.tos",
1636 FT_UINT8, BASE_HEX, NULL, 0x0,
1637 "IP Type of Service", HFILL}
1640 {"Export Flags", "cflow.flags",
1641 FT_UINT8, BASE_HEX, NULL, 0x0,
1642 "CFlow Flags", HFILL}
1644 {&hf_cflow_tcpflags,
1645 {"TCP Flags", "cflow.tcpflags",
1646 FT_UINT8, BASE_HEX, NULL, 0x0,
1650 {"SrcAS", "cflow.srcas",
1651 FT_UINT16, BASE_DEC, NULL, 0x0,
1655 {"DstAS", "cflow.dstas",
1656 FT_UINT16, BASE_DEC, NULL, 0x0,
1657 "Destination AS", HFILL}
1660 {"SrcMask", "cflow.srcmask",
1661 FT_UINT8, BASE_DEC, NULL, 0x0,
1662 "Source Prefix Mask", HFILL}
1665 {"DstMask", "cflow.dstmask",
1666 FT_UINT8, BASE_DEC, NULL, 0x0,
1667 "Destination Prefix Mask", HFILL}
1669 {&hf_cflow_routersc,
1670 {"Router Shortcut", "cflow.routersc",
1671 FT_IPv4, BASE_NONE, NULL, 0x0,
1672 "Router shortcut by switch", HFILL}
1674 {&hf_cflow_mulpackets,
1675 {"MulticastPackets", "cflow.mulpackets",
1676 FT_UINT32, BASE_DEC, NULL, 0x0,
1677 "Count of multicast packets", HFILL}
1679 {&hf_cflow_muloctets,
1680 {"MulticastOctets", "cflow.muloctets",
1681 FT_UINT32, BASE_DEC, NULL, 0x0,
1682 "Count of multicast octets", HFILL}
1684 {&hf_cflow_octets_exp,
1685 {"OctetsExp", "cflow.octetsexp",
1686 FT_UINT32, BASE_DEC, NULL, 0x0,
1687 "Octets exported", HFILL}
1689 {&hf_cflow_packets_exp,
1690 {"PacketsExp", "cflow.packetsexp",
1691 FT_UINT32, BASE_DEC, NULL, 0x0,
1692 "Packets exported", HFILL}
1694 {&hf_cflow_flows_exp,
1695 {"FlowsExp", "cflow.flowsexp",
1696 FT_UINT32, BASE_DEC, NULL, 0x0,
1697 "Flows exported", HFILL}
1700 * end pdu content storage
1704 static gint *ett[] = {
1712 module_t *netflow_module;
1714 proto_netflow = proto_register_protocol("Cisco NetFlow", "CFLOW",
1717 proto_register_field_array(proto_netflow, hf, array_length(hf));
1718 proto_register_subtree_array(ett, array_length(ett));
1720 /* Register our configuration options for NetFlow */
1721 netflow_module = prefs_register_protocol(proto_netflow,
1722 proto_reg_handoff_netflow);
1724 prefs_register_uint_preference(netflow_module, "udp.port",
1725 "NetFlow UDP Port", "Set the port for NetFlow messages",
1726 10, &global_netflow_udp_port);
1728 register_init_routine(&netflow_reinit);
1733 * protocol/port association
1736 proto_reg_handoff_netflow(void)
1738 static int netflow_prefs_initialized = FALSE;
1739 static dissector_handle_t netflow_handle;
1741 if (!netflow_prefs_initialized) {
1742 netflow_handle = create_dissector_handle(dissect_netflow,
1744 netflow_prefs_initialized = TRUE;
1746 dissector_delete("udp.port", netflow_udp_port, netflow_handle);
1749 /* Set out port number for future use */
1750 netflow_udp_port = global_netflow_udp_port;
1752 dissector_add("udp.port", netflow_udp_port, netflow_handle);