Back to index

tor  0.2.3.19-rc
Functions
geoip.h File Reference

Header file for geoip.c. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int should_record_bridge_info (const or_options_t *options)
 Return 1 if we should collect geoip stats on bridge users, and include them in our extrainfo descriptor.
int geoip_load_file (const char *filename, const or_options_t *options)
 Clear the GeoIP database and reload it from the file filename.
int geoip_get_country_by_ip (uint32_t ipaddr)
 Given an IP address in host order, return a number representing the country to which that address belongs, -1 for "No geoip information available", or 0 for the 'unknown country'.
int geoip_get_country_by_addr (const tor_addr_t *addr)
 Given an IP address, return a number representing the country to which that address belongs, -1 for "No geoip information available", or 0 for the 'unknown country'.
int geoip_get_n_countries (void)
 Return the number of countries recognized by the GeoIP database.
const char * geoip_get_country_name (country_t num)
 Return the two-letter country code associated with the number num, or "??" for an unknown value.
int geoip_is_loaded (void)
 Return true iff we have loaded a GeoIP database.
const char * geoip_db_digest (void)
 Return the hex-encoded SHA1 digest of the loaded GeoIP file.
country_t geoip_get_country (const char *countrycode)
 Return the index of the country's entry in the GeoIP DB if it is a valid 2-letter country code, otherwise return -1.
void geoip_note_client_seen (geoip_client_action_t action, const tor_addr_t *addr, time_t now)
 Note that we've seen a client connect from the IP addr at time now.
void geoip_remove_old_clients (time_t cutoff)
 Forget about all clients that haven't connected since cutoff.
void geoip_note_ns_response (geoip_client_action_t action, geoip_ns_response_t response)
 Note that we've rejected a client's request for a v2 or v3 network status, encoded in action for reason reason at time now.
char * geoip_get_client_history (geoip_client_action_t action)
 Return a newly allocated comma-separated string containing entries for all the countries from which we've seen enough clients connect as a bridge, directory server, or entry guard.
char * geoip_get_request_history (geoip_client_action_t action)
 Return a newly allocated string holding the per-country request history for action in a format suitable for an extra-info document, or NULL on failure.
int getinfo_helper_geoip (control_connection_t *control_conn, const char *question, char **answer, const char **errmsg)
 Helper used to implement GETINFO ip-to-country/...
void geoip_free_all (void)
 Release all storage held in this file.
void geoip_start_dirreq (uint64_t dirreq_id, size_t response_size, geoip_client_action_t action, dirreq_type_t type)
 Note that an either direct or tunneled (see type) directory request for a network status with unique ID dirreq_id of size response_size and action action (either v2 or v3) has started.
void geoip_change_dirreq_state (uint64_t dirreq_id, dirreq_type_t type, dirreq_state_t new_state)
 Change the state of the either direct or tunneled (see type) directory request with dirreq_id to new_state and possibly mark it as completed.
void geoip_dirreq_stats_init (time_t now)
 Initialize directory request stats.
void geoip_reset_dirreq_stats (time_t now)
 Reset counters for dirreq stats.
char * geoip_format_dirreq_stats (time_t now)
 Return a newly allocated string containing the dirreq statistics until now, or NULL if we're not collecting dirreq stats.
time_t geoip_dirreq_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current dirreq stats period, write dirreq stats to $DATADIR/stats/dirreq-stats (possibly overwriting an existing file) and reset counters.
void geoip_dirreq_stats_term (void)
 Stop collecting directory request stats in a way that we can re-start doing so in geoip_dirreq_stats_init().
void geoip_entry_stats_init (time_t now)
 Initialize entry stats.
time_t geoip_entry_stats_write (time_t now)
 If 24 hours have passed since the beginning of the current entry stats period, write entry stats to $DATADIR/stats/entry-stats (possibly overwriting an existing file) and reset counters.
void geoip_entry_stats_term (void)
 Stop collecting entry stats in a way that we can re-start doing so in geoip_entry_stats_init().
void geoip_reset_entry_stats (time_t now)
 Reset counters for entry stats.
char * geoip_format_entry_stats (time_t now)
 Return a newly allocated string containing the entry statistics until now, or NULL if we're not collecting entry stats.
