Skip to content

Commit

Permalink
CVars for Secure RCon
Browse files Browse the repository at this point in the history
  • Loading branch information
mbasaglia committed Nov 13, 2015
1 parent 6fe5601 commit 1c11a0a
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 107 deletions.
2 changes: 2 additions & 0 deletions daemon/src.cmake
Expand Up @@ -137,6 +137,8 @@ set(SERVERLIST
${ENGINE_DIR}/server/sv_snapshot.cpp ${ENGINE_DIR}/server/sv_snapshot.cpp
${ENGINE_DIR}/server/Crypto.cpp ${ENGINE_DIR}/server/Crypto.cpp
${ENGINE_DIR}/server/Crypto.h ${ENGINE_DIR}/server/Crypto.h
${ENGINE_DIR}/server/CryptoChallenge.cpp
${ENGINE_DIR}/server/CryptoChallenge.h
) )


set(ENGINELIST set(ENGINELIST
Expand Down
140 changes: 140 additions & 0 deletions daemon/src/engine/server/CryptoChallenge.cpp
@@ -0,0 +1,140 @@
/*
===========================================================================
Daemon BSD Source Code
Copyright (c) 2015, Daemon Developers
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Daemon developers nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===========================================================================
*/

#include "CryptoChallenge.h"

static Cvar::Cvar<int> cvar_server_challenge_timeout(
"server.rcon.challenge.timeout",
"Timeout (in seconds) of a rcon challenge",
Cvar::NONE,
5
);

static Cvar::Cvar<int> cvar_server_challenge_length(
"server.rcon.challenge.length",
"Length in bytes of the challenge data (The hexadecimal representation will be twice as long",
Cvar::NONE,
8
);

static Cvar::Cvar<int> cvar_server_challenge_count(
"server.rcon.challenge.count",
"Maximum number of active challenges kept in memory",
Cvar::NONE,
1024
);

Challenge::Duration Challenge::Timeout()
{
return std::chrono::duration_cast<Duration>( std::chrono::seconds(
cvar_server_challenge_timeout.Get()
) );
}

std::size_t Challenge::Bytes()
{
return cvar_server_challenge_length.Get();
}


std::string Challenge::GenerateString()
{
std::vector<uint8_t> data( Bytes() );
Sys::GenRandomBytes(data.data(), data.size());
std::ostringstream stream;
stream.setf(std::ios::hex, std::ios::basefield);
stream.fill('0');
for ( auto ch : data )
{
stream.width(2);
stream << int( ch );
}
return stream.str();
}


std::size_t ChallengeManager::MaxChallenges() const
{
return cvar_server_challenge_count.Get();
}

std::string ChallengeManager::GenerateChallenge( const netadr_t& source )
{
auto challenge = Challenge( source );
Push( challenge );
return challenge.String();
}

void ChallengeManager::Push( const Challenge& challenge )
{
auto lock = Lock();

Cleanup();

if ( challenges.size() >= MaxChallenges() )
{
challenges.pop_front();
}

challenges.push_back( challenge );
}

bool ChallengeManager::Match( const Challenge& challenge )
{
auto lock = Lock();

Cleanup();

auto it = std::find_if( challenges.begin(), challenges.end(),
[&challenge]( const Challenge& ch ) {
return ch.Matches( challenge );
} );

if ( it != challenges.end() )
{
challenges.erase( it );
return true;
}

return false;
}

void ChallengeManager::Cleanup()
{
auto now = Challenge::Clock::now();
challenges.erase(
std::remove_if( challenges.begin(), challenges.end(),
[&now]( const Challenge& challenge ) {
return !challenge.ValidAt( now );
}
),
challenges.end()
);
}
Expand Up @@ -44,20 +44,12 @@ class Challenge
/* /*
* Time duration a challenge will be valid for * Time duration a challenge will be valid for
*/ */
static Duration Timeout() static Duration Timeout();
{
// TODO Read this from a cvar
return std::chrono::duration_cast<Duration>( std::chrono::seconds( 5 ) );
}


/* /*
* Size of the raw challenge data * Size of the raw challenge data
*/ */
static std::size_t Bytes() static std::size_t Bytes();
{
// TODO Read this from a cvar
return 8;
}


Challenge( const netadr_t& source, const Crypto::Data& challenge ) Challenge( const netadr_t& source, const Crypto::Data& challenge )
: valid_until( Clock::now() + Timeout() ), : valid_until( Clock::now() + Timeout() ),
Expand Down Expand Up @@ -112,20 +104,7 @@ class Challenge
/* /*
* Generates a random challenge * Generates a random challenge
*/ */
std::string GenerateString() std::string GenerateString();
{
std::vector<uint8_t> data( Bytes() );
Sys::GenRandomBytes(data.data(), data.size());
std::ostringstream stream;
stream.setf(std::ios::hex, std::ios::basefield);
stream.fill('0');
for ( auto ch : data )
{
stream.width(2);
stream << int( ch );
}
return stream.str();
}


TimePoint valid_until; TimePoint valid_until;
Crypto::Data challenge; Crypto::Data challenge;
Expand All @@ -142,62 +121,23 @@ class ChallengeManager
return singleton; return singleton;
} }


