vendor/TCPDUMP: Import libpcap 4.99.1
[dragonfly.git] / contrib / 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 #include <stdio.h>
50
51 #include "netdissect.h"
52 #include "addrtoname.h"
53 #include "extract.h"
54
55 #include "tcp.h"
56 #include "ipproto.h"
57
58 struct nfhdr_v1 {
59         nd_uint16_t     version;        /* version number */
60         nd_uint16_t     count;          /* # of records */
61         nd_uint32_t     msys_uptime;
62         nd_uint32_t     utc_sec;
63         nd_uint32_t     utc_nsec;
64 };
65
66 struct nfrec_v1 {
67         nd_ipv4         src_ina;
68         nd_ipv4         dst_ina;
69         nd_ipv4         nhop_ina;
70         nd_uint16_t     input;          /* SNMP index of input interface */
71         nd_uint16_t     output;         /* SNMP index of output interface */
72         nd_uint32_t     packets;        /* packets in the flow */
73         nd_uint32_t     octets;         /* layer 3 octets in the packets of the flow */
74         nd_uint32_t     start_time;     /* sys_uptime value at start of flow */
75         nd_uint32_t     last_time;      /* sys_uptime value when last packet of flow was received */
76         nd_uint16_t     srcport;        /* TCP/UDP source port or equivalent */
77         nd_uint16_t     dstport;        /* TCP/UDP source port or equivalent */
78         nd_byte         pad1[2];        /* pad */
79         nd_uint8_t      proto;          /* IP protocol type */
80         nd_uint8_t      tos;            /* IP type of service */
81         nd_uint8_t      tcp_flags;      /* cumulative OR of TCP flags */
82         nd_byte         pad[3];         /* padding */
83         nd_uint32_t     reserved;       /* unused */
84 };
85
86 struct nfhdr_v5 {
87         nd_uint16_t     version;        /* version number */
88         nd_uint16_t     count;          /* # of records */
89         nd_uint32_t     msys_uptime;
90         nd_uint32_t     utc_sec;
91         nd_uint32_t     utc_nsec;
92         nd_uint32_t     sequence;       /* flow sequence number */
93         nd_uint8_t      engine_type;    /* type of flow-switching engine */
94         nd_uint8_t      engine_id;      /* slot number of the flow-switching engine */
95         nd_uint16_t     sampling_interval; /* sampling mode and interval */
96 };
97
98 struct nfrec_v5 {
99         nd_ipv4         src_ina;
100         nd_ipv4         dst_ina;
101         nd_ipv4         nhop_ina;
102         nd_uint16_t     input;          /* SNMP index of input interface */
103         nd_uint16_t     output;         /* SNMP index of output interface */
104         nd_uint32_t     packets;        /* packets in the flow */
105         nd_uint32_t     octets;         /* layer 3 octets in the packets of the flow */
106         nd_uint32_t     start_time;     /* sys_uptime value at start of flow */
107         nd_uint32_t     last_time;      /* sys_uptime value when last packet of flow was received */
108         nd_uint16_t     srcport;        /* TCP/UDP source port or equivalent */
109         nd_uint16_t     dstport;        /* TCP/UDP source port or equivalent */
110         nd_byte         pad1;           /* pad */
111         nd_uint8_t      tcp_flags;      /* cumulative OR of TCP flags */
112         nd_uint8_t      proto;          /* IP protocol type */
113         nd_uint8_t      tos;            /* IP type of service */
114         nd_uint16_t     src_as;         /* AS number of the source */
115         nd_uint16_t     dst_as;         /* AS number of the destination */
116         nd_uint8_t      src_mask;       /* source address mask bits */
117         nd_uint8_t      dst_mask;       /* destination address prefix mask bits */
118         nd_byte         pad2[2];
119         nd_ipv4         peer_nexthop;   /* v6: IP address of the nexthop within the peer (FIB)*/
120 };
121
122 struct nfhdr_v6 {
123         nd_uint16_t     version;        /* version number */
124         nd_uint16_t     count;          /* # of records */
125         nd_uint32_t     msys_uptime;
126         nd_uint32_t     utc_sec;
127         nd_uint32_t     utc_nsec;
128         nd_uint32_t     sequence;       /* v5 flow sequence number */
129         nd_uint32_t     reserved;       /* v5 only */
130 };
131
132 struct nfrec_v6 {
133         nd_ipv4         src_ina;
134         nd_ipv4         dst_ina;
135         nd_ipv4         nhop_ina;
136         nd_uint16_t     input;          /* SNMP index of input interface */
137         nd_uint16_t     output;         /* SNMP index of output interface */
138         nd_uint32_t     packets;        /* packets in the flow */
139         nd_uint32_t     octets;         /* layer 3 octets in the packets of the flow */
140         nd_uint32_t     start_time;     /* sys_uptime value at start of flow */
141         nd_uint32_t     last_time;      /* sys_uptime value when last packet of flow was received */
142         nd_uint16_t     srcport;        /* TCP/UDP source port or equivalent */
143         nd_uint16_t     dstport;        /* TCP/UDP source port or equivalent */
144         nd_byte         pad1;           /* pad */
145         nd_uint8_t      tcp_flags;      /* cumulative OR of TCP flags */
146         nd_uint8_t      proto;          /* IP protocol type */
147         nd_uint8_t      tos;            /* IP type of service */
148         nd_uint16_t     src_as;         /* AS number of the source */
149         nd_uint16_t     dst_as;         /* AS number of the destination */
150         nd_uint8_t      src_mask;       /* source address mask bits */
151         nd_uint8_t      dst_mask;       /* destination address prefix mask bits */
152         nd_uint16_t     flags;
153         nd_ipv4         peer_nexthop;   /* v6: IP address of the nexthop within the peer (FIB)*/
154 };
155
156 static void
157 cnfp_v1_print(netdissect_options *ndo, const u_char *cp)
158 {
159         const struct nfhdr_v1 *nh;
160         const struct nfrec_v1 *nr;
161         const char *p_name;
162         uint8_t proto;
163         u_int nrecs, ver;
164 #if 0
165         time_t t;
166 #endif
167
168         nh = (const struct nfhdr_v1 *)cp;
169         ND_TCHECK_SIZE(nh);
170
171         ver = GET_BE_U_2(nh->version);
172         nrecs = GET_BE_U_4(nh->count);
173 #if 0
174         /*
175          * This is seconds since the UN*X epoch, and is followed by
176          * nanoseconds.  XXX - format it, rather than just dumping the
177          * raw seconds-since-the-Epoch.
178          */
179         t = GET_BE_U_4(nh->utc_sec);
180 #endif
181
182         ND_PRINT("NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver,
183                GET_BE_U_4(nh->msys_uptime)/1000,
184                GET_BE_U_4(nh->msys_uptime)%1000,
185                GET_BE_U_4(nh->utc_sec), GET_BE_U_4(nh->utc_nsec));
186
187         nr = (const struct nfrec_v1 *)&nh[1];
188
189         ND_PRINT("%2u recs", nrecs);
190
191         for (; nrecs != 0; nr++, nrecs--) {
192                 char buf[20];
193                 char asbuf[20];
194
195                 /*
196                  * Make sure we have the entire record.
197                  */
198                 ND_TCHECK_SIZE(nr);
199                 ND_PRINT("\n  started %u.%03u, last %u.%03u",
200                        GET_BE_U_4(nr->start_time)/1000,
201                        GET_BE_U_4(nr->start_time)%1000,
202                        GET_BE_U_4(nr->last_time)/1000,
203                        GET_BE_U_4(nr->last_time)%1000);
204
205                 asbuf[0] = buf[0] = '\0';
206                 ND_PRINT("\n    %s%s%s:%u ",
207                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->src_ina)),
208                         buf, asbuf,
209                         GET_BE_U_2(nr->srcport));
210
211                 ND_PRINT("> %s%s%s:%u ",
212                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->dst_ina)),
213                         buf, asbuf,
214                         GET_BE_U_2(nr->dstport));
215
216                 ND_PRINT(">> %s\n    ",
217                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->nhop_ina)));
218
219                 proto = GET_U_1(nr->proto);
220                 if (!ndo->ndo_nflag && (p_name = netdb_protoname(proto)) != NULL)
221                         ND_PRINT("%s ", p_name);
222                 else
223                         ND_PRINT("%u ", proto);
224
225                 /* tcp flags for tcp only */
226                 if (proto == IPPROTO_TCP) {
227                         u_int flags;
228                         flags = GET_U_1(nr->tcp_flags);
229                         ND_PRINT("%s%s%s%s%s%s%s",
230                                 flags & TH_FIN  ? "F" : "",
231                                 flags & TH_SYN  ? "S" : "",
232                                 flags & TH_RST  ? "R" : "",
233                                 flags & TH_PUSH ? "P" : "",
234                                 flags & TH_ACK  ? "A" : "",
235                                 flags & TH_URG  ? "U" : "",
236                                 flags           ? " " : "");
237                 }
238
239                 buf[0]='\0';
240                 ND_PRINT("tos %u, %u (%u octets) %s",
241                        GET_U_1(nr->tos),
242                        GET_BE_U_4(nr->packets),
243                        GET_BE_U_4(nr->octets), buf);
244         }
245         return;
246
247 trunc:
248         nd_print_trunc(ndo);
249 }
250
251 static void
252 cnfp_v5_print(netdissect_options *ndo, const u_char *cp)
253 {
254         const struct nfhdr_v5 *nh;
255         const struct nfrec_v5 *nr;
256         const char *p_name;
257         uint8_t proto;
258         u_int nrecs, ver;
259 #if 0
260         time_t t;
261 #endif
262
263         nh = (const struct nfhdr_v5 *)cp;
264         ND_TCHECK_SIZE(nh);
265
266         ver = GET_BE_U_2(nh->version);
267         nrecs = GET_BE_U_4(nh->count);
268 #if 0
269         /*
270          * This is seconds since the UN*X epoch, and is followed by
271          * nanoseconds.  XXX - format it, rather than just dumping the
272          * raw seconds-since-the-Epoch.
273          */
274         t = GET_BE_U_4(nh->utc_sec);
275 #endif
276
277         ND_PRINT("NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver,
278                GET_BE_U_4(nh->msys_uptime)/1000,
279                GET_BE_U_4(nh->msys_uptime)%1000,
280                GET_BE_U_4(nh->utc_sec), GET_BE_U_4(nh->utc_nsec));
281
282         ND_PRINT("#%u, ", GET_BE_U_4(nh->sequence));
283         nr = (const struct nfrec_v5 *)&nh[1];
284
285         ND_PRINT("%2u recs", nrecs);
286
287         for (; nrecs != 0; nr++, nrecs--) {
288                 char buf[20];
289                 char asbuf[20];
290
291                 /*
292                  * Make sure we have the entire record.
293                  */
294                 ND_TCHECK_SIZE(nr);
295                 ND_PRINT("\n  started %u.%03u, last %u.%03u",
296                        GET_BE_U_4(nr->start_time)/1000,
297                        GET_BE_U_4(nr->start_time)%1000,
298                        GET_BE_U_4(nr->last_time)/1000,
299                        GET_BE_U_4(nr->last_time)%1000);
300
301                 asbuf[0] = buf[0] = '\0';
302                 snprintf(buf, sizeof(buf), "/%u", GET_U_1(nr->src_mask));
303                 snprintf(asbuf, sizeof(asbuf), ":%u",
304                         GET_BE_U_2(nr->src_as));
305                 ND_PRINT("\n    %s%s%s:%u ",
306                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->src_ina)),
307                         buf, asbuf,
308                         GET_BE_U_2(nr->srcport));
309
310                 snprintf(buf, sizeof(buf), "/%u", GET_U_1(nr->dst_mask));
311                 snprintf(asbuf, sizeof(asbuf), ":%u",
312                          GET_BE_U_2(nr->dst_as));
313                 ND_PRINT("> %s%s%s:%u ",
314                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->dst_ina)),
315                         buf, asbuf,
316                         GET_BE_U_2(nr->dstport));
317
318                 ND_PRINT(">> %s\n    ",
319                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->nhop_ina)));
320
321                 proto = GET_U_1(nr->proto);
322                 if (!ndo->ndo_nflag && (p_name = netdb_protoname(proto)) != NULL)
323                         ND_PRINT("%s ", p_name);
324                 else
325                         ND_PRINT("%u ", proto);
326
327                 /* tcp flags for tcp only */
328                 if (proto == IPPROTO_TCP) {
329                         u_int flags;
330                         flags = GET_U_1(nr->tcp_flags);
331                         ND_PRINT("%s%s%s%s%s%s%s",
332                                 flags & TH_FIN  ? "F" : "",
333                                 flags & TH_SYN  ? "S" : "",
334                                 flags & TH_RST  ? "R" : "",
335                                 flags & TH_PUSH ? "P" : "",
336                                 flags & TH_ACK  ? "A" : "",
337                                 flags & TH_URG  ? "U" : "",
338                                 flags           ? " " : "");
339                 }
340
341                 buf[0]='\0';
342                 ND_PRINT("tos %u, %u (%u octets) %s",
343                        GET_U_1(nr->tos),
344                        GET_BE_U_4(nr->packets),
345                        GET_BE_U_4(nr->octets), buf);
346         }
347         return;
348
349 trunc:
350         nd_print_trunc(ndo);
351 }
352
353 static void
354 cnfp_v6_print(netdissect_options *ndo, const u_char *cp)
355 {
356         const struct nfhdr_v6 *nh;
357         const struct nfrec_v6 *nr;
358         const char *p_name;
359         uint8_t proto;
360         u_int nrecs, ver;
361 #if 0
362         time_t t;
363 #endif
364
365         nh = (const struct nfhdr_v6 *)cp;
366         ND_TCHECK_SIZE(nh);
367
368         ver = GET_BE_U_2(nh->version);
369         nrecs = GET_BE_U_4(nh->count);
370 #if 0
371         /*
372          * This is seconds since the UN*X epoch, and is followed by
373          * nanoseconds.  XXX - format it, rather than just dumping the
374          * raw seconds-since-the-Epoch.
375          */
376         t = GET_BE_U_4(nh->utc_sec);
377 #endif
378
379         ND_PRINT("NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver,
380                GET_BE_U_4(nh->msys_uptime)/1000,
381                GET_BE_U_4(nh->msys_uptime)%1000,
382                GET_BE_U_4(nh->utc_sec), GET_BE_U_4(nh->utc_nsec));
383
384         ND_PRINT("#%u, ", GET_BE_U_4(nh->sequence));
385         nr = (const struct nfrec_v6 *)&nh[1];
386
387         ND_PRINT("%2u recs", nrecs);
388
389         for (; nrecs != 0; nr++, nrecs--) {
390                 char buf[20];
391                 char asbuf[20];
392
393                 /*
394                  * Make sure we have the entire record.
395                  */
396                 ND_TCHECK_SIZE(nr);
397                 ND_PRINT("\n  started %u.%03u, last %u.%03u",
398                        GET_BE_U_4(nr->start_time)/1000,
399                        GET_BE_U_4(nr->start_time)%1000,
400                        GET_BE_U_4(nr->last_time)/1000,
401                        GET_BE_U_4(nr->last_time)%1000);
402
403                 asbuf[0] = buf[0] = '\0';
404                 snprintf(buf, sizeof(buf), "/%u", GET_U_1(nr->src_mask));
405                 snprintf(asbuf, sizeof(asbuf), ":%u",
406                         GET_BE_U_2(nr->src_as));
407                 ND_PRINT("\n    %s%s%s:%u ",
408                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->src_ina)),
409                         buf, asbuf,
410                         GET_BE_U_2(nr->srcport));
411
412                 snprintf(buf, sizeof(buf), "/%u", GET_U_1(nr->dst_mask));
413                 snprintf(asbuf, sizeof(asbuf), ":%u",
414                          GET_BE_U_2(nr->dst_as));
415                 ND_PRINT("> %s%s%s:%u ",
416                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->dst_ina)),
417                         buf, asbuf,
418                         GET_BE_U_2(nr->dstport));
419
420                 ND_PRINT(">> %s\n    ",
421                         intoa(GET_IPV4_TO_NETWORK_ORDER(nr->nhop_ina)));
422
423                 proto = GET_U_1(nr->proto);
424                 if (!ndo->ndo_nflag && (p_name = netdb_protoname(proto)) != NULL)
425                         ND_PRINT("%s ", p_name);
426                 else
427                         ND_PRINT("%u ", proto);
428
429                 /* tcp flags for tcp only */
430                 if (proto == IPPROTO_TCP) {
431                         u_int flags;
432                         flags = GET_U_1(nr->tcp_flags);
433                         ND_PRINT("%s%s%s%s%s%s%s",
434                                 flags & TH_FIN  ? "F" : "",
435                                 flags & TH_SYN  ? "S" : "",
436                                 flags & TH_RST  ? "R" : "",
437                                 flags & TH_PUSH ? "P" : "",
438                                 flags & TH_ACK  ? "A" : "",
439                                 flags & TH_URG  ? "U" : "",
440                                 flags           ? " " : "");
441                 }
442
443                 buf[0]='\0';
444                 snprintf(buf, sizeof(buf), "(%u<>%u encaps)",
445                          (GET_BE_U_2(nr->flags) >> 8) & 0xff,
446                          (GET_BE_U_2(nr->flags)) & 0xff);
447                 ND_PRINT("tos %u, %u (%u octets) %s",
448                        GET_U_1(nr->tos),
449                        GET_BE_U_4(nr->packets),
450                        GET_BE_U_4(nr->octets), buf);
451         }
452         return;
453
454 trunc:
455         nd_print_trunc(ndo);
456 }
457
458 void
459 cnfp_print(netdissect_options *ndo, const u_char *cp)
460 {
461         int ver;
462
463         /*
464          * First 2 bytes are the version number.
465          */
466         ndo->ndo_protocol = "cnfp";
467         ver = GET_BE_U_2(cp);
468         switch (ver) {
469
470         case 1:
471                 cnfp_v1_print(ndo, cp);
472                 break;
473
474         case 5:
475                 cnfp_v5_print(ndo, cp);
476                 break;
477
478         case 6:
479                 cnfp_v6_print(ndo, cp);
480                 break;
481
482         default:
483                 ND_PRINT("NetFlow v%x", ver);
484                 break;
485         }
486 }