connectd: warn if we ignore peer incoming for longer than 5 seconds.
What changed, and why it matters
This change adds a warning log when the Lightning node's connection handler has ignored incoming peer messages for more than 5 seconds. It does not fix the underlying delay; it only makes the delay visible in logs so operators and developers can spot when message processing stalls.
Treat this as a monitoring/diagnostics improvement rather than a security patch. Operators should watch for the new warning in logs as an indicator of potential liveness issues. If the underlying stall is later shown to be exploitable (e.g., for denial of service), a separate fix would be needed.
Security signals we found
Adds diagnostic warning for peer input processing delays exceeding 5 seconds
Identifies a known stall condition: connectd stops reading peer input until a subdaemon's queue is drained
Reestablish handling on slow machines is called out as a trigger scenario
No input validation, cryptographic, or memory safety changes present
Evidence from the diff
The commit instruments connectd to track when a peer message has been received but not yet forwarded to a subdaemon. It records the message type and timestamp in read_body_from_peer_done(), then in write_to_subd() computes the elapsed time when the subdaemon queue is drained and emits a status_peer_broken() warning if the delay exceeds 5000 ms. This is diagnostic instrumentation, not a behavioral fix for the stall.
Changed components
connectdconnectd/multiplex.cconnectd/connectd.cconnectd/connectd.hInspect captured patch +18 / −0
diff --git a/connectd/connectd.c b/connectd/connectd.c
index 69fe522a..068e4ab5 100644
--- a/connectd/connectd.c
+++ b/connectd/connectd.c
@@ -147,6 +147,7 @@ static struct peer *new_peer(struct daemon *daemon,
peer->sent_to_peer = NULL;
peer->urgent = false;
peer->draining = false;
+ peer->peer_in_lastmsg = -1;
peer->peer_outq = msg_queue_new(peer, false);
peer->last_recv_time = time_now();
peer->is_websocket = is_websocket;
diff --git a/connectd/connectd.h b/connectd/connectd.h
index d43179d9..8b4a224b 100644
--- a/connectd/connectd.h
+++ b/connectd/connectd.h
@@ -96,6 +96,10 @@ struct peer {
/* Last time we received traffic */
struct timeabs last_recv_time;
+ /* How long have we been ignoring peer input? */
+ struct timemono peer_in_lasttime;
+ int peer_in_lastmsg;
+
/* Ratelimits for onion messages. One token per msec. */
size_t onionmsg_incoming_tokens;
struct timemono onionmsg_last_incoming;
diff --git a/connectd/multiplex.c b/connectd/multiplex.c
index a6e418d3..48013e4d 100644
--- a/connectd/multiplex.c
+++ b/connectd/multiplex.c
@@ -1147,6 +1147,16 @@ static struct io_plan *write_to_subd(struct io_conn *subd_conn,
/* Tell them to read again. */
io_wake(&subd->peer->peer_in);
+ if (subd->peer->peer_in_lastmsg != -1) {
+ u64 msec = time_to_msec(timemono_between(time_mono(),
+ subd->peer->peer_in_lasttime));
+ if (msec > 5000)
+ status_peer_broken(&subd->peer->id,
+ "wake delay for %s: %"PRIu64"msec",
+ peer_wire_name(subd->peer->peer_in_lastmsg),
+ msec);
+ subd->peer->peer_in_lastmsg = -1;
+ }
/* Wait for them to wake us */
return msg_queue_wait(subd_conn, subd->outq,
@@ -1317,6 +1327,9 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn,
}
/* Wait for them to wake us */
+ peer->peer_in_lastmsg = type;
+ peer->peer_in_lasttime = time_mono();
+
return io_wait(peer_conn, &peer->peer_in, next_read, peer);
}
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.