|
@@ -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;
|
|
|
+ * operation. */
|
|
|
} clientmap_entry_t;
|
|
|
|
|
|
+#define ACTION_MASK 3
|
|
|
+
|
|
|
|
|
|
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,
|
|
|
|
|
|
* 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
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 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
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
int
|
|
|
getinfo_helper_geoip(control_connection_t *control_conn,
|