1 /*
2 * Copyright (c) 2001 Mark Fullmer and The Ohio State University
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
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: ftio.c,v 1.47 2003/02/24 00:51:47 maf Exp $
27 */
28
29 #include "ftinclude.h"
30 #include "ftlib.h"
31
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/uio.h>
35 #include <sys/socket.h>
36 #include <sys/resource.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <sys/stat.h>
40 #include <syslog.h>
41 #include <dirent.h>
42 #include <limits.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <time.h>
47 #include <fcntl.h>
48 #include <zlib.h>
49
50 #if HAVE_MMAP
51 #include <sys/types.h>
52 #include <sys/mman.h>
53 #include <sys/stat.h>
54 #endif
55
56 /*
57 * function: readn
58 *
59 * read()'s n bytes from fd
60 * returns # of bytes read, or -1 for error
61 */
readn(int fd,void * ptr,int nbytes)62 static int readn(int fd, void *ptr, int nbytes) {
63
64 int nleft, nread;
65
66 nleft = nbytes;
67 while (nleft > 0) {
68 nread = read(fd, ptr, nleft);
69 if (nread < 0)
70 return nread;
71 else if (nread == 0)
72 break;
73
74 nleft -= nread;
75 ptr = (char*)ptr + nread;
76 }
77 return (nbytes - nleft);
78 } /* readn */
79
80
81 /* From Stevens
82 *
83 * function: writen
84 *
85 * write()'s n bytes to fd.
86 * returns # of bytes written, or -1 for error
87 */
writen(int fd,const void * ptr,int nbytes)88 static int writen(int fd, const void *ptr, int nbytes) {
89
90 int nleft, nwritten;
91
92 nleft = nbytes;
93 while (nleft > 0) {
94 nwritten = write(fd, ptr, nleft);
95 if (nwritten <= 0)
96 return(nwritten); /* error */
97
98 nleft -= nwritten;
99 ptr = (char*)ptr + nwritten;
100 }
101 return(nbytes - nleft);
102 } /* writen */
103
104
105 /*
106 * function: ftio_init
107 *
108 * Initialize an ftio structure, allocating r/w buffers, zlib, etc.
109 * On READ the header is consumed.
110 *
111 * flags: FT_IO_FLAG_READ - setup ftio for reading
112 * FT_IO_FLAG_WRITE - setup ftio for writing
113 * FT_IO_FLAG_ZINIT - used with FT_IO_FLAG_WRITE to signal
114 * future use of compression.
115 * FT_IO_FLAG_NO_SWAP - used with FT_IO_FLAG_WRITE. Normally
116 * ftio_write() expects the record in
117 * host format, and will return it in
118 * host format. This will disable the
119 * swap operation to maximize performance
120 * in certain cases.
121 * FT_IO_FLAG_MMAP - use mmap() for reading flows
122 *
123 * ftio_close() must be called on the stream to free resources
124 * and flush buffers on WRITE.
125 *
126 * returns: < 0 error
127 * >= 0 ok
128 */
ftio_init(struct ftio * ftio,int fd,int flag)129 int ftio_init(struct ftio *ftio, int fd, int flag)
130 {
131 int i, ret;
132 struct stat sb;
133 struct ftver ftv;
134
135 bzero(ftio, sizeof (struct ftio));
136
137 ftio->fd = fd;
138
139 ret = -1;
140
141 if (flag & FT_IO_FLAG_READ) {
142
143 #if HAVE_MMAP
144
145 if (flag & FT_IO_FLAG_MMAP) {
146 /* Instead of failing completely when MMAP fails, fallback to the usual
147 * way of doing things
148 */
149
150 if (fstat(ftio->fd, &sb) == 0) {
151 if ((ftio->mr = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
152 ftio->fd, 0)) != MAP_FAILED) {
153 ftio->mr_size = sb.st_size;
154 ftio->flags |= FT_IO_FLAG_MMAP;
155 } else {
156 ftio->mr = NULL;
157 // fterr_warn("mmap()");
158 }
159 } else {
160 // fterr_warn("stat()");
161 }
162
163 } /* FT_IO_FLAG_MMAP */
164
165 #endif /* HAVE_MMAP */
166
167 /* load header */
168 if (ftiheader_read(ftio->fd, &ftio->fth) < 0) {
169 fterr_warnx("ftiheader_read(): failed");
170 goto ftio_init_out;
171 }
172
173 if (ftio->flags & FT_IO_FLAG_MMAP) {
174 ftio->d_start = ftio->fth.enc_len;
175 ftio->d_end = sb.st_size;
176 }
177
178 /* verify stream version */
179 if ((ftio->fth.s_version != 1) && (ftio->fth.s_version != 3)) {
180 fterr_warnx("Unsupported stream version %d", (int)ftio->fth.s_version);
181 goto ftio_init_out;
182 }
183
184 /* backwards compatability hack */
185 if ((ftio->fth.s_version == 1) && (ftio->fth.d_version == 65535))
186 ftio->fth.d_version = 1;
187
188 /* alloc z_buf if compression set and not using mmap */
189 if (!(ftio->flags & FT_IO_FLAG_MMAP)) {
190 if (ftio->fth.flags & FT_HEADER_FLAG_COMPRESS) {
191 if (!(ftio->z_buf = (char*)malloc(FT_Z_BUFSIZE))) {
192 fterr_warn("malloc()");
193 goto ftio_init_out;
194 }
195 }
196 }
197
198 /* calculate record size */
199 if ((ftio->rec_size = ftio_rec_size(ftio)) < 0) {
200 fterr_warnx("Unsupported record type (ftio_rec_size_");
201 goto ftio_init_out;
202 }
203
204 /* calculate FT_XFIELD* */
205 if ((ftio->xfield = ftio_xfield(ftio)) == -1) {
206 fterr_warnx("Unsupported record type (ftio_xfield)");
207 goto ftio_init_out;
208 }
209
210 /* set byte swap function */
211 if (!(ftio->swapf = ftio_rec_swapfunc(ftio))) {
212 goto ftio_init_out;
213 }
214
215 /* get byte for fields */
216 ftio_get_ver(ftio, &ftv);
217 fts3rec_compute_offsets(&ftio->fo, &ftv);
218
219 /*
220 * alloc d_buf -- 1 for compressed or strems, many for uncompressed
221 */
222
223 if (ftio->fth.flags & FT_HEADER_FLAG_COMPRESS)
224 i = ftio->rec_size;
225 else
226 i = FT_D_BUFSIZE;
227
228 if ((ftio->fth.flags & FT_HEADER_FLAG_COMPRESS) ||
229 (!(ftio->flags & FT_IO_FLAG_MMAP))) {
230 if (!(ftio->d_buf = (char*)malloc(i))) {
231 fterr_warn("malloc()");
232 goto ftio_init_out;
233 }
234 }
235
236 /* initialize zlib and set zlib initialized flag */
237 if (ftio->fth.flags & FT_HEADER_FLAG_COMPRESS) {
238
239 ftio->zs.zalloc = (alloc_func)0;
240 ftio->zs.zfree = (free_func)0;
241 ftio->zs.opaque = (voidpf)0;
242
243 if (inflateInit(&ftio->zs) != Z_OK) {
244 fterr_warnx("inflateInit(): failed");
245 goto ftio_init_out;
246 }
247
248 ftio->flags |= FT_IO_FLAG_ZINIT;
249
250 #ifdef HAVE_MMAP
251
252 if (ftio->flags & FT_IO_FLAG_MMAP) {
253
254 ftio->zs.avail_in = sb.st_size - ftio->fth.enc_len;
255 ftio->zs.next_in = (Bytef*)ftio->mr+ftio->fth.enc_len;
256
257 }
258
259 #endif /* HAVE_MMAP */
260
261 ftio->zs.avail_out = ftio->rec_size;
262 ftio->zs.next_out = (Bytef*)ftio->d_buf;
263
264 }
265
266 /* mark stream for reading */
267 ftio->flags |= FT_IO_FLAG_READ;
268
269 /* flags always valid */
270 ftio->fth.fields |= FT_FIELD_HEADER_FLAGS;
271
272 ret = 0;
273
274 } else if (flag & FT_IO_FLAG_WRITE) {
275
276 #if BYTE_ORDER == LITTLE_ENDIAN
277 ftio->fth.byte_order = FT_HEADER_LITTLE_ENDIAN;
278 #endif /* LITTLE_ENDIAN */
279
280 #if BYTE_ORDER == BIG_ENDIAN
281 ftio->fth.byte_order = FT_HEADER_BIG_ENDIAN;
282 #endif /* BIG_ENDIAN */
283
284 /* alloc z_buf if compression set */
285 if (flag & FT_IO_FLAG_ZINIT) {
286
287 if (!(ftio->z_buf = (char*)malloc(FT_Z_BUFSIZE))) {
288 fterr_warn("malloc()");
289 goto ftio_init_out;
290 }
291
292 ftio->zs.zalloc = (alloc_func)0;
293 ftio->zs.zfree = (free_func)0;
294 ftio->zs.opaque = (voidpf)0;
295
296 if (deflateInit(&ftio->zs, ftio->z_level) != Z_OK) {
297 fterr_warnx("deflateInit(): failed");
298 goto ftio_init_out;
299 }
300
301 ftio->flags |= FT_IO_FLAG_ZINIT;
302 ftio->fth.flags |= FT_HEADER_FLAG_COMPRESS;
303
304 ftio->zs.next_out = (Bytef*)ftio->z_buf;
305 ftio->zs.avail_out = FT_Z_BUFSIZE;
306
307 /* no compression */
308 } else {
309
310 if (!(ftio->d_buf = (char*)malloc(FT_D_BUFSIZE))) {
311 fterr_warn("malloc()");
312 goto ftio_init_out;
313 }
314
315 ftio->d_end = FT_D_BUFSIZE;
316
317 }
318
319 /* mark stream for writing */
320 ftio->flags |= FT_IO_FLAG_WRITE;
321
322 /* flags field always valid */
323 ftio->fth.fields |= FT_FIELD_HEADER_FLAGS;
324
325 /* preserve FT_IO_FLAG_NO_SWAP */
326 if (flag & FT_IO_FLAG_NO_SWAP)
327 ftio->flags |= FT_IO_FLAG_NO_SWAP;
328
329 ret = 0;
330
331 } /* write */
332
333 ftio_init_out:
334
335 if (ret) {
336
337 if (ftio->z_buf)
338 free (ftio->z_buf);
339
340 if (ftio->d_buf)
341 free (ftio->d_buf);
342
343 if (ftio->flags & FT_IO_FLAG_ZINIT)
344 inflateEnd(&ftio->zs);
345
346 #if HAVE_MMAP
347
348 if (ftio->mr)
349 munmap(ftio->mr, (size_t)ftio->mr_size);
350
351 #endif /* HAVE_MMAP */
352
353 } /* error */
354
355 return ret;
356 }
357
358 /*
359 * function: ftio_set_z_level
360 *
361 * Set the zlib compression level for a ftio stream.
362 */
ftio_set_z_level(struct ftio * ftio,int z_level)363 void ftio_set_z_level(struct ftio *ftio, int z_level)
364 {
365
366 ftio->fth.fields |= FT_FIELD_HEADER_FLAGS;
367
368 if ((ftio->fth.flags & FT_HEADER_FLAG_COMPRESS) && (!z_level)) {
369 fterr_warnx("Compression can not be disabled");
370 return;
371 }
372
373 if ((!(ftio->fth.flags & FT_HEADER_FLAG_COMPRESS)) && (z_level)) {
374 fterr_warnx("Compression can not be enabled");
375 return;
376 }
377
378 ftio->z_level = z_level;
379
380 if (z_level)
381 if (deflateParams(&ftio->zs, ftio->z_level, Z_DEFAULT_STRATEGY) != Z_OK)
382 fterr_warnx("deflateParams(): failed");
383
384 }
385
386
387 /*
388 * function: ftio_set_flows_count
389 *
390 * Set the # of flows for a ftio stream header
391 */
ftio_set_flows_count(struct ftio * ftio,uint32_t n)392 void ftio_set_flows_count(struct ftio *ftio, uint32_t n)
393 {
394 ftio->fth.fields |= FT_FIELD_FLOW_COUNT;
395 ftio->fth.flows_count = n;
396 }
397
398 /*
399 * function: ftio_set_streaming
400 *
401 * Set the streaming flag for a ftio stream
402 */
ftio_set_streaming(struct ftio * ftio,int flag)403 void ftio_set_streaming(struct ftio *ftio, int flag)
404 {
405 ftio->fth.fields |= FT_FIELD_HEADER_FLAGS;
406
407 if (flag)
408 ftio->fth.flags |= FT_HEADER_FLAG_STREAMING;
409 else
410 ftio->fth.flags &= ~FT_HEADER_FLAG_STREAMING;
411 }
412
413 /*
414 * function: ftio_set_preloaded
415 *
416 * Set the streaming preloaded for a ftio stream
417 */
ftio_set_preloaded(struct ftio * ftio,int flag)418 void ftio_set_preloaded(struct ftio *ftio, int flag)
419 {
420 ftio->fth.fields |= FT_FIELD_HEADER_FLAGS;
421
422 if (flag)
423 ftio->fth.flags |= FT_HEADER_FLAG_PRELOADED;
424 else
425 ftio->fth.flags &= ~FT_HEADER_FLAG_PRELOADED;
426 }
427
428 /*
429 * function: ftio_set_ver
430 *
431 * Set the version information for a ftio stream
432 */
ftio_set_ver(struct ftio * ftio,struct ftver * ver)433 int ftio_set_ver(struct ftio *ftio, struct ftver *ver)
434 {
435
436 ftio->fth.fields |= FT_FIELD_EX_VER;
437
438 if (ver->d_version == 8) {
439 ftio->fth.fields |= FT_FIELD_AGG_VER;
440 ftio->fth.fields |= FT_FIELD_AGG_METHOD;
441 }
442
443 ftio->fth.d_version = ver->d_version;
444 ftio->fth.s_version = ver->s_version;
445 ftio->fth.agg_method = ver->agg_method;
446 ftio->fth.agg_version = ver->agg_version;
447
448 /* calculate record size */
449 if ((ftio->rec_size = ftio_rec_size(ftio)) < 0) {
450 fterr_warnx("Unsupported record type");
451 ftio->fth.d_version = 0;
452 return -1;
453 }
454
455 /* set byte swap function */
456 if (!(ftio->swapf = ftio_rec_swapfunc(ftio))) {
457 return -1;
458 }
459
460 return 0;
461
462 }
463
464 /*
465 * function: ftio_set_byte_order
466 *
467 * Set the byte order for a ftio stream
468 */
ftio_set_byte_order(struct ftio * ftio,int byte_order)469 void ftio_set_byte_order(struct ftio *ftio, int byte_order)
470 {
471 ftio->fth.fields |= FT_FIELD_HEADER_FLAGS;
472 ftio->fth.byte_order = byte_order;
473 }
474
475 /*
476 * function: ftio_set_debug
477 *
478 * Set the debug level for a ftio stream
479 */
ftio_set_debug(struct ftio * ftio,int debug)480 void ftio_set_debug(struct ftio *ftio, int debug)
481 {
482 ftio->debug = debug;
483 }
484
485 /*
486 * function: ftio_set_comment
487 *
488 * Set the header comment for a ftio stream
489 */
ftio_set_comment(struct ftio * ftio,char * comment)490 int ftio_set_comment(struct ftio *ftio, char *comment)
491 {
492
493 if (!comment)
494 return 0;
495
496 if (ftio->fth.comments)
497 free(ftio->fth.comments);
498
499 if (!(ftio->fth.comments = (char*)malloc(strlen(comment)+1))) {
500 fterr_warn("malloc()");
501 return -1;
502 }
503 strcpy(ftio->fth.comments, comment);
504 ftio->fth.fields |= FT_FIELD_COMMENTS;
505 return 0;
506 }
507
508 /*
509 * function: ftio_set_cap_hostname
510 *
511 * Set the header capture hostname for a ftio stream
512 */
ftio_set_cap_hostname(struct ftio * ftio,char * hostname)513 int ftio_set_cap_hostname(struct ftio *ftio, char *hostname)
514 {
515
516 if (!hostname)
517 return 0;
518
519 if (ftio->fth.cap_hostname)
520 free(ftio->fth.cap_hostname);
521
522 if (!(ftio->fth.cap_hostname = (char*)malloc(strlen(hostname)+1))) {
523 fterr_warn("malloc()");
524 }
525 strcpy(ftio->fth.cap_hostname, hostname);
526 ftio->fth.fields |= FT_FIELD_CAP_HOSTNAME;
527 return 0;
528 }
529
530 /*
531 * function: ftio_set_corrupt
532 *
533 * Set the corrupt flows header field
534 */
ftio_set_corrupt(struct ftio * ftio,uint32_t n)535 void ftio_set_corrupt(struct ftio *ftio, uint32_t n)
536 {
537 ftio->fth.fields |= FT_FIELD_PKT_CORRUPT;
538 ftio->fth.pkts_corrupt = n;
539 }
540
541 /*
542 * function: ftio_set_lost
543 *
544 * Set the lost flows header field
545 */
ftio_set_lost(struct ftio * ftio,uint32_t n)546 void ftio_set_lost(struct ftio *ftio, uint32_t n)
547 {
548 ftio->fth.fields |= FT_FIELD_FLOW_LOST;
549 ftio->fth.flows_lost = n;
550 }
551
552 /*
553 * function: ftio_set_reset
554 *
555 * Set the reset sequence header field
556 */
ftio_set_reset(struct ftio * ftio,uint32_t n)557 void ftio_set_reset(struct ftio *ftio, uint32_t n)
558 {
559 ftio->fth.fields |= FT_FIELD_SEQ_RESET;
560 ftio->fth.seq_reset = n;
561 }
562
563
564 /*
565 * function: ftio_set_xip
566 *
567 * Set the exporter ip header field
568 */
ftio_set_xip(struct ftio * ftio,uint32_t ip)569 void ftio_set_xip(struct ftio *ftio, uint32_t ip)
570 {
571 ftio->fth.fields |= FT_FIELD_EXPORTER_IP;
572 ftio->fth.exporter_ip = ip;
573 }
574
575 /*
576 * function: ftio_set_cap_time
577 *
578 * Set the header time for a ftio stream
579 */
ftio_set_cap_time(struct ftio * ftio,uint32_t start,uint32_t end)580 void ftio_set_cap_time(struct ftio *ftio, uint32_t start, uint32_t end)
581 {
582 ftio->fth.fields |= FT_FIELD_CAP_START;
583 ftio->fth.fields |= FT_FIELD_CAP_END;
584 ftio->fth.cap_start = start;
585 ftio->fth.cap_end = end;
586 }
587
588 /*
589 * function: ftio_set_cap_time_start
590 *
591 * Set the header time for a ftio stream
592 */
ftio_set_cap_time_start(struct ftio * ftio,uint32_t start)593 void ftio_set_cap_time_start(struct ftio *ftio, uint32_t start)
594 {
595 ftio->fth.fields |= FT_FIELD_CAP_START;
596 ftio->fth.cap_start = start;
597 }
598
599 /*
600 * function: ftio_get_ver
601 *
602 * Get the version from a ftio stream
603 */
ftio_get_ver(struct ftio * ftio,struct ftver * ver)604 void ftio_get_ver(struct ftio *ftio, struct ftver *ver)
605 {
606 ver->d_version = ftio->fth.d_version;
607 ver->s_version = ftio->fth.s_version;
608 ver->agg_method = ftio->fth.agg_method;
609 ver->agg_version = ftio->fth.agg_version;
610 }
611
ftio_uint32_to_time_t(uint32_t val)612 time_t ftio_uint32_to_time_t(uint32_t val) {
613 return (time_t) val;
614 }
615
616 /*
617 * function: ftio_get_stime
618 *
619 * Get the starting time from a ftio stream
620 */
ftio_get_cap_start(const struct ftio * ftio)621 uint32_t ftio_get_cap_start(const struct ftio *ftio)
622 {
623 return ftio->fth.cap_start;
624 }
625
ftio_get_cap_start_time_t(const struct ftio * ftio)626 time_t ftio_get_cap_start_time_t(const struct ftio *ftio) {
627 return ftio_uint32_to_time_t(ftio_get_cap_start(ftio));
628 }
629
630 /*
631 * function: ftio_get_etime
632 *
633 * Get the ending time from a ftio stream
634 */
ftio_get_cap_end(const struct ftio * ftio)635 uint32_t ftio_get_cap_end(const struct ftio *ftio)
636 {
637 return ftio->fth.cap_end;
638 }
639
ftio_get_cap_end_time_t(const struct ftio * ftio)640 time_t ftio_get_cap_end_time_t(const struct ftio *ftio) {
641 return ftio_uint32_to_time_t(ftio_get_cap_end(ftio));
642 }
643
644 /*
645 * function: ftio_get_rec_total
646 *
647 * Get the total records processed from a ftio stream
648 */
ftio_get_rec_total(struct ftio * ftio)649 uint64_t ftio_get_rec_total(struct ftio *ftio)
650 {
651 return ftio->rec_total;
652 }
653
654 /*
655 * function: ftio_get_flows_count
656 *
657 * Get the total records processed from a ftio stream
658 */
ftio_get_flows_count(struct ftio * ftio)659 uint32_t ftio_get_flows_count(struct ftio *ftio)
660 {
661 return ftio->fth.flows_count;
662 }
663
664
665 /*
666 * function: ftio_get_debug
667 *
668 * Get the debug level from a ftio stream
669 */
ftio_get_debug(struct ftio * ftio)670 int ftio_get_debug(struct ftio *ftio)
671 {
672 return ftio->debug;
673 }
674
675 /*
676 * function: ftio_get_cap_hostname
677 *
678 * Get the header hostname from a ftio stream
679 */
ftio_get_hostname(struct ftio * ftio)680 char *ftio_get_hostname(struct ftio *ftio)
681 {
682 return ftio->fth.cap_hostname;
683 }
684
685 /*
686 * function: ftio_get_comment
687 *
688 * Get the header comment from a ftio stream
689 */
ftio_get_comment(struct ftio * ftio)690 char *ftio_get_comment(struct ftio *ftio)
691 {
692 return ftio->fth.comments;
693 }
694
695 /*
696 * function ftio_get_corrupt
697 *
698 * Get header corrupt flows from a ftio stream
699 */
ftio_get_corrupt(struct ftio * ftio)700 uint32_t ftio_get_corrupt(struct ftio *ftio)
701 {
702 return ftio->fth.pkts_corrupt;
703 }
704
705 /*
706 * function ftio_get_lost
707 *
708 * Get header lost flows from a ftio stream
709 */
ftio_get_lost(struct ftio * ftio)710 uint32_t ftio_get_lost(struct ftio *ftio)
711 {
712 return ftio->fth.flows_lost;
713 }
714
715 /*
716 * function: ftio_close
717 *
718 * Free resources allocated with ftio_init()
719 * Flush any non empty buffers if stream was initialized for WRITE
720 * close file descriptor
721 *
722 * returns: <0 error
723 * >= 0 okay
724 */
ftio_close(struct ftio * ftio)725 int ftio_close(struct ftio *ftio)
726 {
727 int ret, err, n, nbytes;
728
729 ret = -1;
730 nbytes = 0;
731
732 if (ftio->fth.fields & FT_FIELD_COMMENTS)
733 free(ftio->fth.comments);
734
735 if (ftio->fth.fields & FT_FIELD_CAP_HOSTNAME)
736 free(ftio->fth.cap_hostname);
737
738 if (ftio->fth.ftmap)
739 ftmap_free(ftio->fth.ftmap);
740
741 if (ftio->flags & FT_IO_FLAG_READ) {
742
743 if (ftio->flags & FT_IO_FLAG_ZINIT)
744 inflateEnd(&ftio->zs);
745
746 if (ftio->z_buf)
747 free (ftio->z_buf);
748
749 if (ftio->d_buf)
750 free (ftio->d_buf);
751
752 #if HAVE_MMAP
753
754 if (ftio->mr)
755 munmap(ftio->mr, (size_t)ftio->mr_size);
756
757 #endif /* HAVE_MMAP */
758
759 } else if (ftio->flags & FT_IO_FLAG_WRITE) {
760
761 /* compression enabled? */
762 if (ftio->flags & FT_IO_FLAG_ZINIT) {
763
764 ftio->zs.avail_in = 0;
765
766 while (1) {
767
768 err = deflate(&ftio->zs, Z_FINISH);
769
770 /* if done compressing, do final write to disk */
771 if (err == Z_STREAM_END)
772 break;
773
774 /* if anything other than Z_OK, then it's an error */
775 if (err != Z_OK) {
776 fterr_warnx("deflate(): failed");
777 goto ftio_close_out;
778 }
779
780 /* need to flush */
781 if (!ftio->zs.avail_out) {
782
783 n = writen(ftio->fd, ftio->z_buf, FT_Z_BUFSIZE);
784
785 if (n < 0) {
786 fterr_warn("writen()");
787 goto ftio_close_out;
788 }
789
790 if (n == 0) {
791 fterr_warnx("writen(): EOF");
792 goto ftio_close_out;
793 }
794
795 nbytes += n;
796
797 ftio->zs.next_out = (Bytef*)ftio->z_buf;
798 ftio->zs.avail_out = FT_Z_BUFSIZE;
799
800 } else
801 break;
802 } /* while 1 */
803
804 n = writen(ftio->fd, ftio->z_buf, FT_Z_BUFSIZE-ftio->zs.avail_out);
805
806 if (n < 0) {
807 fterr_warn("writen()");
808 goto ftio_close_out;
809 }
810
811 if (n == 0) {
812 fterr_warnx("writen(): EOF");
813 goto ftio_close_out;
814 }
815
816 nbytes += n;
817
818 ret = 0;
819
820 /* no compression */
821 } else {
822
823 if (ftio->d_start) {
824
825 n = writen(ftio->fd, ftio->d_buf, ftio->d_start);
826
827 if (n < 0) {
828 fterr_warn("writen()");
829 goto ftio_close_out;
830 }
831
832 if (n == 0) {
833 fterr_warnx("writen(): EOF");
834 goto ftio_close_out;
835 }
836
837 ftio->d_start = 0;
838
839 nbytes += n;
840
841 ret = 0;
842
843 } /* buffer not empty */
844
845 ret = 0;
846
847 } /* compression */
848
849 } /* io stream enabled for write */
850
851
852 ftio_close_out:
853
854 if (ftio->flags & FT_IO_FLAG_WRITE) {
855
856 if (ftio->flags & FT_IO_FLAG_ZINIT) {
857
858 deflateEnd(&ftio->zs);
859 ftio->flags &= ~FT_IO_FLAG_ZINIT;
860 free(ftio->z_buf);
861
862 } else {
863
864 free (ftio->d_buf);
865
866 }
867
868 } /* FT_IO_FLAG_WRITE */
869
870 /* don't lose error condition if close() is a success */
871 if (ret < 0)
872 ret = close(ftio->fd);
873 else
874 close(ftio->fd);
875
876 /* no error and writing? then return bytes written */
877 if ((ftio->flags & FT_IO_FLAG_WRITE) && (ret >= 0))
878 ret = nbytes;
879
880 return ret;
881
882 } /* ftio_close */
883
884 /*
885 * function: ftio_zstat_print
886 *
887 * Print resources utilization associated with ftio zlib usage
888 *
889 * returns: <0 error
890 * >= 0 okay
891 */
ftio_zstat_print(struct ftio * ftio,FILE * std)892 void ftio_zstat_print(struct ftio *ftio, FILE *std)
893 {
894
895 double d;
896
897 d = ((double)ftio->zs.total_out) / ((double)ftio->zs.total_in);
898 fprintf(std, "compression: total_in=%lu total_out=%lu %3.3f:1\n",
899 ftio->zs.total_in, ftio->zs.total_out, d);
900
901 }
902
903 /*
904 * function: ftio_read
905 *
906 * Return the next fts3rec_* in the ftio stream, or 0L for EOF
907 *
908 * Record is returned in host byte order
909 *
910 * Stream must be first initialized with ftio_init()
911 *
912 */
ftio_read(struct ftio * ftio)913 void *ftio_read(struct ftio *ftio)
914 {
915
916 int n, err;
917 void *ret;
918 struct fts1rec_compat *compat;
919 uint32_t bleft, boff;
920
921 ret = (void*)0L;
922
923 #if HAVE_MMAP
924 /* mmap enabled? */
925 if (ftio->flags & FT_IO_FLAG_MMAP) {
926
927 /* compressed ? */
928 if (ftio->fth.flags & FT_HEADER_FLAG_COMPRESS) {
929
930 /* EOF? */
931 if (!ftio->zs.avail_in)
932 goto ftio_read_out;
933
934 err = inflate(&ftio->zs, Z_SYNC_FLUSH);
935
936 if ((err != Z_OK) && (err != Z_STREAM_END)) {
937 fterr_warnx("inflate(): failed");
938 goto ftio_read_out;
939 }
940
941 /* if avail_out == 0, then a full record was inflated -- return it */
942 if (!ftio->zs.avail_out) {
943
944 /* XXX check for interrupt record */
945
946 /* reset zlib for next call */
947 ftio->zs.avail_out = ftio->rec_size;
948 ftio->zs.next_out = (Bytef*)ftio->d_buf;
949
950 ret = (void*)ftio->d_buf;
951 goto ftio_read_out;
952
953 } else {
954
955 /* should never happen - partial decode */
956 if (ftio->zs.avail_out != ftio->rec_size)
957 fterr_warnx("Warning, partial inflated record before EOF");
958
959 /* signal EOF to caller */
960 goto ftio_read_out;
961
962 } /* ftio->zs.avail_out */
963
964 /* not compressed */
965 } else {
966
967 /* bytes left */
968 bleft = ftio->d_end - ftio->d_start;
969
970 /* enough bytes in d_buf to return a record? */
971 if (bleft >= ftio->rec_size) {
972 boff = ftio->d_start;
973 ftio->d_start += ftio->rec_size;
974
975 ret = (char*)ftio->mr+boff;
976 goto ftio_read_out;
977 }
978
979 /* signal EOF? */
980 if (!bleft)
981 goto ftio_read_out;
982
983 /* shouldn't happen */
984 fterr_warnx("Warning, partial record before EOF");
985 goto ftio_read_out;
986
987 } /* not compressed and mmap */
988
989 } /* mmap */
990
991 #endif /* HAVE_MMAP */
992
993 /* processed compressed stream */
994 if (ftio->fth.flags & FT_HEADER_FLAG_COMPRESS) {
995
996 while (1) {
997
998 /*
999 * if the inflate buffer is empty, perform a read()
1000 */
1001
1002 if (!ftio->zs.avail_in) {
1003
1004 n = read(ftio->fd, (char*)ftio->z_buf, FT_Z_BUFSIZE);
1005
1006 /* EOF and inflate buffer is empty -- done. */
1007 if (!n) {
1008
1009 /*
1010 * check for partial record inflated. This would never
1011 * happen on a uncorrupted stream
1012 */
1013 if (ftio->zs.avail_out != ftio->rec_size)
1014 fterr_warnx("Warning, partial inflated record before EOF");
1015
1016 /* signal EOF to caller */
1017 goto ftio_read_out;
1018
1019 }
1020
1021 /* read error -- done. */
1022 if (n == -1) {
1023 fterr_warn("read()");
1024 goto ftio_read_out;
1025 }
1026
1027 ftio->zs.avail_in = n;
1028 ftio->zs.next_in = (Bytef*)ftio->z_buf;
1029
1030 } /* if inflate buffer empty */
1031
1032 /*
1033 * inflate stream, attempt to get a record
1034 */
1035
1036 err = inflate(&ftio->zs, Z_SYNC_FLUSH);
1037
1038 if ((err != Z_OK) && (err != Z_STREAM_END)) {
1039 fterr_warnx("inflate(): failed");
1040 goto ftio_read_out;
1041 }
1042
1043 /* if avail_out == 0, then a full record was inflated -- return it */
1044 if (!ftio->zs.avail_out) {
1045
1046 /* XXX check for interrupt record */
1047
1048 /* reset zlib for next call */
1049 ftio->zs.avail_out = ftio->rec_size;
1050 ftio->zs.next_out = (Bytef*)ftio->d_buf;
1051
1052 ret = (void*)ftio->d_buf;
1053 goto ftio_read_out;
1054
1055 } /* bytes available for inflate */
1056 } /* while 1 */
1057 } /* compressed stream */
1058
1059 /*
1060 * uncompressed stream
1061 */
1062
1063 /*
1064 * if there are not enough bytes between the start pointer and the end
1065 * of d_buf for a full record, perform a read()
1066 */
1067
1068 /* while(1) loop to optimize for normal case of returning bytes from d_buf */
1069 while (1) {
1070
1071 bleft = ftio->d_end - ftio->d_start;
1072
1073 /* enough bytes in d_buf to return a record? */
1074 if (bleft >= ftio->rec_size) {
1075
1076 boff = ftio->d_start;
1077 ftio->d_start += ftio->rec_size;
1078
1079 /* XXX check for interrupt record */
1080 /* ftio_interrupt(ftio); */
1081 /* continue */
1082
1083 ret = (char*)ftio->d_buf+boff;
1084 goto ftio_read_out;
1085
1086 /* no, perform a read() to try for more */
1087 } else {
1088
1089 /* move trailing partial record to top of buffer */
1090 if (bleft)
1091 bcopy(ftio->d_buf+ftio->d_start, ftio->d_buf, bleft);
1092
1093 ftio->d_end = bleft;
1094 ftio->d_start = 0;
1095
1096 n = read(ftio->fd, (char*)ftio->d_buf+ftio->d_end,
1097 FT_D_BUFSIZE - ftio->d_end);
1098
1099 /* read failed? */
1100 if (n < 0) {
1101 fterr_warn("read()");
1102 goto ftio_read_out;
1103 }
1104
1105 /* eof? */
1106 if (n == 0) {
1107 if (ftio->d_start)
1108 fterr_warnx("Warning, partial record before EOF");
1109 goto ftio_read_out;
1110 }
1111
1112 ftio->d_end += n;
1113
1114 } /* need a read() */
1115 } /* while 1 */
1116
1117 ftio_read_out:
1118
1119 if (ret) {
1120
1121 /* fix byte ordering */
1122 #if BYTE_ORDER == BIG_ENDIAN
1123 if (ftio->fth.byte_order == FT_HEADER_LITTLE_ENDIAN)
1124 ftio->swapf((void*)ret);
1125 #endif /* BYTE_ORDER == BIG_ENDIAN */
1126
1127 #if BYTE_ORDER == LITTLE_ENDIAN
1128 if (ftio->fth.byte_order == FT_HEADER_BIG_ENDIAN)
1129 ftio->swapf((void*)ret);
1130 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1131
1132 /* increment total records processed */
1133 ftio->rec_total ++;
1134
1135 /*
1136 * backwards compatability hack. Map the stream version 1 into
1137 * a stream version 2
1138 */
1139 if (ftio->fth.s_version == 1) {
1140
1141 if (ftio->fth.d_version == 1) {
1142
1143 compat = ret;
1144
1145 ftio->compat_v1.sysUpTime = 0;
1146 ftio->compat_v1.unix_secs = compat->unix_secs;
1147 ftio->compat_v1.unix_nsecs = compat->unix_msecs * 1000000;
1148 ftio->compat_v1.srcaddr = compat->srcaddr;
1149 ftio->compat_v1.dstaddr = compat->dstaddr;
1150 ftio->compat_v1.nexthop = compat->nexthop;
1151 ftio->compat_v1.input = compat->input;
1152 ftio->compat_v1.output = compat->output;
1153 ftio->compat_v1.dPkts = compat->dPkts;
1154 ftio->compat_v1.dOctets = compat->dOctets;
1155 ftio->compat_v1.Last = compat->Last;
1156 ftio->compat_v1.First = compat->First;
1157 ftio->compat_v1.srcport = compat->srcport;
1158 ftio->compat_v1.dstport = compat->dstport;
1159 ftio->compat_v1.prot = compat->prot;
1160 ftio->compat_v1.tos = compat->tos;
1161 ftio->compat_v1.tcp_flags = compat->flags;
1162
1163 ret = (void*)&ftio->compat_v1;
1164
1165 } else if (ftio->fth.d_version == 5) {
1166
1167 compat = ret;
1168
1169 ftio->compat_v5.sysUpTime = 0;
1170 ftio->compat_v5.unix_secs = compat->unix_secs;
1171 ftio->compat_v5.unix_nsecs = compat->unix_msecs * 1000000;
1172 ftio->compat_v5.srcaddr = compat->srcaddr;
1173 ftio->compat_v5.dstaddr = compat->dstaddr;
1174 ftio->compat_v5.nexthop = compat->nexthop;
1175 ftio->compat_v5.input = compat->input;
1176 ftio->compat_v5.output = compat->output;
1177 ftio->compat_v5.dPkts = compat->dPkts;
1178 ftio->compat_v5.dOctets = compat->dOctets;
1179 ftio->compat_v5.Last = compat->Last;
1180 ftio->compat_v5.First = compat->First;
1181 ftio->compat_v5.srcport = compat->srcport;
1182 ftio->compat_v5.dstport = compat->dstport;
1183 ftio->compat_v5.prot = compat->prot;
1184 ftio->compat_v5.tos = compat->tos;
1185 ftio->compat_v5.tcp_flags = compat->flags;
1186 ftio->compat_v5.src_as = compat->src_as;
1187 ftio->compat_v5.dst_as = compat->dst_as;
1188 ftio->compat_v5.src_mask = compat->src_mask;
1189 ftio->compat_v5.dst_mask = compat->dst_mask;
1190
1191 ret = (void*)&ftio->compat_v5;
1192
1193 } /* v5 compat */
1194 } /* need compat hack */
1195
1196 } /* ret is set */
1197
1198 return ret;
1199
1200 }
1201
1202 /*
1203 * function: ftio_write_header
1204 *
1205 * A ftio stream consists of a header and n records. ftio_write_header()
1206 * must be called before ftio_write() to output the header portion of
1207 * the stream
1208 *
1209 * Stream must be first initialized with ftio_init()
1210 *
1211 * returns: <0 error
1212 * >= 0 okay
1213 *
1214 */
ftio_write_header(struct ftio * ftio)1215 int ftio_write_header(struct ftio *ftio)
1216 {
1217 struct ftheader_gen head_gen;
1218 struct ftmap_ifname *ftmin;
1219 struct ftmap_ifalias *ftmia;
1220 uint32_t head_off_d;
1221 int n, ret, restore, flip, len;
1222 char *enc_buf;
1223
1224 ret = -1;
1225 restore = 0;
1226 enc_buf = (char*)0L;
1227
1228 /* if this is not the first time, rewind */
1229 if (ftio->flags & FT_IO_FLAG_HEADER_DONE) {
1230
1231 if (lseek(ftio->fd, (off_t)0L, SEEK_SET) == -1) {
1232 fterr_warn("lseek()");
1233 goto ftio_write_header_out;
1234 }
1235
1236 /* flag to seek back to end of file */
1237 restore = 1;
1238
1239 /* mark the file as complete. Assume that the second call to write_header
1240 * is actually the last
1241 */
1242 ftio->fth.flags |= FT_HEADER_FLAG_DONE;
1243
1244 }
1245
1246 ftio->fth.magic1 = FT_HEADER_MAGIC1;
1247 ftio->fth.magic2 = FT_HEADER_MAGIC2;
1248
1249 ftio->fth.s_version = 3;
1250
1251 if ((!ftio->fth.d_version) || (!ftio->fth.byte_order)) {
1252 fterr_warnx("Set d_version and byte_order first");
1253 goto ftio_write_header_out;
1254 }
1255
1256 if (!(ftio->flags & FT_IO_FLAG_WRITE)) {
1257 fterr_warnx("Stream not initialized for writing");
1258 goto ftio_write_header_out;
1259 }
1260
1261 #if BYTE_ORDER == BIG_ENDIAN
1262 if (ftio->fth.byte_order == FT_HEADER_LITTLE_ENDIAN)
1263 flip = 1;
1264 else
1265 flip = 0;
1266 #endif /* BYTE_ORDER == BIG_ENDIAN */
1267
1268 #if BYTE_ORDER == LITTLE_ENDIAN
1269 if (ftio->fth.byte_order == FT_HEADER_BIG_ENDIAN)
1270 flip = 1;
1271 else
1272 flip = 0;
1273 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1274
1275 /* max header size */
1276 len = FT_IO_MAXHEADER;
1277
1278 /* allocate encode buffer + extra 4 bytes to guarantee alignment */
1279 if (!(enc_buf = (char*)malloc(len+4))) {
1280 fterr_warn("malloc()");
1281 goto ftio_write_header_out;
1282 }
1283
1284 /* clear encode buffer */
1285 bzero(enc_buf, len+4);
1286
1287 head_gen.magic1 = ftio->fth.magic1;
1288 head_gen.magic2 = ftio->fth.magic2;
1289 head_gen.byte_order = ftio->fth.byte_order;
1290 head_gen.s_version = ftio->fth.s_version;
1291
1292 /* encode generic header */
1293 bcopy(&head_gen, enc_buf, sizeof head_gen);
1294
1295 /* leave room to encode head_off_d later */
1296 head_off_d = sizeof head_gen + sizeof head_off_d;
1297
1298 /*
1299 * encode each TLV
1300 */
1301
1302 if (ftio->fth.fields & FT_FIELD_VENDOR) {
1303 if ((n = fttlv_enc_uint8(enc_buf+head_off_d, len-head_off_d,
1304 flip, FT_TLV_VENDOR, ftio->fth.vendor)) < 0)
1305 goto ftio_write_header_out;
1306 else
1307 head_off_d += n;
1308 }
1309
1310 if (ftio->fth.fields & FT_FIELD_EX_VER) {
1311 if ((n = fttlv_enc_uint16(enc_buf+head_off_d, len-head_off_d,
1312 flip, FT_TLV_EX_VER, ftio->fth.d_version)) < 0)
1313 goto ftio_write_header_out;
1314 else
1315 head_off_d += n;
1316 }
1317
1318 if (ftio->fth.fields & FT_FIELD_AGG_VER) {
1319 if ((n = fttlv_enc_uint8(enc_buf+head_off_d, len-head_off_d,
1320 flip, FT_TLV_AGG_VER, ftio->fth.agg_version)) < 0)
1321 goto ftio_write_header_out;
1322 else
1323 head_off_d += n;
1324 }
1325
1326 if (ftio->fth.fields & FT_FIELD_AGG_METHOD) {
1327 if ((n = fttlv_enc_uint8(enc_buf+head_off_d, len-head_off_d,
1328 flip, FT_TLV_AGG_METHOD, ftio->fth.agg_method)) < 0)
1329 goto ftio_write_header_out;
1330 else
1331 head_off_d += n;
1332 }
1333
1334 if (ftio->fth.fields & FT_FIELD_EXPORTER_IP) {
1335 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1336 flip, FT_TLV_EXPORTER_IP, ftio->fth.exporter_ip)) < 0)
1337 goto ftio_write_header_out;
1338 else
1339 head_off_d += n;
1340 }
1341
1342 if (ftio->fth.fields & FT_FIELD_CAP_START) {
1343 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1344 flip, FT_TLV_CAP_START, ftio->fth.cap_start)) < 0)
1345 goto ftio_write_header_out;
1346 else
1347 head_off_d += n;
1348 }
1349
1350 if (ftio->fth.fields & FT_FIELD_CAP_END) {
1351 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1352 flip, FT_TLV_CAP_END, ftio->fth.cap_end)) < 0)
1353 goto ftio_write_header_out;
1354 else
1355 head_off_d += n;
1356 }
1357
1358 if (ftio->fth.fields & FT_FIELD_HEADER_FLAGS) {
1359 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1360 flip, FT_TLV_HEADER_FLAGS, ftio->fth.flags)) < 0)
1361 goto ftio_write_header_out;
1362 else
1363 head_off_d += n;
1364 }
1365
1366 if (ftio->fth.fields & FT_FIELD_ROT_SCHEDULE) {
1367 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1368 flip, FT_TLV_ROT_SCHEDULE, ftio->fth.rotation)) < 0)
1369 goto ftio_write_header_out;
1370 else
1371 head_off_d += n;
1372 }
1373
1374 if (ftio->fth.fields & FT_FIELD_FLOW_COUNT) {
1375 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1376 flip, FT_TLV_FLOW_COUNT, ftio->fth.flows_count)) < 0)
1377 goto ftio_write_header_out;
1378 else
1379 head_off_d += n;
1380 }
1381
1382 if (ftio->fth.fields & FT_FIELD_FLOW_LOST) {
1383 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1384 flip, FT_TLV_FLOW_LOST, ftio->fth.flows_lost)) < 0)
1385 goto ftio_write_header_out;
1386 else
1387 head_off_d += n;
1388 }
1389
1390 if (ftio->fth.fields & FT_FIELD_FLOW_MISORDERED) {
1391 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1392 flip, FT_TLV_FLOW_MISORDERED, ftio->fth.flows_misordered)) < 0)
1393 goto ftio_write_header_out;
1394 else
1395 head_off_d += n;
1396 }
1397
1398 if (ftio->fth.fields & FT_FIELD_PKT_CORRUPT) {
1399 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1400 flip, FT_TLV_PKT_CORRUPT, ftio->fth.pkts_corrupt)) < 0)
1401 goto ftio_write_header_out;
1402 else
1403 head_off_d += n;
1404 }
1405
1406 if (ftio->fth.fields & FT_FIELD_SEQ_RESET) {
1407 if ((n = fttlv_enc_uint32(enc_buf+head_off_d, len-head_off_d,
1408 flip, FT_TLV_SEQ_RESET, ftio->fth.seq_reset)) < 0)
1409 goto ftio_write_header_out;
1410 else
1411 head_off_d += n;
1412 }
1413
1414 if (ftio->fth.fields & FT_FIELD_CAP_HOSTNAME) {
1415 if ((n = fttlv_enc_str(enc_buf+head_off_d, len-head_off_d,
1416 flip, FT_TLV_CAP_HOSTNAME, ftio->fth.cap_hostname)) < 0)
1417 goto ftio_write_header_out;
1418 else
1419 head_off_d += n;
1420 }
1421
1422 if (ftio->fth.fields & FT_FIELD_COMMENTS) {
1423 if ((n = fttlv_enc_str(enc_buf+head_off_d, len-head_off_d,
1424 flip, FT_TLV_COMMENTS, ftio->fth.comments)) < 0)
1425 goto ftio_write_header_out;
1426 else
1427 head_off_d += n;
1428 }
1429
1430 if (ftio->fth.fields & FT_FIELD_IF_NAME) {
1431 FT_LIST_FOREACH(ftmin, &ftio->fth.ftmap->ifname, chain) {
1432 if ((n = fttlv_enc_ifname(enc_buf+head_off_d, len-head_off_d,
1433 flip, FT_TLV_IF_NAME, ftmin->ip, ftmin->ifIndex, ftmin->name)) < 0)
1434 goto ftio_write_header_out;
1435 else
1436 head_off_d += n;
1437 }
1438 }
1439
1440 if (ftio->fth.fields & FT_FIELD_IF_ALIAS) {
1441 FT_LIST_FOREACH(ftmia, &ftio->fth.ftmap->ifalias, chain) {
1442 if ((n = fttlv_enc_ifalias(enc_buf+head_off_d, len-head_off_d,
1443 flip, FT_TLV_IF_ALIAS, ftmia->ip, ftmia->ifIndex_list, ftmia->entries,
1444 ftmia->name)) < 0)
1445 goto ftio_write_header_out;
1446 else
1447 head_off_d += n;
1448 }
1449 }
1450
1451 /* head_off_d must be longword aligned */
1452 if (head_off_d & 0x00000003)
1453 head_off_d = (head_off_d & 0xFFFFFFFC) + 4;
1454
1455 /* if rewriting, ensure header area has not grown or shrunk */
1456 if (restore) {
1457 if (head_off_d != ftio->fth.size) {
1458 fterr_warnx("Header size change during rewrite not supported");
1459 goto ftio_write_header_out;
1460 }
1461 }
1462
1463 /* byte order of target */
1464 if (flip)
1465 SWAPINT32(head_off_d);
1466
1467 /* encode offset to data */
1468 bcopy(&head_off_d, enc_buf+sizeof head_gen, sizeof head_off_d);
1469
1470 /* restore */
1471 if (flip)
1472 SWAPINT32(head_off_d);
1473
1474 n = writen(ftio->fd, enc_buf, head_off_d);
1475
1476 if (n < 0) {
1477 fterr_warn("writen()");
1478 goto ftio_write_header_out;
1479 }
1480
1481 if (n == 0) {
1482 fterr_warnx("writen(): EOF");
1483 goto ftio_write_header_out;
1484 }
1485
1486 /* flag header has been written */
1487 ftio->flags |= FT_IO_FLAG_HEADER_DONE;
1488
1489 /* save write size */
1490 ftio->fth.size = head_off_d;
1491
1492 ret = n;
1493
1494 ftio_write_header_out:
1495
1496 if (restore) {
1497
1498 if (lseek(ftio->fd, (off_t)0L, SEEK_END) == -1) {
1499 fterr_warn("lseek()");
1500 }
1501
1502 }
1503
1504 if (enc_buf)
1505 free(enc_buf);
1506
1507 return ret;
1508
1509 }
1510
1511 /*
1512 * function: ftio_write
1513 *
1514 * Schedule fts3rec_* for output. ftio_write_header() must be called
1515 * on a stream before ftio_write(). If ftio_close() is not called
1516 * records may not be written.
1517 *
1518 * Stream must be first initialized with ftio_init()
1519 *
1520 * returns: <0 error
1521 * >= 0 okay
1522 *
1523 */
ftio_write(struct ftio * ftio,void * data)1524 int ftio_write(struct ftio *ftio, void *data)
1525 {
1526 int ret, n, nbytes;
1527
1528 ret = -1;
1529 nbytes = 0;
1530
1531 if (!(ftio->flags & FT_IO_FLAG_NO_SWAP)) {
1532 #if BYTE_ORDER == BIG_ENDIAN
1533 if (ftio->fth.byte_order == FT_HEADER_LITTLE_ENDIAN)
1534 ftio->swapf((void*)data);
1535 #endif /* BYTE_ORDER == BIG_ENDIAN */
1536
1537 #if BYTE_ORDER == LITTLE_ENDIAN
1538 if (ftio->fth.byte_order == FT_HEADER_BIG_ENDIAN)
1539 ftio->swapf((void*)data);
1540 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1541 }
1542
1543 /* compressed stream? */
1544 if (ftio->fth.flags & FT_HEADER_FLAG_COMPRESS) {
1545
1546 ftio->zs.next_in = (Bytef*)data;
1547 ftio->zs.avail_in = ftio->rec_size;
1548
1549 while (1) {
1550
1551 if (deflate(&ftio->zs, Z_NO_FLUSH) != Z_OK) {
1552 fterr_warnx("deflate(): failed");
1553 goto ftio_write_out;
1554 }
1555
1556 /* need to flush */
1557 if (!ftio->zs.avail_out) {
1558
1559 n = writen(ftio->fd, ftio->z_buf, FT_Z_BUFSIZE);
1560
1561 if (n < 0) {
1562 fterr_warn("writen()");
1563 goto ftio_write_out;
1564 }
1565
1566 if (n == 0) {
1567 fterr_warnx("writen(): EOF");
1568 goto ftio_write_out;
1569 }
1570
1571 ftio->zs.next_out = (Bytef*)ftio->z_buf;
1572 ftio->zs.avail_out = FT_Z_BUFSIZE;
1573
1574 nbytes += n;
1575
1576 ret = 0; /* success */
1577
1578 } else {
1579
1580 ret = 0; /* success */
1581 break;
1582
1583 }
1584
1585 } /* deflating */
1586
1587 /* no, uncompressed stream */
1588
1589 } else {
1590
1591 /* flush full buffer */
1592 if ((ftio->d_start + ftio->rec_size) > ftio->d_end) {
1593
1594 n = writen(ftio->fd, ftio->d_buf, ftio->d_start);
1595
1596 if (n < 0) {
1597 fterr_warn("writen()");
1598 goto ftio_write_out;
1599 }
1600
1601 if (n == 0) {
1602 fterr_warnx("writen(): EOF");
1603 goto ftio_write_out;
1604 }
1605
1606 ftio->d_start = 0;
1607
1608 nbytes += n;
1609
1610 }
1611
1612 bcopy(data, ftio->d_buf+ftio->d_start, ftio->rec_size);
1613
1614 ftio->d_start += ftio->rec_size;
1615
1616 ret = 0; /* success */
1617
1618 }
1619
1620 ftio_write_out:
1621
1622 if (!(ftio->flags & FT_IO_FLAG_NO_SWAP)) {
1623 #if BYTE_ORDER == BIG_ENDIAN
1624 if (ftio->fth.byte_order == FT_HEADER_LITTLE_ENDIAN)
1625 ftio->swapf((void*)data);
1626 #endif /* BYTE_ORDER == BIG_ENDIAN */
1627
1628 #if BYTE_ORDER == LITTLE_ENDIAN
1629 if (ftio->fth.byte_order == FT_HEADER_BIG_ENDIAN)
1630 ftio->swapf((void*)data);
1631 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1632 }
1633
1634 if (ret < 0)
1635 return ret;
1636 else
1637 return nbytes;
1638
1639 } /* ftio_write */
1640
strftime_tz(char * s,size_t max,const time_t timeval)1641 static size_t strftime_tz(char *s, size_t max, const time_t timeval) {
1642 struct tm tm_struct;
1643
1644 return strftime(s, max, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&timeval, &tm_struct));
1645 }
1646
fprintf_time(FILE * std,char * format,char cc,const time_t timeval)1647 static void fprintf_time(FILE *std, char *format, char cc, const time_t timeval) {
1648 char timebuf[128];
1649
1650 strftime_tz(timebuf, sizeof(timebuf), timeval);
1651
1652 fprintf(std, format, cc, timebuf);
1653 }
1654
1655 /*
1656 * function: ftio_header_print
1657 *
1658 * Dump ftio header in readable format
1659 *
1660 * Stream must be first initialized with ftio_init()
1661 *
1662 */
ftio_header_print(struct ftio * ftio,FILE * std,char cc)1663 void ftio_header_print(struct ftio *ftio, FILE *std, char cc)
1664 {
1665 struct ftiheader *fth;
1666 struct ftmap_ifname *ftmin;
1667 struct ftmap_ifalias *ftmia;
1668 char agg_ver, agg_method;
1669 char *agg_name;
1670 char fmt_buf[32];
1671 uint32_t flags, fields;
1672 uint32_t period;
1673 int n, streaming2;
1674
1675 fth = &ftio->fth;
1676
1677 fields = ftio->fth.fields;
1678
1679 if (fields & FT_FIELD_HEADER_FLAGS)
1680 flags = ftio->fth.flags;
1681 else
1682 flags = 0;
1683
1684 streaming2 = (flags & FT_HEADER_FLAG_STREAMING);
1685 if (flags & FT_HEADER_FLAG_PRELOADED)
1686 streaming2 = 0;
1687
1688 if (flags & FT_HEADER_FLAG_STREAMING)
1689 fprintf(std, "%c\n%c mode: streaming\n", cc, cc);
1690 else
1691 fprintf(std, "%c\n%c mode: normal\n", cc, cc);
1692
1693 if (flags & FT_HEADER_FLAG_XLATE)
1694 fprintf(std, "%c translated: yes\n", cc);
1695
1696 if (!(flags & FT_HEADER_FLAG_STREAMING))
1697 if (fields & FT_FIELD_CAP_HOSTNAME)
1698 fprintf(std, "%c capture hostname: %s\n", cc, fth->cap_hostname);
1699
1700 if (!(flags & FT_HEADER_FLAG_STREAMING)) {
1701 if (fields & FT_FIELD_EXPORTER_IP) {
1702 fmt_ipv4(fmt_buf, fth->exporter_ip, FMT_JUST_LEFT);
1703 fprintf(std, "%c exporter IP address: %s\n", cc, fmt_buf);
1704 }
1705 }
1706
1707 if ((!streaming2) && (fields & FT_FIELD_CAP_START))
1708 fprintf_time(std, "%c capture start: %s\n", cc, ftio_get_cap_start_time_t(ftio));
1709
1710 if (!streaming2) {
1711 if ((flags & FT_HEADER_FLAG_DONE) || (flags & FT_HEADER_FLAG_PRELOADED)) {
1712 if (fields & FT_FIELD_CAP_END)
1713 fprintf_time(std, "%c capture end: %s\n", cc, ftio_get_cap_end_time_t(ftio));
1714
1715 if ((fields & FT_FIELD_CAP_END) && (fields & FT_FIELD_CAP_START)) {
1716 period = fth->cap_end - fth->cap_start;
1717 fprintf(std, "%c capture period: %" PRIu32 " seconds\n", cc, period);
1718 }
1719 }
1720 }
1721
1722 fprintf(std, "%c compress: %s\n", cc,
1723 (flags & FT_HEADER_FLAG_COMPRESS) ? "on" : "off");
1724
1725 fprintf(std, "%c byte order: ", cc);
1726 if (fth->byte_order == FT_HEADER_LITTLE_ENDIAN)
1727 fprintf(std, "little\n");
1728 else if (fth->byte_order == FT_HEADER_BIG_ENDIAN)
1729 fprintf(std, "big\n");
1730 else
1731 fprintf(std, "BROKEN\n");
1732
1733 /*
1734 if (!(flags & FT_HEADER_FLAG_STREAMING))
1735 fprintf(std, "%c multiple pdu types: %s\n", cc,
1736 (fth->flags & FT_HEADER_FLAG_MULT_PDU) ? "yes" : "no");
1737 */
1738
1739 fprintf(std, "%c stream version: %u\n", cc, (int)fth->s_version);
1740
1741 if (fields & FT_FIELD_EX_VER)
1742 fprintf(std, "%c export version: %u\n", cc, (int)fth->d_version);
1743
1744 if ((fields & FT_FIELD_EX_VER) && (fields & FT_FIELD_AGG_METHOD)) {
1745
1746 if (fth->d_version == 8) {
1747
1748 agg_ver = ftio->fth.agg_version;
1749 agg_method = ftio->fth.agg_method;
1750
1751 switch (agg_method) {
1752
1753 case 1:
1754 agg_name = "AS";
1755 break;
1756
1757 case 2:
1758 agg_name = "Protocol Port";
1759 break;
1760
1761 case 3:
1762 agg_name = "Source Prefix";
1763 break;
1764
1765 case 4:
1766 agg_name = "Destination Prefix";
1767 break;
1768
1769 case 5:
1770 agg_name = "Prefix";
1771 break;
1772
1773 case 6:
1774 agg_name = "Destination";
1775 break;
1776
1777 case 7:
1778 agg_name = "Source Destination";
1779 break;
1780
1781 case 8:
1782 agg_name = "Full Flow";
1783 break;
1784
1785 case 9:
1786 agg_name = "ToS AS";
1787 break;
1788
1789 case 10:
1790 agg_name = "ToS Proto Port";
1791 break;
1792
1793 case 11:
1794 agg_name = "ToS Source Prefix";
1795 break;
1796
1797 case 12:
1798 agg_name = "ToS Destination Prefix";
1799 break;
1800
1801 case 13:
1802 agg_name = "ToS Prefix";
1803 break;
1804
1805 case 14:
1806 agg_name = "ToS Prefix Port";
1807 break;
1808
1809 default:
1810 agg_name = "Unknown";
1811
1812 } /* switch */
1813
1814 if (fields & FT_FIELD_AGG_VER)
1815 fprintf(std, "%c export agg_version: %u\n", cc, (int)agg_ver);
1816
1817 fprintf(std, "%c export agg_method: %u (%s)\n", cc, (int)agg_method,
1818 agg_name);
1819
1820 }
1821 }
1822
1823 if (!streaming2)
1824 if (fields & FT_FIELD_FLOW_LOST)
1825 fprintf(std, "%c lost flows: %" PRIu32 "\n", cc,
1826 (uint32_t)fth->flows_lost);
1827
1828 if (!streaming2)
1829 if (fields & FT_FIELD_FLOW_MISORDERED)
1830 fprintf(std,
1831 "%c misordered flows: %" PRIu32 "\n", cc, (uint32_t)fth->flows_misordered);
1832
1833 if (!streaming2)
1834 if (fields & FT_FIELD_PKT_CORRUPT)
1835 fprintf(std,
1836 "%c corrupt packets: %" PRIu32 "\n", cc, (uint32_t)fth->pkts_corrupt);
1837
1838 if (!streaming2)
1839 if (fields & FT_FIELD_SEQ_RESET)
1840 fprintf(std,
1841 "%c sequencer resets: %" PRIu32 "\n", cc, (uint32_t)fth->seq_reset);
1842
1843 if (fields & FT_FIELD_COMMENTS)
1844 fprintf(std, "%c comments: %s\n", cc, fth->comments);
1845
1846 if (!streaming2) {
1847
1848 if ((flags & FT_HEADER_FLAG_DONE) || (flags & FT_HEADER_FLAG_PRELOADED)) {
1849
1850 if (fields & FT_FIELD_FLOW_COUNT)
1851 fprintf(std, "%c capture flows: %lu\n", cc,
1852 (unsigned long)fth->flows_count);
1853
1854 } else
1855 fprintf(std, "%c note, incomplete flow file\n", cc);
1856 }
1857
1858 if (fields & FT_FIELD_IF_NAME) {
1859 fprintf(std, "%c\n", cc);
1860 FT_LIST_FOREACH(ftmin, &fth->ftmap->ifname, chain) {
1861 fmt_ipv4(fmt_buf, ftmin->ip, FMT_JUST_LEFT);
1862 fprintf(std, "%c ifname %s %d %s\n", cc, fmt_buf, (int)ftmin->ifIndex,
1863 ftmin->name);
1864 }
1865 } /* FT_FIELD_IF_NAME */
1866
1867 if (fields & FT_FIELD_IF_ALIAS) {
1868 fprintf(std, "%c\n", cc);
1869 FT_LIST_FOREACH(ftmia, &fth->ftmap->ifalias, chain) {
1870 fmt_ipv4(fmt_buf, ftmia->ip, FMT_JUST_LEFT);
1871 fprintf(std, "%c ifalias %s ", cc, fmt_buf);
1872 for (n = 0; n < ftmia->entries; ++n)
1873 fprintf(std, "%d ", (int)ftmia->ifIndex_list[n]);
1874 fprintf(std, "%s\n", ftmia->name);
1875 }
1876 } /* FT_FIELD_IF_ALIAS */
1877
1878 fprintf(std, "%c\n", cc);
1879
1880 } /* ftio_header_print */
1881
1882 /*
1883 * function: ftio_rec_swapfunc
1884 *
1885 * Return the function required to swap a record. Used to create
1886 * jump table based on the d_version and agg_method
1887 *
1888 */
ftio_rec_swapfunc(struct ftio * ftio)1889 void *ftio_rec_swapfunc(struct ftio *ftio)
1890 {
1891
1892 uint8_t s_ver, d_ver, agg_ver, agg_method;
1893 void *ret;
1894
1895 s_ver = ftio->fth.s_version;
1896 d_ver = ftio->fth.d_version;
1897
1898 agg_ver = ftio->fth.agg_version;
1899 agg_method = ftio->fth.agg_method;
1900
1901 switch (s_ver) {
1902
1903 case 1:
1904 ret = fts1rec_swap_compat;
1905 break;
1906
1907 case 3:
1908 switch (ftio->fth.d_version) {
1909
1910 case 1:
1911 ret = fts3rec_swap_v1;
1912 break;
1913
1914 case 5:
1915 ret = fts3rec_swap_v5;
1916 break;
1917
1918 case 6:
1919 ret = fts3rec_swap_v6;
1920 break;
1921
1922 case 7:
1923 ret = fts3rec_swap_v7;
1924 break;
1925
1926 case 8:
1927 if (agg_ver != 2) {
1928 fterr_warnx("Unsupported agg_version %d", (int)agg_ver);
1929 ret = (void*)0L;
1930 break;
1931 }
1932
1933 switch (agg_method) {
1934
1935 case 1:
1936 ret = fts3rec_swap_v8_1;
1937 break;
1938
1939 case 2:
1940 ret = fts3rec_swap_v8_2;
1941 break;
1942
1943 case 3:
1944 ret = fts3rec_swap_v8_3;
1945 break;
1946
1947 case 4:
1948 ret = fts3rec_swap_v8_4;
1949 break;
1950
1951 case 5:
1952 ret = fts3rec_swap_v8_5;
1953 break;
1954
1955 case 6:
1956 ret = fts3rec_swap_v8_6;
1957 break;
1958
1959 case 7:
1960 ret = fts3rec_swap_v8_7;
1961 break;
1962
1963 case 8:
1964 ret = fts3rec_swap_v8_8;
1965 break;
1966
1967 case 9:
1968 ret = fts3rec_swap_v8_9;
1969 break;
1970
1971 case 10:
1972 ret = fts3rec_swap_v8_10;
1973 break;
1974
1975 case 11:
1976 ret = fts3rec_swap_v8_11;
1977 break;
1978
1979 case 12:
1980 ret = fts3rec_swap_v8_12;
1981 break;
1982
1983 case 13:
1984 ret = fts3rec_swap_v8_13;
1985 break;
1986
1987 case 14:
1988 ret = fts3rec_swap_v8_14;
1989 break;
1990
1991 default:
1992 fterr_warnx("Unsupported agg_method %d", (int)agg_method);
1993 ret = (void*)0L;
1994 break;
1995
1996 } /* switch agg_method */
1997 break;
1998
1999 case 1005:
2000 ret = fts3rec_swap_v1005;
2001 break;
2002
2003 default:
2004 fterr_warnx("Unsupported d_version %d", (int)ftio->fth.d_version);
2005 ret = (void*)0L;
2006 break;
2007
2008 } /* switch v8 export */
2009 break;
2010
2011 default:
2012 fterr_warnx("Unsupported s_version %d", (int)s_ver);
2013 ret = (void*)0L;
2014 break;
2015
2016 } /* switch s_version */
2017
2018 return ret;
2019
2020 }
2021
2022 /*
2023 * function: ftrec_size
2024 *
2025 * Return the size of a fts3rec_* based on the d_version and agg_method
2026 *
2027 */
ftrec_size(struct ftver * ver)2028 int ftrec_size(struct ftver *ver)
2029 {
2030
2031 int ret;
2032
2033 switch (ver->s_version) {
2034
2035 case 1:
2036 ret = sizeof (struct fts1rec_compat);
2037 break;
2038
2039 case 3:
2040 switch (ver->d_version) {
2041
2042 case 1:
2043 ret = sizeof (struct fts3rec_v1);
2044 break;
2045
2046 case 5:
2047 ret = sizeof (struct fts3rec_v5);
2048 break;
2049
2050 case 6:
2051 ret = sizeof (struct fts3rec_v6);
2052 break;
2053
2054 case 7:
2055 ret = sizeof (struct fts3rec_v7);
2056 break;
2057
2058 case 8:
2059 if (ver->agg_version != 2) {
2060 fterr_warnx("Unsupported agg_version %d", (int)ver->agg_version);
2061 ret = -1;
2062 break;
2063 }
2064
2065 switch (ver->agg_method) {
2066
2067 case 1:
2068 ret = sizeof (struct fts3rec_v8_1);
2069 break;
2070
2071 case 2:
2072 ret = sizeof (struct fts3rec_v8_2);
2073 break;
2074
2075 case 3:
2076 ret = sizeof (struct fts3rec_v8_3);
2077 break;
2078
2079 case 4:
2080 ret = sizeof (struct fts3rec_v8_4);
2081 break;
2082
2083 case 5:
2084 ret = sizeof (struct fts3rec_v8_5);
2085 break;
2086
2087 case 6:
2088 ret = sizeof (struct fts3rec_v8_6);
2089 break;
2090
2091 case 7:
2092 ret = sizeof (struct fts3rec_v8_7);
2093 break;
2094
2095 case 8:
2096 ret = sizeof (struct fts3rec_v8_8);
2097 break;
2098
2099 case 9:
2100 ret = sizeof (struct fts3rec_v8_9);
2101 break;
2102
2103 case 10:
2104 ret = sizeof (struct fts3rec_v8_10);
2105 break;
2106
2107 case 11:
2108 ret = sizeof (struct fts3rec_v8_11);
2109 break;
2110
2111 case 12:
2112 ret = sizeof (struct fts3rec_v8_12);
2113 break;
2114
2115 case 13:
2116 ret = sizeof (struct fts3rec_v8_13);
2117 break;
2118
2119 case 14:
2120 ret = sizeof (struct fts3rec_v8_14);
2121 break;
2122
2123 default:
2124 fterr_warnx("Unsupported agg_method %d", (int)ver->agg_method);
2125 ret = -1;
2126 break;
2127
2128 } /* switch agg_method */
2129 break;
2130
2131 case 1005:
2132 ret = sizeof (struct fts3rec_v1005);
2133 break;
2134
2135 default:
2136 fterr_warnx("Unsupported d_version %d", (int)ver->d_version);
2137 ret = -1;
2138 break;
2139
2140 } /* switch v8 export */
2141 break;
2142
2143 default:
2144 fterr_warnx("Unsupported s_version %d", (int)ver->s_version);
2145 ret = -1;
2146 break;
2147
2148 } /* switch s_version */
2149
2150 return ret;
2151
2152 }
2153
2154 /*
2155 * function: ftrec_xfield
2156 *
2157 * Return the FT_XFIELD* based on the d_version and agg_method
2158 *
2159 */
ftrec_xfield(struct ftver * ver)2160 uint64_t ftrec_xfield(struct ftver *ver)
2161 {
2162
2163 uint64_t ret;
2164
2165 switch (ver->d_version) {
2166
2167 case 1:
2168 ret = FT_XFIELD_V1_MASK;
2169 break;
2170
2171 case 5:
2172 ret = FT_XFIELD_V5_MASK;
2173 break;
2174
2175 case 6:
2176 ret = FT_XFIELD_V6_MASK;
2177 break;
2178
2179 case 7:
2180 ret = FT_XFIELD_V7_MASK;
2181 break;
2182
2183 case 8:
2184 if (ver->agg_version != 2) {
2185 fterr_warnx("Unsupported agg_version %d", (int)ver->agg_version);
2186 ret = -1;
2187 break;
2188 }
2189
2190 switch (ver->agg_method) {
2191
2192 case 1:
2193 ret = FT_XFIELD_V8_1_MASK;
2194 break;
2195
2196 case 2:
2197 ret = FT_XFIELD_V8_2_MASK;
2198 break;
2199
2200 case 3:
2201 ret = FT_XFIELD_V8_3_MASK;
2202 break;
2203
2204 case 4:
2205 ret = FT_XFIELD_V8_4_MASK;
2206 break;
2207
2208 case 5:
2209 ret = FT_XFIELD_V8_5_MASK;
2210 break;
2211
2212 case 6:
2213 ret = FT_XFIELD_V8_6_MASK;
2214 break;
2215
2216 case 7:
2217 ret = FT_XFIELD_V8_7_MASK;
2218 break;
2219
2220 case 8:
2221 ret = FT_XFIELD_V8_8_MASK;
2222 break;
2223
2224 case 9:
2225 ret = FT_XFIELD_V8_9_MASK;
2226 break;
2227
2228 case 10:
2229 ret = FT_XFIELD_V8_10_MASK;
2230 break;
2231
2232 case 11:
2233 ret = FT_XFIELD_V8_11_MASK;
2234 break;
2235
2236 case 12:
2237 ret = FT_XFIELD_V8_12_MASK;
2238 break;
2239
2240 case 13:
2241 ret = FT_XFIELD_V8_13_MASK;
2242 break;
2243
2244 case 14:
2245 ret = FT_XFIELD_V8_14_MASK;
2246 break;
2247
2248 default:
2249 fterr_warnx("Unsupported agg_method %d", (int)ver->agg_method);
2250 ret = -1;
2251 break;
2252
2253 } /* switch agg_method */
2254 break;
2255
2256 case 1005:
2257 ret = FT_XFIELD_V1005_MASK;
2258 break;
2259
2260 default:
2261 fterr_warnx("Unsupported d_version %d", (int)ver->d_version);
2262 ret = -1;
2263 break;
2264
2265 } /* switch v8 export */
2266
2267 return ret;
2268
2269 } /* ftrec_xfield */
2270
2271 /*
2272 * function: ftio_xfield
2273 *
2274 * Return the FT_XFIELD*
2275 *
2276 */
ftio_xfield(struct ftio * ftio)2277 uint64_t ftio_xfield(struct ftio *ftio)
2278 {
2279 struct ftver ver;
2280
2281 ver.d_version = ftio->fth.d_version;
2282 ver.s_version = ftio->fth.s_version;
2283 ver.agg_method = ftio->fth.agg_method;
2284 ver.agg_version = ftio->fth.agg_version;
2285
2286 return ftrec_xfield(&ver);
2287 }
2288
2289 /*
2290 * function: ftio_rec_size
2291 *
2292 * Return the size of a fts3rec_* based on the initialized ftio
2293 * stream.
2294 *
2295 */
ftio_rec_size(struct ftio * ftio)2296 int ftio_rec_size(struct ftio *ftio)
2297 {
2298 struct ftver ver;
2299
2300 ver.d_version = ftio->fth.d_version;
2301 ver.s_version = ftio->fth.s_version;
2302 ver.agg_method = ftio->fth.agg_method;
2303 ver.agg_version = ftio->fth.agg_version;
2304
2305 return ftrec_size(&ver);
2306
2307 } /* ftio_rec_size */
2308
2309
2310 /*
2311 * function: ftiheader_read
2312 *
2313 * load a ftheader, possibly converting from an older version
2314 *
2315 * header is returned in host byte order
2316 *
2317 * returns: <0 error
2318 * >= 0 okay
2319 */
ftiheader_read(int fd,struct ftiheader * ihead)2320 int ftiheader_read(int fd, struct ftiheader *ihead)
2321 {
2322 struct fts1header *h1;
2323 struct ftheader_gen head_gen;
2324 struct fttlv tlv;
2325 struct ftmap_ifname *ftmin;
2326 struct ftmap_ifalias *ftmia;
2327 int n, ret, len_read, len_buf, off, flip, left;
2328 uint32_t ip;
2329 uint16_t entries, ifIndex, *ifIndex_list;
2330 uint32_t head_off_d;
2331 char *dp, *c, *enc_buf;
2332
2333 ret = -1;
2334 enc_buf = (char*)0L;
2335 ifIndex_list = (uint16_t*)0L;
2336 bzero(ihead, sizeof (struct ftiheader));
2337
2338 /* read the stream header version area */
2339 if ((n = readn(fd, (char*)&head_gen, sizeof head_gen)) < 0) {
2340 fterr_warn("read()");
2341 goto ftiheader_read_out;
2342 }
2343
2344 if (n != sizeof head_gen) {
2345 fterr_warnx(
2346 "ftiheader_read(): Warning, short read while loading header top.");
2347 goto ftiheader_read_out;
2348 }
2349
2350 /* verify magic */
2351 if ((head_gen.magic1 != FT_HEADER_MAGIC1) ||
2352 (head_gen.magic2 != FT_HEADER_MAGIC2)) {
2353 fterr_warnx("ftiheader_read(): Warning, bad magic number");
2354 goto ftiheader_read_out;
2355 }
2356
2357 #if BYTE_ORDER == BIG_ENDIAN
2358 if (head_gen.byte_order == FT_HEADER_LITTLE_ENDIAN)
2359 flip = 1;
2360 else
2361 flip = 0;
2362 #endif /* BYTE_ORDER == BIG_ENDIAN */
2363
2364 #if BYTE_ORDER == LITTLE_ENDIAN
2365 if (head_gen.byte_order == FT_HEADER_BIG_ENDIAN)
2366 flip = 1;
2367 else
2368 flip = 0;
2369 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
2370
2371
2372 /* determine how many bytes to read */
2373 if (head_gen.s_version == 1) {
2374
2375 /* v1 header size static */
2376 len_read = (sizeof (struct fts1header)) - sizeof head_gen;
2377 len_buf = sizeof (struct fts1header);
2378
2379 } else if (head_gen.s_version == 3) {
2380
2381 /* read the version 3 index */
2382 if ((n = readn(fd, (char*)&head_off_d, sizeof head_off_d)) < 0) {
2383 fterr_warn("read()");
2384 goto ftiheader_read_out;
2385 }
2386
2387 if (n != sizeof head_off_d) {
2388 fterr_warnx(
2389 "ftiheader_read(): Error, short read while loading header data offset.");
2390 goto ftiheader_read_out;
2391 }
2392
2393 /* data offset must be in host byte order */
2394 if (flip)
2395 SWAPINT32(head_off_d);
2396
2397 /* v3 dynamic header size */
2398 len_read = head_off_d - sizeof head_gen - sizeof head_off_d;
2399 len_buf = len_read + sizeof head_gen + sizeof head_off_d;
2400
2401 } else {
2402 fterr_warnx("Stream format must be 1 or 3, not %d",
2403 (int)head_gen.s_version);
2404 goto ftiheader_read_out;
2405 }
2406
2407 /* allocate storage for decode */
2408 if (!(enc_buf = (char*)malloc(len_buf))) {
2409 fterr_warn("malloc()");
2410 goto ftiheader_read_out;
2411 }
2412
2413 ihead->enc_len = len_buf;
2414
2415 /* insert the generic part to the top of the buffer */
2416 bcopy(&head_gen, enc_buf, sizeof head_gen);
2417 off = sizeof head_gen;
2418
2419 /* for version 3 insert the data offset */
2420 if (head_gen.s_version == 3) {
2421 bcopy(&head_off_d, enc_buf+off, sizeof head_off_d);
2422 off += sizeof head_off_d;
2423 }
2424
2425 /* read the rest of the header */
2426 if ((n = readn(fd, (char*)enc_buf+off, len_read)) < 0) {
2427 fterr_warn("read()");
2428 goto ftiheader_read_out;
2429 }
2430
2431 if (n != len_read) {
2432 fterr_warnx("Short read while loading header");
2433 goto ftiheader_read_out;
2434 }
2435
2436 /* v1 header? yes, convert it directly to internal format */
2437 if (head_gen.s_version == 1) {
2438
2439 h1 = (struct fts1header*) enc_buf;
2440
2441 ihead->magic1 = h1->magic1;
2442 ihead->magic2 = h1->magic2;
2443 ihead->byte_order = h1->byte_order;
2444 ihead->s_version = h1->s_version;
2445 ihead->d_version = h1->d_version;
2446 ihead->cap_start = h1->start;
2447 ihead->cap_end = h1->end;
2448 ihead->flags = h1->flags;
2449 ihead->rotation = h1->rotation;
2450 ihead->flows_count = h1->nflows;
2451 ihead->flows_lost = h1->pdu_drops;
2452 ihead->flows_misordered = h1->pdu_misordered;
2453
2454 /* translated from v1 */
2455 ihead->flags |= FT_HEADER_FLAG_XLATE;
2456
2457 ihead->fields = FT_FIELD_VENDOR | FT_FIELD_EX_VER | FT_TLV_CAP_START |
2458 FT_TLV_CAP_END | FT_FIELD_HEADER_FLAGS | FT_FIELD_ROT_SCHEDULE |
2459 FT_FIELD_FLOW_COUNT;
2460
2461 /* convert to host byte order */
2462 if (flip) {
2463 SWAPINT16(ihead->d_version);
2464 SWAPINT32(ihead->cap_start);
2465 SWAPINT32(ihead->cap_end);
2466 SWAPINT32(ihead->flags);
2467 SWAPINT32(ihead->rotation);
2468 SWAPINT32(ihead->flows_count);
2469 SWAPINT32(ihead->exporter_ip);
2470 SWAPINT32(ihead->flows_lost);
2471 SWAPINT32(ihead->flows_misordered);
2472 SWAPINT32(ihead->pkts_corrupt);
2473 SWAPINT32(ihead->seq_reset);
2474 } /* flip */
2475
2476 if (h1->hostname[0]) {
2477
2478 if (!(ihead->cap_hostname = (char*)malloc(FT_HEADER1_HN_LEN))) {
2479 fterr_warn("malloc()");
2480 goto ftiheader_read_out;
2481 }
2482
2483 strcpy(ihead->cap_hostname, h1->hostname);
2484
2485 ihead->fields |= FT_FIELD_CAP_HOSTNAME;
2486
2487 }
2488
2489 if (h1->comments[0]) {
2490
2491 if (!(ihead->comments = (char*)malloc(FT_HEADER1_CMNT_LEN))) {
2492 fterr_warn("malloc()");
2493 goto ftiheader_read_out;
2494 }
2495
2496 strcpy(ihead->comments, h1->comments);
2497
2498 ihead->fields |= FT_FIELD_COMMENTS;
2499
2500 }
2501
2502
2503 } else if (head_gen.s_version == 3) {
2504
2505 /* set decode pointer to first tlv */
2506 dp = enc_buf + sizeof head_gen + sizeof head_off_d;
2507 left = len_read;
2508
2509 /* copy generic header to internal */
2510 ihead->magic1 = head_gen.magic1;
2511 ihead->magic2 = head_gen.magic2;
2512 ihead->byte_order = head_gen.byte_order;
2513 ihead->s_version = head_gen.s_version;
2514
2515 /* smallest TLV is 2+2+0 (null TLV). Don't try to read padding added
2516 * for alignment.
2517 */
2518 while (left >= 4) {
2519
2520 /* parse type, store in host byte order */
2521 bcopy(dp, &tlv.t, 2);
2522 if (flip)
2523 SWAPINT16(tlv.t);
2524 dp += 2;
2525 left -= 2;
2526
2527 /* parse len, store in host byte order */
2528 bcopy(dp, &tlv.l, 2);
2529 if (flip)
2530 SWAPINT16(tlv.l);
2531 dp += 2;
2532 left -= 2;
2533
2534 /* parse val */
2535 tlv.v = dp;
2536
2537 /* point decode buf at next tlv */
2538 dp += tlv.l;
2539 left -= tlv.l;
2540
2541 /* TLV length sane? */
2542 if (left < 0)
2543 break;
2544
2545 switch (tlv.t) {
2546
2547 case FT_TLV_NULL:
2548 break;
2549
2550 case FT_TLV_VENDOR:
2551 bcopy(tlv.v, &ihead->vendor, 2);
2552 if (flip) SWAPINT16(ihead->vendor);
2553 ihead->fields |= FT_FIELD_VENDOR;
2554 break;
2555
2556 case FT_TLV_EX_VER:
2557 bcopy(tlv.v, &ihead->d_version, 2);
2558 if (flip) SWAPINT16(ihead->d_version);
2559 ihead->fields |= FT_FIELD_EX_VER;
2560 break;
2561
2562 case FT_TLV_AGG_VER:
2563 bcopy(tlv.v, &ihead->agg_version, 1);
2564 ihead->fields |= FT_FIELD_AGG_VER;
2565 break;
2566
2567 case FT_TLV_AGG_METHOD:
2568 bcopy(tlv.v, &ihead->agg_method, 1);
2569 ihead->fields |= FT_FIELD_AGG_METHOD;
2570 break;
2571
2572 case FT_TLV_EXPORTER_IP:
2573 bcopy(tlv.v, &ihead->exporter_ip, 4);
2574 if (flip) SWAPINT32(ihead->exporter_ip);
2575 ihead->fields |= FT_FIELD_EXPORTER_IP;
2576 break;
2577
2578 case FT_TLV_CAP_START:
2579 bcopy(tlv.v, &ihead->cap_start, 4);
2580 if (flip) SWAPINT32(ihead->cap_start);
2581 ihead->fields |= FT_FIELD_CAP_START;
2582 break;
2583
2584 case FT_TLV_CAP_END:
2585 bcopy(tlv.v, &ihead->cap_end, 4);
2586 if (flip) SWAPINT32(ihead->cap_end);
2587 ihead->fields |= FT_FIELD_CAP_END;
2588 break;
2589
2590 case FT_TLV_HEADER_FLAGS:
2591 bcopy(tlv.v, &ihead->flags, 4);
2592 if (flip) SWAPINT32(ihead->flags);
2593 ihead->fields |= FT_FIELD_HEADER_FLAGS;
2594 break;
2595
2596 case FT_TLV_ROT_SCHEDULE:
2597 bcopy(tlv.v, &ihead->rotation, 4);
2598 if (flip) SWAPINT32(ihead->rotation);
2599 ihead->fields |= FT_FIELD_ROT_SCHEDULE;
2600 break;
2601
2602 case FT_TLV_FLOW_COUNT:
2603 bcopy(tlv.v, &ihead->flows_count, 4);
2604 if (flip) SWAPINT32(ihead->flows_count);
2605 ihead->fields |= FT_FIELD_FLOW_COUNT;
2606 break;
2607
2608 case FT_TLV_FLOW_LOST:
2609 bcopy(tlv.v, &ihead->flows_lost, 4);
2610 if (flip) SWAPINT32(ihead->flows_lost);
2611 ihead->fields |= FT_FIELD_FLOW_LOST;
2612 break;
2613
2614 case FT_TLV_FLOW_MISORDERED:
2615 bcopy(tlv.v, &ihead->flows_misordered, 4);
2616 if (flip) SWAPINT32(ihead->flows_misordered);
2617 ihead->fields |= FT_FIELD_FLOW_MISORDERED;
2618 break;
2619
2620 case FT_TLV_PKT_CORRUPT:
2621 bcopy(tlv.v, &ihead->pkts_corrupt, 4);
2622 if (flip) SWAPINT32(ihead->pkts_corrupt);
2623 ihead->fields |= FT_FIELD_PKT_CORRUPT;
2624 break;
2625
2626 case FT_TLV_SEQ_RESET:
2627 bcopy(tlv.v, &ihead->seq_reset, 4);
2628 if (flip) SWAPINT32(ihead->seq_reset);
2629 ihead->fields |= FT_FIELD_SEQ_RESET;
2630 break;
2631
2632 case FT_TLV_CAP_HOSTNAME:
2633 if (!(ihead->cap_hostname = (char*)malloc(tlv.l))) {
2634 fterr_warn("malloc()");
2635 goto ftiheader_read_out;
2636 }
2637 strcpy(ihead->cap_hostname, tlv.v);
2638 ihead->fields |= FT_FIELD_CAP_HOSTNAME;
2639 break;
2640
2641 case FT_TLV_COMMENTS:
2642 if (!(ihead->comments = (char*)malloc(tlv.l))) {
2643 fterr_warn("malloc()");
2644 goto ftiheader_read_out;
2645 }
2646 strcpy(ihead->comments, tlv.v);
2647 ihead->fields |= FT_FIELD_COMMENTS;
2648 break;
2649
2650 case FT_TLV_IF_NAME:
2651 if (!ihead->ftmap) {
2652 if (!(ihead->ftmap = ftmap_new())) {
2653 fterr_warnx("ftmap_new(): failed");
2654 goto ftiheader_read_out;
2655 }
2656 }
2657
2658 ihead->fields |= FT_FIELD_IF_NAME;
2659
2660 /* decode the value */
2661 bcopy(tlv.v, &ip, 4);
2662 if (flip) SWAPINT32(ip);
2663 bcopy(tlv.v+4, &ifIndex, 2);
2664 if (flip) SWAPINT32(ifIndex);
2665 c = tlv.v+6;
2666
2667 /* allocate space for a ifname */
2668 if (!(ftmin = ftmap_ifname_new(ip, ifIndex, c))) {
2669 fterr_warnx("ftmap_ifname_new(): failed");
2670 goto ftiheader_read_out;
2671 }
2672
2673 /* and link it in */
2674 FT_LIST_INSERT_HEAD(&ihead->ftmap->ifname, ftmin, chain);
2675 break;
2676
2677 case FT_TLV_IF_ALIAS:
2678 if (!ihead->ftmap) {
2679 if (!(ihead->ftmap = ftmap_new())) {
2680 fterr_warnx("ftmap_new(): failed");
2681 goto ftiheader_read_out;
2682 }
2683 }
2684 ihead->fields |= FT_FIELD_IF_ALIAS;
2685
2686 /* decode the value */
2687 bcopy(tlv.v, &ip, 4);
2688 if (flip) SWAPINT32(ip);
2689 bcopy(tlv.v+4, &entries, 2);
2690 if (flip) SWAPINT32(entries);
2691 c = tlv.v+6 + (entries*2);
2692
2693 if (!(ifIndex_list = (uint16_t*)malloc(entries*2))) {
2694 fterr_warn("malloc()");
2695 goto ftiheader_read_out;
2696 }
2697
2698 bcopy(tlv.v+6, ifIndex_list, entries*2);
2699
2700 /* allocate space for a ifname */
2701 if (!(ftmia = ftmap_ifalias_new(ip, ifIndex_list, entries, c))) {
2702 fterr_warnx("ftmap_ifalias_new(): failed");
2703 goto ftiheader_read_out;
2704 }
2705
2706 free(ifIndex_list);
2707 ifIndex_list = (uint16_t*)0L;
2708
2709 /* and link it in */
2710 FT_LIST_INSERT_HEAD(&ihead->ftmap->ifalias, ftmia, chain);
2711 break;
2712
2713 default:
2714 break;
2715
2716 } /* switch */
2717
2718 } /* while */
2719
2720 } /* s_version == 3 */
2721
2722 ret = 0;
2723
2724 ftiheader_read_out:
2725
2726 if (ifIndex_list)
2727 free(ifIndex_list);
2728
2729 if (enc_buf)
2730 free(enc_buf);
2731
2732 return ret;
2733
2734 } /* ftiheader_read */
2735
2736
2737 /*
2738 * function: ftio_check_generic
2739 *
2740 * check if this io stream can be used with the ftstrec_gen
2741 * pseudo record. fts3rec_gen overlays the common fields of
2742 * v1, v5, v6, and v7 formats
2743 *
2744 * returns: <0 error
2745 * >= 0 okay
2746 */
ftio_check_generic(struct ftio * ftio)2747 int ftio_check_generic(struct ftio *ftio)
2748 {
2749 struct ftver ver;
2750
2751 ftio_get_ver(ftio, &ver);
2752
2753 if ((ver.d_version != 1) &&
2754 (ver.d_version != 5) &&
2755 (ver.d_version != 6) &&
2756 (ver.d_version != 7)) {
2757 fterr_warnx("Export version %d not supported by format",
2758 (int)ver.d_version);
2759 return -1;
2760 }
2761
2762 return 0;
2763 } /* ftio_check_generic */
2764
2765 /*
2766 * function: ftio_check_generic5
2767 *
2768 * check if this io stream can be used with the ftstrec_gen
2769 * pseudo record. fts3rec_gen overlays the common fields of
2770 * v5, v6, and v7 formats
2771 *
2772 * returns: <0 error
2773 * >= 0 okay
2774 */
ftio_check_generic5(struct ftio * ftio)2775 int ftio_check_generic5(struct ftio *ftio)
2776 {
2777 struct ftver ver;
2778
2779 ftio_get_ver(ftio, &ver);
2780
2781 if ((ver.d_version != 5) &&
2782 (ver.d_version != 6) &&
2783 (ver.d_version != 7)) {
2784 fterr_warnx("Export version %d not supported by format",
2785 (int)ver.d_version);
2786 return -1;
2787 }
2788
2789 return 0;
2790 } /* ftio_check_generic5 */
2791
2792 /*
2793 * function: ftltime
2794 *
2795 * Flow exports represent time with a combination of uptime of the
2796 * router, real time, and offsets from the router uptime. ftltime
2797 * converts from the PDU to a standard unix seconds/milliseconds
2798 * representation
2799 *
2800 * returns: struct fttime
2801 */
ftltime(uint32_t sys,uint32_t secs,uint32_t nsecs,uint32_t t)2802 struct fttime ftltime(uint32_t sys, uint32_t secs, uint32_t nsecs, uint32_t t)
2803 {
2804
2805 const uint64_t real_t = secs * (uint64_t) 1000 + nsecs / 1000000 - sys + t;
2806 const struct fttime ftt = {
2807 .secs = real_t / 1000,
2808 .msecs = real_t % 1000
2809 };
2810
2811 return ftt;
2812
2813 } /* ftltime */
2814
2815 /*
2816 * function: ftset_init
2817 *
2818 * initialize default settings
2819 *
2820 * returns: initialized ftset
2821 */
ftset_init(struct ftset * ftset,int z_level)2822 void ftset_init(struct ftset *ftset, int z_level)
2823 {
2824
2825 bzero(ftset, sizeof (struct ftset));
2826 ftset->z_level = z_level;
2827
2828 #if BYTE_ORDER == BIG_ENDIAN
2829 ftset->byte_order = FT_HEADER_BIG_ENDIAN;
2830 #endif /* BYTE_ORDER == BIG_ENDIAN */
2831 #if BYTE_ORDER == LITTLE_ENDIAN
2832 ftset->byte_order = FT_HEADER_LITTLE_ENDIAN;
2833 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
2834
2835 } /* ftset_init */
2836
ftio_map_load(struct ftio * ftio,char * fname,uint32_t ip)2837 int ftio_map_load(struct ftio *ftio, char *fname, uint32_t ip)
2838 {
2839
2840 /* load the map */
2841 if (!(ftio->fth.ftmap = ftmap_load(fname, ip))) {
2842 fterr_warnx("ftmap_load(): failed");
2843 return -1;
2844 }
2845
2846 ftio->fth.fields |= FT_FIELD_IF_NAME | FT_FIELD_IF_ALIAS;
2847
2848 return 0;
2849
2850 } /* ftio_map_load */
2851
ftio_interrupt(struct ftio * ftio,uint32_t fields)2852 int ftio_interrupt(struct ftio *ftio, uint32_t fields)
2853 {
2854 struct ftmap_ifname *ftmin;
2855 struct ftmap_ifalias *ftmia;
2856 uint32_t offset, oflag;
2857 char *enc_buf, *rec_buf;
2858 int len, n, ret, flip;
2859
2860 enc_buf = rec_buf = (char*)0L;
2861 ret = -1;
2862
2863 /* disable ftio_write() from swapping bytes */
2864 oflag = ftio->flags;
2865 ftio->flags |= FT_IO_FLAG_NO_SWAP;
2866
2867 /* allocate space for TLV's */
2868 if (!(enc_buf = (char*)malloc(FT_IO_MAXHEADER))) {
2869 fterr_warnx("malloc()");
2870 goto ftio_interrupt_out;
2871 }
2872
2873 /* allocate space for fake flow record */
2874 if (!(rec_buf = (char*)malloc(ftio->rec_size))) {
2875 fterr_warnx("malloc()");
2876 goto ftio_interrupt_out;
2877 }
2878
2879 #if BYTE_ORDER == BIG_ENDIAN
2880 if (ftio->fth.byte_order == FT_HEADER_LITTLE_ENDIAN)
2881 flip = 1;
2882 else
2883 flip = 0;
2884 #endif /* BYTE_ORDER == BIG_ENDIAN */
2885
2886 #if BYTE_ORDER == LITTLE_ENDIAN
2887 if (ftio->fth.byte_order == FT_HEADER_BIG_ENDIAN)
2888 flip = 1;
2889 else
2890 flip = 0;
2891 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
2892
2893 offset = 0;
2894 len = FT_IO_MAXHEADER;
2895
2896 if (fields & FT_FIELD_IF_NAME) {
2897 FT_LIST_FOREACH(ftmin, &ftio->fth.ftmap->ifname, chain) {
2898 if ((n = fttlv_enc_ifname(enc_buf+offset, len-offset,
2899 flip, FT_TLV_IF_NAME, ftmin->ip, ftmin->ifIndex, ftmin->name)) < 0)
2900 goto ftio_interrupt_out;
2901 else
2902 offset += n;
2903 }
2904 }
2905
2906 if (fields & FT_FIELD_IF_ALIAS) {
2907 FT_LIST_FOREACH(ftmia, &ftio->fth.ftmap->ifalias, chain) {
2908 if ((n = fttlv_enc_ifalias(enc_buf+offset, len-offset,
2909 flip, FT_TLV_IF_ALIAS, ftmia->ip, ftmia->ifIndex_list, ftmia->entries,
2910 ftmia->name)) < 0)
2911 goto ftio_interrupt_out;
2912 else
2913 offset += n;
2914 }
2915 }
2916
2917 if (ftio->fth.fields & FT_FIELD_INTERRUPT) {
2918 if ((n = fttlv_enc_uint8(enc_buf+offset, len-offset,
2919 flip, FT_TLV_INTERRUPT, (uint8_t)0)) < 0)
2920 goto ftio_interrupt_out;
2921 else
2922 offset += n;
2923 }
2924
2925 /* bytes 0-15 are 0xFF */
2926 memset(enc_buf, 0xFF, (size_t)16);
2927
2928 if (flip)
2929 SWAPINT32(offset);
2930
2931 /* bytes 16-20 of interrupt flow record are the bytes to follow */
2932 bcopy(enc_buf+16, &offset, 4);
2933
2934 if (flip)
2935 SWAPINT32(offset);
2936
2937 /* schedule the interrupt record for writing */
2938 if (ftio_write(ftio, rec_buf) < 0) {
2939 fterr_warnx("ftio_write(): failed");
2940 goto ftio_interrupt_out;
2941 }
2942
2943 ret = 0;
2944
2945 ftio_interrupt_out:
2946
2947 /* restore ftio->flags */
2948 ftio->flags = oflag;
2949
2950 if (enc_buf)
2951 free(enc_buf);
2952
2953 if (rec_buf)
2954 free(rec_buf);
2955
2956 return ret;
2957
2958 } /* ftio_interrupt */
2959
2960 /*
2961 * function: ftio_check_xfield
2962 *
2963 * Check if xfield_need bits are available in stream
2964 *
2965 * returns: 0 ok
2966 * != fail - a field required is not available.
2967 */
ftio_check_xfield(struct ftio * ftio,uint64_t xfield_need)2968 int ftio_check_xfield(struct ftio *ftio, uint64_t xfield_need)
2969 {
2970
2971 if ((xfield_need & ftio->xfield) != xfield_need)
2972 return -1;
2973 else
2974 return 0;
2975
2976 } /* ftio_xfields */
2977
2978