Fix i32 overflow: peers offline 24.9-49.7 days wrongly reported online (#676)

`Duration::as_millis()` returns u128; casting it `as i32` in the
online-status and punch-hole checks keeps only the low 32 bits as a
signed integer. Once a peer has not registered for more than 2^31 ms
(~24.855 days), the value wraps negative and passes the
`elapsed < REG_TIMEOUT` test, so a long-offline peer is reported online
and connection attempts are relayed to its stale socket_addr. The
in-memory peer map is never evicted, so last_reg_time stays frozen until
hbbs restarts, making the false-online window 24.86-49.71 days (and it
repeats every ~49.71 days).

Widen REG_TIMEOUT and the two elapsed casts from i32 to i64 so the
comparison no longer overflows.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Luc Busquin
2026-07-06 19:14:03 -07:00
committed by GitHub
parent 80d3a50566
commit 91fb928c6e
+3 -3
View File
@@ -47,7 +47,7 @@ enum Data {
RelayServers(RelayServers), RelayServers(RelayServers),
} }
const REG_TIMEOUT: i32 = 30_000; const REG_TIMEOUT: i64 = 30_000;
type TcpStreamSink = SplitSink<Framed<TcpStream, BytesCodec>, Bytes>; type TcpStreamSink = SplitSink<Framed<TcpStream, BytesCodec>, Bytes>;
type WsSink = SplitSink<tokio_tungstenite::WebSocketStream<TcpStream>, tungstenite::Message>; type WsSink = SplitSink<tokio_tungstenite::WebSocketStream<TcpStream>, tungstenite::Message>;
enum Sink { enum Sink {
@@ -697,7 +697,7 @@ impl RendezvousServer {
if let Some(peer) = self.pm.get(&id).await { if let Some(peer) = self.pm.get(&id).await {
let (elapsed, peer_addr) = { let (elapsed, peer_addr) = {
let r = peer.read().await; let r = peer.read().await;
(r.last_reg_time.elapsed().as_millis() as i32, r.socket_addr) (r.last_reg_time.elapsed().as_millis() as i64, r.socket_addr)
}; };
if elapsed >= REG_TIMEOUT { if elapsed >= REG_TIMEOUT {
let mut msg_out = RendezvousMessage::new(); let mut msg_out = RendezvousMessage::new();
@@ -790,7 +790,7 @@ impl RendezvousServer {
let mut states = BytesMut::zeroed((peers.len() + 7) / 8); let mut states = BytesMut::zeroed((peers.len() + 7) / 8);
for (i, peer_id) in peers.iter().enumerate() { for (i, peer_id) in peers.iter().enumerate() {
if let Some(peer) = self.pm.get_in_memory(peer_id).await { if let Some(peer) = self.pm.get_in_memory(peer_id).await {
let elapsed = peer.read().await.last_reg_time.elapsed().as_millis() as i32; let elapsed = peer.read().await.last_reg_time.elapsed().as_millis() as i64;
// bytes index from left to right // bytes index from left to right
let states_idx = i / 8; let states_idx = i / 8;
let bit_idx = 7 - i % 8; let bit_idx = 7 - i % 8;