Fix websocket service disconnect on invalid handshake (#7447)

This commit is contained in:
frytimo
2025-08-05 12:05:48 -03:00
committed by GitHub
parent 0157a58639
commit dc56886d41
4 changed files with 57 additions and 12 deletions

View File

@@ -0,0 +1,38 @@
<?php
/*
* FusionPBX
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FusionPBX
*
* The Initial Developer of the Original Code is
* Mark J Crane <markjcrane@fusionpbx.com>
* Portions created by the Initial Developer are Copyright (C) 2008-2025
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark J Crane <markjcrane@fusionpbx.com>
* Tim Fry <tim@fusionpbx.com>
*/
/**
* Description of invalid_handshake_exception
*
* @author Tim Fry <tim@fusionpbx.com>
*/
class invalid_handshake_exception extends \socket_exception {
public function __construct($id = null, string $message = "Invalid handshake", int $code = 0, ?\Throwable $previous = null) {
return parent::__construct($id, $message, $code, $previous);
}
}

View File

@@ -37,5 +37,5 @@ class socket_exception extends \Exception {
$this->id = $id;
return parent::__construct($message, $code, $previous);
}
public function getResourceId() { return $this->resource_id; }
public function getResourceId() { return $this->id; }
}

View File

@@ -345,7 +345,7 @@ class websocket_server {
}
}
if (!preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $request_header, $matches)) {
throw new \RuntimeException("Invalid WebSocket handshake");
throw new \invalid_handshake_exception($socket, "Invalid WebSocket handshake");
}
$key = trim($matches[1]);
$accept_key = base64_encode(

View File

@@ -528,15 +528,22 @@ class websocket_service extends service {
if ($client_socket === $this->server_socket) {
$conn = @stream_socket_accept($this->server_socket, 0);
if ($conn) {
// complete handshake on blocking socket
stream_set_blocking($conn, true);
$this->handshake($conn);
// switch to non-blocking for further reads
stream_set_blocking($conn, false);
// add them to the websocket list
$this->clients[] = $conn;
// notify websocket on_connect listeners
$this->trigger_connect($conn);
try {
// complete handshake on blocking socket
stream_set_blocking($conn, true);
$this->handshake($conn);
// switch to non-blocking for further reads
stream_set_blocking($conn, false);
// add them to the websocket list
$this->clients[] = $conn;
// notify websocket on_connect listeners
$this->trigger_connect($conn);
} catch (invalid_handshake_exception $ex) {
$resource = $ex->getResourceId();
$this->warning('Invalid handshake from resource ' . $resource);
$this->disconnect_client($resource);
$this->warning('Disconnected resource ' . $resource);
}
continue;
}
}
@@ -756,7 +763,7 @@ class websocket_service extends service {
}
}
if (!preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $request_header, $matches)) {
throw new \RuntimeException("Invalid WebSocket handshake");
throw new invalid_handshake_exception($resource, "Invalid WebSocket handshake");
}
$key = trim($matches[1]);
$accept_key = base64_encode(