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 /* 34 * Cisco NetFlow protocol 35 * 36 * See 37 * 38 * http://www.cisco.com/c/en/us/td/docs/net_mgmt/netflow_collection_engine/3-6/user/guide/format.html#wp1005892 39 */ 40 41 #define NETDISSECT_REWORKED 42 #ifdef HAVE_CONFIG_H 43 #include "config.h" 44 #endif 45 46 #include <tcpdump-stdinc.h> 47 48 #include <stdio.h> 49 #include <string.h> 50 51 #include "interface.h" 52 #include "addrtoname.h" 53 #include "extract.h" 54 55 #include "tcp.h" 56 #include "ipproto.h" 57 58 struct nfhdr_v1 { 59 uint16_t version; /* version number */ 60 uint16_t count; /* # of records */ 61 uint32_t msys_uptime; 62 uint32_t utc_sec; 63 uint32_t utc_nsec; 64 }; 65 66 struct nfrec_v1 { 67 struct in_addr src_ina; 68 struct in_addr dst_ina; 69 struct in_addr nhop_ina; 70 uint16_t input; /* SNMP index of input interface */ 71 uint16_t output; /* SNMP index of output interface */ 72 uint32_t packets; /* packets in the flow */ 73 uint32_t octets; /* layer 3 octets in the packets of the flow */ 74 uint32_t start_time; /* sys_uptime value at start of flow */ 75 uint32_t last_time; /* sys_uptime value when last packet of flow was received */ 76 uint16_t srcport; /* TCP/UDP source port or equivalent */ 77 uint16_t dstport; /* TCP/UDP source port or equivalent */ 78 uint16_t pad1; /* pad */ 79 uint8_t proto; /* IP protocol type */ 80 uint8_t tos; /* IP type of service */ 81 uint8_t tcp_flags; /* cumulative OR of TCP flags */ 82 uint8_t pad[3]; /* padding */ 83 uint32_t reserved; /* unused */ 84 }; 85 86 struct nfhdr_v5 { 87 uint16_t version; /* version number */ 88 uint16_t count; /* # of records */ 89 uint32_t msys_uptime; 90 uint32_t utc_sec; 91 uint32_t utc_nsec; 92 uint32_t sequence; /* flow sequence number */ 93 uint8_t engine_type; /* type of flow-switching engine */ 94 uint8_t engine_id; /* slot number of the flow-switching engine */ 95 uint16_t sampling_interval; /* sampling mode and interval */ 96 }; 97 98 struct nfrec_v5 { 99 struct in_addr src_ina; 100 struct in_addr dst_ina; 101 struct in_addr nhop_ina; 102 uint16_t input; /* SNMP index of input interface */ 103 uint16_t output; /* SNMP index of output interface */ 104 uint32_t packets; /* packets in the flow */ 105 uint32_t octets; /* layer 3 octets in the packets of the flow */ 106 uint32_t start_time; /* sys_uptime value at start of flow */ 107 uint32_t last_time; /* sys_uptime value when last packet of flow was received */ 108 uint16_t srcport; /* TCP/UDP source port or equivalent */ 109 uint16_t dstport; /* TCP/UDP source port or equivalent */ 110 uint8_t pad1; /* pad */ 111 uint8_t tcp_flags; /* cumulative OR of TCP flags */ 112 uint8_t proto; /* IP protocol type */ 113 uint8_t tos; /* IP type of service */ 114 uint16_t src_as; /* AS number of the source */ 115 uint16_t dst_as; /* AS number of the destination */ 116 uint8_t src_mask; /* source address mask bits */ 117 uint8_t dst_mask; /* destination address prefix mask bits */ 118 uint16_t pad2; 119 struct in_addr peer_nexthop; /* v6: IP address of the nexthop within the peer (FIB)*/ 120 }; 121 122 struct nfhdr_v6 { 123 uint16_t version; /* version number */ 124 uint16_t count; /* # of records */ 125 uint32_t msys_uptime; 126 uint32_t utc_sec; 127 uint32_t utc_nsec; 128 uint32_t sequence; /* v5 flow sequence number */ 129 uint32_t reserved; /* v5 only */ 130 }; 131 132 struct nfrec_v6 { 133 struct in_addr src_ina; 134 struct in_addr dst_ina; 135 struct in_addr nhop_ina; 136 uint16_t input; /* SNMP index of input interface */ 137 uint16_t output; /* SNMP index of output interface */ 138 uint32_t packets; /* packets in the flow */ 139 uint32_t octets; /* layer 3 octets in the packets of the flow */ 140 uint32_t start_time; /* sys_uptime value at start of flow */ 141 uint32_t last_time; /* sys_uptime value when last packet of flow was received */ 142 uint16_t srcport; /* TCP/UDP source port or equivalent */ 143 uint16_t dstport; /* TCP/UDP source port or equivalent */ 144 uint8_t pad1; /* pad */ 145 uint8_t tcp_flags; /* cumulative OR of TCP flags */ 146 uint8_t proto; /* IP protocol type */ 147 uint8_t tos; /* IP type of service */ 148 uint16_t src_as; /* AS number of the source */ 149 uint16_t dst_as; /* AS number of the destination */ 150 uint8_t src_mask; /* source address mask bits */ 151 uint8_t dst_mask; /* destination address prefix mask bits */ 152 uint16_t flags; 153 struct in_addr 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 register const struct nfhdr_v1 *nh; 160 register const struct nfrec_v1 *nr; 161 struct protoent *pent; 162 int nrecs, ver; 163 #if 0 164 time_t t; 165 #endif 166 167 nh = (const struct nfhdr_v1 *)cp; 168 ND_TCHECK(*nh); 169 170 ver = EXTRACT_16BITS(&nh->version); 171 nrecs = EXTRACT_32BITS(&nh->count); 172 #if 0 173 /* 174 * This is seconds since the UN*X epoch, and is followed by 175 * nanoseconds. XXX - format it, rather than just dumping the 176 * raw seconds-since-the-Epoch. 177 */ 178 t = EXTRACT_32BITS(&nh->utc_sec); 179 #endif 180 181 ND_PRINT((ndo, "NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver, 182 EXTRACT_32BITS(&nh->msys_uptime)/1000, 183 EXTRACT_32BITS(&nh->msys_uptime)%1000, 184 EXTRACT_32BITS(&nh->utc_sec), EXTRACT_32BITS(&nh->utc_nsec))); 185 186 nr = (const struct nfrec_v1 *)&nh[1]; 187 188 ND_PRINT((ndo, "%2u recs", nrecs)); 189 190 for (; nrecs != 0; nr++, nrecs--) { 191 char buf[20]; 192 char asbuf[20]; 193 194 /* 195 * Make sure we have the entire record. 196 */ 197 ND_TCHECK(*nr); 198 ND_PRINT((ndo, "\n started %u.%03u, last %u.%03u", 199 EXTRACT_32BITS(&nr->start_time)/1000, 200 EXTRACT_32BITS(&nr->start_time)%1000, 201 EXTRACT_32BITS(&nr->last_time)/1000, 202 EXTRACT_32BITS(&nr->last_time)%1000)); 203 204 asbuf[0] = buf[0] = '\0'; 205 ND_PRINT((ndo, "\n %s%s%s:%u ", intoa(nr->src_ina.s_addr), buf, asbuf, 206 EXTRACT_16BITS(&nr->srcport))); 207 208 ND_PRINT((ndo, "> %s%s%s:%u ", intoa(nr->dst_ina.s_addr), buf, asbuf, 209 EXTRACT_16BITS(&nr->dstport))); 210 211 ND_PRINT((ndo, ">> %s\n ", intoa(nr->nhop_ina.s_addr))); 212 213 pent = getprotobynumber(nr->proto); 214 if (!pent || ndo->ndo_nflag) 215 ND_PRINT((ndo, "%u ", nr->proto)); 216 else 217 ND_PRINT((ndo, "%s ", pent->p_name)); 218 219 /* tcp flags for tcp only */ 220 if (pent && pent->p_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 struct protoent *pent; 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 pent = getprotobynumber(nr->proto); 311 if (!pent || ndo->ndo_nflag) 312 ND_PRINT((ndo, "%u ", nr->proto)); 313 else 314 ND_PRINT((ndo, "%s ", pent->p_name)); 315 316 /* tcp flags for tcp only */ 317 if (pent && pent->p_proto == IPPROTO_TCP) { 318 int flags; 319 flags = nr->tcp_flags; 320 ND_PRINT((ndo, "%s%s%s%s%s%s%s", 321 flags & TH_FIN ? "F" : "", 322 flags & TH_SYN ? "S" : "", 323 flags & TH_RST ? "R" : "", 324 flags & TH_PUSH ? "P" : "", 325 flags & TH_ACK ? "A" : "", 326 flags & TH_URG ? "U" : "", 327 flags ? " " : "")); 328 } 329 330 buf[0]='\0'; 331 ND_PRINT((ndo, "tos %u, %u (%u octets) %s", 332 nr->tos, 333 EXTRACT_32BITS(&nr->packets), 334 EXTRACT_32BITS(&nr->octets), buf)); 335 } 336 return; 337 338 trunc: 339 ND_PRINT((ndo, "[|cnfp]")); 340 return; 341 } 342 343 static void 344 cnfp_v6_print(netdissect_options *ndo, const u_char *cp) 345 { 346 register const struct nfhdr_v6 *nh; 347 register const struct nfrec_v6 *nr; 348 struct protoent *pent; 349 int nrecs, ver; 350 #if 0 351 time_t t; 352 #endif 353 354 nh = (const struct nfhdr_v6 *)cp; 355 ND_TCHECK(*nh); 356 357 ver = EXTRACT_16BITS(&nh->version); 358 nrecs = EXTRACT_32BITS(&nh->count); 359 #if 0 360 /* 361 * This is seconds since the UN*X epoch, and is followed by 362 * nanoseconds. XXX - format it, rather than just dumping the 363 * raw seconds-since-the-Epoch. 364 */ 365 t = EXTRACT_32BITS(&nh->utc_sec); 366 #endif 367 368 ND_PRINT((ndo, "NetFlow v%x, %u.%03u uptime, %u.%09u, ", ver, 369 EXTRACT_32BITS(&nh->msys_uptime)/1000, 370 EXTRACT_32BITS(&nh->msys_uptime)%1000, 371 EXTRACT_32BITS(&nh->utc_sec), EXTRACT_32BITS(&nh->utc_nsec))); 372 373 ND_PRINT((ndo, "#%u, ", EXTRACT_32BITS(&nh->sequence))); 374 nr = (const struct nfrec_v6 *)&nh[1]; 375 376 ND_PRINT((ndo, "%2u recs", nrecs)); 377 378 for (; nrecs != 0; nr++, nrecs--) { 379 char buf[20]; 380 char asbuf[20]; 381 382 /* 383 * Make sure we have the entire record. 384 */ 385 ND_TCHECK(*nr); 386 ND_PRINT((ndo, "\n started %u.%03u, last %u.%03u", 387 EXTRACT_32BITS(&nr->start_time)/1000, 388 EXTRACT_32BITS(&nr->start_time)%1000, 389 EXTRACT_32BITS(&nr->last_time)/1000, 390 EXTRACT_32BITS(&nr->last_time)%1000)); 391 392 asbuf[0] = buf[0] = '\0'; 393 snprintf(buf, sizeof(buf), "/%u", nr->src_mask); 394 snprintf(asbuf, sizeof(asbuf), ":%u", 395 EXTRACT_16BITS(&nr->src_as)); 396 ND_PRINT((ndo, "\n %s%s%s:%u ", intoa(nr->src_ina.s_addr), buf, asbuf, 397 EXTRACT_16BITS(&nr->srcport))); 398 399 snprintf(buf, sizeof(buf), "/%d", nr->dst_mask); 400 snprintf(asbuf, sizeof(asbuf), ":%u", 401 EXTRACT_16BITS(&nr->dst_as)); 402 ND_PRINT((ndo, "> %s%s%s:%u ", intoa(nr->dst_ina.s_addr), buf, asbuf, 403 EXTRACT_16BITS(&nr->dstport))); 404 405 ND_PRINT((ndo, ">> %s\n ", intoa(nr->nhop_ina.s_addr))); 406 407 pent = getprotobynumber(nr->proto); 408 if (!pent || ndo->ndo_nflag) 409 ND_PRINT((ndo, "%u ", nr->proto)); 410 else 411 ND_PRINT((ndo, "%s ", pent->p_name)); 412 413 /* tcp flags for tcp only */ 414 if (pent && pent->p_proto == IPPROTO_TCP) { 415 int flags; 416 flags = nr->tcp_flags; 417 ND_PRINT((ndo, "%s%s%s%s%s%s%s", 418 flags & TH_FIN ? "F" : "", 419 flags & TH_SYN ? "S" : "", 420 flags & TH_RST ? "R" : "", 421 flags & TH_PUSH ? "P" : "", 422 flags & TH_ACK ? "A" : "", 423 flags & TH_URG ? "U" : "", 424 flags ? " " : "")); 425 } 426 427 buf[0]='\0'; 428 snprintf(buf, sizeof(buf), "(%u<>%u encaps)", 429 (EXTRACT_16BITS(&nr->flags) >> 8) & 0xff, 430 (EXTRACT_16BITS(&nr->flags)) & 0xff); 431 ND_PRINT((ndo, "tos %u, %u (%u octets) %s", 432 nr->tos, 433 EXTRACT_32BITS(&nr->packets), 434 EXTRACT_32BITS(&nr->octets), buf)); 435 } 436 return; 437 438 trunc: 439 ND_PRINT((ndo, "[|cnfp]")); 440 return; 441 } 442 443 void 444 cnfp_print(netdissect_options *ndo, const u_char *cp) 445 { 446 int ver; 447 448 /* 449 * First 2 bytes are the version number. 450 */ 451 ND_TCHECK2(*cp, 2); 452 ver = EXTRACT_16BITS(cp); 453 switch (ver) { 454 455 case 1: 456 cnfp_v1_print(ndo, cp); 457 break; 458 459 case 5: 460 cnfp_v5_print(ndo, cp); 461 break; 462 463 case 6: 464 cnfp_v6_print(ndo, cp); 465 break; 466 467 default: 468 ND_PRINT((ndo, "NetFlow v%x", ver)); 469 break; 470 } 471 return; 472 473 trunc: 474 ND_PRINT((ndo, "[|cnfp]")); 475 return; 476 } 477