Skip to Content
[CAIDA - Center for Applied Internet Data Analysis logo]
The Center for Applied Internet Data Analysis
corsaro_geodb.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 <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include "libtrace.h"
38 
39 #include "csv.h"
40 #include "ip_utils.h"
41 #include "khash.h"
42 #include "patricia.h"
43 #include "utils.h"
44 
45 #include "corsaro_geo.h"
46 #include "corsaro_log.h"
47 #include "corsaro_plugin.h"
48 
49 #ifdef WITH_PLUGIN_SIXT
50 #include "corsaro_flowtuple.h"
51 #endif
52 
53 #include "corsaro_geodb.h"
54 
73 #define CORSARO_GEODB_MAGIC 0x474F4442
74 
76 #define PLUGIN_NAME "geodb"
77 
79 #define MAXMIND_NAME \
80  (corsaro_geo_get_provider_name(CORSARO_GEO_PROVIDER_MAXMIND))
81 
83 #define NETACQ_EDGE_NAME \
84  (corsaro_geo_get_provider_name(CORSARO_GEO_PROVIDER_NETACQ_EDGE))
85 
87 #define DEFAULT_PROVIDER_NAME MAXMIND_NAME
88 
90 #define BUFFER_LEN 1024
91 
93 typedef enum maxmind_locations_cols {
112 
116 
118 #define MAXMIND_HEADER_ROW_CNT 2
119 
125  NETACQ_EDGE_LOCATION_COL_CC3 = 1, /* not used */
143  NETACQ_EDGE_LOCATION_COL_RCODE = 10, /* not used */
157  NETACQ_EDGE_LOCATION_COL_REGCONF = 17, /* not used */
163  NETACQ_EDGE_LOCATION_COL_GMTOFF = 20, /* not used */
165  NETACQ_EDGE_LOCATION_COL_INDST = 21, /* not used */
167  NETACQ_EDGE_LOCATION_COL_TRAIL = 22, /* not used */
168 
172 
174 typedef enum blocks_cols {
181 
184 } blocks_cols_t;
185 
187 #define NETACQ_EDGE_HEADER_ROW_CNT 1
188 
190 #define LOCATIONS_FILE_NAME "GeoLiteCity-Location.csv.gz"
191 
193 #define BLOCKS_FILE_NAME "GeoLiteCity-Blocks.csv.gz"
194 
195 KHASH_INIT(u16u16, uint16_t, uint16_t, 1,
196  kh_int_hash_func, kh_int_hash_equal)
197 
198 
199 static corsaro_plugin_t corsaro_geodb_plugin = {
200  PLUGIN_NAME, /* name */
201  CORSARO_PLUGIN_ID_GEODB, /* id */
202  CORSARO_GEODB_MAGIC, /* magic */
203 #ifdef WITH_PLUGIN_SIXT
204  CORSARO_PLUGIN_GENERATE_PTRS_FT(corsaro_geodb), /* func ptrs */
205 #else
206  CORSARO_PLUGIN_GENERATE_PTRS(corsaro_geodb),
207 #endif
209 };
210 
212 struct corsaro_geodb_state_t {
213  corsaro_geo_provider_t *provider;
214 
215  /* Info extracted from args */
216  corsaro_geo_provider_id_t provider_id;
217  char *locations_file;
218  char *blocks_file;
219 
220  /* State for CSV parser */
221  struct csv_parser parser;
222  int current_line;
223  int current_column;
224  corsaro_geo_record_t tmp_record;
225  uint16_t cntry_code;
226  uint32_t block_id;
227  ip_prefix_t block_lower;
228  ip_prefix_t block_upper;
229 
230  /* hash that maps from country code to continent code */
231  khash_t(u16u16) *country_continent;
232 };
233 
235 #define STATE(corsaro) \
236  (CORSARO_PLUGIN_STATE(corsaro, geodb, CORSARO_PLUGIN_ID_GEODB))
237 
239 #define PLUGIN(corsaro) \
240  (CORSARO_PLUGIN_PLUGIN(corsaro, CORSARO_PLUGIN_ID_GEODB))
241 
243 static void usage(corsaro_plugin_t *plugin)
244 {
245  fprintf(stderr,
246  "plugin usage: %s [-p format] (-l locations -b blocks)|(-d directory)\n"
247  " -d directory containing blocks and location files\n"
248  " -b blocks file (must be used with -l)\n"
249  " -l locations file (must be used with -b)\n"
250  " -p database format (default: %s)\n"
251  " format must be one of:\n"
252  " - %s\n"
253  " - %s\n",
254  plugin->argv[0],
256  MAXMIND_NAME,
258 }
259 
264 {
265  corsaro_plugin_t *plugin = PLUGIN(corsaro);
266  struct corsaro_geodb_state_t *state = STATE(corsaro);
267  int opt;
268  char *directory = NULL;
269  char *ptr = NULL;
270 
271  assert(plugin->argc > 0 && plugin->argv != NULL);
272 
273  if(plugin->argc == 1)
274  {
275  usage(plugin);
276  return -1;
277  }
278 
279  /* NB: remember to reset optind to 1 before using getopt! */
280  optind = 1;
281 
282  while((opt = getopt(plugin->argc, plugin->argv, "b:d:l:p:?")) >= 0)
283  {
284  switch(opt)
285  {
286  case 'b':
287  /* NB: although the storage for these strings belongs to us,
288  we strdup them so that we can free on cleanup to handle the
289  case where we dynamically build them from the directory path
290  */
291  state->blocks_file = strdup(optarg);
292  break;
293 
294  case 'd':
295  directory = optarg;
296  break;
297 
298  case 'l':
299  state->locations_file = strdup(optarg);
300  break;
301 
302  case 'p':
303  if(strncasecmp(optarg, MAXMIND_NAME, strlen(MAXMIND_NAME)) == 0)
304  {
305  state->provider_id = CORSARO_GEO_PROVIDER_MAXMIND;
306  }
307  else if(strncasecmp(optarg, NETACQ_EDGE_NAME,
308  strlen(NETACQ_EDGE_NAME)) == 0)
309  {
310  state->provider_id = CORSARO_GEO_PROVIDER_NETACQ_EDGE;
311  }
312  else
313  {
314  fprintf(stderr, "ERROR: invalid database format (%s)\n",
315  optarg);
316  usage(plugin);
317  return -1;
318  }
319  break;
320 
321  case '?':
322  case ':':
323  default:
324  usage(plugin);
325  return -1;
326  }
327  }
328 
329  if(directory != NULL)
330  {
331  /* check if they were daft and specified explicit files too */
332  if(state->locations_file != NULL || state->blocks_file != NULL)
333  {
334  fprintf(stderr, "WARNING: both directory and file name specified.\n");
335 
336  /* free up the dup'd strings */
337  if(state->locations_file != NULL)
338  {
339  free(state->locations_file);
340  state->locations_file = NULL;
341  }
342 
343  if(state->blocks_file != NULL)
344  {
345  free(state->blocks_file);
346  state->blocks_file = NULL;
347  }
348  }
349 
350  /* remove the trailing slash if there is one */
351  if(directory[strlen(directory)-1] == '/')
352  {
353  directory[strlen(directory)-1] = '\0';
354  }
355 
356  /* malloc storage for the dir+/+file string */
357  if((state->locations_file = malloc(
358  strlen(directory)+1+
359  strlen(LOCATIONS_FILE_NAME)+1))
360  == NULL)
361  {
362  corsaro_log(__func__, corsaro,
363  "could not malloc location file string");
364  return -1;
365  }
366 
367  if((state->blocks_file = malloc(
368  strlen(directory)+1+
369  strlen(BLOCKS_FILE_NAME)+1))
370  == NULL)
371  {
372  corsaro_log(__func__, corsaro,
373  "could not malloc blocks file string");
374  return -1;
375  }
376 
379  ptr = stpncpy(state->locations_file, directory, strlen(directory));
380  *ptr++ = '/';
381  /* last copy needs a +1 to get the terminating nul. d'oh */
382  ptr = stpncpy(ptr, LOCATIONS_FILE_NAME, strlen(LOCATIONS_FILE_NAME)+1);
383 
384  ptr = stpncpy(state->blocks_file, directory, strlen(directory));
385  *ptr++ = '/';
386  ptr = stpncpy(ptr, BLOCKS_FILE_NAME, strlen(BLOCKS_FILE_NAME)+1);
387 
388  }
389 
390  if(state->locations_file == NULL || state->blocks_file == NULL)
391  {
392  fprintf(stderr, "ERROR: %s requires either '-d' or both '-b' and '-l'\n",
393  plugin->argv[0]);
394  usage(plugin);
395  return -1;
396  }
397 
398  if(state->provider_id == 0)
399  {
400  state->provider_id = CORSARO_GEO_PROVIDER_MAXMIND;
401  }
402 
403  return 0;
404 }
405 
406 /* Parse a maxmind location cell */
407 static void parse_maxmind_location_cell(void *s, size_t i, void *data)
408 {
409  corsaro_t *corsaro = (corsaro_t*)data;
410  struct corsaro_geodb_state_t *state = STATE(corsaro);
411  corsaro_geo_record_t *tmp = &(state->tmp_record);
412  char *tok = (char*)s;
413 
414  char *end;
415 
416  /* skip the first two lines */
417  if(state->current_line < MAXMIND_HEADER_ROW_CNT)
418  {
419  return;
420  }
421 
422  /*
423  corsaro_log(__func__, corsaro, "row: %d, column: %d, tok: %s",
424  state->current_line,
425  state->current_column,
426  tok);
427  */
428 
429  switch(state->current_column)
430  {
432  /* init this record */
433  tmp->id = strtol(tok, &end, 10);
434  if (end == tok || *end != '\0' || errno == ERANGE)
435  {
436  corsaro_log(__func__, corsaro, "Invalid ID Value (%s)", tok);
437  state->parser.status = CSV_EUSER;
438  return;
439  }
440  break;
441 
443  /* country code */
444  if(tok == NULL || strlen(tok) != 2)
445  {
446  corsaro_log(__func__, corsaro, "Invalid Country Code (%s)", tok);
447  state->parser.status = CSV_EUSER;
448  return;
449  }
450  state->cntry_code = (tok[0]<<8) | tok[1];
451  memcpy(tmp->country_code, tok, 2);
452  break;
453 
455  /* region string */
456  if(tok == NULL || strlen(tok) == 0)
457  {
458  tmp->region[0] = '\0';
459  }
460  else
461  {
462  tmp->region[2] = '\0';
463  memcpy(tmp->region, tok, 2);
464  }
465  break;
466 
468  /* city */
469  tmp->city = strndup(tok, strlen(tok));
470  break;
471 
473  /* postal code */
474  tmp->post_code = strndup(tok, strlen(tok));
475  break;
476 
478  /* latitude */
479  tmp->latitude = strtof(tok, &end);
480  if (end == tok || *end != '\0' || errno == ERANGE)
481  {
482  corsaro_log(__func__, corsaro, "Invalid Latitude Value (%s)", tok);
483  state->parser.status = CSV_EUSER;
484  return;
485  }
486  break;
487 
489  /* longitude */
490  tmp->longitude = strtof(tok, &end);
491  if (end == tok || *end != '\0' || errno == ERANGE)
492  {
493  corsaro_log(__func__, corsaro, "Invalid Longitude Value (%s)", tok);
494  state->parser.status = CSV_EUSER;
495  return;
496  }
497  break;
498 
500  /* metro code - whatever the heck that is */
501  if(tok != NULL)
502  {
503  tmp->metro_code = strtol(tok, &end, 10);
504  if (end == tok || *end != '\0' || errno == ERANGE)
505  {
506  corsaro_log(__func__, corsaro, "Invalid Metro Value (%s)", tok);
507  state->parser.status = CSV_EUSER;
508  return;
509  }
510  }
511  break;
512 
514  /* area code - (phone) */
515  if(tok != NULL)
516  {
517  tmp->area_code = strtol(tok, &end, 10);
518  if (end == tok || *end != '\0' || errno == ERANGE)
519  {
520  corsaro_log(__func__, corsaro,
521  "Invalid Area Code Value (%s)", tok);
522  state->parser.status = CSV_EUSER;
523  return;
524  }
525  }
526  break;
527 
528  default:
529  corsaro_log(__func__, corsaro, "Invalid Maxmind Location Column (%d:%d)",
530  state->current_line, state->current_column);
531  state->parser.status = CSV_EUSER;
532  return;
533  break;
534  }
535 
536  /* move on to the next column */
537  state->current_column++;
538 }
539 
541 static void parse_maxmind_location_row(int c, void *data)
542 {
543  corsaro_t *corsaro = (corsaro_t*)data;
544  struct corsaro_geodb_state_t *state = STATE(corsaro);
546 
547  khiter_t khiter;
548 
549  /* skip the first two lines */
550  if(state->current_line < MAXMIND_HEADER_ROW_CNT)
551  {
552  state->current_line++;
553  return;
554  }
555 
556  /* at the end of successful row parsing, current_column will be 9 */
557  /* make sure we parsed exactly as many columns as we anticipated */
558  if(state->current_column != MAXMIND_LOCATION_COL_COUNT)
559  {
560  corsaro_log(__func__, corsaro,
561  "ERROR: Expecting %d columns in the locations file, "
562  "but actually got %d",
563  MAXMIND_LOCATION_COL_COUNT, state->current_column);
564  state->parser.status = CSV_EUSER;
565  return;
566  }
567 
568  /* look up the continent code */
569  if((khiter = kh_get(u16u16, state->country_continent, state->cntry_code)) ==
570  kh_end(state->country_continent))
571  {
572  corsaro_log(__func__, corsaro, "ERROR: Invalid country code (%s) (%x)",
573  state->tmp_record.country_code,
574  state->cntry_code);
575  state->parser.status = CSV_EUSER;
576  return;
577  }
578 
579  state->tmp_record.continent_code =
580  kh_value(state->country_continent, khiter);
581 
582  /*
583  corsaro_log(__func__, NULL, "looking up %s (%x) got %x",
584  tmp.country_code, cntry_code, tmp.continent_code);
585  */
586 
587  if((record = corsaro_geo_init_record(state->provider,
588  state->tmp_record.id)) == NULL)
589  {
590  corsaro_log(__func__, corsaro, "ERROR: Could not initialize geo record");
591  state->parser.status = CSV_EUSER;
592  return;
593  }
594 
595  memcpy(record, &(state->tmp_record), sizeof(corsaro_geo_record_t));
596 
597  /* done processing the line */
598 
599  /* increment the current line */
600  state->current_line++;
601  /* reset the current column */
602  state->current_column = 0;
603  /* reset the temp record */
604  memset(&(state->tmp_record), 0, sizeof(corsaro_geo_record_t));
605  /* reset the country code */
606  state->cntry_code = 0;
607 
608  return;
609 }
610 
612 static void parse_netacq_edge_location_cell(void *s, size_t i, void *data)
613 {
614  corsaro_t *corsaro = (corsaro_t*)data;
615  struct corsaro_geodb_state_t *state = STATE(corsaro);
616  corsaro_geo_record_t *tmp = &(state->tmp_record);
617  char *tok = (char*)s;
618 
619  char *end;
620 
621  /* skip the first two lines */
622  if(state->current_line < NETACQ_EDGE_HEADER_ROW_CNT)
623  {
624  return;
625  }
626 
627  /*
628  corsaro_log(__func__, corsaro, "row: %d, column: %d, tok: %s",
629  state->current_line,
630  state->current_column,
631  tok);
632  */
633 
634  switch(state->current_column)
635  {
637  /* init this record */
638  tmp->id = strtol(tok, &end, 10);
639  if (end == tok || *end != '\0' || errno == ERANGE)
640  {
641  corsaro_log(__func__, corsaro, "Invalid ID Value (%s)", tok);
642  state->parser.status = CSV_EUSER;
643  return;
644  }
645  break;
646 
649  break;
650 
652  if(tok != NULL)
653  {
654  tmp->city = strndup(tok, strlen(tok));
655  }
656  break;
657 
659  if(tok != NULL)
660  {
661  tmp->conn_speed = strndup(tok, strlen(tok));
662  }
663  break;
664 
666  /* metro code - whatever the heck that is */
667  if(tok != NULL)
668  {
669  tmp->metro_code = strtol(tok, &end, 10);
670  if (end == tok || *end != '\0' || errno == ERANGE)
671  {
672  corsaro_log(__func__, corsaro, "Invalid Metro Value (%s)", tok);
673  state->parser.status = CSV_EUSER;
674  return;
675  }
676  }
677  break;
678 
680  tmp->latitude = strtof(tok, &end);
681  if (end == tok || *end != '\0' || errno == ERANGE)
682  {
683  corsaro_log(__func__, corsaro, "Invalid Latitude Value (%s)", tok);
684  state->parser.status = CSV_EUSER;
685  return;
686  }
687  break;
688 
690  /* longitude */
691  tmp->longitude = strtof(tok, &end);
692  if (end == tok || *end != '\0' || errno == ERANGE)
693  {
694  corsaro_log(__func__, corsaro, "Invalid Longitude Value (%s)", tok);
695  state->parser.status = CSV_EUSER;
696  return;
697  }
698  break;
699 
701  tmp->post_code = strndup(tok, strlen(tok));
702  break;
703 
707  break;
708 
710  if(tok != NULL)
711  {
712  tmp->continent_code = strtol(tok, &end, 10);
713  if (end == tok || *end != '\0' || errno == ERANGE)
714  {
715  corsaro_log(__func__, corsaro,
716  "Invalid Continent Code Value (%s)", tok);
717  state->parser.status = CSV_EUSER;
718  return;
719  }
720  }
721  break;
722 
724  if(tok == NULL || strlen(tok) != 2)
725  {
726  corsaro_log(__func__, corsaro, "Invalid Country Code (%s)", tok);
727  corsaro_log(__func__, corsaro,
728  "Invalid Net Acuity Edge Location Column (%d:%d)",
729  state->current_line, state->current_column);
730  state->parser.status = CSV_EUSER;
731  return;
732  }
733  memcpy(tmp->country_code, tok, 2);
734  break;
735 
745  break;
746 
747  default:
748  corsaro_log(__func__, corsaro,
749  "Invalid Net Acuity Edge Location Column (%d:%d)",
750  state->current_line, state->current_column);
751  state->parser.status = CSV_EUSER;
752  return;
753  break;
754  }
755 
756  /* move on to the next column */
757  state->current_column++;
758 
759  return;
760 }
761 
763 static void parse_netacq_edge_location_row(int c, void *data)
764 {
765  corsaro_t *corsaro = (corsaro_t*)data;
766  struct corsaro_geodb_state_t *state = STATE(corsaro);
768 
769  /* skip the first two lines */
770  if(state->current_line < NETACQ_EDGE_HEADER_ROW_CNT)
771  {
772  state->current_line++;
773  return;
774  }
775 
776  /* at the end of successful row parsing, current_column will be 9 */
777  /* make sure we parsed exactly as many columns as we anticipated */
778  if(state->current_column != NETACQ_EDGE_LOCATION_COL_COUNT)
779  {
780  corsaro_log(__func__, corsaro,
781  "ERROR: Expecting %d columns in the locations file, "
782  "but actually got %d",
783  NETACQ_EDGE_LOCATION_COL_COUNT, state->current_column);
784  state->parser.status = CSV_EUSER;
785  return;
786  }
787 
788  if((record = corsaro_geo_init_record(state->provider,
789  state->tmp_record.id)) == NULL)
790  {
791  corsaro_log(__func__, corsaro, "ERROR: Could not initialize geo record");
792  state->parser.status = CSV_EUSER;
793  return;
794  }
795 
796  memcpy(record, &(state->tmp_record), sizeof(corsaro_geo_record_t));
797 
798  /* done processing the line */
799 
800  /* increment the current line */
801  state->current_line++;
802  /* reset the current column */
803  state->current_column = 0;
804  /* reset the temp record */
805  memset(&(state->tmp_record), 0, sizeof(corsaro_geo_record_t));
806  /* reset the country code */
807  state->cntry_code = 0;
808 
809  return;
810 }
811 
813 static int read_locations(corsaro_t *corsaro, corsaro_file_in_t *file)
814 {
815  struct corsaro_geodb_state_t *state = STATE(corsaro);
816 
817  char buffer[BUFFER_LEN];
818  int read = 0;
819 
820  void (*cell_callback)(void *s, size_t i, void *data);
821  void (*row_callback)(int c, void *data);
822  const char *provider_name;
823  switch(STATE(corsaro)->provider_id)
824  {
826  cell_callback = parse_maxmind_location_cell;
827  row_callback = parse_maxmind_location_row;
828  provider_name = MAXMIND_NAME;
829  break;
830 
832  cell_callback = parse_netacq_edge_location_cell;
833  row_callback = parse_netacq_edge_location_row;
834  provider_name = NETACQ_EDGE_NAME;
835  break;
836 
837  default:
838  corsaro_log(__func__, corsaro, "Invalid provider type");
839  return -1;
840  }
841 
842  /* reset the state variables before we start */
843  state->current_column = 0;
844  state->current_line = 0;
845  memset(&(state->tmp_record), 0, sizeof(corsaro_geo_record_t));
846  state->cntry_code = 0;
847 
848  /* options for the csv parser */
849  int options = CSV_STRICT | CSV_REPALL_NL | CSV_STRICT_FINI |
850  CSV_APPEND_NULL | CSV_EMPTY_IS_NULL;
851 
852  csv_init(&(state->parser), options);
853 
854  while((read = corsaro_file_rread(file, &buffer, BUFFER_LEN)) > 0)
855  {
856  if(csv_parse(&(state->parser), buffer, read,
857  cell_callback,
858  row_callback,
859  corsaro) != read)
860  {
861  corsaro_log(__func__, corsaro,
862  "Error parsing %s Location file", provider_name);
863  corsaro_log(__func__, corsaro,
864  "CSV Error: %s",
865  csv_strerror(csv_error(&(state->parser))));
866  return -1;
867  }
868  }
869 
870  if(csv_fini(&(state->parser),
871  cell_callback,
872  row_callback,
873  corsaro) != 0)
874  {
875  corsaro_log(__func__, corsaro,
876  "Error parsing %s Location file", provider_name);
877  corsaro_log(__func__, corsaro,
878  "CSV Error: %s",
879  csv_strerror(csv_error(&(state->parser))));
880  return -1;
881  }
882 
883  csv_free(&(state->parser));
884 
885  return 0;
886 }
887 
889 static void parse_blocks_cell(void *s, size_t i, void *data)
890 {
891  corsaro_t *corsaro = (corsaro_t*)data;
892  struct corsaro_geodb_state_t *state = STATE(corsaro);
893  char *tok = (char*)s;
894  char *end;
895 
896  int skip = 0;
897  switch(STATE(corsaro)->provider_id)
898  {
900  skip = MAXMIND_HEADER_ROW_CNT;
901  break;
902 
905  break;
906 
907  default:
908  corsaro_log(__func__, corsaro, "Invalid provider type");
909  state->parser.status = CSV_EUSER;
910  return;
911  }
912  /* skip the first lines */
913  if(state->current_line < skip)
914  {
915  return;
916  }
917 
918  switch(state->current_column)
919  {
920  case BLOCKS_COL_STARTIP:
921  /* start ip */
922  state->block_lower.addr = strtol(tok, &end, 10);
923  if (end == tok || *end != '\0' || errno == ERANGE)
924  {
925  corsaro_log(__func__, corsaro, "Invalid Start IP Value (%s)", tok);
926  state->parser.status = CSV_EUSER;
927  }
928  break;
929 
930  case BLOCKS_COL_ENDIP:
931  /* end ip */
932  state->block_upper.addr = strtol(tok, &end, 10);
933  if (end == tok || *end != '\0' || errno == ERANGE)
934  {
935  corsaro_log(__func__, corsaro, "Invalid End IP Value (%s)", tok);
936  state->parser.status = CSV_EUSER;
937  }
938  break;
939 
940  case BLOCKS_COL_ID:
941  /* id */
942  state->block_id = strtol(tok, &end, 10);
943  if (end == tok || *end != '\0' || errno == ERANGE)
944  {
945  corsaro_log(__func__, corsaro, "Invalid ID Value (%s)", tok);
946  state->parser.status = CSV_EUSER;
947  }
948  break;
949 
950  default:
951  corsaro_log(__func__, corsaro, "Invalid Blocks Column (%d:%d)",
952  state->current_line, state->current_column);
953  state->parser.status = CSV_EUSER;
954  break;
955  }
956 
957  /* move on to the next column */
958  state->current_column++;
959 }
960 
961 static void parse_blocks_row(int c, void *data)
962 {
963  corsaro_t *corsaro = (corsaro_t*)data;
964  struct corsaro_geodb_state_t *state = STATE(corsaro);
965 
966  ip_prefix_list_t *pfx_list = NULL;
967  ip_prefix_list_t *temp = NULL;
969 
970  /* skip the first lines */
971  int skip = 0;
972  switch(STATE(corsaro)->provider_id)
973  {
975  skip = MAXMIND_HEADER_ROW_CNT;
976  break;
977 
980  break;
981 
982  default:
983  corsaro_log(__func__, corsaro, "Invalid provider type");
984  state->parser.status = CSV_EUSER;
985  return;
986  }
987  if(state->current_line < skip)
988  {
989  state->current_line++;
990  return;
991  }
992 
993  /* done processing the line */
994 
995  /* make sure we parsed exactly as many columns as we anticipated */
996  if(state->current_column != BLOCKS_COL_COUNT)
997  {
998  corsaro_log(__func__, corsaro,
999  "ERROR: Expecting %d columns in the blocks file, "
1000  "but actually got %d",
1001  BLOCKS_COL_COUNT, state->current_column);
1002  state->parser.status = CSV_EUSER;
1003  return;
1004  }
1005 
1006  assert(state->block_id > 0);
1007 
1008  /* convert the range to prefixes */
1009  if(ip_range_to_prefix(state->block_lower,
1010  state->block_upper,
1011  &pfx_list) != 0)
1012  {
1013  corsaro_log(__func__, corsaro,
1014  "ERROR: Could not convert range to pfxs");
1015  state->parser.status = CSV_EUSER;
1016  return;
1017  }
1018  assert(pfx_list != NULL);
1019 
1020  /* get the record from the provider */
1021  if((record = corsaro_geo_get_record(state->provider,
1022  state->block_id)) == NULL)
1023  {
1024  corsaro_log(__func__, corsaro,
1025  "ERROR: Missing record for location %d",
1026  state->block_id);
1027  state->parser.status = CSV_EUSER;
1028  return;
1029  }
1030 
1031  /* iterate over and add each prefix to the trie */
1032  while(pfx_list != NULL)
1033  {
1035  state->provider,
1036  htonl(pfx_list->prefix.addr),
1037  pfx_list->prefix.masklen,
1038  record) != 0)
1039  {
1040  corsaro_log(__func__, corsaro,
1041  "ERROR: Failed to associate record");
1042  state->parser.status = CSV_EUSER;
1043  return;
1044  }
1045 
1046  /* store this node so we can free it */
1047  temp = pfx_list;
1048  /* move on to the next pfx */
1049  pfx_list = pfx_list->next;
1050  /* free this node (saves us walking the list twice) */
1051  free(temp);
1052  }
1053 
1054  /* increment the current line */
1055  state->current_line++;
1056  /* reset the current column */
1057  state->current_column = 0;
1058 }
1059 
1061 static int read_blocks(corsaro_t *corsaro, corsaro_file_in_t *file)
1062 {
1063  struct corsaro_geodb_state_t *state = STATE(corsaro);
1064  char buffer[BUFFER_LEN];
1065  int read = 0;
1066 
1067  /* reset the state variables before we start */
1068  state->current_column = 0;
1069  state->current_line = 0;
1070  state->block_id = 0;
1071  state->block_lower.masklen = 32;
1072  state->block_upper.masklen = 32;
1073 
1074  /* options for the csv parser */
1075  int options = CSV_STRICT | CSV_REPALL_NL | CSV_STRICT_FINI |
1076  CSV_APPEND_NULL | CSV_EMPTY_IS_NULL;
1077 
1078  csv_init(&(state->parser), options);
1079 
1080 
1081  while((read = corsaro_file_rread(file, &buffer, BUFFER_LEN)) > 0)
1082  {
1083  if(csv_parse(&(state->parser), buffer, read,
1085  parse_blocks_row,
1086  corsaro) != read)
1087  {
1088  corsaro_log(__func__, corsaro,
1089  "Error parsing Blocks file");
1090  corsaro_log(__func__, corsaro,
1091  "CSV Error: %s",
1092  csv_strerror(csv_error(&(state->parser))));
1093  return -1;
1094  }
1095  }
1096 
1097  if(csv_fini(&(state->parser),
1099  parse_blocks_row,
1100  corsaro) != 0)
1101  {
1102  corsaro_log(__func__, corsaro,
1103  "Error parsing Maxmind Location file");
1104  corsaro_log(__func__, corsaro,
1105  "CSV Error: %s",
1106  csv_strerror(csv_error(&(state->parser))));
1107  return -1;
1108  }
1109 
1110  csv_free(&(state->parser));
1111 
1112  return 0;
1113 }
1114 
1117  uint32_t src_ip)
1118 {
1119  struct corsaro_geodb_state_t *plugin_state = STATE(corsaro);
1120 
1121  /* remove the old record from the provider */
1122  corsaro_geo_provider_clear(plugin_state->provider);
1123 
1124  /* add this record to the provider */
1125  corsaro_geo_provider_add_record(plugin_state->provider,
1127  corsaro,
1128  plugin_state->provider,
1129  src_ip));
1130 
1131 #if 0
1132 
1133  /* DEBUG */
1134  corsaro_geo_provider_t *provider;
1135  corsaro_geo_record_t *tmp = NULL;
1136  struct in_addr addr;
1137  addr.s_addr = src_ip;
1138 
1139  fprintf(stdout, "src: %s\n",
1140  inet_ntoa(addr));
1141 
1142  /* first, ask for the default geo provider */
1143  provider = corsaro_geo_get_default(corsaro);
1144  assert(provider != NULL);
1145 
1146  while((tmp = corsaro_geo_next_record(provider, tmp)) != NULL)
1147  {
1149  }
1150 #endif
1151 
1152  return 0;
1153 }
1154 
1155 /* == PUBLIC PLUGIN FUNCS BELOW HERE == */
1156 
1159 {
1160  return &corsaro_geodb_plugin;
1161 }
1162 
1164 int corsaro_geodb_probe_filename(const char *fname)
1165 {
1166  /* this writes no files! */
1167  return 0;
1168 }
1169 
1172  corsaro_file_in_t *file)
1173 {
1174  /* this writes no files! */
1175  return 0;
1176 }
1177 
1180 {
1181  struct corsaro_geodb_state_t *state;
1182  corsaro_plugin_t *plugin = PLUGIN(corsaro);
1183  corsaro_file_in_t *file = NULL;
1184 
1185  int country_cnt;
1186  int continent_cnt;
1187  const char **countries;
1188  const char **continents;
1189  uint16_t cntry_code = 0;
1190  uint16_t cont_code = 0;
1191  int i;
1192  khiter_t khiter;
1193  int khret;
1194 
1195  assert(plugin != NULL);
1196 
1197  if((state = malloc_zero(sizeof(struct corsaro_geodb_state_t))) == NULL)
1198  {
1199  corsaro_log(__func__, corsaro,
1200  "could not malloc corsaro_maxmind_state_t");
1201  return -1;
1202  }
1203  corsaro_plugin_register_state(corsaro->plugin_manager, plugin, state);
1204 
1205  /* parse the arguments */
1206  if(parse_args(corsaro) != 0)
1207  {
1208  return -1;
1209  }
1210 
1211  assert(state->locations_file != NULL && state->blocks_file != NULL
1212  && state->provider_id > 0);
1213 
1214  /* register us as a geolocation provider */
1215  if((state->provider =
1216  corsaro_geo_init_provider(corsaro,
1217  state->provider_id,
1220  {
1221  corsaro_log(__func__, corsaro, "could not register as a geolocation"
1222  " provider");
1223  return -1;
1224  }
1225 
1226  /* populate the country2continent hash */
1227  state->country_continent = kh_init(u16u16);
1228  country_cnt = corsaro_geo_get_maxmind_iso2_list(&countries);
1229  continent_cnt = corsaro_geo_get_maxmind_country_continent_list(&continents);
1230  assert(country_cnt == continent_cnt);
1231  for(i=0; i< country_cnt; i++)
1232  {
1233  cntry_code = (countries[i][0]<<8) | countries[i][1];
1234  cont_code = (continents[i][0]<<8) | continents[i][1];
1235 
1236  /* create a mapping for this country */
1237  khiter = kh_put(u16u16, state->country_continent, cntry_code, &khret);
1238  kh_value(state->country_continent, khiter) = cont_code;
1239  }
1240 
1241 
1242  /* open the locations file */
1243  if((file = corsaro_file_ropen(state->locations_file)) == NULL)
1244  {
1245  corsaro_log(__func__, corsaro,
1246  "failed to open location file '%s'", state->locations_file);
1247  return -1;
1248  }
1249 
1250  /* populate the locations hash */
1251  if(read_locations(corsaro, file) != 0)
1252  {
1253  corsaro_log(__func__, corsaro, "failed to parse locations file");
1254  goto err;
1255  }
1256 
1257  /* close the locations file */
1258  corsaro_file_rclose(file);
1259 
1260  /* open the blocks file */
1261  if((file = corsaro_file_ropen(state->blocks_file)) == NULL)
1262  {
1263  corsaro_log(__func__, corsaro,
1264  "failed to open blocks file '%s'", state->blocks_file);
1265  goto err;
1266  }
1267 
1268  /* populate the trie (by joining on the id in the hash) */
1269  if(read_blocks(corsaro, file) != 0)
1270  {
1271  corsaro_log(__func__, corsaro, "failed to parse blocks file");
1272  goto err;
1273  }
1274 
1275  /* close the blocks file */
1276  corsaro_file_rclose(file);
1277 
1278  return 0;
1279 
1280  err:
1281  if(file != NULL)
1282  {
1283  corsaro_file_rclose(file);
1284  }
1285  usage(plugin);
1286  return -1;
1287 }
1288 
1291 {
1292  assert(0);
1293  return -1;
1294 }
1295 
1298 {
1299  assert(0);
1300  return -1;
1301 }
1302 
1305 {
1306  struct corsaro_geodb_state_t *state = STATE(corsaro);
1307  if(state != NULL)
1308  {
1309  if(state->provider != NULL)
1310  {
1311  corsaro_geo_free_provider(corsaro, state->provider);
1312  state->provider = NULL;
1313  }
1314 
1315  if(state->locations_file != NULL)
1316  {
1317  free(state->locations_file);
1318  state->locations_file = NULL;
1319  }
1320 
1321  if(state->blocks_file != NULL)
1322  {
1323  free(state->blocks_file);
1324  state->blocks_file = NULL;
1325  }
1326 
1327  corsaro_plugin_free_state(corsaro->plugin_manager, PLUGIN(corsaro));
1328  }
1329  return 0;
1330 }
1331 
1334  corsaro_in_record_type_t *record_type,
1335  corsaro_in_record_t *record)
1336 {
1337  assert(0);
1338  return -1;
1339 }
1340 
1343  corsaro_in_record_type_t *record_type,
1344  corsaro_in_record_t *record)
1345 {
1346  /* we write nothing to the global file. someone messed up */
1347  return -1;
1348 }
1349 
1352  corsaro_interval_t *int_start)
1353 {
1354  /* we don't care */
1355  return 0;
1356 }
1357 
1360  corsaro_interval_t *int_end)
1361 {
1362  /* we don't care */
1363  return 0;
1364 }
1365 
1369 {
1370  libtrace_packet_t *ltpacket = LT_PKT(packet);
1371  libtrace_ip_t *ip_hdr = NULL;
1372 
1373  /* check for ipv4 */
1374  if((ip_hdr = trace_get_ip(ltpacket)) == NULL)
1375  {
1376  /* not an ip packet */
1377  return 0;
1378  }
1379 
1380  return process_generic(corsaro, &packet->state, ip_hdr->ip_src.s_addr);
1381 }
1382 
1383 #ifdef WITH_PLUGIN_SIXT
1384 
1385 int corsaro_geodb_process_flowtuple(corsaro_t *corsaro,
1386  corsaro_flowtuple_t *flowtuple,
1387  corsaro_packet_state_t *state)
1388 {
1389  return process_generic(corsaro, state,
1390  corsaro_flowtuple_get_source_ip(flowtuple));
1391 }
1392 
1394 int corsaro_geodb_process_flowtuple_class_start(corsaro_t *corsaro,
1395  corsaro_flowtuple_class_start_t *class)
1396 {
1397  /* we dont care about these */
1398  return 0;
1399 }
1400 
1402 int corsaro_geodb_process_flowtuple_class_end(corsaro_t *corsaro,
1403  corsaro_flowtuple_class_end_t *class)
1404 {
1405  /* dont care */
1406  return 0;
1407 }
1408 #endif
Structure representing the start or end of an interval.
Definition: corsaro_int.h:156
uint32_t id
A unique ID for this record (used to join the Blocks and Locations Files)
Definition: corsaro_geo.h:52
An opaque structure defining an corsaro input file.
Definition: corsaro_file.h:86
#define DEFAULT_PROVIDER_NAME
The default provider name.
Definition: corsaro_geodb.c:87
static int read_blocks(corsaro_t *corsaro, corsaro_file_in_t *file)
Read a blocks file (maxmind or netacq)
Header file dealing with the corsaro plugin manager.
char * conn_speed
Connection Speed/Type.
Definition: corsaro_geo.h:85
Default Geolocation data-structure.
Definition: corsaro_geo.h:170
Postal Code String.
static void usage(corsaro_plugin_t *plugin)
Print usage information to stderr.
Header file dealing with the corsaro logging sub-system.
Total number of columns in the locations table.
#define PLUGIN_NAME
The name of this plugin.
Definition: corsaro_geodb.c:76
A reusable opaque structure for corsaro to read an input record into.
Definition: corsaro_int.h:350
void corsaro_geo_free_provider(corsaro_t *corsaro, corsaro_geo_provider_t *provider)
Free the given geolocation provider object.
Definition: corsaro_geo.c:299
static int process_generic(corsaro_t *corsaro, corsaro_packet_state_t *state, uint32_t src_ip)
Common code between process_packet and process_flowtuple.
int corsaro_geo_get_maxmind_iso2_list(const char ***countries)
Get a list of all possible ISO-3166-1 2 character country codes that maxmind uses.
Definition: corsaro_geo.c:734
char ** argv
Array of plugin arguments This is populated by the plugin manager in corsaro_plugin_enable_plugin.
int corsaro_geodb_close_input(corsaro_in_t *corsaro)
Implements the close_input function of the plugin API.
#define LT_PKT(corsaro_packet)
Convenience macro to get to the libtrace packet inside an corsaro packet.
Definition: corsaro_int.h:227
Geolocation data from Net Acuity Edge.
Definition: corsaro_geo.h:126
Total number of columns in locations table.
int corsaro_geodb_close_output(corsaro_t *corsaro)
Implements the close_output function of the plugin API.
enum blocks_cols blocks_cols_t
The columns in the maxmind locations CSV file.
This provider should be the default geolocation result.
Definition: corsaro_geo.h:110
void corsaro_geo_provider_add_record(corsaro_geo_provider_t *provider, corsaro_geo_record_t *record)
Add the given geolocation record to the head of the given geolocation provider object.
Definition: corsaro_geo.c:465
static void parse_maxmind_location_row(int c, void *data)
Handle an end-of-row event from the CSV parser.
Total number of columns in blocks table.
Structure which represents a geolocation provider.
Definition: corsaro_geo.h:137
static int read_locations(corsaro_t *corsaro, corsaro_file_in_t *file)
Read a locations file.
corsaro_geo_record_t * corsaro_geo_provider_lookup_record(corsaro_t *corsaro, corsaro_geo_provider_t *provider, uint32_t addr)
Look up the given address in the provider's datastructure.
Definition: corsaro_geo.c:437
char country_code[3]
2 character string which holds the ISO2 country code
Definition: corsaro_geo.h:55
Header file which exports corsaro_flowtuple plugin API.
static libtrace_packet_t * packet
A pointer to a libtrace packet.
Definition: corsaro_main.c:67
void corsaro_plugin_free_state(corsaro_plugin_manager_t *manager, corsaro_plugin_t *plugin)
Free the state for a plugin.
void corsaro_geo_dump_record(corsaro_geo_record_t *record)
Dump the given geolocation record to stdout (for debugging)
Definition: corsaro_geo.c:536
Header file for common utility functions.
A lightweight wrapper around a libtrace packet.
Definition: corsaro_int.h:211
corsaro_plugin_manager_t * plugin_manager
A pointer to the corsaro plugin manager state.
Definition: corsaro_int.h:273
#define MAXMIND_HEADER_ROW_CNT
The number of header rows in the maxmind CSV files.
ip_prefix_t prefix
The prefix that this element represents.
Definition: ip_utils.h:44
#define CORSARO_PLUGIN_GENERATE_PTRS(plugin)
Convenience macro that defines all the function pointers for the corsaro plugin API.
An element in a linked list of IP prefixes.
Definition: ip_utils.h:41
int corsaro_geo_get_maxmind_country_continent_list(const char ***continents)
Get a mapping of continent codes that maxmind uses.
Definition: corsaro_geo.c:770
void corsaro_plugin_register_state(corsaro_plugin_manager_t *manager, corsaro_plugin_t *plugin, void *state)
Register the state for a plugin.
#define BLOCKS_FILE_NAME
The default file name for the blocks file.
uint8_t masklen
The length of the prefix mask.
Definition: ip_utils.h:37
uint32_t corsaro_flowtuple_get_source_ip(corsaro_flowtuple_t *flowtuple)
Convenience function to get the source IP address from a FlowTuple.
int corsaro_geo_provider_clear(corsaro_geo_provider_t *provider)
Remove all the existing records from the given geolocation provider.
Definition: corsaro_geo.c:447
void corsaro_file_rclose(corsaro_file_in_t *file)
Closes an corsaro input file and frees the reader structure.
Definition: corsaro_file.c:428
corsaro_geo_record_t * corsaro_geo_next_record(corsaro_geo_provider_t *provider, corsaro_geo_record_t *record)
Retrieve the next geolocation provider record in the list.
Definition: corsaro_geo.c:521
netacq_edge_locations_cols
The columns in the netacq_edge locations CSV file.
static void parse_blocks_cell(void *s, size_t i, void *data)
Parse a blocks cell.
#define CORSARO_PLUGIN_GENERATE_TAIL
Convenience macro that defines all the 'remaining' blank fields in a corsaro plugin object...
void * malloc_zero(const size_t size)
Allocate memory and set it to zero.
Definition: utils.c:78
#define STATE(corsaro)
Extends the generic plugin state convenience macro in corsaro_plugin.h.
Area Code (phone)
#define LOCATIONS_FILE_NAME
The default file name for the locations file.
static corsaro_in_record_t * record
A pointer to a corsaro record.
Definition: corsaro_main.c:76
int argc
Count of arguments in argv.
Geolocation Database Lookup Plugin.
int corsaro_geodb_init_input(corsaro_in_t *corsaro)
Implements the init_input function of the plugin API.
double latitude
Latitude of the city.
Definition: corsaro_geo.h:73
Range Start IP.
2 Char Country Code
Definition: corsaro_geodb.c:97
double longitude
Longitude of the city.
Definition: corsaro_geo.h:76
corsaro_plugin_t * corsaro_geodb_alloc(corsaro_t *corsaro)
Implements the alloc function of the plugin API.
Geolocation data from Maxmind (Geo or GeoLite)
Definition: corsaro_geo.h:123
corsaro_packet_state_t state
The corsaro state associated with this packet.
Definition: corsaro_int.h:214
blocks_cols
The columns in the maxmind locations CSV file.
corsaro_geo_record_t * corsaro_geo_get_record(corsaro_geo_provider_t *provider, uint32_t id)
Get the geolocation record for the given id.
Definition: corsaro_geo.c:372
off_t corsaro_file_rread(corsaro_file_in_t *file, void *buffer, off_t len)
Reads from an corsaro input file into the provided buffer.
Definition: corsaro_file.c:332
KHASH_INIT(u16u16, uint16_t, uint16_t, 1, kh_int_hash_func, kh_int_hash_equal)
Common plugin information across all instances.
int corsaro_geodb_init_output(corsaro_t *corsaro)
Implements the init_output function of the plugin API.
corsaro_geo_provider_t * corsaro_geo_get_default(corsaro_t *corsaro)
Retrieve the provider object for the default geolocation provider.
Definition: corsaro_geo.c:489
#define MAXMIND_NAME
The name of the maxmind provider.
Definition: corsaro_geodb.c:79
int corsaro_geodb_probe_filename(const char *fname)
Implements the probe_filename function of the plugin API.
corsaro_geo_provider_t * corsaro_geo_init_provider(corsaro_t *corsaro, corsaro_geo_provider_id_t provider_id, corsaro_geo_datastructure_id_t ds_id, corsaro_geo_provider_default_t set_default)
Allocate a geolocation provider object in the packet state.
Definition: corsaro_geo.c:222
char region[3]
2 character string which represents the region the city is in
Definition: corsaro_geo.h:61
2 Char Country Code
uint32_t area_code
Area code.
Definition: corsaro_geo.h:82
char * post_code
String which contains the postal code.
Definition: corsaro_geo.h:70
int corsaro_geo_provider_associate_record(corsaro_t *corsaro, corsaro_geo_provider_t *provider, uint32_t addr, uint8_t mask, corsaro_geo_record_t *record)
Register a new prefix to record mapping for the given provider.
Definition: corsaro_geo.c:425
Corsaro input state.
Definition: corsaro_int.h:323
static int parse_args(corsaro_t *corsaro)
Parse the arguments given to the plugin.
Structure which contains a geolocation record.
Definition: corsaro_geo.h:45
int corsaro_geodb_start_interval(corsaro_t *corsaro, corsaro_interval_t *int_start)
Implements the start_interval function of the plugin API.
3 Char Country Code
#define NETACQ_EDGE_HEADER_ROW_CNT
The number of header rows in the netacq edge CSV files.
uint32_t metro_code
Metro code.
Definition: corsaro_geo.h:79
struct ip_prefix_list * next
The next prefix in the list.
Definition: ip_utils.h:46
Corsaro state for a packet.
Definition: corsaro_int.h:194
enum maxmind_locations_cols maxmind_locations_cols_t
The columns in the maxmind locations CSV file.
enum netacq_edge_locations_cols netacq_edge_locations_cols_t
The columns in the netacq_edge locations CSV file.
Connection Speed String.
int continent_code
Continent Code.
Definition: corsaro_geo.h:58
int corsaro_geodb_process_packet(corsaro_t *corsaro, corsaro_packet_t *packet)
Implements the process_packet function of the plugin API.
#define BUFFER_LEN
The length of the static line buffer.
Definition: corsaro_geodb.c:90
Corsaro output state.
Definition: corsaro_int.h:230
Represents a IPv4 prefix e.g.
Definition: ip_utils.h:32
uint32_t addr
The address component of the prefix.
Definition: ip_utils.h:35
corsaro_file_in_t * corsaro_file_ropen(const char *filename)
Creates a new corsaro file reader and opens the provided file for reading.
Definition: corsaro_file.c:256
int corsaro_geodb_end_interval(corsaro_t *corsaro, corsaro_interval_t *int_end)
Implements the end_interval function of the plugin API.
void corsaro_log(const char *func, corsaro_t *corsaro, const char *format,...)
Write a formatted string to the logfile associated with an corsaro object.
Definition: corsaro_log.c:113
off_t corsaro_geodb_read_global_data_record(corsaro_in_t *corsaro, corsaro_in_record_type_t *record_type, corsaro_in_record_t *record)
Implements the read_global_data_record function of the plugin API.
int corsaro_geodb_probe_magic(corsaro_in_t *corsaro, corsaro_file_in_t *file)
Implements the probe_magic function of the plugin API.
#define NETACQ_EDGE_NAME
The name of the netacq edge provider.
Definition: corsaro_geodb.c:83
Range End IP.
#define PLUGIN(corsaro)
Extends the generic plugin plugin convenience macro in corsaro_plugin.h.
char * city
String which contains the city name.
Definition: corsaro_geo.h:64
enum corsaro_geo_provider_id corsaro_geo_provider_id_t
A unique identifier for each geolocation provider that corsaro supports.
maxmind_locations_cols
The columns in the maxmind locations CSV file.
Definition: corsaro_geodb.c:93
#define CORSARO_GEODB_MAGIC
The magic number for this plugin - "GODB".
Definition: corsaro_geodb.c:73
enum corsaro_in_record_type corsaro_in_record_type_t
Corsaro input record types.
Header file dealing with the corsaro geolocation subsystem.
An corsaro packet processing plugin.
static void parse_netacq_edge_location_row(int c, void *data)
Handle an end-of-row event from the CSV parser.
off_t corsaro_geodb_read_record(struct corsaro_in *corsaro, corsaro_in_record_type_t *record_type, corsaro_in_record_t *record)
Implements the read_record function of the plugin API.
static void parse_netacq_edge_location_cell(void *s, size_t i, void *data)
Parse a netacq location cell.
corsaro_geo_record_t * corsaro_geo_init_record(corsaro_geo_provider_t *provider, uint32_t id)
Allocate an empty geolocation record for the given id.
Definition: corsaro_geo.c:346
Header file dealing with the internal corsaro functions.