hook up domain request for node to authenticate

This commit is contained in:
Stephen Birarda 2014-02-18 10:54:45 -08:00
parent 4c135dd3a7
commit 7c69028dc5
4 changed files with 134 additions and 109 deletions

View file

@ -175,4 +175,5 @@ void AssignmentClient::assignmentCompleted() {
// reset our NodeList by switching back to unassigned and clearing the list // reset our NodeList by switching back to unassigned and clearing the list
nodeList->setOwnerType(NodeType::Unassigned); nodeList->setOwnerType(NodeType::Unassigned);
nodeList->reset(); nodeList->reset();
nodeList->resetNodeInterestSet();
} }

View file

@ -69,8 +69,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
} else if ((argumentIndex = argumentList.indexOf(CUSTOM_AUTH_OPTION)) != -1) { } else if ((argumentIndex = argumentList.indexOf(CUSTOM_AUTH_OPTION)) != -1) {
_nodeAuthenticationHostname = argumentList.value(argumentIndex + 1); _nodeAuthenticationHostname = argumentList.value(argumentIndex + 1);
} }
qDebug() << "the node authentication hostname is" << _nodeAuthenticationHostname;
NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort); NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort);
@ -254,109 +252,126 @@ void DomainServer::readAvailableDatagrams() {
PacketType requestType = packetTypeForPacket(receivedPacket); PacketType requestType = packetTypeForPacket(receivedPacket);
if (requestType == PacketTypeDomainListRequest) { if (requestType == PacketTypeDomainListRequest) {
// this is an RFD or domain list request packet, and there is a version match
QDataStream packetStream(receivedPacket);
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket); QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
packetStream >> nodeType; if (!_nodeAuthenticationHostname.isEmpty() &&
packetStream >> nodePublicAddress >> nodeLocalAddress; (nodeUUID.isNull() || !nodeList->nodeWithUUID(nodeUUID))) {
// this is a node we do not recognize and we need authentication - ask them to do so
if (nodePublicAddress.getAddress().isNull()) { // by providing them the hostname they should authenticate with
// this node wants to use us its STUN server QByteArray authenticationRequestPacket = byteArrayWithPopluatedHeader(PacketTypeDomainServerAuthRequest);
// so set the node public address to whatever we perceive the public address to be
// if the sender is on our box then leave its public address to 0 so that QDataStream authPacketStream(&authenticationRequestPacket, QIODevice::Append);
// other users attempt to reach it on the same address they have for the domain-server authPacketStream << _nodeAuthenticationHostname;
if (senderSockAddr.getAddress().isLoopback()) {
nodePublicAddress.setAddress(QHostAddress());
} else {
nodePublicAddress.setAddress(senderSockAddr.getAddress());
}
}
SharedAssignmentPointer matchingStaticAssignment;
// check if this is a non-statically assigned node, a node that is assigned and checking in for the first time
// or a node that has already checked in and is continuing to report for duty
if (!STATICALLY_ASSIGNED_NODES.contains(nodeType)
|| (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
|| nodeList->getInstance()->nodeWithUUID(nodeUUID)) {
if (nodeUUID.isNull()) { qDebug() << "Asking node at" << senderSockAddr << "to authenticate.";
// this is a check in from an unidentified node
// we need to generate a session UUID for this node
nodeUUID = QUuid::createUuid();
}
SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, // send the authentication request back to the node
nodeType, nodeList->getNodeSocket().writeDatagram(authenticationRequestPacket,
nodePublicAddress, senderSockAddr.getAddress(), senderSockAddr.getPort());
nodeLocalAddress);
// resize our broadcast packet in preparation to set it up again } else {
broadcastPacket.resize(numBroadcastPacketHeaderBytes); // this is an RFD or domain list request packet, and there is a match
QDataStream packetStream(receivedPacket);
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
if (matchingStaticAssignment) { packetStream >> nodeType;
// this was a newly added node with a matching static assignment packetStream >> nodePublicAddress >> nodeLocalAddress;
if (nodePublicAddress.getAddress().isNull()) {
// this node wants to use us its STUN server
// so set the node public address to whatever we perceive the public address to be
// remove the matching assignment from the assignment queue so we don't take the next check in // if the sender is on our box then leave its public address to 0 so that
// (if it exists) // other users attempt to reach it on the same address they have for the domain-server
if (_hasCompletedRestartHold) { if (senderSockAddr.getAddress().isLoopback()) {
removeMatchingAssignmentFromQueue(matchingStaticAssignment); nodePublicAddress.setAddress(QHostAddress());
} else {
nodePublicAddress.setAddress(senderSockAddr.getAddress());
} }
} }
quint8 numInterestTypes = 0; SharedAssignmentPointer matchingStaticAssignment;
packetStream >> numInterestTypes;
NodeType_t* nodeTypesOfInterest = reinterpret_cast<NodeType_t*>(receivedPacket.data() // check if this is a non-statically assigned node, a node that is assigned and checking in for the first time
+ packetStream.device()->pos()); // or a node that has already checked in and is continuing to report for duty
if (!STATICALLY_ASSIGNED_NODES.contains(nodeType)
// always send the node their own UUID back || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append); || nodeList->getInstance()->nodeWithUUID(nodeUUID)) {
broadcastDataStream << checkInNode->getUUID();
if (nodeUUID.isNull()) {
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(checkInNode->getLinkedData()); // this is a check in from an unidentified node
// we need to generate a session UUID for this node
if (numInterestTypes > 0) { nodeUUID = QUuid::createUuid();
// if the node has any interest types, send back those nodes as well }
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
if (otherNode->getUUID() != nodeUUID && SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID,
memchr(nodeTypesOfInterest, otherNode->getType(), numInterestTypes)) { nodeType,
nodePublicAddress,
// don't send avatar nodes to other avatars, that will come from avatar mixer nodeLocalAddress);
broadcastDataStream << *otherNode.data();
// resize our broadcast packet in preparation to set it up again
// pack the secret that these two nodes will use to communicate with each other broadcastPacket.resize(numBroadcastPacketHeaderBytes);
QUuid secretUUID = nodeData->getSessionSecretHash().value(otherNode->getUUID());
if (secretUUID.isNull()) { if (matchingStaticAssignment) {
// generate a new secret UUID these two nodes can use // this was a newly added node with a matching static assignment
secretUUID = QUuid::createUuid();
// remove the matching assignment from the assignment queue so we don't take the next check in
// set that on the current Node's sessionSecretHash // (if it exists)
nodeData->getSessionSecretHash().insert(otherNode->getUUID(), secretUUID); if (_hasCompletedRestartHold) {
removeMatchingAssignmentFromQueue(matchingStaticAssignment);
// set it on the other Node's sessionSecretHash
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())
->getSessionSecretHash().insert(nodeUUID, secretUUID);
}
broadcastDataStream << secretUUID;
} }
} }
quint8 numInterestTypes = 0;
packetStream >> numInterestTypes;
NodeType_t* nodeTypesOfInterest = reinterpret_cast<NodeType_t*>(receivedPacket.data()
+ packetStream.device()->pos());
// always send the node their own UUID back
QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append);
broadcastDataStream << checkInNode->getUUID();
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(checkInNode->getLinkedData());
if (numInterestTypes > 0) {
// if the node has any interest types, send back those nodes as well
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
if (otherNode->getUUID() != nodeUUID &&
memchr(nodeTypesOfInterest, otherNode->getType(), numInterestTypes)) {
// don't send avatar nodes to other avatars, that will come from avatar mixer
broadcastDataStream << *otherNode.data();
// pack the secret that these two nodes will use to communicate with each other
QUuid secretUUID = nodeData->getSessionSecretHash().value(otherNode->getUUID());
if (secretUUID.isNull()) {
// generate a new secret UUID these two nodes can use
secretUUID = QUuid::createUuid();
// set that on the current Node's sessionSecretHash
nodeData->getSessionSecretHash().insert(otherNode->getUUID(), secretUUID);
// set it on the other Node's sessionSecretHash
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())
->getSessionSecretHash().insert(nodeUUID, secretUUID);
}
broadcastDataStream << secretUUID;
}
}
}
// update last receive to now
quint64 timeNow = usecTimestampNow();
checkInNode->setLastHeardMicrostamp(timeNow);
// send the constructed list back to this node
nodeList->getNodeSocket().writeDatagram(broadcastPacket,
senderSockAddr.getAddress(), senderSockAddr.getPort());
} }
}
// update last receive to now
quint64 timeNow = usecTimestampNow();
checkInNode->setLastHeardMicrostamp(timeNow);
// send the constructed list back to this node
nodeList->getNodeSocket().writeDatagram(broadcastPacket,
senderSockAddr.getAddress(), senderSockAddr.getPort());
}
} else if (requestType == PacketTypeRequestAssignment) { } else if (requestType == PacketTypeRequestAssignment) {
// construct the requested assignment from the packet data // construct the requested assignment from the packet data

View file

@ -68,11 +68,9 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
{ {
_nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort); _nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort);
qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort(); qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort();
}
// clear our NodeList when the domain changes
connect(&_domainInfo, &DomainInfo::hostnameChanged, this, &NodeList::reset);
NodeList::~NodeList() {
clear();
} }
bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) {
@ -87,7 +85,8 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) {
} }
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>() << PacketTypeDomainList const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>() << PacketTypeDomainList
<< PacketTypeDomainListRequest << PacketTypeStunResponse << PacketTypeDataServerConfirm << PacketTypeDomainListRequest << PacketTypeDomainServerAuthRequest
<< PacketTypeStunResponse << PacketTypeDataServerConfirm
<< PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend << PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment; << PacketTypeCreateAssignment << PacketTypeRequestAssignment;
@ -196,6 +195,18 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr
break; break;
} }
case PacketTypeDomainServerAuthRequest: {
// the domain-server has asked us to auth via a data-server
QDataStream authPacketStream(packet);
authPacketStream.skipRawData(numBytesForPacketHeader(packet));
QString authenticationHostname;
authPacketStream >> authenticationHostname;
qDebug() << "Domain server wants us to auth with" << authenticationHostname;
break;
}
case PacketTypePing: { case PacketTypePing: {
// send back a reply // send back a reply
SharedNodePointer matchingNode = sendingNodeForPacket(packet); SharedNodePointer matchingNode = sendingNodeForPacket(packet);
@ -288,10 +299,8 @@ void NodeList::reset() {
clear(); clear();
_numNoReplyDomainCheckIns = 0; _numNoReplyDomainCheckIns = 0;
_nodeTypesOfInterest.clear(); // refresh the owner UUID to the NULL UUID
_sessionUUID = QUuid();
// refresh the owner UUID
_sessionUUID = QUuid::createUuid();
} }
void NodeList::addNodeTypeToInterestSet(NodeType_t nodeTypeToAdd) { void NodeList::addNodeTypeToInterestSet(NodeType_t nodeTypeToAdd) {

View file

@ -88,11 +88,10 @@ public:
int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; } int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
DomainInfo& getDomainInfo() { return _domainInfo; } DomainInfo& getDomainInfo() { return _domainInfo; }
void reset();
const NodeSet& getNodeInterestSet() const { return _nodeTypesOfInterest; } const NodeSet& getNodeInterestSet() const { return _nodeTypesOfInterest; }
void addNodeTypeToInterestSet(NodeType_t nodeTypeToAdd); void addNodeTypeToInterestSet(NodeType_t nodeTypeToAdd);
void addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes); void addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes);
void resetNodeInterestSet() { _nodeTypesOfInterest.clear(); }
int processDomainServerList(const QByteArray& packet); int processDomainServerList(const QByteArray& packet);
@ -121,6 +120,8 @@ public:
void loadData(QSettings* settings); void loadData(QSettings* settings);
void saveData(QSettings* settings); void saveData(QSettings* settings);
public slots: public slots:
void reset();
void sendDomainServerCheckIn(); void sendDomainServerCheckIn();
void pingInactiveNodes(); void pingInactiveNodes();
void removeSilentNodes(); void removeSilentNodes();
@ -130,20 +131,22 @@ signals:
void uuidChanged(const QUuid& ownerUUID); void uuidChanged(const QUuid& ownerUUID);
void nodeAdded(SharedNodePointer); void nodeAdded(SharedNodePointer);
void nodeKilled(SharedNodePointer); void nodeKilled(SharedNodePointer);
private: private:
static NodeList* _sharedInstance; static NodeList* _sharedInstance;
NodeList(char ownerType, unsigned short int socketListenPort); NodeList(char ownerType, unsigned short int socketListenPort);
~NodeList();
NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton
void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton
void sendSTUNRequest(); void sendSTUNRequest();
void processSTUNResponse(const QByteArray& packet); void processSTUNResponse(const QByteArray& packet);
qint64 NodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr,
const QUuid& connectionSecret); const QUuid& connectionSecret);
NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill); NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill);
void clear();
NodeHash _nodeHash; NodeHash _nodeHash;
QMutex _nodeHashMutex; QMutex _nodeHashMutex;
@ -159,10 +162,7 @@ private:
unsigned int _stunRequestsSinceSuccess; unsigned int _stunRequestsSinceSuccess;
void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode);
void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode);
void resetDomainData(char domainField[], const char* domainData);
void domainLookup();
void clear();
}; };
#endif /* defined(__hifi__NodeList__) */ #endif /* defined(__hifi__NodeList__) */