tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit 1b490c2030daae89025794592dab11fdaaa3a48f
parent dba00ebf3435848d95ca58f78078b2e0378f8af1
Author: David Goulet <dgoulet@torproject.org>
Date:   Tue, 13 Jan 2026 11:58:36 -0500

Merge branch 'maint-0.4.8'

Diffstat:
Achanges/bug41192 | 9+++++++++
Achanges/bug41192b | 4++++
Msrc/feature/dircache/dircache.c | 8++++----
Msrc/feature/dircache/dirserv.c | 12++++++++++++
Msrc/feature/dircommon/dir_connection_st.h | 4++++
Msrc/feature/stats/geoip_stats.c | 8+++++---
Msrc/feature/stats/geoip_stats.h | 7+++++--
Msrc/test/test_geoip.c | 13+++++++++----
8 files changed, 52 insertions(+), 13 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/changes/bug41192b b/changes/bug41192b @@ -0,0 +1,4 @@ + o Minor features (directory servers): + - Track how many times directory servers begin serving networkstatus + documents, so we can compare it to the number of times we finish + serving them. Motivated by the fixes in ticket 41192. diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c @@ -968,12 +968,12 @@ handle_get_current_consensus(dir_connection_t *conn, goto done; } + /* Success: we are going to try serving it. */ + geoip_note_ns_response(GEOIP_SERVED); + 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; diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c @@ -390,8 +390,8 @@ geoip_client_cache_total_allocation(void) * statuses? */ static uint32_t ns_v3_responses[GEOIP_NS_RESPONSE_NUM]; -/** Note that we've rejected a client's request for a v3 network status - * for reason <b>reason</b> at time <b>now</b>. */ +/** Note how we have handled a client's request for a v3 network status: + * with <b>reason</b> at time <b>now</b>. */ void geoip_note_ns_response(geoip_ns_response_t response) { @@ -997,7 +997,8 @@ geoip_format_dirreq_stats(time_t now) tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n" "dirreq-v3-ips %s\n" "dirreq-v3-reqs %s\n" - "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u," + "dirreq-v3-resp " + "served=%u,ok=%u,not-enough-sigs=%u,unavailable=%u," "not-found=%u,not-modified=%u,busy=%u\n" "dirreq-v3-direct-dl %s\n" "dirreq-v3-tunneled-dl %s\n", @@ -1005,6 +1006,7 @@ geoip_format_dirreq_stats(time_t now) (unsigned) (now - start_of_dirreq_stats_interval), v3_ips_string ? v3_ips_string : "", v3_reqs_string ? v3_reqs_string : "", + ns_v3_responses[GEOIP_SERVED], ns_v3_responses[GEOIP_SUCCESS], ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS], ns_v3_responses[GEOIP_REJECT_UNAVAILABLE], diff --git a/src/feature/stats/geoip_stats.h b/src/feature/stats/geoip_stats.h @@ -25,7 +25,7 @@ typedef enum { /** We've served a networkstatus consensus as a directory server. */ GEOIP_CLIENT_NETWORKSTATUS = 1, } geoip_client_action_t; -/** Indicates either a positive reply or a reason for rejectng a network +/** Indicates either a positive reply or a reason for rejecting a network * status request that will be included in geoip statistics. */ typedef enum { /** Request is answered successfully. */ @@ -41,8 +41,11 @@ typedef enum { GEOIP_REJECT_NOT_MODIFIED = 4, /** Directory is busy. */ GEOIP_REJECT_BUSY = 5, + /** We began to serve the request, and when we feel we have finished + * serving it we will note this with a GEOIP_SUCCESS call too. */ + GEOIP_SERVED = 6, } geoip_ns_response_t; -#define GEOIP_NS_RESPONSE_NUM 6 +#define GEOIP_NS_RESPONSE_NUM 7 /** Directory requests that we are measuring can be either direct or * tunneled. */ diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c @@ -58,7 +58,8 @@ test_geoip(void *arg) "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips ab=8\n" "dirreq-v3-reqs ab=8\n" - "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=0,ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", @@ -66,7 +67,8 @@ test_geoip(void *arg) "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" - "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=0,ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", @@ -74,7 +76,8 @@ test_geoip(void *arg) "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" - "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=8,ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", @@ -82,7 +85,8 @@ test_geoip(void *arg) "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" - "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," + "dirreq-v3-resp " + "served=8,ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n", @@ -230,6 +234,7 @@ test_geoip(void *arg) /* Note a successful network status response and make sure that it * appears in the history string. */ + geoip_note_ns_response(GEOIP_SERVED); geoip_note_ns_response(GEOIP_SUCCESS); s = geoip_format_dirreq_stats(now + 86400); tt_str_op(dirreq_stats_3,OP_EQ, s);