From 41cedb89d6b8592f99c09975c764ca3875034726 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 24 Oct 2026 18:16:28 -0500 Subject: [PATCH] Only intercept ENet disconnects addressed to our peer (#162) ignoreDisconnectIntercept() runs on every datagram the control stream socket receives, before ENet has validated the packet. It only checked the length and command, so any 12-byte DISCONNECT from any source set disconnectPending, which tears down the session about a second later. Check that the header's peer ID and session ID match our peer and that the packet came from the peer's current address before acting on it. Anything else is passed to ENet unchanged, so a genuine disconnect that does not match (for example from another address of a multi-homed host) is still handled, just without the grace period. --- src/ControlStream.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ControlStream.c b/src/ControlStream.c index 2dfb898..b5e79e6 100644 --- a/src/ControlStream.c +++ b/src/ControlStream.c @@ -888,6 +888,20 @@ static int ignoreDisconnectIntercept(ENetHost* host, ENetEvent* event) { if (host->receivedDataLength == sizeof(ENetProtocolHeader) + sizeof(ENetProtocolDisconnect)) { ENetProtocolHeader* protoHeader = (ENetProtocolHeader*)host->receivedData; ENetProtocolDisconnect* disconnect = (ENetProtocolDisconnect*)(protoHeader + 1); + enet_uint16 peerID = ENET_NET_TO_HOST_16(protoHeader->peerID); + enet_uint8 sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; + + peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + + // This runs before ENet validates the packet at all, so only act on disconnects + // that are addressed to our peer and come from the address we're talking to. + // Anything else is left for ENet's own processing. + if (peer == NULL || + peerID != peer->incomingPeerID || + sessionID != peer->incomingSessionID || + !enet_address_equal(&host->receivedPeerAddress, &peer->address)) { + return 0; + } if ((disconnect->header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) { Limelog("ENet disconnect event pending\n");