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.
This commit is contained in:
Chris authored and GitHub committed 2026-10-24 18:16:28 -05:00
1 parent 6d0f73e09b
commit 41cedb89d6
1 file changed
+14
+14
View File
@@ -888,6 +888,20 @@ static int ignoreDisconnectIntercept(ENetHost* host, ENetEvent* event) {
if (host->receivedDataLength == sizeof(ENetProtocolHeader) + sizeof(ENetProtocolDisconnect)) { if (host->receivedDataLength == sizeof(ENetProtocolHeader) + sizeof(ENetProtocolDisconnect)) {
ENetProtocolHeader* protoHeader = (ENetProtocolHeader*)host->receivedData; ENetProtocolHeader* protoHeader = (ENetProtocolHeader*)host->receivedData;
ENetProtocolDisconnect* disconnect = (ENetProtocolDisconnect*)(protoHeader + 1); 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) { if ((disconnect->header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) {
Limelog("ENet disconnect event pending\n"); Limelog("ENet disconnect event pending\n");