Ejemplo n.º 1
0
static void handleQuery(Game *game, const Address &remoteAddress, Socket &socket, BitStream *stream)
{
   TNLAssert(game->isServer(), "Expected this to be a server!");

   Nonce nonce;
   U32 clientIdentityToken;

   nonce.read(stream);
   stream->read(&clientIdentityToken);

   if(clientIdentityToken == computeSimpleToken(nonce))
   {
      PacketStream queryResponse;
      queryResponse.write(U8(GameNetInterface::QueryResponse));

      nonce.write(&queryResponse);
      queryResponse.writeStringTableEntry(game->getSettings()->getHostName());
      queryResponse.writeStringTableEntry(game->getSettings()->getHostDescr());

      queryResponse.write(game->getPlayerCount());
      queryResponse.write(game->getMaxPlayers());
      queryResponse.write(game->getRobotCount());
      queryResponse.writeFlag(game->isDedicated());
      queryResponse.writeFlag(game->isTestServer());
      queryResponse.writeFlag(game->getSettings()->getServerPassword() != "");

      queryResponse.write(game->getClientId());  // older 019 ignore this or won't read this

      queryResponse.sendto(socket, remoteAddress);
   }
}
Ejemplo n.º 2
0
void NetInterface::handleConnectChallengeResponse(const Address &address, BitStream *stream)
{
   NetConnection *conn = findPendingConnection(address);
   if(!conn || conn->getConnectionState() != NetConnection::AwaitingChallengeResponse)
      return;
   
   Nonce theNonce;
   theNonce.read(stream);

   ConnectionParameters &theParams = conn->getConnectionParameters();
   if(theNonce != theParams.mNonce)
      return;

   stream->read(&theParams.mClientIdentity);

   // see if the server wants us to solve a client puzzle
   theParams.mServerNonce.read(stream);
   stream->read(&theParams.mPuzzleDifficulty);

   if(theParams.mPuzzleDifficulty > ClientPuzzleManager::MaxPuzzleDifficulty)
      return;

   // see if the connection needs to be authenticated or uses key exchange
   if(stream->readFlag())
   {
      if(stream->readFlag())
      {
         theParams.mCertificate = new Certificate(stream);
         if(!theParams.mCertificate->isValid() || !conn->validateCertficate(theParams.mCertificate, true))
            return;         
         theParams.mPublicKey = theParams.mCertificate->getPublicKey();
      }
      else
      {
         theParams.mPublicKey = new AsymmetricKey(stream);
         if(!theParams.mPublicKey->isValid() || !conn->validatePublicKey(theParams.mPublicKey, true))
            return;
      }
      if(mPrivateKey.isNull() || mPrivateKey->getKeySize() != theParams.mPublicKey->getKeySize())
      {
         // we don't have a private key, so generate one for this connection
         theParams.mPrivateKey = new AsymmetricKey(theParams.mPublicKey->getKeySize());
      }
      else
         theParams.mPrivateKey = mPrivateKey;
      theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey);
      //logprintf("shared secret (client) %s", theParams.mSharedSecret->encodeBase64()->getBuffer());
      Random::read(theParams.mSymmetricKey, SymmetricCipher::KeySize);
      theParams.mUsingCrypto = true;
   }

   TNLLogMessageV(LogNetInterface, ("Received Challenge Response: %8x", theParams.mClientIdentity ));

   conn->setConnectionState(NetConnection::ComputingPuzzleSolution);
   conn->mConnectSendCount = 0;

   theParams.mPuzzleSolution = 0;
   conn->mConnectLastSendTime = getCurrentTime();
   continuePuzzleSolution(conn);   
}
Ejemplo n.º 3
0
static void handleQueryResponse(Game *game, const Address &remoteAddress, BitStream *stream)
{
   TNLAssert(!game->isServer(), "Expected this to be a client!");

   Nonce nonce;
   StringTableEntry name;
   StringTableEntry descr;
   U32 playerCount, maxPlayers, botCount;
   bool dedicated, test, passwordRequired;

   nonce.read(stream);
   stream->readStringTableEntry(&name);
   stream->readStringTableEntry(&descr);

   stream->read(&playerCount);
   stream->read(&maxPlayers);
   stream->read(&botCount);
   dedicated = stream->readFlag();
   test = stream->readFlag();
   passwordRequired = stream->readFlag();

   if(!stream->isValid())
      return;

   S32 serverId;
   if(!stream->read(&serverId))  // If we can't read (goes past the end of data size from older 019)
      serverId = 0;              // then set this to zero

   // Alert the user
   game->gotQueryResponse(remoteAddress, serverId, nonce, name.getString(), descr.getString(), 
                          playerCount, maxPlayers, botCount, dedicated, test, passwordRequired);
}
Ejemplo n.º 4
0
int main(int argc, const char **argv)
{
   if(argc < 2)
   {
      printf("Usage: tnlping <remoteAddress> [sourceAddress]\n\n"
      "Example 1: Simple usage expecting port 28000\n   tnlping 192.168.1.2\n\n"
      "Example 2: Advanced usage with specific port\n   tnlping 192.168.1.2:28001\n\n");
      return 1;
   }
   
   U8 randData[sizeof(U32) + sizeof(S64)];
   *((U32 *) randData) = Platform::getRealMilliseconds();
   *((S64 *) (randData + sizeof(U32))) = Platform::getHighPrecisionTimerValue();
   TNL::Random::addEntropy(randData, sizeof(randData));

   Address remoteAddress(argv[1]);
   Address sourceAddress(argc > 2 ? argv[2] : "IP:Any:0");

   Nonce clientNonce;
   clientNonce.getRandom();

   Socket sourceSocket(sourceAddress);

   PacketStream out;
   out.write(U8(NetInterface::ConnectChallengeRequest));
   clientNonce.write(&out);
   out.writeFlag(false);
   out.writeFlag(false);

   for(U32 tryCount = 0; tryCount < 5; tryCount++)
   {
      U32 time = Platform::getRealMilliseconds();
      out.sendto(sourceSocket, remoteAddress);
      for(;;)
      {
         PacketStream incoming;
         Address incomingAddress;
         if(incoming.recvfrom(sourceSocket, &incomingAddress) == NoError)
         {
            U8 packetType;
            Nonce theNonce;
            incoming.read(&packetType);
            theNonce.read(&incoming);
            if(packetType == NetInterface::ConnectChallengeResponse && theNonce == clientNonce)
            {
               printf("TNL Service is UP (pingtime = %d)\n", Platform::getRealMilliseconds() - time);
               return 0;
            }
         }
         Platform::sleep(1);
         if(Platform::getRealMilliseconds() - time > 1000)
            break;
      }
   }
   
   printf("TNL Service is DOWN\n");
   
   return 1;
}
Ejemplo n.º 5
0
void NetInterface::handleConnectChallengeRequest(const Address &addr, BitStream *stream)
{
   TNLLogMessageV(LogNetInterface, ("Received Connect Challenge Request from %s", addr.toString()));

   if(!mAllowConnections)
      return;
   Nonce clientNonce;
   clientNonce.read(stream);
   bool wantsKeyExchange = stream->readFlag();
   bool wantsCertificate = stream->readFlag();

   sendConnectChallengeResponse(addr, clientNonce, wantsKeyExchange, wantsCertificate);
}
void NetInterface::handleConnectReject(const Address &address, BitStream *stream)
{
   Nonce nonce;
   Nonce serverNonce;

   nonce.read(stream);
   serverNonce.read(stream);

   NetConnection *conn = findPendingConnection(address);
   if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse &&
                conn->getConnectionState() != NetConnection::AwaitingConnectResponse))
      return;
   ConnectionParameters &p = conn->getConnectionParameters();
   if(p.mNonce != nonce || p.mServerNonce != serverNonce)
      return;


   NetConnection::TerminationReason reason = (NetConnection::TerminationReason) stream->readEnum(NetConnection::TerminationReasons);

   char reasonStr[256];
   stream->readString(reasonStr);

   logprintf(LogConsumer::LogNetInterface, "Received Connect Reject - reason code %d (%s)", reason, reasonStr);

   // If the reason is a bad puzzle solution, try once more with a new nonce
   if(reason == NetConnection::ReasonPuzzle && !p.mPuzzleRetried)
   {
      p.mPuzzleRetried = true;
      conn->setConnectionState(NetConnection::AwaitingChallengeResponse);
      conn->mConnectSendCount = 0;
      p.mNonce.getRandom();                  // Generate new nonce
      sendConnectChallengeRequest(conn);
      return;
   }

   conn->setConnectionState(NetConnection::ConnectRejected);
   conn->onConnectTerminated(reason, reasonStr);
   removePendingConnection(conn);
}
Ejemplo n.º 7
0
void NetInterface::handleConnectReject(const Address &address, BitStream *stream)
{
   Nonce nonce;
   Nonce serverNonce;

   nonce.read(stream);
   serverNonce.read(stream);

   NetConnection *conn = findPendingConnection(address);
   if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse &&
                conn->getConnectionState() != NetConnection::AwaitingConnectResponse))
      return;
   ConnectionParameters &p = conn->getConnectionParameters();
   if(p.mNonce != nonce || p.mServerNonce != serverNonce)
      return;

   char reason[256];
   stream->readString(reason);

   TNLLogMessageV(LogNetInterface, ("Received Connect Reject - reason %s", reason));
   // if the reason is a bad puzzle solution, try once more with a
   // new nonce.
   if(!strcmp(reason, "Puzzle") && !p.mPuzzleRetried)
   {
      p.mPuzzleRetried = true;
      conn->setConnectionState(NetConnection::AwaitingChallengeResponse);
      conn->mConnectSendCount = 0;
      p.mNonce.getRandom();
      sendConnectChallengeRequest(conn);
      return;
   }

   conn->setConnectionState(NetConnection::ConnectRejected);
   conn->onConnectTerminated(NetConnection::ReasonRemoteHostRejectedConnection, reason);
   removePendingConnection(conn);
}
Ejemplo n.º 8
0
// Process response to Ping, written in handlePing(), above
static void handlePingResponse(Game *game, const Address &remoteAddress, BitStream *stream)
{
   TNLAssert(!game->isServer(), "Expected this to be a client!");

   Nonce nonce;
   U32 clientIdentityToken;
   S32 serverId;

   nonce.read(stream);
   stream->read(&clientIdentityToken);

   if(!stream->isValid())
      return;

   if(!stream->read(&serverId))   // If we can't read (goes past the end of data size from older 019)
      serverId = 0;               // then set this to zero

   game->gotPingResponse(remoteAddress, nonce, clientIdentityToken, serverId);
}
Ejemplo n.º 9
0
static void handlePing(Game *game, const Address &remoteAddress, Socket &socket, BitStream *stream, S32 clientId)
{
   TNLAssert(game->isServer(), "Expected this to be a server!");

   Nonce clientNonce;
   clientNonce.read(stream);

   U32 protocolVersion;
   stream->read(&protocolVersion);

   if(protocolVersion != CS_PROTOCOL_VERSION)   // Ignore pings from incompatible versions
      return;

   U32 clientIdentityToken = computeSimpleToken(clientNonce);
   PacketStream pingResponse;

   pingResponse.write(U8(GameNetInterface::PingResponse));
   clientNonce.write(&pingResponse);
   pingResponse.write(clientIdentityToken);

   pingResponse.write(clientId);  // older 019 ignore this or won't read this

   pingResponse.sendto(socket, remoteAddress);
}
Ejemplo n.º 10
0
void NetInterface::handlePunch(const Address &theAddress, BitStream *stream)
{
   S32 i, j;
   NetConnection *conn;

   Nonce firstNonce;
   firstNonce.read(stream);

   ByteBuffer b(firstNonce.data, Nonce::NonceSize);

   TNLLogMessageV(LogNetInterface, ("Received punch packet from %s - %s", theAddress.toString(), b.encodeBase64()->getBuffer()));

   for(i = 0; i < mPendingConnections.size(); i++)
   {
      conn = mPendingConnections[i];
      ConnectionParameters &theParams = conn->getConnectionParameters();

      if(conn->getConnectionState() != NetConnection::SendingPunchPackets)
         continue;

      if((theParams.mIsInitiator && firstNonce != theParams.mServerNonce) ||
            (!theParams.mIsInitiator && firstNonce != theParams.mNonce))
         continue;

      // first see if the address is in the possible addresses list:
      
      for(j = 0; j < theParams.mPossibleAddresses.size(); j++)
         if(theAddress == theParams.mPossibleAddresses[j])
            break;

      // if there was an exact match, just exit the loop, or
      // continue on to the next pending if this is not an initiator:
      if(j != theParams.mPossibleAddresses.size())
      {
         if(theParams.mIsInitiator)
            break;
         else
            continue;
      }

      // if there was no exact match, we may have a funny NAT in the
      // middle.  But since a packet got through from the remote host
      // we'll want to send a punch to the address it came from, as long
      // as only the port is not an exact match:
      for(j = 0; j < theParams.mPossibleAddresses.size(); j++)
         if(theAddress.isEqualAddress(theParams.mPossibleAddresses[j]))
            break;

      // if the address wasn't even partially in the list, just exit out
      if(j == theParams.mPossibleAddresses.size())
         continue;

      // otherwise, as long as we don't have too many ping addresses,
      // add this one to the list:
      if(theParams.mPossibleAddresses.size() < 5)
         theParams.mPossibleAddresses.push_back(theAddress);      

      // if this is the initiator of the arranged connection, then
      // process the punch packet from the remote host by issueing a
      // connection request.
      if(theParams.mIsInitiator)
         break;
   }
   if(i == mPendingConnections.size())
      return;

   ConnectionParameters &theParams = conn->getConnectionParameters();
   SymmetricCipher theCipher(theParams.mArrangedSecret);
   if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, stream->getBytePosition(), &theCipher))
      return;

   Nonce nextNonce;
   nextNonce.read(stream);

   if(nextNonce != theParams.mNonce)
      return;

   // see if the connection needs to be authenticated or uses key exchange
   if(stream->readFlag())
   {
      if(stream->readFlag())
      {
         theParams.mCertificate = new Certificate(stream);
         if(!theParams.mCertificate->isValid() || !conn->validateCertficate(theParams.mCertificate, true))
            return;         
         theParams.mPublicKey = theParams.mCertificate->getPublicKey();
      }
      else
      {
         theParams.mPublicKey = new AsymmetricKey(stream);
         if(!theParams.mPublicKey->isValid() || !conn->validatePublicKey(theParams.mPublicKey, true))
            return;
      }
      if(mPrivateKey.isNull() || mPrivateKey->getKeySize() != theParams.mPublicKey->getKeySize())
      {
         // we don't have a private key, so generate one for this connection
         theParams.mPrivateKey = new AsymmetricKey(theParams.mPublicKey->getKeySize());
      }
      else
         theParams.mPrivateKey = mPrivateKey;
      theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey);
      //logprintf("shared secret (client) %s", theParams.mSharedSecret->encodeBase64()->getBuffer());
      Random::read(theParams.mSymmetricKey, SymmetricCipher::KeySize);
      theParams.mUsingCrypto = true;
   }
   conn->setNetAddress(theAddress);
   TNLLogMessageV(LogNetInterface, ("Punch from %s matched nonces - connecting...", theAddress.toString()));

   conn->setConnectionState(NetConnection::AwaitingConnectResponse);
   conn->mConnectSendCount = 0;
   conn->mConnectLastSendTime = getCurrentTime();

   sendArrangedConnectRequest(conn);
}