summaryrefslogtreecommitdiff
path: root/src/or/geoip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/geoip.c')
-rw-r--r--src/or/geoip.c69
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,