std::size_t MaxChallenges() const std::size_t MaxChallenges() const;
{
// TODO Read this from a cvar
return 1024;
}


/* /*
* Generates a challenge for the given address and returns the challenge string * Generates a challenge for the given address and returns the challenge string
*/ */
std::string GenerateChallenge( const netadr_t& source ) std::string GenerateChallenge( const netadr_t& source );
{
auto challenge = Challenge( source );
Push( challenge );
return challenge.String();
}


/* /*
* Add a challenge to the pool * Add a challenge to the pool
*/ */
void Push( const Challenge& challenge ) void Push( const Challenge& challenge );
{
auto lock = Lock();

Cleanup();

if ( challenges.size() >= MaxChallenges() )
{
challenges.pop_front();
}

challenges.push_back( challenge );
}


/* /*
* Check if a challenge matches any of the registered ones * Check if a challenge matches any of the registered ones
* If it does and it's valid, it'll return false * If it does and it's valid, it'll return false
*/ */
bool Match( const Challenge& challenge ) bool Match( const Challenge& challenge );
{
auto lock = Lock();

Cleanup();

auto it = std::find_if( challenges.begin(), challenges.end(),
[&challenge]( const Challenge& ch ) {
return ch.Matches( challenge );
} );

if ( it != challenges.end() )
{
challenges.erase( it );
return true;
}

return false;
}


private: private:
ChallengeManager() = default; ChallengeManager() = default;
Expand All @@ -213,18 +153,7 @@ class ChallengeManager
* Removes outdated challenges * Removes outdated challenges
* PRE: The caller has acquired a lock on mutex * PRE: The caller has acquired a lock on mutex
*/ */
void Cleanup() void Cleanup();
{
auto now = Challenge::Clock::now();
challenges.erase(
std::remove_if( challenges.begin(), challenges.end(),
[&now]( const Challenge& challenge ) {
return !challenge.ValidAt( now );
}
),
challenges.end()
);
}


std::mutex mutex; std::mutex mutex;
std::deque<Challenge> challenges; std::deque<Challenge> challenges;
Expand Down
1 change: 0 additions & 1 deletion daemon/src/engine/server/server.h
Expand Up @@ -346,7 +346,6 @@ extern GameVM gvm; // game virtual machine
extern cvar_t *sv_fps; extern cvar_t *sv_fps;
extern cvar_t *sv_timeout; extern cvar_t *sv_timeout;
extern cvar_t *sv_zombietime; extern cvar_t *sv_zombietime;
extern cvar_t *sv_rconPassword;
extern cvar_t *sv_privatePassword; extern cvar_t *sv_privatePassword;
extern cvar_t *sv_allowDownload; extern cvar_t *sv_allowDownload;
extern cvar_t *sv_maxclients; extern cvar_t *sv_maxclients;
Expand Down
2 changes: 1 addition & 1 deletion daemon/src/engine/server/sv_client.cpp
Expand Up @@ -35,7 +35,7 @@ Maryland 20850 USA.
// sv_client.c -- server code for dealing with clients // sv_client.c -- server code for dealing with clients


#include "server.h" #include "server.h"
#include "CryptoChallege.h" #include "CryptoChallenge.h"


static void SV_CloseDownload( client_t *cl ); static void SV_CloseDownload( client_t *cl );


Expand Down
1 change: 0 additions & 1 deletion daemon/src/engine/server/sv_init.cpp
Expand Up @@ -667,7 +667,6 @@ void SV_Init()
Cvar_Get( "sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get( "sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );


// server vars // server vars
sv_rconPassword = Cvar_Get( "rconPassword", "", CVAR_TEMP );
sv_privatePassword = Cvar_Get( "sv_privatePassword", "", CVAR_TEMP ); sv_privatePassword = Cvar_Get( "sv_privatePassword", "", CVAR_TEMP );
sv_fps = Cvar_Get( "sv_fps", "40", CVAR_TEMP ); sv_fps = Cvar_Get( "sv_fps", "40", CVAR_TEMP );
sv_timeout = Cvar_Get( "sv_timeout", "240", CVAR_TEMP ); sv_timeout = Cvar_Get( "sv_timeout", "240", CVAR_TEMP );
Expand Down

0 comments on commit 1c11a0a

Please sign in to comment.