transferred bytes per port to disk every 24 hours. To enable this,
run configure with the --enable-exit-stats option, and set
"ExitPortStatistics 1" in your torrc.
+ - Entry nodes can write statistics on the rough number and origins of
+ connecting clients to disk every 24 hours. To enable this, run
+ configure with the --enable-entry-stats option, and set
+ "EntryStatistics 1" in your torrc.
o Minor bugfixes
- Hidden service clients didn't use a cached service descriptor that
AC_DEFINE(ENABLE_GEOIP_STATS, 1, [Defined if we try to collect per-country statistics])
fi
+AC_ARG_ENABLE(entry-stats,
+ AS_HELP_STRING(--enable-entry-stats, enable code for entry guards to collect per-country statistics))
+
+if test "$enable_entry_stats" = "yes"; then
+ AC_DEFINE(ENABLE_ENTRY_STATS, 1, [Defined if we try to collect per-country statistics])
+fi
+
AC_ARG_ENABLE(gcc-warnings,
AS_HELP_STRING(--enable-gcc-warnings, enable verbose warnings))
V(DownloadExtraInfo, BOOL, "0"),
V(EnforceDistinctSubnets, BOOL, "1"),
V(EntryNodes, ROUTERSET, NULL),
+ V(EntryStatistics, BOOL, "0"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
V(ExcludeNodes, ROUTERSET, NULL),
V(ExcludeExitNodes, ROUTERSET, NULL),
if (options->ExitPortStatistics)
log_warn(LD_CONFIG, "ExitPortStatistics enabled, but Tor was built "
"without port statistics support.");
+#endif
+#ifdef ENABLE_ENTRY_STATS
+ if (options->EntryStatistics) {
+ if (should_record_bridge_info(options)) {
+ /* Don't allow measuring statistics on entry guards when configured
+ * as bridge. */
+ log_warn(LD_CONFIG, "Bridges cannot be configured to measure "
+ "additional GeoIP statistics as entry guards.");
+ return -1;
+ } else
+ log_notice(LD_CONFIG, "Configured to measure entry node "
+ "statistics. Look for the entry-stats file that will "
+ "first be written to the data directory in 24 hours "
+ "from now.");
+ }
+#else
+ if (options->EntryStatistics)
+ log_warn(LD_CONFIG, "EntryStatistics enabled, but Tor was built "
+ "without entry node statistics support.");
#endif
/* Check if we need to parse and add the EntryNodes config option. */
if (options->EntryNodes &&
static void clear_geoip_db(void);
static void dump_geoip_stats(void);
+static void dump_entry_stats(void);
/** An entry from the GeoIP file: maps an IP range to a country. */
typedef struct geoip_entry_t {
or_options_t *options = get_options();
clientmap_entry_t lookup, *ent;
if (action == GEOIP_CLIENT_CONNECT) {
+#ifdef ENABLE_ENTRY_STATS
+ if (!options->EntryStatistics)
+ return;
+#else
if (!(options->BridgeRelay && options->BridgeRecordUsageByCountry))
return;
+#endif
/* Did we recently switch from bridge to relay or back? */
if (client_history_starts > now)
return;
geoip_remove_old_clients(current_request_period_starts);
/* Before rotating, write the current stats to disk. */
dump_geoip_stats();
+ if (get_options()->EntryStatistics)
+ dump_entry_stats();
/* Now rotate request period */
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
memmove(&c->n_v2_ns_requests[0], &c->n_v2_ns_requests[1],
#endif
}
+/** Store all our geoip statistics as entry guards into
+ * $DATADIR/entry-stats. */
+static void
+dump_entry_stats(void)
+{
+#ifdef ENABLE_ENTRY_STATS
+ time_t now = time(NULL);
+ char *filename = get_datadir_fname("entry-stats");
+ char *data = NULL;
+ char since[ISO_TIME_LEN+1], written[ISO_TIME_LEN+1];
+ open_file_t *open_file = NULL;
+ FILE *out;
+
+ data = geoip_get_client_history(now, GEOIP_CLIENT_CONNECT);
+ format_iso_time(since, geoip_get_history_start());
+ format_iso_time(written, now);
+ out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND,
+ 0600, &open_file);
+ if (!out)
+ goto done;
+ if (fprintf(out, "written %s\nstarted-at %s\nips %s\n",
+ written, since, data ? data : "") < 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);
+#endif
+}
+
/** Helper used to implement GETINFO ip-to-country/... controller command. */
int
getinfo_helper_geoip(control_connection_t *control_conn,
/** If true, the user wants us to collect statistics on port usage. */
int ExitPortStatistics;
+ /** If true, the user wants us to collect statistics as entry node. */
+ int EntryStatistics;
+
/** If true, do not believe anybody who tells us that a domain resolves
* to an internal address, or that an internal address has a PTR mapping.
* Helps avoid some cross-site attacks. */
* we are willing to talk about it? */
#define DIR_RECORD_USAGE_MIN_OBSERVATION_TIME (24*60*60)
+/** Time interval: Flush geoip data to disk this often when measuring on an
+ * entry guard. */
+#define ENTRY_RECORD_USAGE_RETAIN_IPS (24*60*60)
+
#ifdef GEOIP_PRIVATE
int geoip_parse_entry(const char *line);
#endif
* the others, we're not.
*/
typedef enum {
- /** We've noticed a connection as a bridge relay. */
+ /** We've noticed a connection as a bridge relay or entry guard. */
GEOIP_CLIENT_CONNECT = 0,
/** We've served a networkstatus consensus as a directory server. */
GEOIP_CLIENT_NETWORKSTATUS = 1,
int geoip_purge_interval = 48*60*60;
#ifdef ENABLE_GEOIP_STATS
geoip_purge_interval = DIR_RECORD_USAGE_RETAIN_IPS;
+#endif
+#ifdef ENABLE_ENTRY_STATS
+ geoip_purge_interval = ENTRY_RECORD_USAGE_RETAIN_IPS;
#endif
if (now > last_purged_at+geoip_purge_interval) {
/* (Note that this also discards items in the client history with