]> The Tcpdump Group git mirrors - tcpdump/blob - print-cnfp.c
gre: add support for MikroTik Ethernet-over-IP hack.
[tcpdump] / print-cnfp.c
1 /* $OpenBSD: print-cnfp.c,v 1.2 1998/06/25 20:26:59 mickey Exp $ */
2
3 /*
4 * Copyright (c) 1998 Michael Shalayeff
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Michael Shalayeff.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /* \summary: Cisco NetFlow protocol printer */
34
35 /*
36 * Cisco NetFlow protocol
37 *
38 * See
39 *
40 * https://www.cisco.com/c/en/us/td/docs/net_mgmt/netflow_collection_engine/3-6/user/guide/format.html#wp1005892
41 */
42
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif
46
47 #include "netdissect-stdinc.h"
48
49 #define ND_LONGJMP_FROM_TCHECK
50 #include "netdissect.h"
51 #include "addrtoname.h"
52 #include "extract.h"
53
54 #include "tcp.h"
55 #include "ipproto.h"
56
57 struct nfhdr_v1 {
58 nd_uint16_t version; /* version number */
59 nd_uint16_t count; /* # of records */
60 nd_uint32_t msys_uptime;
61 nd_uint32_t utc_sec;
62 nd_uint32_t utc_nsec;
63 };
64
65 struct nfrec_v1 {
66 nd_ipv4 src_ina;
67 nd_ipv4 dst_ina;
68 nd_ipv4 nhop_ina;
69 nd_uint16_t input; /* SNMP index of input interface */
70 nd_uint16_t output; /* SNMP index of output interface */
71 nd_uint32_t packets; /* packets in the flow */
72 nd_uint32_t octets; /* layer 3 octets in the packets of the flow */
73 nd_uint32_t start_time; /* sys_uptime value at start of flow */
74 nd_uint32_t last_time; /* sys_uptime value when last packet of flow was received */
75 nd_uint16_t srcport; /* TCP/UDP source port or equivalent */
76 nd_uint16_t dstport; /* TCP/UDP source port or equivalent */
77 nd_byte pad1[2]; /* pad */
78 nd_uint8_t proto; /* IP protocol type */
79 nd_uint8_t tos; /* IP type of service */
80 nd_uint8_t tcp_flags; /* cumulative OR of TCP flags */
81 nd_byte pad[3]; /* padding */
82 nd_uint32_t reserved; /* unused */
83 };
84
85 struct nfhdr_v5 {
86 nd_uint16_t version; /* version number */
87 nd_uint16_t count; /* # of records */
88 nd_uint32_t msys_uptime;
89 nd_uint32_t utc_sec;
90 nd_uint32_t utc_nsec;
91 nd_uint32_t sequence; /* flow sequence number */
92 nd_uint8_t engine_type; /* type of flow-switching engine */
93 nd_uint8_t engine_id; /* slot number of the flow-switching engine */
94 nd_uint16_t sampling_interval; /* sampling mode and interval */
95 };
96
97 struct nfrec_v5 {
98 nd_ipv4 src_ina;
99 nd_ipv4 dst_ina;
100 nd_ipv4 nhop_ina;
101 nd_uint16_t input; /* SNMP index of input interface */
102 nd_uint16_t output; /* SNMP index of output interface */
103 nd_uint32_t packets; /* packets in the flow */
104 nd_uint32_t octets; /* layer 3 octets in the packets of the flow */
105 nd_uint32_t start_time; /* sys_uptime value at start of flow */
106 nd_uint32_t last_time; /* sys_uptime value when last packet of flow was received */
107 nd_uint16_t srcport; /* TCP/UDP source port or equivalent */
108 nd_uint16_t dstport; /* TCP/UDP source port or equivalent */
109 nd_byte pad1; /* pad */
110 nd_uint8_t tcp_flags; /* cumulative OR of TCP flags */
111 nd_uint8_t proto; /* IP protocol type */
112 nd_uint8_t tos; /* IP type of service */
113 nd_uint16_t src_as; /* AS number of the source */
114 nd_uint16_t dst_as; /* AS number of the destination */
115 nd_uint8_t src_mask; /* source address mask bits */
116 nd_uint8_t dst_mask; /* destination address prefix mask bits */
117 nd_byte pad2[2];
118 nd_ipv4 peer_nexthop; /* v6: IP address of the nexthop within the peer (FIB)*/
119 };
120
121 struct nfhdr_v6 {
122 nd_uint16_t version; /* version number */
123 nd_uint16_t count; /* # of records */
124 nd_uint32_t msys_uptime;
125 nd_uint32_t utc_sec;
126 nd_uint32_t utc_nsec;
127 nd_uint32_t sequence; /* v5 flow sequence number */
128 nd_uint32_t reserved; /* v5 only */
129 };
130
131 struct nfrec_v6 {
132 nd_ipv4 src_ina;
133 nd_ipv4 dst_ina;
134 nd_ipv4 nhop_ina;
135 nd_uint16_t input; /* SNMP index of input interface */
136 nd_uint16_t output; /* SNMP index of output interface */
137 nd_uint32_t packets; /* packets in the flow */
138 nd_uint32_t octets; /* layer 3 octets in the packets of the flow */
139 nd_uint32_t start_time; /* sys_uptime value at start of flow */
140 nd_uint32_t last_time; /* sys_uptime value when last packet of flow was received */
141 nd_uint16_t srcport; /* TCP/UDP source port or equivalent */
142 nd_uint16_t dstport; /* TCP/UDP source port or equivalent */
143 nd_byte pad1; /* pad */
144 nd_uint8_t tcp_flags; /* cumulative OR of TCP flags */
145 nd_uint8_t proto; /* IP protocol type */
146 nd_uint8_t tos; /* IP type of service */
147 nd_uint16_t src_as; /* AS number of the source */
148 nd_uint16_t dst_as; /* AS number of the destination */
149 nd_uint8_t src_mask; /* source address mask bits */
150 nd_uint8_t dst_mask; /* destination address prefix mask bits */
151 nd_uint16_t flags;
152 nd_ipv4 peer_nexthop; /* v6: IP address of the nexthop within the peer (FIB)*/
153 };
154
155 static void
156 cnfp_v1_print(netdissect_options *ndo, const u_char *cp)
157 {
158 const struct nfhdr_v1 *nh;
159 const struct nfrec_v1 *nr;
160 const char *p_name;
161 uint8_t proto;
162 u_int nrecs, ver;
163 #if 0
164 time_t t;
165 #endif
166
167 nh = (const struct nfhdr_v1 *)cp;
168
169 ver = GET_BE_U_2(nh->version);
170 nrecs = GET_BE_U_4(nh->count);
171 #if 0
172 /*
173 * This is seconds since the UN*X epoch, and is followed by
174 * nanoseconds. XXX - format it, rather than just dumping the
175 * raw seconds-since-the-Epoch.
176 */
177 t = GET_BE_U_4(nh->utc_sec);
178 #endif
179
180 ND_PRINT("NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver,
181 GET_BE_U_4(nh->msys_uptime)/1000,
182 GET_BE_U_4(nh->msys_uptime)%1000,
183 GET_BE_U_4(nh->utc_sec), GET_BE_U_4(nh->utc_nsec));
184
185 nr = (const struct nfrec_v1 *)&nh[1];
186
187 ND_PRINT("%2u recs", nrecs);
188
189 for (; nrecs != 0; nr++, nrecs--) {
190 ND_PRINT("\n started %u.%03u, last %u.%03u",
191 GET_BE_U_4(nr->start_time)/1000,
192 GET_BE_U_4(nr->start_time)%1000,
193 GET_BE_U_4(nr->last_time)/1000,
194 GET_BE_U_4(nr->last_time)%1000);
195
196 ND_PRINT("\n %s:%u ",
197 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->src_ina)),
198 GET_BE_U_2(nr->srcport));
199
200 ND_PRINT("> %s:%u ",
201 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->dst_ina)),
202 GET_BE_U_2(nr->dstport));
203
204 ND_PRINT(">> %s\n ",
205 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->nhop_ina)));
206
207 proto = GET_U_1(nr->proto);
208 if (!ndo->ndo_nflag && (p_name = netdb_protoname(proto)) != NULL)
209 ND_PRINT("%s ", p_name);
210 else
211 ND_PRINT("%u ", proto);
212
213 /* tcp flags for tcp only */
214 if (proto == IPPROTO_TCP) {
215 u_int flags;
216 flags = GET_U_1(nr->tcp_flags);
217 if (flags)
218 ND_PRINT("%s ", bittok2str_nosep(tcp_flag_values, "", flags));
219 }
220
221 ND_PRINT("tos %u, %u (%u octets)",
222 GET_U_1(nr->tos),
223 GET_BE_U_4(nr->packets),
224 GET_BE_U_4(nr->octets));
225 /* This was not all of struct nfrec_v1. */
226 ND_TCHECK_SIZE(nr);
227 }
228 }
229
230 static void
231 cnfp_v5_print(netdissect_options *ndo, const u_char *cp)
232 {
233 const struct nfhdr_v5 *nh;
234 const struct nfrec_v5 *nr;
235 const char *p_name;
236 uint8_t proto;
237 u_int nrecs, ver;
238 #if 0
239 time_t t;
240 #endif
241
242 nh = (const struct nfhdr_v5 *)cp;
243
244 ver = GET_BE_U_2(nh->version);
245 nrecs = GET_BE_U_4(nh->count);
246 #if 0
247 /*
248 * This is seconds since the UN*X epoch, and is followed by
249 * nanoseconds. XXX - format it, rather than just dumping the
250 * raw seconds-since-the-Epoch.
251 */
252 t = GET_BE_U_4(nh->utc_sec);
253 #endif
254
255 ND_PRINT("NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver,
256 GET_BE_U_4(nh->msys_uptime)/1000,
257 GET_BE_U_4(nh->msys_uptime)%1000,
258 GET_BE_U_4(nh->utc_sec), GET_BE_U_4(nh->utc_nsec));
259
260 ND_PRINT("#%u, ", GET_BE_U_4(nh->sequence));
261 /* This was not all of struct nfhdr_v5. */
262 ND_TCHECK_SIZE(nh);
263 nr = (const struct nfrec_v5 *)&nh[1];
264
265 ND_PRINT("%2u recs", nrecs);
266
267 for (; nrecs != 0; nr++, nrecs--) {
268 ND_PRINT("\n started %u.%03u, last %u.%03u",
269 GET_BE_U_4(nr->start_time)/1000,
270 GET_BE_U_4(nr->start_time)%1000,
271 GET_BE_U_4(nr->last_time)/1000,
272 GET_BE_U_4(nr->last_time)%1000);
273
274 ND_PRINT("\n %s/%u:%u:%u ",
275 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->src_ina)),
276 GET_U_1(nr->src_mask), GET_BE_U_2(nr->src_as),
277 GET_BE_U_2(nr->srcport));
278
279 ND_PRINT("> %s/%u:%u:%u ",
280 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->dst_ina)),
281 GET_U_1(nr->dst_mask), GET_BE_U_2(nr->dst_as),
282 GET_BE_U_2(nr->dstport));
283
284 ND_PRINT(">> %s\n ",
285 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->nhop_ina)));
286
287 proto = GET_U_1(nr->proto);
288 if (!ndo->ndo_nflag && (p_name = netdb_protoname(proto)) != NULL)
289 ND_PRINT("%s ", p_name);
290 else
291 ND_PRINT("%u ", proto);
292
293 /* tcp flags for tcp only */
294 if (proto == IPPROTO_TCP) {
295 u_int flags;
296 flags = GET_U_1(nr->tcp_flags);
297 if (flags)
298 ND_PRINT("%s ", bittok2str_nosep(tcp_flag_values, "", flags));
299 }
300
301 ND_PRINT("tos %u, %u (%u octets)",
302 GET_U_1(nr->tos),
303 GET_BE_U_4(nr->packets),
304 GET_BE_U_4(nr->octets));
305 /* This was not all of struct nfrec_v5. */
306 ND_TCHECK_SIZE(nr);
307 }
308 }
309
310 static void
311 cnfp_v6_print(netdissect_options *ndo, const u_char *cp)
312 {
313 const struct nfhdr_v6 *nh;
314 const struct nfrec_v6 *nr;
315 const char *p_name;
316 uint8_t proto;
317 u_int nrecs, ver;
318 #if 0
319 time_t t;
320 #endif
321
322 nh = (const struct nfhdr_v6 *)cp;
323
324 ver = GET_BE_U_2(nh->version);
325 nrecs = GET_BE_U_4(nh->count);
326 #if 0
327 /*
328 * This is seconds since the UN*X epoch, and is followed by
329 * nanoseconds. XXX - format it, rather than just dumping the
330 * raw seconds-since-the-Epoch.
331 */
332 t = GET_BE_U_4(nh->utc_sec);
333 #endif
334
335 ND_PRINT("NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver,
336 GET_BE_U_4(nh->msys_uptime)/1000,
337 GET_BE_U_4(nh->msys_uptime)%1000,
338 GET_BE_U_4(nh->utc_sec), GET_BE_U_4(nh->utc_nsec));
339
340 ND_PRINT("#%u, ", GET_BE_U_4(nh->sequence));
341 /* This was not all of struct nfhdr_v6. */
342 ND_TCHECK_SIZE(nh);
343 nr = (const struct nfrec_v6 *)&nh[1];
344
345 ND_PRINT("%2u recs", nrecs);
346
347 for (; nrecs != 0; nr++, nrecs--) {
348 ND_PRINT("\n started %u.%03u, last %u.%03u",
349 GET_BE_U_4(nr->start_time)/1000,
350 GET_BE_U_4(nr->start_time)%1000,
351 GET_BE_U_4(nr->last_time)/1000,
352 GET_BE_U_4(nr->last_time)%1000);
353
354 ND_PRINT("\n %s/%u:%u:%u ",
355 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->src_ina)),
356 GET_U_1(nr->src_mask), GET_BE_U_2(nr->src_as),
357 GET_BE_U_2(nr->srcport));
358
359 ND_PRINT("> %s/%u:%u:%u ",
360 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->dst_ina)),
361 GET_U_1(nr->dst_mask), GET_BE_U_2(nr->dst_as),
362 GET_BE_U_2(nr->dstport));
363
364 ND_PRINT(">> %s\n ",
365 intoa(GET_IPV4_TO_NETWORK_ORDER(nr->nhop_ina)));
366
367 proto = GET_U_1(nr->proto);
368 if (!ndo->ndo_nflag && (p_name = netdb_protoname(proto)) != NULL)
369 ND_PRINT("%s ", p_name);
370 else
371 ND_PRINT("%u ", proto);
372
373 /* tcp flags for tcp only */
374 if (proto == IPPROTO_TCP) {
375 u_int flags;
376 flags = GET_U_1(nr->tcp_flags);
377 if (flags)
378 ND_PRINT("%s ", bittok2str_nosep(tcp_flag_values, "", flags));
379 }
380
381 ND_PRINT("tos %u, %u (%u octets) (%u<>%u encaps)",
382 GET_U_1(nr->tos),
383 GET_BE_U_4(nr->packets),
384 GET_BE_U_4(nr->octets),
385 (GET_BE_U_2(nr->flags) >> 8) & 0xff,
386 (GET_BE_U_2(nr->flags)) & 0xff);
387 /* This was not all of struct nfrec_v6. */
388 ND_TCHECK_SIZE(nr);
389 }
390 }
391
392 void
393 cnfp_print(netdissect_options *ndo, const u_char *cp)
394 {
395 int ver;
396
397 /*
398 * First 2 bytes are the version number.
399 */
400 ndo->ndo_protocol = "cnfp";
401 ver = GET_BE_U_2(cp);
402 switch (ver) {
403
404 case 1:
405 cnfp_v1_print(ndo, cp);
406 break;
407
408 case 5:
409 cnfp_v5_print(ndo, cp);
410 break;
411
412 case 6:
413 cnfp_v6_print(ndo, cp);
414 break;
415
416 default:
417 ND_PRINT("NetFlow v%x", ver);
418 break;
419 }
420 }