void geoip_bridge_stats_init (time_t now)
 Initialize bridge stats.
char * geoip_format_bridge_stats (time_t now)
 Return a newly allocated string holding our bridge usage stats by country in a format suitable for inclusion in an extrainfo document.
time_t geoip_bridge_stats_write (time_t now)
 Write bridge statistics to $DATADIR/stats/bridge-stats and return when we should next try to write statistics.
void geoip_bridge_stats_term (void)
 Stop collecting bridge stats in a way that we can re-start doing so in geoip_bridge_stats_init().
const char * geoip_get_bridge_stats_extrainfo (time_t)
 Return most recent bridge statistics for inclusion in extra-info descriptors, or NULL if we don't have recent bridge statistics.
char * geoip_get_bridge_stats_controller (time_t)
 Return a new string containing the recent bridge statistics to be returned to controller clients, or NULL if we don't have any bridge statistics.

Detailed Description

Header file for geoip.c.

Definition in file geoip.h.


Function Documentation

void geoip_bridge_stats_init ( time_t  now)

Initialize bridge stats.

Definition at line 1146 of file geoip.c.

Here is the caller graph for this function:

void geoip_bridge_stats_term ( void  )

Stop collecting bridge stats in a way that we can re-start doing so in geoip_bridge_stats_init().

Definition at line 1154 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t geoip_bridge_stats_write ( time_t  now)

Write bridge statistics to $DATADIR/stats/bridge-stats and return when we should next try to write statistics.

Definition at line 1264 of file geoip.c.

{
  char *filename = NULL, *val = NULL, *statsdir = NULL;

  /* Check if 24 hours have passed since starting measurements. */
  if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL)
    return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL;

  /* Discard all items in the client history that are too old. */
  geoip_remove_old_clients(start_of_bridge_stats_interval);

  /* Generate formatted string */
  val = geoip_format_bridge_stats(now);
  if (val == NULL)
    goto done;

  /* Update the stored value. */
  tor_free(bridge_stats_extrainfo);
  bridge_stats_extrainfo = val;
  start_of_bridge_stats_interval = now;

  /* Write it to disk. */
  statsdir = get_datadir_fname("stats");
  if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
    goto done;
  filename = get_datadir_fname2("stats", "bridge-stats");

  write_str_to_file(filename, bridge_stats_extrainfo, 0);

  /* Tell the controller, "hey, there are clients!" */
  {
    char *controller_str = format_bridge_stats_controller(now);
    if (controller_str)
      control_event_clients_seen(controller_str);
    tor_free(controller_str);
  }
 done:
  tor_free(filename);
  tor_free(statsdir);

  return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_change_dirreq_state ( uint64_t  dirreq_id,
dirreq_type_t  type,
dirreq_state_t  new_state 
)

Change the state of the either direct or tunneled (see type) directory request with dirreq_id to new_state and possibly mark it as completed.

If no entry can be found for the given key parts (e.g., if this is a directory request that we are not measuring, or one that was started in the previous measurement period), or if the state cannot be advanced to new_state, do nothing.

Definition at line 691 of file geoip.c.

