Skip to Content
[CAIDA - Cooperative Association for Internet Data Analysis logo]
The Cooperative Association for Internet Data Analysis
corsaro_file.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 <stdarg.h>
31 #include <inttypes.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "wandio.h"
37 
38 #include "corsaro_file.h"
39 #include "corsaro_log.h"
40 
41 /* fix for solaris (data-login.sdsc.edu) */
42 #if (defined (__SVR4) && defined (__sun))
43 extern int vasprintf(char **, const char *, __va_list);
44 #endif
45 
47 #define CORSARO_FILE_ASCII_CHECK "# CORSARO"
48 
50 #define CORSARO_FILE_TRACE_FORMAT "pcapfile:"
51 
52 corsaro_file_compress_t corsaro_file_detect_compression(corsaro_t *corsaro,
53  char *filename)
54 {
55  char *ptr = filename;
56 
57  /* check for a .gz extension */
58  ptr += strlen(filename)-strlen(CORSARO_FILE_ZLIB_SUFFIX);
59  if(strncmp(ptr, CORSARO_FILE_ZLIB_SUFFIX, 4) == 0)
60  {
62  }
63 
64  ptr = filename;
65  /* check for a .bz2 extension */
66  ptr += strlen(filename)-strlen(CORSARO_FILE_BZ2_SUFFIX);
67  if(strncmp(ptr, CORSARO_FILE_BZ2_SUFFIX, 4) == 0)
68  {
70  }
71 
72  /* this is a suffix we don't know. don't compress */
74 }
75 
76 corsaro_file_t *corsaro_file_open(corsaro_t *corsaro,
77  const char *filename,
79  corsaro_file_compress_t compress_type,
80  int compress_level,
81  int flags)
82 {
83  corsaro_file_t *f = NULL;
84 
85  size_t flen, rlen, len;
86  char *ptr, *traceuri;
87 
88  if((f = malloc(sizeof(corsaro_file_t))) == NULL)
89  {
90  corsaro_log(__func__, corsaro, "could not malloc new corsaro_file_t");
91  return NULL;
92  }
93 
94  f->mode = mode;
95 
96  /* did they ask for a libtrace file? */
97  switch(mode)
98  {
100  flen = strlen(CORSARO_FILE_TRACE_FORMAT);
101  rlen = strlen(filename);
102  len = flen+rlen+1;
103  if((ptr = traceuri = malloc(len)) == NULL)
104  {
105  corsaro_log(__func__, corsaro, "could not malloc traceuri");
106  return NULL;
107  }
108  strncpy(traceuri, CORSARO_FILE_TRACE_FORMAT, flen);
109  ptr += flen;
110  strncpy(ptr, filename, rlen);
111  traceuri[len-1] = '\0';
112  f->trace_io = trace_create_output(traceuri);
113  free(traceuri);
114 
115  if (trace_is_err_output(f->trace_io))
116  {
117  corsaro_log(__func__, corsaro, "trace_create_output failed for %s",
118  filename);
119  return NULL;
120  }
121  if(trace_config_output(f->trace_io, TRACE_OPTION_OUTPUT_COMPRESS,
122  &compress_level) ||
123  trace_config_output(f->trace_io, TRACE_OPTION_OUTPUT_COMPRESSTYPE,
124  &compress_type) != 0)
125  {
126  corsaro_log(__func__, corsaro,
127  "could not set compression levels for trace");
128  return NULL;
129  }
130  if (trace_start_output(f->trace_io) == -1) {
131  corsaro_log(__func__, corsaro, "trace_start_output failed for %s",
132  filename);
133  return NULL;
134  }
135  /* trace is configured! */
136  break;
137 
140  if((f->wand_io = wandio_wcreate(filename, compress_type,
141  compress_level, flags)) == NULL)
142  {
143  corsaro_log(__func__, corsaro, "wandio could not create file %s",
144  filename);
145  free(f);
146  return NULL;
147  }
148  break;
149 
150  default:
151  corsaro_log(__func__, corsaro, "invalid file mode %d", mode);
152  free(f);
153  return NULL;
154  }
155 
156  return f;
157 }
158 
159 off_t corsaro_file_write(corsaro_t *corsaro,
160  corsaro_file_t *file, const void *buffer, off_t len)
161 {
162  /* let's not try and write raw bytes to a libtrace file... */
163  assert(file->mode == CORSARO_FILE_MODE_ASCII ||
164  file->mode == CORSARO_FILE_MODE_BINARY);
165  assert(file->wand_io != NULL);
166 
167  return wandio_wwrite(file->wand_io, buffer, len);
168 }
169 
170 off_t corsaro_file_write_packet(corsaro_t *corsaro,
171  corsaro_file_t *file, libtrace_packet_t *packet)
172 {
173  uint8_t *pkt_buf = NULL;
174  libtrace_linktype_t linktype;
175 
176  switch(file->mode)
177  {
179  assert(file->wand_io != NULL);
180 #ifdef HAVE_LIBPACKETDUMP
181  corsaro_log(__func__, corsaro,
182  "libpacketdump currently does not support dumping "
183  "to a file");
184  return 0;
185 #else
186  corsaro_log(__func__, corsaro,
187  "corsaro must be built with libpacketdump to dump "
188  "a packet to ASCII");
189  return 0;
190 #endif
191  break;
192 
194  assert(file->wand_io != NULL);
195  if((pkt_buf = trace_get_packet_buffer(packet,
196  &linktype, NULL)) == NULL)
197  {
198  corsaro_log(__func__, corsaro, "could not get packet buffer");
199  return -1;
200  }
201  return corsaro_file_write(corsaro, file, pkt_buf,
202  trace_get_capture_length(packet));
203 
205  assert(file->trace_io != NULL);
206  return trace_write_packet(file->trace_io, packet);
207 
208  default:
209  corsaro_log(__func__, corsaro, "invalid corsaro file mode %d", file->mode);
210  return -1;
211  }
212 
213  return -1;
214 }
215 
216 static size_t wiovprintf(iow_t *io, const char *fmt, va_list args)
217 {
218  char *buf;
219  size_t len;
220  int ret;
221 
222  if ((ret = vasprintf(&buf, fmt, args)) < 0)
223  return ret;
224  len = strlen(buf);
225  len = len == (unsigned)len ? (size_t)wandio_wwrite(io, buf,
226  (unsigned)len) : 0;
227  free(buf);
228  return len;
229 }
230 
231 off_t corsaro_file_vprintf(corsaro_t *corsaro, corsaro_file_t *file,
232  const char *format, va_list args)
233 {
234  /* let's not try and print text to a libtrace file... */
235  assert(file->mode == CORSARO_FILE_MODE_ASCII ||
236  file->mode == CORSARO_FILE_MODE_BINARY);
237  assert(file->wand_io != NULL);
238 
239  return wiovprintf(file->wand_io, format, args);
240 
241 }
242 
243 off_t corsaro_file_printf(corsaro_t *corsaro,
244  corsaro_file_t *file, const char *format, ...)
245 {
246  va_list ap;
247 
248  va_start(ap, format);
249  return corsaro_file_vprintf(corsaro, file, format, ap);
250  va_end(ap);
251 }
252 
253 void corsaro_file_flush(corsaro_t *corsaro, corsaro_file_t *file)
254 {
255  /* not supported by wandio? */
256  return;
257 }
258 
259 void corsaro_file_close(corsaro_t *corsaro, corsaro_file_t *file)
260 {
261  switch(file->mode)
262  {
265  /* close the wandio object */
266  if(file->wand_io != NULL)
267  {
268  wandio_wdestroy(file->wand_io);
269  file->wand_io = NULL;
270  }
271  /* just for sanity */
272  file->trace_io = NULL;
273  break;
274 
276  if(file->trace_io != NULL)
277  {
278  trace_destroy_output(file->trace_io);
279  file->trace_io = NULL;
280  }
281  /* just for sanity */
282  file->wand_io = NULL;
283  break;
284 
285  default:
286  corsaro_log(__func__, corsaro, "corsaro_file_t freed more than once?");
287  corsaro_log(__func__, corsaro, "the file mode was %d", file->mode);
288  }
289 
290  free(file);
291 
292  return;
293 }
294 
295 corsaro_file_in_t *corsaro_file_ropen(corsaro_in_t *corsaro, const char *filename)
296 {
297  corsaro_file_in_t *f = NULL;
298  char buffer[1024];
299  int len;
300 
301  if((f = malloc(sizeof(corsaro_file_in_t))) == NULL)
302  {
303  corsaro_log_in(__func__, corsaro, "could not malloc new corsaro_file_in_t");
304  return NULL;
305  }
306 
307  /* we need to try and guess the mode... */
308  /* if there is a : in the uri, we guess it is a libtrace file */
309  /* this should be refined to do something more intelligent */
310  if(strchr(filename, ':') != NULL)
311  {
313 
314  /* open this as a trace file */
315  f->trace_io = trace_create(filename);
316 
317  if(trace_is_err(f->trace_io))
318  {
319  corsaro_log_in(__func__, corsaro, "trace_create failed for %s", filename);
320  free(f);
321  return NULL;
322  }
323 
324  if (trace_start(f->trace_io) == -1) {
325  corsaro_log_in(__func__, corsaro, "trace_start failed for %s", filename);
326  free(f);
327  return NULL;
328  }
329  /* trace is set to go! */
330  return f;
331  }
332  else
333  {
334  /* lets open the file and take a peek to see what we find */
335  if((f->wand_io = wandio_create(filename)) == NULL)
336  {
337  corsaro_log_in(__func__, corsaro, "wandio could not open file %s",
338  filename);
339  free(f);
340  return NULL;
341  }
342 
343  len = wandio_peek(f->wand_io, buffer, sizeof(buffer));
344 
345  /* an ASCII corsaro file will start with "# CORSARO_VERSION" */
346  if(len >= strlen(CORSARO_FILE_ASCII_CHECK) &&
347  memcmp(CORSARO_FILE_ASCII_CHECK, buffer,
348  strlen(CORSARO_FILE_ASCII_CHECK)) == 0)
349  {
351  }
352  /* a binary corsaro file will start with an corsaro header "EDGRHEAD" but,
353  it is possible that an old binary corsaro file can just start with an
354  interval header - "EDGRINTR", so we will only look for "EDGR" */
355  else if(len >= 4 && buffer[0] == 'E' && buffer[1] == 'D' &&
356  buffer[2] == 'G' && buffer[3] == 'R')
357  {
359  }
360  else
361  {
362  /* who knows! */
363  corsaro_log_in(__func__, corsaro,
364  "could not determine the file type for %s",
365  filename);
366  corsaro_log_in(__func__, corsaro,
367  "if this is a libtrace file, make sure you have "
368  "specified the uri properly (with a ':')");
369  free(f);
370  return NULL;
371  }
372  }
373 
374  return f;
375 }
376 
377 off_t corsaro_file_rread(corsaro_in_t *corsaro,
378  corsaro_file_in_t *file, void *buffer, off_t len)
379 {
380  /* refuse to read from a libtrace file */
381  assert(file->mode == CORSARO_FILE_MODE_ASCII ||
382  file->mode == CORSARO_FILE_MODE_BINARY);
383  assert(file->wand_io != NULL);
384 
385  return wandio_read(file->wand_io, buffer, len);
386 }
387 
388 off_t corsaro_file_rgets(struct corsaro_in *corsaro,
389  corsaro_file_in_t *file, void *buffer, off_t len)
390 {
391  /* refuse to read from a libtrace file */
392  assert(file != NULL);
393  assert(file->mode == CORSARO_FILE_MODE_ASCII ||
394  file->mode == CORSARO_FILE_MODE_BINARY);
395  assert(file->wand_io != NULL);
396 
397  char cbuf;
398  int rval;
399  int i;
400  int done = 0;
401 
402  if(buffer == NULL || len <= 0)
403  {
404  return 0;
405  }
406 
407  for(i=0; !done && i < len-1; i++)
408  {
409  if((rval = wandio_read(file->wand_io, &cbuf, 1)) < 0)
410  {
411  return rval;
412  }
413  if(rval == 0)
414  {
415  done = 1;
416  i--;
417  }
418  else
419  {
420  ((char*)buffer)[i] = cbuf;
421  if(cbuf == '\n')
422  {
423  done = 1;
424  }
425  }
426  }
427 
428  ((char*)buffer)[i] = '\0';
429  return i;
430 }
431 
432 off_t corsaro_file_rread_packet(corsaro_in_t *corsaro,
433  corsaro_file_in_t *file,
434  libtrace_packet_t *packet,
435  uint16_t len)
436 {
437  uint8_t *pktbuf;
438 
439  switch(file->mode)
440  {
442  if((pktbuf = malloc(len)) == NULL)
443  {
444  fprintf(stderr, "could not malloc the packet buffer\n");
445  return -1;
446  }
447  if(wandio_read(file->wand_io, pktbuf, len) != len)
448  {
449  fprintf(stderr, "could not read packet into buffer\n");
450  return -1;
451  }
452  trace_construct_packet(packet, TRACE_TYPE_ETH,
453  pktbuf, len);
454  return len;
455  break;
456 
458  return trace_read_packet(file->trace_io, packet);
459  break;
460 
462  /* refuse to read a packet from an ascii file */
463  /* this is a design flaw in the code if we get here */
464  assert(1);
465  return -1;
466  }
467 
468  return -1;
469 }
470 
471 off_t corsaro_file_rpeek(corsaro_in_t *corsaro,
472  corsaro_file_in_t *file, void *buffer, off_t len)
473 {
474  /* refuse to read from a libtrace file */
475  assert(file->mode == CORSARO_FILE_MODE_ASCII ||
476  file->mode == CORSARO_FILE_MODE_BINARY);
477  assert(file->wand_io != NULL);
478 
479  return wandio_peek(file->wand_io, buffer, len);
480 }
481 
482 off_t corsaro_file_rseek(corsaro_in_t *corsaro,
483  corsaro_file_in_t *file, off_t offset, int whence)
484 {
485  /* refuse to read from a libtrace file */
486  assert(file->mode == CORSARO_FILE_MODE_ASCII ||
487  file->mode == CORSARO_FILE_MODE_BINARY);
488  assert(file->wand_io != NULL);
489 
490  return wandio_seek(file->wand_io, offset, whence);
491 }
492 
493 off_t corsaro_file_rtell(corsaro_in_t *corsaro, corsaro_file_in_t *file)
494 {
495  /* refuse to read from a libtrace file */
496  assert(file->mode == CORSARO_FILE_MODE_ASCII ||
497  file->mode == CORSARO_FILE_MODE_BINARY);
498  assert(file->wand_io != NULL);
499 
500  return wandio_tell(file->wand_io);
501 }
502 
503 void corsaro_file_rclose(corsaro_in_t *corsaro, corsaro_file_in_t *file)
504 {
505  switch(file->mode)
506  {
509  /* close the wandio object */
510  if(file->wand_io != NULL)
511  {
512  wandio_destroy(file->wand_io);
513  file->wand_io = NULL;
514  }
515  /* just for sanity */
516  file->trace_io = NULL;
517  break;
518 
520  if(file->trace_io != NULL)
521  {
522  trace_destroy(file->trace_io);
523  file->trace_io = NULL;
524  }
525  /* just for sanity */
526  file->wand_io = NULL;
527 
528  default:
529  corsaro_log_in(__func__, corsaro, "corsaro_file_in_t freed more than once?");
530  }
531  /* this will prevent an idiot from using this object again */
532  file->mode = -1;
533 
534  return;
535 }