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