{
  dirreq_map_entry_t *ent;
  if (!get_options()->DirReqStatistics)
    return;
  ent = _dirreq_map_get(type, dirreq_id);
  if (!ent)
    return;
  if (new_state == DIRREQ_IS_FOR_NETWORK_STATUS)
    return;
  if (new_state - 1 != ent->state)
    return;
  ent->state = new_state;
  if ((type == DIRREQ_DIRECT &&
         new_state == DIRREQ_FLUSHING_DIR_CONN_FINISHED) ||
      (type == DIRREQ_TUNNELED &&
         new_state == DIRREQ_OR_CONN_BUFFER_FLUSHED)) {
    tor_gettimeofday(&ent->completion_time);
    ent->completed = 1;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* geoip_db_digest ( void  )

Return the hex-encoded SHA1 digest of the loaded GeoIP file.

The result does not need to be deallocated, but will be overwritten by the next call of hex_str().

Definition at line 311 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_dirreq_stats_init ( time_t  now)

Initialize directory request stats.

Definition at line 941 of file geoip.c.

Here is the caller graph for this function:

void geoip_dirreq_stats_term ( void  )

Stop collecting directory request stats in a way that we can re-start doing so in geoip_dirreq_stats_init().

Definition at line 986 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t geoip_dirreq_stats_write ( time_t  now)

If 24 hours have passed since the beginning of the current dirreq stats period, write dirreq stats to $DATADIR/stats/dirreq-stats (possibly overwriting an existing file) and reset counters.

Return when we would next want to write dirreq stats or 0 if we never want to write.

Definition at line 1105 of file geoip.c.

{
  char *statsdir = NULL, *filename = NULL, *str = NULL;

  if (!start_of_dirreq_stats_interval)
    return 0; /* Not initialized. */
  if (start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL > now)
    goto done; /* Not ready to write. */

  /* Discard all items in the client history that are too old. */
  geoip_remove_old_clients(start_of_dirreq_stats_interval);

  /* Generate history string .*/
  str = geoip_format_dirreq_stats(now);

  /* Write dirreq-stats string to disk. */
  statsdir = get_datadir_fname("stats");
  if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
    log_warn(LD_HIST, "Unable to create stats/ directory!");
    goto done;
  }
  filename = get_datadir_fname2("stats", "dirreq-stats");
  if (write_str_to_file(filename, str, 0) < 0)
    log_warn(LD_HIST, "Unable to write dirreq statistics to disk!");

  /* Reset measurement interval start. */
  geoip_reset_dirreq_stats(now);

 done:
  tor_free(statsdir);
  tor_free(filename);
  tor_free(str);
  return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_entry_stats_init ( time_t  now)

Initialize entry stats.

Definition at line 1348 of file geoip.c.

Here is the caller graph for this function:

void geoip_entry_stats_term ( void  )

Stop collecting entry stats in a way that we can re-start doing so in geoip_entry_stats_init().

Definition at line 1364 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

time_t geoip_entry_stats_write ( time_t  now)

If 24 hours have passed since the beginning of the current entry stats period, write entry stats to $DATADIR/stats/entry-stats (possibly overwriting an existing file) and reset counters.

Return when we would next want to write entry stats or 0 if we never want to write.

Definition at line 1398 of file geoip.c.

{
  char *statsdir = NULL, *filename = NULL, *str = NULL;

  if (!start_of_entry_stats_interval)
    return 0; /* Not initialized. */
  if (start_of_entry_stats_interval + WRITE_STATS_INTERVAL > now)
    goto done; /* Not ready to write. */

  /* Discard all items in the client history that are too old. */
  geoip_remove_old_clients(start_of_entry_stats_interval);

  /* Generate history string .*/
  str = geoip_format_entry_stats(now);

  /* Write entry-stats string to disk. */
  statsdir = get_datadir_fname("stats");
  if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
    log_warn(LD_HIST, "Unable to create stats/ directory!");
    goto done;
  }
  filename = get_datadir_fname2("stats", "entry-stats");
  if (write_str_to_file(filename, str, 0) < 0)
    log_warn(LD_HIST, "Unable to write entry statistics to disk!");

  /* Reset measurement interval start. */
  geoip_reset_entry_stats(now);

 done:
  tor_free(statsdir);
  tor_free(filename);
  tor_free(str);
  return start_of_entry_stats_interval + WRITE_STATS_INTERVAL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* geoip_format_bridge_stats ( time_t  now)

Return a newly allocated string holding our bridge usage stats by country in a format suitable for inclusion in an extrainfo document.

Return NULL on failure.

Definition at line 1217 of file geoip.c.

{
  char *out = NULL, *data = NULL;
  long duration = now - start_of_bridge_stats_interval;
  char written[ISO_TIME_LEN+1];

  if (duration < 0)
    return NULL;
  if (!start_of_bridge_stats_interval)
    return NULL; /* Not initialized. */

  format_iso_time(written, now);
  data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);

  tor_asprintf(&out,
               "bridge-stats-end %s (%ld s)\n"
               "bridge-ips %s\n",
               written, duration,
               data ? data : "");
  tor_free(data);

  return out;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* geoip_format_dirreq_stats ( time_t  now)

Return a newly allocated string containing the dirreq statistics until now, or NULL if we're not collecting dirreq stats.

Caller must ensure start_of_dirreq_stats_interval is in the past.

Definition at line 995 of file geoip.c.

{
  char t[ISO_TIME_LEN+1];
  double v2_share = 0.0, v3_share = 0.0;
  int i;
  char *v3_ips_string, *v2_ips_string, *v3_reqs_string, *v2_reqs_string,
       *v2_share_string = NULL, *v3_share_string = NULL,
       *v3_direct_dl_string, *v2_direct_dl_string,
       *v3_tunneled_dl_string, *v2_tunneled_dl_string;
  char *result;

  if (!start_of_dirreq_stats_interval)
    return NULL; /* Not initialized. */

  tor_assert(now >= start_of_dirreq_stats_interval);

  format_iso_time(t, now);
  v2_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
  v3_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
  v2_reqs_string = geoip_get_request_history(
                   GEOIP_CLIENT_NETWORKSTATUS_V2);
  v3_reqs_string = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);

#define RESPONSE_GRANULARITY 8
  for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
    ns_v2_responses[i] = round_uint32_to_next_multiple_of(
                               ns_v2_responses[i], RESPONSE_GRANULARITY);
    ns_v3_responses[i] = round_uint32_to_next_multiple_of(
                               ns_v3_responses[i], RESPONSE_GRANULARITY);
  }
#undef RESPONSE_GRANULARITY

  if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
    tor_asprintf(&v2_share_string, "dirreq-v2-share %0.2f%%\n",
                 v2_share*100);
    tor_asprintf(&v3_share_string, "dirreq-v3-share %0.2f%%\n",
                 v3_share*100);
  }

  v2_direct_dl_string = geoip_get_dirreq_history(
                        GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_DIRECT);
  v3_direct_dl_string = geoip_get_dirreq_history(
                        GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_DIRECT);

  v2_tunneled_dl_string = geoip_get_dirreq_history(
                          GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_TUNNELED);
  v3_tunneled_dl_string = geoip_get_dirreq_history(
                          GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_TUNNELED);

  /* Put everything together into a single string. */
  tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n"
              "dirreq-v3-ips %s\n"
              "dirreq-v2-ips %s\n"
              "dirreq-v3-reqs %s\n"
              "dirreq-v2-reqs %s\n"
              "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
                   "not-found=%u,not-modified=%u,busy=%u\n"
              "dirreq-v2-resp ok=%u,unavailable=%u,"
                   "not-found=%u,not-modified=%u,busy=%u\n"
              "%s"
              "%s"
              "dirreq-v3-direct-dl %s\n"
              "dirreq-v2-direct-dl %s\n"
              "dirreq-v3-tunneled-dl %s\n"
              "dirreq-v2-tunneled-dl %s\n",
              t,
              (unsigned) (now - start_of_dirreq_stats_interval),
              v3_ips_string ? v3_ips_string : "",
              v2_ips_string ? v2_ips_string : "",
              v3_reqs_string ? v3_reqs_string : "",
              v2_reqs_string ? v2_reqs_string : "",
              ns_v3_responses[GEOIP_SUCCESS],
              ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
              ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
              ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
              ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
              ns_v3_responses[GEOIP_REJECT_BUSY],
              ns_v2_responses[GEOIP_SUCCESS],
              ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
              ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
              ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
              ns_v2_responses[GEOIP_REJECT_BUSY],
              v2_share_string ? v2_share_string : "",
              v3_share_string ? v3_share_string : "",
              v3_direct_dl_string ? v3_direct_dl_string : "",
              v2_direct_dl_string ? v2_direct_dl_string : "",
              v3_tunneled_dl_string ? v3_tunneled_dl_string : "",
              v2_tunneled_dl_string ? v2_tunneled_dl_string : "");

  /* Free partial strings. */
  tor_free(v3_ips_string);
  tor_free(v2_ips_string);
  tor_free(v3_reqs_string);
  tor_free(v2_reqs_string);
  tor_free(v2_share_string);
  tor_free(v3_share_string);
  tor_free(v3_direct_dl_string);
  tor_free(v2_direct_dl_string);
  tor_free(v3_tunneled_dl_string);
  tor_free(v2_tunneled_dl_string);

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* geoip_format_entry_stats ( time_t  now)

