diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f66a28f063..dec88f8647 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -42,7 +42,7 @@ int const DomainServer::EXIT_CODE_REBOOT = 234923; -const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; +const QString ICE_SERVER_DEFAULT_HOSTNAME = "localhost"; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), @@ -1053,11 +1053,55 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) { domainUpdateJSON.toUtf8()); } -// TODO: have data-web respond with ice-server hostname to use - void DomainServer::sendHeartbeatToIceServer() { if (!_iceServerSocket.getAddress().isNull()) { - DependencyManager::get()->sendHeartbeatToIceServer(_iceServerSocket); + static auto heartbeatPacket = NLPacket::create(PacketType::ICEServerHeartbeat); + + bool shouldRecreatePacket = false; + + auto limitedNodeList = DependencyManager::get(); + + if (heartbeatPacket->getPayloadSize() > 0) { + // if either of our sockets have changed we need to re-sign the heartbeat + // first read the sockets out from the current packet + heartbeatPacket->seek(0); + QDataStream heartbeatStream(heartbeatPacket.get()); + + QUuid senderUUID; + HifiSockAddr publicSocket, localSocket; + heartbeatStream >> senderUUID >> publicSocket >> localSocket; + + if (publicSocket != limitedNodeList->getPublicSockAddr() || localSocket != limitedNodeList->getLocalSockAddr()) { + shouldRecreatePacket = true; + } + } else { + shouldRecreatePacket = true; + } + + if (shouldRecreatePacket) { + // either we don't have a heartbeat packet yet or sockets have changed and we need to make a new one + + // reset the position in the packet before writing + heartbeatPacket->reset(); + + // write our plaintext data to the packet + QDataStream heartbeatDataStream(heartbeatPacket.get()); + heartbeatDataStream << limitedNodeList->getSessionUUID() + << limitedNodeList->getPublicSockAddr() << limitedNodeList->getLocalSockAddr(); + + // setup a QByteArray that points to the plaintext data + auto plaintext = QByteArray::fromRawData(heartbeatPacket->getPayload(), heartbeatPacket->getPayloadSize()); + + // generate a signature for the plaintext data in the packet + auto& accountManager = AccountManager::getInstance(); + auto signature = accountManager.getAccountInfo().signPlaintext(plaintext); + + // pack the signature with the data + heartbeatDataStream << plaintext; + } + + // send the heartbeat packet to the ice server now + limitedNodeList->sendUnreliablePacket(*heartbeatPacket, _iceServerSocket); } } diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index fc1d8e9458..a24b0b471c 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -33,7 +33,7 @@ #include "AccountManager.h" #include "NetworkLogging.h" -const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; +const bool VERBOSE_HTTP_REQUEST_DEBUGGING = true; AccountManager& AccountManager::getInstance(bool forceReset) { static std::unique_ptr sharedInstance(new AccountManager()); diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 20c7f778c9..706da1ce72 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -117,41 +117,47 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject } QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) { - + QByteArray lowercaseUsername = _username.toLower().toUtf8(); + QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()), + QCryptographicHash::Sha256); + + auto signature = signPlaintext(usernameWithToken); + if (!signature.isEmpty()) { + qDebug(networking) << "Returning username" << _username + << "signed with connection UUID" << uuidStringWithoutCurlyBraces(connectionToken); + } else { + qCDebug(networking) << "Error signing username with connection token"; + qCDebug(networking) << "Will re-attempt on next domain-server check in."; + } + + return signature; +} + +QByteArray DataServerAccountInfo::signPlaintext(const QByteArray& plaintext) { if (!_privateKey.isEmpty()) { const char* privateKeyData = _privateKey.constData(); RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL, reinterpret_cast(&privateKeyData), _privateKey.size()); if (rsaPrivateKey) { - QByteArray lowercaseUsername = _username.toLower().toUtf8(); - QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()), - QCryptographicHash::Sha256); - - QByteArray usernameSignature(RSA_size(rsaPrivateKey), 0); - unsigned int usernameSignatureSize = 0; - + QByteArray signature(RSA_size(rsaPrivateKey), 0); + unsigned int signatureBytes = 0; + int encryptReturn = RSA_sign(NID_sha256, - reinterpret_cast(usernameWithToken.constData()), - usernameWithToken.size(), - reinterpret_cast(usernameSignature.data()), - &usernameSignatureSize, + reinterpret_cast(plaintext.constData()), + plaintext.size(), + reinterpret_cast(signature.data()), + &signatureBytes, rsaPrivateKey); - + // free the private key RSA struct now that we are done with it RSA_free(rsaPrivateKey); - if (encryptReturn == -1) { - qCDebug(networking) << "Error encrypting username signature."; - qCDebug(networking) << "Will re-attempt on next domain-server check in."; - } else { - qDebug(networking) << "Returning username" << _username << "signed with connection UUID" << uuidStringWithoutCurlyBraces(connectionToken); - return usernameSignature; + if (encryptReturn != -1) { + return signature; } - } else { qCDebug(networking) << "Could not create RSA struct from QByteArray private key."; - qCDebug(networking) << "Will re-attempt on next domain-server check in."; } } return QByteArray(); diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 483cd28ff2..6223bc008e 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -54,6 +54,8 @@ public: bool hasPrivateKey() const { return !_privateKey.isEmpty(); } void setPrivateKey(const QByteArray& privateKey) { _privateKey = privateKey; } + QByteArray signPlaintext(const QByteArray& plaintext); + void setDomainID(const QUuid& domainID) { _domainID = domainID; } const QUuid& getDomainID() const { return _domainID; } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index a3707d19ba..f236f9d596 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -902,10 +902,6 @@ void LimitedNodeList::updateLocalSockAddr() { } } -void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr) { - sendPacketToIceServer(PacketType::ICEServerHeartbeat, iceServerSockAddr, _sessionUUID); -} - void LimitedNodeList::sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID) { sendPacketToIceServer(PacketType::ICEServerQuery, iceServerSockAddr, clientID, peerID); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index fcad23da8f..de110c7e7f 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -143,6 +143,7 @@ public: bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; } const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; } + const HifiSockAddr& getPublicSockAddr() const { return _publicSockAddr; } const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; } void processKillNode(ReceivedMessage& message); @@ -161,7 +162,6 @@ public: std::unique_ptr constructICEPingPacket(PingType_t pingType, const QUuid& iceID); std::unique_ptr constructICEPingReplyPacket(ReceivedMessage& message, const QUuid& iceID); - void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr); void sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID); SharedNodePointer findNodeWithAddr(const HifiSockAddr& addr); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 4e6418279d..8a4c2ec34f 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -45,6 +45,8 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::AvatarData: case PacketType::BulkAvatarData: return static_cast(AvatarMixerPacketVersion::SoftAttachmentSupport); + case PacketType::ICEServerHeartbeat: + return 18; // ICE Server Heartbeat signing default: return 17; }