22declare(strict_types=1);
38use
function random_bytes;
43 private string $lastToken;
44 private string $token;
46 private \Logger $logger;
48 public const HANDSHAKE = 9;
49 public const STATISTICS = 0;
51 public function __construct(
54 $this->logger = new \PrefixedLogger($this->
server->getLogger(),
"Query Handler");
65 $this->token = $this->generateToken();
66 $this->lastToken = $this->token;
70 return
'/^\xfe\xfd.+$/s';
73 private function generateToken() : string{
74 return random_bytes(16);
77 public function regenerateToken() : void{
78 $this->lastToken = $this->token;
79 $this->token = $this->generateToken();
82 public static function getTokenString(
string $token,
string $salt) : int{
83 return Binary::readInt(substr(hash(
"sha512", $salt .
":" . $token, true), 7, 4));
89 $header = $stream->
get(2);
90 if($header !==
"\xfe\xfd"){
93 $packetType = $stream->getByte();
94 $sessionID = $stream->getInt();
98 $reply = chr(self::HANDSHAKE);
99 $reply .= Binary::writeInt($sessionID);
100 $reply .= self::getTokenString($this->token, $address) .
"\x00";
105 case self::STATISTICS:
106 $token = $stream->getInt();
107 if($token !== ($t1 = self::getTokenString($this->token, $address)) && $token !== ($t2 = self::getTokenString($this->lastToken, $address))){
108 $this->logger->debug(
"Bad token $token from $address $port, expected $t1 or $t2");
112 $reply = chr(self::STATISTICS);
113 $reply .= Binary::writeInt($sessionID);
115 $remaining = $stream->getRemaining();
116 if(strlen($remaining) === 4){
117 $reply .= $this->
server->getQueryInformation()->getLongQuery();
119 $reply .= $this->
server->getQueryInformation()->getShortQuery();
127 }
catch(BinaryDataException $e){
128 $this->logger->debug(
"Bad packet from $address $port: " . $e->getMessage());
handle(AdvancedNetworkInterface $interface, string $address, int $port, string $packet)
sendRawPacket(string $address, int $port, string $payload)