connected: tell lightningd if we didn't find an address we could even *try* to connect to.
What changed, and why it matters
This change improves how Core Lightning reports connection failures. It adds a flag telling the main daemon whether the node actually tried to connect to any address, or couldn't even attempt one (for example, because the peer only offers Tor addresses and this node has no Tor proxy, or only offers IPv6 and this node can't use IPv6). This helps avoid wrongly marking peers as unreachable when the real problem is local network capability. There is no direct security vulnerability being fixed here; it is a reliability and diagnostic improvement.
No urgent action required. This is a reliability/diagnostic improvement. Downstream code may later consume the `connect_attempted` flag to adjust reconnection or peer-penalty behavior. Reviewers should verify that all call sites of `connect_failed` in connectd set the flag correctly and that the wire message version compatibility is handled in mixed-version deployments.
Security signals we found
Information-flow improvement: distinguishes 'no usable address' from 'tried and failed', reducing false positives in peer reachability state
No memory safety, cryptographic, authentication, or authorization changes visible
No input validation changes visible
No privilege boundary crossed beyond existing connectd/lightningd IPC
No CVE, advisory, or vendor security disclosure referenced in commit
Evidence from the diff
The commit extends the connectd->lightningd CONNECTD_CONNECT_FAILED wire message with a new boolean field connect_attempted. connectd now tracks whether any address was actually attempted (connect->connect_attempted is set true when an address is selected for connection). If all addresses are unsuitable (Tor-only without proxy, IPv6-only without IPv6 support, etc.), connectd reports connect_attempted=false. lightningd’s connect_control.c receives and forwards this flag, but the current diff does not show any downstream consumer acting on it. The change is defensive: it prevents misclassification of unreachable peers and lays groundwork for better retry/penalty logic.
Changed components
connectd/connectd.cconnectd/connectd.hconnectd/connectd_wire.csvlightningd/connect_control.cInspect captured patch +24 / −8
diff --git a/connectd/connectd.c b/connectd/connectd.c
index ea93b230..761b6dd2 100644
--- a/connectd/connectd.c
+++ b/connectd/connectd.c
@@ -789,11 +789,12 @@ struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect)
*/
static void connect_failed(struct daemon *daemon,
const struct node_id *id,
+ bool connect_attempted,
const char *connect_reason,
struct timemono start,
enum jsonrpc_errcode errcode,
const char *errfmt, ...)
- PRINTF_FMT(6, 7);
+ PRINTF_FMT(7, 8);
static void reconnect(struct important_id *imp)
{
@@ -865,6 +866,7 @@ void release_one_waiting_connection(struct daemon *daemon, const char *why)
static void connect_failed(struct daemon *daemon,
const struct node_id *id,
+ bool connect_attempted,
const char *connect_reason,
struct timemono start,
enum jsonrpc_errcode errcode,
@@ -885,7 +887,8 @@ static void connect_failed(struct daemon *daemon,
msg = towire_connectd_connect_failed(NULL, id,
connect_reason,
time_to_nsec(timemono_since(start)),
- errcode, errmsg);
+ errcode, errmsg,
+ connect_attempted);
daemon_conn_send(daemon->master, take(msg));
/* If we're supposed to schedule a reconnect, do so */
@@ -1038,9 +1041,10 @@ static void try_connect_one_addr(struct connecting *connect)
const char *errors = tal_steal(tmpctx, connect->errors);
const char *reason = tal_steal(tmpctx, connect->reason);
struct timemono start = connect->start;
+ bool attempted = connect->connect_attempted;
tal_free(connect);
- connect_failed(daemon, &id, reason, start,
+ connect_failed(daemon, &id, attempted, reason, start,
CONNECT_ALL_ADDRESSES_FAILED,
"All addresses failed: %s",
errors);
@@ -1167,6 +1171,8 @@ static void try_connect_one_addr(struct connecting *connect)
goto next;
}
+ connect->connect_attempted = true;
+
/* This creates the new connection using our fd, with the initialization
* function one of the above. */
if (use_proxy)
@@ -1873,7 +1879,7 @@ static void try_connect_peer(struct daemon *daemon,
/* Still no address? Fail immediately. Important ones get
* retried; an address may get gossiped. */
if (tal_count(addrs) == 0) {
- connect_failed(daemon, id, reason, time_mono(),
+ connect_failed(daemon, id, false, reason, time_mono(),
CONNECT_NO_KNOWN_ADDRESS,
"Unable to connect, no address known for peer");
return;
@@ -1893,6 +1899,7 @@ static void try_connect_peer(struct daemon *daemon,
connect->connstate = "Connection establishment";
connect->errors = tal_strdup(connect, "");
connect->conn = NULL;
+ connect->connect_attempted = false;
connecting_htable_add(daemon->connecting, connect);
tal_add_destructor(connect, destroy_connecting);
diff --git a/connectd/connectd.h b/connectd/connectd.h
index 8a576233..fd750963 100644
--- a/connectd/connectd.h
+++ b/connectd/connectd.h
@@ -214,6 +214,9 @@ struct connecting {
/* When did we start? */
struct timemono start;
+ /* Did we find an address we could attempt to connect to? */
+ bool connect_attempted;
+
/* Accumulated errors */
char *errors;
};
diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv
index c4ad70ea..d3af2709 100644
--- a/connectd/connectd_wire.csv
+++ b/connectd/connectd_wire.csv
@@ -73,6 +73,7 @@ msgdata,connectd_connect_failed,connect_reason,wirestring,
msgdata,connectd_connect_failed,connect_nsec,u64,
msgdata,connectd_connect_failed,failcode,enum jsonrpc_errcode,
msgdata,connectd_connect_failed,failreason,wirestring,
+msgdata,connectd_connect_failed,connect_attempted,bool,
# Connectd -> master: we got a peer.
msgtype,connectd_peer_connected,2002
diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c
index 8766009b..850dc9d7 100644
--- a/lightningd/connect_control.c
+++ b/lightningd/connect_control.c
@@ -257,7 +257,8 @@ static void connect_failed(struct lightningd *ld,
const char *connect_reason,
u64 connect_nsec,
enum jsonrpc_errcode errcode,
- const char *errmsg)
+ const char *errmsg,
+ bool connect_attempted)
{
struct connect *c;
@@ -275,7 +276,8 @@ void connect_failed_disconnect(struct lightningd *ld,
connect_failed(ld, id, addrhint,
"", 0,
CONNECT_DISCONNECTED_DURING,
- "disconnected during connection");
+ "disconnected during connection",
+ false);
}
static void handle_connect_failed(struct lightningd *ld, const u8 *msg)
@@ -285,15 +287,18 @@ static void handle_connect_failed(struct lightningd *ld, const u8 *msg)
char *errmsg;
char *connect_reason;
u64 nsec;
+ bool connect_attempted;
if (!fromwire_connectd_connect_failed(tmpctx, msg, &id,
&connect_reason,
&nsec,
- &errcode, &errmsg))
+ &errcode, &errmsg,
+ &connect_attempted))
fatal("Connect gave bad CONNECTD_CONNECT_FAILED message %s",
tal_hex(msg, msg));
- connect_failed(ld, &id, NULL, connect_reason, nsec, errcode, errmsg);
+ connect_failed(ld, &id, NULL, connect_reason, nsec, errcode, errmsg,
+ connect_attempted);
}
const char *connect_any_cmd_id(const tal_t *ctx,
Why this scored 22/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.