Properly handle Query packet errors

This commit is contained in:
Dylan K. Taylor 2019-01-17 22:22:53 +00:00
parent 38cf8d157d
commit 2dee7e9e0f
2 changed files with 56 additions and 46 deletions

View File

@ -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
}

View File

@ -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;
}
}
}