commit 8a7ade95b64407fe29350f96def8782d049f4ddd
parent 7c1241bf778d8489aece0208167781b9369ac49b
Author: Alexander Hansen Færøy <ahf@torproject.org>
Date: Thu, 28 Aug 2025 15:19:52 +0200
Merge branch 'bridgeline' into 'main'
bridge: output complete bridge lines to logs & disk
See merge request tpo/core/tor!782
Diffstat:
7 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/changes/ticket29128 b/changes/ticket29128
@@ -0,0 +1,2 @@
+ o Minor features (bridges):
+ - Save complete bridge lines to 'datadir/bridgelines'. Closes ticket 29128.
diff --git a/doc/man/tor.1.txt b/doc/man/tor.1.txt
@@ -4103,6 +4103,10 @@ __DataDirectory__/**`hashed-fingerprint`**::
Only used by bridges. Contains the hashed fingerprint of the bridge's
identity key. (That is, the hash of the hash of the identity key.)
+__DataDirectory__/**`bridgelines`**::
+ Only used by bridges. Contains the bridge lines that clients can use to
+ connect using pluggable transports.
+
__DataDirectory__/**`approved-routers`**::
Only used by authoritative directory servers. Each line lists a status and
an identity, separated by whitespace. Identities can be hex-encoded RSA
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
@@ -13,6 +13,7 @@
#include "core/mainloop/mainloop.h"
+#include "feature/client/transports.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
@@ -132,14 +133,18 @@ resolved_addr_set_suggested(const tor_addr_t *addr)
}
/* In case we don't have a configured address, log that we will be using the
- * one discovered from the dirauth. */
+ * one discovered from the dirauth, and, if running a bridge, use the new IP
+ * for the bridge lines. */
const int idx = af_to_idx(tor_addr_family(addr));
if (tor_addr_is_null(&last_resolved_addrs[idx]) &&
!tor_addr_eq(&last_suggested_addrs[idx], addr)) {
log_notice(LD_CONFIG, "External address seen and suggested by a "
"directory authority: %s", fmt_addr(addr));
+ tor_addr_copy(&last_suggested_addrs[idx], addr);
+ pt_update_bridge_lines();
+ } else {
+ tor_addr_copy(&last_suggested_addrs[idx], addr);
}
- tor_addr_copy(&last_suggested_addrs[idx], addr);
}
/** Copy the last resolved address of family into addr_out.
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
@@ -2332,6 +2332,7 @@ ip_address_changed(int on_client_conn)
reset_bandwidth_test();
reset_uptime();
router_reset_reachability();
+ pt_update_bridge_lines();
/* All relays include their IP addresses as their ORPort addresses in
* their descriptor.
* Exit relays also incorporate interface addresses in their exit
diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c
@@ -676,6 +676,7 @@ register_server_proxy(const managed_proxy_t *mp)
t->name, fmt_addrport(&t->addr, t->port));
control_event_transport_launched("server", t->name, &t->addr, t->port);
} SMARTLIST_FOREACH_END(t);
+ pt_update_bridge_lines();
}
/** Register all the transports supported by client managed proxy
@@ -1830,6 +1831,92 @@ pt_get_extra_info_descriptor_string(void)
return the_string;
}
+/** Log the bridge lines that clients can use to connect. */
+void
+pt_update_bridge_lines(void)
+{
+ char fingerprint[FINGERPRINT_LEN+1];
+ smartlist_t *string_chunks = NULL;
+
+ if (!server_identity_key_is_set() || !managed_proxy_list)
+ return;
+
+ if (crypto_pk_get_fingerprint(get_server_identity_key(), fingerprint, 0)<0) {
+ log_err(LD_BUG, "Error computing fingerprint");
+ return;
+ }
+
+ string_chunks = smartlist_new();
+
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) {
+ if (!mp->is_server)
+ continue;
+
+ tor_assert(mp->transports);
+
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ char *transport_args = NULL;
+ const char *saddr = NULL;
+
+ /* If the transport proxy returned "0.0.0.0" as its address, display
+ * our external address if we know it, or a placeholder if we don't */
+ if (tor_addr_is_null(&t->addr)) {
+ tor_addr_t addr;
+ /* Attempt to find the IPv4 and then attempt to find the IPv6 if we
+ * can't find it. */
+ bool found = relay_find_addr_to_publish(get_options(), AF_INET,
+ RELAY_FIND_ADDR_NO_FLAG,
+ &addr);
+ if (!found) {
+ found = relay_find_addr_to_publish(get_options(), AF_INET6,
+ RELAY_FIND_ADDR_NO_FLAG, &addr);
+ }
+ if (found && !tor_addr_is_null(&addr)) {
+ saddr = fmt_and_decorate_addr(&addr);
+ } else {
+ saddr = "<IP ADDRESS>";
+ }
+ } else {
+ saddr = fmt_and_decorate_addr(&t->addr);
+ }
+
+ /* If this transport has any arguments with it, prepend a space
+ * to them so that we can add them to the transport line, and replace
+ * commas with spaces to make it a valid bridge line. */
+ if (t->extra_info_args) {
+ tor_asprintf(&transport_args, " %s", t->extra_info_args);
+ for (int i = 0; transport_args[i]; i++) {
+ if (transport_args[i] == ',') {
+ transport_args[i] = ' ';
+ }
+ }
+ }
+
+ smartlist_add_asprintf(string_chunks, "Bridge %s %s:%d %s%s",
+ t->name, saddr, t->port, fingerprint,
+ transport_args ? transport_args : "");
+ tor_free(transport_args);
+ } SMARTLIST_FOREACH_END(t);
+ } SMARTLIST_FOREACH_END(mp);
+
+ /* If we have any valid bridgelines, join them into a single string, and
+ * save them to disk. Don't create an empty file. */
+ if (smartlist_len(string_chunks) != 0) {
+ char *str = smartlist_join_strings(string_chunks, "\n", 1, NULL);
+ char *fname = get_datadir_fname("bridgelines");
+ if (write_str_to_file_if_not_equal(fname, str)) {
+ log_warn(LD_FS, "Couldn't save bridge lines to disk");
+ } else {
+ log_info(LD_FS, "Saved bridge lines to disk");
+ }
+ tor_free(fname);
+ tor_free(str);
+ }
+
+ SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s));
+ smartlist_free(string_chunks);
+}
+
/** Stringify the SOCKS arguments in <b>socks_args</b> according to
* 180_pluggable_transport.txt. The string is allocated on the heap
* and it's the responsibility of the caller to free it after use. */
diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h
@@ -57,6 +57,7 @@ void pt_configure_remaining_proxies(void);
int pt_proxies_configuration_pending(void);
char *pt_get_extra_info_descriptor_string(void);
+void pt_update_bridge_lines(void);
void pt_free_all(void);
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
@@ -382,6 +382,7 @@ set_server_identity_key(crypto_pk_t *k)
log_err(LD_BUG, "Couldn't compute our own identity key digest.");
tor_assert(0);
}
+ pt_update_bridge_lines();
}
#ifdef TOR_UNIT_TESTS