diff options
Diffstat (limited to 'src/or/geoip.c')
-rw-r--r-- | src/or/geoip.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/src/or/geoip.c b/src/or/geoip.c index 9cd56b1d35..35d882499f 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -131,7 +131,7 @@ _geoip_compare_key_to_entry(const void *_key, const void **_member) * "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). */ @@ -208,9 +208,12 @@ geoip_is_loaded(void) typedef struct clientmap_entry_t { HT_ENTRY(clientmap_entry_t) node; uint32_t ipaddr; - time_t last_seen; + time_t last_seen; /* The last 2 bits of this value hold the client + * operation. */ } clientmap_entry_t; +#define ACTION_MASK 3 + /** Map from client IP address to last time seen. */ static HT_HEAD(clientmap, clientmap_entry_t) client_history = HT_INITIALIZER(); @@ -238,12 +241,28 @@ HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash, /** Note that we've seen a client connect from the IP <b>addr</b> (host order) * at time <b>now</b>. Ignored by all but bridges. */ void -geoip_note_client_seen(uint32_t addr, time_t now) +geoip_note_client_seen(geoip_client_action_t action, + uint32_t addr, time_t now) { or_options_t *options = get_options(); clientmap_entry_t lookup, *ent; - if (!(options->BridgeRelay && options->BridgeRecordUsageByCountry)) + if (action == GEOIP_CLIENT_CONNECT) { + if (!(options->BridgeRelay && options->BridgeRecordUsageByCountry)) + return; + } else { +#ifndef ENABLE_GEOIP_STATS return; +#else + if (options->BridgeRelay || options->BridgeAuthoritativeDir || + !options->DirRecordUsageByCountry) + return; +#endif + } + + /* We use the low 3 bits of the time to encode the action. Since we're + * potentially remembering times of clients, we don't want to make + * clientmap_entry_t larger than it has to be. */ + now = (now & ~ACTION_MASK) | (((int)action) & ACTION_MASK); lookup.ipaddr = addr; ent = HT_FIND(clientmap, &client_history, &lookup); if (ent) { @@ -328,7 +347,7 @@ _c_hist_compare(const void **_a, const void **_b) * that country, and cc is a lowercased country code. Returns NULL if we don't * want to export geoip data yet. */ char * -geoip_get_client_history(time_t now) +geoip_get_client_history(time_t now, geoip_client_action_t action) { char *result = NULL; if (!geoip_is_loaded()) @@ -343,7 +362,10 @@ geoip_get_client_history(time_t now) unsigned *counts = tor_malloc_zero(sizeof(unsigned)*n_countries); unsigned total = 0; HT_FOREACH(ent, clientmap, &client_history) { - int country = geoip_get_country_by_ip((*ent)->ipaddr); + int country; + if (((*ent)->last_seen & ACTION_MASK) != action) + continue; + country = geoip_get_country_by_ip((*ent)->ipaddr); if (country < 0) continue; tor_assert(0 <= country && country < n_countries); @@ -404,6 +426,41 @@ geoip_get_client_history(time_t now) return result; } +void +dump_geoip_stats(void) +{ +#ifdef ENABLE_GEOIP_STATS + time_t now = time(NULL); + char *filename = get_datadir_fname("geoip-stats"); + char *data_v2 = NULL, *data_v3 = NULL; + char since[ISO_TIME_LEN+1], written[ISO_TIME_LEN+1]; + open_file_t *open_file = NULL; + FILE *out; + + data_v2 = geoip_get_client_history(now, GEOIP_CLIENT_NETWORKSTATUS_V2); + data_v3 = geoip_get_client_history(now, GEOIP_CLIENT_NETWORKSTATUS); + format_iso_time(since, geoip_get_history_start()); + format_iso_time(written, now); + if (!data_v2 || !data_v3) + goto done; + out = start_writing_to_stdio_file(filename, 0, 0600, &open_file); + if (!out) + goto done; + if (fprintf(out, "written %s\nstarted-at %s\nns %s\nns-v2%s\n", + written, since, data_v3, data_v2) < 0) + goto done; + + finish_writing_to_file(open_file); + open_file = NULL; + done: + if (open_file) + abort_writing_to_file(open_file); + tor_free(filename); + tor_free(data_v2); + tor_free(data_v3); +#endif +} + /** Helper used to implement GETINFO ip-to-country/... controller command. */ int getinfo_helper_geoip(control_connection_t *control_conn, |