Return a newly allocated string containing the entry statistics until now, or NULL if we're not collecting entry stats.

Caller must ensure start_of_entry_stats_interval lies in the past.

Definition at line 1373 of file geoip.c.

{
  char t[ISO_TIME_LEN+1];
  char *data = NULL;
  char *result;

  if (!start_of_entry_stats_interval)
    return NULL; /* Not initialized. */

  tor_assert(now >= start_of_entry_stats_interval);

  data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
  format_iso_time(t, now);
  tor_asprintf(&result, "entry-stats-end %s (%u s)\nentry-ips %s\n",
              t, (unsigned) (now - start_of_entry_stats_interval),
              data ? data : "");
  tor_free(data);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_free_all ( void  )

Release all storage held in this file.

Definition at line 1479 of file geoip.c.

{
  {
    clientmap_entry_t **ent, **next, *this;
    for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) {
      this = *ent;
      next = HT_NEXT_RMV(clientmap, &client_history, ent);
      tor_free(this);
    }
    HT_CLEAR(clientmap, &client_history);
  }
  {
    dirreq_map_entry_t **ent, **next, *this;
    for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) {
      this = *ent;
      next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent);
      tor_free(this);
    }
    HT_CLEAR(dirreqmap, &dirreq_map);
  }

  clear_geoip_db();
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* geoip_get_bridge_stats_controller ( time_t  now)

