/* * Modification History * * 2003-June-27 Jason Rohrer * Created. * * 2003-August-7 Jason Rohrer * Added a duplicate message detector. * * 2003-August-8 Jason Rohrer * Switched log to file output. * Added functions for getting and setting target connection count. * * 2003-August-11 Jason Rohrer * Added stopping log messages. * * 2003-August-12 Jason Rohrer * Changed to tell duplicate detector about our locally generated messages. * * 2003-August-13 Jason Rohrer * Added use of unique node name to prevent self and multiple connections. * * 2003-August-14 Jason Rohrer * Made unique name function publicly available. * Added a function for getting connected host list. * * 2003-August-24 Jason Rohrer * Added generation of node RSA keys. * Added functions for seeding the random number generator. * * 2003-August-25 Jason Rohrer * Added support for registering message handler functions. * Replaced local info hash with secure random string for unique names. * * 2003-October-9 Jason Rohrer * Added support for message limiters. * * 2003-October-12 Jason Rohrer * Switched to a floating point limit. * Added use of message ID tracker. * * 2003-November-2 Jason Rohrer * Switched inbound limit setting function to a floating point limit. * * 2003-November-24 Jason Rohrer * Added support for flags. * * 2003-December-5 Jason Rohrer * Added support for message utility. * * 2004-January-11 Jason Rohrer * Made include paths explicit to help certain compilers. * * 2004-February-4 Jason Rohrer * Added utility functions for modifying flag strings. * * 2004-February-20 Jason Rohrer * Added function for getting info about current connection attempt. * * 2004-March-1 Jason Rohrer * Added function for generating message IDs. * * 2004-March-9 Jason Rohrer * Added support for new FORWARD scheme. * * 2004-March-15 Jason Rohrer * Added forward hash code that was originally in ChannelReceivingThread.cpp. * Added code to ensure that forward hash seed is forwardable. * * 2004-March-19 Jason Rohrer * Added support for DROP tails. * * 2004-March-23 Jason Rohrer * Added a maximum connection count. */ #include "MUTE/layers/messageRouting/messageRouter.h" #include "MUTE/layers/messageRouting/ConnectionMaintainer.h" #include "MUTE/layers/messageRouting/OutboundChannelManager.h" #include "MUTE/layers/messageRouting/LocalAddressReceiver.h" #include "MUTE/layers/messageRouting/ServerThread.h" #include "MUTE/layers/messageRouting/MessageIDTracker.h" #include "MUTE/common/CryptoUtils.h" #include "minorGems/network/p2pParts/HostCatcher.h" #include "minorGems/network/p2pParts/MessagePerSecondLimiter.h" #include "minorGems/network/HostAddress.h" #include "minorGems/util/random/StdRandomSource.h" #include "minorGems/util/stringUtils.h" #include "minorGems/util/SettingsManager.h" #include "minorGems/util/SimpleVector.h" #include "minorGems/crypto/hashes/sha1.h" #include "minorGems/util/log/AppLog.h" #include "minorGems/util/log/FileLog.h" #include // static data elements OutboundChannelManager *muteOutboundChannelManager = NULL; LocalAddressReceiver *muteLocalAddressReceiver = NULL; ConnectionMaintainer *muteConnectionMaintainer = NULL; HostCatcher *muteHostCatcher = NULL; MessageIDTracker *muteMessageIDTracker = NULL; MessagePerSecondLimiter *muteOutboundMessagePerSecondLimiter = NULL; MessagePerSecondLimiter *muteInboundMessagePerSecondLimiter = NULL; char *muteNodeUniqueName = NULL; unsigned int mutePort = 0; ServerThread *muteServerThread = NULL; StdRandomSource *muteRandomSource = NULL; char *muteForwardHashSeed = NULL; double muteContinueForwardProbability = 0.5; char muteDropTailChainMessages = false; int muteDropTailTreeStartingTTL = 2; void muteSeedRandomGenerator( char *inSeedString ) { CryptoUtils::seedRandomGenerator( inSeedString ); } char *muteGetRandomGeneratorState() { return CryptoUtils::getRandomGeneratorState(); } void muteStart( unsigned int inPort ) { AppLog::setLog( new FileLog( "MUTE.log" ) ); AppLog::setLoggingLevel( Log::TRACE_LEVEL ); char *loggerName = "messageRouter"; // load RSA keys char *nodePublicKey = SettingsManager::getStringSetting( "nodePublicKey" ); char *nodePrivateKey = SettingsManager::getStringSetting( "nodePrivateKey" ); if( nodePublicKey == NULL || strcmp( nodePublicKey, "" ) == 0 || nodePrivateKey == NULL || strcmp( nodePrivateKey, "" ) == 0 ) { if( nodePublicKey != NULL ) { delete [] nodePublicKey; } if( nodePrivateKey != NULL ) { delete [] nodePrivateKey; } char keyLengthFound; int keyLength = SettingsManager::getIntSetting( "nodeKeySize", &keyLengthFound ); if( !keyLengthFound ) { // defaults to 1024 keyLength = 1024; } printf( "Generating %d-bit RSA key pair for node connections...\n", keyLength ); CryptoUtils::generateRSAKey( keyLength, &nodePublicKey, &nodePrivateKey ); printf( "...done\n" ); SettingsManager::setSetting( "nodePublicKey", nodePublicKey ); SettingsManager::setSetting( "nodePrivateKey", nodePrivateKey ); } delete [] nodePublicKey; delete [] nodePrivateKey; muteRandomSource = new StdRandomSource(); muteNodeUniqueName = muteGetUniqueName(); // read our setting for the probability of continuing to forward a message char found; float continueForwardProbabilitySetting = SettingsManager::getFloatSetting( "continueForwardProbability", &found ); if( found ) { muteContinueForwardProbability = continueForwardProbabilitySetting; } else { // default to 50% muteContinueForwardProbability = 0.5; } // make sure our forward probability is positive if( muteContinueForwardProbability <= 0 ) { // default to 50% if not muteContinueForwardProbability = 0.5; } // read our setting for the probability of dropping tail chain messages float tailChainDropProbability = SettingsManager::getFloatSetting( "tailChainDropProbability", &found ); if( !found ) { tailChainDropProbability = 0.5; } // using this drop probability, decide whether we will pass or // drop all tail chain messages if( muteRandomSource->getRandomFloat() <= tailChainDropProbability ) { muteDropTailChainMessages = true; } else { muteDropTailChainMessages = false; } // pick a TTL that matches the expected length of our drop chain muteDropTailTreeStartingTTL = (int)( 1.0 / tailChainDropProbability ); // keep picking hash seeds until we find one that we would // forward according to our forward probability muteForwardHashSeed = CryptoUtils::getRandomHexString( 20 ); // re-hash our seed to see if it produces a new hash that would // be forwarded char *newHashSeed = muteComputeNewForwardHash( muteForwardHashSeed ); // while new hash would not be forwarded while( newHashSeed == NULL ) { char *logMessage = autoSprintf( "Picked %s as forward hash seed, " "but it does not re-hash to a " "forwardable hash, so picking again.", muteForwardHashSeed ); AppLog::info( loggerName, logMessage ); delete [] logMessage; delete [] muteForwardHashSeed; muteForwardHashSeed = CryptoUtils::getRandomHexString( 20 ); newHashSeed = muteComputeNewForwardHash( muteForwardHashSeed ); } // we have found a new hash seed that would be forwarded // use this new hash seed as our hash seed delete [] muteForwardHashSeed; muteForwardHashSeed = newHashSeed; char *logMessage = autoSprintf( "Chose a forward hash seed: %s", muteForwardHashSeed ); AppLog::info( loggerName, logMessage ); delete [] logMessage; muteOutboundChannelManager = new OutboundChannelManager( muteRandomSource ); muteLocalAddressReceiver = new LocalAddressReceiver(); muteHostCatcher = new HostCatcher( 50 ); muteMessageIDTracker = new MessageIDTracker( 100 ); double outboundLimit = SettingsManager::getFloatSetting( "outboundMessageLimit", &found ); if( !found ) { outboundLimit = -1; } muteOutboundMessagePerSecondLimiter = new MessagePerSecondLimiter( outboundLimit ); double inboundLimit = SettingsManager::getFloatSetting( "inboundMessageLimit", &found ); if( !found ) { inboundLimit = -1; } muteInboundMessagePerSecondLimiter = new MessagePerSecondLimiter( inboundLimit ); // load any seed hosts SimpleVector *seedHostVector = SettingsManager::getSetting( "seedHosts" ); int vectorSize = seedHostVector->size(); if( vectorSize % 2 != 0 ) { printf( "seedHosts settings file not properly formatted\n" ); for( int i=0; igetElement( i ) ) ); } } else { int numSeedHosts = vectorSize / 2; for( int i=0; igetElement( 2 * i ) ); char *portString = *( seedHostVector->getElement( 2 * i + 1 ) ); int port; int numRead = sscanf( portString, "%d", &port ); if( numRead == 1 ) { HostAddress *host = new HostAddress( stringDuplicate( addressString ), port ); muteHostCatcher->addHost( host ); delete host; } else { printf( "seedHosts settings file not properly formatted\n" ); } delete [] addressString; delete [] portString; } } delete seedHostVector; mutePort = inPort; muteConnectionMaintainer = new ConnectionMaintainer( mutePort, muteNodeUniqueName, muteLocalAddressReceiver, muteOutboundChannelManager, muteHostCatcher, muteMessageIDTracker, muteOutboundMessagePerSecondLimiter, muteInboundMessagePerSecondLimiter ); muteServerThread = new ServerThread( mutePort, muteConnectionMaintainer ); } void muteStop() { char *loggerName = "messageRouter"; if( muteServerThread != NULL ) { AppLog::info( loggerName, "Destroying ServerThread." ); delete muteServerThread; muteServerThread = NULL; } if( muteConnectionMaintainer != NULL ) { AppLog::info( loggerName, "Destroying Connectionmaintainer." ); delete muteConnectionMaintainer; muteConnectionMaintainer = NULL; } if( muteHostCatcher != NULL ) { AppLog::info( loggerName, "Destroying HostCatcher." ); delete muteHostCatcher; muteHostCatcher = NULL; } if( muteMessageIDTracker != NULL ) { AppLog::info( loggerName, "Destroying MessageIDTracker." ); delete muteMessageIDTracker; muteMessageIDTracker = NULL; } if( muteOutboundMessagePerSecondLimiter != NULL ) { AppLog::info( loggerName, "Destroying outbound MessagePerSecondLimiter." ); delete muteOutboundMessagePerSecondLimiter; muteOutboundMessagePerSecondLimiter = NULL; } if( muteInboundMessagePerSecondLimiter != NULL ) { AppLog::info( loggerName, "Destroying inbound MessagePerSecondLimiter." ); delete muteInboundMessagePerSecondLimiter; muteInboundMessagePerSecondLimiter = NULL; } if( muteLocalAddressReceiver != NULL ) { AppLog::info( loggerName, "Destroying LocalAddressReceiver." ); delete muteLocalAddressReceiver; muteLocalAddressReceiver = NULL; } if( muteOutboundChannelManager != NULL ) { AppLog::info( loggerName, "Destroying OutboundChannelManager." ); delete muteOutboundChannelManager; muteOutboundChannelManager = NULL; } if( muteNodeUniqueName != NULL ) { AppLog::info( loggerName, "Destroying node's unique name." ); delete [] muteNodeUniqueName; muteNodeUniqueName = NULL; } if( muteForwardHashSeed != NULL ) { AppLog::info( loggerName, "Destroying node's forward hash seed." ); delete [] muteForwardHashSeed; muteForwardHashSeed = NULL; } if( muteRandomSource != NULL ) { AppLog::info( loggerName, "Destroying RandomSource." ); delete muteRandomSource; muteRandomSource = NULL; } } void muteAddHost( char *inAddress, unsigned int inPort ) { HostAddress *address = new HostAddress( stringDuplicate( inAddress ), inPort ); muteHostCatcher->addHost( address ); delete address; } void muteSetTargetNumberOfConnections( int inTarget ) { muteConnectionMaintainer->setTargetConnectionCount( inTarget ); } int muteGetTargetNumberOfConnections() { return muteConnectionMaintainer->getTargetConnectionCount(); } void muteSetMaxNumberOfConnections( int inMax ) { muteConnectionMaintainer->setMaxConnectionCount( inMax ); } int muteGetMaxNumberOfConnections() { return muteConnectionMaintainer->getMaxConnectionCount(); } int muteGetConnectedHostList( char ***outHostAddresses, int **outHostPorts, int **outSentMessageCounts, int **outQueuedMessageCounts, int **outDroppedMessageCounts ) { SimpleVector *addressList = muteOutboundChannelManager->getConnectedHosts( outSentMessageCounts, outQueuedMessageCounts, outDroppedMessageCounts ); int count = addressList->size(); char **addresses = new char*[ count ]; int *ports = new int[ count ]; for( int i=0; igetElement( i ) ); addresses[i] = stringDuplicate( host->mAddressString ); ports[i] = host->mPort; delete host; } *outHostAddresses = addresses; *outHostPorts = ports; delete addressList; return count; } char muteGetCurrentConnectionAttempt( char **outHostAddress, int *outPort ) { return muteConnectionMaintainer->getCurrentConnectionAttempt( outHostAddress, outPort ); } void muteSetOutboundMessagePerSecondLimit( double inLimitPerSecond ) { SettingsManager::setSetting( "outboundMessageLimit", (float)inLimitPerSecond ); muteOutboundMessagePerSecondLimiter->setLimit( inLimitPerSecond ); } double muteGetOutboundMessagePerSecondLimit() { return muteOutboundMessagePerSecondLimiter->getLimit(); } void muteSetInboundMessagePerSecondLimit( double inLimitPerSecond ) { SettingsManager::setSetting( "inboundMessageLimit", (float)inLimitPerSecond ); muteInboundMessagePerSecondLimiter->setLimit( inLimitPerSecond ); } double muteGetInboundMessagePerSecondLimit() { return muteInboundMessagePerSecondLimiter->getLimit(); } void muteAddReceiveAddress( char *inAddress ) { muteLocalAddressReceiver->addReceiveAddress( inAddress ); } void muteRemoveReceiveAddress( char *inAddress ) { muteLocalAddressReceiver->removeReceiveAddress( inAddress ); } void muteSendMessage( char *inFromAddress, char *inToAddress, char *inMessage, char *inFlags ) { // generate an ID for this outbound message char *messageID = muteGetFreshMessageID(); //printf( "Registering outbound ID %s\n", messageID ); // tell the ID tracker about our message so that we will drop // it if it gets routed back through us muteMessageIDTracker->checkIfIDFresh( messageID ); char *flags; if( inFlags != NULL ) { flags = inFlags; } else { flags = "NONE"; } if( strstr( flags, "FRESH_ROUTE" ) ) { // clear the routing information in the outbound direction muteOutboundChannelManager-> clearRoutingInformation( inToAddress ); // we don't need to clear routes for inFromAddress, since it is // our address and we shouldn't have any routing information for it } // send the message // a fresh message has 0 utility so far, but the channel manager // will add chaff to protect our identity muteOutboundChannelManager->routeMessage( messageID, inFromAddress, inToAddress, flags, 0, // utility inMessage ); delete [] messageID; } int muteAddMessageHandler( int (*inHandlerFunction)( char *, char *, char *, void * ), void *inExtraHandlerArgument ) { return muteLocalAddressReceiver->addMessageHandler( inHandlerFunction, inExtraHandlerArgument ); } void muteRemoveMessageHandler( int inHandlerID ) { muteLocalAddressReceiver->removeMessageHandler( inHandlerID ); } unsigned int muteGetWaitingMessageCount( char *inAddress ) { return muteLocalAddressReceiver->getWaitingMessageCount( inAddress ); } unsigned int muteGetReceivedMessages( char *inAddress, unsigned int inNumMessages, char ***outMessages, char ***outFromAddresses ) { return muteLocalAddressReceiver->getReceivedMessages( inAddress, inNumMessages, outMessages, outFromAddresses ); } char *muteGetUniqueName() { return CryptoUtils::getRandomHexString( 20 ); } char *muteGetFreshMessageID() { // first, generate a unique name char *uniqueName = muteGetUniqueName(); unsigned int counter = muteMessageIDTracker->getFreshCounter(); char *messageID = autoSprintf( "%s_%u", uniqueName, counter ); delete [] uniqueName; return messageID; } char *muteAddFlag( char *inFlags, char *inFlagToAdd ) { if( strcmp( inFlags, "NONE" ) == 0 ) { // new string only contains inFlagToAdd return stringDuplicate( inFlagToAdd ); } else { // inFlags already contains flags // add inFlagToAdd to the end return autoSprintf( "%s|%s", inFlags, inFlagToAdd ); } } char *muteRemoveFlag( char *inFlags, char *inFlagToRemove ) { if( strstr( inFlags, inFlagToRemove ) == NULL ) { // inFlagToRemove does not exist in inFlags // no change to inFlags return stringDuplicate( inFlags ); } else if( strcmp( inFlags, inFlagToRemove ) == 0 ) { // inFlags contains only inFlagToRemove // return the NONE flag string return stringDuplicate( "NONE" ); } else { // inFlags contains multiple flags, including inFlagToRemove int numOldFlags; char **oldFlags = split( inFlags, "|", &numOldFlags ); SimpleVector *newFlagVector = new SimpleVector(); int i; for( i=0; ipush_back( oldFlags[i] ); } else { // matches inFlagToRemove, delete it delete [] oldFlags[i]; } } delete [] oldFlags; char **newFlags = newFlagVector->getElementArray(); int numNewFlags = newFlagVector->size(); delete newFlagVector; char *newFlagString = join( newFlags, numNewFlags, "|" ); for( i=0; i