2019-09-02 10:28:14 +00:00
# include "StdAfx.h"
# include "Profiler.h"
# include "NodeRelay.h"
# include "GateRelay.h"
# include "ConnectorBridge.h"
# include "DeviceBridge.h"
2020-03-05 15:30:50 +00:00
# include "Common/FSecure/CppTools/Utils.h"
2019-09-02 10:28:14 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
std : : mutex FSecure : : C3 : : Core : : Profiler : : Profile : : m_Mutex ;
2019-09-02 10:28:14 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Profiler ( std : : filesystem : : path snapshotPath ) : m_SnapshotPath ( std : : move ( snapshotPath ) )
2019-09-02 10:28:14 +00:00
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Initialize ( std : : string name , std : : shared_ptr < GateRelay > gateway )
2019-09-02 10:28:14 +00:00
{
m_Gateway = Gateway { shared_from_this ( ) , name , gateway } ;
for ( auto & & e : m_Gateway - > m_Gateway . lock ( ) - > m_InterfaceFactory . GetMap < AbstractPeripheral > ( ) )
m_BindersMappings . emplace_back ( e . first , e . second . m_ClousureConnectorHash ) ;
RestoreFromSnapshot ( ) ;
std : : thread ( & Profiler : : DumpSnapshots , this ) . detach ( ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : HandleActionsPacket ( ByteView actionsPacket )
2019-09-02 10:28:14 +00:00
{
std : : scoped_lock lock ( m_AccessMutex ) ;
try
{
auto actions = json : : parse ( std : : string { actionsPacket } ) ;
auto jActions = actions . find ( " Command " ) ;
if ( jActions = = actions . end ( ) )
throw std : : runtime_error { " Command object is missing " } ;
( * jActions ) [ " ByteForm " ] = base64 : : encode ( TranslateCommand ( * jActions ) ) ;
// Helper lambda that read particular element from actions JSON.
auto ReadJsonElement = [ & actions ] ( std : : string_view elementName )
{
auto element = actions . find ( elementName ) ;
if ( element ! = actions . end ( ) )
return element ;
throw std : : runtime_error { std : : string { elementName } + " is not specified. " } ;
} ;
// Parse AgentId.
if ( auto relayAgentId = ReadJsonElement ( " relayAgentId " ) ; relayAgentId - > is_null ( ) )
m_Gateway - > ParseAndRunCommand ( actions ) ;
else if ( auto agent = m_Gateway - > m_Agents . Find ( relayAgentId - > get < std : : string > ( ) ) )
agent - > ParseAndRunCommand ( actions ) ;
else
throw std : : runtime_error { " Unknown AgentId. " } ;
}
catch ( std : : exception & exception )
{
2019-11-15 14:38:18 +00:00
if ( auto gateway = m_Gateway - > m_Gateway . lock ( ) )
2020-03-05 15:30:50 +00:00
gateway - > Log ( { " Caught an exception while parsing Action. " s + exception . what ( ) , FSecure : : C3 : : LogMessage : : Severity : : Error } ) ;
2019-09-02 10:28:14 +00:00
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Profile FSecure : : C3 : : Core : : Profiler : : Get ( )
2019-09-02 10:28:14 +00:00
{
return Profile { * m_Gateway } ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
uint32_t FSecure : : C3 : : Core : : Profiler : : GetBinderTo ( uint32_t id )
2019-09-02 10:28:14 +00:00
{
for ( auto & & e : m_BindersMappings )
if ( e . first = = id )
return e . second ;
else if ( e . second = = id )
return e . first ;
return 0u ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : ByteVector FSecure : : C3 : : Core : : Profiler : : TranslateCommand ( json const & command )
2019-09-02 10:28:14 +00:00
{
2019-11-21 10:33:30 +00:00
return ByteVector : : Create ( command . at ( " id " ) . get < uint16_t > ( ) ) . Concat ( TranslateArguments ( command . at ( " arguments " ) ) ) ;
2019-09-02 10:28:14 +00:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : ByteVector FSecure : : C3 : : Core : : Profiler : : TranslateArguments ( json const & arguments )
2019-09-02 10:28:14 +00:00
{
ByteVector ret ;
auto translate = [ & ret ] ( auto arg ) { ret . Concat ( Translate ( arg . at ( " type " ) , arg . at ( " value " ) ) ) ; } ;
for ( auto argument : arguments )
{
if ( ! argument . is_array ( ) )
translate ( argument ) ;
else
2019-08-29 09:59:54 +00:00
for ( auto const subargument : argument )
2019-09-02 10:28:14 +00:00
translate ( subargument ) ;
}
return ret ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : ByteVector FSecure : : C3 : : Core : : Profiler : : TranslateStartupCommand ( json const & jcommand )
2019-09-02 10:28:14 +00:00
{
auto commandId = jcommand . at ( " id " ) . get < std : : uint16_t > ( ) ;
auto const & createCommands = m_Gateway - > m_CreateCommands ;
auto command = std : : find_if ( createCommands . cbegin ( ) , createCommands . cend ( ) , [ commandId ] ( Gateway : : CreateCommand const & cc ) { return cc . m_IsDevice & & cc . m_Id = = commandId ; } ) ;
// this function will only support create commands
if ( command = = createCommands . cend ( ) | | ! command - > m_IsDevice )
throw std : : logic_error { " Failed to find a create command " } ;
2019-11-21 10:33:30 +00:00
return ByteVector : : Create ( command - > m_IsNegotiableChannel , command - > m_Hash ) . Concat ( TranslateArguments ( jcommand . at ( " arguments " ) ) ) ;
2019-09-02 10:28:14 +00:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : ByteVector FSecure : : C3 : : Core : : Profiler : : Translate ( std : : string const & type , json : : value_type const & value )
2019-09-02 10:28:14 +00:00
{
if ( type = = " uint8 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < uint8_t > ( std : : stoull ( value . get < std : : string > ( ) ) ) : value . get < uint8_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " uint16 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < uint16_t > ( std : : stoull ( value . get < std : : string > ( ) ) ) : value . get < uint16_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " uint32 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < uint32_t > ( std : : stoull ( value . get < std : : string > ( ) ) ) : value . get < uint32_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " uint64 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < uint64_t > ( std : : stoull ( value . get < std : : string > ( ) ) ) : value . get < uint64_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " int8 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < int8_t > ( std : : stoll ( value . get < std : : string > ( ) ) ) : value . get < int8_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " int16 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < int16_t > ( std : : stoll ( value . get < std : : string > ( ) ) ) : value . get < int16_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " int32 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < int32_t > ( std : : stoll ( value . get < std : : string > ( ) ) ) : value . get < int32_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " int64 " )
2020-03-05 15:30:50 +00:00
return ByteVector { } . Write ( value . is_string ( ) ? FSecure : : Utils : : SafeCast < int64_t > ( std : : stoll ( value . get < std : : string > ( ) ) ) : value . get < int64_t > ( ) ) ;
2019-09-02 10:28:14 +00:00
if ( type = = " float " )
return ByteVector { } . Write ( value . is_string ( ) ? std : : stof ( value . get < std : : string > ( ) ) : value . get < float > ( ) ) ;
if ( type = = " boolean " )
return ByteVector { } . Write ( value . get < bool > ( ) ) ;
if ( type = = " string " | | type = = " ip " )
return ByteVector { } . Write ( value . get < std : : string > ( ) ) ;
if ( type = = " binary " )
return ByteVector { } . Write ( base64 : : decode < ByteVector > ( value . get < std : : string > ( ) ) ) ;
throw std : : invalid_argument { " Unrecognized argument type: " + type } ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : DumpSnapshots ( )
2019-09-02 10:28:14 +00:00
{
2019-11-14 16:49:30 +00:00
auto sp = GetSnapshotProxy ( ) ;
2019-09-02 10:28:14 +00:00
while ( true )
{
2019-11-25 12:29:20 +00:00
if ( sp . CheckUpdates ( ) )
2019-09-02 10:28:14 +00:00
{
2019-11-14 16:49:30 +00:00
const auto snapshotTmpPath = std : : filesystem : : path ( m_SnapshotPath ) . replace_extension ( " .tmp " ) ;
2019-09-02 10:28:14 +00:00
{
std : : ofstream snapshotTmp { snapshotTmpPath } ;
2019-11-25 12:29:20 +00:00
snapshotTmp < < sp . GetSnapshot ( ) . dump ( ) < < std : : endl ;
2019-09-02 10:28:14 +00:00
}
std : : filesystem : : rename ( snapshotTmpPath , m_SnapshotPath ) ;
}
std : : this_thread : : sleep_for ( 1 s ) ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : RestoreFromSnapshot ( )
2019-09-02 10:28:14 +00:00
{
json snapshot ;
// get snapshot
{
auto ifile = std : : ifstream { m_SnapshotPath } ;
auto str = std : : string ( ( std : : istreambuf_iterator < char > ( ifile ) ) , std : : istreambuf_iterator < char > ( ) ) ;
if ( str . empty ( ) )
return ;
snapshot = json : : parse ( str ) ;
}
// restore gateway.
{
for ( auto & & b : snapshot [ " _RegisteredBuilds " ] )
{
m_Gateway - > AddAgentBuild
(
b . at ( " _bid " ) . get < BuildId : : UnderlyingIntegerType > ( ) ,
BuildProperties
{
b . at ( " _x64 " ) . get < bool > ( ) ,
b . at ( " _ban " ) . get < bool > ( ) ,
b . at ( " _startCmd " ) ,
}
) ;
}
for ( auto & & channel : snapshot [ " channels " ] )
{
auto gateRelay = Get ( ) . m_Gateway . m_Gateway . lock ( ) ;
if ( ! gateRelay )
throw std : : logic_error ( " Parent GateRelay cannot be locked " ) ;
auto byteForm = base64 : : decode < ByteVector > ( channel [ " startupCommand " ] [ " ByteForm " ] . get < std : : string > ( ) ) ;
auto readView = ByteView { byteForm } ;
readView . remove_prefix ( sizeof ( uint16_t ) ) ; // remove number of command
auto did = DeviceId { channel [ " iId " ] . get < std : : string > ( ) } ;
auto device = gateRelay - > CreateAndAttachDevice
(
did ,
channel [ " type " ] . get < HashT > ( ) ,
channel [ " isNegotiationChannel " ] . get < bool > ( ) ,
readView
) ;
2020-03-05 15:30:50 +00:00
auto jitter = std : : pair { FSecure : : Utils : : ToMilliseconds ( channel [ " jitter " ] [ 0 ] . get < float > ( ) ) , FSecure : : Utils : : ToMilliseconds ( channel [ " jitter " ] [ 1 ] . get < float > ( ) ) } ;
2019-09-12 15:18:43 +00:00
device - > SetUpdateDelay ( jitter . first , jitter . second ) ;
2019-09-02 10:28:14 +00:00
auto profile = Get ( ) ; // we need to take profile each time, as it is also taken in CreateAndAttachDevice and that would lead to deadlock.
auto channelProfile = profile . m_Gateway . m_Channels . Find ( did ) ;
channelProfile - > m_StartupArguments = channel [ " startupCommand " ] ;
channelProfile - > m_Jitter = jitter ;
}
for ( auto & & connector : snapshot [ " connectors " ] )
{
auto gateRelay = Get ( ) . m_Gateway . m_Gateway . lock ( ) ;
if ( ! gateRelay )
throw std : : logic_error ( " Parent GateRelay cannot be locked " ) ;
auto byteForm = base64 : : decode < ByteVector > ( connector [ " startupCommand " ] [ " ByteForm " ] . get < std : : string > ( ) ) ;
auto readView = ByteView { byteForm } ;
readView . remove_prefix ( sizeof ( uint16_t ) ) ; // remove number of command
auto did = connector [ " type " ] . get < HashT > ( ) ;
gateRelay - > TurnOnConnector
(
did ,
readView
) ;
auto profile = Get ( ) ; // we need to take profile each time, as it is also taken in CreateAndAttachDevice and that would lead to deadlock.
auto connectorProfile = profile . m_Gateway . m_Connectors . Find ( did ) ;
connectorProfile - > m_StartupArguments = connector [ " startupCommand " ] ;
} ;
}
// restore agents
{
auto profile = Get ( ) ;
for ( auto & & route : snapshot [ " routes " ] )
profile . m_Gateway . ReAddRoute ( RouteId ( route [ " destinationAgent " ] . get < std : : string > ( ) , route [ " receivingInterface " ] . get < std : : string > ( ) ) , route [ " outgoingInterface " ] . get < std : : string > ( ) , route [ " isNeighbour " ] . get < bool > ( ) ) ;
for ( auto & & relay : snapshot [ " relays " ] )
{
auto agent = profile . m_Gateway . ReAddAgent
(
relay [ " agentId " ] . get < std : : string > ( ) ,
relay [ " buildId " ] . get < std : : string > ( ) ,
base64 : : decode < ByteVector > ( relay [ " publicKey " ] . get < std : : string > ( ) ) ,
false ,
relay [ " timestamp " ] . get < int32_t > ( ) ,
HostInfo ( relay [ " hostInfo " ] )
) ;
agent - > m_LastDeviceId = relay [ " _LastDeviceId " ] . get < DeviceId : : UnderlyingIntegerType > ( ) ;
for ( auto & & channel : relay [ " channels " ] )
{
auto device = agent - > ReAddChannel ( channel [ " iId " ] . get < std : : string > ( ) , channel [ " type " ] . get < HashT > ( ) , channel [ " isReturnChannel " ] . get < bool > ( ) , channel [ " isNegotiationChannel " ] . get < bool > ( ) ) ;
device - > m_StartupArguments = channel [ " startupCommand " ] ;
2020-03-05 15:30:50 +00:00
device - > m_Jitter = std : : pair { FSecure : : Utils : : ToMilliseconds ( channel [ " jitter " ] [ 0 ] . get < float > ( ) ) , FSecure : : Utils : : ToMilliseconds ( channel [ " jitter " ] [ 1 ] . get < float > ( ) ) } ;
2019-09-02 10:28:14 +00:00
}
for ( auto & & peripheral : relay [ " peripherals " ] )
{
auto device = agent - > ReAddPeripheral ( peripheral [ " iId " ] . get < std : : string > ( ) , peripheral [ " type " ] . get < HashT > ( ) ) ;
device - > m_StartupArguments = peripheral [ " startupCommand " ] ;
2020-03-05 15:30:50 +00:00
device - > m_Jitter = std : : pair { FSecure : : Utils : : ToMilliseconds ( peripheral [ " jitter " ] [ 0 ] . get < float > ( ) ) , FSecure : : Utils : : ToMilliseconds ( peripheral [ " jitter " ] [ 1 ] . get < float > ( ) ) } ;
2019-09-02 10:28:14 +00:00
}
for ( auto & & route : relay [ " routes " ] )
agent - > ReAddRoute ( RouteId ( route [ " destinationAgent " ] . get < std : : string > ( ) , route [ " receivingInterface " ] . get < std : : string > ( ) ) , route [ " outgoingInterface " ] . get < std : : string > ( ) , route [ " isNeighbour " ] . get < bool > ( ) ) ;
}
}
// Restore real routing table
{
auto profile = Get ( ) ;
auto gateRelay = profile . m_Gateway . m_Gateway . lock ( ) ;
if ( ! gateRelay )
throw std : : logic_error ( " Parent GateRelay cannot be locked " ) ;
auto const & routes = profile . m_Gateway . m_Routes . GetUnderlyingContainer ( ) ;
for ( auto const & route : routes )
{
auto outgoingDevice = gateRelay - > FindDevice ( route . m_OutgoingDevice ) ;
if ( ! outgoingDevice )
throw std : : logic_error ( " Outgoing device cannot be locked " ) ;
gateRelay - > AddRoute ( route . m_Id , outgoingDevice ) ;
}
profile . m_Gateway . m_LastDeviceId = snapshot [ " _LastDeviceId " ] . get < DeviceId : : UnderlyingIntegerType > ( ) ;
}
// restore connections in connector. It must be last step in the chain.
{
auto gateway = m_Gateway - > m_Gateway . lock ( ) ;
if ( ! gateway )
return ;
for ( auto & & relay : snapshot [ " relays " ] )
{
auto profile = Get ( ) ;
for ( auto & & peripheral : relay [ " peripherals " ] )
{
auto connectorHash = GetBinderTo ( peripheral [ " type " ] . get < HashT > ( ) ) ;
auto connector = gateway - > m_Connectors . Find ( [ & ] ( auto const & e ) { return e - > GetNameHash ( ) = = connectorHash ; } ) ;
if ( ! connector )
continue ;
auto route = gateway - > FindRoute ( AgentId { relay [ " agentId " ] . get < std : : string > ( ) } ) ;
if ( ! route )
continue ;
auto creationCommand = base64 : : decode < ByteVector > ( peripheral [ " startupCommand " ] [ " ByteForm " ] . get < std : : string > ( ) ) ;
auto readView = ByteView { creationCommand } ;
2020-03-13 13:13:19 +00:00
auto connectionId = ByteVector : : Create ( RouteId { route - > m_RouteId . GetAgentId ( ) , DeviceId { peripheral [ " iId " ] . get < std : : string > ( ) } } ) ;
2019-09-02 10:28:14 +00:00
readView . remove_prefix ( sizeof ( uint16_t ) ) ; // remove command id
connector - > PeripheralCreationCommand ( connectionId , readView ) ; // throw away the response.
connector - > OnCommandFromBinder ( connectionId , base64 : : decode < ByteVector > ( peripheral [ " startupCommand " ] [ " FirstResponse " ] . get < std : : string > ( ) ) ) ;
}
}
}
// Gateway peripherals will not be restored. Supporting this case is not important, and they would need new staging to be done in this function. Might be added in the future.
//for (auto&& peripheral : snapshot["peripherals"])
//{
// auto gateRelay = Get().m_Gateway.m_Gateway.lock();
// if (!gateRelay)
// throw std::logic_error("Parent GateRelay cannot be locked");
// auto byteForm = base64::decode<ByteVector>(peripheral["startupCommand"]["ByteForm"].get<std::string>());
// auto readView = ByteView{ byteForm };
// readView.remove_prefix(sizeof(uint16_t)); // remove number of command
// auto did = DeviceId{ peripheral["iId"].get<std::string>() };
// gateRelay->CreateAndAttachDevice
// (
// did,
// peripheral["type"].get<HashT>(),
// false,
// readView
// );
// auto profile = Get(); // we need to take profile each time, as it is also taken in CreateAndAttachDevice and that would lead to deadlock.
// auto peripheralProfile = profile.m_Gateway.m_Peripherals.Find(did);
// peripheralProfile->m_StartupArguments = peripheral["startupCommand"];
//}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : HandleNewBuildMessage ( json const & message )
2019-09-02 10:28:14 +00:00
{
auto newBuildId = message . at ( " BuildId " ) . get < BuildId : : UnderlyingIntegerType > ( ) ;
auto const & command = message . at ( " Command " ) ;
auto commandBinary = TranslateStartupCommand ( command ) ;
auto response = json
{
{ " BinaryCommand " , base64 : : encode ( commandBinary ) } ,
} ;
{
// Add build to profiler
auto arch = message . at ( " Arch " ) . get < std : : string > ( ) ;
std : : transform ( arch . begin ( ) , arch . end ( ) , arch . begin ( ) , [ ] ( char c ) { return std : : tolower ( c ) ; } ) ;
auto isX64 = arch = = " x64 " ;
Get ( ) . m_Gateway . AddAgentBuild ( newBuildId , { isX64 , false , command } ) ;
}
return response ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : Gateway : : CreateProfileSnapshot ( ) const
2019-09-02 10:28:14 +00:00
{
auto gateway = m_Gateway . lock ( ) ;
if ( ! gateway )
return { } ;
// Fill in basic data.
json profile = {
{ " agentId " , gateway - > m_AgentId . ToString ( ) } ,
{ " buildId " , gateway - > m_BuildId . ToString ( ) } ,
{ " _LastDeviceId " , m_LastDeviceId } ,
{ " timestamp " , m_LastSeen } ,
{ " isActive " , true }
} ;
if ( ! m_ErrorState . empty ( ) )
profile [ " error " ] = m_ErrorState ;
// Populate output json with all containers and their elements Profiles.
profile [ " channels " ] = m_Channels . CreateProfileSnapshot ( ) ;
profile [ " peripherals " ] = m_Peripherals . CreateProfileSnapshot ( ) ;
profile [ " routes " ] = m_Routes . CreateProfileSnapshot ( ) ;
profile [ " connectors " ] = m_Connectors . CreateProfileSnapshot ( ) ;
profile [ " relays " ] = m_Agents . CreateProfileSnapshot ( ) ;
json registeredBuilds ;
for ( auto b : m_AgentBuilds )
{
registeredBuilds . push_back
(
{
{ " _bid " , b . first . ToUnderlyingType ( ) } ,
{ " _ban " , b . second . m_IsBanned } ,
{ " _x64 " , b . second . m_IsX64 } ,
{ " _startCmd " , b . second . m_StartupCmd } ,
}
) ;
}
profile [ " _RegisteredBuilds " ] = registeredBuilds ;
return profile ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Agent : : Agent ( std : : weak_ptr < Profiler > owner , AgentId agentId , BuildId buildId , FSecure : : Crypto : : PublicKey encryptionKey , bool isBanned , int32_t lastSeen , bool isX64 , HostInfo hostInfo )
2019-09-02 10:28:14 +00:00
: Relay ( owner , agentId , buildId , lastSeen )
, m_EncryptionKey ( encryptionKey )
2020-02-21 13:08:40 +00:00
, m_HostInfo ( std : : move ( hostInfo ) )
2019-09-02 10:28:14 +00:00
, m_IsBanned ( isBanned )
, m_IsX64 ( isX64 )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : Agent : : CreateProfileSnapshot ( ) const
2019-09-02 10:28:14 +00:00
{
// Fill in basic data.
json profile = {
{ " agentId " , m_Id . ToString ( ) } ,
{ " buildId " , m_BuildId . ToString ( ) } ,
{ " publicKey " , m_EncryptionKey . ToBase64 ( ) } ,
{ " _LastDeviceId " , m_LastDeviceId } ,
{ " timestamp " , m_LastSeen } ,
{ " hostInfo " , m_HostInfo } ,
2020-03-05 15:30:50 +00:00
{ " isActive " , FSecure : : Utils : : TimeSinceEpoch ( ) - m_LastSeen < 300 }
2019-09-02 10:28:14 +00:00
} ;
if ( ! m_ErrorState . empty ( ) )
profile [ " error " ] = m_ErrorState ;
// Populate output json with all containers and their elements Profiles.
profile [ " channels " ] = m_Channels . CreateProfileSnapshot ( ) ;
profile [ " peripherals " ] = m_Peripherals . CreateProfileSnapshot ( ) ;
profile [ " routes " ] = m_Routes . CreateProfileSnapshot ( ) ;
return profile ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Agent : : ParseAndRunCommand ( json const & jCommandElement ) noexcept ( false )
2019-09-02 10:28:14 +00:00
{
auto profiler = m_Owner . lock ( ) ;
if ( ! profiler )
return ; // probably shutting down
// check if the command should be run on device
std : : optional < DeviceId > deviceId ;
bool deviceIsChannel = false ; // have meaning only when it is command for device.
if ( auto jChannelId = jCommandElement . find ( " channelId " ) ; jChannelId ! = jCommandElement . end ( ) & & ! jChannelId - > is_null ( ) )
{
if ( auto channel = m_Channels . Find ( jChannelId - > get < std : : string > ( ) ) ; channel )
{
deviceId = channel - > m_Id ;
deviceIsChannel = true ;
}
else
throw std : : runtime_error { " Unknown ChannelId. " } ;
}
else if ( auto jPeripheralId = jCommandElement . find ( " peripheralId " ) ; jPeripheralId ! = jCommandElement . end ( ) & & ! jPeripheralId - > is_null ( ) )
{
if ( auto peripheral = m_Peripherals . Find ( jPeripheralId - > get < std : : string > ( ) ) ; peripheral )
deviceId = peripheral - > m_Id ;
else
throw std : : runtime_error { " Unknown PeripheralId. " } ;
}
auto commandWithArgs = base64 : : decode < ByteVector > ( jCommandElement [ " Command " ] [ " ByteForm " ] . get < std : : string > ( ) ) ;
2019-09-11 09:35:52 +00:00
auto gateRelay = profiler - > m_Gateway - > m_Gateway . lock ( ) ;
if ( ! gateRelay )
return ; // probably shutting down
2019-09-02 10:28:14 +00:00
if ( deviceId )
{
std : : function < void ( ) > finalizer = [ ] ( ) { } ;
auto commandReadView = ByteView { commandWithArgs } ;
auto commandId = commandReadView . Read < std : : uint16_t > ( ) ;
if ( commandId > static_cast < std : : uint16_t > ( - 256 ) )
{
// generic interface commands
2020-03-05 15:30:50 +00:00
switch ( static_cast < FSecure : : C3 : : Command > ( commandId ) )
2019-09-02 10:28:14 +00:00
{
2020-03-05 15:30:50 +00:00
case FSecure : : C3 : : Command : : Close :
2019-09-11 09:35:52 +00:00
finalizer = [ & ] ( )
2019-09-02 10:28:14 +00:00
{
2019-09-11 09:35:52 +00:00
if ( deviceIsChannel )
{
m_Channels . TryRemove ( * deviceId ) ;
2020-04-07 14:04:05 +00:00
m_Routes . RemoveIf ( [ deviceId ] ( Profiler : : Route const & route ) { return route . m_OutgoingDevice = = deviceId ; } ) ;
2019-09-11 09:35:52 +00:00
}
else
{
// Find connector hash
auto element = m_Peripherals . Find ( * deviceId ) ;
if ( ! element )
return ;
auto connectorHash = profiler - > GetBinderTo ( element - > m_TypeHash ) ;
// remove peripheral
m_Peripherals . TryRemove ( * deviceId ) ;
// Get connector
auto connector = gateRelay - > m_Connectors . Find ( [ & ] ( auto const & e ) { return e - > GetNameHash ( ) = = connectorHash ; } ) ;
if ( ! connector )
return ;
// Remove connection.
2020-03-13 13:13:19 +00:00
connector - > CloseConnection ( ByteVector : : Create ( RouteId { m_Id , * deviceId } ) ) ;
2019-09-11 09:35:52 +00:00
}
2019-09-02 10:28:14 +00:00
} ;
break ;
2020-03-05 15:30:50 +00:00
case FSecure : : C3 : : Command : : UpdateJitter :
2019-09-02 10:28:14 +00:00
finalizer = [ this , deviceId , deviceIsChannel , commandReadView ] ( ) mutable
{
Device * device = deviceIsChannel ? m_Channels . Find ( * deviceId ) : m_Peripherals . Find ( * deviceId ) ;
if ( ! device )
throw std : : runtime_error { " Device not found " } ;
2020-03-05 15:30:50 +00:00
device - > m_Jitter . first = FSecure : : Utils : : ToMilliseconds ( commandReadView . Read < float > ( ) ) ;
device - > m_Jitter . second = FSecure : : Utils : : ToMilliseconds ( commandReadView . Read < float > ( ) ) ;
2019-09-02 10:28:14 +00:00
} ;
break ;
2020-02-21 13:08:40 +00:00
default :
break ;
2019-09-02 10:28:14 +00:00
}
}
auto route = gateRelay - > FindRoute ( m_Id ) ;
if ( ! route )
throw std : : runtime_error ( " Failed to find route to agent id = " + m_Id . ToString ( ) ) ;
auto outgoingChannel = route - > m_Channel . lock ( ) ;
if ( ! outgoingChannel )
throw std : : runtime_error ( " Tried to send command through dead channel " ) ; // TODO maybe try through different route
auto query = ProceduresG2X : : RunCommandOnDeviceQuery : : Create ( route - > m_RouteId , gateRelay - > m_Signature , m_EncryptionKey , gateRelay - > m_DecryptionKey , * deviceId , ByteView { commandWithArgs } ) ;
gateRelay - > LockAndSendPacket ( query - > ComposeQueryPacket ( ) , outgoingChannel ) ;
finalizer ( ) ;
}
else // If we're here then let NodeRelay run Command on itself.
{
PerformCreateCommand ( jCommandElement ) ;
RunCommand ( commandWithArgs ) ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Agent : : RunCommand ( ByteView commandWithArguments )
2019-09-02 10:28:14 +00:00
{
auto commandReadView = commandWithArguments ;
auto commandId = commandReadView . Read < std : : uint16_t > ( ) ;
// this function handle only last part of commands range.
if ( commandId < = static_cast < uint16_t > ( - 256 ) )
return ;
auto profiler = m_Owner . lock ( ) ;
if ( ! profiler )
return ; // probably shutting down
auto gateRelay = profiler - > m_Gateway - > m_Gateway . lock ( ) ;
if ( ! gateRelay )
return ; // probably shutting down
auto route = gateRelay - > FindRoute ( m_Id ) ;
if ( ! route )
throw std : : runtime_error ( " Failed to find route to agent id = " + m_Id . ToString ( ) ) ;
std : : function < void ( ) > finalizer = [ ] ( ) { } ;
2019-10-31 13:11:18 +00:00
switch ( static_cast < Command > ( commandId ) )
2019-09-02 10:28:14 +00:00
{
2019-10-31 13:11:18 +00:00
case Command : : Close :
2019-09-02 10:28:14 +00:00
{
2019-09-11 09:35:52 +00:00
finalizer = [ & ] ( )
2019-09-02 10:28:14 +00:00
{
auto owner = m_Owner . lock ( ) ;
if ( ! owner )
throw std : : runtime_error { " Cannot obtain owner " } ;
2019-09-11 09:35:52 +00:00
2019-09-02 10:28:14 +00:00
m_Channels . Clear ( ) ;
2019-09-11 09:35:52 +00:00
for ( auto & & element : m_Peripherals . GetUnderlyingContainer ( ) )
{
auto connectorHash = profiler - > GetBinderTo ( element . m_TypeHash ) ;
auto connector = gateRelay - > m_Connectors . Find ( [ & ] ( auto const & e ) { return e - > GetNameHash ( ) = = connectorHash ; } ) ;
if ( ! connector )
break ;
// Remove connection.
2020-03-13 13:13:19 +00:00
connector - > CloseConnection ( ByteVector : : Create ( RouteId { m_Id , element . m_Id } ) ) ;
2019-09-11 09:35:52 +00:00
}
m_Peripherals . Clear ( ) ;
2019-09-02 10:28:14 +00:00
owner - > Get ( ) . m_Gateway . m_Agents . Remove ( m_Id ) ;
} ;
break ;
}
2019-10-31 13:11:18 +00:00
case Command : : CreateRoute :
2019-09-02 10:28:14 +00:00
{
finalizer = [ this , commandReadView ] ( ) mutable
{
2019-09-19 16:13:34 +00:00
auto [ ridStr , didStr , isNbr ] = commandReadView . Read < std : : string_view , std : : string_view , bool > ( ) ;
ReAddRoute ( ridStr , didStr , isNbr ) ;
2019-09-02 10:28:14 +00:00
} ;
break ;
}
2019-10-31 13:11:18 +00:00
case Command : : RemoveRoute :
2019-09-02 10:28:14 +00:00
{
finalizer = [ this , commandReadView ] ( ) mutable
{
2019-09-19 16:13:34 +00:00
ReRemoveRoute ( commandReadView . Read < std : : string_view > ( ) ) ;
2019-09-02 10:28:14 +00:00
} ;
break ;
}
2019-10-31 13:11:18 +00:00
case Command : : SetGRC :
2019-09-02 10:28:14 +00:00
{
finalizer = [ this , commandReadView ] ( ) mutable
{
2019-09-19 16:13:34 +00:00
auto did = DeviceId { commandReadView . Read < std : : string_view > ( ) } ;
2019-09-02 10:28:14 +00:00
if ( ! m_Channels . Find ( did ) )
throw std : : runtime_error { " Channel not found " } ;
for ( auto & e : m_Channels . GetUnderlyingContainer ( ) )
e . m_IsReturnChannel = e . m_Id = = did ;
} ;
break ;
}
2019-10-31 13:11:18 +00:00
case Command : : Ping :
2019-09-02 10:28:14 +00:00
break ;
default :
throw std : : runtime_error ( " Profiler received an unknown command for agent id: " + m_Id . ToString ( ) ) ;
}
auto outgoingChannel = route - > m_Channel . lock ( ) ;
if ( ! outgoingChannel )
throw std : : runtime_error ( " Tried to send command through dead channel " ) ; // TODO maybe try through different route
auto query = ProceduresG2X : : RunCommandOnAgentQuery : : Create ( route - > m_RouteId , gateRelay - > m_Signature , m_EncryptionKey , gateRelay - > m_DecryptionKey , commandWithArguments ) ;
gateRelay - > LockAndSendPacket ( query - > ComposeQueryPacket ( ) , outgoingChannel ) ;
finalizer ( ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Agent : : PerformCreateCommand ( json const & jCommandElement )
2019-09-02 10:28:14 +00:00
{
auto profiler = m_Owner . lock ( ) ;
if ( ! profiler )
return ; // probably shutting down
auto gateRelay = profiler - > m_Gateway - > m_Gateway . lock ( ) ;
if ( ! gateRelay )
return ; // probably shutting down
auto route = gateRelay - > FindRoute ( m_Id ) ;
if ( ! route )
throw std : : runtime_error ( " Failed to find route to agent id = " + m_Id . ToString ( ) ) ;
auto commandWithArguments = base64 : : decode < ByteVector > ( jCommandElement [ " Command " ] [ " ByteForm " ] . get < std : : string > ( ) ) ;
// check if command is a create device command -> then we need to assign deviceId and retreive its hash and repack commandWithArguments
// [CommandId{CreateAndAttachDevice}(u16)][NewDeviceId(u16)][NewDeviceTypeHash(HashT)][arguments]
auto commandReadView = ByteView { commandWithArguments } ;
auto commandId = commandReadView . Read < std : : uint16_t > ( ) ;
auto const & createCommands = profiler - > m_Gateway - > m_CreateCommands ;
auto command = std : : find_if ( createCommands . cbegin ( ) , createCommands . cend ( ) , [ commandId ] ( Gateway : : CreateCommand const & cc ) { return cc . m_IsDevice & & cc . m_Id = = commandId ; } ) ;
// this function will only suport create commands
if ( command = = createCommands . cend ( ) )
return ;
// it is a create command
DeviceId newDeviceId = + + m_LastDeviceId ;
ByteVector repacked ;
2019-11-21 10:33:30 +00:00
repacked . Write ( Command : : AddDevice , newDeviceId , command - > m_IsNegotiableChannel , command - > m_Hash ) ;
2019-09-02 10:28:14 +00:00
if ( auto binder = profiler - > GetBinderTo ( command - > m_Hash ) ; binder & & command - > m_IsDevice ) // peripheral, check if payload is needed.
{
auto connector = profiler - > m_Gateway - > m_Gateway . lock ( ) - > GetConnector ( binder ) ;
if ( ! connector )
throw std : : runtime_error { " Connector for requested peripheral is closed " } ;
2020-03-13 13:13:19 +00:00
auto updatedArguments = connector - > PeripheralCreationCommand ( ByteVector : : Create ( RouteId { route - > m_RouteId . GetAgentId ( ) , newDeviceId } ) , commandReadView , m_IsX64 ) ;
2019-09-02 10:28:14 +00:00
repacked . Concat ( updatedArguments ) ;
}
else
{
repacked . Concat ( commandReadView ) ;
}
commandWithArguments = repacked ;
auto outgoingChannel = route - > m_Channel . lock ( ) ;
if ( ! outgoingChannel )
throw std : : runtime_error ( " Tried to send command through dead channel " ) ; // TODO maybe try through different route
// push json with startup arguments to some container, use it if channel is created.
AddScheduledDevice ( newDeviceId , jCommandElement [ " Command " ] ) ;
auto query = ProceduresG2X : : RunCommandOnAgentQuery : : Create ( route - > m_RouteId , gateRelay - > m_Signature , m_EncryptionKey , gateRelay - > m_DecryptionKey , commandWithArguments ) ;
gateRelay - > LockAndSendPacket ( query - > ComposeQueryPacket ( ) , outgoingChannel ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Channel * FSecure : : C3 : : Core : : Profiler : : Agent : : ReAddChannel ( Device : : Id did , HashT typeNameHash , bool isReturnChannel /*= false*/ , bool isNegotiationChannel /*= false*/ )
2019-09-02 10:28:14 +00:00
{
auto channel = Relay : : ReAddChannel ( did , typeNameHash , isReturnChannel , isNegotiationChannel ) ;
if ( auto it = m_ScheduledDevices . find ( did . ToUnderlyingType ( ) ) ; it ! = m_ScheduledDevices . cend ( ) )
channel - > m_StartupArguments = it - > second ;
return channel ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Device * FSecure : : C3 : : Core : : Profiler : : Agent : : ReAddPeripheral ( Device : : Id did , HashT typeNameHash )
2019-09-02 10:28:14 +00:00
{
auto device = Relay : : ReAddPeripheral ( did , typeNameHash ) ;
if ( auto it = m_ScheduledDevices . find ( did . ToUnderlyingType ( ) ) ; it ! = m_ScheduledDevices . cend ( ) )
device - > m_StartupArguments = it - > second ;
return device ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Agent : : AddScheduledDevice ( DeviceId deviceId , json command )
2019-09-02 10:28:14 +00:00
{
m_ScheduledDevices . emplace ( deviceId . ToUnderlyingType ( ) , std : : move ( command ) ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Channel * FSecure : : C3 : : Core : : Profiler : : Agent : : FindGrc ( )
2019-09-02 10:28:14 +00:00
{
for ( auto & e : m_Channels . GetUnderlyingContainer ( ) )
if ( e . m_IsReturnChannel )
return & e ;
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Gateway : : Gateway ( std : : weak_ptr < Profiler > owner , std : : string name , std : : shared_ptr < GateRelay > gateway )
: Relay ( owner , gateway - > m_AgentId , gateway - > m_BuildId , FSecure : : Utils : : TimeSinceEpoch ( ) )
2019-09-02 10:28:14 +00:00
, m_Name ( std : : move ( name ) )
, m_Gateway ( gateway )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : ParseAndRunCommand ( json const & jCommandElement ) noexcept ( false )
2019-09-02 10:28:14 +00:00
{
auto commandWithArgs = base64 : : decode < ByteVector > ( jCommandElement [ " Command " ] [ " ByteForm " ] . get < std : : string > ( ) ) ;
auto commandReadView = ByteView { commandWithArgs } ;
auto conditionalRun = [ & ] ( auto jsonEntryToFind , bool isDevice ) - > bool
{
if ( auto jConnectorId = jCommandElement . find ( jsonEntryToFind ) ; jConnectorId ! = jCommandElement . end ( ) & & ! jConnectorId - > is_null ( ) )
{
2020-02-21 13:08:40 +00:00
auto id = std : : stoull ( jConnectorId - > template get < std : : string > ( ) , nullptr , 16 ) ; // throws on error.
2019-09-02 10:28:14 +00:00
if ( isDevice )
{
auto gateway = m_Gateway . lock ( ) ;
2020-03-05 15:30:50 +00:00
if ( auto device = gateway - > FindDevice ( FSecure : : Utils : : SafeCast < DeviceId : : UnderlyingIntegerType > ( id ) ) ; device )
2019-09-02 10:28:14 +00:00
{
2019-09-11 09:35:52 +00:00
auto localView = commandReadView ;
2020-03-05 15:30:50 +00:00
switch ( FSecure : : C3 : : Command ( localView . Read < std : : uint16_t > ( ) ) )
2019-09-02 10:28:14 +00:00
{
2020-03-05 15:30:50 +00:00
case FSecure : : C3 : : Command : : UpdateJitter :
2019-09-11 09:35:52 +00:00
{
Device * profilerElement = m_Channels . Find ( device - > GetDid ( ) ) ;
if ( ! profilerElement )
profilerElement = m_Peripherals . Find ( device - > GetDid ( ) ) ;
if ( ! profilerElement )
throw std : : runtime_error { " Device not found " } ;
2020-03-05 15:30:50 +00:00
profilerElement - > m_Jitter . first = FSecure : : Utils : : ToMilliseconds ( localView . Read < float > ( ) ) ;
profilerElement - > m_Jitter . second = FSecure : : Utils : : ToMilliseconds ( localView . Read < float > ( ) ) ;
2019-09-11 09:35:52 +00:00
break ;
}
2020-03-05 15:30:50 +00:00
case FSecure : : C3 : : Command : : Close :
2019-09-11 09:35:52 +00:00
{
2020-04-07 14:04:05 +00:00
if ( auto profilerElement = m_Peripherals . Find ( device - > GetDid ( ) ) )
{
auto connectorHash = m_Owner . lock ( ) - > GetBinderTo ( profilerElement - > m_TypeHash ) ;
auto connector = m_Gateway . lock ( ) - > m_Connectors . Find ( [ & ] ( auto const & e ) { return e - > GetNameHash ( ) = = connectorHash ; } ) ;
if ( ! connector )
break ;
// Remove connection.
connector - > CloseConnection ( ByteVector : : Create ( RouteId { m_Id , device - > GetDid ( ) } ) ) ;
}
else if ( auto profilerElemnt = m_Channels . Find ( device - > GetDid ( ) ) )
{
m_Routes . RemoveIf ( [ did = device - > GetDid ( ) ] ( Profiler : : Route const & route ) { return route . m_OutgoingDevice = = did ; } ) ;
}
2019-09-11 09:35:52 +00:00
break ;
}
default :
break ;
2019-09-02 10:28:14 +00:00
}
2019-09-11 09:35:52 +00:00
device - > RunCommand ( commandReadView ) ;
2019-09-02 10:28:14 +00:00
return true ;
}
}
else
{
2020-03-05 15:30:50 +00:00
if ( auto connector = m_Connectors . Find ( FSecure : : Utils : : SafeCast < HashT > ( id ) ) ; connector )
2019-09-02 10:28:14 +00:00
return connector - > RunCommand ( commandReadView ) , true ;
}
throw std : : runtime_error { " Unknown Id. " } ;
}
return false ;
} ;
if ( conditionalRun ( " connectorId " , false ) ) return ;
if ( conditionalRun ( " channelId " , true ) ) return ;
if ( conditionalRun ( " peripheralId " , true ) ) return ;
// If we're here then let NodeRelay run Command on itself.
RunCommand ( commandReadView ) ;
// try performing create command.
PerformCreateCommand ( jCommandElement ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : Gateway : : GetCapability ( )
2019-09-02 10:28:14 +00:00
{
// Request access to Gateway object.
auto gateway = m_Gateway . lock ( ) ;
if ( ! gateway )
return { } ;
// TODO This function require refactoring.
// Construct the InitialPacket.
json initialPacket = json : : parse ( gateway - > m_InterfaceFactory . GetCapability ( ) ) ;
2019-08-29 09:59:54 +00:00
for ( auto & interface : initialPacket [ " channels " ] )
2019-11-05 16:18:25 +00:00
EnsureCreateExists ( interface ) ;
2019-08-29 09:59:54 +00:00
2019-09-02 10:28:14 +00:00
// Create method in interface is constructor. It must be a relay/gateway command.
// initialPacket is copied to original to prevent iterator invalidation.
// last 256 commands will be reserved for common commands.
auto modifyEntry = [ & , id = static_cast < uint16_t > ( - 257 ) , oryginal = initialPacket ] ( std : : vector < std : : string > const & relayTypes , auto interfaceType , std : : vector < std : : string > prefix , bool isDevice ) mutable
{
auto idToErase = 0 ;
std : : vector < std : : unordered_map < std : : string , std : : vector < json > > > buffer ;
buffer . resize ( prefix . size ( ) ) ;
2019-08-29 09:59:54 +00:00
for ( auto & & element : oryginal [ interfaceType ] )
2019-09-02 10:28:14 +00:00
{
try
{
for ( auto i = 0u ; i < prefix . size ( ) ; + + i )
{
2019-08-29 09:59:54 +00:00
auto arguments = element . at ( " create " ) . at ( " arguments " ) ;
2019-09-02 10:28:14 +00:00
if ( i ) // NegotiationChannel command
{
if ( arguments . empty ( ) | | arguments [ 0 ] . size ( ) ! = 2 )
continue ;
arguments [ 0 ] = { { " type " , " string " } , { " name " , " Negotiation Identifier " } , { " randomize " , true } , { " description " , " One identifier used to negotiate identifiers for each joining relay " } } ;
}
for ( auto & & relayType : relayTypes )
2020-02-21 13:08:40 +00:00
buffer [ i ] [ relayType ] . push_back ( json { { " name " , prefix [ i ] + element [ " name " ] . template get < std : : string > ( ) } , { " arguments " , arguments } , { " id " , id } } ) ;
2019-09-02 10:28:14 +00:00
2020-02-21 13:08:40 +00:00
m_CreateCommands . push_back ( { id , initialPacket [ interfaceType ] [ idToErase ] [ " type " ] . template get < uint32_t > ( ) , isDevice , ! ! i } ) ; // store command id and hash.
2019-09-02 10:28:14 +00:00
- - id ;
}
// modify initial Packet with extra entries.
initialPacket [ interfaceType ] [ idToErase ] . erase ( " create " ) ;
2019-11-05 16:18:25 +00:00
AddBuildInCommands ( initialPacket [ interfaceType ] [ idToErase ] , isDevice ) ;
2019-09-02 10:28:14 +00:00
}
catch ( std : : exception & e )
{
m_Gateway . lock ( ) - > Log ( { std : : string ( " Exception caught when parsing interface capability. " ) + e . what ( ) , LogMessage : : Severity : : Error } ) ;
}
+ + idToErase ;
}
// move commands from buffer to modified json in correct order.
for ( auto prefixEntryIterator = buffer . rbegin ( ) ; prefixEntryIterator ! = buffer . rend ( ) ; + + prefixEntryIterator )
for ( auto & & relayEntry : * prefixEntryIterator )
for ( auto & & e : relayEntry . second )
initialPacket [ relayEntry . first ] [ " commands " ] . push_back ( std : : move ( e ) ) ;
} ;
m_CreateCommands . clear ( ) ; // clear old create commands.
modifyEntry ( { " gateway " , " relay " } , " channels " , { " AddChannel " , " AddNegotiationChannel " } , true ) ;
modifyEntry ( { " gateway " , " relay " } , " peripherals " , { " AddPeripheral " } , true ) ;
modifyEntry ( { " gateway " } , " connectors " , { " TurnOnConnector " } , false ) ;
// Add common commands for relay.
auto addRelayCommand = [ & ] ( std : : vector < std : : string > relayTypes , json const & newCommand )
{
for ( auto & & relayType : relayTypes )
initialPacket [ relayType ] [ " commands " ] . push_back ( newCommand ) ;
} ;
2019-10-31 13:11:18 +00:00
addRelayCommand ( { " gateway " , " relay " } , json { { " name " , " Close " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : Close ) } , { " arguments " , json : : array ( ) } } ) ;
2019-09-02 10:28:14 +00:00
2019-10-31 13:11:18 +00:00
addRelayCommand ( { " gateway " , " relay " } , json { { " name " , " CreateRoute " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : CreateRoute ) } , { " arguments " , {
2019-09-02 10:28:14 +00:00
{ { " type " , " string " } , { " name " , " RouteID " } , { " description " , " Id of route in string form. " } , { " min " , 1 } } ,
{ { " type " , " string " } , { " name " , " DeviceId " } , { " description " , " Id of device in string form. " } , { " min " , 1 } } ,
{ { " type " , " boolean " } , { " name " , " Neighbor " } , { " description " , " Informs if relay is direct neighbor. " } , { " defaultValue " , true } }
} } } ) ;
2019-10-31 13:11:18 +00:00
addRelayCommand ( { " gateway " , " relay " } , json { { " name " , " RemoveRoute " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : RemoveRoute ) } , { " arguments " , {
2019-09-02 10:28:14 +00:00
{ { " type " , " string " } , { " name " , " RouteID " } , { " description " , " Id of route in string form. " } , { " min " , 1 } }
} } } ) ;
2019-10-31 13:11:18 +00:00
addRelayCommand ( { " relay " } , json { { " name " , " SetGatewayReturnChannel " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : SetGRC ) } , { " arguments " , {
2019-09-02 10:28:14 +00:00
{ { " type " , " string " } , { " name " , " DeviceID " } , { " description " , " Id of device in string form. " } , { " min " , 1 } }
} } } ) ;
2019-10-31 13:11:18 +00:00
addRelayCommand ( { " relay " } , json { { " name " , " Ping " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : Ping ) } , { " arguments " , json : : array ( ) } } ) ;
2019-09-02 10:28:14 +00:00
2019-10-31 13:11:18 +00:00
addRelayCommand ( { " gateway " } , json { { " name " , " ClearNetwork " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : ClearNetwork ) } , { " arguments " , {
2019-09-02 10:28:14 +00:00
{ { " type " , " boolean " } , { " name " , " Are you sure? " } , { " description " , " Confirm clearing the network. All network state will be lost, this can not be undone. " } , { " default " , false } }
} } } ) ;
// add extra fields.
auto gatewayPushBack = [ & ] ( auto key , auto value )
{
initialPacket [ " gateway " ] [ key ] = value ;
} ;
gatewayPushBack ( " agentId " , m_Id . ToString ( ) ) ;
gatewayPushBack ( " buildId " , m_BuildId . ToString ( ) ) ;
gatewayPushBack ( " publicKey " , Crypto : : ExtractPublic ( gateway - > m_Signature ) . ToBase64 ( ) ) ;
gatewayPushBack ( " broadcastKey " , gateway - > m_BroadcastKey . ToBase64 ( ) ) ;
gatewayPushBack ( " name " , m_Name ) ;
return initialPacket ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : EnsureCreateExists ( json & interface )
2019-11-05 16:18:25 +00:00
{
if ( ! interface . contains ( " create " ) )
interface [ " create " ] = json : : parse ( R " (
{
" arguments " :
[
{
" type " : " binary " ,
" description " : " Blob of data that will be provided to Channel constructor. " ,
" name " : " arguments "
}
]
}
) " );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : AddBuildInCommands ( json & interface , bool isDevice )
2019-11-05 16:18:25 +00:00
{
2019-11-06 14:00:06 +00:00
interface [ " commands " ] . push_back ( json { { " name " , isDevice ? " Close " : " TurnOff " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : Close ) } , { " arguments " , json : : array ( ) } } ) ;
2019-11-05 16:18:25 +00:00
if ( isDevice )
2019-11-06 14:00:06 +00:00
interface [ " commands " ] . push_back ( json { { " name " , " Set UpdateDelayJitter " } , { " description " , " Set delay between receiving function calls. " } , { " id " , static_cast < std : : underlying_type_t < Command > > ( Command : : UpdateJitter ) } ,
2019-11-05 16:18:25 +00:00
{ " arguments " , {
{ { " type " , " float " } , { " name " , " Min " } , { " description " , " Minimal delay in seconds " } , { " min " , 0.03 } } ,
{ { " type " , " float " } , { " name " , " Max " } , { " description " , " Maximal delay in seconds. " } , { " min " , 0.03 } }
} } } ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : RunCommand ( ByteView commandWithArguments )
2019-09-02 10:28:14 +00:00
{
auto pin = m_Gateway . lock ( ) ;
if ( ! pin )
return ;
2019-10-31 13:11:18 +00:00
switch ( static_cast < Command > ( commandWithArguments . Read < std : : underlying_type_t < Command > > ( ) ) )
2019-09-02 10:28:14 +00:00
{
2019-10-31 13:11:18 +00:00
case Command : : Close :
2019-09-02 10:28:14 +00:00
pin - > Close ( ) ;
break ;
2019-10-31 13:11:18 +00:00
case Command : : CreateRoute :
2019-09-02 10:28:14 +00:00
{
pin - > CreateRoute ( commandWithArguments ) ;
2019-09-19 16:13:34 +00:00
auto [ ridStr , didStr , isNbr ] = commandWithArguments . Read < std : : string_view , std : : string_view , bool > ( ) ;
ReAddRoute ( ridStr , didStr , isNbr ) ;
2019-09-02 10:28:14 +00:00
break ;
}
2019-10-31 13:11:18 +00:00
case Command : : RemoveRoute :
2019-09-02 10:28:14 +00:00
{
pin - > RemoveRoute ( commandWithArguments ) ;
2019-09-19 16:13:34 +00:00
ReRemoveRoute ( commandWithArguments . Read < std : : string_view > ( ) ) ;
2019-09-02 10:28:14 +00:00
break ;
}
2019-10-31 13:11:18 +00:00
case Command : : ClearNetwork :
2019-09-02 10:28:14 +00:00
{
// Clear real gateway
pin - > Reset ( ) ;
// clear profiler view
{
auto profiler = m_Owner . lock ( ) ;
auto profile = profiler - > Get ( ) ;
profile . m_Gateway . Reset ( ) ;
}
break ;
}
2020-02-21 13:08:40 +00:00
default :
break ;
2019-09-02 10:28:14 +00:00
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : PerformCreateCommand ( json const & jCommandElement ) //GateRelay& gate, std::uint16_t commandId, ByteView arguments)
2019-09-02 10:28:14 +00:00
{
auto pin = m_Gateway . lock ( ) ;
if ( ! pin )
throw std : : runtime_error { " Cannot lock gateway " } ;
auto & gate = * pin ;
auto command = base64 : : decode < ByteVector > ( jCommandElement [ " Command " ] [ " ByteForm " ] . get < std : : string > ( ) ) ;
auto arguments = ByteView { command } ;
auto commandId = arguments . Read < uint16_t > ( ) ;
auto profiler = m_Owner . lock ( ) ; // bad code, refactor.
auto createCommandIt = std : : find_if ( m_CreateCommands . cbegin ( ) , m_CreateCommands . cend ( ) , [ commandId ] ( auto const & cc ) { return cc . m_Id = = commandId ; } ) ;
if ( createCommandIt = = m_CreateCommands . cend ( ) )
return ;
auto createCommand = * createCommandIt ;
if ( createCommand . m_IsDevice )
{
ByteVector updatedArguments ;
//createCommand.
auto binder = profiler - > GetBinderTo ( createCommand . m_Hash ) ;
if ( binder )
{
auto connector = gate . GetConnector ( binder ) ;
if ( ! connector )
throw std : : runtime_error { " Connector for requested peripheral is closed " } ;
2020-03-13 13:13:19 +00:00
updatedArguments = connector - > PeripheralCreationCommand ( ByteVector : : Create ( RouteId { gate . GetAgentId ( ) , DeviceId ( m_LastDeviceId + 1 ) } ) , arguments , FSecure : : Utils : : IsProcess64bit ( ) ) ;
2019-09-02 10:28:14 +00:00
arguments = updatedArguments ;
}
auto device = gate . CreateAndAttachDevice ( + + m_LastDeviceId , createCommand . m_Hash , createCommand . m_IsNegotiableChannel , arguments ) ;
// TODO refactor - seriously bad code CreateAndAttach calls ReAddChannel / ReAddDevice and here we search for it
Device * deviceView ;
if ( device - > IsChannel ( ) )
deviceView = profiler - > Get ( ) . m_Gateway . m_Channels . Find ( device - > GetDid ( ) ) ;
else
deviceView = profiler - > Get ( ) . m_Gateway . m_Peripherals . Find ( device - > GetDid ( ) ) ;
if ( deviceView )
deviceView - > m_StartupArguments = jCommandElement [ " Command " ] ;
}
else
{
gate . TurnOnConnector ( createCommand . m_Hash , arguments ) ;
auto connectorView = profiler - > Get ( ) . m_Gateway . m_Connectors . Find ( createCommand . m_Hash ) ;
if ( connectorView )
connectorView - > m_StartupArguments = jCommandElement [ " Command " ] ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : ReTurnOnConnector ( HashT typeNameHash , std : : shared_ptr < ConnectorBridge > connector )
2019-09-02 10:28:14 +00:00
{
m_Connectors . Add ( typeNameHash , Connector { m_Owner , typeNameHash , connector } ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : ReTurnOffConnector ( HashT connectorNameHash )
2019-09-02 10:28:14 +00:00
{
m_Connectors . Remove ( connectorNameHash ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : ReDeleteChannel ( DeviceId iidOfDeviceToDetach )
2019-09-02 10:28:14 +00:00
{
m_Channels . Remove ( iidOfDeviceToDetach ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : ReDeletePeripheral ( DeviceId iidOfDeviceToDetach )
2019-09-02 10:28:14 +00:00
{
m_Peripherals . Remove ( iidOfDeviceToDetach ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Agent * FSecure : : C3 : : Core : : Profiler : : Gateway : : ReAddAgent ( AgentId agentId , BuildId buildId , FSecure : : Crypto : : PublicKey encryptionKey , bool isBanned , int32_t lastSeen , HostInfo hostInfo )
2019-09-02 10:28:14 +00:00
{
auto build = m_AgentBuilds . find ( buildId ) ;
if ( build = = m_AgentBuilds . cend ( ) )
throw std : : runtime_error { " Tried to add agent with unknown buildId " } ;
if ( build - > second . m_IsBanned )
return nullptr ;
auto agent = m_Agents . Add ( agentId , Agent { m_Owner , agentId , buildId , encryptionKey , isBanned , lastSeen , build - > second . m_IsX64 , std : : move ( hostInfo ) } ) ;
agent - > AddScheduledDevice ( 0u , build - > second . m_StartupCmd ) ;
return agent ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Agent * FSecure : : C3 : : Core : : Profiler : : Gateway : : ReAddRemoteAgent ( RouteId childRouteId , BuildId buildId , FSecure : : Crypto : : PublicKey encryptionKey , RouteId ridOfConectionPlace , HashT childGrcHash , int32_t lastSeen , HostInfo hostInfo )
2019-09-02 10:28:14 +00:00
{
// add agent
auto newAgent = ReAddAgent ( childRouteId . GetAgentId ( ) , buildId , encryptionKey , false , lastSeen , std : : move ( hostInfo ) ) ; // TODO check if is banned
// add routes
Relay * current = this ;
while ( current - > m_Id ! = ridOfConectionPlace . GetAgentId ( ) )
{
DeviceId outDevice = current - > FindDirectionDevice ( ridOfConectionPlace . GetAgentId ( ) ) ;
current - > ReAddRoute ( childRouteId , outDevice , false ) ;
current = FindNeighborOnDevice ( * current , outDevice ) ;
}
// add route to neighboring device
current - > ReAddRoute ( childRouteId , ridOfConectionPlace . GetInterfaceId ( ) , true ) ;
// add return channel to new agent
newAgent - > ReAddChannel ( childRouteId . GetInterfaceId ( ) , childGrcHash , true ) ;
return newAgent ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Relay : : UpdateFromNegotiationChannel ( DeviceId negotiationDid , DeviceId newDeviceId , std : : string newInputId , std : : string newOutputId )
2019-09-02 10:28:14 +00:00
{
auto oldDeviceProfile = m_Channels . Find ( negotiationDid ) ;
auto newDeviceProfile = m_Channels . Find ( newDeviceId ) ;
if ( oldDeviceProfile & & newDeviceProfile )
{
newDeviceProfile - > m_StartupArguments = oldDeviceProfile - > m_StartupArguments ;
newDeviceProfile - > m_StartupArguments [ " arguments " ] [ 0 ] = { { { " name " , " Input ID " } , { " type " , " string " } , { " value " , newInputId } } , { { " name " , " Output ID " } , { " type " , " string " } , { " value " , newOutputId } } } ;
auto oldDeviceCmd = base64 : : decode < ByteVector > ( oldDeviceProfile - > m_StartupArguments [ " ByteForm " ] . get < std : : string > ( ) ) ;
auto oldDeviceCmdReadView = ByteView { oldDeviceCmd } ;
auto [ cmdId , uniqueId ] = oldDeviceCmdReadView . Read < uint16_t , std : : string > ( ) ;
auto newDeviceCmd = ByteVector { } . Write ( cmdId , newInputId , newOutputId ) . Concat ( oldDeviceCmdReadView ) ;
newDeviceProfile - > m_StartupArguments [ " ByteForm " ] = base64 : : encode ( newDeviceCmd ) ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Agent * FSecure : : C3 : : Core : : Profiler : : Gateway : : FindNeighborOnDevice ( Relay & relay , DeviceId did )
2019-09-02 10:28:14 +00:00
{
auto & routes = relay . m_Routes . GetUnderlyingContainer ( ) ;
auto it = std : : find_if ( routes . begin ( ) , routes . end ( ) , [ & ] ( auto & e ) { return e . m_IsNeighbour & & e . m_OutgoingDevice = = did ; } ) ;
if ( it = = routes . end ( ) )
throw std : : logic_error { " There is no route from provided agent " } ;
auto ret = m_Agents . Find ( it - > m_Id . GetAgentId ( ) ) ;
if ( ! ret )
throw std : : logic_error { " There is no route from provided agent " } ;
return ret ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : UpdateRouteTimestamps ( AgentId agentId , int32_t timestamp )
2019-09-02 10:28:14 +00:00
{
Agent * agent = m_Agents . Find ( agentId ) ;
if ( ! agent )
throw std : : runtime_error { " Agent not found " } ;
for ( auto e : GetPathFromAgent ( agent ) )
e - > m_LastSeen = timestamp ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Agent * FSecure : : C3 : : Core : : Profiler : : Gateway : : FindGatewaySideAgent ( Agent * agent )
2019-09-02 10:28:14 +00:00
{
2020-04-07 14:04:05 +00:00
auto & channels = agent - > m_Channels . GetUnderlyingContainer ( ) ;
2019-09-02 10:28:14 +00:00
auto grcIt = std : : find_if ( channels . begin ( ) , channels . end ( ) , [ ] ( auto & e ) { return e . m_IsReturnChannel ; } ) ;
if ( grcIt = = channels . end ( ) )
throw std : : runtime_error { " GRC not found " } ;
for ( auto & current : m_Agents . GetUnderlyingContainer ( ) )
{
for ( auto & route : current . m_Routes . GetUnderlyingContainer ( ) )
{
if ( route . m_IsNeighbour & & route . m_Id . GetAgentId ( ) = = agent - > m_Id & & route . m_Id . GetInterfaceId ( ) = = grcIt - > m_Id )
return & current ;
}
}
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
std : : vector < FSecure : : C3 : : Core : : Profiler : : Agent * > FSecure : : C3 : : Core : : Profiler : : Gateway : : GetPathFromAgent ( Agent * agent )
2019-09-02 10:28:14 +00:00
{
std : : vector < Agent * > ret ;
auto depthLimit = 128 ;
while ( agent & & agent - > m_Id ! = m_Id )
{
if ( ! ( - - depthLimit ) )
return { } ;
ret . push_back ( agent ) ;
agent = FindGatewaySideAgent ( agent ) ;
}
return ret ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
bool FSecure : : C3 : : Core : : Profiler : : Gateway : : ConnectionExist ( AgentId agentId )
2019-09-02 10:28:14 +00:00
{
if ( auto path = GetPathFromAgent ( m_Agents . Find ( agentId ) ) ; ! path . empty ( ) )
for ( auto & e : m_Routes . GetUnderlyingContainer ( ) )
if ( e . m_IsNeighbour & & e . m_Id . GetAgentId ( ) = = path . back ( ) - > m_Id )
return true ;
return false ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : AddAgentBuild ( BuildId bid , BuildProperties properties )
2019-09-02 10:28:14 +00:00
{
auto emplaced = m_AgentBuilds . emplace ( bid , properties ) ;
if ( ! emplaced . second )
throw std : : logic_error { " Tried to add new build with existing buildId " } ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : ConditionalUpdateChannelParameters ( RouteId connectionPlace )
2019-09-02 10:28:14 +00:00
{
try
{
// parent is known
Relay * parent = connectionPlace . GetAgentId ( ) = = m_Id ? static_cast < Relay * > ( this ) : m_Agents . Find ( connectionPlace . GetAgentId ( ) ) ;
if ( ! parent )
return ;
auto parentChannel = parent - > m_Channels . Find ( connectionPlace . GetInterfaceId ( ) ) ;
if ( ! parentChannel | | parentChannel - > m_StartupArguments . is_null ( ) )
return ;
Agent * agent = FindNeighborOnDevice ( * parent , connectionPlace . GetInterfaceId ( ) ) ;
auto agentChannel = agent - > FindGrc ( ) ;
if ( ! agentChannel )
return ;
// Channel does not have startup arguments.
if ( ! agentChannel - > m_StartupArguments . is_null ( ) )
return ;
// build started with neg channel
auto buildIterator = m_AgentBuilds . find ( agent - > m_BuildId ) ;
if ( buildIterator = = m_AgentBuilds . end ( ) | | buildIterator - > second . m_StartupCmd [ " command " ] . get < std : : string > ( ) . find ( " AddNegotiationChannel " ) = = std : : string : : npos )
return ;
// update
json startupArguments = { { " arguments " , json : : array ( ) } } ;
startupArguments [ " arguments " ] [ 0 ] [ 0 ] = parentChannel - > m_StartupArguments [ " arguments " ] [ 0 ] [ 1 ] ;
startupArguments [ " arguments " ] [ 0 ] [ 1 ] = parentChannel - > m_StartupArguments [ " arguments " ] [ 0 ] [ 0 ] ;
for ( auto i = 1u ; i < buildIterator - > second . m_StartupCmd [ " arguments " ] . size ( ) ; + + i )
startupArguments [ " arguments " ] [ i ] = buildIterator - > second . m_StartupCmd [ " arguments " ] [ i ] ;
agentChannel - > m_StartupArguments = startupArguments ;
}
catch ( const std : : exception & )
{
return ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : Reset ( )
2019-09-02 10:28:14 +00:00
{
m_Agents . Clear ( ) ;
m_Connectors . Clear ( ) ;
m_Peripherals . Clear ( ) ;
m_Channels . Clear ( ) ;
m_Routes . Clear ( ) ;
m_AgentBuilds . clear ( ) ;
m_LastDeviceId = 0 ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Device : : RunCommand ( ByteView commandWithArguments )
2019-09-02 10:28:14 +00:00
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Device : : Device ( std : : weak_ptr < Profiler > owner , Id id , HashT typeHash )
2019-09-02 10:28:14 +00:00
: ProfileElement ( owner )
, m_Id ( id )
, m_TypeHash ( typeHash )
{
if ( auto ptrCh = InterfaceFactory : : Instance ( ) . GetInterfaceData < AbstractChannel > ( m_TypeHash ) ; ptrCh )
m_Jitter = ptrCh - > m_StartupJitter ;
else if ( auto ptrP = InterfaceFactory : : Instance ( ) . GetInterfaceData < AbstractPeripheral > ( m_TypeHash ) ; ptrP )
m_Jitter = ptrP - > m_StartupJitter ;
else
throw std : : runtime_error ( " Type hash does is not device: " + std : : to_string ( m_TypeHash ) ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Route : : Route ( std : : weak_ptr < Profiler > owner , RouteId id , Device : : Id outgoingDeviceId , bool isNeighbour )
2019-09-02 10:28:14 +00:00
: ProfileElement ( owner )
, m_OutgoingDevice ( outgoingDeviceId )
2020-02-21 13:08:40 +00:00
, m_Id ( id )
2019-09-02 10:28:14 +00:00
, m_IsNeighbour ( isNeighbour )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : Route : : CreateProfileSnapshot ( ) const
2019-09-02 10:28:14 +00:00
{
// Construct profile.
json profile = {
{ " outgoingInterface " , m_OutgoingDevice . ToString ( ) } ,
{ " destinationAgent " , m_Id . GetAgentId ( ) . ToString ( ) } ,
{ " receivingInterface " , m_Id . GetInterfaceId ( ) . ToString ( ) } ,
{ " isNeighbour " , m_IsNeighbour } ,
} ;
// Add state indicators if needed.
if ( ! m_ErrorState . empty ( ) )
profile [ " error " ] = m_ErrorState ;
// Return profile.
return profile ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Route : : RunCommand ( ByteView commandWithArguments )
2019-09-02 10:28:14 +00:00
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Relay : : Relay ( std : : weak_ptr < Profiler > owner , AgentId agentId , BuildId buildId , int32_t lastSeen )
2019-09-02 10:28:14 +00:00
: ProfileElement ( owner )
, m_Id ( agentId )
, m_BuildId ( buildId )
, m_LastSeen ( lastSeen )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Relay : : ParseAndRunCommand ( json const & jCommandElement ) noexcept ( false )
2019-09-02 10:28:14 +00:00
{
throw std : : runtime_error ( " Relay::ParseAndRunCommand should be overriden " ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Relay : : RunCommand ( ByteView commandWithArguments )
2019-09-02 10:28:14 +00:00
{
throw std : : runtime_error ( " Relay::RunCommand should be overriden " ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Channel * FSecure : : C3 : : Core : : Profiler : : Relay : : ReAddChannel ( Device : : Id did , HashT typeNameHash , bool isReturnChannel /*= false*/ , bool isNegotiationChannel /*= false*/ )
2019-09-02 10:28:14 +00:00
{
auto ret = m_Channels . Add ( did , Channel { m_Owner , did , typeNameHash , isReturnChannel , isNegotiationChannel } ) ;
return ret ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Device * FSecure : : C3 : : Core : : Profiler : : Relay : : ReAddPeripheral ( Device : : Id did , HashT typeNameHash )
2019-09-02 10:28:14 +00:00
{
auto ret = m_Peripherals . Add ( did , Device { m_Owner , did , typeNameHash } ) ;
return ret ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Relay : : ReAddRoute ( RouteId receivingRid , DeviceId outgoingInterface , bool isNeighbour )
2019-09-02 10:28:14 +00:00
{
m_Routes . Add ( receivingRid , Route { m_Owner , receivingRid , outgoingInterface , isNeighbour } ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Relay : : ReRemoveRoute ( RouteId rid )
2019-09-02 10:28:14 +00:00
{
m_Routes . Remove ( rid ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : DeviceId FSecure : : C3 : : Core : : Profiler : : Relay : : FindDirectionDevice ( AgentId aid )
2019-09-02 10:28:14 +00:00
{
auto & routes = m_Routes . GetUnderlyingContainer ( ) ;
auto it = std : : find_if ( routes . begin ( ) , routes . end ( ) , [ & ] ( auto & e ) { return e . m_Id . GetAgentId ( ) = = aid ; } ) ;
if ( it = = routes . end ( ) )
throw std : : logic_error { " There is no route to provided agent " } ;
return it - > m_OutgoingDevice ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
void FSecure : : C3 : : Core : : Profiler : : Gateway : : Connector : : RunCommand ( ByteView commandWithArguments )
2019-09-02 10:28:14 +00:00
{
if ( auto pin = m_Connector . lock ( ) ; pin )
pin - > RunCommand ( commandWithArguments ) ;
else
throw std : : runtime_error { " Connector cannot be obtained " } ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Gateway : : Connector : : Connector ( std : : weak_ptr < Profiler > owner , Id id , std : : shared_ptr < ConnectorBridge > connector )
2019-09-02 10:28:14 +00:00
: ProfileElement ( owner )
, m_Id ( id )
, m_Connector ( connector )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Profile : : Profile ( Gateway & gateway )
2019-09-02 10:28:14 +00:00
: m_Gateway ( gateway )
, m_Lock ( m_Mutex )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : ProfileElement : : CreateProfileSnapshot ( ) const
2019-09-02 10:28:14 +00:00
{
// Start with empty JSON.
json profile ;
if ( ! m_ErrorState . empty ( ) )
profile [ " error " ] = m_ErrorState ;
// Done.
return profile ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : ProfileElement : : ProfileElement ( std : : weak_ptr < Profiler > owner ) : m_Owner ( owner )
2019-09-02 10:28:14 +00:00
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : Gateway : : Connector : : CreateProfileSnapshot ( ) const
2019-09-02 10:28:14 +00:00
{
auto profile = __super : : CreateProfileSnapshot ( ) ;
profile [ " iId " ] = Identifier ( m_Id ) . ToString ( ) ;
profile [ " type " ] = m_Id ;
profile [ " startupCommand " ] = m_StartupArguments ;
if ( auto lock = m_Connector . lock ( ) ; lock & & ! lock - > GetErrorStatus ( ) . empty ( ) )
profile [ " error " ] = lock - > GetErrorStatus ( ) ;
return profile ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : Device : : CreateProfileSnapshot ( ) const
2019-09-02 10:28:14 +00:00
{
auto profile = __super : : CreateProfileSnapshot ( ) ;
profile [ " iId " ] = m_Id . ToString ( ) ;
profile [ " type " ] = m_TypeHash ;
profile [ " startupCommand " ] = m_StartupArguments ;
2020-03-05 15:30:50 +00:00
profile [ " jitter " ] = { FSecure : : Utils : : DoubleSeconds ( m_Jitter . first ) . count ( ) , FSecure : : Utils : : DoubleSeconds ( m_Jitter . second ) . count ( ) } ;
2019-09-02 10:28:14 +00:00
// get error here.
return profile ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : Channel : : Channel ( std : : weak_ptr < Profiler > owner , Id id , HashT typeHash , bool isReturnChannel /*= false*/ , bool isNegotiationChannel /*= false*/ )
2019-09-02 10:28:14 +00:00
: Device ( owner , id , typeHash )
, m_IsReturnChannel ( isReturnChannel )
, m_IsNegotiationChannel ( isNegotiationChannel )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json FSecure : : C3 : : Core : : Profiler : : Channel : : CreateProfileSnapshot ( ) const
2019-09-02 10:28:14 +00:00
{
auto profile = __super : : CreateProfileSnapshot ( ) ;
profile [ " isReturnChannel " ] = m_IsReturnChannel ;
profile [ " isNegotiationChannel " ] = m_IsNegotiationChannel ;
return profile ;
}
2019-11-25 11:27:30 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
FSecure : : C3 : : Core : : Profiler : : SnapshotProxy : : SnapshotProxy ( Profiler & profiler ) :
2019-11-25 11:27:30 +00:00
m_Profiler ( profiler )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
bool FSecure : : C3 : : Core : : Profiler : : SnapshotProxy : : CheckUpdates ( )
2019-11-25 11:27:30 +00:00
{
2019-11-25 12:29:20 +00:00
m_CurrentSnapshot = m_Profiler . Get ( ) . m_Gateway . CreateProfileSnapshot ( ) ;
auto currentHash = std : : hash < json > { } ( m_CurrentSnapshot ) ;
if ( m_PreviousHash & & currentHash = = * m_PreviousHash )
return false ;
2019-11-25 11:27:30 +00:00
2019-11-25 12:29:20 +00:00
m_PreviousHash = currentHash ;
return true ;
2019-11-25 11:27:30 +00:00
}
2019-11-25 12:29:20 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2020-03-05 15:30:50 +00:00
json const & FSecure : : C3 : : Core : : Profiler : : SnapshotProxy : : GetSnapshot ( ) const
2019-11-25 12:29:20 +00:00
{
return m_CurrentSnapshot ;
}