Return a new string containing the recent bridge statistics to be returned to controller clients, or NULL if we don't have any bridge statistics.

Definition at line 1337 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

const char* geoip_get_bridge_stats_extrainfo ( time_t  now)

Return most recent bridge statistics for inclusion in extra-info descriptors, or NULL if we don't have recent bridge statistics.

Definition at line 1328 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Return a newly allocated comma-separated string containing entries for all the countries from which we've seen enough clients connect as a bridge, directory server, or entry guard.

The entry format is cc=num where num is the number of IPs we've seen connecting from that country, and cc is a lowercased country code. Returns NULL if we don't want to export geoip data yet.

unresolved requests are stored at index 0.

Definition at line 823 of file geoip.c.

{
  char *result = NULL;
  unsigned granularity = IP_GRANULARITY;
  smartlist_t *chunks = NULL;
  smartlist_t *entries = NULL;
  int n_countries = geoip_get_n_countries();
  int i;
  clientmap_entry_t **ent;
  unsigned *counts = NULL;
  unsigned total = 0;

  if (!geoip_is_loaded())
    return NULL;

  counts = tor_malloc_zero(sizeof(unsigned)*n_countries);
  HT_FOREACH(ent, clientmap, &client_history) {
    int country;
    if ((*ent)->action != (int)action)
      continue;
    country = geoip_get_country_by_addr(&(*ent)->addr);
    if (country < 0)
      country = 0; 
    tor_assert(0 <= country && country < n_countries);
    ++counts[country];
    ++total;
  }
  /* Don't record anything if we haven't seen enough IPs. */
  if (total < MIN_IPS_TO_NOTE_ANYTHING)
    goto done;
  /* Make a list of c_hist_t */
  entries = smartlist_new();
  for (i = 0; i < n_countries; ++i) {
    unsigned c = counts[i];
    const char *countrycode;
    c_hist_t *ent;
    /* Only report a country if it has a minimum number of IPs. */
    if (c >= MIN_IPS_TO_NOTE_COUNTRY) {
      c = round_to_next_multiple_of(c, granularity);
      countrycode = geoip_get_country_name(i);
      ent = tor_malloc(sizeof(c_hist_t));
      strlcpy(ent->country, countrycode, sizeof(ent->country));
      ent->total = c;
      smartlist_add(entries, ent);
    }
  }
  /* Sort entries. Note that we must do this _AFTER_ rounding, or else
   * the sort order could leak info. */
  smartlist_sort(entries, _c_hist_compare);

  /* Build the result. */
  chunks = smartlist_new();
  SMARTLIST_FOREACH(entries, c_hist_t *, ch, {
      smartlist_add_asprintf(chunks, "%s=%u", ch->country, ch->total);
  });
  result = smartlist_join_strings(chunks, ",", 0, NULL);
 done:
  tor_free(counts);
  if (chunks) {
    SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
    smartlist_free(chunks);
  }
  if (entries) {
    SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c));
    smartlist_free(entries);
  }
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

