Skip to Content
[CAIDA - Cooperative Association for Internet Data Analysis logo]
The Cooperative Association for Internet Data Analysis
corsaro_flowtuple.c
Go to the documentation of this file.
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 <arpa/inet.h>
30 #include <assert.h>
31 #include <inttypes.h>
32 #include <stdio.h>
33 #include <string.h>
34 
35 #include "libtrace.h"
36 
37 #include "utils.h"
38 
39 #include "corsaro_io.h"
40 #include "corsaro_file.h"
41 #include "corsaro_log.h"
42 #include "corsaro_plugin.h"
43 
44 #include "corsaro_flowtuple.h"
45 
54 /* This magic number is a legacy number from when we used to call it the
55  'sixtuple' */
56 #ifdef CORSARO_SLASH_EIGHT
57 
58 #define CORSARO_FLOWTUPLE_MAGIC 0x53495854
59 #else
60 
61 #define CORSARO_FLOWTUPLE_MAGIC 0x53495855
62 #endif
63 
65 #define PLUGIN_NAME "flowtuple"
66 
69  PLUGIN_NAME, /* name */
71  CORSARO_FLOWTUPLE_MAGIC, /* magic */
73  NULL, /* next */
74 };
75 
77 static const char *class_names[] = {
78  "flowtuple_backscatter",
79  "flowtuple_icmpreq",
80  "flowtuple_other",
81 };
82 
85 
87 /*KHASH_INIT(sixt, corsaro_flowtuple_t*, khint32_t, 1, */
88 KHASH_INIT(sixt, corsaro_flowtuple_t*, char, 0,
90 
92 struct corsaro_flowtuple_state_t {
94  khash_t(sixt) *st_hash[CORSARO_FLOWTUPLE_CLASS_MAX+1];
96  corsaro_file_t *outfile;
97 };
98 
100 struct corsaro_flowtuple_in_state_t {
102  corsaro_in_record_type_t expected_type;
104  int tuple_total;
106  int tuple_cnt;
107 };
108 
110 #define STATE(corsaro) \
111  (CORSARO_PLUGIN_STATE(corsaro, flowtuple, CORSARO_PLUGIN_ID_FLOWTUPLE))
112 
113 #define STATE_IN(corsaro) \
114  (CORSARO_PLUGIN_STATE(corsaro, flowtuple_in, CORSARO_PLUGIN_ID_FLOWTUPLE))
115 
116 #define PLUGIN(corsaro) \
117  (CORSARO_PLUGIN_PLUGIN(corsaro, CORSARO_PLUGIN_ID_FLOWTUPLE))
118 
126 static int flowtuple_classify_packet(corsaro_t *corsaro, libtrace_packet_t *packet)
127 {
128  void *temp = NULL;
129  uint16_t ethertype;
130  uint8_t proto;
131  uint32_t remaining;
132 
133  libtrace_tcp_t *tcp_hdr = NULL;
134  libtrace_icmp_t *icmp_hdr = NULL;
135 
136  /* check for ipv4 */
137  if((temp = trace_get_layer3(packet, &ethertype, &remaining)) == NULL ||
138  ethertype != TRACE_ETHERTYPE_IP)
139  {
140  /* not an ip packet */
141  corsaro_log(__func__, corsaro, "non-ip packet found (ethertype: %x)",
142  ethertype);
144  }
145 
146  /* get the transport header */
147  if((temp = trace_get_transport(packet, &proto, &remaining)) == NULL)
148  {
149  /* not enough payload */
151  }
152 
153  /* check for tcp */
154  if(proto == TRACE_IPPROTO_TCP && remaining >= 4)
155  {
156  tcp_hdr = (libtrace_tcp_t *)temp;
157 
158  /* look for SYNACK or RST */
159  if((tcp_hdr->syn && tcp_hdr->ack) || tcp_hdr->rst)
160  {
162  }
163  else
164  {
166  }
167  }
168  /* check for icmp */
169  else if(proto == TRACE_IPPROTO_ICMP && remaining >= 2)
170  {
171  icmp_hdr = (libtrace_icmp_t *)temp;
172  if(icmp_hdr->type == 0 ||
173  icmp_hdr->type == 3 ||
174  icmp_hdr->type == 4 ||
175  icmp_hdr->type == 5 ||
176  icmp_hdr->type == 11 ||
177  icmp_hdr->type == 12 ||
178  icmp_hdr->type == 14 ||
179  icmp_hdr->type == 16 ||
180  icmp_hdr->type == 18)
181  {
183  }
184  else
185  {
187  }
188  }
189  else
190  {
192  }
193 
194  return -1;
195 }
196 
198 static int sort_hash(corsaro_t *corsaro, kh_sixt_t *hash, corsaro_flowtuple_t ***sorted)
199 {
200  khiter_t i;
201  corsaro_flowtuple_t **ptr;
202 
203  if((ptr = malloc(sizeof(corsaro_flowtuple_t*)*kh_size(hash))) == NULL)
204  {
205  corsaro_log(__func__, corsaro, "could not malloc array for sorted keys");
206  return -1;
207  }
208  *sorted = ptr;
209 
210  if(kh_size(hash) == 0)
211  {
212  /* no need to try and sort an empty hash */
213  return 0;
214  }
215 
216  for(i = kh_begin(hash); i != kh_end(hash); ++i)
217  {
218  if(kh_exist(hash, i))
219  {
220  *ptr = kh_key(hash, i);
221  ptr++;
222  }
223  }
224 
225  ks_heapsort(sixt, kh_size(hash), *sorted);
226  return 0;
227 }
228 
231 {
232  kh_sixt_t *h = STATE(corsaro)->st_hash[dist];
233 
234  int j;
235  khiter_t i = 0;
236 
237  corsaro_flowtuple_t **sorted_keys;
238 
239  uint8_t hbuf[4+2+4];
240  uint8_t *hptr = &hbuf[0];
241 
242  corsaro_flowtuple_t *flowtuple = NULL;;
243 
244  bytes_htonl(hptr, CORSARO_FLOWTUPLE_MAGIC);
245  hptr+=4;
246 
247  bytes_htons(hptr, dist);
248  hptr+=2;
249 
250  bytes_htonl(hptr, kh_size(h));
251 
252  if(corsaro_file_write(corsaro, STATE(corsaro)->outfile, &hbuf[0], 10) != 10)
253  {
254  corsaro_log(__func__, corsaro, "could not dump byte flowtuple header to file");
255  return -1;
256  }
257 
258  if(kh_size(h) > 0)
259  {
260  if(sort_hash(corsaro, h, &sorted_keys) != 0)
261  {
262  corsaro_log(__func__, corsaro, "could not sort keys");
263  return -1;
264  }
265 
266  for(j = 0; j < kh_size(h); j++)
267  {
268  i = kh_get(sixt, h, sorted_keys[j]);
269  if(kh_exist(h, i))
270  {
271  flowtuple = kh_key(h, i);
272  /* store the value in the flowtuple structure */
273  /*kh_key(h, i)->packet_cnt = htonl(kh_val(h, i));*/
274  /*flowtuple->packet_cnt = htonl(flowtuple->packet_cnt);*/
275 
276  if(corsaro_file_write(corsaro, STATE(corsaro)->outfile,
277  flowtuple, CORSARO_FLOWTUPLE_BYTECNT) !=
279  {
280  corsaro_log(__func__, corsaro,
281  "could not write flowtuple to file");
282  return -1;
283  }
284  }
285  }
286  free(sorted_keys);
287  }
288 
289  if(corsaro_file_write(corsaro, STATE(corsaro)->outfile, &hbuf[0], 6) != 6)
290  {
291  corsaro_log(__func__, corsaro, "could not dump flowtuple trailer to file");
292  return -1;
293  }
294  return 0;
295 }
296 
299 {
300  khiter_t i;
301  int j;
302  corsaro_flowtuple_t *key;
303  corsaro_flowtuple_t **sorted_keys;
304 
305  /*const char *name = class_names[dist];*/
306  kh_sixt_t *h = STATE(corsaro)->st_hash[dist];
307 
310 
311  class_start.magic = CORSARO_FLOWTUPLE_MAGIC;
312  class_start.class_type = dist;
313  class_start.count = kh_size(h);
314 
315  class_end.magic = CORSARO_FLOWTUPLE_MAGIC;
316  class_end.class_type = dist;
317 
318  corsaro_flowtuple_class_start_fprint(corsaro, STATE(corsaro)->outfile,
319  &class_start);
320 
321  if(kh_size(h) > 0)
322  {
323  if(sort_hash(corsaro, h, &sorted_keys) != 0)
324  {
325  corsaro_log(__func__, corsaro, "could not sort keys");
326  return -1;
327  }
328  for(j = 0; j < kh_size(h); j++)
329  {
330  i = kh_get(sixt, h, sorted_keys[j]);
331  if(kh_exist(h, i))
332  {
333  key = kh_key(h, i);
334  /*key->packet_cnt = htonl(key->packet_cnt);*/
335  corsaro_flowtuple_fprint(corsaro, STATE(corsaro)->outfile, key);
336  }
337  }
338  free(sorted_keys);
339  }
340 
341  corsaro_flowtuple_class_end_fprint(corsaro, STATE(corsaro)->outfile, &class_end);
342  return 0;
343 }
344 
345 static int validate_class_start(corsaro_flowtuple_class_start_t *class)
346 {
347  /* byteswap the values */
348  class->magic = ntohl(class->magic);
349  class->class_type = ntohs(class->class_type);
350  class->count = ntohl(class->count);
351 
352  /* do some sanity checking */
353  if(class->magic != CORSARO_FLOWTUPLE_MAGIC ||
354  class->class_type > CORSARO_FLOWTUPLE_CLASS_MAX)
355  {
356  return 0;
357  }
358  return 1;
359 }
360 
361 static int read_class_start(corsaro_in_t *corsaro,
362  corsaro_in_record_type_t *record_type,
363  corsaro_in_record_t *record)
364 {
365  off_t bytes_read;
366 
367  if((bytes_read =
368  corsaro_io_read_bytes(corsaro, record,
369  sizeof(corsaro_flowtuple_class_start_t))) !=
371  {
372  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
373  return bytes_read;
374  }
375 
376  if(validate_class_start((corsaro_flowtuple_class_start_t *)record->buffer) != 1)
377  {
378  corsaro_log_in(__func__, corsaro, "could not validate flowtuple class");
379  corsaro_log_in(__func__, corsaro,
380  "it is possible this flowtuple file was written "
381 #ifdef CORSARO_SLASH_EIGHT
382  "without /8 "
383 #else
384  "with /8 "
385 #endif
386  "optimizations enabled");
387  corsaro_log_in(__func__, corsaro, "try rebuilding using the "
388 #ifdef CORSARO_SLASH_EIGHT
389  "--without-slash-eight "
390 #else
391  "--with-slash-eight=0 "
392 #endif
393  "configure option");
394  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
395  return -1;
396  }
397 
398  assert(bytes_read == sizeof(corsaro_flowtuple_class_start_t));
399 
401  STATE_IN(corsaro)->tuple_total = ((corsaro_flowtuple_class_start_t *)
402  record->buffer)->count;
403 
404  STATE_IN(corsaro)->expected_type = (STATE_IN(corsaro)->tuple_total == 0) ?
407 
408  return bytes_read;
409 }
410 
411 static int validate_class_end(corsaro_flowtuple_class_end_t *class)
412 {
413  /* byteswap the values */
414  class->magic = ntohl(class->magic);
415  class->class_type = ntohs(class->class_type);
416 
417  /* do some sanity checking */
418  if(class->magic != CORSARO_FLOWTUPLE_MAGIC ||
419  class->class_type > CORSARO_FLOWTUPLE_CLASS_MAX)
420  {
421  return 0;
422  }
423  return 1;
424 }
425 
426 static int read_class_end(corsaro_in_t *corsaro,
427  corsaro_in_record_type_t *record_type,
428  corsaro_in_record_t *record)
429 {
430  off_t bytes_read;
431 
432  if((bytes_read =
433  corsaro_io_read_bytes(corsaro, record,
434  sizeof(corsaro_flowtuple_class_end_t))) !=
436  {
437  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
438  return bytes_read;
439  }
440 
441  if(validate_class_end((corsaro_flowtuple_class_end_t *)record->buffer) != 1)
442  {
443  corsaro_log_in(__func__, corsaro, "could not validate flowtuple class end");
444  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
445  return -1;
446  }
447 
448  assert(bytes_read == sizeof(corsaro_flowtuple_class_end_t));
449 
451  STATE_IN(corsaro)->expected_type = (((corsaro_flowtuple_class_end_t *)
452  record->buffer)->class_type ==
453  (uint16_t)CORSARO_FLOWTUPLE_CLASS_MAX) ?
456  STATE_IN(corsaro)->tuple_total = 0;
457  STATE_IN(corsaro)->tuple_cnt = 0;
458 
459  return bytes_read;
460 }
461 
462 static int validate_flowtuple(corsaro_flowtuple_t *flowtuple)
463 {
464  /* there is no real validation that can be done with this */
465  return 1;
466 }
467 
468 static int read_flowtuple(corsaro_in_t *corsaro,
469  corsaro_in_record_type_t *record_type,
470  corsaro_in_record_t *record)
471 {
472  off_t bytes_read;
473 
474  if((bytes_read = corsaro_io_read_bytes(corsaro, record,
475  sizeof(corsaro_flowtuple_t))) !=
476  sizeof(corsaro_flowtuple_t))
477  {
478  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
479  return bytes_read;
480  }
481 
482  if(validate_flowtuple((corsaro_flowtuple_t *)record->buffer) != 1)
483  {
484  corsaro_log_in(__func__, corsaro, "could not validate flowtuple");
485  *record_type = CORSARO_IN_RECORD_TYPE_NULL;
486  return -1;
487  }
488 
490 
491  if(++(STATE_IN(corsaro)->tuple_cnt) == STATE_IN(corsaro)->tuple_total)
492  {
493  STATE_IN(corsaro)->expected_type = CORSARO_IN_RECORD_TYPE_FLOWTUPLE_CLASS_END;
494  }
495 
496  assert(bytes_read == sizeof(corsaro_flowtuple_t));
497 
498  return bytes_read;
499 }
500 
501 /* == PUBLIC PLUGIN FUNCS BELOW HERE == */
502 
503 corsaro_plugin_t *corsaro_flowtuple_alloc(corsaro_t *corsaro)
504 {
505  return &corsaro_flowtuple_plugin;
506 }
507 
508 int corsaro_flowtuple_probe_filename(const char *fname)
509 {
510  /* look for 'corsaro_flowtuple' in the name */
511  return corsaro_plugin_probe_filename(fname, &corsaro_flowtuple_plugin);
512 }
513 
514 int corsaro_flowtuple_probe_magic(corsaro_in_t *corsaro, corsaro_file_in_t *file)
515 {
516  char buffer[1024];
517  int len;
519 
520  len = corsaro_file_rpeek(corsaro, file, buffer, sizeof(buffer));
521 
522  /* an corsaro flowtuple file will have 'SIX[TU]' at 14, 15, 16, 17 */
524  buffer[i++] == 'S' && buffer[i++] == 'I' &&
525  buffer[i++] == 'X' && (buffer[i] == 'T' || buffer[i] == 'U'))
526  {
527  return 1;
528  }
529 
530  return 0;
531 }
532 
537 {
538  int i;
539  struct corsaro_flowtuple_state_t *state;
540  corsaro_plugin_t *plugin = PLUGIN(corsaro);
541  assert(plugin != NULL);
542 
543  if((state = malloc_zero(sizeof(struct corsaro_flowtuple_state_t))) == NULL)
544  {
545  corsaro_log(__func__, corsaro,
546  "could not malloc corsaro_flowtuple_state_t");
547  goto err;
548  }
549  corsaro_plugin_register_state(corsaro->plugin_manager, plugin, state);
550 
551  /* open the output file */
552  if((state->outfile = corsaro_io_prepare_file(corsaro, plugin->name)) == NULL)
553  {
554  corsaro_log(__func__, corsaro, "could not open %s output file",
555  plugin->name);
556  goto err;
557  }
558 
559  for(i = 0; i <= CORSARO_FLOWTUPLE_CLASS_MAX; i++)
560  {
561  assert(state->st_hash[i] == NULL);
562  state->st_hash[i] = kh_init(sixt);
563  assert(state->st_hash[i] != NULL);
564  }
565 
566  return 0;
567 
568  err:
569  corsaro_flowtuple_close_output(corsaro);
570  return -1;
571 }
572 
573 int corsaro_flowtuple_init_input(corsaro_in_t *corsaro)
574 {
575  struct corsaro_flowtuple_in_state_t *state;
576  corsaro_plugin_t *plugin = PLUGIN(corsaro);
577  assert(plugin != NULL);
578 
579  if((state = malloc_zero(sizeof(struct corsaro_flowtuple_in_state_t))) == NULL)
580  {
581  corsaro_log_in(__func__, corsaro,
582  "could not malloc corsaro_flowtuple_state_t");
583  goto err;
584  }
585  corsaro_plugin_register_state(corsaro->plugin_manager, plugin, state);
586 
587  /* we initially expect an corsaro interval record */
588  state->expected_type = CORSARO_IN_RECORD_TYPE_IO_INTERVAL_START;
589 
590  /* don't set the tuple_cnt until we actually see a class start record */
591 
592  return 0;
593 
594  err:
595  corsaro_flowtuple_close_input(corsaro);
596  return -1;
597 }
598 
599 int corsaro_flowtuple_close_input(corsaro_in_t *corsaro)
600 {
601  struct corsaro_flowtuple_in_state_t *state = STATE_IN(corsaro);
602 
603  if(state != NULL)
604  {
605  corsaro_plugin_free_state(corsaro->plugin_manager, PLUGIN(corsaro));
606  }
607  return 0;
608 }
609 
610 int corsaro_flowtuple_close_output(corsaro_t *corsaro)
611 {
612  int i;
613  struct corsaro_flowtuple_state_t *state = STATE(corsaro);
614 
615  if(state != NULL)
616  {
617  for(i = 0; i <= CORSARO_FLOWTUPLE_CLASS_MAX; i++)
618  {
619  if(state->st_hash[i] != NULL)
620  {
621  kh_free(sixt, state->st_hash[i], &corsaro_flowtuple_free);
622  kh_destroy(sixt, state->st_hash[i]);
623  state->st_hash[i] = NULL;
624  }
625  }
626 
627  if(state->outfile != NULL)
628  {
629  corsaro_file_close(corsaro, state->outfile);
630  state->outfile = NULL;
631  }
632  corsaro_plugin_free_state(corsaro->plugin_manager, PLUGIN(corsaro));
633  }
634  return 0;
635 }
636 
637 off_t corsaro_flowtuple_read_record(struct corsaro_in *corsaro,
638  corsaro_in_record_type_t *record_type,
639  corsaro_in_record_t *record)
640 {
641 
642  struct corsaro_flowtuple_in_state_t *state = STATE_IN(corsaro);
643 
644  off_t bytes_read = -1;
645 
646  /* we have 5 different types of records that could be in this file */
647  switch(state->expected_type)
648  {
650  /* ask the io subsystem to read it for us */
651  bytes_read = corsaro_io_read_interval_start(corsaro, corsaro->file,
652  record_type, record);
653  if(bytes_read == sizeof(corsaro_interval_t))
654  {
655  state->expected_type = CORSARO_IN_RECORD_TYPE_FLOWTUPLE_CLASS_START;
656  }
657  break;
658 
660  /* we'll handle this one */
661  bytes_read = read_class_start(corsaro, record_type, record);
662  break;
663 
665  /* we'll handle this too */
666  bytes_read = read_flowtuple(corsaro, record_type, record);
667  break;
668 
670  /* as with this */
671  bytes_read = read_class_end(corsaro, record_type, record);
672  break;
673 
675  /* ask the io subsystem to read it for us */
676  bytes_read = corsaro_io_read_interval_end(corsaro, corsaro->file,
677  record_type, record);
678  if(bytes_read == sizeof(corsaro_interval_t))
679  {
680  state->expected_type = CORSARO_IN_RECORD_TYPE_IO_INTERVAL_START;
681  }
682  break;
683 
684  default:
685  corsaro_log_in(__func__, corsaro, "invalid expected record type");
686  }
687 
688  return bytes_read;
689 }
690 
691 off_t corsaro_flowtuple_read_global_data_record(struct corsaro_in *corsaro,
692  enum corsaro_in_record_type *record_type,
693  struct corsaro_in_record *record)
694 {
695  /* we write nothing to the global file. someone messed up */
696  return -1;
697 }
698 
699 int corsaro_flowtuple_start_interval(corsaro_t *corsaro, corsaro_interval_t *int_start)
700 {
701  int i;
702  for(i = 0; i <= CORSARO_FLOWTUPLE_CLASS_MAX; i++)
703  {
704  if(STATE(corsaro)->st_hash[i] == NULL)
705  {
706  corsaro_log(__func__, corsaro,
707  "corsaro_flowtuple_init must be called first");
708  return -1;
709  }
710  else
711  {
712  /* free all of the flowtuples */
713  kh_free(sixt, STATE(corsaro)->st_hash[i], &corsaro_flowtuple_free);
714  kh_clear(sixt, STATE(corsaro)->st_hash[i]);
715  }
716  }
717  return 0;
718 }
719 
720 int corsaro_flowtuple_end_interval(corsaro_t *corsaro, corsaro_interval_t *int_end)
721 {
722  int i;
723 
724  corsaro_io_write_interval_start(corsaro, STATE(corsaro)->outfile,
725  &corsaro->interval_start);
726 
727  for(i = 0; i <= CORSARO_FLOWTUPLE_CLASS_MAX; i++)
728  {
729  if((CORSARO_FILE_MODE(STATE(corsaro)->outfile) == CORSARO_FILE_MODE_ASCII &&
730  ascii_dump(corsaro, i) != 0) ||
731  (CORSARO_FILE_MODE(STATE(corsaro)->outfile) == CORSARO_FILE_MODE_BINARY &&
732  binary_dump(corsaro, i) != 0))
733  {
734  corsaro_log(__func__, corsaro, "could not dump hash");
735  return -1;
736  }
737  }
738 
739  corsaro_io_write_interval_end(corsaro, STATE(corsaro)->outfile, int_end);
740 
741  return 0;
742 }
743 
744 int corsaro_flowtuple_process_packet(corsaro_t *corsaro,
745  corsaro_packet_t *packet)
746 {
747  libtrace_packet_t *ltpacket = LT_PKT(packet);
748  libtrace_ip_t *ip_hdr = NULL;
749  libtrace_icmp_t *icmp_hdr = NULL;
750  libtrace_tcp_t *tcp_hdr = NULL;
752  int class;
753 
754  if((ip_hdr = trace_get_ip(ltpacket)) != NULL)
755  {
756  /* finish building the flowtuple */
757  t.ip_len = ip_hdr->ip_len;
758 
759  t.src_ip = ip_hdr->ip_src.s_addr;
760  CORSARO_FLOWTUPLE_IP_TO_SIXT(ip_hdr->ip_dst.s_addr, &t);
761 
762  t.protocol = ip_hdr->ip_p;
763  t.tcp_flags = 0; /* in case we don't find a tcp header */
764 
765  t.ttl = ip_hdr->ip_ttl;
766 
767  if(ip_hdr->ip_p == TRACE_IPPROTO_ICMP &&
768  (icmp_hdr = trace_get_icmp(ltpacket)) != NULL)
769  {
770  t.src_port = htons(icmp_hdr->type);
771  t.dst_port = htons(icmp_hdr->code);
772  }
773  else
774  {
775  if(ip_hdr->ip_p == TRACE_IPPROTO_TCP &&
776  (tcp_hdr = trace_get_tcp(ltpacket)) != NULL)
777  {
778  /* we have ignore the NS flag because it doesn't fit in
779  an 8 bit field. blame alberto (ak - 2/2/12) */
780  t.tcp_flags = (
781  (tcp_hdr->cwr << 7) |
782  (tcp_hdr->ece << 6) |
783  (tcp_hdr->urg << 5) |
784  (tcp_hdr->ack << 4) |
785  (tcp_hdr->psh << 3) |
786  (tcp_hdr->rst << 2) |
787  (tcp_hdr->syn << 1) |
788  (tcp_hdr->fin << 0)
789  );
790  }
791 
792  t.src_port = htons(trace_get_source_port(ltpacket));
793  t.dst_port = htons(trace_get_destination_port(ltpacket));
794  }
795 
796  /* classify this packet and increment the appropriate hash */
797  if((class = flowtuple_classify_packet(corsaro, ltpacket)) < 0)
798  {
799  corsaro_log(__func__, corsaro, "could not classify packet");
800  return -1;
801  }
802 
804  {
805  packet->state.flags |= CORSARO_PACKET_STATE_FLAG_BACKSCATTER;
806  }
807 
808  if(corsaro_flowtuple_add_inc(STATE(corsaro)->st_hash[class], &t, 1) != 0)
809  {
810  corsaro_log(__func__, corsaro, "could not increment value for flowtuple");
811  return -1;
812  }
813  }
814  /*
815  else
816  {
817  corsaro_log(__func__, corsaro, "packet found without IPv4 header\n");
818  }
819  */
820  return 0;
821 }
822 
823 /* ==== FlowTuple External Convenience Functions ==== */
824 
826 {
827  assert(flowtuple != NULL);
828 
829  return flowtuple->src_ip;
830 }
831 
833 {
834  assert(flowtuple != NULL);
835 
836  return CORSARO_FLOWTUPLE_SIXT_TO_IP(flowtuple);
837 }
838 
840  corsaro_flowtuple_t *flowtuple)
841 {
842  char ip_a[INET_ADDRSTRLEN];
843  char ip_b[INET_ADDRSTRLEN];
844  uint32_t tmp;
845 
846  assert(corsaro != NULL);
847  assert(file != NULL);
848  assert(flowtuple != NULL);
849 
850  tmp = flowtuple->src_ip;
851  inet_ntop(AF_INET,&tmp, &ip_a[0], 16);
852  tmp = CORSARO_FLOWTUPLE_SIXT_TO_IP(flowtuple);
853  inet_ntop(AF_INET, &tmp, &ip_b[0], 16);
854 
855  return corsaro_file_printf(corsaro, file, "%s|%s"
856  "|%"PRIu16"|%"PRIu16
857  "|%"PRIu8"|%"PRIu8"|0x%02"PRIx8
858  "|%"PRIu16
859  ",%"PRIu32"\n",
860  ip_a, ip_b,
861  ntohs(flowtuple->src_port),
862  ntohs(flowtuple->dst_port),
863  flowtuple->protocol,
864  flowtuple->ttl,
865  flowtuple->tcp_flags,
866  ntohs(flowtuple->ip_len),
867  ntohl(flowtuple->packet_cnt));
868 }
869 
871 {
872  char ip_a[16];
873  char ip_b[16];
874  uint32_t tmp;
875 
876  assert(flowtuple != NULL);
877 
878  tmp = flowtuple->src_ip;
879  inet_ntop(AF_INET,&tmp, &ip_a[0], 16);
880  tmp = CORSARO_FLOWTUPLE_SIXT_TO_IP(flowtuple);
881  inet_ntop(AF_INET, &tmp, &ip_b[0], 16);
882 
883  fprintf(stdout, "%s|%s"
884  "|%"PRIu16"|%"PRIu16
885  "|%"PRIu8"|%"PRIu8"|0x%02"PRIx8
886  "|%"PRIu16
887  ",%"PRIu32"\n",
888  ip_a, ip_b,
889  ntohs(flowtuple->src_port),
890  ntohs(flowtuple->dst_port),
891  flowtuple->protocol,
892  flowtuple->ttl,
893  flowtuple->tcp_flags,
894  ntohs(flowtuple->ip_len),
895  ntohl(flowtuple->packet_cnt));
896 }
897 
900 {
901  return corsaro_file_printf(corsaro, file,
902  "START %s %"PRIu32"\n",
903  class_names[class->class_type],
904  class->count);
905 }
906 
908 {
909  fprintf(stdout, "START %s %"PRIu32"\n", class_names[class->class_type],
910  class->count);
911 }
912 
915 {
916  return corsaro_file_printf(corsaro, file, "END %s\n",
917  class_names[class->class_type]);
918 }
919 
921 {
922  fprintf(stdout, "END %s\n", class_names[class->class_type]);
923 }
924 
926  corsaro_in_record_type_t record_type,
927  corsaro_in_record_t *record)
928 {
929  switch(record_type)
930  {
932  return corsaro_flowtuple_class_start_fprint(corsaro, file,
934  break;
935 
937  return corsaro_flowtuple_class_end_fprint(corsaro, file,
939  break;
940 
942  return corsaro_flowtuple_fprint(corsaro, file,
943  (corsaro_flowtuple_t *)record->buffer);
944  break;
945 
946  default:
947  corsaro_log(__func__, corsaro, "record_type %d not a flowtuple record",
948  record_type);
949  return -1;
950  break;
951  }
952 
953  return -1;
954 }
955 
957  corsaro_in_record_t *record)
958 {
959  switch(record_type)
960  {
964  break;
965 
969  break;
970 
973  break;
974 
975  default:
976  corsaro_log_file(__func__, NULL, "record_type %d not a flowtuple record",
977  record_type);
978  return -1;
979  break;
980  }
981 
982  return 0;
983 }
984 
986 {
987  free(t);
988 }
989 
991 int corsaro_flowtuple_add_inc(void *h, corsaro_flowtuple_t *t, int increment)
992 {
993  kh_sixt_t *hash = (kh_sixt_t *)h;
994  int khret;
995  khiter_t khiter;
996  corsaro_flowtuple_t *new_6t = NULL;
997 
998  assert(hash != NULL);
999 
1000  /* check if this is in the hash already */
1001  if((khiter = kh_get(sixt, hash, t)) == kh_end(hash))
1002  {
1003  /* create a new tuple struct */
1004  if((new_6t = malloc(sizeof(corsaro_flowtuple_t))) == NULL)
1005  {
1006  corsaro_log_file(__func__, NULL, "malloc failed");
1007  return -1;
1008  }
1009 
1010  /* fill it */
1011  memcpy(new_6t, t, sizeof(corsaro_flowtuple_t));
1012 
1013  /* add it to the hash */
1014  khiter = kh_put(sixt, hash, new_6t, &khret);
1015  /* set the count to one */
1016  /*kh_value(hash, khiter) = increment;*/
1017  new_6t->packet_cnt = htonl(increment);
1018  }
1019  else
1020  {
1021  /* simply increment the existing one */
1022  /*kh_value(hash, khiter)+=increment;*/
1023  new_6t = kh_key(hash, khiter);
1024  new_6t->packet_cnt = htonl(ntohl(new_6t->packet_cnt)+increment);
1025  }
1026  return 0;
1027 }