complete inital DTLS setup in domain-server

This commit is contained in:
Stephen Birarda 2014-03-31 14:02:11 -07:00
parent dc38b27485
commit da30d21f6e
4 changed files with 90 additions and 10 deletions

View file

@ -35,7 +35,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
_HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), _HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
_staticAssignmentHash(), _staticAssignmentHash(),
_assignmentQueue(), _assignmentQueue(),
_x509Credentials() _isUsingDTLS(false),
_x509Credentials(NULL),
_dhParams(NULL),
_priorityCache(NULL)
{ {
setOrganizationName("High Fidelity"); setOrganizationName("High Fidelity");
setOrganizationDomain("highfidelity.io"); setOrganizationDomain("highfidelity.io");
@ -44,29 +47,85 @@ DomainServer::DomainServer(int argc, char* argv[]) :
_argumentList = arguments(); _argumentList = arguments();
if (readCertificateAndPrivateKey()) { if (optionallySetupDTLS()) {
// we either read a certificate and private key or were not passed one, good to load assignments // we either read a certificate and private key or were not passed one, good to load assignments
// and set up the node list // and set up the node list
qDebug() << "Setting up NodeList and assignments.";
setupNodeListAndAssignments(); setupNodeListAndAssignments();
if (_isUsingDTLS) {
// we're using DTLS and our NodeList socket is good to go, so make the required DTLS changes
// DTLS requires that IP_DONTFRAG be set
// This is not accessible on some platforms (OS X) so we need to make sure DTLS still works without it
NodeList* nodeList = NodeList::getInstance();
#if defined(IP_DONTFRAG) || defined(IP_MTU_DISCOVER)
qDebug() << "Making required DTLS changes to NodeList DTLS socket.";
int socketHandle = NodeList::getInstance()->getDTLSSocket().socketDescriptor();
#if defined(IP_DONTFRAG)
int optValue = 1;yea
setsockopt(socketHandle, IPPROTO_IP, IP_DONTFRAG, (const void*) optValue, sizeof(optValue));
#elif defined(IP_MTU_DISCOVER)
int optValue = 1;
setsockopt(socketHandle, IPPROTO_IP, IP_MTU_DISCOVER, (const void*) optValue, sizeof(optValue));
#endif
#endif
// connect our socket to read datagrams received on the DTLS socket
connect(&nodeList->getDTLSSocket(), &QUdpSocket::readyRead, this, &DomainServer::readAvailableDTLSDatagrams);
}
} }
} }
bool DomainServer::readCertificateAndPrivateKey() { bool DomainServer::optionallySetupDTLS() {
if (readX509KeyAndCertificate()) {
qDebug() << "Generating Diffie-Hellman parameters.";
// generate Diffie-Hellman parameters
// When short bit length is used, it might be wise to regenerate parameters often.
int dhBits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
_dhParams = new gnutls_dh_params_t;
gnutls_dh_params_init(_dhParams);
gnutls_dh_params_generate2(*_dhParams, dhBits);
qDebug() << "Successfully generated Diffie-Hellman parameters.";
// set the D-H paramters on the X509 credentials
gnutls_certificate_set_dh_params(*_x509Credentials, *_dhParams);
_priorityCache = new gnutls_priority_t;
const char DTLS_PRIORITY_STRING[] = "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.2:%SERVER_PRECEDENCE";
gnutls_priority_init(_priorityCache, DTLS_PRIORITY_STRING, NULL);
_isUsingDTLS = true;
qDebug() << "Initial DTLS setup complete.";
return true;
} else {
return false;
}
}
bool DomainServer::readX509KeyAndCertificate() {
const QString X509_CERTIFICATE_OPTION = "--cert"; const QString X509_CERTIFICATE_OPTION = "--cert";
const QString X509_PRIVATE_KEY_OPTION = "--key"; const QString X509_PRIVATE_KEY_OPTION = "--key";
const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE"; const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE";
int certIndex = _argumentList.indexOf(X509_CERTIFICATE_OPTION); int certIndex = _argumentList.indexOf(X509_CERTIFICATE_OPTION);
int keyIndex = _argumentList.indexOf(X509_PRIVATE_KEY_OPTION); int keyIndex = _argumentList.indexOf(X509_PRIVATE_KEY_OPTION);
if (certIndex != -1 && keyIndex != -1) { if (certIndex != -1 && keyIndex != -1) {
// the user wants to use DTLS to encrypt communication with nodes // the user wants to use DTLS to encrypt communication with nodes
// let's make sure we can load the ey // let's make sure we can load the key and certificate
gnutls_certificate_allocate_credentials(&_x509Credentials); _x509Credentials = new gnutls_certificate_credentials_t;
gnutls_certificate_allocate_credentials(_x509Credentials);
QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV); QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV);
int gnutlsReturn = gnutls_certificate_set_x509_key_file2(_x509Credentials, int gnutlsReturn = gnutls_certificate_set_x509_key_file2(*_x509Credentials,
_argumentList[certIndex + 1].toLocal8Bit().constData(), _argumentList[certIndex + 1].toLocal8Bit().constData(),
_argumentList[keyIndex + 1].toLocal8Bit().constData(), _argumentList[keyIndex + 1].toLocal8Bit().constData(),
GNUTLS_X509_FMT_PEM, GNUTLS_X509_FMT_PEM,
@ -79,7 +138,8 @@ bool DomainServer::readCertificateAndPrivateKey() {
return false; return false;
} }
qDebug() << "Successfully read certificate and private key. Using DTLS for node communication."; qDebug() << "Successfully read certificate and private key.";
} else if (certIndex != -1 || keyIndex != -1) { } else if (certIndex != -1 || keyIndex != -1) {
qDebug() << "Missing certificate or private key. domain-server will now quit."; qDebug() << "Missing certificate or private key. domain-server will now quit.";
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
@ -552,6 +612,10 @@ void DomainServer::readAvailableDatagrams() {
} }
} }
void DomainServer::readAvailableDTLSDatagrams() {
}
QJsonObject DomainServer::jsonForSocket(const HifiSockAddr& socket) { QJsonObject DomainServer::jsonForSocket(const HifiSockAddr& socket) {
QJsonObject socketJSON; QJsonObject socketJSON;

View file

@ -45,9 +45,11 @@ private slots:
void processCreateResponseFromDataServer(const QJsonObject& jsonObject); void processCreateResponseFromDataServer(const QJsonObject& jsonObject);
void readAvailableDatagrams(); void readAvailableDatagrams();
void readAvailableDTLSDatagrams();
private: private:
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
bool readCertificateAndPrivateKey(); bool optionallySetupDTLS();
bool readX509KeyAndCertificate();
void requestAuthenticationFromPotentialNode(const HifiSockAddr& senderSockAddr); void requestAuthenticationFromPotentialNode(const HifiSockAddr& senderSockAddr);
void addNodeToNodeListAndConfirmConnection(const QByteArray& packet, const HifiSockAddr& senderSockAddr, void addNodeToNodeListAndConfirmConnection(const QByteArray& packet, const HifiSockAddr& senderSockAddr,
@ -81,7 +83,10 @@ private:
QStringList _argumentList; QStringList _argumentList;
gnutls_certificate_credentials_t _x509Credentials; bool _isUsingDTLS;
gnutls_certificate_credentials_t* _x509Credentials;
gnutls_dh_params_t* _dhParams;
gnutls_priority_t* _priorityCache;
}; };
#endif /* defined(__hifi__DomainServer__) */ #endif /* defined(__hifi__DomainServer__) */

View file

@ -89,6 +89,15 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
_packetStatTimer.start(); _packetStatTimer.start();
} }
QUdpSocket& NodeList::getDTLSSocket() {
if (_dtlsSocket.state() == QAbstractSocket::UnconnectedState) {
_dtlsSocket.bind(QHostAddress::AnyIPv4);
qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket.localPort();
}
return _dtlsSocket;
}
void NodeList::changeSendSocketBufferSize(int numSendBytes) { void NodeList::changeSendSocketBufferSize(int numSendBytes) {
// change the socket send buffer size to be 1MB // change the socket send buffer size to be 1MB
int oldBufferSize = 0; int oldBufferSize = 0;

View file

@ -72,6 +72,7 @@ public:
void setSessionUUID(const QUuid& sessionUUID); void setSessionUUID(const QUuid& sessionUUID);
QUdpSocket& getNodeSocket() { return _nodeSocket; } QUdpSocket& getNodeSocket() { return _nodeSocket; }
QUdpSocket& getDTLSSocket();
bool packetVersionAndHashMatch(const QByteArray& packet); bool packetVersionAndHashMatch(const QByteArray& packet);
@ -165,6 +166,7 @@ private:
NodeHash _nodeHash; NodeHash _nodeHash;
QMutex _nodeHashMutex; QMutex _nodeHashMutex;
QUdpSocket _nodeSocket; QUdpSocket _nodeSocket;
QUdpSocket _dtlsSocket;
NodeType_t _ownerType; NodeType_t _ownerType;
NodeSet _nodeTypesOfInterest; NodeSet _nodeTypesOfInterest;
DomainInfo _domainInfo; DomainInfo _domainInfo;