From 33c3059c8233fb9a3076c8452f7cea00412ccdfb Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 20 Apr 2023 20:55:17 +0000 Subject: [PATCH] Handle infinite loop with only one bridge (or snowflake). --- src/core/or/conflux_pool.c | 9 +++++++++ src/feature/client/bridges.c | 35 +++++++++++++++++++++++++++++++++++ src/feature/client/bridges.h | 1 + 3 files changed, 45 insertions(+) diff --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c index b9da1fe75a..ae14bd1b3c 100644 --- a/src/core/or/conflux_pool.c +++ b/src/core/or/conflux_pool.c @@ -35,6 +35,7 @@ #include "core/or/conflux_st.h" #include "feature/nodelist/nodelist.h" +#include "feature/client/bridges.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" @@ -1150,6 +1151,14 @@ conflux_add_guards_to_exclude_list(const origin_circuit_t *orig_circ, return; } + /* If there is only one bridge, then only issue a warn once that + * at least two bridges are best for conflux. Exempt Snowflake + * from this warn */ + if (get_options()->UseBridges && !conflux_can_exclude_used_bridges()) { + /* Do not build any exclude lists; not enough bridges */ + return; + } + /* A linked set exists, use it. */ const conflux_t *cfx = linked_pool_get(circ->conflux_pending_nonce, true); if (cfx) { diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index 9e36d26929..a0375828a7 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -139,6 +139,41 @@ bridge_list_get(void) return bridge_list; } +/** + * Returns true if there are enough bridges to make a conflux set + * without re-using the same bridge. + */ +bool +conflux_can_exclude_used_bridges(void) +{ + if (smartlist_len(bridge_list_get()) == 1) { + static bool warned_once = false; + bridge_info_t *bridge = smartlist_get(bridge_list_get(), 0); + tor_assert(bridge); + + /* Snowflake is a special case. With one snowflake bridge, + * you are load balanced among many back-end bridges. + * So we do not need to warn the user for it. */ + if (bridge->transport_name && + strcasecmp(bridge->transport_name, "snowflake") == 0) { + return false; + } + + if (!warned_once) { + log_warn(LD_CIRC, "Only one bridge (transport: '%s') is configured. " + "You should have at least two for conflux, " + "for any transport that is not 'snowflake'.", + bridge->transport_name ? + bridge->transport_name : "vanilla"); + warned_once = true; + } + + return false; + } + + return true; +} + /** * Given a bridge, return a pointer to its RSA identity digest, or * NULL if we don't know one for it. diff --git a/src/feature/client/bridges.h b/src/feature/client/bridges.h index dd3e498a0a..2b514ba6c9 100644 --- a/src/feature/client/bridges.h +++ b/src/feature/client/bridges.h @@ -67,6 +67,7 @@ MOCK_DECL(download_status_t *, get_bridge_dl_status_by_id, (const char *digest)); void bridges_free_all(void); +bool conflux_can_exclude_used_bridges(void); #ifdef TOR_BRIDGES_PRIVATE STATIC void clear_bridge_list(void);