Skip to Content
[CAIDA - Cooperative Association for Internet Data Analysis logo]
The Cooperative Association for Internet Data Analysis
corsaro_io.c
1 /*
2  * corsaro
3  *
4  * Alistair King, CAIDA, UC San Diego
5  * corsaro-info@caida.org
6  *
7  * Copyright (C) 2012 The Regents of the University of California.
8  *
9  * This file is part of corsaro.
10  *
11  * corsaro is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * corsaro is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with corsaro. If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25 
26 #include "config.h"
27 #include "corsaro_int.h"
28 
29 #include <assert.h>
30 #include <inttypes.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "corsaro.h"
35 #include "corsaro_file.h"
36 #include "corsaro_log.h"
37 #include "corsaro_plugin.h"
38 #include "utils.h"
39 
40 /* plugin headers */
41 #ifdef WITH_PLUGIN_DIST
42 #include "corsaro_distributions.h"
43 #endif
44 #ifdef WITH_PLUGIN_SIXT
45 #include "corsaro_flowtuple.h"
46 #endif
47 #ifdef WITH_PLUGIN_DOS
48 #include "corsaro_dos.h"
49 #endif
50 
51 #include "corsaro_io.h"
52 #include "corsaro_plugin.h"
53 
55 typedef struct output_funcs
56 {
57  int (*headers)(corsaro_t *corsaro, corsaro_file_t *file,
58  corsaro_header_t *header);
59  int (*interval_start)(corsaro_t *corsaro, corsaro_file_t *file,
60  corsaro_interval_t *int_start);
61  int (*interval_end)(corsaro_t *corsaro, corsaro_file_t *file,
62  corsaro_interval_t *int_end);
63  int (*plugin_start)(corsaro_t *corsaro, corsaro_file_t *file,
64  corsaro_plugin_t *plugin);
65  int (*plugin_end)(corsaro_t *corsaro, corsaro_file_t *file,
66  corsaro_plugin_t *plugin);
67  int (*trailers)(corsaro_t *corsaro, corsaro_file_t *file,
68  corsaro_trailer_t *trailer);
69 } output_funcs_t;
70 
71 #define GENERATE_OUTPUT_FUNCS(o) \
72  {output_headers_##o, output_interval_start_##o, output_interval_end_##o, \
73  output_plugin_start_##o, output_plugin_end_##o, output_trailers_##o}
74 
75 #define GENERATE_OUTPUT_FUNC_PROTOS(o) \
76  static int output_headers_##o(corsaro_t *corsaro, corsaro_file_t *file,\
77  corsaro_header_t *header); \
78  static int output_interval_start_##o(corsaro_t *corsaro, \
79  corsaro_file_t *file, \
80  corsaro_interval_t *int_start); \
81  static int output_interval_end_##o(corsaro_t *corsaro, \
82  corsaro_file_t *file, \
83  corsaro_interval_t *int_end); \
84  static int output_plugin_start_##o(corsaro_t *corsaro, corsaro_file_t *file, \
85  corsaro_plugin_t *plugin); \
86  static int output_plugin_end_##o(corsaro_t *corsaro, corsaro_file_t *file, \
87  corsaro_plugin_t *plugin); \
88  static int output_trailers_##o(corsaro_t *corsaro, corsaro_file_t *file,\
89  corsaro_trailer_t *trailer);
90 
91 GENERATE_OUTPUT_FUNC_PROTOS(ascii);
92 GENERATE_OUTPUT_FUNC_PROTOS(binary);
93 
94 static output_funcs_t output_funcs[] = {
95  GENERATE_OUTPUT_FUNCS(ascii), /* CORSARO_FILE_MODE_ASCII */
96  GENERATE_OUTPUT_FUNCS(binary), /* CORSARO_FILE_MODE_BINARY */
97  {NULL}, /* CORSARO_FILE_MODE_TRACE */
98 };
99 
100 
101 /*
102  * print_headers
103  *
104  * prints the global corsaro details which appear at the head of the output
105  * file
106  */
107 static int output_headers_ascii(corsaro_t *corsaro, corsaro_file_t *file,
108  corsaro_header_t *header)
109 {
110  corsaro_plugin_t *tmp = NULL;
111  uint32_t bytes_out = 0;
112 
113  corsaro_header_t *ph = NULL;
115 
116  int i;
117 
118  if(header == NULL)
119  {
120  h.version_major = CORSARO_MAJOR_VERSION;
121  h.version_minor = CORSARO_MINOR_VERSION;
122  h.local_init_time = corsaro->init_time.tv_sec;
123  h.interval_length = corsaro->interval;
124  h.traceuri = (uint8_t*)corsaro->uridata;
125 
126  ph = &h;
127  }
128  else
129  {
130  ph = header;
131  }
132 
133 
134  bytes_out += corsaro_file_printf(corsaro, file,
135  "# CORSARO_VERSION %"PRIu8".%"PRIu8"\n",
136  ph->version_major, ph->version_minor);
137  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_INITTIME %ld\n",
138  ph->local_init_time);
139  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_INTERVAL %d\n",
140  ph->interval_length);
141  if(ph->traceuri != NULL)
142  {
143  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_TRACEURI %s\n",
144  ph->traceuri);
145  }
146 
147  if(header == NULL)
148  {
149  while((tmp = corsaro_plugin_next(corsaro->plugin_manager, tmp)) != NULL)
150  {
151  bytes_out += corsaro_file_printf(corsaro, file,
152  "# CORSARO_PLUGIN %s\n",
153  tmp->name);
154  }
155  }
156  else
157  {
158  for(i=0;i<header->plugin_cnt;i++)
159  {
160  bytes_out += corsaro_file_printf(corsaro, file,
161  "# CORSARO_PLUGIN %s\n",
162  corsaro_plugin_get_name(corsaro->plugin_manager,
163  header->plugin_ids[i]));
164  }
165  }
166 
167  return bytes_out;
168 }
169 
170 static int output_headers_binary(corsaro_t *corsaro, corsaro_file_t *file,
171  corsaro_header_t *header)
172 {
173  corsaro_plugin_t *p = NULL;
174  uint8_t fbuffer[CORSARO_IO_HEADER_FIXED_BYTE_LEN];
175  uint8_t *ptr = &fbuffer[0];
176  uint16_t tmp_len;
177  uint8_t tmp[2];
178 
179  uint32_t bytes_out = 0;
180 
181  /* magic numbers */
182  bytes_htonl(ptr, CORSARO_MAGIC);
183  ptr+=4;
184  bytes_htonl(ptr, CORSARO_MAGIC_HEADER);
185  ptr+=4;
186 
187  /* version */
188  *ptr = CORSARO_MAJOR_VERSION;
189  ptr++;
190  *ptr = CORSARO_MID_VERSION;
191  ptr++;
192 
193  /* init time */
194  bytes_htonl(ptr, corsaro->init_time.tv_sec);
195  ptr+=4;
196 
197  /* interval length */
198  bytes_htons(ptr, corsaro->interval);
199 
200  if(corsaro_file_write(corsaro, file, &fbuffer[0],
203  {
204  corsaro_log(__func__, corsaro, "could not dump byte array to file");
205  return -1;
206  }
207 
209 
210  /* the traceuri */
211  if(corsaro->uridata != NULL)
212  {
213  tmp_len = strlen(corsaro->uridata);
214  bytes_htons(&tmp[0], tmp_len);
215  if(corsaro_file_write(corsaro, file, &tmp[0], 2) != 2)
216  {
217  corsaro_log(__func__, corsaro, "could not dump traceuri length to file");
218  return -1;
219  }
220  if(corsaro_file_write(corsaro, file, corsaro->uridata, tmp_len) != tmp_len)
221  {
222  corsaro_log(__func__, corsaro, "could not dump traceuri string to file");
223  return -1;
224  }
225  bytes_out += 2 + tmp_len;
226  }
227  else
228  {
229  memset(&tmp[0], 0, 2);
230  if(corsaro_file_write(corsaro, file, &tmp[0], 2) != 2)
231  {
232  corsaro_log(__func__, corsaro, "could not dump zero traceuri length to file");
233  return -1;
234  }
235  bytes_out += 2;
236  }
237 
238  /* the plugin list */
239  bytes_htons(&tmp[0], corsaro->plugin_manager->plugins_cnt);
240  if(corsaro_file_write(corsaro, file, &tmp[0], 2) != 2)
241  {
242  corsaro_log(__func__, corsaro, "could not dump plugins cnt to file");
243  return -1;
244  }
245  bytes_out += 2;
246 
247  while((p = corsaro_plugin_next(corsaro->plugin_manager, p)) != NULL)
248  {
249  bytes_htons(&tmp[0], p->id);
250  if(corsaro_file_write(corsaro, file, &tmp[0], 2) != 2)
251  {
252  corsaro_log(__func__, corsaro, "could not dump plugin id to file");
253  return -1;
254  }
255  bytes_out += 2;
256  }
257 
258  return bytes_out;
259 }
260 
261 /*
262  * output_interval
263  *
264  * prints data for the interval which is about to be completed.
265  */
266 static int output_interval_start_ascii(corsaro_t *corsaro, corsaro_file_t *file,
267  corsaro_interval_t *int_start)
268 {
269  return corsaro_file_printf(corsaro, file,
270  "# CORSARO_INTERVAL_START %d %ld\n",
271  int_start->number, int_start->time);
272 }
273 
274 static int output_interval_end_ascii(corsaro_t *corsaro, corsaro_file_t *file,
275  corsaro_interval_t *int_end)
276 {
277  return corsaro_file_printf(corsaro, file,
278  "# CORSARO_INTERVAL_END %d %ld\n",
279  int_end->number,
280  int_end->time);
281 }
282 
283 static int write_interval_header_binary(corsaro_t * corsaro, corsaro_file_t *file,
285 {
286  corsaro_interval_t nint;
287 
288 #if 0
290  uint8_t *iptr = &ibuff[0];
291 
292  /* interval header */
293  bytes_htonl(iptr, CORSARO_MAGIC);
294  iptr+=4;
295  bytes_htonl(iptr, CORSARO_MAGIC_INTERVAL);
296  iptr+=4;
297  bytes_htons(iptr, corsaro->interval_cnt);
298  iptr+=2;
299  bytes_htonl(iptr, tv.tv_sec);
300 
301  if(corsaro_file_write(corsaro, file, &ibuff[0],
304  {
305  corsaro_log(__func__, corsaro, "could not dump interval header to file");
306  return -1;
307  }
309  #endif
310 
311  /* byte flip all the fields */
312  nint.corsaro_magic = htonl(interval->corsaro_magic);
313  nint.magic = htonl(interval->magic);
314  nint.number = htons(interval->number);
315  nint.time = htonl(interval->time);
316 
317  if(corsaro_file_write(corsaro, file, &nint, sizeof(corsaro_interval_t)) !=
318  sizeof(corsaro_interval_t))
319  {
320  corsaro_log(__func__, corsaro, "could not dump interval header to file");
321  return -1;
322  }
323 
324  return sizeof(corsaro_interval_t);
325 }
326 
327 static int output_interval_start_binary(corsaro_t *corsaro, corsaro_file_t *file,
328  corsaro_interval_t *int_start)
329 {
330  return write_interval_header_binary(corsaro, file, int_start);
331 }
332 
333 static int output_interval_end_binary(corsaro_t *corsaro, corsaro_file_t *file,
334  corsaro_interval_t *int_end)
335 {
336  return write_interval_header_binary(corsaro, file, int_end);
337 }
338 
339 static int output_plugin_start_ascii(corsaro_t *corsaro, corsaro_file_t *file,
340  corsaro_plugin_t *plugin)
341 {
342  return corsaro_file_printf(corsaro, file,
343  "# CORSARO_PLUGIN_DATA_START %s\n",
344  plugin->name);
345 }
346 
347 static int output_plugin_end_ascii(corsaro_t *corsaro, corsaro_file_t *file,
348  corsaro_plugin_t *plugin)
349 {
350  return corsaro_file_printf(corsaro, file,
351  "# CORSARO_PLUGIN_DATA_END %s\n",
352  plugin->name);
353 }
354 
355 static int write_plugin_header_binary(corsaro_t *corsaro, corsaro_file_t *file,
356  corsaro_plugin_t *plugin)
357 {
359  uint8_t *idptr = &idbuff[0];
360 
361  bytes_htonl(idptr, CORSARO_MAGIC);
362  idptr+=4;
363 
364  bytes_htonl(idptr, CORSARO_MAGIC_DATA);
365  idptr+=4;
366 
367  bytes_htons(idptr, plugin->id);
368  if(corsaro_file_write(corsaro, file, &idbuff[0],
371  {
372  corsaro_log(__func__, corsaro, "could not dump interval data header to file");
373  return -1;
374  }
376 }
377 
378 static int output_plugin_start_binary(corsaro_t *corsaro, corsaro_file_t *file,
379  corsaro_plugin_t *plugin)
380 {
381  return write_plugin_header_binary(corsaro, file, plugin);
382 }
383 
384 static int output_plugin_end_binary(corsaro_t *corsaro, corsaro_file_t *file,
385  corsaro_plugin_t *plugin)
386 {
387  return write_plugin_header_binary(corsaro, file, plugin);
388 }
389 
390 /*
391  * print_trailers
392  *
393  * prints the global corsaro details which appear at the tail of the output
394  * file (when corsaro_finalize has been called)
395  */
396 static int output_trailers_ascii(corsaro_t *corsaro, corsaro_file_t *file,
397  corsaro_trailer_t *trailer)
398 {
399  struct timeval ts;
400  uint32_t bytes_out = 0;
401  gettimeofday_wrap(&ts);
402 
403  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_PACKETCNT %"PRIu64"\n",
404  corsaro->packet_cnt);
405  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_FIRSTPKT %ld\n",
406  corsaro->first_ts.tv_sec);
407  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_LASTPKT %ld\n",
408  corsaro->last_ts.tv_sec);
409  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_FINALTIME %ld\n",
410  ts.tv_sec);
411  bytes_out += corsaro_file_printf(corsaro, file, "# CORSARO_RUNTIME %ld\n",
412  ts.tv_sec-corsaro->init_time.tv_sec);
413 
414  corsaro_log(__func__, corsaro, "pkt cnt: %"PRIu64, corsaro->packet_cnt);
415 
416  return bytes_out;
417 }
418 
419 static int output_trailers_binary(corsaro_t *corsaro, corsaro_file_t *file,
420  corsaro_trailer_t *trailer)
421 {
422  uint8_t buff[CORSARO_IO_TRAILER_BYTE_LEN];
423  uint8_t *ptr = &buff[0];
424 
425  struct timeval ts;
426  gettimeofday_wrap(&ts);
427 
428  bytes_htonl(ptr, CORSARO_MAGIC);
429  ptr+=4;
430 
431  bytes_htonl(ptr, CORSARO_MAGIC_TRAILER);
432  ptr+=4;
433 
434  bytes_htonll(ptr, corsaro->packet_cnt);
435  ptr+=8;
436 
437  bytes_htonl(ptr, corsaro->first_ts.tv_sec);
438  ptr+=4;
439 
440  bytes_htonl(ptr, corsaro->last_ts.tv_sec);
441  ptr+=4;
442 
443  bytes_htonl(ptr, ts.tv_sec);
444  ptr+=4;
445 
446  bytes_htonl(ptr, ts.tv_sec-corsaro->init_time.tv_sec);
447 
448  if(corsaro_file_write(corsaro, file, &buff[0], CORSARO_IO_TRAILER_BYTE_LEN) !=
450  {
451  corsaro_log(__func__, corsaro, "could not dump trailers to file");
452  return -1;
453  }
454 
455  corsaro_log(__func__, corsaro, "pkt cnt: %"PRIu64, corsaro->packet_cnt);
457 }
458 
459 static char *generate_file_name(corsaro_t *corsaro, const char *plugin,
460  corsaro_file_compress_t compress)
461 {
462  size_t new_size;
463  char *new_name = NULL;
464  char *ptr;
465  char *tmpl;
466 
467  assert(corsaro->template != NULL && strlen(corsaro->template) >=
468  strlen(CORSARO_IO_PLUGIN_PATTERN));
469  assert(plugin != NULL && strlen(plugin) > 0);
470 
471  new_size = strlen(corsaro->template) - strlen(CORSARO_IO_PLUGIN_PATTERN) +
472  strlen(plugin) + 1;
473 
474  if((ptr = new_name = malloc(new_size)) == NULL)
475  {
476  corsaro_log(__func__, corsaro, "could not malloc output file name");
477  return NULL;
478  }
479 
480  /* copy the template up to pattern into the new string */
481  if((tmpl = strstr(corsaro->template, CORSARO_IO_PLUGIN_PATTERN)) == NULL)
482  {
483  corsaro_log(__func__, corsaro, "template (%s) does not contain pattern!",
484  corsaro->template);
485  return NULL;
486  }
487  strncpy(ptr, corsaro->template, tmpl-corsaro->template);
488  ptr += tmpl-corsaro->template;
489 
490  /* copy the plugin name into the new string */
491  strncpy(ptr, plugin, strlen(plugin));
492  ptr += strlen(plugin);
493 
494  /* skip past the template */
495  tmpl += strlen(CORSARO_IO_PLUGIN_PATTERN);
496 
497  /* copy the remainder of the template */
498  strncpy(ptr, tmpl, strlen(tmpl));
499 
500  new_name[new_size-1] = '\0';
501 
502  if(compress == CORSARO_FILE_COMPRESS_NONE)
503  {
504  /* try and be kind and fix the suffix of the file if no compression has
505  been asked for. if you call a file xxx.gz and ask for bzip, well,
506  suffer. */
507  /* this is actually most useful for corsaro_log to allow it to open
508  an uncompressed log file when the user has asked for compressed files */
509 
510  ptr = new_name+(new_size-1-strlen(CORSARO_FILE_ZLIB_SUFFIX));
511 
512  if(strncmp(ptr, CORSARO_FILE_ZLIB_SUFFIX, strlen(CORSARO_FILE_ZLIB_SUFFIX))
513  == 0)
514  {
515  /* remove the .gz from the end of the string */
516  *ptr = '\0';
517  }
518  else
519  {
520  ptr = new_name+(new_size-1-strlen(CORSARO_FILE_BZ2_SUFFIX));
521  if(strncmp(ptr, CORSARO_FILE_BZ2_SUFFIX, strlen(CORSARO_FILE_BZ2_SUFFIX))
522  == 0)
523  {
524  /* remove the .bz2 from the end of the string */
525  *ptr = '\0';
526  }
527  }
528  }
529 
530  return new_name;
531 }
532 
533 static int validate_header_static(corsaro_header_t *h)
534 {
535  /* WARNING: do not try and access past traceuri_len */
536 
537  /* byteswap the values */
538  h->corsaro_magic = ntohl(h->corsaro_magic);
539  h->magic = ntohl(h->magic);
540  h->local_init_time = ntohl(h->local_init_time);
541  h->interval_length = ntohs(h->interval_length);
542  h->traceuri_len = ntohs(h->traceuri_len);
543 
544  /* do some sanity checking on the interval */
545  if(h->corsaro_magic != CORSARO_MAGIC ||
547  {
548  return 0;
549  }
550  return 1;
551 }
552 
553 static int validate_interval(corsaro_interval_t *interval)
554 {
555  /* byteswap the values */
556  interval->corsaro_magic = ntohl(interval->corsaro_magic);
557  interval->magic = ntohl(interval->magic);
558  interval->number = ntohs(interval->number);
559  interval->time = ntohl(interval->time);
560 
561  /* do some sanity checking on the interval */
562  if(interval->corsaro_magic != CORSARO_MAGIC ||
563  interval->magic != CORSARO_MAGIC_INTERVAL)
564  {
565  return 0;
566  }
567  return 1;
568 }
569 
570 static int validate_plugin_data(corsaro_plugin_data_t *pd)
571 {
572  /* byteswap the values */
573  pd->corsaro_magic = ntohl(pd->corsaro_magic);
574  pd->magic = ntohl(pd->magic);
575  pd->plugin_id = ntohs(pd->plugin_id);
576 
577  /* do some sanity checking on the interval */
578  if(pd->corsaro_magic != CORSARO_MAGIC ||
579  pd->magic != CORSARO_MAGIC_DATA)
580  {
581  return 0;
582  }
583  return 1;
584 }
585 
586 static int validate_trailer(corsaro_trailer_t *t)
587 {
588  /* WARNING: do not try and access past traceuri_len */
589 
590  /* byteswap the values */
591  t->corsaro_magic = ntohl(t->corsaro_magic);
592  t->magic = ntohl(t->magic);
593  t->packet_cnt = ntohll(t->packet_cnt);
594  t->first_packet_time = ntohl(t->first_packet_time);
595  t->last_packet_time = ntohl(t->last_packet_time);
596  t->local_final_time = ntohl(t->local_final_time);
597  t->runtime = ntohl(t->runtime);
598 
599  /* do some sanity checking on the interval */
600  if(t->corsaro_magic != CORSARO_MAGIC ||
601  t->magic != CORSARO_MAGIC_TRAILER)
602  {
603  return 0;
604  }
605  return 1;
606 }
607 
608 off_t read_plugin_data(corsaro_in_t *corsaro,
609  corsaro_file_in_t *file,
610  corsaro_in_record_type_t *record_type,
611  corsaro_in_record_t *record)
612 {
613  off_t bread = -1;
614  if((bread = corsaro_io_read_bytes(corsaro, record,
615  sizeof(corsaro_plugin_data_t))) !=
616  sizeof(corsaro_plugin_data_t))
617  {
618  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
619  return -1;
620  }
621 
622  if(validate_plugin_data((corsaro_plugin_data_t *)record->buffer) != 1)
623  {
624  corsaro_log_in(__func__, corsaro, "could not validate plugin data");
625  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
626  return -1;
627  }
628 
629  assert(bread == sizeof(corsaro_plugin_data_t));
630  return bread;
631 }
632 
633 /* == EXPORTED FUNCTIONS BELOW THIS POINT == */
634 
635 corsaro_file_t *corsaro_io_prepare_file(corsaro_t *corsaro, const char *plugin_name)
636 {
637  return corsaro_io_prepare_file_full(corsaro, plugin_name, corsaro->output_mode,
638  corsaro->compress, corsaro->compress_level,
639  O_CREAT);
640 }
641 
642 corsaro_file_t *corsaro_io_prepare_file_full(corsaro_t *corsaro,
643  const char *plugin_name,
644  corsaro_file_mode_t mode,
645  corsaro_file_compress_t compress,
646  int compress_level,
647  int flags)
648 {
649  corsaro_file_t *f = NULL;
650  char *outfileuri;
651 
652  /* generate a file name based on the plugin name */
653  if((outfileuri = generate_file_name(corsaro, plugin_name, compress)) == NULL)
654  {
655  corsaro_log(__func__, corsaro, "could not generate file name for %s", plugin_name);
656  return NULL;
657  }
658 
659  if((f = corsaro_file_open(corsaro,
660  outfileuri,
661  mode,
662  compress,
663  compress_level,
664  flags)) == NULL)
665  {
666  corsaro_log(__func__, corsaro, "could not open %s for writing", outfileuri);
667  return NULL;
668  }
669 
670  free(outfileuri);
671  return f;
672 }
673 
674 int corsaro_io_validate_template(corsaro_t *corsaro, char *template)
675 {
676  /* be careful using corsaro here, it is likely not initialized fully */
677 
678  /* check for length first */
679  if(template == NULL)
680  {
681  corsaro_log(__func__, corsaro, "output template must be set");
682  return 0;
683  }
684 
685  if(strlen(template) < strlen(CORSARO_IO_PLUGIN_PATTERN))
686  {
687  corsaro_log(__func__, corsaro, "template is too short to contain needed fields",
689  return 0;
690  }
691 
692  /* check that the plugin pattern is in the template */
693  if(strstr(template, CORSARO_IO_PLUGIN_PATTERN) == NULL)
694  {
695  corsaro_log(__func__, corsaro, "template string must contain %s",
697  return 0;
698  }
699 
700  /* we're good! */
701  return 1;
702 }
703 
704 off_t corsaro_io_write_header(corsaro_t *corsaro, corsaro_file_t *file,
705  corsaro_header_t *header)
706 {
707  assert(CORSARO_FILE_MODE(file) == CORSARO_FILE_MODE_ASCII ||
709  return output_funcs[CORSARO_FILE_MODE(file)].headers(corsaro, file, header);
710 }
711 
712 void corsaro_io_print_header(corsaro_plugin_manager_t *plugin_manager,
713  corsaro_header_t *header)
714 {
715  int i;
716 
717  fprintf(stdout, "# CORSARO_VERSION %"PRIu8".%"PRIu8"\n",
718  header->version_major, header->version_minor);
719  fprintf(stdout, "# CORSARO_INITTIME %"PRIu32"\n",
720  header->local_init_time);
721  fprintf(stdout, "# CORSARO_INTERVAL %"PRIu16"\n", header->interval_length);
722 
723  if(header->traceuri != NULL)
724  {
725  fprintf(stdout, "# CORSARO_TRACEURI %s\n", header->traceuri);
726  }
727  for(i=0;i<header->plugin_cnt;i++)
728  {
729  fprintf(stdout, "# CORSARO_PLUGIN %s\n",
730  corsaro_plugin_get_name(plugin_manager, header->plugin_ids[i]));
731  }
732 
733 }
734 
735 off_t corsaro_io_write_trailer(corsaro_t *corsaro, corsaro_file_t *file,
736  corsaro_trailer_t *trailer)
737 {
738  assert(CORSARO_FILE_MODE(file) == CORSARO_FILE_MODE_ASCII ||
740  return output_funcs[CORSARO_FILE_MODE(file)].trailers(corsaro, file,
741  trailer);
742 }
743 
744 void corsaro_io_print_trailer(corsaro_trailer_t *trailer)
745 {
746  fprintf(stdout, "# CORSARO_PACKETCNT %"PRIu64"\n",
747  trailer->packet_cnt);
748  fprintf(stdout, "# CORSARO_FIRSTPKT %"PRIu32"\n",
749  trailer->first_packet_time);
750  fprintf(stdout, "# CORSARO_LASTPKT %"PRIu32"\n",
751  trailer->last_packet_time);
752  fprintf(stdout, "# CORSARO_FINALTIME %"PRIu32"\n",
753  trailer->local_final_time);
754  fprintf(stdout, "# CORSARO_RUNTIME %"PRIu32"\n",
755  trailer->runtime);
756 }
757 
758 
759 off_t corsaro_io_write_interval_start(corsaro_t *corsaro, corsaro_file_t *file,
760  corsaro_interval_t *int_start)
761 {
762  assert(CORSARO_FILE_MODE(file) == CORSARO_FILE_MODE_ASCII ||
764  return output_funcs[CORSARO_FILE_MODE(file)].interval_start(corsaro, file,
765  int_start);
766 }
767 
768 void corsaro_io_print_interval_start(corsaro_interval_t *int_start)
769 {
770  fprintf(stdout,
771  "# CORSARO_INTERVAL_START %d %"PRIu32"\n",
772  int_start->number, int_start->time);
773 }
774 
775 off_t corsaro_io_write_interval_end(corsaro_t *corsaro, corsaro_file_t *file,
776  corsaro_interval_t *int_end)
777 {
778  assert(CORSARO_FILE_MODE(file) == CORSARO_FILE_MODE_ASCII ||
780  return (output_funcs[CORSARO_FILE_MODE(file)].interval_end)(corsaro, file,
781  int_end);
782 }
783 
784 void corsaro_io_print_interval_end(corsaro_interval_t *int_end)
785 {
786  fprintf(stdout,
787  "# CORSARO_INTERVAL_END %d %"PRIu32"\n",
788  int_end->number,
789  int_end->time);
790 }
791 
792 off_t corsaro_io_write_plugin_start(corsaro_t *corsaro, corsaro_file_t *file,
793  corsaro_plugin_t *plugin)
794 {
795  assert(CORSARO_FILE_MODE(file) == CORSARO_FILE_MODE_ASCII ||
797  assert(plugin != NULL);
798 
799  return (output_funcs[CORSARO_FILE_MODE(file)].plugin_start)(corsaro, file,
800  plugin);
801 }
802 
803 void corsaro_io_print_plugin_start(corsaro_plugin_t *plugin)
804 {
805  fprintf(stdout, "# CORSARO_PLUGIN_DATA_START %s\n", plugin->name);
806 }
807 
808 off_t corsaro_io_write_plugin_end(corsaro_t *corsaro, corsaro_file_t *file,
809  corsaro_plugin_t *plugin)
810 {
811  assert(CORSARO_FILE_MODE(file) == CORSARO_FILE_MODE_ASCII ||
813  assert(plugin != NULL);
814 
815  return (output_funcs[CORSARO_FILE_MODE(file)].plugin_end)(corsaro, file,
816  plugin);
817 }
818 
819 void corsaro_io_print_plugin_end(corsaro_plugin_t *plugin)
820 {
821  fprintf(stdout, "# CORSARO_PLUGIN_DATA_END %s\n", plugin->name);
822 }
823 
828 off_t corsaro_io_write_record(corsaro_t *corsaro, corsaro_file_t *file,
829  corsaro_in_record_type_t record_type,
830  corsaro_in_record_t *record)
831 {
832  corsaro_plugin_t *plugin = NULL;
833  corsaro_plugin_data_t *data = NULL;
834 
835  switch(record_type)
836  {
838  /*
839  corsaro_log(__func__, corsaro, "refusing to write null record to file");
840  */
841  return 0;
842  break;
843 
845  return corsaro_io_write_header(corsaro, file,
846  (corsaro_header_t *)record->buffer);
847  break;
849  return corsaro_io_write_trailer(corsaro, file,
850  (corsaro_trailer_t *)record->buffer);
851  break;
852 
854  return corsaro_io_write_interval_start(corsaro, file,
855  (corsaro_interval_t *)record->buffer);
856  break;
857 
859  return corsaro_io_write_interval_end(corsaro, file,
860  (corsaro_interval_t *)record->buffer);
861  break;
862 
864  data = (corsaro_plugin_data_t*)record->buffer;
865  if((plugin = corsaro_plugin_get_by_id(corsaro->plugin_manager,
866  data->plugin_id)) == NULL)
867  {
868  corsaro_log(__func__, corsaro, "invalid plugin id detected");
869  corsaro_log(__func__, corsaro, "is corsaro built with all"
870  "necessary plugins?");
871  return 0;
872  }
873  return corsaro_io_write_plugin_start(corsaro, file, plugin);
874  break;
875 
877  data = (corsaro_plugin_data_t*)record->buffer;
878  if((plugin = corsaro_plugin_get_by_id(corsaro->plugin_manager,
879  data->plugin_id)) == NULL)
880  {
881  corsaro_log(__func__, corsaro, "invalid plugin id detected");
882  corsaro_log(__func__, corsaro, "is corsaro built with all"
883  "necessary plugins?");
884  return 0;
885  }
886  return corsaro_io_write_plugin_end(corsaro, file, plugin);
887  break;
888 
892 #ifdef WITH_PLUGIN_DIST
893  return corsaro_distributions_record_fprint(corsaro, file,
894  record_type, record);
895 #else
896  corsaro_log(__func__, corsaro,
897  "corsaro is not built with distributions support");
898  return 0;
899 #endif
900  break;
901 
905 #ifdef WITH_PLUGIN_SIXT
906  return corsaro_flowtuple_record_fprint(corsaro, file, record_type, record);
907 #else
908  corsaro_log(__func__, corsaro, "corsaro is not built with flowtuple support");
909  return 0;
910 #endif
911  break;
912 
916 #ifdef WITH_PLUGIN_DOS
917  return corsaro_dos_record_fprint(corsaro, file, record_type, record);
918 #else
919  corsaro_log(__func__, corsaro, "corsaro is not built with dos support");
920  return 0;
921 #endif
922  break;
923 
924  default:
925  corsaro_log(__func__, corsaro, "invalid record type %d\n", (int)record_type);
926  return 0;
927  }
928 
929  return -1;
930 }
931 
932 int corsaro_io_print_record(corsaro_plugin_manager_t *plugin_manager,
933  corsaro_in_record_type_t record_type,
934  corsaro_in_record_t *record)
935 {
936  corsaro_plugin_t *plugin = NULL;
937  corsaro_plugin_data_t *data = NULL;
938 
939  switch(record_type)
940  {
942  /*
943  fprintf(stderr, "refusing to write null record to file");
944  */
945  break;
946 
948  corsaro_io_print_header(plugin_manager,
949  (corsaro_header_t *)record->buffer);
950  break;
951 
953  corsaro_io_print_trailer((corsaro_trailer_t *)record->buffer);
954  break;
955 
957  corsaro_io_print_interval_start((corsaro_interval_t *)record->buffer);
958  break;
959 
961  corsaro_io_print_interval_end((corsaro_interval_t *)record->buffer);
962  break;
963 
965  data = (corsaro_plugin_data_t*)record->buffer;
966  if((plugin = corsaro_plugin_get_by_id(plugin_manager,
967  data->plugin_id)) == NULL)
968  {
969  fprintf(stderr, "invalid plugin id detected\n");
970  fprintf(stderr, "is corsaro built with all"
971  "necessary plugins?\n");
972  return 0;
973  }
974  corsaro_io_print_plugin_start(plugin);
975  break;
976 
978  data = (corsaro_plugin_data_t*)record->buffer;
979  if((plugin = corsaro_plugin_get_by_id(plugin_manager,
980  data->plugin_id)) == NULL)
981  {
982  fprintf(stderr, "invalid plugin id detected\n");
983  fprintf(stderr, "is corsaro built with all"
984  "necessary plugins?\n");
985  return 0;
986  }
987  corsaro_io_print_plugin_end(plugin);
988  break;
989 
993 #ifdef WITH_PLUGIN_DIST
994  return corsaro_distributions_record_print(record_type, record);
995 #else
996  fprintf(stdout, "corsaro is not built with distributions support\n");
997  return 0;
998 #endif
999  break;
1000 
1004 #ifdef WITH_PLUGIN_SIXT
1005  return corsaro_flowtuple_record_print(record_type, record);
1006 #else
1007  fprintf(stdout, "corsaro is not built with flowtuple support\n");
1008  return 0;
1009 #endif
1010  break;
1011 
1015 #ifdef WITH_PLUGIN_DOS
1016  return corsaro_dos_record_print(record_type, record);
1017 #else
1018  fprintf(stdout, "corsaro is not built with dos support\n");
1019  return 0;
1020 #endif
1021  break;
1022 
1023  default:
1024  fprintf(stderr, "invalid record type %d\n", (int)record_type);
1025  return -1;
1026  }
1027 
1028  return 0;
1029 }
1030 
1031 /* ==== INPUT FUNCTIONS ==== */
1032 
1033 off_t corsaro_io_read_header(corsaro_in_t *corsaro, corsaro_file_in_t *file,
1034  corsaro_in_record_type_t *record_type,
1035  corsaro_in_record_t *record)
1036 {
1037  off_t bread;
1038  off_t bsbread = CORSARO_IO_HEADER_FIXED_BYTE_LEN+sizeof(uint16_t);
1039  corsaro_header_t *header;
1040  off_t offset = sizeof(corsaro_header_t);
1041  int i;
1042 
1043  /* read the static portion of the header */
1044  if((bread = corsaro_io_read_bytes(corsaro, record, bsbread)) != bsbread)
1045  {
1046  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1047  return bread;
1048  }
1049 
1050  header = (corsaro_header_t*)record->buffer;
1051 
1052  if(validate_header_static(header) != 1)
1053  {
1054  corsaro_log_in(__func__, corsaro, "could not validate header");
1055  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1056  return -1;
1057  }
1058 
1059  if(header->traceuri_len == 0)
1060  {
1061  header->traceuri = NULL;
1062  }
1063  else
1064  {
1065  /* read the traceuri into the buffer */
1066  if((bread += corsaro_io_read_bytes_offset(corsaro, record,
1067  offset,
1068  header->traceuri_len)) !=
1069  (bsbread+=header->traceuri_len))
1070  {
1071  corsaro_log_in(__func__, corsaro,
1072  "failed to read traceuri from file");
1073  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1074  return bread;
1075  }
1076  header->traceuri = record->buffer+sizeof(corsaro_header_t);
1077  offset += header->traceuri_len;
1078  *(record->buffer+offset) = '\0';
1079  offset++;
1080  }
1081 
1082  /* now, read the plugin count */
1083  if((bread += corsaro_io_read_bytes_offset(corsaro, record,
1085  +sizeof(uint16_t)
1086  +sizeof(uint8_t*),
1087  sizeof(uint16_t))) !=
1088  (bsbread+=sizeof(uint16_t)))
1089  {
1090  corsaro_log_in(__func__, corsaro,
1091  "failed to read plugin count from file");
1092  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1093  return bread;
1094  }
1095 
1096  header->plugin_cnt = ntohs(header->plugin_cnt);
1097 
1098  if(header->plugin_cnt == 0)
1099  {
1100  header->plugin_ids = NULL;
1101  }
1102  else
1103  {
1104  /* read the plugin array into the buffer */
1105  if((bread += corsaro_io_read_bytes_offset(corsaro, record,
1106  offset,
1107  sizeof(uint16_t)
1108  *header->plugin_cnt)) !=
1109  (bsbread+=sizeof(uint16_t)*header->plugin_cnt))
1110  {
1111  corsaro_log_in(__func__, corsaro,
1112  "failed to read plugin ids from file");
1113  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1114  return bread;
1115  }
1116  header->plugin_ids = (uint16_t*)(record->buffer+offset);
1117  }
1118 
1119  for(i =0; i<header->plugin_cnt;i++)
1120  {
1121  header->plugin_ids[i] = ntohs(header->plugin_ids[i]);
1122  }
1123 
1124  assert(bread == CORSARO_IO_HEADER_FIXED_BYTE_LEN+sizeof(uint16_t)
1125  +header->traceuri_len+sizeof(uint16_t)
1126  +(header->plugin_cnt*sizeof(uint16_t)));
1127 
1128  *record_type = CORSARO_IN_RECORD_TYPE_IO_HEADER;
1129 
1130  return bread;
1131 }
1132 
1133 off_t corsaro_io_read_trailer(corsaro_in_t *corsaro, corsaro_file_in_t *file,
1134  corsaro_in_record_type_t *record_type,
1135  corsaro_in_record_t *record)
1136 {
1137  off_t bytes_read;
1138 
1139  if((bytes_read = corsaro_io_read_bytes(corsaro, record,
1140  sizeof(corsaro_trailer_t))) !=
1141  sizeof(corsaro_trailer_t))
1142  {
1143  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1144  return bytes_read;
1145  }
1146 
1147  if(validate_trailer((corsaro_trailer_t *)record->buffer) != 1)
1148  {
1149  corsaro_log_in(__func__, corsaro, "could not validate trailer");
1150  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1151  return -1;
1152  }
1153 
1154  *record_type = CORSARO_IN_RECORD_TYPE_IO_TRAILER;
1155 
1156  return bytes_read;
1157 }
1158 
1159 off_t corsaro_io_read_interval_start(corsaro_in_t *corsaro, corsaro_file_in_t *file,
1160  corsaro_in_record_type_t *record_type,
1161  corsaro_in_record_t *record)
1162 {
1163  off_t bread;
1164 
1165  if((bread = corsaro_io_read_bytes(corsaro, record,
1168  {
1169  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1170  return bread;
1171  }
1172 
1173  if(validate_interval((corsaro_interval_t *)record->buffer) != 1)
1174  {
1175  corsaro_log_in(__func__, corsaro, "could not validate interval");
1176  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1177  return -1;
1178  }
1179 
1180  assert(bread == CORSARO_IO_INTERVAL_HEADER_BYTE_LEN);
1181 
1183 
1184  return bread;
1185 }
1186 
1187 off_t corsaro_io_read_interval_end(corsaro_in_t *corsaro, corsaro_file_in_t *file,
1188  corsaro_in_record_type_t *record_type,
1189  corsaro_in_record_t *record)
1190 {
1191  off_t bread;
1192 
1193  if((bread = corsaro_io_read_bytes(corsaro, record,
1196  {
1197  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1198  return bread;
1199  }
1200 
1201  if(validate_interval((corsaro_interval_t *)record->buffer) != 1)
1202  {
1203  corsaro_log_in(__func__, corsaro, "could not validate interval");
1204  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
1205  return -1;
1206  }
1207 
1208  assert(bread == CORSARO_IO_INTERVAL_HEADER_BYTE_LEN);
1209 
1211 
1212  return bread;
1213 }
1214 
1215 off_t corsaro_io_read_plugin_start(corsaro_in_t *corsaro,
1216  corsaro_file_in_t *file,
1217  corsaro_in_record_type_t *record_type,
1218  corsaro_in_record_t *record)
1219 {
1220  off_t bread = read_plugin_data(corsaro, file, record_type, record);
1221 
1222  if(bread > 0)
1223  {
1225  }
1226 
1227  return bread;
1228 }
1229 
1230 off_t corsaro_io_read_plugin_end(corsaro_in_t *corsaro, corsaro_file_in_t *file,
1231  corsaro_in_record_type_t *record_type,
1232  corsaro_in_record_t *record)
1233 {
1234  off_t bread = read_plugin_data(corsaro, file, record_type, record);
1235 
1236  if(bread > 0)
1237  {
1238  *record_type = CORSARO_IN_RECORD_TYPE_IO_PLUGIN_END;
1239  }
1240 
1241  return bread;
1242 }
1243 
1244 off_t corsaro_io_read_bytes(corsaro_in_t *corsaro, corsaro_in_record_t *record,
1245  off_t len)
1246 {
1247  /* fix this with a realloc later? */
1248  assert(record->buffer_len >= len);
1249 
1250  return corsaro_file_rread(corsaro, corsaro->file, record->buffer, len);
1251 }
1252 
1253 off_t corsaro_io_read_bytes_offset(corsaro_in_t *corsaro,
1254  corsaro_in_record_t *record,
1255  off_t offset, off_t len)
1256 {
1257  /* fix this with a realloc later? */
1258  assert(record->buffer_len >= offset+len);
1259 
1260  return corsaro_file_rread(corsaro, corsaro->file,
1261  (record->buffer)+offset, len);
1262 }