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.
26 ** NetFlow v9 patches by Luca Deri <deri@ntop.org>
30 ** http://www.cisco.com/warp/public/cc/pd/iosw/prodlit/tflow_wp.htm
32 ** for NetFlow v9 information.
34 *****************************************************************************
36 ** this code was written from the following documentation:
38 ** http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_6/iug/format.pdf
39 ** http://www.caida.org/tools/measurement/cflowd/configuration/configuration-9.html
41 ** some documentation is more accurate then others. in some cases, live data and
42 ** information contained in responses from vendors were also used. some fields
43 ** are dissected as vendor specific fields.
47 ** http://www.cisco.com/univercd/cc/td/doc/cisintwk/intsolns/netflsol/nfwhite.htm
49 ** $Yahoo: //depot/fumerola/packet-netflow/packet-netflow.c#14 $
58 #include <epan/packet.h>
61 #include <epan/prefs.h>
63 #define UDP_PORT_NETFLOW 2055
65 static guint global_netflow_udp_port = UDP_PORT_NETFLOW;
66 static guint netflow_udp_port = 0;
69 * pdu identifiers & sizes
72 #define V1PDU_SIZE (4 * 12)
73 #define V5PDU_SIZE (4 * 12)
74 #define V7PDU_SIZE (4 * 13)
75 #define V8PDU_AS_SIZE (4 * 7)
76 #define V8PDU_PROTO_SIZE (4 * 7)
77 #define V8PDU_SPREFIX_SIZE (4 * 8)
78 #define V8PDU_DPREFIX_SIZE (4 * 8)
79 #define V8PDU_MATRIX_SIZE (4 * 10)
80 #define V8PDU_DESTONLY_SIZE (4 * 8)
81 #define V8PDU_SRCDEST_SIZE (4 * 10)
82 #define V8PDU_FULL_SIZE (4 * 11)
83 #define V8PDU_TOSAS_SIZE (V8PDU_AS_SIZE + 4)
84 #define V8PDU_TOSPROTOPORT_SIZE (V8PDU_PROTO_SIZE + 4)
85 #define V8PDU_TOSSRCPREFIX_SIZE V8PDU_SPREFIX_SIZE
86 #define V8PDU_TOSDSTPREFIX_SIZE V8PDU_DPREFIX_SIZE
87 #define V8PDU_TOSMATRIX_SIZE V8PDU_MATRIX_SIZE
88 #define V8PDU_PREPORTPROTOCOL_SIZE (4 * 10)
90 static const value_string v5_sampling_mode[] = {
91 {0, "No sampling mode configured"},
92 {1, "Packet Interval sampling mode configured"},
100 V8PDU_SPREFIX_METHOD,
101 V8PDU_DPREFIX_METHOD,
103 V8PDU_DESTONLY_METHOD,
104 V8PDU_SRCDEST_METHOD,
107 V8PDU_TOSPROTOPORT_METHOD,
108 V8PDU_TOSSRCPREFIX_METHOD,
109 V8PDU_TOSDSTPREFIX_METHOD,
110 V8PDU_TOSMATRIX_METHOD,
111 V8PDU_PREPORTPROTOCOL_METHOD
114 static const value_string v8_agg[] = {
115 {V8PDU_AS_METHOD, "V8 AS aggregation"},
116 {V8PDU_PROTO_METHOD, "V8 Proto/Port aggregation"},
117 {V8PDU_SPREFIX_METHOD, "V8 Source Prefix aggregation"},
118 {V8PDU_DPREFIX_METHOD, "V8 Destination Prefix aggregation"},
119 {V8PDU_MATRIX_METHOD, "V8 Network Matrix aggregation"},
120 {V8PDU_DESTONLY_METHOD, "V8 Destination aggregation (Cisco Catalyst)"},
121 {V8PDU_SRCDEST_METHOD, "V8 Src/Dest aggregation (Cisco Catalyst)"},
122 {V8PDU_FULL_METHOD, "V8 Full aggregation (Cisco Catalyst)"},
123 {V8PDU_TOSAS_METHOD, "V8 TOS+AS aggregation aggregation"},
124 {V8PDU_TOSPROTOPORT_METHOD, "V8 TOS+Protocol aggregation"},
125 {V8PDU_TOSSRCPREFIX_METHOD, "V8 TOS+Source Prefix aggregation"},
126 {V8PDU_TOSDSTPREFIX_METHOD, "V8 TOS+Destination Prefix aggregation"},
127 {V8PDU_TOSMATRIX_METHOD, "V8 TOS+Prefix Matrix aggregation"},
128 {V8PDU_PREPORTPROTOCOL_METHOD, "V8 Port+Protocol aggregation"},
132 /* Version 9 template cache structures */
133 #define V9TEMPLATE_CACHE_MAX_ENTRIES 100
135 struct v9_template_entry {
146 guint16 option_template; /* 0=data template, 1=option template */
147 struct v9_template_entry *entries;
150 static struct v9_template v9_template_cache[V9TEMPLATE_CACHE_MAX_ENTRIES];
153 * ethereal tree identifiers
156 static int proto_netflow = -1;
157 static int ett_netflow = -1;
158 static int ett_unixtime = -1;
159 static int ett_flow = -1;
160 static int ett_template = -1;
161 static int ett_dataflowset = -1;
167 static int hf_cflow_version = -1;
168 static int hf_cflow_count = -1;
169 static int hf_cflow_sysuptime = -1;
170 static int hf_cflow_unix_secs = -1;
171 static int hf_cflow_unix_nsecs = -1;
172 static int hf_cflow_timestamp = -1;
173 static int hf_cflow_samplingmode = -1;
174 static int hf_cflow_samplerate = -1;
177 * cflow version specific info
179 static int hf_cflow_sequence = -1;
180 static int hf_cflow_engine_type = -1;
181 static int hf_cflow_engine_id = -1;
182 static int hf_cflow_source_id = -1;
184 static int hf_cflow_aggmethod = -1;
185 static int hf_cflow_aggversion = -1;
189 static int hf_cflow_template_flowset_id = -1;
190 static int hf_cflow_data_flowset_id = -1;
191 static int hf_cflow_options_flowset_id = -1;
192 static int hf_cflow_flowset_id = -1;
193 static int hf_cflow_flowset_length = -1;
194 static int hf_cflow_template_id = -1;
195 static int hf_cflow_template_field_count = -1;
196 static int hf_cflow_template_field_type = -1;
197 static int hf_cflow_template_field_length = -1;
198 static int hf_cflow_option_scope_length = -1;
199 static int hf_cflow_option_length = -1;
200 static int hf_cflow_template_scope_field_type = -1;
201 static int hf_cflow_template_scope_field_length = -1;
207 static int hf_cflow_srcaddr = -1;
208 static int hf_cflow_srcaddr_v6 = -1;
209 static int hf_cflow_srcnet = -1;
210 static int hf_cflow_dstaddr = -1;
211 static int hf_cflow_dstaddr_v6 = -1;
212 static int hf_cflow_dstnet = -1;
213 static int hf_cflow_nexthop = -1;
214 static int hf_cflow_nexthop_v6 = -1;
215 static int hf_cflow_bgpnexthop = -1;
216 static int hf_cflow_bgpnexthop_v6 = -1;
217 static int hf_cflow_inputint = -1;
218 static int hf_cflow_outputint = -1;
219 static int hf_cflow_flows = -1;
220 static int hf_cflow_packets = -1;
221 static int hf_cflow_packets64 = -1;
222 static int hf_cflow_packetsout = -1;
223 static int hf_cflow_octets = -1;
224 static int hf_cflow_octets64 = -1;
225 static int hf_cflow_timestart = -1;
226 static int hf_cflow_timeend = -1;
227 static int hf_cflow_srcport = -1;
228 static int hf_cflow_dstport = -1;
229 static int hf_cflow_prot = -1;
230 static int hf_cflow_tos = -1;
231 static int hf_cflow_flags = -1;
232 static int hf_cflow_tcpflags = -1;
233 static int hf_cflow_dstas = -1;
234 static int hf_cflow_srcas = -1;
235 static int hf_cflow_dstmask = -1;
236 static int hf_cflow_srcmask = -1;
237 static int hf_cflow_routersc = -1;
238 static int hf_cflow_mulpackets = -1;
239 static int hf_cflow_muloctets = -1;
240 static int hf_cflow_octets_exp = -1;
241 static int hf_cflow_packets_exp = -1;
242 static int hf_cflow_flows_exp = -1;
243 static int hf_cflow_sampling_interval = -1;
244 static int hf_cflow_sampling_algorithm = -1;
245 static int hf_cflow_flow_active_timeout = -1;
246 static int hf_cflow_flow_inactive_timeout = -1;
248 void proto_reg_handoff_netflow(void);
250 typedef int dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
252 static int dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
254 static int dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
255 int offset, int verspec);
256 static int dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
257 int offset, int verspec);
258 static int dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb,
259 int offset, int verspec);
260 static int dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb,
261 int offset, guint16 id, guint length);
262 static void dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb,
263 int offset, struct v9_template * template);
264 static int dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb,
266 static int dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb,
268 static void v9_template_add(struct v9_template * template);
269 static struct v9_template *v9_template_get(guint16 id, guint32 src_addr,
272 static gchar *getprefix(const guint32 * address, int prefix);
273 static void dissect_netflow(tvbuff_t * tvb, packet_info * pinfo,
276 static int flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb,
278 static int flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb,
280 static int flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb,
282 static int flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb,
284 static int flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb,
286 static int flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb,
287 int offset, int bytes,
292 dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
294 proto_tree *netflow_tree = NULL;
296 proto_item *timeitem, *pduitem;
297 proto_tree *timetree, *pdutree;
298 unsigned int pduret, ver = 0, pdus = 0, x = 1, vspec;
299 size_t available, pdusize, offset = 0;
301 dissect_pdu_t *pduptr;
303 if (check_col(pinfo->cinfo, COL_PROTOCOL))
304 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFLOW");
305 if (check_col(pinfo->cinfo, COL_INFO))
306 col_clear(pinfo->cinfo, COL_INFO);
309 ti = proto_tree_add_item(tree, proto_netflow, tvb,
311 netflow_tree = proto_item_add_subtree(ti, ett_netflow);
314 ver = tvb_get_ntohs(tvb, offset);
318 pdusize = V1PDU_SIZE;
319 pduptr = &dissect_pdu;
322 pdusize = V5PDU_SIZE;
323 pduptr = &dissect_pdu;
326 pdusize = V7PDU_SIZE;
327 pduptr = &dissect_pdu;
330 pdusize = -1; /* deferred */
331 pduptr = &dissect_v8_aggpdu;
334 pdusize = -1; /* deferred */
335 pduptr = &dissect_v9_flowset;
342 proto_tree_add_uint(netflow_tree, hf_cflow_version, tvb,
346 pdus = tvb_get_ntohs(tvb, offset);
350 proto_tree_add_uint(netflow_tree, hf_cflow_count, tvb,
355 * set something interesting in the display now that we have info
357 if (check_col(pinfo->cinfo, COL_INFO)) {
359 col_add_fstr(pinfo->cinfo, COL_INFO,
360 "total: %u (v%u) FlowSets", pdus, ver);
362 col_add_fstr(pinfo->cinfo, COL_INFO,
363 "total: %u (v%u) flows", pdus, ver);
368 * the rest is only interesting if we're displaying/searching the
374 proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb,
378 ts.secs = tvb_get_ntohl(tvb, offset);
379 ts.nsecs = tvb_get_ntohl(tvb, offset + 4);
380 timeitem = proto_tree_add_time(netflow_tree,
381 hf_cflow_timestamp, tvb, offset,
383 timetree = proto_item_add_subtree(timeitem, ett_unixtime);
385 proto_tree_add_item(timetree, hf_cflow_unix_secs, tvb,
390 proto_tree_add_item(timetree, hf_cflow_unix_nsecs, tvb,
396 * version specific header
398 if (ver == 5 || ver == 7 || ver == 8 || ver == 9) {
399 proto_tree_add_item(netflow_tree, hf_cflow_sequence,
400 tvb, offset, 4, FALSE);
403 if (ver == 5 || ver == 8) {
404 proto_tree_add_item(netflow_tree, hf_cflow_engine_type,
405 tvb, offset++, 1, FALSE);
406 proto_tree_add_item(netflow_tree, hf_cflow_engine_id,
407 tvb, offset++, 1, FALSE);
408 } else if (ver == 9) {
409 proto_tree_add_item(netflow_tree, hf_cflow_source_id,
410 tvb, offset, 4, FALSE);
414 vspec = tvb_get_guint8(tvb, offset);
416 case V8PDU_AS_METHOD:
417 pdusize = V8PDU_AS_SIZE;
419 case V8PDU_PROTO_METHOD:
420 pdusize = V8PDU_PROTO_SIZE;
422 case V8PDU_SPREFIX_METHOD:
423 pdusize = V8PDU_SPREFIX_SIZE;
425 case V8PDU_DPREFIX_METHOD:
426 pdusize = V8PDU_DPREFIX_SIZE;
428 case V8PDU_MATRIX_METHOD:
429 pdusize = V8PDU_MATRIX_SIZE;
431 case V8PDU_DESTONLY_METHOD:
432 pdusize = V8PDU_DESTONLY_SIZE;
433 pduptr = &dissect_v8_flowpdu;
435 case V8PDU_SRCDEST_METHOD:
436 pdusize = V8PDU_SRCDEST_SIZE;
437 pduptr = &dissect_v8_flowpdu;
439 case V8PDU_FULL_METHOD:
440 pdusize = V8PDU_FULL_SIZE;
441 pduptr = &dissect_v8_flowpdu;
443 case V8PDU_TOSAS_METHOD:
444 pdusize = V8PDU_TOSAS_SIZE;
446 case V8PDU_TOSPROTOPORT_METHOD:
447 pdusize = V8PDU_TOSPROTOPORT_SIZE;
449 case V8PDU_TOSSRCPREFIX_METHOD:
450 pdusize = V8PDU_TOSSRCPREFIX_SIZE;
452 case V8PDU_TOSDSTPREFIX_METHOD:
453 pdusize = V8PDU_TOSDSTPREFIX_SIZE;
455 case V8PDU_TOSMATRIX_METHOD:
456 pdusize = V8PDU_TOSMATRIX_SIZE;
458 case V8PDU_PREPORTPROTOCOL_METHOD:
459 pdusize = V8PDU_PREPORTPROTOCOL_SIZE;
466 proto_tree_add_uint(netflow_tree, hf_cflow_aggmethod,
467 tvb, offset++, 1, vspec);
468 proto_tree_add_item(netflow_tree, hf_cflow_aggversion,
469 tvb, offset++, 1, FALSE);
471 if (ver == 7 || ver == 8)
472 offset = flow_process_textfield(netflow_tree, tvb, offset, 4,
475 proto_tree_add_item(netflow_tree, hf_cflow_samplingmode,
476 tvb, offset, 2, FALSE);
477 proto_tree_add_item(netflow_tree, hf_cflow_samplerate,
478 tvb, offset, 2, FALSE);
483 * everything below here should be payload
485 for (x = 1; x < pdus + 1; x++) {
487 * make sure we have a pdu's worth of data
489 available = tvb_length_remaining(tvb, offset);
490 if (ver == 9 && available >= 4) {
491 /* pdusize can be different for each v9 flowset */
492 pdusize = tvb_get_ntohs(tvb, offset + 2);
495 if (available < pdusize)
499 pduitem = proto_tree_add_text(netflow_tree, tvb,
500 offset, pdusize, "FlowSet %u/%u", x, pdus);
502 pduitem = proto_tree_add_text(netflow_tree, tvb,
503 offset, pdusize, "pdu %u/%u", x, pdus);
505 pdutree = proto_item_add_subtree(pduitem, ett_flow);
507 pduret = pduptr(pdutree, tvb, offset, vspec);
509 if (pduret < pdusize) pduret = pdusize; /* padding */
512 * if we came up short, stop processing
514 if (pduret == pdusize)
522 * flow_process_* == common groups of fields, probably could be inline
526 flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb, int offset)
528 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, FALSE);
531 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
539 flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb, int offset)
541 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2, FALSE);
544 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE);
551 flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb, int offset)
555 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
556 ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
557 proto_tree_add_time(pdutree, hf_cflow_timestart, tvb, offset, 4, &ts);
560 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
561 ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
562 proto_tree_add_time(pdutree, hf_cflow_timeend, tvb, offset, 4, &ts);
570 flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb, int offset)
572 proto_tree_add_item(pdutree, hf_cflow_srcas, tvb, offset, 2, FALSE);
575 proto_tree_add_item(pdutree, hf_cflow_dstas, tvb, offset, 2, FALSE);
582 flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb, int offset)
584 proto_tree_add_item(pdutree, hf_cflow_packets, tvb, offset, 4, FALSE);
587 proto_tree_add_item(pdutree, hf_cflow_octets, tvb, offset, 4, FALSE);
594 flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
595 int bytes, const char *text)
597 proto_tree_add_text(pdutree, tvb, offset, bytes, text);
604 dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
607 int startoffset = offset;
609 proto_tree_add_item(pdutree, hf_cflow_dstaddr, tvb, offset, 4, FALSE);
612 if (verspec != V8PDU_DESTONLY_METHOD) {
613 proto_tree_add_item(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
617 if (verspec == V8PDU_FULL_METHOD) {
618 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2,
621 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2,
626 offset = flow_process_sizecount(pdutree, tvb, offset);
627 offset = flow_process_timeperiod(pdutree, tvb, offset);
629 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
633 if (verspec != V8PDU_DESTONLY_METHOD) {
634 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2,
639 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1, FALSE);
640 if (verspec == V8PDU_FULL_METHOD)
641 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
643 offset = flow_process_textfield(pdutree, tvb, offset, 1, "marked tos");
645 if (verspec == V8PDU_SRCDEST_METHOD)
647 flow_process_textfield(pdutree, tvb, offset, 2,
649 else if (verspec == V8PDU_FULL_METHOD)
651 flow_process_textfield(pdutree, tvb, offset, 1, "padding");
654 flow_process_textfield(pdutree, tvb, offset, 4, "extra packets");
656 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE);
659 return (offset - startoffset);
663 * dissect a version 8 pdu, returning the length of the pdu processed
667 dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
670 int startoffset = offset;
672 proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE);
675 offset = flow_process_sizecount(pdutree, tvb, offset);
676 offset = flow_process_timeperiod(pdutree, tvb, offset);
679 case V8PDU_AS_METHOD:
680 case V8PDU_TOSAS_METHOD:
681 offset = flow_process_aspair(pdutree, tvb, offset);
683 if (verspec == V8PDU_TOSAS_METHOD) {
684 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
687 flow_process_textfield(pdutree, tvb, offset, 1,
690 flow_process_textfield(pdutree, tvb, offset, 2,
694 case V8PDU_PROTO_METHOD:
695 case V8PDU_TOSPROTOPORT_METHOD:
696 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
699 if (verspec == V8PDU_PROTO_METHOD)
701 flow_process_textfield(pdutree, tvb, offset, 1,
703 else if (verspec == V8PDU_TOSPROTOPORT_METHOD)
704 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
708 flow_process_textfield(pdutree, tvb, offset, 2,
710 offset = flow_process_ports(pdutree, tvb, offset);
712 if (verspec == V8PDU_TOSPROTOPORT_METHOD)
713 offset = flow_process_ints(pdutree, tvb, offset);
715 case V8PDU_SPREFIX_METHOD:
716 case V8PDU_DPREFIX_METHOD:
717 case V8PDU_TOSSRCPREFIX_METHOD:
718 case V8PDU_TOSDSTPREFIX_METHOD:
719 proto_tree_add_item(pdutree,
721 V8PDU_SPREFIX_METHOD ?
722 hf_cflow_srcnet : hf_cflow_dstnet, tvb,
726 proto_tree_add_item(pdutree,
728 V8PDU_SPREFIX_METHOD ?
729 hf_cflow_srcmask : hf_cflow_dstmask, tvb,
732 if (verspec == V8PDU_SPREFIX_METHOD
733 || verspec == V8PDU_DPREFIX_METHOD)
735 flow_process_textfield(pdutree, tvb, offset, 1,
737 else if (verspec == V8PDU_TOSSRCPREFIX_METHOD
738 || verspec == V8PDU_TOSDSTPREFIX_METHOD)
739 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
742 proto_tree_add_item(pdutree,
744 V8PDU_SPREFIX_METHOD ? hf_cflow_srcas
745 : hf_cflow_dstas, tvb, offset, 2, FALSE);
748 proto_tree_add_item(pdutree,
750 V8PDU_SPREFIX_METHOD ?
751 hf_cflow_inputint : hf_cflow_outputint,
752 tvb, offset, 2, FALSE);
756 flow_process_textfield(pdutree, tvb, offset, 2,
759 case V8PDU_MATRIX_METHOD:
760 case V8PDU_TOSMATRIX_METHOD:
761 case V8PDU_PREPORTPROTOCOL_METHOD:
762 proto_tree_add_item(pdutree, hf_cflow_srcnet, tvb, offset, 4,
766 proto_tree_add_item(pdutree, hf_cflow_dstnet, tvb, offset, 4,
770 proto_tree_add_item(pdutree, hf_cflow_srcmask, tvb, offset++,
773 proto_tree_add_item(pdutree, hf_cflow_dstmask, tvb, offset++,
776 if (verspec == V8PDU_TOSMATRIX_METHOD ||
777 verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
778 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
780 if (verspec == V8PDU_TOSMATRIX_METHOD) {
782 flow_process_textfield(pdutree, tvb,
785 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
786 proto_tree_add_item(pdutree, hf_cflow_prot,
787 tvb, offset++, 1, FALSE);
791 flow_process_textfield(pdutree, tvb, offset, 2,
795 if (verspec == V8PDU_MATRIX_METHOD
796 || verspec == V8PDU_TOSMATRIX_METHOD) {
797 offset = flow_process_aspair(pdutree, tvb, offset);
798 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
799 offset = flow_process_ports(pdutree, tvb, offset);
802 offset = flow_process_ints(pdutree, tvb, offset);
807 return (offset - startoffset);
810 /* Dissect a version 9 FlowSet and return the length we processed. */
813 dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
821 flowset_id = tvb_get_ntohs(tvb, offset);
822 if (flowset_id == 0) {
824 proto_tree_add_item(pdutree, hf_cflow_template_flowset_id, tvb,
828 length = tvb_get_ntohs(tvb, offset);
829 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
833 dissect_v9_template(pdutree, tvb, offset);
834 } else if (flowset_id == 1) {
836 proto_tree_add_item(pdutree, hf_cflow_options_flowset_id, tvb,
840 length = tvb_get_ntohs(tvb, offset);
841 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
845 dissect_v9_options(pdutree, tvb, offset);
846 } else if (flowset_id >= 2 && flowset_id <= 255) {
848 proto_tree_add_item(pdutree, hf_cflow_flowset_id, tvb,
852 length = tvb_get_ntohs(tvb, offset);
853 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
858 proto_tree_add_item(pdutree, hf_cflow_data_flowset_id, tvb,
862 length = tvb_get_ntohs(tvb, offset);
863 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
868 * The length includes the length of the FlowSet ID and
869 * the length field itself.
873 dissect_v9_data(pdutree, tvb, offset, flowset_id,
882 dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
883 guint16 id, guint length)
885 struct v9_template *template;
886 proto_tree *data_tree;
887 proto_item *data_item;
889 template = v9_template_get(id, 0, 0);
890 if (template != NULL && template->length != 0) {
894 while (length >= template->length) {
895 data_item = proto_tree_add_text(pdutree, tvb,
896 offset, template->length, "pdu %d", count++);
897 data_tree = proto_item_add_subtree(data_item,
900 dissect_v9_pdu(data_tree, tvb, offset, template);
902 offset += template->length;
903 length -= template->length;
906 proto_tree_add_text(pdutree, tvb, offset, length,
907 "Padding (%u byte%s)",
908 length, plurality(length, "", "s"));
911 proto_tree_add_text(pdutree, tvb, offset, length,
912 "Data (%u byte%s), no template found",
913 length, plurality(length, "", "s"));
920 dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
921 struct v9_template * template)
925 for (i = 0; i < template->count; i++) {
928 guint16 type, length;
931 type = template->entries[i].type;
932 length = template->entries[i].length;
937 proto_tree_add_item(pdutree, hf_cflow_octets,
938 tvb, offset, length, FALSE);
939 } else if (length == 8) {
940 proto_tree_add_item(pdutree, hf_cflow_octets64,
941 tvb, offset, length, FALSE);
943 proto_tree_add_text(pdutree,
945 "Octets: length %u", length);
949 case 2: /* packets */
951 proto_tree_add_item(pdutree, hf_cflow_packets,
952 tvb, offset, length, FALSE);
953 } else if (length == 8) {
954 proto_tree_add_item(pdutree, hf_cflow_packets64,
955 tvb, offset, length, FALSE);
957 proto_tree_add_text(pdutree,
959 "Packets: length %u", length);
965 proto_tree_add_item(pdutree, hf_cflow_flows,
966 tvb, offset, length, FALSE);
968 proto_tree_add_text(pdutree,
970 "Flows: length %u", length);
975 proto_tree_add_item(pdutree, hf_cflow_prot,
976 tvb, offset, length, FALSE);
980 proto_tree_add_item(pdutree, hf_cflow_tos,
981 tvb, offset, length, FALSE);
984 case 6: /* TCP flags */
985 proto_tree_add_item(pdutree, hf_cflow_tcpflags,
986 tvb, offset, length, FALSE);
989 case 7: /* source port */
990 proto_tree_add_item(pdutree, hf_cflow_srcport,
991 tvb, offset, length, FALSE);
994 case 8: /* source IP */
996 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
998 proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr,
999 tvb, offset, length, ipv4addr);
1000 } else if (length == 16) {
1001 tvb_memcpy(tvb, ipv6addr, offset,
1003 proto_tree_add_ipv6(pdutree, hf_cflow_srcaddr_v6,
1004 tvb, offset, length, ipv6addr);
1006 proto_tree_add_text(pdutree,
1007 tvb, offset, length,
1008 "SrcAddr: length %u", length);
1012 case 9: /* source mask */
1013 proto_tree_add_item(pdutree, hf_cflow_srcmask,
1014 tvb, offset, length, FALSE);
1017 case 10: /* input SNMP */
1018 proto_tree_add_item(pdutree, hf_cflow_inputint,
1019 tvb, offset, length, FALSE);
1022 case 11: /* dest port */
1023 proto_tree_add_item(pdutree, hf_cflow_dstport,
1024 tvb, offset, length, FALSE);
1027 case 12: /* dest IP */
1029 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
1031 proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr,
1032 tvb, offset, length, ipv4addr);
1033 } else if (length == 16) {
1034 tvb_memcpy(tvb, ipv6addr, offset,
1036 proto_tree_add_ipv6(pdutree, hf_cflow_dstaddr_v6,
1037 tvb, offset, length, ipv6addr);
1039 proto_tree_add_text(pdutree,
1040 tvb, offset, length,
1041 "DstAddr: length %u", length);
1045 case 13: /* dest mask */
1046 proto_tree_add_item(pdutree, hf_cflow_dstmask,
1047 tvb, offset, length, FALSE);
1050 case 14: /* output SNMP */
1051 proto_tree_add_item(pdutree, hf_cflow_outputint,
1052 tvb, offset, length, FALSE);
1055 case 15: /* nexthop IP */
1057 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
1059 proto_tree_add_ipv4(pdutree, hf_cflow_nexthop,
1060 tvb, offset, length, ipv4addr);
1061 } else if (length == 16) {
1062 tvb_memcpy(tvb, ipv6addr, offset,
1064 proto_tree_add_ipv6(pdutree, hf_cflow_nexthop_v6,
1065 tvb, offset, length, ipv6addr);
1067 proto_tree_add_text(pdutree,
1068 tvb, offset, length,
1069 "NextHop: length %u", length);
1073 case 16: /* source AS */
1074 proto_tree_add_item(pdutree, hf_cflow_srcas,
1075 tvb, offset, length, FALSE);
1078 case 17: /* dest AS */
1079 proto_tree_add_item(pdutree, hf_cflow_dstas,
1080 tvb, offset, length, FALSE);
1083 case 18: /* BGP nexthop IP */
1085 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset,
1087 proto_tree_add_ipv4(pdutree, hf_cflow_bgpnexthop,
1088 tvb, offset, length, ipv4addr);
1089 } else if (length == 16) {
1090 tvb_memcpy(tvb, ipv6addr, offset,
1092 proto_tree_add_ipv6(pdutree, hf_cflow_bgpnexthop_v6,
1093 tvb, offset, length, ipv6addr);
1095 proto_tree_add_text(pdutree,
1096 tvb, offset, length,
1097 "BGPNextHop: length %u", length);
1101 case 19: /* multicast packets */
1102 proto_tree_add_item(pdutree, hf_cflow_mulpackets,
1103 tvb, offset, length, FALSE);
1106 case 20: /* multicast octets */
1107 proto_tree_add_item(pdutree, hf_cflow_muloctets,
1108 tvb, offset, length, FALSE);
1111 case 21: /* last switched */
1112 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
1114 proto_tree_add_time(pdutree, hf_cflow_timeend,
1115 tvb, offset, length, &ts);
1118 case 22: /* first switched */
1119 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
1121 proto_tree_add_time(pdutree, hf_cflow_timestart,
1122 tvb, offset, length, &ts);
1125 case 34: /* sampling interval */
1126 proto_tree_add_item(pdutree, hf_cflow_sampling_interval,
1127 tvb, offset, length, FALSE);
1130 case 35: /* sampling algorithm */
1131 proto_tree_add_item(pdutree, hf_cflow_sampling_algorithm,
1132 tvb, offset, length, FALSE);
1135 case 36: /* flow active timeout */
1136 proto_tree_add_item(pdutree, hf_cflow_flow_active_timeout,
1137 tvb, offset, length, FALSE);
1140 case 37: /* flow inactive timeout */
1141 proto_tree_add_item(pdutree, hf_cflow_flow_inactive_timeout,
1142 tvb, offset, length, FALSE);
1145 case 40: /* bytes exported */
1146 proto_tree_add_item(pdutree, hf_cflow_octets_exp,
1147 tvb, offset, length, FALSE);
1150 case 41: /* packets exported */
1151 proto_tree_add_item(pdutree, hf_cflow_packets_exp,
1152 tvb, offset, length, FALSE);
1155 case 42: /* flows exported */
1156 proto_tree_add_item(pdutree, hf_cflow_flows_exp,
1157 tvb, offset, length, FALSE);
1161 proto_tree_add_text(pdutree, tvb, offset, length,
1171 dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb, int offset)
1173 guint16 length, option_scope_len, option_len, i, id, size;
1174 struct v9_template template;
1175 int template_offset;
1177 id = tvb_get_ntohs(tvb, offset);
1178 proto_tree_add_item(pdutree, hf_cflow_template_id, tvb,
1182 option_scope_len = length = tvb_get_ntohs(tvb, offset);
1183 proto_tree_add_item(pdutree, hf_cflow_option_scope_length, tvb,
1187 option_len = length = tvb_get_ntohs(tvb, offset);
1188 proto_tree_add_item(pdutree, hf_cflow_option_length, tvb,
1192 for(i=0; i<option_scope_len; i++) {
1193 length = tvb_get_ntohs(tvb, offset);
1194 proto_tree_add_item(pdutree, hf_cflow_template_scope_field_type, tvb,
1196 offset += 2; i += 2;
1198 length = tvb_get_ntohs(tvb, offset);
1199 proto_tree_add_item(pdutree, hf_cflow_template_scope_field_length, tvb,
1201 offset += 2; i += 2;
1204 template_offset = offset;
1206 for(i=0; i<option_len;) {
1207 length = tvb_get_ntohs(tvb, offset);
1208 proto_tree_add_item(pdutree, hf_cflow_template_field_type, tvb,
1210 offset += 2; i += 2;
1212 length = tvb_get_ntohs(tvb, offset);
1213 proto_tree_add_item(pdutree, hf_cflow_template_field_length, tvb,
1215 offset += 2; i += 2;
1218 /* Cache template */
1219 memset(&template, 0, sizeof(template));
1221 template.count = option_len/4;
1222 template.source_addr = 0; /* XXX */
1223 template.source_id = 0; /* XXX */
1224 template.option_template = 1; /* Option template */
1225 size = template.count * sizeof(struct v9_template_entry);
1226 template.entries = g_malloc(size);
1227 tvb_memcpy(tvb, (guint8 *)template.entries, template_offset, size);
1229 v9_template_add(&template);
1235 dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb, int offset)
1237 struct v9_template template;
1238 proto_tree *template_tree;
1239 proto_item *template_item;
1243 id = tvb_get_ntohs(tvb, offset);
1244 proto_tree_add_item(pdutree, hf_cflow_template_id, tvb,
1248 count = tvb_get_ntohs(tvb, offset);
1249 proto_tree_add_item(pdutree, hf_cflow_template_field_count, tvb,
1253 /* Cache template */
1254 memset(&template, 0, sizeof(template));
1256 template.count = count;
1257 template.source_addr = 0; /* XXX */
1258 template.source_id = 0; /* XXX */
1259 template.option_template = 0; /* Data template */
1260 template.entries = g_malloc(count * sizeof(struct v9_template_entry));
1261 tvb_memcpy(tvb, (guint8 *)template.entries, offset,
1262 count * sizeof(struct v9_template_entry));
1263 v9_template_add(&template);
1265 for (i = 1; i <= count; i++) {
1266 guint16 type, length;
1268 type = tvb_get_ntohs(tvb, offset);
1269 length = tvb_get_ntohs(tvb, offset + 2);
1271 template_item = proto_tree_add_text(pdutree, tvb,
1272 offset, 4, "Field (%u/%u)", i, count);
1273 template_tree = proto_item_add_subtree(template_item, ett_template);
1275 proto_tree_add_item(template_tree,
1276 hf_cflow_template_field_type, tvb, offset, 2, FALSE);
1279 proto_tree_add_item(template_tree,
1280 hf_cflow_template_field_length, tvb, offset, 2, FALSE);
1287 static value_string v9_template_types[] = {
1294 { 7, "L4_SRC_PORT" },
1295 { 8, "IP_SRC_ADDR" },
1297 { 10, "INPUT_SNMP" },
1298 { 11, "L4_DST_PORT" },
1299 { 12, "IP_DST_ADDR" },
1301 { 14, "OUTPUT_SNMP" },
1302 { 15, "IP_NEXT_HOP" },
1305 { 18, "BGP_NEXT_HOP" },
1306 { 19, "MUL_DPKTS" },
1307 { 20, "MUL_DOCTETS" },
1308 { 21, "LAST_SWITCHED" },
1309 { 22, "FIRST_SWITCHED" },
1310 { 27, "IPV6_SRC_ADDR" },
1311 { 28, "IPV6_DST_ADDR" },
1312 { 29, "IPV6_SRC_MASK" },
1313 { 30, "IPV6_DST_MASK" },
1314 { 31, "FLOW_LABEL" },
1315 { 32, "ICMP_TYPE" },
1316 { 33, "IGMP_TYPE" },
1317 { 34, "SAMPLING_INTERVAL" },
1318 { 35, "SAMPLING_ALGORITHM" },
1319 { 36, "FLOW_ACTIVE_TIMEOUT" },
1320 { 37, "FLOW_INACTIVE_TIMEOUT" },
1321 { 38, "ENGINE_TYPE" },
1322 { 39, "ENGINE_ID" },
1324 { 40, "TOTAL_BYTES_EXP" },
1325 { 41, "TOTAL_PKTS_EXP" },
1326 { 42, "TOTAL_FLOWS_EXP" },
1331 { 60, "IP_PROTOCOL_VERSION" },
1332 { 61, "DIRECTION" },
1333 { 62, "IPV6_NEXT_HOP" },
1334 { 63, "BPG_IPV6_NEXT_HOP" },
1335 { 64, "IPV6_OPTION_HEADERS" },
1336 { 70, "MPLS_LABEL_1" },
1337 { 71, "MPLS_LABEL_2" },
1338 { 72, "MPLS_LABEL_3" },
1339 { 73, "MPLS_LABEL_4" },
1340 { 74, "MPLS_LABEL_5" },
1341 { 75, "MPLS_LABEL_6" },
1342 { 76, "MPLS_LABEL_7" },
1343 { 71, "MPLS_LABEL_8" },
1344 { 72, "MPLS_LABEL_9" },
1345 { 72, "MPLS_LABEL_10" },
1349 static value_string v9_scope_field_types[] = {
1353 { 4, "NetFlow Cache" },
1359 v9_template_add(struct v9_template *template)
1363 /* Add up the actual length of the data and store in proper byte order */
1364 template->length = 0;
1365 for (i = 0; i < template->count; i++) {
1366 template->entries[i].type = g_ntohs(template->entries[i].type);
1367 template->entries[i].length = g_ntohs(template->entries[i].length);
1368 template->length += template->entries[i].length;
1371 memmove(&v9_template_cache[template->id % V9TEMPLATE_CACHE_MAX_ENTRIES],
1372 template, sizeof(*template));
1375 static struct v9_template *
1376 v9_template_get(guint16 id, guint32 src_addr, guint32 src_id)
1378 struct v9_template *template;
1381 template = &v9_template_cache[id % V9TEMPLATE_CACHE_MAX_ENTRIES];
1383 if (template->id != id ||
1384 template->source_addr != src_addr ||
1385 template->source_id != src_id) {
1393 * dissect a version 1, 5, or 7 pdu and return the length of the pdu we
1398 dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
1400 int startoffset = offset;
1401 guint32 srcaddr, dstaddr;
1405 memset(&ts, '\0', sizeof(ts));
1408 * memcpy so we can use the values later to calculate a prefix
1410 tvb_memcpy(tvb, (guint8 *) & srcaddr, offset, 4);
1411 proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
1415 tvb_memcpy(tvb, (guint8 *) & dstaddr, offset, 4);
1416 proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr, tvb, offset, 4,
1420 proto_tree_add_item(pdutree, hf_cflow_nexthop, tvb, offset, 4, FALSE);
1423 offset = flow_process_ints(pdutree, tvb, offset);
1424 offset = flow_process_sizecount(pdutree, tvb, offset);
1425 offset = flow_process_timeperiod(pdutree, tvb, offset);
1426 offset = flow_process_ports(pdutree, tvb, offset);
1429 * and the similarities end here
1433 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1435 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1438 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1441 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1445 flow_process_textfield(pdutree, tvb, offset, 3, "padding");
1448 flow_process_textfield(pdutree, tvb, offset, 4,
1453 flow_process_textfield(pdutree, tvb, offset, 1,
1456 proto_tree_add_item(pdutree, hf_cflow_flags, tvb,
1457 offset++, 1, FALSE);
1460 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1463 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1466 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1469 offset = flow_process_aspair(pdutree, tvb, offset);
1471 mask = tvb_get_guint8(tvb, offset);
1472 proto_tree_add_text(pdutree, tvb, offset, 1,
1473 "SrcMask: %u (prefix: %s/%u)",
1474 mask, getprefix(&srcaddr, mask),
1475 mask != 0 ? mask : 32);
1476 proto_tree_add_uint_hidden(pdutree, hf_cflow_srcmask, tvb,
1479 mask = tvb_get_guint8(tvb, offset);
1480 proto_tree_add_text(pdutree, tvb, offset, 1,
1481 "DstMask: %u (prefix: %s/%u)",
1482 mask, getprefix(&dstaddr, mask),
1483 mask != 0 ? mask : 32);
1484 proto_tree_add_uint_hidden(pdutree, hf_cflow_dstmask, tvb,
1488 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1491 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb,
1497 return (offset - startoffset);
1501 getprefix(const guint32 * address, int prefix)
1505 gprefix = *address & g_htonl((0xffffffff << (32 - prefix)));
1507 return (ip_to_str((const guint8 *)&gprefix));
1512 netflow_reinit(void)
1517 * Clear out the template cache.
1518 * Free the table of fields for each entry, and then zero out
1521 for (i = 0; i < V9TEMPLATE_CACHE_MAX_ENTRIES; i++)
1522 g_free(v9_template_cache[i].entries);
1523 memset(v9_template_cache, 0, sizeof v9_template_cache);
1527 proto_register_netflow(void)
1529 static hf_register_info hf[] = {
1534 {"Version", "cflow.version",
1535 FT_UINT16, BASE_DEC, NULL, 0x0,
1536 "NetFlow Version", HFILL}
1539 {"Count", "cflow.count",
1540 FT_UINT16, BASE_DEC, NULL, 0x0,
1541 "Count of PDUs", HFILL}
1543 {&hf_cflow_sysuptime,
1544 {"SysUptime", "cflow.sysuptime",
1545 FT_UINT32, BASE_DEC, NULL, 0x0,
1546 "Time since router booted (in milliseconds)", HFILL}
1549 {&hf_cflow_timestamp,
1550 {"Timestamp", "cflow.timestamp",
1551 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1552 "Current seconds since epoch", HFILL}
1554 {&hf_cflow_unix_secs,
1555 {"CurrentSecs", "cflow.unix_secs",
1556 FT_UINT32, BASE_DEC, NULL, 0x0,
1557 "Current seconds since epoch", HFILL}
1559 {&hf_cflow_unix_nsecs,
1560 {"CurrentNSecs", "cflow.unix_nsecs",
1561 FT_UINT32, BASE_DEC, NULL, 0x0,
1562 "Residual nanoseconds since epoch", HFILL}
1564 {&hf_cflow_samplingmode,
1565 {"SamplingMode", "cflow.samplingmode",
1566 FT_UINT16, BASE_DEC, VALS(v5_sampling_mode), 0xC000,
1567 "Sampling Mode of exporter", HFILL}
1569 {&hf_cflow_samplerate,
1570 {"SampleRate", "cflow.samplerate",
1571 FT_UINT16, BASE_DEC, NULL, 0x3FFF,
1572 "Sample Frequency of exporter", HFILL}
1576 * end version-agnostic header
1577 * version-specific flow header
1579 {&hf_cflow_sequence,
1580 {"FlowSequence", "cflow.sequence",
1581 FT_UINT32, BASE_DEC, NULL, 0x0,
1582 "Sequence number of flows seen", HFILL}
1584 {&hf_cflow_engine_type,
1585 {"EngineType", "cflow.engine_type",
1586 FT_UINT8, BASE_DEC, NULL, 0x0,
1587 "Flow switching engine type", HFILL}
1589 {&hf_cflow_engine_id,
1590 {"EngineId", "cflow.engine_id",
1591 FT_UINT8, BASE_DEC, NULL, 0x0,
1592 "Slot number of switching engine", HFILL}
1594 {&hf_cflow_source_id,
1595 {"SourceId", "cflow.source_id",
1596 FT_UINT32, BASE_DEC, NULL, 0x0,
1597 "Identifier for export device", HFILL}
1599 {&hf_cflow_aggmethod,
1600 {"AggMethod", "cflow.aggmethod",
1601 FT_UINT8, BASE_DEC, VALS(v8_agg), 0x0,
1602 "CFlow V8 Aggregation Method", HFILL}
1604 {&hf_cflow_aggversion,
1605 {"AggVersion", "cflow.aggversion",
1606 FT_UINT8, BASE_DEC, NULL, 0x0,
1607 "CFlow V8 Aggregation Version", HFILL}
1610 * end version specific header storage
1615 {&hf_cflow_flowset_id,
1616 {"FlowSet Id", "cflow.flowset_id",
1617 FT_UINT16, BASE_DEC, NULL, 0x0,
1618 "FlowSet Id", HFILL}
1620 {&hf_cflow_data_flowset_id,
1621 {"Data FlowSet (Template Id)", "cflow.data_flowset_id",
1622 FT_UINT16, BASE_DEC, NULL, 0x0,
1623 "Data FlowSet with corresponding to a template Id", HFILL}
1625 {&hf_cflow_options_flowset_id,
1626 {"Options FlowSet", "cflow.options_flowset_id",
1627 FT_UINT16, BASE_DEC, NULL, 0x0,
1628 "Options FlowSet", HFILL}
1630 {&hf_cflow_template_flowset_id,
1631 {"Template FlowSet", "cflow.template_flowset_id",
1632 FT_UINT16, BASE_DEC, NULL, 0x0,
1633 "Template FlowSet", HFILL}
1635 {&hf_cflow_flowset_length,
1636 {"FlowSet Length", "cflow.flowset_length",
1637 FT_UINT16, BASE_DEC, NULL, 0x0,
1638 "FlowSet length", HFILL}
1640 {&hf_cflow_template_id,
1641 {"Template Id", "cflow.template_id",
1642 FT_UINT16, BASE_DEC, NULL, 0x0,
1643 "Template Id", HFILL}
1645 {&hf_cflow_template_field_count,
1646 {"Field Count", "cflow.template_field_count",
1647 FT_UINT16, BASE_DEC, NULL, 0x0,
1648 "Template field count", HFILL}
1650 {&hf_cflow_template_field_type,
1651 {"Type", "cflow.template_field_type",
1652 FT_UINT16, BASE_DEC, VALS(v9_template_types), 0x0,
1653 "Template field type", HFILL}
1655 {&hf_cflow_template_field_length,
1656 {"Length", "cflow.template_field_length",
1657 FT_UINT16, BASE_DEC, NULL, 0x0,
1658 "Template field length", HFILL}
1662 {&hf_cflow_option_scope_length,
1663 {"Option Scope Length", "cflow.option_scope_length",
1664 FT_UINT16, BASE_DEC, NULL, 0x0,
1665 "Option scope length", HFILL}
1667 {&hf_cflow_option_length,
1668 {"Option Length", "cflow.option_length",
1669 FT_UINT16, BASE_DEC, NULL, 0x0,
1670 "Option length", HFILL}
1672 {&hf_cflow_template_scope_field_type,
1673 {"Scope Type", "cflow.scope_field_type",
1674 FT_UINT16, BASE_DEC, VALS(v9_scope_field_types), 0x0,
1675 "Scope field type", HFILL}
1677 {&hf_cflow_template_scope_field_length,
1678 {"Scope Field Length", "cflow.scope_field_length",
1679 FT_UINT16, BASE_DEC, NULL, 0x0,
1680 "Scope field length", HFILL}
1682 {&hf_cflow_sampling_interval,
1683 {"Sampling interval", "cflow.sampling_interval",
1684 FT_UINT32, BASE_DEC, NULL, 0x0,
1685 "Sampling interval", HFILL}
1687 {&hf_cflow_sampling_algorithm,
1688 {"Sampling algorithm", "cflow.sampling_algorithm",
1689 FT_UINT8, BASE_DEC, NULL, 0x0,
1690 "Sampling algorithm", HFILL}
1692 {&hf_cflow_flow_active_timeout,
1693 {"Flow active timeout", "cflow.flow_active_timeout",
1694 FT_UINT16, BASE_DEC, NULL, 0x0,
1695 "Flow active timeout", HFILL}
1697 {&hf_cflow_flow_inactive_timeout,
1698 {"Flow inactive timeout", "cflow.flow_inactive_timeout",
1699 FT_UINT16, BASE_DEC, NULL, 0x0,
1700 "Flow inactive timeout", HFILL}
1704 * begin pdu content storage
1707 {"SrcAddr", "cflow.srcaddr",
1708 FT_IPv4, BASE_NONE, NULL, 0x0,
1709 "Flow Source Address", HFILL}
1711 {&hf_cflow_srcaddr_v6,
1712 {"SrcAddr", "cflow.srcaddrv6",
1713 FT_IPv6, BASE_NONE, NULL, 0x0,
1714 "Flow Source Address", HFILL}
1717 {"SrcNet", "cflow.srcnet",
1718 FT_IPv4, BASE_NONE, NULL, 0x0,
1719 "Flow Source Network", HFILL}
1722 {"DstAddr", "cflow.dstaddr",
1723 FT_IPv4, BASE_NONE, NULL, 0x0,
1724 "Flow Destination Address", HFILL}
1726 {&hf_cflow_dstaddr_v6,
1727 {"DstAddr", "cflow.dstaddrv6",
1728 FT_IPv6, BASE_NONE, NULL, 0x0,
1729 "Flow Destination Address", HFILL}
1732 {"DstNet", "cflow.dstaddr",
1733 FT_IPv4, BASE_NONE, NULL, 0x0,
1734 "Flow Destination Network", HFILL}
1737 {"NextHop", "cflow.nexthop",
1738 FT_IPv4, BASE_NONE, NULL, 0x0,
1739 "Router nexthop", HFILL}
1741 {&hf_cflow_nexthop_v6,
1742 {"NextHop", "cflow.nexthopv6",
1743 FT_IPv6, BASE_NONE, NULL, 0x0,
1744 "Router nexthop", HFILL}
1746 {&hf_cflow_bgpnexthop,
1747 {"BGPNextHop", "cflow.bgpnexthop",
1748 FT_IPv4, BASE_NONE, NULL, 0x0,
1749 "BGP Router Nexthop", HFILL}
1751 {&hf_cflow_bgpnexthop_v6,
1752 {"BGPNextHop", "cflow.bgpnexthopv6",
1753 FT_IPv6, BASE_NONE, NULL, 0x0,
1754 "BGP Router Nexthop", HFILL}
1756 {&hf_cflow_inputint,
1757 {"InputInt", "cflow.inputint",
1758 FT_UINT16, BASE_DEC, NULL, 0x0,
1759 "Flow Input Interface", HFILL}
1761 {&hf_cflow_outputint,
1762 {"OutputInt", "cflow.outputint",
1763 FT_UINT16, BASE_DEC, NULL, 0x0,
1764 "Flow Output Interface", HFILL}
1767 {"Flows", "cflow.flows",
1768 FT_UINT32, BASE_DEC, NULL, 0x0,
1769 "Flows Aggregated in PDU", HFILL}
1772 {"Packets", "cflow.packets",
1773 FT_UINT32, BASE_DEC, NULL, 0x0,
1774 "Count of packets", HFILL}
1776 {&hf_cflow_packets64,
1777 {"Packets", "cflow.packets64",
1778 FT_UINT64, BASE_DEC, NULL, 0x0,
1779 "Count of packets", HFILL}
1781 {&hf_cflow_packetsout,
1782 {"PacketsOut", "cflow.packetsout",
1783 FT_UINT64, BASE_DEC, NULL, 0x0,
1784 "Count of packets going out", HFILL}
1787 {"Octets", "cflow.octets",
1788 FT_UINT32, BASE_DEC, NULL, 0x0,
1789 "Count of bytes", HFILL}
1791 {&hf_cflow_octets64,
1792 {"Octets", "cflow.octets64",
1793 FT_UINT64, BASE_DEC, NULL, 0x0,
1794 "Count of bytes", HFILL}
1796 {&hf_cflow_timestart,
1797 {"StartTime", "cflow.timestart",
1798 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1799 "Uptime at start of flow", HFILL}
1802 {"EndTime", "cflow.timeend",
1803 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1804 "Uptime at end of flow", HFILL}
1807 {"SrcPort", "cflow.srcport",
1808 FT_UINT16, BASE_DEC, NULL, 0x0,
1809 "Flow Source Port", HFILL}
1812 {"DstPort", "cflow.dstport",
1813 FT_UINT16, BASE_DEC, NULL, 0x0,
1814 "Flow Destination Port", HFILL}
1817 {"Protocol", "cflow.protocol",
1818 FT_UINT8, BASE_DEC, NULL, 0x0,
1819 "IP Protocol", HFILL}
1822 {"IP ToS", "cflow.tos",
1823 FT_UINT8, BASE_HEX, NULL, 0x0,
1824 "IP Type of Service", HFILL}
1827 {"Export Flags", "cflow.flags",
1828 FT_UINT8, BASE_HEX, NULL, 0x0,
1829 "CFlow Flags", HFILL}
1831 {&hf_cflow_tcpflags,
1832 {"TCP Flags", "cflow.tcpflags",
1833 FT_UINT8, BASE_HEX, NULL, 0x0,
1837 {"SrcAS", "cflow.srcas",
1838 FT_UINT16, BASE_DEC, NULL, 0x0,
1842 {"DstAS", "cflow.dstas",
1843 FT_UINT16, BASE_DEC, NULL, 0x0,
1844 "Destination AS", HFILL}
1847 {"SrcMask", "cflow.srcmask",
1848 FT_UINT8, BASE_DEC, NULL, 0x0,
1849 "Source Prefix Mask", HFILL}
1852 {"DstMask", "cflow.dstmask",
1853 FT_UINT8, BASE_DEC, NULL, 0x0,
1854 "Destination Prefix Mask", HFILL}
1856 {&hf_cflow_routersc,
1857 {"Router Shortcut", "cflow.routersc",
1858 FT_IPv4, BASE_NONE, NULL, 0x0,
1859 "Router shortcut by switch", HFILL}
1861 {&hf_cflow_mulpackets,
1862 {"MulticastPackets", "cflow.mulpackets",
1863 FT_UINT32, BASE_DEC, NULL, 0x0,
1864 "Count of multicast packets", HFILL}
1866 {&hf_cflow_muloctets,
1867 {"MulticastOctets", "cflow.muloctets",
1868 FT_UINT32, BASE_DEC, NULL, 0x0,
1869 "Count of multicast octets", HFILL}
1871 {&hf_cflow_octets_exp,
1872 {"OctetsExp", "cflow.octetsexp",
1873 FT_UINT32, BASE_DEC, NULL, 0x0,
1874 "Octets exported", HFILL}
1876 {&hf_cflow_packets_exp,
1877 {"PacketsExp", "cflow.packetsexp",
1878 FT_UINT32, BASE_DEC, NULL, 0x0,
1879 "Packets exported", HFILL}
1881 {&hf_cflow_flows_exp,
1882 {"FlowsExp", "cflow.flowsexp",
1883 FT_UINT32, BASE_DEC, NULL, 0x0,
1884 "Flows exported", HFILL}
1887 * end pdu content storage
1891 static gint *ett[] = {
1899 module_t *netflow_module;
1901 proto_netflow = proto_register_protocol("Cisco NetFlow", "CFLOW",
1904 proto_register_field_array(proto_netflow, hf, array_length(hf));
1905 proto_register_subtree_array(ett, array_length(ett));
1907 /* Register our configuration options for NetFlow */
1908 netflow_module = prefs_register_protocol(proto_netflow,
1909 proto_reg_handoff_netflow);
1911 prefs_register_uint_preference(netflow_module, "udp.port",
1912 "NetFlow UDP Port", "Set the port for NetFlow messages",
1913 10, &global_netflow_udp_port);
1915 register_init_routine(&netflow_reinit);
1920 * protocol/port association
1923 proto_reg_handoff_netflow(void)
1925 static int netflow_prefs_initialized = FALSE;
1926 static dissector_handle_t netflow_handle;
1928 if (!netflow_prefs_initialized) {
1929 netflow_handle = create_dissector_handle(dissect_netflow,
1931 netflow_prefs_initialized = TRUE;
1933 dissector_delete("udp.port", netflow_udp_port, netflow_handle);
1936 /* Set out port number for future use */
1937 netflow_udp_port = global_netflow_udp_port;
1939 dissector_add("udp.port", netflow_udp_port, netflow_handle);