mirror of
https://github.com/overte-org/overte.git
synced 2025-07-26 09:18:26 +02:00
add signed heartbeat sending to domain-server
This commit is contained in:
parent
d444d5dd18
commit
11a1bc4488
7 changed files with 81 additions and 31 deletions
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
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[]) :
|
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
QCoreApplication(argc, argv),
|
QCoreApplication(argc, argv),
|
||||||
|
@ -1053,11 +1053,55 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
|
||||||
domainUpdateJSON.toUtf8());
|
domainUpdateJSON.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: have data-web respond with ice-server hostname to use
|
|
||||||
|
|
||||||
void DomainServer::sendHeartbeatToIceServer() {
|
void DomainServer::sendHeartbeatToIceServer() {
|
||||||
if (!_iceServerSocket.getAddress().isNull()) {
|
if (!_iceServerSocket.getAddress().isNull()) {
|
||||||
DependencyManager::get<LimitedNodeList>()->sendHeartbeatToIceServer(_iceServerSocket);
|
static auto heartbeatPacket = NLPacket::create(PacketType::ICEServerHeartbeat);
|
||||||
|
|
||||||
|
bool shouldRecreatePacket = false;
|
||||||
|
|
||||||
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#include "AccountManager.h"
|
#include "AccountManager.h"
|
||||||
#include "NetworkLogging.h"
|
#include "NetworkLogging.h"
|
||||||
|
|
||||||
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false;
|
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = true;
|
||||||
|
|
||||||
AccountManager& AccountManager::getInstance(bool forceReset) {
|
AccountManager& AccountManager::getInstance(bool forceReset) {
|
||||||
static std::unique_ptr<AccountManager> sharedInstance(new AccountManager());
|
static std::unique_ptr<AccountManager> sharedInstance(new AccountManager());
|
||||||
|
|
|
@ -117,41 +117,47 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) {
|
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()) {
|
if (!_privateKey.isEmpty()) {
|
||||||
const char* privateKeyData = _privateKey.constData();
|
const char* privateKeyData = _privateKey.constData();
|
||||||
RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL,
|
RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL,
|
||||||
reinterpret_cast<const unsigned char**>(&privateKeyData),
|
reinterpret_cast<const unsigned char**>(&privateKeyData),
|
||||||
_privateKey.size());
|
_privateKey.size());
|
||||||
if (rsaPrivateKey) {
|
if (rsaPrivateKey) {
|
||||||
QByteArray lowercaseUsername = _username.toLower().toUtf8();
|
QByteArray signature(RSA_size(rsaPrivateKey), 0);
|
||||||
QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()),
|
unsigned int signatureBytes = 0;
|
||||||
QCryptographicHash::Sha256);
|
|
||||||
|
|
||||||
QByteArray usernameSignature(RSA_size(rsaPrivateKey), 0);
|
|
||||||
unsigned int usernameSignatureSize = 0;
|
|
||||||
|
|
||||||
int encryptReturn = RSA_sign(NID_sha256,
|
int encryptReturn = RSA_sign(NID_sha256,
|
||||||
reinterpret_cast<const unsigned char*>(usernameWithToken.constData()),
|
reinterpret_cast<const unsigned char*>(plaintext.constData()),
|
||||||
usernameWithToken.size(),
|
plaintext.size(),
|
||||||
reinterpret_cast<unsigned char*>(usernameSignature.data()),
|
reinterpret_cast<unsigned char*>(signature.data()),
|
||||||
&usernameSignatureSize,
|
&signatureBytes,
|
||||||
rsaPrivateKey);
|
rsaPrivateKey);
|
||||||
|
|
||||||
// free the private key RSA struct now that we are done with it
|
// free the private key RSA struct now that we are done with it
|
||||||
RSA_free(rsaPrivateKey);
|
RSA_free(rsaPrivateKey);
|
||||||
|
|
||||||
if (encryptReturn == -1) {
|
if (encryptReturn != -1) {
|
||||||
qCDebug(networking) << "Error encrypting username signature.";
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(networking) << "Could not create RSA struct from QByteArray private key.";
|
qCDebug(networking) << "Could not create RSA struct from QByteArray private key.";
|
||||||
qCDebug(networking) << "Will re-attempt on next domain-server check in.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
|
|
|
@ -54,6 +54,8 @@ public:
|
||||||
bool hasPrivateKey() const { return !_privateKey.isEmpty(); }
|
bool hasPrivateKey() const { return !_privateKey.isEmpty(); }
|
||||||
void setPrivateKey(const QByteArray& privateKey) { _privateKey = privateKey; }
|
void setPrivateKey(const QByteArray& privateKey) { _privateKey = privateKey; }
|
||||||
|
|
||||||
|
QByteArray signPlaintext(const QByteArray& plaintext);
|
||||||
|
|
||||||
void setDomainID(const QUuid& domainID) { _domainID = domainID; }
|
void setDomainID(const QUuid& domainID) { _domainID = domainID; }
|
||||||
const QUuid& getDomainID() const { return _domainID; }
|
const QUuid& getDomainID() const { return _domainID; }
|
||||||
|
|
||||||
|
|
|
@ -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,
|
void LimitedNodeList::sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID,
|
||||||
const QUuid& peerID) {
|
const QUuid& peerID) {
|
||||||
sendPacketToIceServer(PacketType::ICEServerQuery, iceServerSockAddr, clientID, peerID);
|
sendPacketToIceServer(PacketType::ICEServerQuery, iceServerSockAddr, clientID, peerID);
|
||||||
|
|
|
@ -143,6 +143,7 @@ public:
|
||||||
bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; }
|
bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; }
|
||||||
|
|
||||||
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
|
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
|
||||||
|
const HifiSockAddr& getPublicSockAddr() const { return _publicSockAddr; }
|
||||||
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
|
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
|
||||||
|
|
||||||
void processKillNode(ReceivedMessage& message);
|
void processKillNode(ReceivedMessage& message);
|
||||||
|
@ -161,7 +162,6 @@ public:
|
||||||
std::unique_ptr<NLPacket> constructICEPingPacket(PingType_t pingType, const QUuid& iceID);
|
std::unique_ptr<NLPacket> constructICEPingPacket(PingType_t pingType, const QUuid& iceID);
|
||||||
std::unique_ptr<NLPacket> constructICEPingReplyPacket(ReceivedMessage& message, const QUuid& iceID);
|
std::unique_ptr<NLPacket> constructICEPingReplyPacket(ReceivedMessage& message, const QUuid& iceID);
|
||||||
|
|
||||||
void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr);
|
|
||||||
void sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID);
|
void sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID);
|
||||||
|
|
||||||
SharedNodePointer findNodeWithAddr(const HifiSockAddr& addr);
|
SharedNodePointer findNodeWithAddr(const HifiSockAddr& addr);
|
||||||
|
|
|
@ -45,6 +45,8 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::AvatarData:
|
case PacketType::AvatarData:
|
||||||
case PacketType::BulkAvatarData:
|
case PacketType::BulkAvatarData:
|
||||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SoftAttachmentSupport);
|
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SoftAttachmentSupport);
|
||||||
|
case PacketType::ICEServerHeartbeat:
|
||||||
|
return 18; // ICE Server Heartbeat signing
|
||||||
default:
|
default:
|
||||||
return 17;
|
return 17;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue