geoip.c 22 KB

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