country_t geoip_get_country ( const char *  countrycode)

Return the index of the country's entry in the GeoIP DB if it is a valid 2-letter country code, otherwise return -1.

Definition at line 54 of file geoip.c.

{
  void *_idxplus1;
  intptr_t idx;

  _idxplus1 = strmap_get_lc(country_idxplus1_by_lc_code, country);
  if (!_idxplus1)
    return -1;

  idx = ((uintptr_t)_idxplus1)-1;
  return (country_t)idx;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int geoip_get_country_by_addr ( const tor_addr_t addr)

Given an IP address, return a number representing the country to which that address belongs, -1 for "No geoip information available", or 0 for the 'unknown country'.

The return value will always be less than geoip_get_n_countries(). To decode it, call geoip_get_country_name().

Definition at line 270 of file geoip.c.

{
  if (tor_addr_family(addr) != AF_INET) {
    /*XXXX IP6 support ipv6 geoip.*/
    return -1;
  }
  return geoip_get_country_by_ip(tor_addr_to_ipv4h(addr));
}

Here is the call graph for this function:

Here is the caller graph for this function:

int geoip_get_country_by_ip ( uint32_t  ipaddr)

Given an IP address in host order, return a number representing the country to which that address belongs, -1 for "No geoip information available", or 0 for the 'unknown country'.

The return value will always be less than geoip_get_n_countries(). To decode it, call geoip_get_country_name().

Definition at line 255 of file geoip.c.

{
  geoip_entry_t *ent;
  if (!geoip_entries)
    return -1;
  ent = smartlist_bsearch(geoip_entries, &ipaddr, _geoip_compare_key_to_entry);
  return ent ? (int)ent->country : 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* geoip_get_country_name ( country_t  num)

Return the two-letter country code associated with the number num, or "??" for an unknown value.

Definition at line 291 of file geoip.c.

{
  if (geoip_countries && num >= 0 && num < smartlist_len(geoip_countries)) {
    geoip_country_t *c = smartlist_get(geoip_countries, num);
    return c->countrycode;
  } else
    return "??";
}

Here is the caller graph for this function:

int geoip_get_n_countries ( void  )

Return the number of countries recognized by the GeoIP database.

Definition at line 281 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Return a newly allocated string holding the per-country request history for action in a format suitable for an extra-info document, or NULL on failure.

Definition at line 896 of file geoip.c.

{
  smartlist_t *entries, *strings;
  char *result;
  unsigned granularity = IP_GRANULARITY;

  if (action != GEOIP_CLIENT_NETWORKSTATUS &&
      action != GEOIP_CLIENT_NETWORKSTATUS_V2)
    return NULL;
  if (!geoip_countries)
    return NULL;

  entries = smartlist_new();
  SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
      uint32_t tot = 0;
      c_hist_t *ent;
      tot = (action == GEOIP_CLIENT_NETWORKSTATUS) ?
            c->n_v3_ns_requests : c->n_v2_ns_requests;
      if (!tot)
        continue;
      ent = tor_malloc_zero(sizeof(c_hist_t));
      strlcpy(ent->country, c->countrycode, sizeof(ent->country));
      ent->total = round_to_next_multiple_of(tot, granularity);
      smartlist_add(entries, ent);
  });
  smartlist_sort(entries, _c_hist_compare);

  strings = smartlist_new();
  SMARTLIST_FOREACH(entries, c_hist_t *, ent, {
      smartlist_add_asprintf(strings, "%s=%u", ent->country, ent->total);
  });
  result = smartlist_join_strings(strings, ",", 0, NULL);
  SMARTLIST_FOREACH(strings, char *, cp, tor_free(cp));
  SMARTLIST_FOREACH(entries, c_hist_t *, ent, tor_free(ent));
  smartlist_free(strings);
  smartlist_free(entries);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int geoip_is_loaded ( void  )

Return true iff we have loaded a GeoIP database.

Definition at line 302 of file geoip.c.

{
  return geoip_countries != NULL && geoip_entries != NULL;
}

Here is the caller graph for this function:

int geoip_load_file ( const char *  filename,
const or_options_t options 
)

Clear the GeoIP database and reload it from the file filename.

Return 0 on success, -1 on failure.

Recognized line formats are: INTIPLOW,INTIPHIGH,CC and "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME" where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned integers, and CC is a country code.

It also recognizes, and skips over, blank lines and lines that start with '#' (comments).

Definition at line 202 of file geoip.c.

{
  FILE *f;
  const char *msg = "";
  int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO;
  crypto_digest_t *geoip_digest_env = NULL;
  clear_geoip_db();
  if (!(f = tor_fopen_cloexec(filename, "r"))) {
    log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s.  %s",
           filename, msg);
    return -1;
  }
  if (!geoip_countries)
    init_geoip_countries();
  if (geoip_entries) {
    SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, e, tor_free(e));
    smartlist_free(geoip_entries);
  }
  geoip_entries = smartlist_new();
  geoip_digest_env = crypto_digest_new();
  log_notice(LD_GENERAL, "Parsing GEOIP file %s.", filename);
  while (!feof(f)) {
    char buf[512];
    if (fgets(buf, (int)sizeof(buf), f) == NULL)
      break;
    crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf));
    /* FFFF track full country name. */
    geoip_parse_entry(buf);
  }
  /*XXXX abort and return -1 if no entries/illformed?*/
  fclose(f);

  smartlist_sort(geoip_entries, _geoip_compare_entries);

  /* Okay, now we need to maybe change our mind about what is in which
   * country. */
  refresh_all_country_info();

  /* Remember file digest so that we can include it in our extra-info
   * descriptors. */
  crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN);
  crypto_digest_free(geoip_digest_env);

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_note_client_seen ( geoip_client_action_t  action,
const tor_addr_t addr,
time_t  now 
)

