diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 4fdcaf089..e96250cfe 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -2118,16 +2118,8 @@ class Server{ * TODO: move this to Network */ public function handlePacket(AdvancedNetworkInterface $interface, string $address, int $port, string $payload){ - try{ - if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){ - $this->queryHandler->handle($interface, $address, $port, $payload); - }else{ - $this->logger->debug("Unhandled raw packet from $address $port: " . bin2hex($payload)); - } - }catch(\Throwable $e){ - $this->logger->logException($e); - - $this->getNetwork()->blockAddress($address, 600); + if($this->queryHandler === null or !$this->queryHandler->handle($interface, $address, $port, $payload)){ + $this->logger->debug("Unhandled raw packet from $address $port: " . bin2hex($payload)); } //TODO: add raw packet events } diff --git a/src/pocketmine/network/query/QueryHandler.php b/src/pocketmine/network/query/QueryHandler.php index 541f95e0b..feb7928c0 100644 --- a/src/pocketmine/network/query/QueryHandler.php +++ b/src/pocketmine/network/query/QueryHandler.php @@ -30,11 +30,11 @@ namespace pocketmine\network\query; use pocketmine\network\AdvancedNetworkInterface; use pocketmine\Server; use pocketmine\utils\Binary; -use function bin2hex; +use pocketmine\utils\BinaryDataException; +use pocketmine\utils\BinaryStream; use function chr; use function hash; use function microtime; -use function ord; use function random_bytes; use function strlen; use function substr; @@ -88,44 +88,62 @@ class QueryHandler{ return Binary::readInt(substr(hash("sha512", $salt . ":" . $token, true), 7, 4)); } - public function handle(AdvancedNetworkInterface $interface, string $address, int $port, string $packet) : void{ - $offset = 2; - $packetType = ord($packet{$offset++}); - $sessionID = Binary::readInt(substr($packet, $offset, 4)); - $offset += 4; - $payload = substr($packet, $offset); + /** + * @param AdvancedNetworkInterface $interface + * @param string $address + * @param int $port + * @param string $packet + * + * @return bool + */ + public function handle(AdvancedNetworkInterface $interface, string $address, int $port, string $packet) : bool{ + try{ + $stream = new BinaryStream($packet); + $header = $stream->get(2); + if($header !== "\xfe\xfd"){ //TODO: have this filtered by the regex filter we installed above + return false; + } + $packetType = $stream->getByte(); + $sessionID = $stream->getInt(); - switch($packetType){ - case self::HANDSHAKE: //Handshake - $reply = chr(self::HANDSHAKE); - $reply .= Binary::writeInt($sessionID); - $reply .= self::getTokenString($this->token, $address) . "\x00"; + switch($packetType){ + case self::HANDSHAKE: //Handshake + $reply = chr(self::HANDSHAKE); + $reply .= Binary::writeInt($sessionID); + $reply .= self::getTokenString($this->token, $address) . "\x00"; - $interface->sendRawPacket($address, $port, $reply); - break; - case self::STATISTICS: //Stat - $token = Binary::readInt(substr($payload, 0, 4)); - if($token !== ($t1 = self::getTokenString($this->token, $address)) and $token !== ($t2 = self::getTokenString($this->lastToken, $address))){ - $this->debug("Bad token $token from $address $port, expected $t1 or $t2"); - break; - } - $reply = chr(self::STATISTICS); - $reply .= Binary::writeInt($sessionID); + $interface->sendRawPacket($address, $port, $reply); - if($this->timeout < microtime(true)){ - $this->regenerateInfo(); - } + return true; + case self::STATISTICS: //Stat + $token = $stream->getInt(); + if($token !== ($t1 = self::getTokenString($this->token, $address)) and $token !== ($t2 = self::getTokenString($this->lastToken, $address))){ + $this->debug("Bad token $token from $address $port, expected $t1 or $t2"); - if(strlen($payload) === 8){ - $reply .= $this->longData; - }else{ - $reply .= $this->shortData; - } - $interface->sendRawPacket($address, $port, $reply); - break; - default: - $this->debug("Unhandled packet from $address $port: 0x" . bin2hex($packet)); - break; + return true; + } + $reply = chr(self::STATISTICS); + $reply .= Binary::writeInt($sessionID); + + if($this->timeout < microtime(true)){ + $this->regenerateInfo(); + } + + $remaining = $stream->getRemaining(); + if(strlen($remaining) === 4){ //TODO: check this! according to the spec, this should always be here and always be FF FF FF 01 + $reply .= $this->longData; + }else{ + $reply .= $this->shortData; + } + $interface->sendRawPacket($address, $port, $reply); + + return true; + default: + return false; + } + }catch(BinaryDataException $e){ + $this->debug("Bad packet from $address $port: " . $e->getMessage()); + return false; } } }