1 /*
2 * Copyright (c) 2019-2020, Peter Haag
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the author nor the names of its contributors may be
14 * used to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include "config.h"
32
33 #include <stdio.h>
34 #include <stddef.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <time.h>
40 #include <string.h>
41
42 #ifdef HAVE_STDINT_H
43 #include <stdint.h>
44 #endif
45
46 #include "util.h"
47 #include "nfdump.h"
48 #include "nffile.h"
49 #include "nfx.h"
50 #include "output_util.h"
51 #include "output_raw.h"
52
53 #define STRINGSIZE 10240
54 #define IP_STRING_LEN (INET6_ADDRSTRLEN)
55
56 static char data_string[STRINGSIZE];
57
58 // record counter
59 static uint32_t recordCount;
60
raw_prolog(void)61 void raw_prolog(void) {
62 recordCount = 0;
63 memset(data_string, 0, STRINGSIZE);
64 } // End of raw_prolog
65
raw_epilog(void)66 void raw_epilog(void) {
67 // empty
68 } // End of raw_epilog
69
flow_record_to_raw(void * record,char ** s,int tag)70 void flow_record_to_raw(void *record, char ** s, int tag) {
71 char *_s, as[IP_STRING_LEN], ds[IP_STRING_LEN], datestr1[64], datestr2[64], datestr3[64];
72 char s_snet[IP_STRING_LEN], s_dnet[IP_STRING_LEN];
73 int i, id;
74 ssize_t slen, _slen;
75 time_t when;
76 struct tm *ts;
77 master_record_t *r = (master_record_t *)record;
78 extension_map_t *extension_map = r->map_ref;
79
80 as[0] = 0;
81 ds[0] = 0;
82 if ( TestFlag(r->flags,FLAG_IPV6_ADDR ) != 0 ) { // IPv6
83 uint64_t snet[2];
84 uint64_t dnet[2];
85
86 snet[0] = htonll(r->V6.srcaddr[0]);
87 snet[1] = htonll(r->V6.srcaddr[1]);
88 dnet[0] = htonll(r->V6.dstaddr[0]);
89 dnet[1] = htonll(r->V6.dstaddr[1]);
90 inet_ntop(AF_INET6, snet, as, sizeof(as));
91 inet_ntop(AF_INET6, dnet, ds, sizeof(ds));
92
93 inet6_ntop_mask(r->V6.srcaddr, r->src_mask, s_snet, sizeof(s_snet));
94 inet6_ntop_mask(r->V6.dstaddr, r->dst_mask, s_dnet, sizeof(s_dnet));
95
96 } else { // IPv4
97 uint32_t snet, dnet;
98 snet = htonl(r->V4.srcaddr);
99 dnet = htonl(r->V4.dstaddr);
100 inet_ntop(AF_INET, &snet, as, sizeof(as));
101 inet_ntop(AF_INET, &dnet, ds, sizeof(ds));
102
103 inet_ntop_mask(r->V4.srcaddr, r->src_mask, s_snet, sizeof(s_snet));
104 inet_ntop_mask(r->V4.dstaddr, r->dst_mask, s_dnet, sizeof(s_dnet));
105
106 }
107 as[IP_STRING_LEN-1] = 0;
108 ds[IP_STRING_LEN-1] = 0;
109
110 when = r->first;
111 ts = localtime(&when);
112 strftime(datestr1, 63, "%Y-%m-%d %H:%M:%S", ts);
113
114 when = r->last;
115 ts = localtime(&when);
116 strftime(datestr2, 63, "%Y-%m-%d %H:%M:%S", ts);
117
118 _s = data_string;
119 slen = STRINGSIZE;
120 snprintf(_s, slen-1, "\n"
121 "Flow Record: \n"
122 " Flags = 0x%.2x %s, %s\n"
123 " label = %16s\n"
124 " export sysid = %5u\n"
125 " size = %5u\n"
126 " first = %10u [%s]\n"
127 " last = %10u [%s]\n"
128 " msec_first = %5u\n"
129 " msec_last = %5u\n"
130 " src addr = %16s\n"
131 " dst addr = %16s\n"
132 ,
133 r->flags, TestFlag(r->flags, FLAG_EVENT) ? "EVENT" : "FLOW",
134 TestFlag(r->flags, FLAG_SAMPLED) ? "Sampled" : "Unsampled",
135 r->label ? r->label : "<none>",
136 r->exporter_sysid, r->size, r->first,
137 datestr1, r->last, datestr2, r->msec_first, r->msec_last,
138 as, ds );
139
140 _slen = strlen(data_string);
141 _s = data_string + _slen;
142 slen = STRINGSIZE - _slen;
143
144 if ( r->prot == IPPROTO_ICMP || r->prot == IPPROTO_ICMPV6 ) { // ICMP
145 snprintf(_s, slen-1,
146 " ICMP = %2u.%-2u type.code\n",
147 r->icmp_type, r->icmp_code);
148 } else {
149 snprintf(_s, slen-1,
150 " src port = %5u\n"
151 " dst port = %5u\n",
152 r->srcport, r->dstport);
153 }
154
155 _slen = strlen(data_string);
156 _s = data_string + _slen;
157 slen = STRINGSIZE - _slen;
158
159 snprintf(_s, slen-1,
160 " fwd status = %3u\n"
161 " tcp flags = 0x%.2x %s\n"
162 " proto = %3u %s\n"
163 " (src)tos = %3u\n"
164 " (in)packets = %10llu\n"
165 " (in)bytes = %10llu\n",
166 r->fwd_status, r->tcp_flags, FlagsString(r->tcp_flags), r->prot, ProtoString(r->prot, 0), r->tos,
167 (unsigned long long)r->dPkts, (unsigned long long)r->dOctets);
168
169 _slen = strlen(data_string);
170 _s = data_string + _slen;
171 slen = STRINGSIZE - _slen;
172
173 i = 0;
174 while ( (id = extension_map->ex_id[i]) != 0 ) {
175 if ( slen <= 20 ) {
176 fprintf(stderr, "String too short! Missing record data!\n");
177 data_string[STRINGSIZE-1] = 0;
178 *s = data_string;
179 }
180 switch(id) {
181 case EX_IO_SNMP_2:
182 case EX_IO_SNMP_4:
183 snprintf(_s, slen-1,
184 " input = %5u\n"
185 " output = %5u\n"
186 , r->input, r->output);
187 _slen = strlen(data_string);
188 _s = data_string + _slen;
189 slen = STRINGSIZE - _slen;
190 break;
191 case EX_AS_2:
192 case EX_AS_4:
193 snprintf(_s, slen-1,
194 " src as = %5u\n"
195 " dst as = %5u\n"
196 , r->srcas, r->dstas);
197 _slen = strlen(data_string);
198 _s = data_string + _slen;
199 slen = STRINGSIZE - _slen;
200 break;
201 case EX_BGPADJ:
202 snprintf(_s, slen-1,
203 " next as = %5u\n"
204 " prev as = %5u\n"
205 , r->bgpNextAdjacentAS, r->bgpPrevAdjacentAS);
206 _slen = strlen(data_string);
207 _s = data_string + _slen;
208 slen = STRINGSIZE - _slen;
209 break;
210 case EX_MULIPLE:
211 snprintf(_s, slen-1,
212 " src mask = %5u %s/%u\n"
213 " dst mask = %5u %s/%u\n"
214 " dst tos = %3u\n"
215 " direction = %3u\n"
216 , r->src_mask, s_snet, r->src_mask, r->dst_mask, s_dnet, r->dst_mask, r->dst_tos, r->dir );
217 _slen = strlen(data_string);
218 _s = data_string + _slen;
219 slen = STRINGSIZE - _slen;
220 break;
221 case EX_NEXT_HOP_v4:
222 case EX_NEXT_HOP_v6:
223 if ( (r->flags & FLAG_IPV6_NH ) != 0 ) { // IPv6
224 as[0] = 0;
225 r->ip_nexthop.V6[0] = htonll(r->ip_nexthop.V6[0]);
226 r->ip_nexthop.V6[1] = htonll(r->ip_nexthop.V6[1]);
227 inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as));
228 as[IP_STRING_LEN-1] = 0;
229 } else {
230 as[0] = 0;
231 r->ip_nexthop.V4 = htonl(r->ip_nexthop.V4);
232 inet_ntop(AF_INET, &r->ip_nexthop.V4, as, sizeof(as));
233 as[IP_STRING_LEN-1] = 0;
234 }
235
236 snprintf(_s, slen-1,
237 " ip next hop = %16s\n"
238 , as);
239 _slen = strlen(data_string);
240 _s = data_string + _slen;
241 slen = STRINGSIZE - _slen;
242 break;
243 case EX_NEXT_HOP_BGP_v4:
244 case EX_NEXT_HOP_BGP_v6:
245 if ( (r->flags & FLAG_IPV6_NHB ) != 0 ) { // IPv6
246 as[0] = 0;
247 r->bgp_nexthop.V6[0] = htonll(r->bgp_nexthop.V6[0]);
248 r->bgp_nexthop.V6[1] = htonll(r->bgp_nexthop.V6[1]);
249 inet_ntop(AF_INET6, r->ip_nexthop.V6, as, sizeof(as));
250 as[IP_STRING_LEN-1] = 0;
251 } else {
252 as[0] = 0;
253 r->bgp_nexthop.V4 = htonl(r->bgp_nexthop.V4);
254 inet_ntop(AF_INET, &r->bgp_nexthop.V4, as, sizeof(as));
255 as[IP_STRING_LEN-1] = 0;
256 }
257 snprintf(_s, slen-1,
258 " bgp next hop = %16s\n"
259 , as);
260 _slen = strlen(data_string);
261 _s = data_string + _slen;
262 slen = STRINGSIZE - _slen;
263 break;
264 case EX_VLAN:
265 snprintf(_s, slen-1,
266 " src vlan = %5u\n"
267 " dst vlan = %5u\n"
268 , r->src_vlan, r->dst_vlan);
269 _slen = strlen(data_string);
270 _s = data_string + _slen;
271 slen = STRINGSIZE - _slen;
272 break;
273 case EX_OUT_PKG_4:
274 case EX_OUT_PKG_8:
275 snprintf(_s, slen-1,
276 " out packets = %10llu\n"
277 , (long long unsigned)r->out_pkts);
278 _slen = strlen(data_string);
279 _s = data_string + _slen;
280 slen = STRINGSIZE - _slen;
281 break;
282 case EX_OUT_BYTES_4:
283 case EX_OUT_BYTES_8:
284 snprintf(_s, slen-1,
285 " out bytes = %10llu\n"
286 , (long long unsigned)r->out_bytes);
287 _slen = strlen(data_string);
288 _s = data_string + _slen;
289 slen = STRINGSIZE - _slen;
290 break;
291 case EX_AGGR_FLOWS_4:
292 case EX_AGGR_FLOWS_8:
293 snprintf(_s, slen-1,
294 " aggr flows = %10llu\n"
295 , (long long unsigned)r->aggr_flows);
296 _slen = strlen(data_string);
297 _s = data_string + _slen;
298 slen = STRINGSIZE - _slen;
299 break;
300 case EX_MAC_1: {
301 int i;
302 uint8_t mac1[6], mac2[6];
303
304 for ( i=0; i<6; i++ ) {
305 mac1[i] = (r->in_src_mac >> ( i*8 )) & 0xFF;
306 }
307 for ( i=0; i<6; i++ ) {
308 mac2[i] = (r->out_dst_mac >> ( i*8 )) & 0xFF;
309 }
310
311 snprintf(_s, slen-1,
312 " in src mac = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
313 " out dst mac = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
314 , mac1[5], mac1[4], mac1[3], mac1[2], mac1[1], mac1[0], mac2[5], mac2[4], mac2[3], mac2[2], mac2[1], mac2[0] );
315 _slen = strlen(data_string);
316 _s = data_string + _slen;
317 slen = STRINGSIZE - _slen;
318 } break;
319 case EX_MAC_2: {
320 int i;
321 uint8_t mac1[6], mac2[6];
322
323 for ( i=0; i<6; i++ ) {
324 mac1[i] = (r->in_dst_mac >> ( i*8 )) & 0xFF;
325 }
326 for ( i=0; i<6; i++ ) {
327 mac2[i] = (r->out_src_mac >> ( i*8 )) & 0xFF;
328 }
329
330 snprintf(_s, slen-1,
331 " in dst mac = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
332 " out src mac = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n"
333 , mac1[5], mac1[4], mac1[3], mac1[2], mac1[1], mac1[0], mac2[5], mac2[4], mac2[3], mac2[2], mac2[1], mac2[0] );
334 _slen = strlen(data_string);
335 _s = data_string + _slen;
336 slen = STRINGSIZE - _slen;
337 } break;
338 case EX_MPLS: {
339 unsigned int i;
340 for ( i=0; i<10; i++ ) {
341 snprintf(_s, slen-1,
342 " MPLS Lbl %2u = %8u-%1u-%1u\n", i+1
343 , r->mpls_label[i] >> 4 , (r->mpls_label[i] & 0xF ) >> 1, r->mpls_label[i] & 1 );
344 _slen = strlen(data_string);
345 _s = data_string + _slen;
346 slen = STRINGSIZE - _slen;
347 }
348 } break;
349 case EX_ROUTER_IP_v4:
350 as[0] = 0;
351 r->ip_router.V4 = htonl(r->ip_router.V4);
352 inet_ntop(AF_INET, &r->ip_router.V4, as, sizeof(as));
353 as[IP_STRING_LEN-1] = 0;
354
355 snprintf(_s, slen-1,
356 " ip router = %16s\n"
357 , as);
358 _slen = strlen(data_string);
359 _s = data_string + _slen;
360 slen = STRINGSIZE - _slen;
361
362 break;
363 case EX_ROUTER_IP_v6:
364 as[0] = 0;
365 r->ip_router.V6[0] = htonll(r->ip_router.V6[0]);
366 r->ip_router.V6[1] = htonll(r->ip_router.V6[1]);
367 inet_ntop(AF_INET6, &r->ip_router.V6, as, sizeof(as));
368 as[IP_STRING_LEN-1] = 0;
369
370 snprintf(_s, slen-1,
371 " ip router = %16s\n"
372 , as);
373 _slen = strlen(data_string);
374 _s = data_string + _slen;
375 slen = STRINGSIZE - _slen;
376 break;
377 case EX_LATENCY: {
378 double f1, f2, f3;
379 f1 = (double)r->client_nw_delay_usec / 1000.0;
380 f2 = (double)r->server_nw_delay_usec / 1000.0;
381 f3 = (double)r->appl_latency_usec / 1000.0;
382
383 snprintf(_s, slen-1,
384 " cli latency = %9.3f ms\n"
385 " srv latency = %9.3f ms\n"
386 " app latency = %9.3f ms\n"
387 , f1, f2, f3);
388
389 _slen = strlen(data_string);
390 _s = data_string + _slen;
391 slen = STRINGSIZE - _slen;
392
393 } break;
394 case EX_ROUTER_ID:
395 snprintf(_s, slen-1,
396 " engine type = %5u\n"
397 " engine ID = %5u\n"
398 , r->engine_type, r->engine_id);
399 _slen = strlen(data_string);
400 _s = data_string + _slen;
401 slen = STRINGSIZE - _slen;
402 break;
403 case EX_RECEIVED:
404 when = r->received / 1000LL;
405 ts = localtime(&when);
406 strftime(datestr3, 63, "%Y-%m-%d %H:%M:%S", ts);
407
408 snprintf(_s, slen-1,
409 " received at = %13llu [%s.%03llu]\n"
410 , (long long unsigned)r->received, datestr3, (long long unsigned)(r->received % 1000L));
411 _slen = strlen(data_string);
412 _s = data_string + _slen;
413 slen = STRINGSIZE - _slen;
414 break;
415 #ifdef NSEL
416 case EX_NSEL_COMMON: {
417 when = r->event_time / 1000LL;
418 ts = localtime(&when);
419 strftime(datestr3, 63, "%Y-%m-%d %H:%M:%S", ts);
420 snprintf(_s, slen-1,
421 " connect ID = %10u\n"
422 " fw event = %5u: %s\n"
423 " fw ext event = %5u: %s\n"
424 " secgroup tag = %5u\n"
425 " Event time = %13llu [%s.%03llu]\n"
426 , r->conn_id, r->event, r->event_flag == FW_EVENT ? FwEventString(r->event) : EventString(r->event)
427 , r->fw_xevent, EventXString(r->fw_xevent), r->sec_group_tag
428 , (long long unsigned)r->event_time, datestr3, (long long unsigned)(r->event_time % 1000L));
429 _slen = strlen(data_string);
430 _s = data_string + _slen;
431 slen = STRINGSIZE - _slen;
432 } break;
433 case EX_NEL_COMMON: {
434 snprintf(_s, slen-1,
435 " nat event = %5u: %s\n"
436 " ingress VRF = %10u\n"
437 " egress VRF = %10u\n"
438 , r->event, r->event_flag == FW_EVENT ? FwEventString(r->event) : EventString(r->event)
439 , r->ingress_vrfid, r->egress_vrfid);
440 _slen = strlen(data_string);
441 _s = data_string + _slen;
442 slen = STRINGSIZE - _slen;
443 } break;
444 case EX_NSEL_XLATE_PORTS: {
445 snprintf(_s, slen-1,
446 " src xlt port = %5u\n"
447 " dst xlt port = %5u\n"
448 , r->xlate_src_port, r->xlate_dst_port );
449 _slen = strlen(data_string);
450 _s = data_string + _slen;
451 slen = STRINGSIZE - _slen;
452 } break;
453 case EX_PORT_BLOCK_ALLOC: {
454 snprintf(_s, slen-1,
455 " pblock start = %5u\n"
456 " pblock end = %5u\n"
457 " pblock step = %5u\n"
458 " pblock size = %5u\n"
459 , r->block_start, r->block_end, r->block_step, r->block_size );
460 _slen = strlen(data_string);
461 _s = data_string + _slen;
462 slen = STRINGSIZE - _slen;
463 } break;
464 case EX_NSEL_XLATE_IP_v4:
465 as[0] = 0;
466 ds[0] = 0;
467 r->xlate_src_ip.V4 = htonl(r->xlate_src_ip.V4);
468 r->xlate_dst_ip.V4 = htonl(r->xlate_dst_ip.V4);
469 inet_ntop(AF_INET, &r->xlate_src_ip.V4, as, sizeof(as));
470 inet_ntop(AF_INET, &r->xlate_dst_ip.V4, ds, sizeof(ds));
471 as[IP_STRING_LEN-1] = 0;
472 ds[IP_STRING_LEN-1] = 0;
473
474 snprintf(_s, slen-1,
475 " src xlt ip = %16s\n"
476 " dst xlt ip = %16s\n"
477 , as, ds);
478 _slen = strlen(data_string);
479 _s = data_string + _slen;
480 slen = STRINGSIZE - _slen;
481 break;
482 case EX_NSEL_XLATE_IP_v6:
483 as[0] = 0;
484 ds[0] = 0;
485 r->xlate_src_ip.V6[0] = htonll(r->xlate_src_ip.V6[0]);
486 r->xlate_src_ip.V6[1] = htonll(r->xlate_src_ip.V6[1]);
487 r->xlate_dst_ip.V6[0] = htonll(r->xlate_dst_ip.V6[0]);
488 r->xlate_dst_ip.V6[1] = htonll(r->xlate_dst_ip.V6[1]);
489 inet_ntop(AF_INET6, &r->xlate_src_ip.V6, as, sizeof(as));
490 inet_ntop(AF_INET6, &r->xlate_dst_ip.V6, ds, sizeof(ds));
491 as[IP_STRING_LEN-1] = 0;
492 ds[IP_STRING_LEN-1] = 0;
493
494 snprintf(_s, slen-1,
495 " src xlate ip = %16s\n"
496 " dst xlate ip = %16s\n"
497 , as, ds);
498 _slen = strlen(data_string);
499 _s = data_string + _slen;
500 slen = STRINGSIZE - _slen;
501 break;
502 case EX_NSEL_ACL:
503 snprintf(_s, slen-1,
504 " Ingress ACL = 0x%x/0x%x/0x%x\n"
505 " Egress ACL = 0x%x/0x%x/0x%x\n"
506 , r->ingress_acl_id[0], r->ingress_acl_id[1], r->ingress_acl_id[2],
507 r->egress_acl_id[0], r->egress_acl_id[1], r->egress_acl_id[2]);
508 _slen = strlen(data_string);
509 _s = data_string + _slen;
510 slen = STRINGSIZE - _slen;
511 break;
512 case EX_NSEL_USER:
513 case EX_NSEL_USER_MAX:
514 snprintf(_s, slen-1,
515 " User name = %s\n"
516 , r->username[0] ? r->username : " <empty>");
517 _slen = strlen(data_string);
518 _s = data_string + _slen;
519 slen = STRINGSIZE - _slen;
520 break;
521 #endif
522 default:
523 snprintf(_s, slen-1, "Type %u not implemented\n", id);
524
525 }
526 i++;
527 }
528
529 data_string[STRINGSIZE-1] = 0;
530 *s = data_string;
531
532 } // End of flow_record_to_raw
533