mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
add additional IP check to DS packet filter operator
This commit is contained in:
parent
80eac56c4d
commit
c122b22dfc
7 changed files with 80 additions and 17 deletions
|
@ -54,6 +54,7 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
|
||||||
if (message->getSize() == 0) {
|
if (message->getSize() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream packetStream(message->getMessage());
|
QDataStream packetStream(message->getMessage());
|
||||||
|
|
||||||
// read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it
|
// read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it
|
||||||
|
|
|
@ -458,7 +458,7 @@ const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool DomainServer::packetVersionMatch(const udt::Packet& packet) {
|
bool DomainServer::isPacketVerified(const udt::Packet& packet) {
|
||||||
PacketType headerType = NLPacket::typeInHeader(packet);
|
PacketType headerType = NLPacket::typeInHeader(packet);
|
||||||
PacketVersion headerVersion = NLPacket::versionInHeader(packet);
|
PacketVersion headerVersion = NLPacket::versionInHeader(packet);
|
||||||
|
|
||||||
|
@ -471,7 +471,50 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) {
|
||||||
DomainGatekeeper::sendProtocolMismatchConnectionDenial(packet.getSenderSockAddr());
|
DomainGatekeeper::sendProtocolMismatchConnectionDenial(packet.getSenderSockAddr());
|
||||||
}
|
}
|
||||||
|
|
||||||
// let the normal nodeList implementation handle all other packets.
|
if (!PacketTypeEnum::getNonSourcedPackets().contains(headerType)) {
|
||||||
|
// this is a sourced packet - first check if we have a node that matches
|
||||||
|
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
|
||||||
|
SharedNodePointer sourceNode = nodeList->nodeWithUUID(sourceID);
|
||||||
|
|
||||||
|
if (sourceNode) {
|
||||||
|
// unverified DS packets (due to a lack of connection secret between DS + node)
|
||||||
|
// must come either from the same public IP address or a local IP address (set by RFC 1918)
|
||||||
|
|
||||||
|
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(sourceNode->getLinkedData());
|
||||||
|
|
||||||
|
bool exactAddressMatch = nodeData->getSendingSockAddr() == packet.getSenderSockAddr();
|
||||||
|
bool bothPrivateAddresses = nodeData->getSendingSockAddr().hasPrivateAddress()
|
||||||
|
&& packet.getSenderSockAddr().hasPrivateAddress();
|
||||||
|
|
||||||
|
qDebug() << exactAddressMatch << bothPrivateAddresses;
|
||||||
|
|
||||||
|
if (nodeData && (exactAddressMatch || bothPrivateAddresses)) {
|
||||||
|
// to the best of our ability we've verified that this packet comes from the right place
|
||||||
|
// let the NodeList do its checks now (but pass it the sourceNode so it doesn't need to look it up again)
|
||||||
|
return nodeList->isPacketVerifiedWithSource(packet, sourceNode.data());
|
||||||
|
} else {
|
||||||
|
static const QString UNKNOWN_REGEX = "Packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unmatched IP for UUID";
|
||||||
|
static QString repeatedMessage
|
||||||
|
= LogHandler::getInstance().addRepeatedMessageRegex(UNKNOWN_REGEX);
|
||||||
|
|
||||||
|
qDebug() << "Packet of type" << headerType
|
||||||
|
<< "received from unmatched IP for UUID" << uuidStringWithoutCurlyBraces(sourceID);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static const QString UNKNOWN_REGEX = "Packet of type \\d+ \\([\\sa-zA-Z:]+\\) received from unknown node with UUID";
|
||||||
|
static QString repeatedMessage
|
||||||
|
= LogHandler::getInstance().addRepeatedMessageRegex(UNKNOWN_REGEX);
|
||||||
|
|
||||||
|
qDebug() << "Packet of type" << headerType
|
||||||
|
<< "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback to allow the normal NodeList implementation to verify packets
|
||||||
return nodeList->isPacketVerified(packet);
|
return nodeList->isPacketVerified(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,7 +613,7 @@ void DomainServer::setupNodeListAndAssignments() {
|
||||||
addStaticAssignmentsToQueue();
|
addStaticAssignmentsToQueue();
|
||||||
|
|
||||||
// set a custom packetVersionMatch as the verify packet operator for the udt::Socket
|
// set a custom packetVersionMatch as the verify packet operator for the udt::Socket
|
||||||
nodeList->setPacketFilterOperator(&DomainServer::packetVersionMatch);
|
nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
||||||
|
@ -853,7 +896,6 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||||
|
|
||||||
QDataStream packetStream(message->getMessage());
|
QDataStream packetStream(message->getMessage());
|
||||||
NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr(), false);
|
NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr(), false);
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ public slots:
|
||||||
|
|
||||||
void restart();
|
void restart();
|
||||||
|
|
||||||
|
private slots:
|
||||||
void processRequestAssignmentPacket(QSharedPointer<ReceivedMessage> packet);
|
void processRequestAssignmentPacket(QSharedPointer<ReceivedMessage> packet);
|
||||||
void processListRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
void processListRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||||
void processNodeJSONStatsPacket(QSharedPointer<ReceivedMessage> packetList, SharedNodePointer sendingNode);
|
void processNodeJSONStatsPacket(QSharedPointer<ReceivedMessage> packetList, SharedNodePointer sendingNode);
|
||||||
|
@ -79,7 +80,6 @@ public slots:
|
||||||
void processICEServerHeartbeatDenialPacket(QSharedPointer<ReceivedMessage> message);
|
void processICEServerHeartbeatDenialPacket(QSharedPointer<ReceivedMessage> message);
|
||||||
void processICEServerHeartbeatACK(QSharedPointer<ReceivedMessage> message);
|
void processICEServerHeartbeatACK(QSharedPointer<ReceivedMessage> message);
|
||||||
|
|
||||||
private slots:
|
|
||||||
void setupPendingAssignmentCredits();
|
void setupPendingAssignmentCredits();
|
||||||
void sendPendingTransactionsToServer();
|
void sendPendingTransactionsToServer();
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ private:
|
||||||
|
|
||||||
void getTemporaryName(bool force = false);
|
void getTemporaryName(bool force = false);
|
||||||
|
|
||||||
static bool packetVersionMatch(const udt::Packet& packet);
|
static bool isPacketVerified(const udt::Packet& packet);
|
||||||
|
|
||||||
bool resetAccountManagerAccessToken();
|
bool resetAccountManagerAccessToken();
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,18 @@ QString HifiSockAddr::toString() const {
|
||||||
return _address.toString() + ":" + QString::number(_port);
|
return _address.toString() + ":" + QString::number(_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HifiSockAddr::hasPrivateAddress() const {
|
||||||
|
// an address is private if it falls in any of the RFC1918 address spaces
|
||||||
|
const QPair<QHostAddress, int> TWENTY_FOUR_BIT_BLOCK = { QHostAddress("10.0.0.0"), 8 };
|
||||||
|
const QPair<QHostAddress, int> TWENTY_BIT_BLOCK = { QHostAddress("172.16.0.0") , 12 };
|
||||||
|
const QPair<QHostAddress, int> SIXTEEN_BIT_BLOCK = { QHostAddress("192.168.0.0"), 16 };
|
||||||
|
|
||||||
|
return _address.isLoopback()
|
||||||
|
|| _address.isInSubnet(TWENTY_FOUR_BIT_BLOCK)
|
||||||
|
|| _address.isInSubnet(TWENTY_BIT_BLOCK)
|
||||||
|
|| _address.isInSubnet(SIXTEEN_BIT_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr) {
|
QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr) {
|
||||||
debug.nospace() << sockAddr._address.toString().toLocal8Bit().constData() << ":" << sockAddr._port;
|
debug.nospace() << sockAddr._address.toString().toLocal8Bit().constData() << ":" << sockAddr._port;
|
||||||
return debug.space();
|
return debug.space();
|
||||||
|
|
|
@ -55,6 +55,8 @@ public:
|
||||||
|
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
|
||||||
|
bool hasPrivateAddress() const; // checks if the address behind this sock addr is private per RFC 1918
|
||||||
|
|
||||||
friend QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr);
|
friend QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr);
|
||||||
friend QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr);
|
friend QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr);
|
||||||
friend QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr);
|
friend QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr);
|
||||||
|
|
|
@ -202,12 +202,12 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() {
|
||||||
return *_dtlsSocket;
|
return *_dtlsSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LimitedNodeList::isPacketVerified(const udt::Packet& packet) {
|
bool LimitedNodeList::isPacketVerifiedWithSource(const udt::Packet& packet, Node* sourceNode) {
|
||||||
// We track bandwidth when doing packet verification to avoid needing to do a node lookup
|
// We track bandwidth when doing packet verification to avoid needing to do a node lookup
|
||||||
// later when we already do it in packetSourceAndHashMatchAndTrackBandwidth. A node lookup
|
// later when we already do it in packetSourceAndHashMatchAndTrackBandwidth. A node lookup
|
||||||
// incurs a lock, so it is ideal to avoid needing to do it 2+ times for each packet
|
// incurs a lock, so it is ideal to avoid needing to do it 2+ times for each packet
|
||||||
// received.
|
// received.
|
||||||
return packetVersionMatch(packet) && packetSourceAndHashMatchAndTrackBandwidth(packet);
|
return packetVersionMatch(packet) && packetSourceAndHashMatchAndTrackBandwidth(packet, sourceNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
|
bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
|
||||||
|
@ -256,7 +256,7 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet) {
|
bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet, Node* sourceNode) {
|
||||||
|
|
||||||
PacketType headerType = NLPacket::typeInHeader(packet);
|
PacketType headerType = NLPacket::typeInHeader(packet);
|
||||||
|
|
||||||
|
@ -298,14 +298,18 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
||||||
} else {
|
} else {
|
||||||
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
|
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
|
||||||
|
|
||||||
// figure out which node this is from
|
// check if we were passed a sourceNode hint or if we need to look it up
|
||||||
SharedNodePointer matchingNode = nodeWithUUID(sourceID);
|
if (!sourceNode) {
|
||||||
|
// figure out which node this is from
|
||||||
|
SharedNodePointer matchingNode = nodeWithUUID(sourceID);
|
||||||
|
sourceNode = matchingNode.data();
|
||||||
|
}
|
||||||
|
|
||||||
if (matchingNode) {
|
if (sourceNode) {
|
||||||
if (!PacketTypeEnum::getNonVerifiedPackets().contains(headerType)) {
|
if (!PacketTypeEnum::getNonVerifiedPackets().contains(headerType)) {
|
||||||
|
|
||||||
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
||||||
QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, matchingNode->getConnectionSecret());
|
QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, sourceNode->getConnectionSecret());
|
||||||
|
|
||||||
// check if the md5 hash in the header matches the hash we would expect
|
// check if the md5 hash in the header matches the hash we would expect
|
||||||
if (packetHeaderHash != expectedHash) {
|
if (packetHeaderHash != expectedHash) {
|
||||||
|
@ -323,9 +327,9 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
||||||
|
|
||||||
// No matter if this packet is handled or not, we update the timestamp for the last time we heard
|
// No matter if this packet is handled or not, we update the timestamp for the last time we heard
|
||||||
// from this sending node
|
// from this sending node
|
||||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
sourceNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
|
||||||
emit dataReceived(matchingNode->getType(), packet.getPayloadSize());
|
emit dataReceived(sourceNode->getType(), packet.getPayloadSize());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -286,7 +286,9 @@ public:
|
||||||
|
|
||||||
void setPacketFilterOperator(udt::PacketFilterOperator filterOperator) { _nodeSocket.setPacketFilterOperator(filterOperator); }
|
void setPacketFilterOperator(udt::PacketFilterOperator filterOperator) { _nodeSocket.setPacketFilterOperator(filterOperator); }
|
||||||
bool packetVersionMatch(const udt::Packet& packet);
|
bool packetVersionMatch(const udt::Packet& packet);
|
||||||
bool isPacketVerified(const udt::Packet& packet);
|
|
||||||
|
bool isPacketVerifiedWithSource(const udt::Packet& packet, Node* sourceNode = nullptr);
|
||||||
|
bool isPacketVerified(const udt::Packet& packet) { return isPacketVerifiedWithSource(packet); }
|
||||||
|
|
||||||
static void makeSTUNRequestPacket(char* stunRequestPacket);
|
static void makeSTUNRequestPacket(char* stunRequestPacket);
|
||||||
|
|
||||||
|
@ -352,7 +354,7 @@ protected:
|
||||||
|
|
||||||
void setLocalSocket(const HifiSockAddr& sockAddr);
|
void setLocalSocket(const HifiSockAddr& sockAddr);
|
||||||
|
|
||||||
bool packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet);
|
bool packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet, Node* sourceNode = nullptr);
|
||||||
void processSTUNResponse(std::unique_ptr<udt::BasePacket> packet);
|
void processSTUNResponse(std::unique_ptr<udt::BasePacket> packet);
|
||||||
|
|
||||||
void handleNodeKill(const SharedNodePointer& node);
|
void handleNodeKill(const SharedNodePointer& node);
|
||||||
|
|
Loading…
Reference in a new issue