flowmon-http-plugins  1.0
FlowMon HTTP Input/Process/export plugins
 All Data Structures Files Functions Variables Typedefs Macros
flowmon-input-http.c
Go to the documentation of this file.
1 
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <pcap.h>
44 #include <stdbool.h>
45 #include <sys/timeb.h>
46 #include <time.h>
47 #include <signal.h>
48 #include <sys/cdefs.h>
49 #include <flowmonexp/plugin_input.h>
50 #include <netinet/ip.h>
51 #include <netinet/ip6.h>
52 #include <netinet/ether.h>
53 #include "flowmon-input-http.h"
54 #include "lex.h"
55 
56 #ifdef BENCHMARK
57 #include "benchmark_packets.h"
58 #endif
59 
60 #include <openssl/md5.h>
61 #include <inttypes.h>
62 
64 #define PRINTV(format, args...) do {if (VERBOSE) { fprintf(stdout, format, ##args); fflush(stdout); } } while (0)
65 
67 #define PRINTD(format, args...) do {if (DEBUG) { fprintf(stdout, format, ##args); fflush(stdout); } } while (0)
68 
70 #define PRINTA(format, args...) do {if (VERBOSE || DEBUG) { fprintf(stdout, format, ##args); fflush(stdout); } } while (0)
71 
73 SET_PLUGIN_TYPE(PLUGIN_TYPE_INPUT | PLUGIN_TYPE_PROCESS);
74 
77 
79 bool VERBOSE;
80 
82 bool DEBUG;
83 
92 inline int lex_strstr(char *buf, int n, http_record_t *http);
93 
101 void plugin_input_getter_init(void *plugin_private,
102  flow_record_getter_t **getter_list);
103 
110 char *getfilter(char *file);
111 
119 void *plugin_input_init(char *params, int full_packet, int data_offset);
120 
128 void plugin_process_update(void *plugin_private, flow_record_t *record,
129  flow_record_t *update);
130 
139 inline unsigned char *getbuf(int counter, unsigned char *packets[40], int min,
140  int max);
141 
149 inline int parse_headers(unsigned char *buf, http_record_t *http, int buflen);
150 
152 char YY_GET_EOF_CHAR();
153 
155 YY_BUFFER_STATE my_scan_buffer(char *base, yy_size_t size,
156  yyscan_t yyscanner);
157 
159 void my_init_extra(yyscan_t backup_scanner, YY_EXTRA_TYPE user_defined,
160  yyscan_t scanner);
161 
163 YY_BUFFER_STATE my_scan_bytes(yyconst char *yybytes,
164  yy_size_t _yybytes_len,
165  yyscan_t yyscanner);
166 
168 void my_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner);
169 
171 yyscan_t backup_scanner;
172 
174 yyscan_t scanner;
175 
179 typedef struct {
180 
182  pcap_t *pcap;
183 
185  flow_record_getter_t **getter_list;
186 
188  char *input;
189 
191  long long int counter;
192 
194  int data;
195 
197  int offline;
198 
200  int filter;
201 
204 
206  unsigned char *buffer;
207 
209  unsigned char *benchmark_packets[40];
210 
212  int benchmin;
213 
215  int benchmax;
216 
218  struct timespec startuptime;
219 
222 
224 
228 static plugin_desc_t pcap_desc = {
229  "input-http",
230  "Plugin parse HTTP headers into flow\n"
231  "Parameters:\n"
232  " filter=y use default filter in plugin\n"
233  " filter=n don't use any filter\n"
234  " filterfile=filter.txt use filter in file\n"
235  " file must contain just one line with string representing pcap_filter\n"
236  " device=dev device to listen to\n"
237  " file=/path/file.pcap path to pcap file"
238  " benchmin=int Set range of packets for benchmarkin\n"
239  " benchmax=int Set range of packets for benchmarking\n"
240  " benchtick=int Set number of packets to pass between each line of output of benchmarking mode\n"
241  " debug=y/n Switch on/off debug mode (default: same as flowmonexp)"
242  " verbose=y/n switch on/off verbose mode (default: same as flowmonexp)",
243  sizeof(http_record_t),
244  0
245 };
246 
251 PLUGIN_INPUT_DESC {
252  return &pcap_desc;
253 }
254 
255 inline unsigned char *getbuf(int counter, unsigned char *packets[40], int min,
256  int max)
257 {
258  return packets[min + (counter % (max - min + 1))];
259 }
260 
261 inline int lex_strstr(char *buf, int n, http_record_t *http)
262 {
263  /* Init the scanner structure */
265 
266  /* Prepare the buffer */
267  YY_BUFFER_STATE b = my_scan_buffer(buf, n, scanner);
268 
269  /* Do the HTTP parsing */
270  yylex(scanner);
271 
272  /* Delete the buffer */
274 
275  return 0;
276 }
277 
278 char *getfilter(char *path)
279 {
280  FILE *file = NULL;
281  char *ret = NULL, *filter = NULL;
282 
283  /* Allocate memory for the filter */
284  filter = malloc(FILTER_SIZE * sizeof(char));
285  if (ret == NULL) {
286  return NULL;
287  }
288 
289  /* Open the file */
290  file = fopen(path, "r");
291  if (file == NULL) {
292  fprintf(stderr, "Cannot open file \"%s\"", path);
293  free(filter);
294 
295  return NULL;
296  }
297 
298  /* Read a line form filter file */
299  /* TODO read the whole file! */
300  ret = fgets(filter, FILTER_SIZE, file);
301  if (ret == NULL) {
302  fprintf(stderr, "Cannot read file \"%s\"", path);
303 
304  /* Set return value to NULL */
305  free(filter);
306  }
307 
308  return ret;
309 }
310 
317 int parse_params(char *params, plugin_private_http *conf)
318 {
319  char *token, *value, *param;
320  uint8_t state = 0; /* state 0: expect param, state 1: expect value */
321 
322  /* Check that there are parameters */
323  if (params == NULL) {
324  fprintf(stderr, "input-http-flow need parameters\n");
325  return 1;
326  }
327 
328  /* Parse parameter string */
329  token = strtok(params, ",=");
330  while (token != NULL) {
331  if (state == 0) {
332  param = token;
333  } else {
334  value = token;
335  PRINTA("param: %s\t", param);
336  PRINTA("value: %s\n", value);
337  if (strcmp("file", param) == 0) {
338 #ifdef BENCHMARK
339  fprintf(stderr,
340  "BENCHMARK MODE forbids 'file' parameter\n Did you forgot to recompile with '--enable-benchmark' option?\n");
341  return 7;
342 #endif
343  conf->offline = 1;
344  conf->input =
345  malloc((1 + strlen(value)) * sizeof(char));
346  strcpy(conf->input, value);
347  } else if (strcmp("device", param) == 0) {
348 #ifdef BENCHMARK
349  fprintf(stderr,
350  "BENCHMARK MODE forbids 'device' parameter\n Did you forgot to recompile with '--enable-benchmark' option?\n");
351  return 7;
352 #endif
353  conf->offline = 0;
354  conf->input =
355  malloc((1 + strlen(value)) * sizeof(char));
356  strcpy(conf->input, value);
357  } else if (strcmp("benchmin", param) == 0) {
358 #ifndef BENCHMARK
359  fprintf(stderr,
360  "Supported only in benchmark mode. Did you forgot to recompile with '--enable-benchmark' option?\n");
361  return 7;
362 #endif
363  conf->benchmin = atoi(value);
364  } else if (strcmp("benchmax", param) == 0) {
365 #ifndef BENCHMARK
366  fprintf(stderr,
367  "Supported only in benchmark mode. Did you forgot to recompile with '--enable-benchmark' option?\n");
368  return 7;
369 #endif
370  conf->benchmax = atoi(value);
371  } else if (strcmp("benchtick", param) == 0) {
372 #ifndef BENCHMARK
373  fprintf(stderr,
374  "Supported only in benchmark mode. Did you forgot to recompile with '--enable-benchmark' option?\n");
375  return 7;
376 #endif
377  conf->benchtick = atoi(value);
378  } else if (strcmp("filter", param) == 0) {
379  if (strcmp(value, "y") == 0) {
380  conf->filter = 1;
381  } else if (strcmp(value, "n") == 0) {
382  conf->filter = 0;
383  } else {
384  fprintf(stderr,
385  " value of 'filter' parameter is not valid");
386  return 7;
387  }
388  } else if (strcmp("filterfile", param) == 0) {
389  conf->filter_string =
390  malloc((1 +
391  strlen(getfilter(value))) *
392  sizeof(char));
393  PRINTV("Read from filter file : %s",
394  getfilter(value));
395  strcpy(conf->filter_string, getfilter(value));
396  conf->filter = 1;
397  } else if (strcmp("verbose", param) == 0) {
398  if (strcmp(value, "y") == 0) {
399  VERBOSE = true;
400  } else if (strcmp(value, "n") == 0) {
401  VERBOSE = false;
402  } else {
403  fprintf(stderr,
404  " value of 'verbose' parameter is not valid");
405  }
406  } else if (strcmp("debug", param) == 0) {
407  if (strcmp(value, "y") == 0) {
408  DEBUG = true;
409  } else if (strcmp(value, "n") == 0) {
410  DEBUG = false;
411  } else {
412  fprintf(stderr,
413  " value of 'debug' parameter is not valid");
414  }
415  } else {
416  fprintf(stderr, "Unknown parameter '%s'\n",
417  param);
418  return 1;
419  }
420  }
421 
422  /* Move to next token */
423  token = strtok(NULL, ",=");
424  state = 1 - state;
425  }
426 
427  return 0;
428 }
429 
430 inline int parse_headers(unsigned char *buf, http_record_t *http, int buflen)
431 {
432  char *position = (char *)buf;
433 
434  lex_strstr(position, buflen * sizeof(char), http);
435  return 0;
436 }
437 
442 int value_length_uint64(void *self, flow_record_t *r)
443 {
444  return sizeof(uint64_t);
445 }
446 
451 int value_length_uint8(void *self, flow_record_t *r)
452 {
453  return sizeof(uint8_t);
454 }
455 
460 int value_length_uint16(void *self, flow_record_t *r)
461 {
462  return sizeof(uint16_t);
463 }
464 
469 int value_length_domain(void *self, flow_record_t *r)
470 {
471  return DOMAIN_LENGTH * sizeof(char);
472 }
473 
478 int value_length_referer(void *self, flow_record_t *r)
479 {
480  return REFERER_LENGTH * sizeof(char);
481 }
482 
487 int value_length_url(void *self, flow_record_t *r)
488 {
489  return URL_LENGTH * sizeof(char);
490 }
491 
497 int validity_OK(void *self, flow_record_t *r)
498 {
499  return 1;
500 }
501 
506 int validity_by_valid(void *self, flow_record_t *r)
507 {
509  http_record_t *pr = PLUGIN_DATA(r, p->data);
510  return pr->valid;
511 }
512 
522 void value_fill_useragent(void *self, flow_record_t *record, void *dst,
523  int len, int to_network_byte_order)
524 {
526  http_record_t *pr = PLUGIN_DATA(record, p->data);
527  record_universal_get(dst, &(pr->useragent), 0, sizeof(uint8_t), len,
528  to_network_byte_order);
529 }
530 
540 void value_fill_domain(void *self, flow_record_t *record, void *dst, int len,
541  int to_network_byte_order)
542 {
544  http_record_t *pr = PLUGIN_DATA(record, p->data);
545  record_universal_get(dst, &(pr->domain), 0,
546  DOMAIN_LENGTH * sizeof(char), len,
547  to_network_byte_order);
548 }
549 
550 inline int min(int x, int y)
551 {
552  if (x < y) {
553  return x;
554  } else {
555  return y;
556  }
557 }
567 void value_fill_url(void *self, flow_record_t *record, void *dst, int len,
568  int to_network_byte_order)
569 {
571  http_record_t *pr = PLUGIN_DATA(record, p->data);
572  record_universal_get(dst, &(pr->url), 0, URL_LENGTH * sizeof(char), len,
573  to_network_byte_order);
574 }
575 
585 void value_fill_referer(void *self, flow_record_t *record, void *dst, int len,
586  int to_network_byte_order)
587 {
589  http_record_t *pr = PLUGIN_DATA(record, p->data);
590  record_universal_get(dst, &(pr->referer), 0,
591  REFERER_LENGTH * sizeof(char), len,
592  to_network_byte_order);
593 }
594 
604 void value_fill_method(void *self, flow_record_t *record, void *dst, int len,
605  int to_network_byte_order)
606 {
608  http_record_t *pr = PLUGIN_DATA(record, p->data);
609  record_universal_get(dst, &(pr->method), 0, sizeof(uint8_t), len,
610  to_network_byte_order);
611 }
612 
622 void value_fill_status(void *self, flow_record_t *record, void *dst, int len,
623  int to_network_byte_order)
624 {
626  http_record_t *pr = PLUGIN_DATA(record, p->data);
627  record_universal_get(dst, &(pr->status), 0, sizeof(uint16_t), len,
628  to_network_byte_order);
629 }
630 
640 void value_fill_header_count(void *self, flow_record_t *record, void *dst, int len,
641  int to_network_byte_order)
642 {
644  http_record_t *pr = PLUGIN_DATA(record, p->data);
645  record_universal_get(dst, &(pr->header_count), 0, sizeof(uint16_t), len,
646  to_network_byte_order);
647 }
648 
658 void value_fill_content_type(void *self, flow_record_t *record, void *dst,
659  int len, int to_network_byte_order)
660 {
662  http_record_t *pr = PLUGIN_DATA(record, p->data);
663  record_universal_get(dst, &(pr->content_type), 0, sizeof(uint8_t), len,
664  to_network_byte_order);
665 }
666 
673 void plugin_input_getter_init(void *plugin_private,
674  flow_record_getter_t **getter_list)
675 {
676  PRINTD("Getter init started\n");
677 
678  getter_add(getter_list, "HTTP_USERAGENT", sizeof(uint8_t),
679  plugin_private, &validity_by_valid, &value_length_uint8,
680  &value_fill_useragent);
681  getter_add(getter_list, "HTTP_METHOD", sizeof(uint8_t), plugin_private,
682  &validity_by_valid, &value_length_uint8, &value_fill_method);
683  getter_add(getter_list, "HTTP_DOMAIN", DOMAIN_LENGTH * sizeof(char),
684  plugin_private, &validity_by_valid, &value_length_domain,
685  &value_fill_domain);
686  getter_add(getter_list, "HTTP_REFERER", REFERER_LENGTH * sizeof(char),
687  plugin_private, &validity_by_valid, &value_length_referer,
688  &value_fill_referer);
689  getter_add(getter_list, "HTTP_CONTENT_TYPE", sizeof(uint8_t),
690  plugin_private, &validity_by_valid, &value_length_uint8,
691  &value_fill_content_type);
692  getter_add(getter_list, "HTTP_URL", URL_LENGTH * sizeof(char),
693  plugin_private, &validity_by_valid, &value_length_url,
694  &value_fill_url);
695  getter_add(getter_list, "HTTP_STATUS", sizeof(uint16_t),
696  plugin_private, &validity_by_valid, &value_length_uint16,
697  &value_fill_status);
698  getter_add(getter_list, "HTTP_HEADER_COUNT", sizeof(uint16_t),
699  plugin_private, &validity_by_valid, &value_length_uint8,
700  &value_fill_header_count);
701 
702  PRINTD("Getter init finished\n");
703 }
704 
705 void *plugin_input_init(char *params, int full_packet, int data_offset)
706 {
707  plugin_private_http *retval;
708 
709  /* Set verbose and debug mode */
710  VERBOSE = (verbose_level >= 0) ? true : false;
711  DEBUG = (debug_level >= 0) ? true : false;
712 
713  /* Allocate private structure */
714  retval = malloc(sizeof(plugin_private_http));
715  if (retval == NULL) {
716  return NULL;
717  }
718 
719 #ifndef BENCHMARK
720  char errbuf[PCAP_ERRBUF_SIZE];
721  struct bpf_program fp;
722 #endif
723 
724  GLOBAL_FLOW_OFFSET = data_offset;
725  VERBOSE = false;
726 
727 #ifdef BENCHMARK
728  /* Prepare benchmark packets */
729  for (int x = 0; x < 40; x++) {
730  retval->benchmark_packets[x] =
731  malloc(PCAP_SIZE * sizeof(unsigned char));
732  }
733  memcpy(retval->benchmark_packets[0], &pkt1,
734  sizeof(pkt1) / sizeof(unsigned char));
735  memcpy(retval->benchmark_packets[1], &pkt2,
736  sizeof(pkt2) / sizeof(unsigned char));
737  memcpy(retval->benchmark_packets[2], &pkt3,
738  sizeof(pkt3) / sizeof(unsigned char));
739  memcpy(retval->benchmark_packets[3], &pkt4,
740  sizeof(pkt4) / sizeof(unsigned char));
741  memcpy(retval->benchmark_packets[4], &pkt5,
742  sizeof(pkt5) / sizeof(unsigned char));
743  memcpy(retval->benchmark_packets[5], &pkt6,
744  sizeof(pkt6) / sizeof(unsigned char));
745  memcpy(retval->benchmark_packets[6], &pkt7,
746  sizeof(pkt7) / sizeof(unsigned char));
747  memcpy(retval->benchmark_packets[7], &pkt8,
748  sizeof(pkt8) / sizeof(unsigned char));
749  memcpy(retval->benchmark_packets[8], &pkt9,
750  sizeof(pkt9) / sizeof(unsigned char));
751  memcpy(retval->benchmark_packets[9], &pkt10,
752  sizeof(pkt10) / sizeof(unsigned char));
753  memcpy(retval->benchmark_packets[10], &pkt11,
754  sizeof(pkt11) / sizeof(unsigned char));
755  memcpy(retval->benchmark_packets[11], &pkt12,
756  sizeof(pkt12) / sizeof(unsigned char));
757  memcpy(retval->benchmark_packets[12], &pkt13,
758  sizeof(pkt13) / sizeof(unsigned char));
759  memcpy(retval->benchmark_packets[13], &pkt14,
760  sizeof(pkt14) / sizeof(unsigned char));
761  memcpy(retval->benchmark_packets[14], &pkt15,
762  sizeof(pkt15) / sizeof(unsigned char));
763  memcpy(retval->benchmark_packets[15], &pkt16,
764  sizeof(pkt16) / sizeof(unsigned char));
765  memcpy(retval->benchmark_packets[16], &pkt17,
766  sizeof(pkt17) / sizeof(unsigned char));
767  memcpy(retval->benchmark_packets[17], &pkt18,
768  sizeof(pkt18) / sizeof(unsigned char));
769  memcpy(retval->benchmark_packets[18], &pkt19,
770  sizeof(pkt19) / sizeof(unsigned char));
771  memcpy(retval->benchmark_packets[19], &pkt20,
772  sizeof(pkt20) / sizeof(unsigned char));
773  memcpy(retval->benchmark_packets[20], &pkt21,
774  sizeof(pkt21) / sizeof(unsigned char));
775  memcpy(retval->benchmark_packets[21], &pkt22,
776  sizeof(pkt22) / sizeof(unsigned char));
777  memcpy(retval->benchmark_packets[22], &pkt23,
778  sizeof(pkt23) / sizeof(unsigned char));
779  memcpy(retval->benchmark_packets[23], &pkt24,
780  sizeof(pkt24) / sizeof(unsigned char));
781  memcpy(retval->benchmark_packets[24], &pkt25,
782  sizeof(pkt25) / sizeof(unsigned char));
783  memcpy(retval->benchmark_packets[25], &pkt26,
784  sizeof(pkt26) / sizeof(unsigned char));
785  memcpy(retval->benchmark_packets[26], &pkt27,
786  sizeof(pkt27) / sizeof(unsigned char));
787  memcpy(retval->benchmark_packets[27], &pkt28,
788  sizeof(pkt28) / sizeof(unsigned char));
789  memcpy(retval->benchmark_packets[28], &pkt29,
790  sizeof(pkt29) / sizeof(unsigned char));
791  memcpy(retval->benchmark_packets[29], &pkt30,
792  sizeof(pkt30) / sizeof(unsigned char));
793  memcpy(retval->benchmark_packets[30], &pkt31,
794  sizeof(pkt31) / sizeof(unsigned char));
795  memcpy(retval->benchmark_packets[31], &pkt32,
796  sizeof(pkt32) / sizeof(unsigned char));
797  memcpy(retval->benchmark_packets[32], &pkt33,
798  sizeof(pkt33) / sizeof(unsigned char));
799  memcpy(retval->benchmark_packets[33], &pkt34,
800  sizeof(pkt34) / sizeof(unsigned char));
801  memcpy(retval->benchmark_packets[34], &pkt35,
802  sizeof(pkt35) / sizeof(unsigned char));
803  memcpy(retval->benchmark_packets[35], &pkt36,
804  sizeof(pkt36) / sizeof(unsigned char));
805  memcpy(retval->benchmark_packets[36], &pkt37,
806  sizeof(pkt37) / sizeof(unsigned char));
807  memcpy(retval->benchmark_packets[37], &pkt38,
808  sizeof(pkt38) / sizeof(unsigned char));
809  memcpy(retval->benchmark_packets[38], &pkt39,
810  sizeof(pkt39) / sizeof(unsigned char));
811  memcpy(retval->benchmark_packets[39], &pkt40,
812  sizeof(pkt40) / sizeof(unsigned char));
813  retval->benchtick = 1000000;
814  retval->benchmin = 0;
815  retval->benchmax = 40;
816 #endif
817 
818  /* Init input plugin private config structure */
819  PRINTV("HTTP input plugin init with args: %s\n", params);
820 
821  retval->data = data_offset;
822  retval->counter = 0;
823  retval->filter = 0;
824  retval->offline = 0;
825  retval->filter_string = NULL;
826  retval->buffer = malloc((PCAP_SIZE + 2) * sizeof(unsigned char));
827  if (!(retval->buffer)) {
828  return NULL;
829  }
830 
831  /* Parse command line parameters */
832  if (parse_params(params, retval) != 0) {
833  return NULL;
834  }
835 
836 #ifndef BENCHMARK
837  /* Open the pcap device */
838  if (retval->offline == 1) {
839  PRINTA("http plugin opens file %s\n", retval->input);
840  retval->pcap = pcap_open_offline(retval->input, errbuf);
841  } else {
842  PRINTA("http plugin opens live device %s\n", retval->input);
843  retval->pcap =
844  pcap_open_live(retval->input, PCAP_SIZE, 1, 0, errbuf);
845  }
846 
847  /* Check the pcap device */
848  if (retval->pcap == NULL) {
849  fprintf(stderr, "Unable to init pcap: %s\n", errbuf);
850  free(retval);
851 
852  return NULL;
853  }
854 
855  /* Process filter settings */
856  if (retval->filter == 1) {
857  /* Setup default filter */
858  if (retval->filter_string == NULL) {
859  PRINTV("Setting up default filter\n");
860  retval->filter_string =
861  malloc(FILTER_SIZE * sizeof(char));
862  strcpy(retval->filter_string, FILTER);
863  }
864 
865  /* Compile the filter */
866  if (pcap_compile(retval->pcap, &fp, retval->filter_string, 0,
867  PCAP_NETMASK_UNKNOWN) == -1) {
868 
869  fprintf(stderr, "Couldn't parse filter %s: %s\n",
870  retval->filter_string, pcap_geterr(retval->pcap));
871  free(retval);
872 
873  return NULL;
874  }
875 
876  /* Install the filter */
877  if (pcap_setfilter(retval->pcap, &fp) == -1) {
878  fprintf(stderr, "Couldn't install filter %s: %s\n",
879  retval->filter_string,
880  pcap_geterr(retval->pcap));
881  free(retval);
882  return NULL;
883  }
884  }
885 
886  /* Check datalink type */
887  int datalink = pcap_datalink(retval->pcap);
888  if (datalink != DLT_EN10MB) {
889  /* Not an ethernet packet */
890  return 0;
891  }
892 #endif
893 
894  /* Initialize flex scanner structures */
895  yylex_init(&backup_scanner);
896  yylex_init(&scanner);
897 
898  return retval;
899 }
900 
907 uint64_t plugin_input_get_flow(void *plugin_private, flow_record_t *record)
908 {
909  plugin_private_http *dev = (plugin_private_http *) plugin_private;
910  http_record_t *precord = PLUGIN_DATA(record, (dev->data));
911  struct pcap_pkthdr hdr;
912  unsigned char *buf;
913  uint64_t hash;
914  uint32_t offset = 0;
915  uint32_t caplen;
916  uint32_t caplen2;
917 
918 #ifdef BENCHMARK
919  struct timespec tmp1;
920  int sec;
921  long int msec;
922 #endif
923 
924 
925 #ifndef BENCHMARK
926  /* Get packet from pcap */
927  buf = (unsigned char *)pcap_next(dev->pcap, &hdr);
928  caplen = hdr.caplen;
929 #else
930  dev->counter++;
931 
932  /* Startup time initialization */
933  if (dev->counter == 1) {
934  clock_gettime(CLOCK_REALTIME, &(dev->startuptime));
935  }
936 
937  /* Periodic output */
938  if (dev->counter % dev->benchtick == 0) {
939  clock_gettime(CLOCK_REALTIME, &tmp1);
940 
941  printf("packets %ld | ", dev->counter);
942  sec = (tmp1.tv_sec - (dev->startuptime).tv_sec) + 1;
943  msec =
944  (tmp1.tv_sec - dev->startuptime.tv_sec) * 1000 +
945  (tmp1.tv_nsec - dev->startuptime.tv_nsec) / 1000000;
946  printf("time: %.3f | ", ((double)msec) / 1000);
947  printf("%.2f packets/s\n",
948  ((double)dev->counter / ((double)msec / 1000)));
949  }
950 
951  /* Prepare packet from benchmark set */
952  buf = getbuf(dev->counter, dev->benchmark_packets, dev->benchmin,
953  dev->benchmax);
954  caplen = PCAP_SIZE;
955 #endif
956 
957  /* Check for end of pcap file */
958  if (buf == NULL && dev->offline == 1) {
959  PRINTA("reached end of file\n");
960  sleep(5); /* let the output plugins do what they need - the time should be probably (in)active timeout? */
961  raise(SIGQUIT);
962  sleep(5);
963  return 0;
964  }
965 
966  /* Check that the packet was read successfully */
967  if (buf == NULL) {
968  return 0;
969  }
970 
971  /* START OF PARSING PACKET */
972 #ifndef BENCHMARK
973  record->flow_end = record->flow_start =
974  ((uint64_t) hdr.ts.tv_sec * 1000 * 1000 * 1000) +
975  ((uint64_t) hdr.ts.tv_usec * 1000);
976 #endif
977 
978  /* Let flowmonexp do the packet header parsing */
979  hash = record_process_packet(buf, caplen, record);
980  /* Check that the packet is valid (discards non IP packets) */
981  if (hash == 0) {
982  return 0;
983  }
984 
985  /* Process only TCP packets */
986  if (record->l4.protocol != 6) {
987  return hash | FLOW_OK_BIT;
988  }
989 
990  /* Get packet data offset and check for malformed packets */
991  caplen2 = caplen;
992  if (get_packet_data(&caplen2, &offset) == NULL) {
993  /* Do not parse malformed packets */
994  return hash | FLOW_OK_BIT;
995  }
996 
997  /* Do not parse packets shorter than 8 bytes for HTTP content */
998  if (caplen - 8 > offset) { /* caplen - offset > 8, beware of unsigned int underflow */
999  buf += offset;
1000  } else {
1001  return hash | FLOW_OK_BIT;
1002  }
1003 
1004  /* Initialize the http record */
1005  memset((void *)precord, 0, sizeof(http_record_t));
1006 
1007  /* Ensure that packets longer than PCAP_SIZE are trimmed */
1008  caplen = min(caplen, PCAP_SIZE);
1009 
1010  /* Create buffer for flex to work on */
1011  memcpy(dev->buffer, buf, caplen - offset);
1012  buf = dev->buffer;
1013  /* Set EOF chars to the end of the buffer */
1014  buf[caplen - offset] = buf[caplen - offset + 1] = YY_GET_EOF_CHAR();
1015 
1016  /* Parse the packet payload for HTTP information */
1017  parse_headers(buf, precord, caplen - offset + 2); /* add +2 for terminating bytes */
1018 
1019  return hash | FLOW_OK_BIT;
1020 }
1021 
1026 void plugin_process_getter_init(void *plugin_private,
1027  flow_record_getter_t **getter_list)
1028 {
1029  return;
1030 }
1031 
1036 void plugin_process_create(void *plugin_private, flow_record_t *record)
1037 {
1038  return;
1039 }
1040 
1045 void plugin_process_release(void *plugin_private, flow_record_t *record,
1046  int reason)
1047 {
1048  return;
1049 }
1050 
1058 void plugin_process_update(void *plugin_private, flow_record_t *record,
1059  flow_record_t *update)
1060 {
1061  http_record_t *original = PLUGIN_DATA(record, GLOBAL_FLOW_OFFSET);
1062  http_record_t *up = PLUGIN_DATA(update, GLOBAL_FLOW_OFFSET);
1063 
1064  /* If the new apcket has HTTP header */
1065  if (up->valid == 1) {
1066  /* Update only non HTTP record */
1067  if (original->valid != 1) {
1068  /* Copy http structure */
1069  *((http_record_t *) original) = *((http_record_t *) up);
1070  } else {
1071  /* Update header count on any other valid HTTP record */
1072  original->header_count++;
1073  }
1074  }
1075 }
1076 
1080 static plugin_desc_t plugin_proc_desc = {
1081  "process-http",
1082  "Controls if record is properly filled, if not, refills it from next packets in the flow",
1083  0,
1084  0
1085 };
1086 
1091 plugin_desc_t *plugin_process_desc()
1092 {
1093  return &plugin_proc_desc;
1094 }
1095 
1100 void *plugin_process_init(char *params, int data_offset)
1101 {
1102  return &GLOBAL_FLOW_OFFSET;
1103 }