Note that we've seen a client connect from the IP addr at time now.

Ignored by all but bridges and directories if configured accordingly.

unresolved requests are stored at index 0.

Definition at line 440 of file geoip.c.

{
  const or_options_t *options = get_options();
  clientmap_entry_t lookup, *ent;
  if (action == GEOIP_CLIENT_CONNECT) {
    /* Only remember statistics as entry guard or as bridge. */
    if (!options->EntryStatistics &&
        (!(options->BridgeRelay && options->BridgeRecordUsageByCountry)))
      return;
  } else {
    if (options->BridgeRelay || options->BridgeAuthoritativeDir ||
        !options->DirReqStatistics)
      return;
  }

  tor_addr_copy(&lookup.addr, addr);
  lookup.action = (int)action;
  ent = HT_FIND(clientmap, &client_history, &lookup);
  if (! ent) {
    ent = tor_malloc_zero(sizeof(clientmap_entry_t));
    tor_addr_copy(&ent->addr, addr);
    ent->action = (int)action;
    HT_INSERT(clientmap, &client_history, ent);
  }
  if (now / 60 <= (int)MAX_LAST_SEEN_IN_MINUTES && now >= 0)
    ent->last_seen_in_minutes = (unsigned)(now/60);
  else
    ent->last_seen_in_minutes = 0;

  if (action == GEOIP_CLIENT_NETWORKSTATUS ||
      action == GEOIP_CLIENT_NETWORKSTATUS_V2) {
    int country_idx = geoip_get_country_by_addr(addr);
    if (country_idx < 0)
      country_idx = 0; 
    if (country_idx >= 0 && country_idx < smartlist_len(geoip_countries)) {
      geoip_country_t *country = smartlist_get(geoip_countries, country_idx);
      if (action == GEOIP_CLIENT_NETWORKSTATUS)
        ++country->n_v3_ns_requests;
      else
        ++country->n_v2_ns_requests;
    }

    /* Periodically determine share of requests that we should see */
    if (last_time_determined_shares + REQUEST_SHARE_INTERVAL < now)
      geoip_determine_shares(now);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Note that we've rejected a client's request for a v2 or v3 network status, encoded in action for reason reason at time now.

Definition at line 524 of file geoip.c.

{
  static int arrays_initialized = 0;
  if (!get_options()->DirReqStatistics)
    return;
  if (!arrays_initialized) {
    memset(ns_v2_responses, 0, sizeof(ns_v2_responses));
    memset(ns_v3_responses, 0, sizeof(ns_v3_responses));
    arrays_initialized = 1;
  }
  tor_assert(action == GEOIP_CLIENT_NETWORKSTATUS ||
             action == GEOIP_CLIENT_NETWORKSTATUS_V2);
  tor_assert(response < GEOIP_NS_RESPONSE_NUM);
  if (action == GEOIP_CLIENT_NETWORKSTATUS)
    ns_v3_responses[response]++;
  else
    ns_v2_responses[response]++;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_remove_old_clients ( time_t  cutoff)

Forget about all clients that haven't connected since cutoff.

Definition at line 505 of file geoip.c.

{
  clientmap_HT_FOREACH_FN(&client_history,
                          _remove_old_client_helper,
                          &cutoff);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_reset_dirreq_stats ( time_t  now)

Reset counters for dirreq stats.

Definition at line 948 of file geoip.c.

{
  SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
      c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
  });
  {
    clientmap_entry_t **ent, **next, *this;
    for (ent = HT_START(clientmap, &client_history); ent != NULL;
         ent = next) {
      if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS ||
          (*ent)->action == GEOIP_CLIENT_NETWORKSTATUS_V2) {
        this = *ent;
        next = HT_NEXT_RMV(clientmap, &client_history, ent);
        tor_free(this);
      } else {
        next = HT_NEXT(clientmap, &client_history, ent);
      }
    }
  }
  v2_share_times_seconds = v3_share_times_seconds = 0.0;
  last_time_determined_shares = 0;
  share_seconds = 0;
  memset(ns_v2_responses, 0, sizeof(ns_v2_responses));
  memset(ns_v3_responses, 0, sizeof(ns_v3_responses));
  {
    dirreq_map_entry_t **ent, **next, *this;
    for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) {
      this = *ent;
      next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent);
      tor_free(this);
    }
  }
  start_of_dirreq_stats_interval = now;
}

