geoip.c
上传用户:awang829
上传日期:2019-07-14
资源大小:2356k
文件大小:22k
源码类别:

网络

开发平台:

Unix_Linux

  1. /* Copyright (c) 2007-2009, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4.  * file geoip.c
  5.  * brief Functions related to maintaining an IP-to-country database and to
  6.  *    summarizing client connections by country.
  7.  */
  8. #define GEOIP_PRIVATE
  9. #include "or.h"
  10. #include "ht.h"
  11. static void clear_geoip_db(void);
  12. /** An entry from the GeoIP file: maps an IP range to a country. */
  13. typedef struct geoip_entry_t {
  14.   uint32_t ip_low; /**< The lowest IP in the range, in host order */
  15.   uint32_t ip_high; /**< The highest IP in the range, in host order */
  16.   intptr_t country; /**< An index into geoip_countries */
  17. } geoip_entry_t;
  18. /** For how many periods should we remember per-country request history? */
  19. #define REQUEST_HIST_LEN 3
  20. /** How long are the periods for which we should remember request history? */
  21. #define REQUEST_HIST_PERIOD (8*60*60)
  22. /** A per-country record for GeoIP request history. */
  23. typedef struct geoip_country_t {
  24.   char countrycode[3];
  25.   uint32_t n_v2_ns_requests[REQUEST_HIST_LEN];
  26.   uint32_t n_v3_ns_requests[REQUEST_HIST_LEN];
  27. } geoip_country_t;
  28. /** A list of geoip_country_t */
  29. static smartlist_t *geoip_countries = NULL;
  30. /** A map from lowercased country codes to their position in geoip_countries.
  31.  * The index is encoded in the pointer, and 1 is added so that NULL can mean
  32.  * not found. */
  33. static strmap_t *country_idxplus1_by_lc_code = NULL;
  34. /** A list of all known geoip_entry_t, sorted by ip_low. */
  35. static smartlist_t *geoip_entries = NULL;
  36. /** Return the index of the <b>country</b>'s entry in the GeoIP DB
  37.  * if it is a valid 2-letter country code, otherwise return zero.
  38.  */
  39. country_t
  40. geoip_get_country(const char *country)
  41. {
  42.   void *_idxplus1;
  43.   intptr_t idx;
  44.   _idxplus1 = strmap_get_lc(country_idxplus1_by_lc_code, country);
  45.   if (!_idxplus1)
  46.     return -1;
  47.   idx = ((uintptr_t)_idxplus1)-1;
  48.   return (country_t)idx;
  49. }
  50. /** Add an entry to the GeoIP table, mapping all IPs between <b>low</b> and
  51.  * <b>high</b>, inclusive, to the 2-letter country code <b>country</b>.
  52.  */
  53. static void
  54. geoip_add_entry(uint32_t low, uint32_t high, const char *country)
  55. {
  56.   intptr_t idx;
  57.   geoip_entry_t *ent;
  58.   void *_idxplus1;
  59.   if (high < low)
  60.     return;
  61.   _idxplus1 = strmap_get_lc(country_idxplus1_by_lc_code, country);
  62.   if (!_idxplus1) {
  63.     geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t));
  64.     strlcpy(c->countrycode, country, sizeof(c->countrycode));
  65.     tor_strlower(c->countrycode);
  66.     smartlist_add(geoip_countries, c);
  67.     idx = smartlist_len(geoip_countries) - 1;
  68.     strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1));
  69.   } else {
  70.     idx = ((uintptr_t)_idxplus1)-1;
  71.   }
  72.   {
  73.     geoip_country_t *c = smartlist_get(geoip_countries, idx);
  74.     tor_assert(!strcasecmp(c->countrycode, country));
  75.   }
  76.   ent = tor_malloc_zero(sizeof(geoip_entry_t));
  77.   ent->ip_low = low;
  78.   ent->ip_high = high;
  79.   ent->country = idx;
  80.   smartlist_add(geoip_entries, ent);
  81. }
  82. /** Add an entry to the GeoIP table, parsing it from <b>line</b>.  The
  83.  * format is as for geoip_load_file(). */
  84. /*private*/ int
  85. geoip_parse_entry(const char *line)
  86. {
  87.   unsigned int low, high;
  88.   char b[3];
  89.   if (!geoip_countries) {
  90.     geoip_countries = smartlist_create();
  91.     geoip_entries = smartlist_create();
  92.     country_idxplus1_by_lc_code = strmap_new();
  93.   }
  94.   while (TOR_ISSPACE(*line))
  95.     ++line;
  96.   if (*line == '#')
  97.     return 0;
  98.   if (sscanf(line,"%u,%u,%2s", &low, &high, b) == 3) {
  99.     geoip_add_entry(low, high, b);
  100.     return 0;
  101.   } else if (sscanf(line,""%u","%u","%2s",", &low, &high, b) == 3) {
  102.     geoip_add_entry(low, high, b);
  103.     return 0;
  104.   } else {
  105.     log_warn(LD_GENERAL, "Unable to parse line from GEOIP file: %s",
  106.              escaped(line));
  107.     return -1;
  108.   }
  109. }
  110. /** Sorting helper: return -1, 1, or 0 based on comparison of two
  111.  * geoip_entry_t */
  112. static int
  113. _geoip_compare_entries(const void **_a, const void **_b)
  114. {
  115.   const geoip_entry_t *a = *_a, *b = *_b;
  116.   if (a->ip_low < b->ip_low)
  117.     return -1;
  118.   else if (a->ip_low > b->ip_low)
  119.     return 1;
  120.   else
  121.     return 0;
  122. }
  123. /** bsearch helper: return -1, 1, or 0 based on comparison of an IP (a pointer
  124.  * to a uint32_t in host order) to a geoip_entry_t */
  125. static int
  126. _geoip_compare_key_to_entry(const void *_key, const void **_member)
  127. {
  128.   const uint32_t addr = *(uint32_t *)_key;
  129.   const geoip_entry_t *entry = *_member;
  130.   if (addr < entry->ip_low)
  131.     return -1;
  132.   else if (addr > entry->ip_high)
  133.     return 1;
  134.   else
  135.     return 0;
  136. }
  137. /** Return 1 if we should collect geoip stats on bridge users, and
  138.  * include them in our extrainfo descriptor. Else return 0. */
  139. int
  140. should_record_bridge_info(or_options_t *options)
  141. {
  142.   return options->BridgeRelay && options->BridgeRecordUsageByCountry;
  143. }
  144. /** Clear the GeoIP database and reload it from the file
  145.  * <b>filename</b>. Return 0 on success, -1 on failure.
  146.  *
  147.  * Recognized line formats are:
  148.  *   INTIPLOW,INTIPHIGH,CC
  149.  * and
  150.  *   "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME"
  151.  * where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned
  152.  * integers, and CC is a country code.
  153.  *
  154.  * It also recognizes, and skips over, blank lines and lines that start
  155.  * with '#' (comments).
  156.  */
  157. int
  158. geoip_load_file(const char *filename, or_options_t *options)
  159. {
  160.   FILE *f;
  161.   const char *msg = "";
  162.   int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO;
  163.   clear_geoip_db();
  164.   if (!(f = fopen(filename, "r"))) {
  165.     log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s.  %s",
  166.            filename, msg);
  167.     return -1;
  168.   }
  169.   if (!geoip_countries) {
  170.     geoip_countries = smartlist_create();
  171.     country_idxplus1_by_lc_code = strmap_new();
  172.   }
  173.   if (geoip_entries) {
  174.     SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, e, tor_free(e));
  175.     smartlist_free(geoip_entries);
  176.   }
  177.   geoip_entries = smartlist_create();
  178.   log_notice(LD_GENERAL, "Parsing GEOIP file.");
  179.   while (!feof(f)) {
  180.     char buf[512];
  181.     if (fgets(buf, (int)sizeof(buf), f) == NULL)
  182.       break;
  183.     /* FFFF track full country name. */
  184.     geoip_parse_entry(buf);
  185.   }
  186.   /*XXXX abort and return -1 if no entries/illformed?*/
  187.   fclose(f);
  188.   smartlist_sort(geoip_entries, _geoip_compare_entries);
  189.   /* Okay, now we need to maybe change our mind about what is in which
  190.    * country. */
  191.   refresh_all_country_info();
  192.   return 0;
  193. }
  194. /** Given an IP address in host order, return a number representing the
  195.  * country to which that address belongs, or -1 for unknown.  The return value
  196.  * will always be less than geoip_get_n_countries().  To decode it,
  197.  * call geoip_get_country_name().
  198.  */
  199. int
  200. geoip_get_country_by_ip(uint32_t ipaddr)
  201. {
  202.   geoip_entry_t *ent;
  203.   if (!geoip_entries)
  204.     return -1;
  205.   ent = smartlist_bsearch(geoip_entries, &ipaddr, _geoip_compare_key_to_entry);
  206.   return ent ? (int)ent->country : -1;
  207. }
  208. /** Return the number of countries recognized by the GeoIP database. */
  209. int
  210. geoip_get_n_countries(void)
  211. {
  212.   return (int) smartlist_len(geoip_countries);
  213. }
  214. /** Return the two-letter country code associated with the number <b>num</b>,
  215.  * or "??" for an unknown value. */
  216. const char *
  217. geoip_get_country_name(country_t num)
  218. {
  219.   if (geoip_countries && num >= 0 && num < smartlist_len(geoip_countries)) {
  220.     geoip_country_t *c = smartlist_get(geoip_countries, num);
  221.     return c->countrycode;
  222.   } else
  223.     return "??";
  224. }
  225. /** Return true iff we have loaded a GeoIP database.*/
  226. int
  227. geoip_is_loaded(void)
  228. {
  229.   return geoip_countries != NULL && geoip_entries != NULL;
  230. }
  231. /** Entry in a map from IP address to the last time we've seen an incoming
  232.  * connection from that IP address. Used by bridges only, to track which
  233.  * countries have them blocked. */
  234. typedef struct clientmap_entry_t {
  235.   HT_ENTRY(clientmap_entry_t) node;
  236.   uint32_t ipaddr;
  237.   time_t last_seen; /* The last 2 bits of this value hold the client
  238.                      * operation. */
  239. } clientmap_entry_t;
  240. #define ACTION_MASK 3
  241. /** Map from client IP address to last time seen. */
  242. static HT_HEAD(clientmap, clientmap_entry_t) client_history =
  243.      HT_INITIALIZER();
  244. /** Time at which we started tracking client IP history. */
  245. static time_t client_history_starts = 0;
  246. /** When did the current period of checking per-country request history
  247.  * start? */
  248. static time_t current_request_period_starts = 0;
  249. /** How many older request periods are we remembering? */
  250. static int n_old_request_periods = 0;
  251. /** Hashtable helper: compute a hash of a clientmap_entry_t. */
  252. static INLINE unsigned
  253. clientmap_entry_hash(const clientmap_entry_t *a)
  254. {
  255.   return ht_improve_hash((unsigned) a->ipaddr);
  256. }
  257. /** Hashtable helper: compare two clientmap_entry_t values for equality. */
  258. static INLINE int
  259. clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b)
  260. {
  261.   return a->ipaddr == b->ipaddr;
  262. }
  263. HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
  264.              clientmap_entries_eq);
  265. HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
  266.             clientmap_entries_eq, 0.6, malloc, realloc, free);
  267. /** Note that we've seen a client connect from the IP <b>addr</b> (host order)
  268.  * at time <b>now</b>. Ignored by all but bridges. */
  269. void
  270. geoip_note_client_seen(geoip_client_action_t action,
  271.                        uint32_t addr, time_t now)
  272. {
  273.   or_options_t *options = get_options();
  274.   clientmap_entry_t lookup, *ent;
  275.   if (action == GEOIP_CLIENT_CONNECT) {
  276.     if (!(options->BridgeRelay && options->BridgeRecordUsageByCountry))
  277.       return;
  278.     /* Did we recently switch from bridge to relay or back? */
  279.     if (client_history_starts > now)
  280.       return;
  281.   } else {
  282. #ifndef ENABLE_GEOIP_STATS
  283.     return;
  284. #else
  285.     if (options->BridgeRelay || options->BridgeAuthoritativeDir ||
  286.         !options->DirRecordUsageByCountry)
  287.       return;
  288. #endif
  289.   }
  290.   /* Rotate the current request period. */
  291.   while (current_request_period_starts + REQUEST_HIST_PERIOD < now) {
  292.     if (!geoip_countries)
  293.       geoip_countries = smartlist_create();
  294.     if (!current_request_period_starts) {
  295.       current_request_period_starts = now;
  296.       break;
  297.     }
  298.     SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
  299.         memmove(&c->n_v2_ns_requests[0], &c->n_v2_ns_requests[1],
  300.                 sizeof(uint32_t)*(REQUEST_HIST_LEN-1));
  301.         memmove(&c->n_v3_ns_requests[0], &c->n_v3_ns_requests[1],
  302.                 sizeof(uint32_t)*(REQUEST_HIST_LEN-1));
  303.         c->n_v2_ns_requests[REQUEST_HIST_LEN-1] = 0;
  304.         c->n_v3_ns_requests[REQUEST_HIST_LEN-1] = 0;
  305.       });
  306.     current_request_period_starts += REQUEST_HIST_PERIOD;
  307.     if (n_old_request_periods < REQUEST_HIST_LEN-1)
  308.       ++n_old_request_periods;
  309.    }
  310.   /* We use the low 3 bits of the time to encode the action. Since we're
  311.    * potentially remembering tons of clients, we don't want to make
  312.    * clientmap_entry_t larger than it has to be. */
  313.   now = (now & ~ACTION_MASK) | (((int)action) & ACTION_MASK);
  314.   lookup.ipaddr = addr;
  315.   ent = HT_FIND(clientmap, &client_history, &lookup);
  316.   if (ent) {
  317.     ent->last_seen = now;
  318.   } else {
  319.     ent = tor_malloc_zero(sizeof(clientmap_entry_t));
  320.     ent->ipaddr = addr;
  321.     ent->last_seen = now;
  322.     HT_INSERT(clientmap, &client_history, ent);
  323.   }
  324.   if (action == GEOIP_CLIENT_NETWORKSTATUS ||
  325.       action == GEOIP_CLIENT_NETWORKSTATUS_V2) {
  326.     int country_idx = geoip_get_country_by_ip(addr);
  327.     if (country_idx >= 0 && country_idx < smartlist_len(geoip_countries)) {
  328.       geoip_country_t *country = smartlist_get(geoip_countries, country_idx);
  329.       if (action == GEOIP_CLIENT_NETWORKSTATUS)
  330.         ++country->n_v3_ns_requests[REQUEST_HIST_LEN-1];
  331.       else
  332.         ++country->n_v2_ns_requests[REQUEST_HIST_LEN-1];
  333.     }
  334.   }
  335.   if (!client_history_starts) {
  336.     client_history_starts = now;
  337.     current_request_period_starts = now;
  338.   }
  339. }
  340. /** HT_FOREACH helper: remove a clientmap_entry_t from the hashtable if it's
  341.  * older than a certain time. */
  342. static int
  343. _remove_old_client_helper(struct clientmap_entry_t *ent, void *_cutoff)
  344. {
  345.   time_t cutoff = *(time_t*)_cutoff;
  346.   if (ent->last_seen < cutoff) {
  347.     tor_free(ent);
  348.     return 1;
  349.   } else {
  350.     return 0;
  351.   }
  352. }
  353. /** Forget about all clients that haven't connected since <b>cutoff</b>.
  354.  * If <b>cutoff</b> is in the future, clients won't be added to the history
  355.  * until this time is reached. This is useful to prevent relays that switch
  356.  * to bridges from reporting unbelievable numbers of clients. */
  357. void
  358. geoip_remove_old_clients(time_t cutoff)
  359. {
  360.   clientmap_HT_FOREACH_FN(&client_history,
  361.                           _remove_old_client_helper,
  362.                           &cutoff);
  363.   if (client_history_starts < cutoff)
  364.     client_history_starts = cutoff;
  365. }
  366. /** Do not mention any country from which fewer than this number of IPs have
  367.  * connected.  This conceivably avoids reporting information that could
  368.  * deanonymize users, though analysis is lacking. */
  369. #define MIN_IPS_TO_NOTE_COUNTRY 1
  370. /** Do not report any geoip data at all if we have fewer than this number of
  371.  * IPs to report about. */
  372. #define MIN_IPS_TO_NOTE_ANYTHING 1
  373. /** When reporting geoip data about countries, round up to the nearest
  374.  * multiple of this value. */
  375. #define IP_GRANULARITY 8
  376. /** Return the time at which we started recording geoip data. */
  377. time_t
  378. geoip_get_history_start(void)
  379. {
  380.   return client_history_starts;
  381. }
  382. /** Helper type: used to sort per-country totals by value. */
  383. typedef struct c_hist_t {
  384.   char country[3]; /**< Two-letter country code. */
  385.   unsigned total; /**< Total IP addresses seen in this country. */
  386. } c_hist_t;
  387. /** Sorting helper: return -1, 1, or 0 based on comparison of two
  388.  * geoip_entry_t.  Sort in descending order of total, and then by country
  389.  * code. */
  390. static int
  391. _c_hist_compare(const void **_a, const void **_b)
  392. {
  393.   const c_hist_t *a = *_a, *b = *_b;
  394.   if (a->total > b->total)
  395.     return -1;
  396.   else if (a->total < b->total)
  397.     return 1;
  398.   else
  399.     return strcmp(a->country, b->country);
  400. }
  401. /** How long do we have to have observed per-country request history before we
  402.  * are willing to talk about it? */
  403. #define GEOIP_MIN_OBSERVATION_TIME (12*60*60)
  404. /** Return the lowest x such that x is at least <b>number</b>, and x modulo
  405.  * <b>divisor</b> == 0. */
  406. static INLINE unsigned
  407. round_to_next_multiple_of(unsigned number, unsigned divisor)
  408. {
  409.   number += divisor - 1;
  410.   number -= number % divisor;
  411.   return number;
  412. }
  413. /** Return a newly allocated comma-separated string containing entries for all
  414.  * the countries from which we've seen enough clients connect. The entry
  415.  * format is cc=num where num is the number of IPs we've seen connecting from
  416.  * that country, and cc is a lowercased country code. Returns NULL if we don't
  417.  * want to export geoip data yet. */
  418. char *
  419. geoip_get_client_history(time_t now, geoip_client_action_t action)
  420. {
  421.   char *result = NULL;
  422.   if (!geoip_is_loaded())
  423.     return NULL;
  424.   if (client_history_starts < (now - GEOIP_MIN_OBSERVATION_TIME)) {
  425.     char buf[32];
  426.     smartlist_t *chunks = NULL;
  427.     smartlist_t *entries = NULL;
  428.     int n_countries = geoip_get_n_countries();
  429.     int i;
  430.     clientmap_entry_t **ent;
  431.     unsigned *counts = tor_malloc_zero(sizeof(unsigned)*n_countries);
  432.     unsigned total = 0;
  433.     unsigned granularity = IP_GRANULARITY;
  434. #ifdef ENABLE_GEOIP_STATS
  435.     if (get_options()->DirRecordUsageByCountry)
  436.       granularity = get_options()->DirRecordUsageGranularity;
  437. #endif
  438.     HT_FOREACH(ent, clientmap, &client_history) {
  439.       int country;
  440.       if (((*ent)->last_seen & ACTION_MASK) != (int)action)
  441.         continue;
  442.       country = geoip_get_country_by_ip((*ent)->ipaddr);
  443.       if (country < 0)
  444.         continue;
  445.       tor_assert(0 <= country && country < n_countries);
  446.       ++counts[country];
  447.       ++total;
  448.     }
  449.     /* Don't record anything if we haven't seen enough IPs. */
  450.     if (total < MIN_IPS_TO_NOTE_ANYTHING)
  451.       goto done;
  452.     /* Make a list of c_hist_t */
  453.     entries = smartlist_create();
  454.     for (i = 0; i < n_countries; ++i) {
  455.       unsigned c = counts[i];
  456.       const char *countrycode;
  457.       c_hist_t *ent;
  458.       /* Only report a country if it has a minimum number of IPs. */
  459.       if (c >= MIN_IPS_TO_NOTE_COUNTRY) {
  460.         c = round_to_next_multiple_of(c, granularity);
  461.         countrycode = geoip_get_country_name(i);
  462.         ent = tor_malloc(sizeof(c_hist_t));
  463.         strlcpy(ent->country, countrycode, sizeof(ent->country));
  464.         ent->total = c;
  465.         smartlist_add(entries, ent);
  466.       }
  467.     }
  468.     /* Sort entries. Note that we must do this _AFTER_ rounding, or else
  469.      * the sort order could leak info. */
  470.     smartlist_sort(entries, _c_hist_compare);
  471.     /* Build the result. */
  472.     chunks = smartlist_create();
  473.     SMARTLIST_FOREACH(entries, c_hist_t *, ch, {
  474.         tor_snprintf(buf, sizeof(buf), "%s=%u", ch->country, ch->total);
  475.         smartlist_add(chunks, tor_strdup(buf));
  476.       });
  477.     result = smartlist_join_strings(chunks, ",", 0, NULL);
  478.   done:
  479.     tor_free(counts);
  480.     if (chunks) {
  481.       SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
  482.       smartlist_free(chunks);
  483.     }
  484.     if (entries) {
  485.       SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c));
  486.       smartlist_free(entries);
  487.     }
  488.   }
  489.   return result;
  490. }
  491. /** Return a newly allocated string holding the per-country request history
  492.  * for <b>action</b> in a format suitable for an extra-info document, or NULL
  493.  * on failure. */
  494. char *
  495. geoip_get_request_history(time_t now, geoip_client_action_t action)
  496. {
  497.   smartlist_t *entries, *strings;
  498.   char *result;
  499.   unsigned granularity = IP_GRANULARITY;
  500. #ifdef ENABLE_GEOIP_STATS
  501.   if (get_options()->DirRecordUsageByCountry)
  502.     granularity = get_options()->DirRecordUsageGranularity;
  503. #endif
  504.   if (client_history_starts >= (now - GEOIP_MIN_OBSERVATION_TIME))
  505.     return NULL;
  506.   if (action != GEOIP_CLIENT_NETWORKSTATUS &&
  507.       action != GEOIP_CLIENT_NETWORKSTATUS_V2)
  508.     return NULL;
  509.   if (!geoip_countries)
  510.     return NULL;
  511.   entries = smartlist_create();
  512.   SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
  513.       uint32_t *n = (action == GEOIP_CLIENT_NETWORKSTATUS)
  514.         ? c->n_v3_ns_requests : c->n_v2_ns_requests;
  515.       uint32_t tot = 0;
  516.       int i;
  517.       c_hist_t *ent;
  518.       for (i=0; i < REQUEST_HIST_LEN; ++i)
  519.         tot += n[i];
  520.       if (!tot)
  521.         continue;
  522.       ent = tor_malloc_zero(sizeof(c_hist_t));
  523.       strlcpy(ent->country, c->countrycode, sizeof(ent->country));
  524.       ent->total = round_to_next_multiple_of(tot, granularity);
  525.       smartlist_add(entries, ent);
  526.   });
  527.   smartlist_sort(entries, _c_hist_compare);
  528.   strings = smartlist_create();
  529.   SMARTLIST_FOREACH(entries, c_hist_t *, ent, {
  530.       char buf[32];
  531.       tor_snprintf(buf, sizeof(buf), "%s=%u", ent->country, ent->total);
  532.       smartlist_add(strings, tor_strdup(buf));
  533.     });
  534.   result = smartlist_join_strings(strings, ",", 0, NULL);
  535.   SMARTLIST_FOREACH(strings, char *, cp, tor_free(cp));
  536.   SMARTLIST_FOREACH(entries, c_hist_t *, ent, tor_free(ent));
  537.   smartlist_free(strings);
  538.   smartlist_free(entries);
  539.   return result;
  540. }
  541. /** Store all our geoip statistics into $DATADIR/geoip-stats. */
  542. void
  543. dump_geoip_stats(void)
  544. {
  545. #ifdef ENABLE_GEOIP_STATS
  546.   time_t now = time(NULL);
  547.   time_t request_start;
  548.   char *filename = get_datadir_fname("geoip-stats");
  549.   char *data_v2 = NULL, *data_v3 = NULL;
  550.   char since[ISO_TIME_LEN+1], written[ISO_TIME_LEN+1];
  551.   open_file_t *open_file = NULL;
  552.   double v2_share = 0.0, v3_share = 0.0;
  553.   FILE *out;
  554.   data_v2 = geoip_get_client_history(now, GEOIP_CLIENT_NETWORKSTATUS_V2);
  555.   data_v3 = geoip_get_client_history(now, GEOIP_CLIENT_NETWORKSTATUS);
  556.   format_iso_time(since, geoip_get_history_start());
  557.   format_iso_time(written, now);
  558.   out = start_writing_to_stdio_file(filename, OPEN_FLAGS_REPLACE,
  559.                                     0600, &open_file);
  560.   if (!out)
  561.     goto done;
  562.   if (fprintf(out, "written %snstarted-at %snns-ips %snns-v2-ips %sn",
  563.               written, since,
  564.               data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
  565.     goto done;
  566.   tor_free(data_v2);
  567.   tor_free(data_v3);
  568.   request_start = current_request_period_starts -
  569.     (n_old_request_periods * REQUEST_HIST_PERIOD);
  570.   format_iso_time(since, request_start);
  571.   data_v2 = geoip_get_request_history(now, GEOIP_CLIENT_NETWORKSTATUS_V2);
  572.   data_v3 = geoip_get_request_history(now, GEOIP_CLIENT_NETWORKSTATUS);
  573.   if (fprintf(out, "requests-start %snn-ns-reqs %snn-v2-ns-reqs %sn",
  574.               since,
  575.               data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
  576.     goto done;
  577.   if (!router_get_my_share_of_directory_requests(&v2_share, &v3_share)) {
  578.     if (fprintf(out, "v2-ns-share %0.2lf%%n", v2_share*100) < 0)
  579.       goto done;
  580.     if (fprintf(out, "v3-ns-share %0.2lf%%n", v3_share*100) < 0)
  581.       goto done;
  582.   }
  583.   finish_writing_to_file(open_file);
  584.   open_file = NULL;
  585.  done:
  586.   if (open_file)
  587.     abort_writing_to_file(open_file);
  588.   tor_free(filename);
  589.   tor_free(data_v2);
  590.   tor_free(data_v3);
  591. #endif
  592. }
  593. /** Helper used to implement GETINFO ip-to-country/... controller command. */
  594. int
  595. getinfo_helper_geoip(control_connection_t *control_conn,
  596.                      const char *question, char **answer)
  597. {
  598.   (void)control_conn;
  599.   if (geoip_is_loaded() && !strcmpstart(question, "ip-to-country/")) {
  600.     int c;
  601.     uint32_t ip;
  602.     struct in_addr in;
  603.     question += strlen("ip-to-country/");
  604.     if (tor_inet_aton(question, &in) != 0) {
  605.       ip = ntohl(in.s_addr);
  606.       c = geoip_get_country_by_ip(ip);
  607.       *answer = tor_strdup(geoip_get_country_name(c));
  608.     }
  609.   }
  610.   return 0;
  611. }
  612. /** Release all storage held by the GeoIP database. */
  613. static void
  614. clear_geoip_db(void)
  615. {
  616.   if (geoip_countries) {
  617.     SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, tor_free(c));
  618.     smartlist_free(geoip_countries);
  619.   }
  620.   if (country_idxplus1_by_lc_code)
  621.     strmap_free(country_idxplus1_by_lc_code, NULL);
  622.   if (geoip_entries) {
  623.     SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, ent, tor_free(ent));
  624.     smartlist_free(geoip_entries);
  625.   }
  626.   geoip_countries = NULL;
  627.   country_idxplus1_by_lc_code = NULL;
  628.   geoip_entries = NULL;
  629. }
  630. /** Release all storage held in this file. */
  631. void
  632. geoip_free_all(void)
  633. {
  634.   clientmap_entry_t **ent, **next, *this;
  635.   for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) {
  636.     this = *ent;
  637.     next = HT_NEXT_RMV(clientmap, &client_history, ent);
  638.     tor_free(this);
  639.   }
  640.   HT_CLEAR(clientmap, &client_history);
  641.   clear_geoip_db();
  642. }