geoip.c 19 KB

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