Here is the caller graph for this function:

void geoip_reset_entry_stats ( time_t  now)

Reset counters for entry stats.

Definition at line 1355 of file geoip.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void geoip_start_dirreq ( uint64_t  dirreq_id,
size_t  response_size,
geoip_client_action_t  action,
dirreq_type_t  type 
)

Note that an either direct or tunneled (see type) directory request for a network status with unique ID dirreq_id of size response_size and action action (either v2 or v3) has started.

Definition at line 669 of file geoip.c.

{
  dirreq_map_entry_t *ent;
  if (!get_options()->DirReqStatistics)
    return;
  ent = tor_malloc_zero(sizeof(dirreq_map_entry_t));
  ent->dirreq_id = dirreq_id;
  tor_gettimeofday(&ent->request_time);
  ent->response_size = response_size;
  ent->action = action;
  ent->type = type;
  _dirreq_map_put(ent, type, dirreq_id);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int getinfo_helper_geoip ( control_connection_t control_conn,
const char *  question,
char **  answer,
const char **  errmsg 
)

Helper used to implement GETINFO ip-to-country/...

controller command.

Definition at line 1435 of file geoip.c.

{
  (void)control_conn;
  if (!geoip_is_loaded()) {
    *errmsg = "GeoIP data not loaded";
    return -1;
  }
  if (!strcmpstart(question, "ip-to-country/")) {
    int c;
    uint32_t ip;
    struct in_addr in;
    question += strlen("ip-to-country/");
    if (tor_inet_aton(question, &in) != 0) {
      ip = ntohl(in.s_addr);
      c = geoip_get_country_by_ip(ip);
      *answer = tor_strdup(geoip_get_country_name(c));
    }
  }
  return 0;
}

Here is the call graph for this function:

int should_record_bridge_info ( const or_options_t options)

Return 1 if we should collect geoip stats on bridge users, and include them in our extrainfo descriptor.

Else return 0.

Definition at line 165 of file geoip.c.

{
  return options->BridgeRelay && options->BridgeRecordUsageByCountry;
}

Here is the caller graph for this function: