Skip to Content
[CAIDA - Center for Applied Internet Data Analysis logo]
The Center for Applied Internet Data Analysis
corsaro_filtergeo.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 <assert.h>
30 #include <inttypes.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "libtrace.h"
37 
38 #include "khash.h"
39 #include "utils.h"
40 
41 #include "corsaro_geo.h"
42 #include "corsaro_io.h"
43 #include "corsaro_log.h"
44 #include "corsaro_plugin.h"
45 
46 #ifdef WITH_PLUGIN_SIXT
47 #include "corsaro_flowtuple.h"
48 #endif
49 
50 #include "corsaro_filtergeo.h"
51 
61 #define CORSARO_ANON_MAGIC 0x4647454F
62 
64 #define PLUGIN_NAME "filtergeo"
65 
67 #define BUFFER_LEN 1024
68 
71 #define MAX_COMMAND_LINE_COUNTRIES 100
72 
75  PLUGIN_NAME, /* name */
77  CORSARO_ANON_MAGIC, /* magic */
78 #ifdef WITH_PLUGIN_SIXT
79  CORSARO_PLUGIN_GENERATE_PTRS_FT(corsaro_filtergeo), /* func ptrs */
80 #else
81  CORSARO_PLUGIN_GENERATE_PTRS(corsaro_filtergeo),
82 #endif
84 };
85 
86 /* to contain the list of country codes that we will filter on */
87 KHASH_SET_INIT_STR(country)
88 
89 
90 struct corsaro_filtergeo_state_t {
92  khash_t(country) *countries;
93 
95  char *country_file;
96 
98  char *cmd_countries[MAX_COMMAND_LINE_COUNTRIES];
99 
101  int cmd_country_cnt;
102 
105  uint8_t invert;
106 };
107 
109 #define STATE(corsaro) \
110  (CORSARO_PLUGIN_STATE(corsaro, filtergeo, CORSARO_PLUGIN_ID_FILTERGEO))
111 
113 #define PLUGIN(corsaro) \
114  (CORSARO_PLUGIN_PLUGIN(corsaro, CORSARO_PLUGIN_ID_FILTERGEO))
115 
117 static void usage(corsaro_plugin_t *plugin)
118 {
119  fprintf(stderr,
120  "plugin usage: %s [-di] [-c country [-p country]] [-f country_file]\n"
121  " -c country code to match against, -c can be used "
122  "up to %d times\n"
123  " Note: use 2 character ISO 3166-1 alpha-2 codes\n"
124  " -f read countries from the given file\n"
125  " -i invert the matching (default: find matches)\n",
126  plugin->argv[0],
128 }
129 
132 {
133  corsaro_plugin_t *plugin = PLUGIN(corsaro);
134  struct corsaro_filtergeo_state_t *state = STATE(corsaro);
135  int opt;
136 
137  /* remember the storage for the argv strings belongs to us, we don't need
138  to strdup them */
139 
140  /* NB: remember to reset optind to 1 before using getopt! */
141  optind = 1;
142 
143  while((opt = getopt(plugin->argc, plugin->argv, "c:f:i?")) >= 0)
144  {
145  switch(opt)
146  {
147 
148  case 'f':
149  state->country_file = optarg;
150  break;
151 
152  case 'i':
153  state->invert = 1;
154  break;
155 
156  case 'c':
157  if(state->cmd_country_cnt == MAX_COMMAND_LINE_COUNTRIES)
158  {
159  fprintf(stderr, "ERROR: A maximum of %d countries can be "
160  "specified using the -c option.\n"
161  "Consider using the -f option instead\n",
163  usage(plugin);
164  return -1;
165  }
166  state->cmd_countries[state->cmd_country_cnt] = optarg;
167  state->cmd_country_cnt++;
168  break;
169 
170  case '?':
171  case ':':
172  default:
173  usage(plugin);
174  return -1;
175  }
176  }
177 
178  if(state->country_file == NULL && state->cmd_country_cnt == 0)
179  {
180  fprintf(stderr, "ERROR: %s requires either '-f' or '-c' to be specified\n",
181  plugin->argv[0]);
182  usage(plugin);
183  return -1;
184  }
185 
186  if(state->country_file != NULL && state->cmd_country_cnt > 0)
187  {
188  fprintf(stderr,
189  "WARNING: both -f and -c used, all specified countries "
190  "will be used\n");
191  }
192 
193  return 0;
194 }
195 
197 static int add_country(corsaro_t *corsaro, char *cc_str)
198 {
199  int khret;
200 
201  /* a country code needs to be two characters long */
202  /* lets be kind */
203  if(strnlen(cc_str, BUFFER_LEN) != 2)
204  {
205  corsaro_log(__func__, corsaro, "Invalid country code %s",
206  cc_str);
207  return -1;
208  }
209 
210  /* is it already in the hash ? */
211  if(kh_get(country, STATE(corsaro)->countries, cc_str)
212  == kh_end(STATE(corsaro)->countries))
213  {
214  kh_put(country, STATE(corsaro)->countries, strndup(cc_str, 2), &khret);
215  }
216 
217  return 0;
218 }
219 
222 {
223  char buffer[BUFFER_LEN];
224 
225  while(corsaro_file_rgets(file, &buffer, BUFFER_LEN) > 0)
226  {
227  /* hack off the newline */
228  chomp(buffer);
229 
230  if(strnlen(buffer, BUFFER_LEN) == 0)
231  {
232  continue;
233  }
234 
235  if(add_country(corsaro, buffer) != 0)
236  {
237  return -1;
238  }
239  }
240 
241  return 0;
242 }
243 
246 {
247  struct corsaro_filtergeo_state_t *fg_state = STATE(corsaro);
248  corsaro_geo_provider_t *provider;
250  char *country = "--";
251 
252  /* first, ask for the default geo provider */
253  if((provider = corsaro_geo_get_default(corsaro)) == NULL)
254  {
255  /* no provider? this can't be what they want */
256  corsaro_log(__func__, corsaro, "WARNING: No default geolocation "
257  "provider is available");
258  return;
259  }
260 
261  /* we will only look at the first record for this packet */
262  if((record = corsaro_geo_next_record(provider, NULL)) != NULL)
263  {
264  /* check the country */
265  if(record->country_code != NULL)
266  {
267  country = record->country_code;
268  }
269  }
270 
271  /* now, country will either be "--", or a country code */
272 
273  if(kh_get(country, fg_state->countries, country)
274  == kh_end(fg_state->countries))
275  {
276  /* this country is NOT in the hash */
277  if(fg_state->invert == 0)
278  {
280  }
281  }
282  else
283  {
284  /* this country IS in the hash */
285  if(fg_state->invert != 0)
286  {
288  }
289  }
290 
291  return;
292 }
293 
295 static inline void str_free(const char *str)
296 {
297  free((char*)str);
298 }
299 
300 /* == PUBLIC PLUGIN FUNCS BELOW HERE == */
301 
304 {
305  return &corsaro_filtergeo_plugin;
306 }
307 
309 int corsaro_filtergeo_probe_filename(const char *fname)
310 {
311  /* this does not write files */
312  return 0;
313 }
314 
317 {
318  /* this does not write files */
319  return 0;
320 }
321 
324 {
325  struct corsaro_filtergeo_state_t *state;
326  corsaro_plugin_t *plugin = PLUGIN(corsaro);
327  corsaro_file_in_t *file = NULL;
328  int i;
329 
330  assert(plugin != NULL);
331 
332  if((state = malloc_zero(sizeof(struct corsaro_filtergeo_state_t))) == NULL)
333  {
334  corsaro_log(__func__, corsaro,
335  "could not malloc corsaro_filtergeo_state_t");
336  goto err;
337  }
338  corsaro_plugin_register_state(corsaro->plugin_manager, plugin, state);
339 
340  /* parse the arguments */
341  if(parse_args(corsaro) != 0)
342  {
343  /* parse args calls usage itself, so do not goto err here */
344  return -1;
345  }
346 
347  state->countries = kh_init(country);
348 
349  /* read in countries from country_file (if there is one) */
350  if(state->country_file != NULL)
351  {
352  if((file = corsaro_file_ropen(state->country_file)) == NULL)
353  {
354  corsaro_log(__func__, corsaro,
355  "failed to open country file '%s'", state->country_file);
356 
357  goto err;
358  }
359 
360  if(read_country_file(corsaro, file) != 0)
361  {
362  corsaro_log(__func__, corsaro,
363  "failed to read country file '%s'", state->country_file);
364  goto err;
365  }
366 
367  /* close the country file */
368  corsaro_file_rclose(file);
369  file = NULL;
370  }
371 
372  /* add the countries that have been manually specified */
373  for(i = 0; i < state->cmd_country_cnt; i++)
374  {
375  if(add_country(corsaro, state->cmd_countries[i]) != 0)
376  {
377  goto err;
378  }
379  }
380 
381  return 0;
382 
383  err:
385  return -1;
386 }
387 
390 {
391  assert(0);
392  return -1;
393 }
394 
397 {
398  assert(0);
399  return -1;
400 }
401 
404 {
405  struct corsaro_filtergeo_state_t *state = STATE(corsaro);
406 
407  if(state != NULL)
408  {
409  if(state->countries != NULL)
410  {
411  kh_free(country, state->countries, str_free);
412  kh_destroy(country, state->countries);
413  state->countries = NULL;
414  }
415 
416  corsaro_plugin_free_state(corsaro->plugin_manager, PLUGIN(corsaro));
417  }
418 
419  return 0;
420 }
421 
424  corsaro_in_record_type_t *record_type,
426 {
427  assert(0);
428  return -1;
429 }
430 
433  enum corsaro_in_record_type *record_type,
434  struct corsaro_in_record *record)
435 {
436  /* we write nothing to the global file. someone messed up */
437  return -1;
438 }
439 
442  corsaro_interval_t *int_start)
443 {
444  /* we do not care */
445  return 0;
446 }
447 
450  corsaro_interval_t *int_end)
451 {
452  /* we do not care */
453  return 0;
454 }
455 
459 {
460  process_generic(corsaro, &packet->state);
461  return 0;
462 }
463 
464 #ifdef WITH_PLUGIN_SIXT
465 
466 int corsaro_filtergeo_process_flowtuple(corsaro_t *corsaro,
467  corsaro_flowtuple_t *flowtuple,
468  corsaro_packet_state_t *state)
469 {
470  process_generic(corsaro, state);
471  return 0;
472 }
473 
475 int corsaro_filtergeo_process_flowtuple_class_start(corsaro_t *corsaro,
476  corsaro_flowtuple_class_start_t *class)
477 {
478  /* we dont care about these */
479  return 0;
480 }
481 
483 int corsaro_filtergeo_process_flowtuple_class_end(corsaro_t *corsaro,
484  corsaro_flowtuple_class_end_t *class)
485 {
486  /* dont care */
487  return 0;
488 }
489 #endif
Structure representing the start or end of an interval.
Definition: corsaro_int.h:156
An opaque structure defining an corsaro input file.
Definition: corsaro_file.h:86
Plugins which write output should ignore this packet.
Definition: corsaro_int.h:207
int corsaro_filtergeo_end_interval(corsaro_t *corsaro, corsaro_interval_t *int_end)
Implements the end_interval function of the plugin API.
Header file dealing with the corsaro plugin manager.
off_t corsaro_file_rgets(corsaro_file_in_t *file, void *buffer, off_t len)
Reads a string from an corsaro input file into the provided buffer.
Definition: corsaro_file.c:343
Header file dealing with the corsaro logging sub-system.
corsaro_plugin_t * corsaro_filtergeo_alloc(corsaro_t *corsaro)
Implements the alloc function of the plugin API.
A reusable opaque structure for corsaro to read an input record into.
Definition: corsaro_int.h:350
char ** argv
Array of plugin arguments This is populated by the plugin manager in corsaro_plugin_enable_plugin.
static void usage(corsaro_plugin_t *plugin)
Print usage information to stderr.
int corsaro_filtergeo_init_output(corsaro_t *corsaro)
Implements the init_output function of the plugin API.
static int parse_args(corsaro_t *corsaro)
Parse the arguments given to the plugin.
int corsaro_filtergeo_close_output(corsaro_t *corsaro)
Implements the close_output function of the plugin API.
int corsaro_filtergeo_process_packet(corsaro_t *corsaro, corsaro_packet_t *packet)
Implements the process_packet function of the plugin API.
Structure which represents a geolocation provider.
Definition: corsaro_geo.h:137
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.
static void str_free(const char *str)
Free a string (used to clear the hash)
int corsaro_filtergeo_start_interval(corsaro_t *corsaro, corsaro_interval_t *int_start)
Implements the start_interval function of the plugin API.
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 CORSARO_PLUGIN_GENERATE_PTRS(plugin)
Convenience macro that defines all the function pointers for the corsaro plugin API.
corsaro_in_record_type
Corsaro input record types.
Definition: corsaro.h:97
void corsaro_plugin_register_state(corsaro_plugin_manager_t *manager, corsaro_plugin_t *plugin, void *state)
Register the state for a plugin.
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
#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 PLUGIN(corsaro)
Extends the generic plugin plugin convenience macro in corsaro_plugin.h.
static int read_country_file(corsaro_t *corsaro, corsaro_file_in_t *file)
Read a file containing a list of country codes.
static corsaro_in_record_t * record
A pointer to a corsaro record.
Definition: corsaro_main.c:76
int argc
Count of arguments in argv.
#define CORSARO_ANON_MAGIC
The magic number for this plugin - "FGEO".
void chomp(char *line)
Remove a newline from the given string.
Definition: utils.c:114
corsaro_packet_state_t state
The corsaro state associated with this packet.
Definition: corsaro_int.h:214
uint8_t flags
Features of the packet that have been identified by earlier plugins.
Definition: corsaro_int.h:197
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 MAX_COMMAND_LINE_COUNTRIES
The max number of countries which can be supplied on the command line, if you have more than this...
int corsaro_filtergeo_close_input(corsaro_in_t *corsaro)
Implements the close_input function of the plugin API.
Corsaro input state.
Definition: corsaro_int.h:323
off_t corsaro_filtergeo_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.
Structure which contains a geolocation record.
Definition: corsaro_geo.h:45
off_t corsaro_filtergeo_read_global_data_record(struct corsaro_in *corsaro, enum corsaro_in_record_type *record_type, struct corsaro_in_record *record)
Implements the read_global_data_record function of the plugin API.
int corsaro_filtergeo_probe_filename(const char *fname)
Implements the probe_filename function of the plugin API.
Corsaro state for a packet.
Definition: corsaro_int.h:194
#define PLUGIN_NAME
The name of this plugin.
static corsaro_plugin_t corsaro_filtergeo_plugin
Common plugin information across all instances.
Header file dealing with the corsaro file IO.
int corsaro_filtergeo_probe_magic(corsaro_in_t *corsaro, corsaro_file_in_t *file)
Implements the probe_magic function of the plugin API.
Corsaro output state.
Definition: corsaro_int.h:230
static void process_generic(corsaro_t *corsaro, corsaro_packet_state_t *state)
Common code between process_packet and process_flowtuple.
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
static int add_country(corsaro_t *corsaro, char *cc_str)
Parse a country code string and add it to the hash.
int corsaro_filtergeo_init_input(corsaro_in_t *corsaro)
Implements the init_input 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
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.
#define BUFFER_LEN
The length of the static line buffer.
#define STATE(corsaro)
Extends the generic plugin state convenience macro in corsaro_plugin.h.
Header file dealing with the internal corsaro functions.