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 * wireshark 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_field = -1;
162 static int ett_dataflowset = -1;
168 static int hf_cflow_version = -1;
169 static int hf_cflow_count = -1;
170 static int hf_cflow_sysuptime = -1;
171 static int hf_cflow_unix_secs = -1;
172 static int hf_cflow_unix_nsecs = -1;
173 static int hf_cflow_timestamp = -1;
174 static int hf_cflow_samplingmode = -1;
175 static int hf_cflow_samplerate = -1;
178 * cflow version specific info
180 static int hf_cflow_sequence = -1;
181 static int hf_cflow_engine_type = -1;
182 static int hf_cflow_engine_id = -1;
183 static int hf_cflow_source_id = -1;
185 static int hf_cflow_aggmethod = -1;
186 static int hf_cflow_aggversion = -1;
190 static int hf_cflow_template_flowset_id = -1;
191 static int hf_cflow_data_flowset_id = -1;
192 static int hf_cflow_options_flowset_id = -1;
193 static int hf_cflow_flowset_id = -1;
194 static int hf_cflow_flowset_length = -1;
195 static int hf_cflow_template_id = -1;
196 static int hf_cflow_template_field_count = -1;
197 static int hf_cflow_template_field_type = -1;
198 static int hf_cflow_template_field_length = -1;
199 static int hf_cflow_option_scope_length = -1;
200 static int hf_cflow_option_length = -1;
201 static int hf_cflow_template_scope_field_type = -1;
202 static int hf_cflow_template_scope_field_length = -1;
208 static int hf_cflow_srcaddr = -1;
209 static int hf_cflow_srcaddr_v6 = -1;
210 static int hf_cflow_srcnet = -1;
211 static int hf_cflow_dstaddr = -1;
212 static int hf_cflow_dstaddr_v6 = -1;
213 static int hf_cflow_dstnet = -1;
214 static int hf_cflow_nexthop = -1;
215 static int hf_cflow_nexthop_v6 = -1;
216 static int hf_cflow_bgpnexthop = -1;
217 static int hf_cflow_bgpnexthop_v6 = -1;
218 static int hf_cflow_inputint = -1;
219 static int hf_cflow_outputint = -1;
220 static int hf_cflow_flows = -1;
221 static int hf_cflow_packets = -1;
222 static int hf_cflow_packets64 = -1;
223 static int hf_cflow_packetsout = -1;
224 static int hf_cflow_octets = -1;
225 static int hf_cflow_octets64 = -1;
226 static int hf_cflow_timestart = -1;
227 static int hf_cflow_timeend = -1;
228 static int hf_cflow_srcport = -1;
229 static int hf_cflow_dstport = -1;
230 static int hf_cflow_prot = -1;
231 static int hf_cflow_tos = -1;
232 static int hf_cflow_flags = -1;
233 static int hf_cflow_tcpflags = -1;
234 static int hf_cflow_dstas = -1;
235 static int hf_cflow_srcas = -1;
236 static int hf_cflow_dstmask = -1;
237 static int hf_cflow_srcmask = -1;
238 static int hf_cflow_routersc = -1;
239 static int hf_cflow_mulpackets = -1;
240 static int hf_cflow_muloctets = -1;
241 static int hf_cflow_octets_exp = -1;
242 static int hf_cflow_packets_exp = -1;
243 static int hf_cflow_flows_exp = -1;
244 static int hf_cflow_sampling_interval = -1;
245 static int hf_cflow_sampling_algorithm = -1;
246 static int hf_cflow_flow_active_timeout = -1;
247 static int hf_cflow_flow_inactive_timeout = -1;
248 static int hf_cflow_mpls_top_label_type = -1;
249 static int hf_cflow_mpls_pe_addr = -1;
250 const value_string special_mpls_top_label_type[] = {
262 proto_tree_add_mpls_label(proto_tree * pdutree, tvbuff_t * tvb, int offset, int length, int level)
265 guint8 b0 = tvb_get_guint8(tvb, offset);
266 guint8 b1 = tvb_get_guint8(tvb, offset + 1);
267 guint8 b2 = tvb_get_guint8(tvb, offset + 2);
268 proto_tree_add_text(pdutree, tvb, offset, length,
269 "MPLS-Label%d: %u exp-bits: %u %s", level,
270 ((b0<<12)+(b1<<4)+(b2>>4)),
272 ((b2&0x1)?"top-of-stack":""));
274 proto_tree_add_text(pdutree, tvb, offset, length,
275 "MPLS-Label%d: bad lengh %d", level, length);
279 void proto_reg_handoff_netflow(void);
281 typedef int dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
283 static int dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
285 static int dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
286 int offset, int verspec);
287 static int dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
288 int offset, int verspec);
289 static int dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb,
290 int offset, int verspec);
291 static int dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb,
292 int offset, guint16 id, guint length);
293 static void dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb,
294 int offset, struct v9_template * template);
295 static int dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb,
297 static int dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb,
298 int offset, int len);
299 static void v9_template_add(struct v9_template * template);
300 static struct v9_template *v9_template_get(guint16 id, guint32 src_addr,
303 static gchar *getprefix(const guint32 * address, int prefix);
304 static void dissect_netflow(tvbuff_t * tvb, packet_info * pinfo,
307 static int flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb,
309 static int flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb,
311 static int flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb,
313 static int flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb,
315 static int flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb,
317 static int flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb,
318 int offset, int bytes,
323 dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
325 proto_tree *netflow_tree = NULL;
327 proto_item *timeitem, *pduitem;
328 proto_tree *timetree, *pdutree;
329 unsigned int pduret, ver = 0, pdus = 0, x = 1, vspec;
330 size_t available, pdusize, offset = 0;
332 dissect_pdu_t *pduptr;
334 if (check_col(pinfo->cinfo, COL_PROTOCOL))
335 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFLOW");
336 if (check_col(pinfo->cinfo, COL_INFO))
337 col_clear(pinfo->cinfo, COL_INFO);
340 ti = proto_tree_add_item(tree, proto_netflow, tvb,
342 netflow_tree = proto_item_add_subtree(ti, ett_netflow);
345 ver = tvb_get_ntohs(tvb, offset);
349 pdusize = V1PDU_SIZE;
350 pduptr = &dissect_pdu;
353 pdusize = V5PDU_SIZE;
354 pduptr = &dissect_pdu;
357 pdusize = V7PDU_SIZE;
358 pduptr = &dissect_pdu;
361 pdusize = -1; /* deferred */
362 pduptr = &dissect_v8_aggpdu;
365 pdusize = -1; /* deferred */
366 pduptr = &dissect_v9_flowset;
373 proto_tree_add_uint(netflow_tree, hf_cflow_version, tvb,
377 pdus = tvb_get_ntohs(tvb, offset);
381 proto_tree_add_uint(netflow_tree, hf_cflow_count, tvb,
386 * set something interesting in the display now that we have info
388 if (check_col(pinfo->cinfo, COL_INFO)) {
390 col_add_fstr(pinfo->cinfo, COL_INFO,
391 "total: %u (v%u) record%s", pdus, ver,
392 plurality(pdus, "", "s"));
394 col_add_fstr(pinfo->cinfo, COL_INFO,
395 "total: %u (v%u) flow%s", pdus, ver,
396 plurality(pdus, "", "s"));
401 * the rest is only interesting if we're displaying/searching the
407 proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb,
411 ts.secs = tvb_get_ntohl(tvb, offset);
413 ts.nsecs = tvb_get_ntohl(tvb, offset + 4);
414 timeitem = proto_tree_add_time(netflow_tree,
415 hf_cflow_timestamp, tvb, offset,
419 timeitem = proto_tree_add_time(netflow_tree,
420 hf_cflow_timestamp, tvb, offset,
424 timetree = proto_item_add_subtree(timeitem, ett_unixtime);
426 proto_tree_add_item(timetree, hf_cflow_unix_secs, tvb,
431 proto_tree_add_item(timetree, hf_cflow_unix_nsecs, tvb,
437 * version specific header
439 if (ver == 5 || ver == 7 || ver == 8 || ver == 9) {
440 proto_tree_add_item(netflow_tree, hf_cflow_sequence,
441 tvb, offset, 4, FALSE);
444 if (ver == 5 || ver == 8) {
445 proto_tree_add_item(netflow_tree, hf_cflow_engine_type,
446 tvb, offset++, 1, FALSE);
447 proto_tree_add_item(netflow_tree, hf_cflow_engine_id,
448 tvb, offset++, 1, FALSE);
449 } else if (ver == 9) {
450 proto_tree_add_item(netflow_tree, hf_cflow_source_id,
451 tvb, offset, 4, FALSE);
455 vspec = tvb_get_guint8(tvb, offset);
457 case V8PDU_AS_METHOD:
458 pdusize = V8PDU_AS_SIZE;
460 case V8PDU_PROTO_METHOD:
461 pdusize = V8PDU_PROTO_SIZE;
463 case V8PDU_SPREFIX_METHOD:
464 pdusize = V8PDU_SPREFIX_SIZE;
466 case V8PDU_DPREFIX_METHOD:
467 pdusize = V8PDU_DPREFIX_SIZE;
469 case V8PDU_MATRIX_METHOD:
470 pdusize = V8PDU_MATRIX_SIZE;
472 case V8PDU_DESTONLY_METHOD:
473 pdusize = V8PDU_DESTONLY_SIZE;
474 pduptr = &dissect_v8_flowpdu;
476 case V8PDU_SRCDEST_METHOD:
477 pdusize = V8PDU_SRCDEST_SIZE;
478 pduptr = &dissect_v8_flowpdu;
480 case V8PDU_FULL_METHOD:
481 pdusize = V8PDU_FULL_SIZE;
482 pduptr = &dissect_v8_flowpdu;
484 case V8PDU_TOSAS_METHOD:
485 pdusize = V8PDU_TOSAS_SIZE;
487 case V8PDU_TOSPROTOPORT_METHOD:
488 pdusize = V8PDU_TOSPROTOPORT_SIZE;
490 case V8PDU_TOSSRCPREFIX_METHOD:
491 pdusize = V8PDU_TOSSRCPREFIX_SIZE;
493 case V8PDU_TOSDSTPREFIX_METHOD:
494 pdusize = V8PDU_TOSDSTPREFIX_SIZE;
496 case V8PDU_TOSMATRIX_METHOD:
497 pdusize = V8PDU_TOSMATRIX_SIZE;
499 case V8PDU_PREPORTPROTOCOL_METHOD:
500 pdusize = V8PDU_PREPORTPROTOCOL_SIZE;
507 proto_tree_add_uint(netflow_tree, hf_cflow_aggmethod,
508 tvb, offset++, 1, vspec);
509 proto_tree_add_item(netflow_tree, hf_cflow_aggversion,
510 tvb, offset++, 1, FALSE);
512 if (ver == 7 || ver == 8)
513 offset = flow_process_textfield(netflow_tree, tvb, offset, 4,
516 proto_tree_add_item(netflow_tree, hf_cflow_samplingmode,
517 tvb, offset, 2, FALSE);
518 proto_tree_add_item(netflow_tree, hf_cflow_samplerate,
519 tvb, offset, 2, FALSE);
524 * everything below here should be payload
526 for (x = 1; x < pdus + 1; x++) {
528 * make sure we have a pdu's worth of data
530 available = tvb_length_remaining(tvb, offset);
531 if (ver == 9 && available >= 4) {
532 /* pdusize can be different for each v9 flowset */
533 pdusize = tvb_get_ntohs(tvb, offset + 2);
536 if (available < pdusize)
540 pduitem = proto_tree_add_text(netflow_tree, tvb,
541 offset, pdusize, "FlowSet %u", x);
543 pduitem = proto_tree_add_text(netflow_tree, tvb,
544 offset, pdusize, "pdu %u/%u", x, pdus);
546 pdutree = proto_item_add_subtree(pduitem, ett_flow);
548 pduret = pduptr(pdutree, tvb, offset, vspec);
550 if (pduret < pdusize) pduret = pdusize; /* padding */
553 * if we came up short, stop processing
555 if (pduret == pdusize)
563 * flow_process_* == common groups of fields, probably could be inline
567 flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb, int offset)
569 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, FALSE);
572 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
580 flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb, int offset)
582 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2, FALSE);
585 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE);
592 flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb, int offset)
597 msec = tvb_get_ntohl(tvb, offset);
598 ts.secs = msec / 1000;
599 ts.nsecs = (msec % 1000) * 1000000;
600 proto_tree_add_time(pdutree, hf_cflow_timestart, tvb, offset, 4, &ts);
603 msec = tvb_get_ntohl(tvb, offset);
604 ts.secs = msec / 1000;
605 ts.nsecs = (msec % 1000) * 1000000;
606 proto_tree_add_time(pdutree, hf_cflow_timeend, tvb, offset, 4, &ts);
614 flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb, int offset)
616 proto_tree_add_item(pdutree, hf_cflow_srcas, tvb, offset, 2, FALSE);
619 proto_tree_add_item(pdutree, hf_cflow_dstas, tvb, offset, 2, FALSE);
626 flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb, int offset)
628 proto_tree_add_item(pdutree, hf_cflow_packets, tvb, offset, 4, FALSE);
631 proto_tree_add_item(pdutree, hf_cflow_octets, tvb, offset, 4, FALSE);
638 flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
639 int bytes, const char *text)
641 proto_tree_add_text(pdutree, tvb, offset, bytes, text);
648 dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
651 int startoffset = offset;
653 proto_tree_add_item(pdutree, hf_cflow_dstaddr, tvb, offset, 4, FALSE);
656 if (verspec != V8PDU_DESTONLY_METHOD) {
657 proto_tree_add_item(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
661 if (verspec == V8PDU_FULL_METHOD) {
662 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2,
665 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2,
670 offset = flow_process_sizecount(pdutree, tvb, offset);
671 offset = flow_process_timeperiod(pdutree, tvb, offset);
673 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
677 if (verspec != V8PDU_DESTONLY_METHOD) {
678 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2,
683 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1, FALSE);
684 if (verspec == V8PDU_FULL_METHOD)
685 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
687 offset = flow_process_textfield(pdutree, tvb, offset, 1, "marked tos");
689 if (verspec == V8PDU_SRCDEST_METHOD)
691 flow_process_textfield(pdutree, tvb, offset, 2,
693 else if (verspec == V8PDU_FULL_METHOD)
695 flow_process_textfield(pdutree, tvb, offset, 1, "padding");
698 flow_process_textfield(pdutree, tvb, offset, 4, "extra packets");
700 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE);
703 return (offset - startoffset);
707 * dissect a version 8 pdu, returning the length of the pdu processed
711 dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
714 int startoffset = offset;
716 proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE);
719 offset = flow_process_sizecount(pdutree, tvb, offset);
720 offset = flow_process_timeperiod(pdutree, tvb, offset);
723 case V8PDU_AS_METHOD:
724 case V8PDU_TOSAS_METHOD:
725 offset = flow_process_aspair(pdutree, tvb, offset);
727 if (verspec == V8PDU_TOSAS_METHOD) {
728 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
731 flow_process_textfield(pdutree, tvb, offset, 1,
734 flow_process_textfield(pdutree, tvb, offset, 2,
738 case V8PDU_PROTO_METHOD:
739 case V8PDU_TOSPROTOPORT_METHOD:
740 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
743 if (verspec == V8PDU_PROTO_METHOD)
745 flow_process_textfield(pdutree, tvb, offset, 1,
747 else if (verspec == V8PDU_TOSPROTOPORT_METHOD)
748 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
752 flow_process_textfield(pdutree, tvb, offset, 2,
754 offset = flow_process_ports(pdutree, tvb, offset);
756 if (verspec == V8PDU_TOSPROTOPORT_METHOD)
757 offset = flow_process_ints(pdutree, tvb, offset);
759 case V8PDU_SPREFIX_METHOD:
760 case V8PDU_DPREFIX_METHOD:
761 case V8PDU_TOSSRCPREFIX_METHOD:
762 case V8PDU_TOSDSTPREFIX_METHOD:
763 proto_tree_add_item(pdutree,
765 V8PDU_SPREFIX_METHOD ?
766 hf_cflow_srcnet : hf_cflow_dstnet, tvb,
770 proto_tree_add_item(pdutree,
772 V8PDU_SPREFIX_METHOD ?
773 hf_cflow_srcmask : hf_cflow_dstmask, tvb,
776 if (verspec == V8PDU_SPREFIX_METHOD
777 || verspec == V8PDU_DPREFIX_METHOD)
779 flow_process_textfield(pdutree, tvb, offset, 1,
781 else if (verspec == V8PDU_TOSSRCPREFIX_METHOD
782 || verspec == V8PDU_TOSDSTPREFIX_METHOD)
783 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
786 proto_tree_add_item(pdutree,
788 V8PDU_SPREFIX_METHOD ? hf_cflow_srcas
789 : hf_cflow_dstas, tvb, offset, 2, FALSE);
792 proto_tree_add_item(pdutree,
794 V8PDU_SPREFIX_METHOD ?
795 hf_cflow_inputint : hf_cflow_outputint,
796 tvb, offset, 2, FALSE);
800 flow_process_textfield(pdutree, tvb, offset, 2,
803 case V8PDU_MATRIX_METHOD:
804 case V8PDU_TOSMATRIX_METHOD:
805 case V8PDU_PREPORTPROTOCOL_METHOD:
806 proto_tree_add_item(pdutree, hf_cflow_srcnet, tvb, offset, 4,
810 proto_tree_add_item(pdutree, hf_cflow_dstnet, tvb, offset, 4,
814 proto_tree_add_item(pdutree, hf_cflow_srcmask, tvb, offset++,
817 proto_tree_add_item(pdutree, hf_cflow_dstmask, tvb, offset++,
820 if (verspec == V8PDU_TOSMATRIX_METHOD ||
821 verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
822 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
824 if (verspec == V8PDU_TOSMATRIX_METHOD) {
826 flow_process_textfield(pdutree, tvb,
829 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
830 proto_tree_add_item(pdutree, hf_cflow_prot,
831 tvb, offset++, 1, FALSE);
835 flow_process_textfield(pdutree, tvb, offset, 2,
839 if (verspec == V8PDU_MATRIX_METHOD
840 || verspec == V8PDU_TOSMATRIX_METHOD) {
841 offset = flow_process_aspair(pdutree, tvb, offset);
842 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
843 offset = flow_process_ports(pdutree, tvb, offset);
846 offset = flow_process_ints(pdutree, tvb, offset);
851 return (offset - startoffset);
854 /* Dissect a version 9 FlowSet and return the length we processed. */
857 dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
865 flowset_id = tvb_get_ntohs(tvb, offset);
866 if (flowset_id == 0) {
868 proto_tree_add_item(pdutree, hf_cflow_template_flowset_id, tvb,
872 length = tvb_get_ntohs(tvb, offset);
873 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
877 dissect_v9_template(pdutree, tvb, offset, length - 4);
878 } else if (flowset_id == 1) {
880 proto_tree_add_item(pdutree, hf_cflow_options_flowset_id, tvb,
884 length = tvb_get_ntohs(tvb, offset);
885 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
889 dissect_v9_options(pdutree, tvb, offset);
890 } else if (flowset_id >= 2 && flowset_id <= 255) {
892 proto_tree_add_item(pdutree, hf_cflow_flowset_id, tvb,
896 length = tvb_get_ntohs(tvb, offset);
897 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
902 proto_tree_add_item(pdutree, hf_cflow_data_flowset_id, tvb,
906 length = tvb_get_ntohs(tvb, offset);
907 proto_tree_add_item(pdutree, hf_cflow_flowset_length, tvb,
912 * The length includes the length of the FlowSet ID and
913 * the length field itself.
917 dissect_v9_data(pdutree, tvb, offset, flowset_id,
926 dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
927 guint16 id, guint length)
929 struct v9_template *template;
930 proto_tree *data_tree;
931 proto_item *data_item;
933 template = v9_template_get(id, 0, 0);
934 if (template != NULL && template->length != 0) {
938 while (length >= template->length) {
939 data_item = proto_tree_add_text(pdutree, tvb,
940 offset, template->length, "pdu %d", count++);
941 data_tree = proto_item_add_subtree(data_item,
944 dissect_v9_pdu(data_tree, tvb, offset, template);
946 offset += template->length;
947 length -= template->length;
950 proto_tree_add_text(pdutree, tvb, offset, length,
951 "Padding (%u byte%s)",
952 length, plurality(length, "", "s"));
955 proto_tree_add_text(pdutree, tvb, offset, length,
956 "Data (%u byte%s), no template found",
957 length, plurality(length, "", "s"));
964 dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
965 struct v9_template * template)
969 for (i = 0; i < template->count; i++) {
970 guint16 type, length;
974 type = template->entries[i].type;
975 length = template->entries[i].length;
980 proto_tree_add_item(pdutree, hf_cflow_octets,
981 tvb, offset, length, FALSE);
982 } else if (length == 8) {
983 proto_tree_add_item(pdutree, hf_cflow_octets64,
984 tvb, offset, length, FALSE);
986 proto_tree_add_text(pdutree,
988 "Octets: length %u", length);
992 case 2: /* packets */
994 proto_tree_add_item(pdutree, hf_cflow_packets,
995 tvb, offset, length, FALSE);
996 } else if (length == 8) {
997 proto_tree_add_item(pdutree, hf_cflow_packets64,
998 tvb, offset, length, FALSE);
1000 proto_tree_add_text(pdutree,
1001 tvb, offset, length,
1002 "Packets: length %u", length);
1008 proto_tree_add_item(pdutree, hf_cflow_flows,
1009 tvb, offset, length, FALSE);
1011 proto_tree_add_text(pdutree,
1012 tvb, offset, length,
1013 "Flows: length %u", length);
1018 proto_tree_add_item(pdutree, hf_cflow_prot,
1019 tvb, offset, length, FALSE);
1023 proto_tree_add_item(pdutree, hf_cflow_tos,
1024 tvb, offset, length, FALSE);
1027 case 6: /* TCP flags */
1028 proto_tree_add_item(pdutree, hf_cflow_tcpflags,
1029 tvb, offset, length, FALSE);
1032 case 7: /* source port */
1033 proto_tree_add_item(pdutree, hf_cflow_srcport,
1034 tvb, offset, length, FALSE);
1037 case 8: /* source IP */
1039 proto_tree_add_item(pdutree, hf_cflow_srcaddr,
1040 tvb, offset, length, FALSE);
1041 } else if (length == 16) {
1042 proto_tree_add_item(pdutree, hf_cflow_srcaddr_v6,
1043 tvb, offset, length, FALSE);
1045 proto_tree_add_text(pdutree,
1046 tvb, offset, length,
1047 "SrcAddr: length %u", length);
1051 case 9: /* source mask */
1052 proto_tree_add_item(pdutree, hf_cflow_srcmask,
1053 tvb, offset, length, FALSE);
1056 case 10: /* input SNMP */
1057 proto_tree_add_item(pdutree, hf_cflow_inputint,
1058 tvb, offset, length, FALSE);
1061 case 11: /* dest port */
1062 proto_tree_add_item(pdutree, hf_cflow_dstport,
1063 tvb, offset, length, FALSE);
1066 case 12: /* dest IP */
1068 proto_tree_add_item(pdutree, hf_cflow_dstaddr,
1069 tvb, offset, length, FALSE);
1070 } else if (length == 16) {
1071 proto_tree_add_item(pdutree, hf_cflow_dstaddr_v6,
1072 tvb, offset, length, FALSE);
1074 proto_tree_add_text(pdutree,
1075 tvb, offset, length,
1076 "DstAddr: length %u", length);
1080 case 13: /* dest mask */
1081 proto_tree_add_item(pdutree, hf_cflow_dstmask,
1082 tvb, offset, length, FALSE);
1085 case 14: /* output SNMP */
1086 proto_tree_add_item(pdutree, hf_cflow_outputint,
1087 tvb, offset, length, FALSE);
1090 case 15: /* nexthop IP */
1092 proto_tree_add_item(pdutree, hf_cflow_nexthop,
1093 tvb, offset, length, FALSE);
1094 } else if (length == 16) {
1095 proto_tree_add_item(pdutree, hf_cflow_nexthop_v6,
1096 tvb, offset, length, FALSE);
1098 proto_tree_add_text(pdutree,
1099 tvb, offset, length,
1100 "NextHop: length %u", length);
1104 case 16: /* source AS */
1105 proto_tree_add_item(pdutree, hf_cflow_srcas,
1106 tvb, offset, length, FALSE);
1109 case 17: /* dest AS */
1110 proto_tree_add_item(pdutree, hf_cflow_dstas,
1111 tvb, offset, length, FALSE);
1114 case 18: /* BGP nexthop IP */
1116 proto_tree_add_item(pdutree, hf_cflow_bgpnexthop,
1117 tvb, offset, length, FALSE);
1118 } else if (length == 16) {
1119 proto_tree_add_item(pdutree, hf_cflow_bgpnexthop_v6,
1120 tvb, offset, length, FALSE);
1122 proto_tree_add_text(pdutree,
1123 tvb, offset, length,
1124 "BGPNextHop: length %u", length);
1128 case 19: /* multicast packets */
1129 proto_tree_add_item(pdutree, hf_cflow_mulpackets,
1130 tvb, offset, length, FALSE);
1133 case 20: /* multicast octets */
1134 proto_tree_add_item(pdutree, hf_cflow_muloctets,
1135 tvb, offset, length, FALSE);
1138 case 21: /* last switched */
1139 msec = tvb_get_ntohl(tvb, offset);
1140 ts.secs = msec / 1000;
1141 ts.nsecs = (msec % 1000) * 1000000;
1142 proto_tree_add_time(pdutree, hf_cflow_timeend,
1143 tvb, offset, length, &ts);
1146 case 22: /* first switched */
1147 msec = tvb_get_ntohl(tvb, offset);
1148 ts.secs = msec / 1000;
1149 ts.nsecs = (msec % 1000) * 1000000;
1150 proto_tree_add_time(pdutree, hf_cflow_timestart,
1151 tvb, offset, length, &ts);
1154 case 34: /* sampling interval */
1155 proto_tree_add_item(pdutree, hf_cflow_sampling_interval,
1156 tvb, offset, length, FALSE);
1159 case 35: /* sampling algorithm */
1160 proto_tree_add_item(pdutree, hf_cflow_sampling_algorithm,
1161 tvb, offset, length, FALSE);
1164 case 36: /* flow active timeout */
1165 proto_tree_add_item(pdutree, hf_cflow_flow_active_timeout,
1166 tvb, offset, length, FALSE);
1169 case 37: /* flow inactive timeout */
1170 proto_tree_add_item(pdutree, hf_cflow_flow_inactive_timeout,
1171 tvb, offset, length, FALSE);
1174 case 40: /* bytes exported */
1175 proto_tree_add_item(pdutree, hf_cflow_octets_exp,
1176 tvb, offset, length, FALSE);
1179 case 41: /* packets exported */
1180 proto_tree_add_item(pdutree, hf_cflow_packets_exp,
1181 tvb, offset, length, FALSE);
1184 case 42: /* flows exported */
1185 proto_tree_add_item(pdutree, hf_cflow_flows_exp,
1186 tvb, offset, length, FALSE);
1189 case 46: /* top MPLS label type*/
1190 proto_tree_add_item(pdutree, hf_cflow_mpls_top_label_type,
1191 tvb, offset, length, FALSE);
1193 case 47: /* top MPLS label PE address*/
1194 proto_tree_add_item(pdutree, hf_cflow_mpls_pe_addr,
1195 tvb, offset, length, FALSE);
1197 case 70: /* MPLS label1*/
1198 proto_tree_add_mpls_label(pdutree, tvb, offset, length, 1);
1200 case 71: /* MPLS label2*/
1201 proto_tree_add_mpls_label(pdutree, tvb, offset, length, 2);
1203 case 72: /* MPLS label3*/
1204 proto_tree_add_mpls_label(pdutree, tvb, offset, length, 3);
1206 case 73: /* MPLS label4*/
1207 proto_tree_add_mpls_label(pdutree, tvb, offset, length, 4);
1210 proto_tree_add_text(pdutree, tvb, offset, length,
1220 dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb, int offset)
1222 guint16 length, option_scope_len, option_len, i, id, size;
1223 struct v9_template template;
1224 int template_offset;
1226 id = tvb_get_ntohs(tvb, offset);
1227 proto_tree_add_item(pdutree, hf_cflow_template_id, tvb,
1231 option_scope_len = length = tvb_get_ntohs(tvb, offset);
1232 proto_tree_add_item(pdutree, hf_cflow_option_scope_length, tvb,
1236 option_len = length = tvb_get_ntohs(tvb, offset);
1237 proto_tree_add_item(pdutree, hf_cflow_option_length, tvb,
1241 for(i=0; i<option_scope_len; i++) {
1242 length = tvb_get_ntohs(tvb, offset);
1243 proto_tree_add_item(pdutree, hf_cflow_template_scope_field_type, tvb,
1245 offset += 2; i += 2;
1247 length = tvb_get_ntohs(tvb, offset);
1248 proto_tree_add_item(pdutree, hf_cflow_template_scope_field_length, tvb,
1250 offset += 2; i += 2;
1253 template_offset = offset;
1255 for(i=0; i<option_len;) {
1256 length = tvb_get_ntohs(tvb, offset);
1257 proto_tree_add_item(pdutree, hf_cflow_template_field_type, tvb,
1259 offset += 2; i += 2;
1261 length = tvb_get_ntohs(tvb, offset);
1262 proto_tree_add_item(pdutree, hf_cflow_template_field_length, tvb,
1264 offset += 2; i += 2;
1267 /* Cache template */
1268 memset(&template, 0, sizeof(template));
1270 template.count = option_len/4;
1271 template.source_addr = 0; /* XXX */
1272 template.source_id = 0; /* XXX */
1273 template.option_template = 1; /* Option template */
1274 size = template.count * sizeof(struct v9_template_entry);
1275 template.entries = g_malloc(size);
1276 tvb_memcpy(tvb, (guint8 *)template.entries, template_offset, size);
1278 v9_template_add(&template);
1284 dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb, int offset, int len)
1286 struct v9_template template;
1287 proto_tree *template_tree;
1288 proto_item *template_item;
1289 proto_tree *field_tree;
1290 proto_item *field_item;
1292 int remaining = len;
1295 while (remaining > 0) {
1297 id = tvb_get_ntohs(tvb, offset);
1298 count = tvb_get_ntohs(tvb, offset + 2);
1300 template_item = proto_tree_add_text(pdutree, tvb, offset,
1301 4 + sizeof(struct v9_template_entry) * count,
1302 "Template (Id = %u, Count = %u)", id, count);
1303 template_tree = proto_item_add_subtree(template_item, ett_template);
1305 proto_tree_add_item(template_tree, hf_cflow_template_id, tvb,
1309 proto_tree_add_item(template_tree, hf_cflow_template_field_count,
1310 tvb, offset, 2, FALSE);
1313 /* Cache template */
1314 memset(&template, 0, sizeof(template));
1316 template.count = count;
1317 template.source_addr = 0; /* XXX */
1318 template.source_id = 0; /* XXX */
1319 template.option_template = 0; /* Data template */
1320 template.entries = g_malloc(count * sizeof(struct v9_template_entry));
1321 tvb_memcpy(tvb, (guint8 *)template.entries, offset,
1322 count * sizeof(struct v9_template_entry));
1323 v9_template_add(&template);
1325 for (i = 1; i <= count; i++) {
1326 guint16 type, length;
1328 type = tvb_get_ntohs(tvb, offset);
1329 length = tvb_get_ntohs(tvb, offset + 2);
1331 field_item = proto_tree_add_text(template_tree, tvb,
1332 offset, 4, "Field (%u/%u)", i, count);
1333 field_tree = proto_item_add_subtree(field_item, ett_field);
1335 proto_tree_add_item(field_tree,
1336 hf_cflow_template_field_type, tvb, offset, 2, FALSE);
1339 proto_tree_add_item(field_tree,
1340 hf_cflow_template_field_length, tvb, offset, 2, FALSE);
1343 remaining -= 4 + sizeof(struct v9_template_entry) * count;
1349 static value_string v9_template_types[] = {
1356 { 7, "L4_SRC_PORT" },
1357 { 8, "IP_SRC_ADDR" },
1359 { 10, "INPUT_SNMP" },
1360 { 11, "L4_DST_PORT" },
1361 { 12, "IP_DST_ADDR" },
1363 { 14, "OUTPUT_SNMP" },
1364 { 15, "IP_NEXT_HOP" },
1367 { 18, "BGP_NEXT_HOP" },
1368 { 19, "MUL_DPKTS" },
1369 { 20, "MUL_DOCTETS" },
1370 { 21, "LAST_SWITCHED" },
1371 { 22, "FIRST_SWITCHED" },
1372 { 23, "OUT_BYTES" },
1374 { 27, "IPV6_SRC_ADDR" },
1375 { 28, "IPV6_DST_ADDR" },
1376 { 29, "IPV6_SRC_MASK" },
1377 { 30, "IPV6_DST_MASK" },
1378 { 31, "FLOW_LABEL" },
1379 { 32, "ICMP_TYPE" },
1380 { 33, "IGMP_TYPE" },
1381 { 34, "SAMPLING_INTERVAL" },
1382 { 35, "SAMPLING_ALGORITHM" },
1383 { 36, "FLOW_ACTIVE_TIMEOUT" },
1384 { 37, "FLOW_INACTIVE_TIMEOUT" },
1385 { 38, "ENGINE_TYPE" },
1386 { 39, "ENGINE_ID" },
1387 { 40, "TOTAL_BYTES_EXP" },
1388 { 41, "TOTAL_PKTS_EXP" },
1389 { 42, "TOTAL_FLOWS_EXP" },
1390 { 46, "MPLS_TOP_LABEL_TYPE" },
1391 { 47, "MPLS_TOP_LABEL_ADDR" },
1392 { 48, "FLOW_SAMPLER_ID" },
1393 { 49, "FLOW_SAMPLER_MODE" },
1394 { 50, "FLOW_SAMPLER_RANDOM_INTERVAL" },
1400 { 60, "IP_PROTOCOL_VERSION" },
1401 { 61, "DIRECTION" },
1402 { 62, "IPV6_NEXT_HOP" },
1403 { 63, "BPG_IPV6_NEXT_HOP" },
1404 { 64, "IPV6_OPTION_HEADERS" },
1405 { 70, "MPLS_LABEL_1" },
1406 { 71, "MPLS_LABEL_2" },
1407 { 72, "MPLS_LABEL_3" },
1408 { 73, "MPLS_LABEL_4" },
1409 { 74, "MPLS_LABEL_5" },
1410 { 75, "MPLS_LABEL_6" },
1411 { 76, "MPLS_LABEL_7" },
1412 { 77, "MPLS_LABEL_8" },
1413 { 78, "MPLS_LABEL_9" },
1414 { 79, "MPLS_LABEL_10" },
1418 static value_string v9_scope_field_types[] = {
1422 { 4, "NetFlow Cache" },
1428 v9_template_add(struct v9_template *template)
1432 /* Add up the actual length of the data and store in proper byte order */
1433 template->length = 0;
1434 for (i = 0; i < template->count; i++) {
1435 template->entries[i].type = g_ntohs(template->entries[i].type);
1436 template->entries[i].length = g_ntohs(template->entries[i].length);
1437 template->length += template->entries[i].length;
1440 memmove(&v9_template_cache[template->id % V9TEMPLATE_CACHE_MAX_ENTRIES],
1441 template, sizeof(*template));
1444 static struct v9_template *
1445 v9_template_get(guint16 id, guint32 src_addr, guint32 src_id)
1447 struct v9_template *template;
1450 template = &v9_template_cache[id % V9TEMPLATE_CACHE_MAX_ENTRIES];
1452 if (template->id != id ||
1453 template->source_addr != src_addr ||
1454 template->source_id != src_id) {
1462 * dissect a version 1, 5, or 7 pdu and return the length of the pdu we
1467 dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
1469 int startoffset = offset;
1470 guint32 srcaddr, dstaddr;
1474 memset(&ts, '\0', sizeof(ts));
1477 * memcpy so we can use the values later to calculate a prefix
1479 srcaddr = tvb_get_ipv4(tvb, offset);
1480 proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
1484 dstaddr = tvb_get_ipv4(tvb, offset);
1485 proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr, tvb, offset, 4,
1489 proto_tree_add_item(pdutree, hf_cflow_nexthop, tvb, offset, 4, FALSE);
1492 offset = flow_process_ints(pdutree, tvb, offset);
1493 offset = flow_process_sizecount(pdutree, tvb, offset);
1494 offset = flow_process_timeperiod(pdutree, tvb, offset);
1495 offset = flow_process_ports(pdutree, tvb, offset);
1498 * and the similarities end here
1502 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1504 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1507 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1510 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1514 flow_process_textfield(pdutree, tvb, offset, 3, "padding");
1517 flow_process_textfield(pdutree, tvb, offset, 4,
1522 flow_process_textfield(pdutree, tvb, offset, 1,
1525 proto_tree_add_item(pdutree, hf_cflow_flags, tvb,
1526 offset++, 1, FALSE);
1529 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
1532 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
1535 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
1538 offset = flow_process_aspair(pdutree, tvb, offset);
1540 mask = tvb_get_guint8(tvb, offset);
1541 proto_tree_add_text(pdutree, tvb, offset, 1,
1542 "SrcMask: %u (prefix: %s/%u)",
1543 mask, getprefix(&srcaddr, mask),
1544 mask != 0 ? mask : 32);
1545 proto_tree_add_uint_hidden(pdutree, hf_cflow_srcmask, tvb,
1548 mask = tvb_get_guint8(tvb, offset);
1549 proto_tree_add_text(pdutree, tvb, offset, 1,
1550 "DstMask: %u (prefix: %s/%u)",
1551 mask, getprefix(&dstaddr, mask),
1552 mask != 0 ? mask : 32);
1553 proto_tree_add_uint_hidden(pdutree, hf_cflow_dstmask, tvb,
1557 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
1560 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb,
1566 return (offset - startoffset);
1570 getprefix(const guint32 * address, int prefix)
1574 gprefix = *address & g_htonl((0xffffffff << (32 - prefix)));
1576 return (ip_to_str((const guint8 *)&gprefix));
1581 netflow_reinit(void)
1586 * Clear out the template cache.
1587 * Free the table of fields for each entry, and then zero out
1590 for (i = 0; i < V9TEMPLATE_CACHE_MAX_ENTRIES; i++)
1591 g_free(v9_template_cache[i].entries);
1592 memset(v9_template_cache, 0, sizeof v9_template_cache);
1596 proto_register_netflow(void)
1598 static hf_register_info hf[] = {
1603 {"Version", "cflow.version",
1604 FT_UINT16, BASE_DEC, NULL, 0x0,
1605 "NetFlow Version", HFILL}
1608 {"Count", "cflow.count",
1609 FT_UINT16, BASE_DEC, NULL, 0x0,
1610 "Count of PDUs", HFILL}
1612 {&hf_cflow_sysuptime,
1613 {"SysUptime", "cflow.sysuptime",
1614 FT_UINT32, BASE_DEC, NULL, 0x0,
1615 "Time since router booted (in milliseconds)", HFILL}
1618 {&hf_cflow_timestamp,
1619 {"Timestamp", "cflow.timestamp",
1620 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1621 "Current seconds since epoch", HFILL}
1623 {&hf_cflow_unix_secs,
1624 {"CurrentSecs", "cflow.unix_secs",
1625 FT_UINT32, BASE_DEC, NULL, 0x0,
1626 "Current seconds since epoch", HFILL}
1628 {&hf_cflow_unix_nsecs,
1629 {"CurrentNSecs", "cflow.unix_nsecs",
1630 FT_UINT32, BASE_DEC, NULL, 0x0,
1631 "Residual nanoseconds since epoch", HFILL}
1633 {&hf_cflow_samplingmode,
1634 {"SamplingMode", "cflow.samplingmode",
1635 FT_UINT16, BASE_DEC, VALS(v5_sampling_mode), 0xC000,
1636 "Sampling Mode of exporter", HFILL}
1638 {&hf_cflow_samplerate,
1639 {"SampleRate", "cflow.samplerate",
1640 FT_UINT16, BASE_DEC, NULL, 0x3FFF,
1641 "Sample Frequency of exporter", HFILL}
1645 * end version-agnostic header
1646 * version-specific flow header
1648 {&hf_cflow_sequence,
1649 {"FlowSequence", "cflow.sequence",
1650 FT_UINT32, BASE_DEC, NULL, 0x0,
1651 "Sequence number of flows seen", HFILL}
1653 {&hf_cflow_engine_type,
1654 {"EngineType", "cflow.engine_type",
1655 FT_UINT8, BASE_DEC, NULL, 0x0,
1656 "Flow switching engine type", HFILL}
1658 {&hf_cflow_engine_id,
1659 {"EngineId", "cflow.engine_id",
1660 FT_UINT8, BASE_DEC, NULL, 0x0,
1661 "Slot number of switching engine", HFILL}
1663 {&hf_cflow_source_id,
1664 {"SourceId", "cflow.source_id",
1665 FT_UINT32, BASE_DEC, NULL, 0x0,
1666 "Identifier for export device", HFILL}
1668 {&hf_cflow_aggmethod,
1669 {"AggMethod", "cflow.aggmethod",
1670 FT_UINT8, BASE_DEC, VALS(v8_agg), 0x0,
1671 "CFlow V8 Aggregation Method", HFILL}
1673 {&hf_cflow_aggversion,
1674 {"AggVersion", "cflow.aggversion",
1675 FT_UINT8, BASE_DEC, NULL, 0x0,
1676 "CFlow V8 Aggregation Version", HFILL}
1679 * end version specific header storage
1684 {&hf_cflow_flowset_id,
1685 {"FlowSet Id", "cflow.flowset_id",
1686 FT_UINT16, BASE_DEC, NULL, 0x0,
1687 "FlowSet Id", HFILL}
1689 {&hf_cflow_data_flowset_id,
1690 {"Data FlowSet (Template Id)", "cflow.data_flowset_id",
1691 FT_UINT16, BASE_DEC, NULL, 0x0,
1692 "Data FlowSet with corresponding to a template Id", HFILL}
1694 {&hf_cflow_options_flowset_id,
1695 {"Options FlowSet", "cflow.options_flowset_id",
1696 FT_UINT16, BASE_DEC, NULL, 0x0,
1697 "Options FlowSet", HFILL}
1699 {&hf_cflow_template_flowset_id,
1700 {"Template FlowSet", "cflow.template_flowset_id",
1701 FT_UINT16, BASE_DEC, NULL, 0x0,
1702 "Template FlowSet", HFILL}
1704 {&hf_cflow_flowset_length,
1705 {"FlowSet Length", "cflow.flowset_length",
1706 FT_UINT16, BASE_DEC, NULL, 0x0,
1707 "FlowSet length", HFILL}
1709 {&hf_cflow_template_id,
1710 {"Template Id", "cflow.template_id",
1711 FT_UINT16, BASE_DEC, NULL, 0x0,
1712 "Template Id", HFILL}
1714 {&hf_cflow_template_field_count,
1715 {"Field Count", "cflow.template_field_count",
1716 FT_UINT16, BASE_DEC, NULL, 0x0,
1717 "Template field count", HFILL}
1719 {&hf_cflow_template_field_type,
1720 {"Type", "cflow.template_field_type",
1721 FT_UINT16, BASE_DEC, VALS(v9_template_types), 0x0,
1722 "Template field type", HFILL}
1724 {&hf_cflow_template_field_length,
1725 {"Length", "cflow.template_field_length",
1726 FT_UINT16, BASE_DEC, NULL, 0x0,
1727 "Template field length", HFILL}
1731 {&hf_cflow_option_scope_length,
1732 {"Option Scope Length", "cflow.option_scope_length",
1733 FT_UINT16, BASE_DEC, NULL, 0x0,
1734 "Option scope length", HFILL}
1736 {&hf_cflow_option_length,
1737 {"Option Length", "cflow.option_length",
1738 FT_UINT16, BASE_DEC, NULL, 0x0,
1739 "Option length", HFILL}
1741 {&hf_cflow_template_scope_field_type,
1742 {"Scope Type", "cflow.scope_field_type",
1743 FT_UINT16, BASE_DEC, VALS(v9_scope_field_types), 0x0,
1744 "Scope field type", HFILL}
1746 {&hf_cflow_template_scope_field_length,
1747 {"Scope Field Length", "cflow.scope_field_length",
1748 FT_UINT16, BASE_DEC, NULL, 0x0,
1749 "Scope field length", HFILL}
1751 {&hf_cflow_sampling_interval,
1752 {"Sampling interval", "cflow.sampling_interval",
1753 FT_UINT32, BASE_DEC, NULL, 0x0,
1754 "Sampling interval", HFILL}
1756 {&hf_cflow_sampling_algorithm,
1757 {"Sampling algorithm", "cflow.sampling_algorithm",
1758 FT_UINT8, BASE_DEC, NULL, 0x0,
1759 "Sampling algorithm", HFILL}
1761 {&hf_cflow_flow_active_timeout,
1762 {"Flow active timeout", "cflow.flow_active_timeout",
1763 FT_UINT16, BASE_DEC, NULL, 0x0,
1764 "Flow active timeout", HFILL}
1766 {&hf_cflow_flow_inactive_timeout,
1767 {"Flow inactive timeout", "cflow.flow_inactive_timeout",
1768 FT_UINT16, BASE_DEC, NULL, 0x0,
1769 "Flow inactive timeout", HFILL}
1773 * begin pdu content storage
1776 {"SrcAddr", "cflow.srcaddr",
1777 FT_IPv4, BASE_NONE, NULL, 0x0,
1778 "Flow Source Address", HFILL}
1780 {&hf_cflow_srcaddr_v6,
1781 {"SrcAddr", "cflow.srcaddrv6",
1782 FT_IPv6, BASE_NONE, NULL, 0x0,
1783 "Flow Source Address", HFILL}
1786 {"SrcNet", "cflow.srcnet",
1787 FT_IPv4, BASE_NONE, NULL, 0x0,
1788 "Flow Source Network", HFILL}
1791 {"DstAddr", "cflow.dstaddr",
1792 FT_IPv4, BASE_NONE, NULL, 0x0,
1793 "Flow Destination Address", HFILL}
1795 {&hf_cflow_dstaddr_v6,
1796 {"DstAddr", "cflow.dstaddrv6",
1797 FT_IPv6, BASE_NONE, NULL, 0x0,
1798 "Flow Destination Address", HFILL}
1801 {"DstNet", "cflow.dstaddr",
1802 FT_IPv4, BASE_NONE, NULL, 0x0,
1803 "Flow Destination Network", HFILL}
1806 {"NextHop", "cflow.nexthop",
1807 FT_IPv4, BASE_NONE, NULL, 0x0,
1808 "Router nexthop", HFILL}
1810 {&hf_cflow_nexthop_v6,
1811 {"NextHop", "cflow.nexthopv6",
1812 FT_IPv6, BASE_NONE, NULL, 0x0,
1813 "Router nexthop", HFILL}
1815 {&hf_cflow_bgpnexthop,
1816 {"BGPNextHop", "cflow.bgpnexthop",
1817 FT_IPv4, BASE_NONE, NULL, 0x0,
1818 "BGP Router Nexthop", HFILL}
1820 {&hf_cflow_bgpnexthop_v6,
1821 {"BGPNextHop", "cflow.bgpnexthopv6",
1822 FT_IPv6, BASE_NONE, NULL, 0x0,
1823 "BGP Router Nexthop", HFILL}
1825 {&hf_cflow_inputint,
1826 {"InputInt", "cflow.inputint",
1827 FT_UINT16, BASE_DEC, NULL, 0x0,
1828 "Flow Input Interface", HFILL}
1830 {&hf_cflow_outputint,
1831 {"OutputInt", "cflow.outputint",
1832 FT_UINT16, BASE_DEC, NULL, 0x0,
1833 "Flow Output Interface", HFILL}
1836 {"Flows", "cflow.flows",
1837 FT_UINT32, BASE_DEC, NULL, 0x0,
1838 "Flows Aggregated in PDU", HFILL}
1841 {"Packets", "cflow.packets",
1842 FT_UINT32, BASE_DEC, NULL, 0x0,
1843 "Count of packets", HFILL}
1845 {&hf_cflow_packets64,
1846 {"Packets", "cflow.packets64",
1847 FT_UINT64, BASE_DEC, NULL, 0x0,
1848 "Count of packets", HFILL}
1850 {&hf_cflow_packetsout,
1851 {"PacketsOut", "cflow.packetsout",
1852 FT_UINT64, BASE_DEC, NULL, 0x0,
1853 "Count of packets going out", HFILL}
1856 {"Octets", "cflow.octets",
1857 FT_UINT32, BASE_DEC, NULL, 0x0,
1858 "Count of bytes", HFILL}
1860 {&hf_cflow_octets64,
1861 {"Octets", "cflow.octets64",
1862 FT_UINT64, BASE_DEC, NULL, 0x0,
1863 "Count of bytes", HFILL}
1865 {&hf_cflow_timestart,
1866 {"StartTime", "cflow.timestart",
1867 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1868 "Uptime at start of flow", HFILL}
1871 {"EndTime", "cflow.timeend",
1872 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1873 "Uptime at end of flow", HFILL}
1876 {"SrcPort", "cflow.srcport",
1877 FT_UINT16, BASE_DEC, NULL, 0x0,
1878 "Flow Source Port", HFILL}
1881 {"DstPort", "cflow.dstport",
1882 FT_UINT16, BASE_DEC, NULL, 0x0,
1883 "Flow Destination Port", HFILL}
1886 {"Protocol", "cflow.protocol",
1887 FT_UINT8, BASE_DEC, NULL, 0x0,
1888 "IP Protocol", HFILL}
1891 {"IP ToS", "cflow.tos",
1892 FT_UINT8, BASE_HEX, NULL, 0x0,
1893 "IP Type of Service", HFILL}
1896 {"Export Flags", "cflow.flags",
1897 FT_UINT8, BASE_HEX, NULL, 0x0,
1898 "CFlow Flags", HFILL}
1900 {&hf_cflow_tcpflags,
1901 {"TCP Flags", "cflow.tcpflags",
1902 FT_UINT8, BASE_HEX, NULL, 0x0,
1906 {"SrcAS", "cflow.srcas",
1907 FT_UINT16, BASE_DEC, NULL, 0x0,
1911 {"DstAS", "cflow.dstas",
1912 FT_UINT16, BASE_DEC, NULL, 0x0,
1913 "Destination AS", HFILL}
1916 {"SrcMask", "cflow.srcmask",
1917 FT_UINT8, BASE_DEC, NULL, 0x0,
1918 "Source Prefix Mask", HFILL}
1921 {"DstMask", "cflow.dstmask",
1922 FT_UINT8, BASE_DEC, NULL, 0x0,
1923 "Destination Prefix Mask", HFILL}
1925 {&hf_cflow_routersc,
1926 {"Router Shortcut", "cflow.routersc",
1927 FT_IPv4, BASE_NONE, NULL, 0x0,
1928 "Router shortcut by switch", HFILL}
1930 {&hf_cflow_mulpackets,
1931 {"MulticastPackets", "cflow.mulpackets",
1932 FT_UINT32, BASE_DEC, NULL, 0x0,
1933 "Count of multicast packets", HFILL}
1935 {&hf_cflow_muloctets,
1936 {"MulticastOctets", "cflow.muloctets",
1937 FT_UINT32, BASE_DEC, NULL, 0x0,
1938 "Count of multicast octets", HFILL}
1940 {&hf_cflow_octets_exp,
1941 {"OctetsExp", "cflow.octetsexp",
1942 FT_UINT32, BASE_DEC, NULL, 0x0,
1943 "Octets exported", HFILL}
1945 {&hf_cflow_packets_exp,
1946 {"PacketsExp", "cflow.packetsexp",
1947 FT_UINT32, BASE_DEC, NULL, 0x0,
1948 "Packets exported", HFILL}
1950 {&hf_cflow_mpls_top_label_type,
1951 {"TopLabelType", "cflow.toplabeltype",
1952 FT_UINT8, BASE_DEC, VALS(special_mpls_top_label_type), 0x0,
1953 "Top MPLS label Type", HFILL}
1955 {&hf_cflow_mpls_pe_addr,
1956 {"TopLabelAddr", "cflow.toplabeladdr",
1957 FT_IPv4, BASE_NONE, NULL, 0x0,
1958 "Top MPLS label PE address", HFILL}
1960 {&hf_cflow_flows_exp,
1961 {"FlowsExp", "cflow.flowsexp",
1962 FT_UINT32, BASE_DEC, NULL, 0x0,
1963 "Flows exported", HFILL}
1966 * end pdu content storage
1970 static gint *ett[] = {
1979 module_t *netflow_module;
1981 proto_netflow = proto_register_protocol("Cisco NetFlow", "CFLOW",
1984 proto_register_field_array(proto_netflow, hf, array_length(hf));
1985 proto_register_subtree_array(ett, array_length(ett));
1987 /* Register our configuration options for NetFlow */
1988 netflow_module = prefs_register_protocol(proto_netflow,
1989 proto_reg_handoff_netflow);
1991 prefs_register_uint_preference(netflow_module, "udp.port",
1992 "NetFlow UDP Port", "Set the port for NetFlow messages",
1993 10, &global_netflow_udp_port);
1995 register_init_routine(&netflow_reinit);
2000 * protocol/port association
2003 proto_reg_handoff_netflow(void)
2005 static int netflow_prefs_initialized = FALSE;
2006 static dissector_handle_t netflow_handle;
2008 if (!netflow_prefs_initialized) {
2009 netflow_handle = create_dissector_handle(dissect_netflow,
2011 netflow_prefs_initialized = TRUE;
2013 dissector_delete("udp.port", netflow_udp_port, netflow_handle);
2016 /* Set out port number for future use */
2017 netflow_udp_port = global_netflow_udp_port;
2019 dissector_add("udp.port", netflow_udp_port, netflow_handle);