From 7231921b0bfce69255369a2bc7933d40cef3cbda Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Thu, 19 Nov 2020 10:58:23 +0200 Subject: [PATCH] Add 1200 byte padding to all requests https://steamcommunity.com/discussions/forum/14/2989789048633291344/ --- SourceQuery/BaseSocket.php | 1 + SourceQuery/Socket.php | 20 ++++++++++++++++++++ SourceQuery/SourceQuery.php | 13 ++++++++----- Tests/Tests.php | 5 +++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/SourceQuery/BaseSocket.php b/SourceQuery/BaseSocket.php index 33fa9c4..462d235 100644 --- a/SourceQuery/BaseSocket.php +++ b/SourceQuery/BaseSocket.php @@ -41,6 +41,7 @@ abstract public function Close( ) : void; abstract public function Open( string $Address, int $Port, int $Timeout, int $Engine ) : void; abstract public function Write( int $Header, string $String = '' ) : bool; + abstract public function WritePadded( int $Header, string $String = '' ) : bool; abstract public function Read( int $Length = 1400 ) : Buffer; protected function ReadInternal( Buffer $Buffer, int $Length, callable $SherlockFunction ) : Buffer diff --git a/SourceQuery/Socket.php b/SourceQuery/Socket.php index 4f5cf9f..51c9851 100644 --- a/SourceQuery/Socket.php +++ b/SourceQuery/Socket.php @@ -61,6 +61,26 @@ return $Length === FWrite( $this->Socket, $Command, $Length ); } + /** + * Write a request packge to the socket. Pads it up to 1200 bytes to prevent reflective DoS. + * + * @see https://steamcommunity.com/discussions/forum/14/2989789048633291344/ + * @return bool Whether fwrite succeeded. + */ + public function WritePadded( int $Header, string $String = '' ) : bool + { + $Command = pack( 'ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String ); + $Length = strlen( $Command ); + + if( $Length < 1200 ) + { + $Command .= str_repeat( "\0", 1200 - $Length ); + $Length = 1200; + } + + return $Length === fwrite( $this->Socket, $Command, $Length ); + } + /** * Reads from socket and returns Buffer. * diff --git a/SourceQuery/SourceQuery.php b/SourceQuery/SourceQuery.php index ecc9757..3dda7ee 100644 --- a/SourceQuery/SourceQuery.php +++ b/SourceQuery/SourceQuery.php @@ -200,7 +200,7 @@ throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED ); } - $this->Socket->Write( self::A2S_INFO, "Source Engine Query\0" ); + $this->Socket->WritePadded( self::A2S_INFO, "Source Engine Query\0" ); $Buffer = $this->Socket->Read( ); $Type = $Buffer->GetByte( ); @@ -365,7 +365,7 @@ $this->GetChallenge( self::A2S_PLAYER, self::S2A_PLAYER ); - $this->Socket->Write( self::A2S_PLAYER, $this->Challenge ); + $this->Socket->WritePadded( self::A2S_PLAYER, $this->Challenge ); $Buffer = $this->Socket->Read( 14000 ); // Moronic Arma 3 developers do not split their packets, so we have to read more data // This violates the protocol spec, and they probably should fix it: https://developer.valvesoftware.com/wiki/Server_queries#Protocol @@ -411,7 +411,7 @@ $this->GetChallenge( self::A2S_RULES, self::S2A_RULES ); - $this->Socket->Write( self::A2S_RULES, $this->Challenge ); + $this->Socket->WritePadded( self::A2S_RULES, $this->Challenge ); $Buffer = $this->Socket->Read( ); $Type = $Buffer->GetByte( ); @@ -452,10 +452,13 @@ if( $this->UseOldGetChallengeMethod ) { - $Header = self::A2S_SERVERQUERY_GETCHALLENGE; + $this->Socket->Write( self::A2S_SERVERQUERY_GETCHALLENGE, "\xFF\xFF\xFF\xFF" ); + } + else + { + $this->Socket->WritePadded( $Header, "\xFF\xFF\xFF\xFF" ); } - $this->Socket->Write( $Header, "\xFF\xFF\xFF\xFF" ); $Buffer = $this->Socket->Read( ); $Type = $Buffer->GetByte( ); diff --git a/Tests/Tests.php b/Tests/Tests.php index dc0ebda..ec79583 100644 --- a/Tests/Tests.php +++ b/Tests/Tests.php @@ -38,6 +38,11 @@ return true; } + public function WritePadded( int $Header, string $String = '' ) : bool + { + return true; + } + public function Read( int $Length = 1400 ) : Buffer { $Buffer = new Buffer( );