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