commit 49a410d5c1568cde733502478defe751f9940a8a
parent c27d1f33b56ed4557426bc167a568101bdda691b
Author: Roger Dingledine <arma@torproject.org>
Date: Thu, 8 Jan 2026 00:03:58 -0500
Don't count networkstatus serves until they finish
When we started serving a consensus document but the client didn't
receive all of it, we were still counting that as a success in our stats.
This mistake, which can be triggered for example by obsolete clients or
by DPI-based censorship, led to wildly inflated user counts because we
estimate total users in the world based on successful consensus fetches.
Fixes bug 41192; bugfix on 0.2.1.1-alpha.
Diffstat:
4 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/changes/bug41192 b/changes/bug41192
@@ -0,0 +1,9 @@
+ o Major bugfixes (directory servers):
+ - Don't count networkstatus serves until they finish. When we started
+ serving a consensus document but the client didn't receive all of
+ it, we were still counting that as a success in our stats. This
+ mistake, which can be triggered for example by obsolete clients
+ or by DPI-based censorship, led to wildly inflated user counts
+ because we estimate total users in the world based on successful
+ consensus fetches. Fixes bug 41192; bugfix on 0.2.1.1-alpha.
+
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
@@ -968,12 +968,11 @@ handle_get_current_consensus(dir_connection_t *conn,
goto done;
}
+ /* Success: we are going to try serving it. */
+ conn->should_count_geoip_when_finished = 1;
+
tor_addr_t addr;
if (tor_addr_parse(&addr, (TO_CONN(conn))->address) >= 0) {
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS,
- &addr, NULL,
- time(NULL));
- geoip_note_ns_response(GEOIP_SUCCESS);
/* Note that a request for a network status has started, so that we
* can measure the download time later on. */
if (conn->dirreq_id)
diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c
@@ -15,6 +15,7 @@
#include "feature/nodelist/routerlist.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
+#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
#include "feature/dircache/cached_dir_st.h"
@@ -778,6 +779,17 @@ connection_dirserv_flushed_some(dir_connection_t *conn)
tor_compress_free(conn->compress_state);
conn->compress_state = NULL;
}
+ if (conn->should_count_geoip_when_finished) {
+ /* only count successfully networkstatus serves when the spool runs dry */
+ tor_addr_t addr;
+ if (tor_addr_parse(&addr, (TO_CONN(conn))->address) >= 0) {
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS,
+ &addr, NULL,
+ time(NULL));
+ }
+ geoip_note_ns_response(GEOIP_SUCCESS);
+ conn->should_count_geoip_when_finished = 0;
+ }
return 0;
}
diff --git a/src/feature/dircommon/dir_connection_st.h b/src/feature/dircommon/dir_connection_st.h
@@ -61,6 +61,10 @@ struct dir_connection_t {
* needs this for the incoming side, so it's moved here. */
uint64_t dirreq_id;
+ /** 0 normally, 1 if we're serving a consensus and we're delaying counting
+ * geoip until we've served the final bytes. */
+ bool should_count_geoip_when_finished;
+
#ifdef MEASUREMENTS_21206
/** Number of RELAY_DATA cells received. */
uint32_t data_cells_received;