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>
25 *****************************************************************************
27 ** this code was written from the following documentation:
29 ** http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_6/iug/format.pdf
30 ** http://www.caida.org/tools/measurement/cflowd/configuration/configuration-9.html
32 ** some documentation is more accurate then others. in some cases, live data and
33 ** information contained in responses from vendors were also used. some fields
34 ** are dissected as vendor specific fields.
36 ** $Yahoo: //depot/fumerola/packet-netflow/packet-netflow.c#14 $
37 ** $Id: packet-netflow.c,v 1.7 2002/10/08 19:26:35 guy Exp $
45 #include <epan/packet.h>
48 #define UDP_PORT_NETFLOW 2055
51 * pdu identifiers & sizes
54 #define V1PDU_SIZE (4 * 12)
55 #define V5PDU_SIZE (4 * 12)
56 #define V7PDU_SIZE (4 * 13)
57 #define V8PDU_AS_SIZE (4 * 7)
58 #define V8PDU_PROTO_SIZE (4 * 7)
59 #define V8PDU_SPREFIX_SIZE (4 * 8)
60 #define V8PDU_DPREFIX_SIZE (4 * 8)
61 #define V8PDU_MATRIX_SIZE (4 * 10)
62 #define V8PDU_DESTONLY_SIZE (4 * 8)
63 #define V8PDU_SRCDEST_SIZE (4 * 10)
64 #define V8PDU_FULL_SIZE (4 * 11)
65 #define V8PDU_TOSAS_SIZE (V8PDU_AS_SIZE + 4)
66 #define V8PDU_TOSPROTOPORT_SIZE (V8PDU_PROTO_SIZE + 4)
67 #define V8PDU_TOSSRCPREFIX_SIZE V8PDU_SPREFIX_SIZE
68 #define V8PDU_TOSDSTPREFIX_SIZE V8PDU_DPREFIX_SIZE
69 #define V8PDU_TOSMATRIX_SIZE V8PDU_MATRIX_SIZE
70 #define V8PDU_PREPORTPROTOCOL_SIZE (4 * 10)
79 V8PDU_DESTONLY_METHOD,
83 V8PDU_TOSPROTOPORT_METHOD,
84 V8PDU_TOSSRCPREFIX_METHOD,
85 V8PDU_TOSDSTPREFIX_METHOD,
86 V8PDU_TOSMATRIX_METHOD,
87 V8PDU_PREPORTPROTOCOL_METHOD
90 static const value_string v8_agg[] = {
91 {V8PDU_AS_METHOD, "V8 AS aggregation"},
92 {V8PDU_PROTO_METHOD, "V8 Proto/Port aggregation"},
93 {V8PDU_SPREFIX_METHOD, "V8 Source Prefix aggregation"},
94 {V8PDU_DPREFIX_METHOD, "V8 Destination Prefix aggregation"},
95 {V8PDU_MATRIX_METHOD, "V8 Network Matrix aggregation"},
96 {V8PDU_DESTONLY_METHOD, "V8 Destination aggregation (Cisco Catalyst)"},
97 {V8PDU_SRCDEST_METHOD, "V8 Src/Dest aggregation (Cisco Catalyst)"},
98 {V8PDU_FULL_METHOD, "V8 Full aggregation (Cisco Catalyst)"},
99 {V8PDU_TOSAS_METHOD, "V8 TOS+AS aggregation aggregation"},
100 {V8PDU_TOSPROTOPORT_METHOD, "V8 TOS+Protocol aggregation"},
101 {V8PDU_TOSSRCPREFIX_METHOD, "V8 TOS+Source Prefix aggregation"},
102 {V8PDU_TOSDSTPREFIX_METHOD, "V8 TOS+Destination Prefix aggregation"},
103 {V8PDU_TOSMATRIX_METHOD, "V8 TOS+Prefix Matrix aggregation"},
104 {V8PDU_PREPORTPROTOCOL_METHOD, "V8 Port+Protocol aggregation"},
110 * ethereal tree identifiers
113 static int proto_netflow = -1;
114 static int ett_netflow = -1;
115 static int ett_unixtime = -1;
116 static int ett_flow = -1;
122 static int hf_cflow_version = -1;
123 static int hf_cflow_count = -1;
124 static int hf_cflow_sysuptime = -1;
125 static int hf_cflow_unix_secs = -1;
126 static int hf_cflow_unix_nsecs = -1;
127 static int hf_cflow_timestamp = -1;
128 static int hf_cflow_samplerate = -1;
131 * cflow version specific info
133 static int hf_cflow_sequence = -1;
134 static int hf_cflow_engine_type = -1;
135 static int hf_cflow_engine_id = -1;
137 static int hf_cflow_aggmethod = -1;
138 static int hf_cflow_aggversion = -1;
143 static int hf_cflow_srcaddr = -1;
144 static int hf_cflow_srcnet = -1;
145 static int hf_cflow_dstaddr = -1;
146 static int hf_cflow_dstnet = -1;
147 static int hf_cflow_nexthop = -1;
148 static int hf_cflow_inputint = -1;
149 static int hf_cflow_outputint = -1;
150 static int hf_cflow_flows = -1;
151 static int hf_cflow_packets = -1;
152 static int hf_cflow_octets = -1;
153 static int hf_cflow_timestart = -1;
154 static int hf_cflow_timeend = -1;
155 static int hf_cflow_srcport = -1;
156 static int hf_cflow_dstport = -1;
157 static int hf_cflow_prot = -1;
158 static int hf_cflow_tos = -1;
159 static int hf_cflow_flags = -1;
160 static int hf_cflow_tcpflags = -1;
161 static int hf_cflow_dstas = -1;
162 static int hf_cflow_srcas = -1;
163 static int hf_cflow_dstmask = -1;
164 static int hf_cflow_srcmask = -1;
165 static int hf_cflow_routersc = -1;
167 typedef int dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
169 static int dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
171 static int dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
172 int offset, int verspec);
173 static int dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
174 int offset, int verspec);
176 static gchar *getprefix(const guint32 * address, int prefix);
177 static void dissect_netflow(tvbuff_t * tvb, packet_info * pinfo,
180 static int flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb,
182 static int flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb,
184 static int flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb,
186 static int flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb,
188 static int flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb,
190 static int flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb,
191 int offset, int bytes,
196 dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
198 proto_tree *netflow_tree = NULL;
200 proto_item *timeitem, *pduitem;
201 proto_tree *timetree, *pdutree;
202 unsigned int pduret, ver = 0, pdus = 0, x = 1, vspec;
203 size_t available, pdusize, offset = 0;
205 dissect_pdu_t *pduptr;
207 if (check_col(pinfo->cinfo, COL_PROTOCOL))
208 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFLOW");
209 if (check_col(pinfo->cinfo, COL_INFO))
210 col_clear(pinfo->cinfo, COL_INFO);
213 ti = proto_tree_add_item(tree, proto_netflow, tvb,
215 netflow_tree = proto_item_add_subtree(ti, ett_netflow);
218 ver = tvb_get_ntohs(tvb, offset);
222 pdusize = V1PDU_SIZE;
223 pduptr = &dissect_pdu;
226 pdusize = V5PDU_SIZE;
227 pduptr = &dissect_pdu;
230 pdusize = V7PDU_SIZE;
231 pduptr = &dissect_pdu;
234 pdusize = -1; /* deferred */
235 pduptr = &dissect_v8_aggpdu;
242 proto_tree_add_uint(netflow_tree, hf_cflow_version, tvb,
246 pdus = tvb_get_ntohs(tvb, offset);
250 proto_tree_add_uint(netflow_tree, hf_cflow_count, tvb,
255 * set something interesting in the display now that we have info
257 if (check_col(pinfo->cinfo, COL_INFO))
258 col_add_fstr(pinfo->cinfo, COL_INFO, "total: %u (v%u) flows",
262 * the rest is only interesting if we're displaying/searching the
268 proto_tree_add_item(netflow_tree, hf_cflow_sysuptime, tvb,
272 ts.secs = tvb_get_ntohl(tvb, offset);
273 ts.nsecs = tvb_get_ntohl(tvb, offset + 4);
274 timeitem = proto_tree_add_time(netflow_tree,
275 hf_cflow_timestamp, tvb, offset,
277 timetree = proto_item_add_subtree(timeitem, ett_unixtime);
279 proto_tree_add_item(timetree, hf_cflow_unix_secs, tvb,
283 proto_tree_add_item(timetree, hf_cflow_unix_nsecs, tvb,
288 * version specific header
290 if (ver == 5 || ver == 7 || ver == 8) {
291 proto_tree_add_item(netflow_tree, hf_cflow_sequence,
292 tvb, offset, 4, FALSE);
295 if (ver == 5 || ver == 8) {
296 proto_tree_add_item(netflow_tree, hf_cflow_engine_type,
297 tvb, offset++, 1, FALSE);
298 proto_tree_add_item(netflow_tree, hf_cflow_engine_id,
299 tvb, offset++, 1, FALSE);
302 vspec = tvb_get_guint8(tvb, offset);
304 case V8PDU_AS_METHOD:
305 pdusize = V8PDU_AS_SIZE;
307 case V8PDU_PROTO_METHOD:
308 pdusize = V8PDU_PROTO_SIZE;
310 case V8PDU_SPREFIX_METHOD:
311 pdusize = V8PDU_SPREFIX_SIZE;
313 case V8PDU_DPREFIX_METHOD:
314 pdusize = V8PDU_DPREFIX_SIZE;
316 case V8PDU_MATRIX_METHOD:
317 pdusize = V8PDU_MATRIX_SIZE;
319 case V8PDU_DESTONLY_METHOD:
320 pdusize = V8PDU_DESTONLY_SIZE;
321 pduptr = &dissect_v8_flowpdu;
323 case V8PDU_SRCDEST_METHOD:
324 pdusize = V8PDU_SRCDEST_SIZE;
325 pduptr = &dissect_v8_flowpdu;
327 case V8PDU_FULL_METHOD:
328 pdusize = V8PDU_FULL_SIZE;
329 pduptr = &dissect_v8_flowpdu;
331 case V8PDU_TOSAS_METHOD:
332 pdusize = V8PDU_TOSAS_SIZE;
334 case V8PDU_TOSPROTOPORT_METHOD:
335 pdusize = V8PDU_TOSPROTOPORT_SIZE;
337 case V8PDU_TOSSRCPREFIX_METHOD:
338 pdusize = V8PDU_TOSSRCPREFIX_SIZE;
340 case V8PDU_TOSDSTPREFIX_METHOD:
341 pdusize = V8PDU_TOSDSTPREFIX_SIZE;
343 case V8PDU_TOSMATRIX_METHOD:
344 pdusize = V8PDU_TOSMATRIX_SIZE;
346 case V8PDU_PREPORTPROTOCOL_METHOD:
347 pdusize = V8PDU_PREPORTPROTOCOL_SIZE;
354 proto_tree_add_uint(netflow_tree, hf_cflow_aggmethod,
355 tvb, offset++, 1, vspec);
356 proto_tree_add_item(netflow_tree, hf_cflow_aggversion,
357 tvb, offset++, 1, FALSE);
359 if (ver == 7 || ver == 8)
360 offset = flow_process_textfield(netflow_tree, tvb, offset, 4,
363 proto_tree_add_item(netflow_tree, hf_cflow_samplerate,
364 tvb, offset, 2, FALSE);
369 * everything below here should be payload
371 for (x = 1; x < pdus + 1; x++) {
373 * make sure we have a pdu's worth of data
375 available = tvb_length_remaining(tvb, offset);
376 if (available < pdusize)
380 proto_tree_add_text(netflow_tree, tvb, offset, pdusize,
381 "pdu %u/%u", x, pdus);
382 pdutree = proto_item_add_subtree(pduitem, ett_flow);
384 pduret = pduptr(pdutree, tvb, offset, vspec);
387 * if we came up short, stop processing
389 if (pduret == pdusize)
399 * flow_process_* == common groups of fields, probably could be inline
403 flow_process_ints(proto_tree * pdutree, tvbuff_t * tvb, int offset)
405 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2, FALSE);
408 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
416 flow_process_ports(proto_tree * pdutree, tvbuff_t * tvb, int offset)
418 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2, FALSE);
421 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2, FALSE);
428 flow_process_timeperiod(proto_tree * pdutree, tvbuff_t * tvb, int offset)
432 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
433 ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
434 proto_tree_add_time(pdutree, hf_cflow_timestart, tvb, offset, 4, &ts);
437 ts.secs = tvb_get_ntohl(tvb, offset) / 1000;
438 ts.nsecs = ((tvb_get_ntohl(tvb, offset) % 1000) * 1000000);
439 proto_tree_add_time(pdutree, hf_cflow_timeend, tvb, offset, 4, &ts);
447 flow_process_aspair(proto_tree * pdutree, tvbuff_t * tvb, int offset)
449 proto_tree_add_item(pdutree, hf_cflow_srcas, tvb, offset, 2, FALSE);
452 proto_tree_add_item(pdutree, hf_cflow_dstas, tvb, offset, 2, FALSE);
459 flow_process_sizecount(proto_tree * pdutree, tvbuff_t * tvb, int offset)
461 proto_tree_add_item(pdutree, hf_cflow_packets, tvb, offset, 4, FALSE);
464 proto_tree_add_item(pdutree, hf_cflow_octets, tvb, offset, 4, FALSE);
471 flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
472 int bytes, const char *text)
474 proto_tree_add_text(pdutree, tvb, offset, bytes, text);
481 dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
484 int startoffset = offset;
486 proto_tree_add_item(pdutree, hf_cflow_dstaddr, tvb, offset, 4, FALSE);
489 if (verspec != V8PDU_DESTONLY_METHOD) {
490 proto_tree_add_item(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
494 if (verspec == V8PDU_FULL_METHOD) {
495 proto_tree_add_item(pdutree, hf_cflow_dstport, tvb, offset, 2,
498 proto_tree_add_item(pdutree, hf_cflow_srcport, tvb, offset, 2,
503 offset = flow_process_sizecount(pdutree, tvb, offset);
504 offset = flow_process_timeperiod(pdutree, tvb, offset);
506 proto_tree_add_item(pdutree, hf_cflow_outputint, tvb, offset, 2,
510 if (verspec != V8PDU_DESTONLY_METHOD) {
511 proto_tree_add_item(pdutree, hf_cflow_inputint, tvb, offset, 2,
516 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1, FALSE);
517 if (verspec == V8PDU_FULL_METHOD)
518 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
520 offset = flow_process_textfield(pdutree, tvb, offset, 1, "marked tos");
522 if (verspec == V8PDU_SRCDEST_METHOD)
524 flow_process_textfield(pdutree, tvb, offset, 2,
526 else if (verspec == V8PDU_FULL_METHOD)
528 flow_process_textfield(pdutree, tvb, offset, 1, "padding");
531 flow_process_textfield(pdutree, tvb, offset, 4, "extra packets");
533 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb, offset, 4, FALSE);
536 return (offset - startoffset);
540 * dissect a version 8 pdu, returning the length of the pdu processed
544 dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
547 int startoffset = offset;
549 proto_tree_add_item(pdutree, hf_cflow_flows, tvb, offset, 4, FALSE);
552 offset = flow_process_sizecount(pdutree, tvb, offset);
553 offset = flow_process_timeperiod(pdutree, tvb, offset);
556 case V8PDU_AS_METHOD:
557 case V8PDU_TOSAS_METHOD:
558 offset = flow_process_aspair(pdutree, tvb, offset);
560 if (verspec == V8PDU_TOSAS_METHOD) {
561 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
564 flow_process_textfield(pdutree, tvb, offset, 1,
567 flow_process_textfield(pdutree, tvb, offset, 2,
571 case V8PDU_PROTO_METHOD:
572 case V8PDU_TOSPROTOPORT_METHOD:
573 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
576 if (verspec == V8PDU_PROTO_METHOD)
578 flow_process_textfield(pdutree, tvb, offset, 1,
580 else if (verspec == V8PDU_TOSPROTOPORT_METHOD)
581 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
585 flow_process_textfield(pdutree, tvb, offset, 2,
587 offset = flow_process_ports(pdutree, tvb, offset);
589 if (verspec == V8PDU_TOSPROTOPORT_METHOD)
590 offset = flow_process_ints(pdutree, tvb, offset);
592 case V8PDU_SPREFIX_METHOD:
593 case V8PDU_DPREFIX_METHOD:
594 case V8PDU_TOSSRCPREFIX_METHOD:
595 case V8PDU_TOSDSTPREFIX_METHOD:
596 proto_tree_add_item(pdutree,
598 V8PDU_SPREFIX_METHOD ?
599 hf_cflow_srcnet : hf_cflow_dstnet, tvb,
603 proto_tree_add_item(pdutree,
605 V8PDU_SPREFIX_METHOD ?
606 hf_cflow_srcmask : hf_cflow_dstmask, tvb,
609 if (verspec == V8PDU_SPREFIX_METHOD
610 || verspec == V8PDU_DPREFIX_METHOD)
612 flow_process_textfield(pdutree, tvb, offset, 1,
614 else if (verspec == V8PDU_TOSSRCPREFIX_METHOD
615 || verspec == V8PDU_TOSDSTPREFIX_METHOD)
616 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
619 proto_tree_add_item(pdutree,
621 V8PDU_SPREFIX_METHOD ? hf_cflow_srcas
622 : hf_cflow_dstas, tvb, offset, 2, FALSE);
625 proto_tree_add_item(pdutree,
627 V8PDU_SPREFIX_METHOD ?
628 hf_cflow_inputint : hf_cflow_outputint,
629 tvb, offset, 2, FALSE);
633 flow_process_textfield(pdutree, tvb, offset, 2,
636 case V8PDU_MATRIX_METHOD:
637 case V8PDU_TOSMATRIX_METHOD:
638 case V8PDU_PREPORTPROTOCOL_METHOD:
639 proto_tree_add_item(pdutree, hf_cflow_srcnet, tvb, offset, 4,
643 proto_tree_add_item(pdutree, hf_cflow_dstnet, tvb, offset, 4,
647 proto_tree_add_item(pdutree, hf_cflow_srcmask, tvb, offset++,
650 proto_tree_add_item(pdutree, hf_cflow_dstmask, tvb, offset++,
653 if (verspec == V8PDU_TOSMATRIX_METHOD ||
654 verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
655 proto_tree_add_item(pdutree, hf_cflow_tos, tvb,
657 if (verspec == V8PDU_TOSMATRIX_METHOD) {
659 flow_process_textfield(pdutree, tvb,
662 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
663 proto_tree_add_item(pdutree, hf_cflow_prot,
664 tvb, offset++, 1, FALSE);
668 flow_process_textfield(pdutree, tvb, offset, 2,
672 if (verspec == V8PDU_MATRIX_METHOD
673 || verspec == V8PDU_TOSMATRIX_METHOD) {
674 offset = flow_process_aspair(pdutree, tvb, offset);
675 } else if (verspec == V8PDU_PREPORTPROTOCOL_METHOD) {
676 offset = flow_process_ports(pdutree, tvb, offset);
679 offset = flow_process_ints(pdutree, tvb, offset);
684 return (offset - startoffset);
688 * dissect a version 1, 5, or 7 pdu and return the length of the pdu we
693 dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, int ver)
695 int startoffset = offset;
696 guint32 srcaddr, dstaddr;
700 memset(&ts, '\0', sizeof(ts));
703 * memcpy so we can use the values later to calculate a prefix
705 tvb_memcpy(tvb, (guint8 *) & srcaddr, offset, 4);
706 proto_tree_add_ipv4(pdutree, hf_cflow_srcaddr, tvb, offset, 4,
710 tvb_memcpy(tvb, (guint8 *) & dstaddr, offset, 4);
711 proto_tree_add_ipv4(pdutree, hf_cflow_dstaddr, tvb, offset, 4,
715 proto_tree_add_item(pdutree, hf_cflow_nexthop, tvb, offset, 4, FALSE);
718 offset = flow_process_ints(pdutree, tvb, offset);
719 offset = flow_process_sizecount(pdutree, tvb, offset);
720 offset = flow_process_timeperiod(pdutree, tvb, offset);
721 offset = flow_process_ports(pdutree, tvb, offset);
724 * and the similarities end here
728 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
730 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
733 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
736 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
740 flow_process_textfield(pdutree, tvb, offset, 3, "padding");
743 flow_process_textfield(pdutree, tvb, offset, 4,
748 flow_process_textfield(pdutree, tvb, offset, 1,
751 proto_tree_add_item(pdutree, hf_cflow_flags, tvb,
755 proto_tree_add_item(pdutree, hf_cflow_tcpflags, tvb, offset++,
758 proto_tree_add_item(pdutree, hf_cflow_prot, tvb, offset++, 1,
761 proto_tree_add_item(pdutree, hf_cflow_tos, tvb, offset++, 1,
764 offset = flow_process_aspair(pdutree, tvb, offset);
766 mask = tvb_get_guint8(tvb, offset);
767 proto_tree_add_text(pdutree, tvb, offset, 1,
768 "SrcMask: %u (prefix: %s/%u)",
769 mask, getprefix(&srcaddr, mask),
770 mask != 0 ? mask : 32);
771 proto_tree_add_uint_hidden(pdutree, hf_cflow_srcmask, tvb,
774 mask = tvb_get_guint8(tvb, offset);
775 proto_tree_add_text(pdutree, tvb, offset, 1,
776 "DstMask: %u (prefix: %s/%u)",
777 mask, getprefix(&dstaddr, mask),
778 mask != 0 ? mask : 32);
779 proto_tree_add_uint_hidden(pdutree, hf_cflow_dstmask, tvb,
783 flow_process_textfield(pdutree, tvb, offset, 2, "padding");
786 proto_tree_add_item(pdutree, hf_cflow_routersc, tvb,
792 return (offset - startoffset);
796 getprefix(const guint32 * address, int prefix)
800 gprefix = *address & g_htonl((0xffffffff << (32 - prefix)));
802 return (ip_to_str((const guint8 *)&gprefix));
806 proto_register_netflow(void)
808 static hf_register_info hf[] = {
813 {"Version", "cflow.version",
814 FT_UINT16, BASE_DEC, NULL, 0x0,
815 "NetFlow Version", HFILL}
818 {"Count", "cflow.count",
819 FT_UINT16, BASE_DEC, NULL, 0x0,
820 "Count of PDUs", HFILL}
822 {&hf_cflow_sysuptime,
823 {"SysUptime", "cflow.sysuptime",
824 FT_UINT32, BASE_DEC, NULL, 0x0,
825 "Time since router booted (in milliseconds)", HFILL}
828 {&hf_cflow_timestamp,
829 {"Timestamp", "cflow.timestamp",
830 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
831 "Current seconds since epoch", HFILL}
833 {&hf_cflow_unix_secs,
834 {"CurrentSecs", "cflow.unix_secs",
835 FT_UINT32, BASE_DEC, NULL, 0x0,
836 "Current seconds since epoch", HFILL}
838 {&hf_cflow_unix_nsecs,
839 {"CurrentNSecs", "cflow.unix_nsecs",
840 FT_UINT32, BASE_DEC, NULL, 0x0,
841 "Residual nanoseconds since epoch", HFILL}
843 {&hf_cflow_samplerate,
844 {"SampleRate", "cflow.samplerate",
845 FT_UINT16, BASE_DEC, NULL, 0x0,
846 "Sample Frequency of exporter", HFILL}
850 * end version-agnostic header
851 * version-specific flow header
854 {"FlowSequence", "cflow.sequence",
855 FT_UINT32, BASE_DEC, NULL, 0x0,
856 "Sequence number of flows seen", HFILL}
858 {&hf_cflow_engine_type,
859 {"EngineType", "cflow.engine_type",
860 FT_UINT8, BASE_DEC, NULL, 0x0,
861 "Flow switching engine type", HFILL}
863 {&hf_cflow_engine_id,
864 {"EngineId", "cflow.engine_id",
865 FT_UINT8, BASE_DEC, NULL, 0x0,
866 "Slot number of switching engine", HFILL}
868 {&hf_cflow_aggmethod,
869 {"AggMethod", "cflow.aggmethod",
870 FT_UINT8, BASE_DEC, VALS(v8_agg), 0x0,
871 "CFlow V8 Aggregation Method", HFILL}
873 {&hf_cflow_aggversion,
874 {"AggVersion", "cflow.aggversion",
875 FT_UINT8, BASE_DEC, NULL, 0x0,
876 "CFlow V8 Aggregation Version", HFILL}
879 * end version specific header storage
882 * begin pdu content storage
885 {"SrcAddr", "cflow.srcaddr",
886 FT_IPv4, BASE_NONE, NULL, 0x0,
887 "Flow Source Address", HFILL}
890 {"SrcNet", "cflow.srcnet",
891 FT_IPv4, BASE_NONE, NULL, 0x0,
892 "Flow Source Network", HFILL}
895 {"DstAddr", "cflow.dstaddr",
896 FT_IPv4, BASE_NONE, NULL, 0x0,
897 "Flow Destination Address", HFILL}
900 {"DstNet", "cflow.dstaddr",
901 FT_IPv4, BASE_NONE, NULL, 0x0,
902 "Flow Destination Network", HFILL}
905 {"NextHop", "cflow.nexthop",
906 FT_IPv4, BASE_NONE, NULL, 0x0,
907 "Router nexthop", HFILL}
910 {"InputInt", "cflow.inputint",
911 FT_UINT16, BASE_DEC, NULL, 0x0,
912 "Flow Input Interface", HFILL}
914 {&hf_cflow_outputint,
915 {"OutputInt", "cflow.outputint",
916 FT_UINT16, BASE_DEC, NULL, 0x0,
917 "Flow Output Interface", HFILL}
920 {"Flows", "cflow.flows",
921 FT_UINT32, BASE_DEC, NULL, 0x0,
922 "Flows Aggregated in PDU", HFILL}
925 {"Packets", "cflow.packets",
926 FT_UINT32, BASE_DEC, NULL, 0x0,
927 "Count of packets", HFILL}
930 {"Octets", "cflow.octets",
931 FT_UINT32, BASE_DEC, NULL, 0x0,
932 "Count of bytes", HFILL}
934 {&hf_cflow_timestart,
935 {"StartTime", "cflow.timestart",
936 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
937 "Uptime at start of flow", HFILL}
940 {"EndTime", "cflow.timeend",
941 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
942 "Uptime at end of flow", HFILL}
945 {"SrcPort", "cflow.srcport",
946 FT_UINT16, BASE_DEC, NULL, 0x0,
947 "Flow Source Port", HFILL}
950 {"DstPort", "cflow.dstport",
951 FT_UINT16, BASE_DEC, NULL, 0x0,
952 "Flow Destination Port", HFILL}
955 {"Protocol", "cflow.protocol",
956 FT_UINT8, BASE_DEC, NULL, 0x0,
957 "IP Protocol", HFILL}
960 {"IP ToS", "cflow.tos",
961 FT_UINT8, BASE_HEX, NULL, 0x0,
962 "IP Type of Service", HFILL}
965 {"Export Flags", "cflow.flags",
966 FT_UINT8, BASE_HEX, NULL, 0x0,
967 "CFlow Flags", HFILL}
970 {"TCP Flags", "cflow.tcpflags",
971 FT_UINT8, BASE_HEX, NULL, 0x0,
975 {"SrcAS", "cflow.srcas",
976 FT_UINT16, BASE_DEC, NULL, 0x0,
980 {"DstAS", "cflow.dstas",
981 FT_UINT16, BASE_DEC, NULL, 0x0,
982 "Destination AS", HFILL}
985 {"SrcMask", "cflow.srcmask",
986 FT_UINT8, BASE_DEC, NULL, 0x0,
987 "Source Prefix Mask", HFILL}
990 {"DstMask", "cflow.dstmask",
991 FT_UINT8, BASE_DEC, NULL, 0x0,
992 "Destination Prefix Mask", HFILL}
995 {"Router Shortcut", "cflow.routersc",
996 FT_IPv4, BASE_NONE, NULL, 0x0,
997 "Router shortcut by switch", HFILL}
1000 * end pdu content storage
1004 static gint *ett[] = {
1010 proto_netflow = proto_register_protocol("Cisco NetFlow", "CFLOW",
1013 proto_register_field_array(proto_netflow, hf, array_length(hf));
1014 proto_register_subtree_array(ett, array_length(ett));
1016 register_dissector("cflow", dissect_netflow, proto_netflow);
1021 * protocol/port association
1024 proto_reg_handoff_netflow(void)
1026 dissector_handle_t netflow_handle;
1028 netflow_handle = create_dissector_handle(dissect_netflow,
1030 dissector_add("udp.port", UDP_PORT_NETFLOW, netflow_handle);