diff --git a/src/association.cpp b/src/association.cpp index 41040f06..e522a6e6 100644 --- a/src/association.cpp +++ b/src/association.cpp @@ -3,6 +3,8 @@ #include "association.h" #include "packet.h" +#include +#include DtlsAssociation::DtlsAssociation(QHostAddress &address, quint16 port, const QString &connectionName, std::vector cmdComponents) @@ -44,22 +46,7 @@ DtlsAssociation::DtlsAssociation(QHostAddress &address, quint16 port, //check if the address field contains a valid host name instead of implicite address if (hostName.isEmpty()){ - QHostInfo host = QHostInfo::fromName(cmdComponents[1]); - // Check if the lookup was successful - if (host.error() != QHostInfo::NoError) { - packetToSend.errorString += "Lookup failed:" + host.errorString(); - qDebug() << "Lookup failed:" << host.errorString(); - } else { - // Output the host name - foreach (const QHostAddress &resolvedAddress, host.addresses()) { - //if it is an ipv4 save it as addres and fill the hostName with the current hostName - if (resolvedAddress.protocol() == QAbstractSocket::IPv4Protocol){ - address = resolvedAddress; - hostName = cmdComponents[1]; - } - - } - } + hostName = "empty host name"; } configuration.setLocalCertificate(certificate); @@ -101,12 +88,14 @@ void DtlsAssociation::startHandshake() } if (!crypto.doHandshake(&socket)){ + //socket.waitForBytesWritten(); packetToSend.errorString += " Failed to start a handshake "; emit errorMessage(tr("%1: failed to start a handshake - %2").arg(name, crypto.dtlsErrorString())); } else{ + while(true){ - socket.waitForReadyRead(); + socket.waitForReadyRead(2000); if(crypto.isConnectionEncrypted() || closeRequest){ break; @@ -153,9 +142,9 @@ void DtlsAssociation::readyRead() } if (crypto.dtlsError() == QDtlsError::RemoteClosedConnectionError) { - packetToSend.errorString += " Shutdown alert received"; - emit errorMessage(tr("%1: shutdown alert received").arg(name)); - socket.close(); +// packetToSend.errorString += " Shutdown alert received"; +// emit errorMessage(tr("%1: shutdown alert received").arg(name)); + //socket.close(); pingTimer.stop(); return; } @@ -164,13 +153,14 @@ void DtlsAssociation::readyRead() } else { //! [7] //! [8] - if (!crypto.doHandshake(&socket, dgram)) { - packetToSend.errorString += " handshake error "; - emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString())); - return; - } + QThread::msleep(HANDSHAKE_STEPS_TIMEOUT); + if (!crypto.doHandshake(&socket, dgram)) { + packetToSend.errorString += " handshake error "; + emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString())); + return; + } //! [8] - crypto.doHandshake(&socket, dgram); + //crypto.doHandshake(&socket, dgram); //! [9] if (crypto.isConnectionEncrypted()) { emit infoMessage(tr("%1: encrypted connection established!").arg(name)); diff --git a/src/dtlsserver.cpp b/src/dtlsserver.cpp index c7feb777..10a75f6b 100644 --- a/src/dtlsserver.cpp +++ b/src/dtlsserver.cpp @@ -6,9 +6,11 @@ #include #include +bool DtlsServer::closeNotifyReceived = false; namespace { + QString peer_info(const QHostAddress &address, quint16 port) { const static QString info = QStringLiteral("(%1:%2)"); @@ -35,6 +37,7 @@ QString connection_info(QDtls *connection) } // unnamed namespace + //! [1] DtlsServer::DtlsServer() { @@ -88,11 +91,14 @@ void DtlsServer::readyRead() QHostAddress peerAddress; quint16 peerPort = 0; const qint64 bytesRead = serverSocket.readDatagram(dgram.data(), dgram.size(), - &peerAddress, &peerPort); + &peerAddress, &peerPort); if (bytesRead <= 0) { emit warningMessage(tr("Failed to read a datagram: ") + serverSocket.errorString()); return; } +// if (dgram.contains("00")){ +// int ret = 1; +// } dgram.resize(bytesRead); //! [3] @@ -115,27 +121,45 @@ void DtlsServer::readyRead() //! [5] //! [6] - if ((*client)->isConnectionEncrypted()) { + + QDtls * dtlsServer = client->get(); + + if (dtlsServer->isConnectionEncrypted()) { QSettings settings(SETTINGSFILE, QSettings::IniFormat); + bool sendResponse = settings.value("sendReponse", false).toBool(); + bool sendSmartResponse = settings.value("sendSmartResponse", false).toBool(); - QDtls * dtlsServer = client->get(); dgram = dtlsServer->decryptDatagram(&serverSocket, dgram); + QByteArray closeNotify("close notify"); + + std::vector recievedPacketInfo = createInfoVect(dtlsServer->peerAddress(), dtlsServer->peerPort(), serverSocket.localAddress(), serverSocket.localPort()); + if (dtlsServer->dtlsError() == QDtlsError::RemoteClosedConnectionError){ + dgram = closeNotify; + closeNotifyReceived = true; + //dtlsServer->shutdown(&serverSocket); + sendResponse = false; + knownClients.erase(client); + + } Packet recivedPacket = createPacket(recievedPacketInfo, dgram); emit serverPacketReceived(recivedPacket); - if(settings.value("sendSimpleAck").toString() == "true"){ + if(settings.value("sendSimpleAck").toString() == "true" && !dgram.contains("close notify")){ + //if(settings.value("sendSimpleAck").toString() == "true" && closeNotifyReceived == false){ sendAck(dtlsServer, dgram); + return; + } else { + errorMessage("close notify recieved"); } - bool sendResponse = settings.value("sendReponse", false).toBool(); - bool sendSmartResponse = settings.value("sendReponse", false).toBool(); - smartData.clear(); + smartData.clear(); + //sendSmartResponse = true; if (sendSmartResponse) { QList smartList; smartList.append(Packet::fetchSmartConfig(1, SETTINGSFILE)); @@ -143,20 +167,34 @@ void DtlsServer::readyRead() smartList.append(Packet::fetchSmartConfig(3, SETTINGSFILE)); smartList.append(Packet::fetchSmartConfig(4, SETTINGSFILE)); smartList.append(Packet::fetchSmartConfig(5, SETTINGSFILE)); - smartData = Packet::smartResponseMatch(smartList, dgram); + if(!smartData.isEmpty()){ + //TODO: if(responseEnableCheck1 == true) + if(serverResonse(client->get())){ + return; + } + } + + } - if (sendResponse || !smartData.isEmpty()) { - if(serverResonse(client->get())){ -// QMessageBox::critical(nullptr, "Connection Error", "server response can't be sent."); - } + //sendResponse =false; + + if (sendResponse) { + //if(!dgram.contains("close notify")){ + + if(serverResonse(client->get())){ + return; + // QMessageBox::critical(nullptr, "Connection Error", "server response can't be sent."); + } + //} } - if ((*client)->dtlsError() == QDtlsError::RemoteClosedConnectionError) - knownClients.erase(client); +// if ((*client)->dtlsError() == QDtlsError::RemoteClosedConnectionError) +// knownClients.erase(client); + return; } //! [6] @@ -240,13 +278,16 @@ void DtlsServer::sendAck(QDtls *connection, const QByteArray &clientMessage) if (clientMessage.size()) { std::vector sentPacketInfo = createInfoVect(serverSocket.localAddress(), serverSocket.localPort(), connection->peerAddress(), connection->peerPort()); Packet sentPacket = createPacket(sentPacketInfo, clientMessage); - if(connection->writeDatagramEncrypted(&serverSocket, tr("from %1: %2").arg(serverInfo, QString::fromUtf8(clientMessage)).toLatin1())){ - QString massageFromTheOtherPeer = "ACK: " + QString::fromUtf8(clientMessage); - sentPacket.hexString = sentPacket.ASCIITohex(massageFromTheOtherPeer); - emit serverPacketSent(sentPacket); - }else{ - sentPacket.errorString = "Could not send response"; - emit serverPacketSent(sentPacket); + if(connection->isConnectionEncrypted()){ + + if(connection->writeDatagramEncrypted(&serverSocket, tr("from %1: %2").arg(serverInfo, QString::fromUtf8(clientMessage)).toLatin1())){ + QString massageFromTheOtherPeer = "ACK: " + QString::fromUtf8(clientMessage); + sentPacket.hexString = sentPacket.ASCIITohex(massageFromTheOtherPeer); + emit serverPacketSent(sentPacket); + }else{ + sentPacket.errorString = "Could not send response"; + emit serverPacketSent(sentPacket); + } } } else if (connection->dtlsError() == QDtlsError::NoError) { emit warningMessage(peerInfo + ": " + tr("0 byte dgram, could be a re-connect attempt?")); @@ -331,16 +372,18 @@ bool DtlsServer::serverResonse(QDtls* dtlsServer){ } serverSocket.waitForBytesWritten(); - if(dtlsServer->writeDatagramEncrypted(&serverSocket,responsePacket.getByteArray())){ - emit serverPacketSent(responsePacket); - return true; - }else{ - responsePacket.errorString = "Could not send response"; - emit serverPacketSent(responsePacket); - return false; - } + if(dtlsServer->isConnectionEncrypted()){ + if(dtlsServer->writeDatagramEncrypted(&serverSocket,responsePacket.getByteArray())){ + emit serverPacketSent(responsePacket); + return true; + }else{ + responsePacket.errorString = "Could not send response"; + emit serverPacketSent(responsePacket); + return false; + } + } } diff --git a/src/dtlsserver.h b/src/dtlsserver.h index b5ef01e2..23cae052 100644 --- a/src/dtlsserver.h +++ b/src/dtlsserver.h @@ -17,6 +17,9 @@ class DtlsServer : public QObject Q_OBJECT public: + static bool closeNotifyReceived; // Initialize static member + + QSslCertificate certificate; QSslKey privateKey; QSslCertificate caCertificate; @@ -51,7 +54,7 @@ class DtlsServer : public QObject - + //bool closeNotifyRecieved; QUdpSocket serverSocket; QByteArray smartData; @@ -88,6 +91,7 @@ public slots: QDtlsClientVerifier cookieSender; std::vector> knownClients; + Q_DISABLE_COPY(DtlsServer) }; //! [0] diff --git a/src/dtlsthread.cpp b/src/dtlsthread.cpp index df742eec..fd8744e7 100644 --- a/src/dtlsthread.cpp +++ b/src/dtlsthread.cpp @@ -3,6 +3,8 @@ #include "packet.h" #include "association.h" #include "packetnetwork.h" +#include "mainwindow.h" +#include //#include "QSettings" @@ -17,15 +19,24 @@ Dtlsthread::~Dtlsthread() { void Dtlsthread::run() { + handShakeDone = false; dtlsAssociation = initDtlsAssociation(); dtlsAssociation->closeRequest = false; connect(dtlsAssociation, &DtlsAssociation::handShakeComplited,this, &Dtlsthread::handShakeComplited); dtlsAssociation->startHandshake(); + //dtlsAssociation->crypto.continueHandshake() + connect(&(dtlsAssociation->crypto), &QDtls::handshakeTimeout, this, &Dtlsthread::onHandshakeTimeout); writeMassage(sendpacket, dtlsAssociation); - persistentConnectionLoop(); - connectStatus("Connected"); + dtlsAssociation->socket.waitForReadyRead(); + if(persistentRequest){ + persistentConnectionLoop(); + connectStatus("Connected"); + } + else{ + return; + } } @@ -75,10 +86,11 @@ void Dtlsthread::handShakeComplited(){ void Dtlsthread::writeMassage(Packet packetToSend, DtlsAssociation* dtlsAssociation){ const qint64 written = dtlsAssociation->crypto.writeDatagramEncrypted(&(dtlsAssociation->socket), packetToSend.asciiString().toLatin1()); if (written <= 0) { - packetToSend.errorString.append(", Failed to send"); - if(dtlsAssociation->crypto.isConnectionEncrypted()){ + packetToSend.errorString.append(" Failed to send"); + //if(dtlsAssociation->crypto.isConnectionEncrypted()){ emit packetSent(packetToSend); - } + + //} return; } emit packetSent(packetToSend); @@ -218,7 +230,10 @@ void Dtlsthread::persistentConnectionLoop() } } // end while connected + emit connectStatus("Disconnected"); + if (dtlsAssociation->closeRequest) { + emit connectStatus("Disconnected"); clientConnection->close(); clientConnection->waitForDisconnected(100); //quit(); @@ -228,6 +243,9 @@ void Dtlsthread::persistentConnectionLoop() } void Dtlsthread::receivedDatagram(QByteArray plainText){ + respondRecieved = true; + //MainWindow *parentNetwork = qobject_cast(parent()); + //connect(this, SIGNAL(packetReceived(Packet)), parentNetwork, SLOT(toTrafficLog(Packet))); recievedMassage = QString::fromUtf8(plainText); Packet recPacket; recPacket.init(); @@ -271,13 +289,36 @@ void Dtlsthread::sendPersistant(Packet sendpacket) } void Dtlsthread::onTimeout(){ - dtlsAssociation->closeRequest = true; - timer->stop(); - if(!(dtlsAssociation->crypto.isConnectionEncrypted())){ - //QString errors = dtlsAssociation->crypto.dtlsErrorString(); - sendpacket.errorString = "Error " + dtlsAssociation->packetToSend.errorString /*+ errors*/ ; - emit packetSent(sendpacket); + if(respondRecieved == false){ + dtlsAssociation->closeRequest = true; + +// if(!handShakeDone && retries < 5){//we can test handShakeDone for each thread because the server serving only one client at one time according to the udp socket +// retries++; +// dtlsAssociation->startHandshake(); +// +// }else{ + sendpacket.errorString = "Error timeout" + dtlsAssociation->packetToSend.errorString /*+ errors*/ ; + //emit packetSent(sendpacket); + handShakeDone = false; + closeRequest = true; + timer->stop(); +// } + } else{ + closeRequest = true; + timer->stop(); + this->exit(); } + + //dtlsAssociation->closeRequest = true; + //timer->stop(); + //&& leaveSessionOpen + //emit packetSent(sendpacket); + + //if(!(dtlsAssociation->crypto.isConnectionEncrypted())){ + // //QString errors = dtlsAssociation->crypto.dtlsErrorString(); + // sendpacket.errorString = "Error timeout" + dtlsAssociation->packetToSend.errorString /*+ errors*/ ; + // emit packetSent(sendpacket); + //} } DtlsAssociation* Dtlsthread::initDtlsAssociation(){ @@ -295,12 +336,17 @@ DtlsAssociation* Dtlsthread::initDtlsAssociation(){ sendpacket.fromPort = dtlsAssociationP->socket.localPort(); connect(dtlsAssociationP, &DtlsAssociation::receivedDatagram, this, &Dtlsthread::receivedDatagram); PacketNetwork *parentNetwork = qobject_cast(parent()); - connect(this, SIGNAL(packetReceived(Packet)), parentNetwork, SLOT(toTrafficLog(Packet))); + //connect(this, SIGNAL(packetReceived(Packet)), parentNetwork, SLOT(toTrafficLog(Packet))); dtlsAssociationP->setCipher(settings.value("cipher", "cipher suit doesn't found").toString()); return dtlsAssociationP; } +void Dtlsthread::onHandshakeTimeout() { + // Introduce a delay before retrying + QTimer::singleShot(1000, this, &Dtlsthread::retryHandshake); +} - - +void Dtlsthread::retryHandshake() { + dtlsAssociation->crypto.handleTimeout(&dtlsAssociation->socket); +} diff --git a/src/dtlsthread.h b/src/dtlsthread.h index da01c7ef..eb6d4e30 100644 --- a/src/dtlsthread.h +++ b/src/dtlsthread.h @@ -12,6 +12,8 @@ class Dtlsthread : public QThread Q_OBJECT public: + bool respondRecieved = false; + int retries = 0; Dtlsthread(Packet sendPacket, QObject *parent); DtlsAssociation* initDtlsAssociation(); virtual ~Dtlsthread(); @@ -19,6 +21,7 @@ class Dtlsthread : public QThread void run() override; // Pure virtual function making this class abstract std::vector getCmdInput(Packet sendpacket, QSettings& settings); void writeMassage(Packet packetToSend, DtlsAssociation* dtlsAssociation); + void retryHandshake(); QTimer* timer; std::vector dtlsAssociations; @@ -30,8 +33,10 @@ class Dtlsthread : public QThread bool closeRequest; bool handShakeDone; bool insidePersistent; + bool persistentRequest = false; public slots: + void onHandshakeTimeout(); void onTimeout(); void sendPersistant(Packet sendpacket); void handShakeComplited(); diff --git a/src/globals.h b/src/globals.h index d4683026..94b444fd 100755 --- a/src/globals.h +++ b/src/globals.h @@ -13,6 +13,9 @@ #define SW_VERSION "8.6.5" //END SW VERSION +#define HANDSHAKE_STEPS_TIMEOUT 10 /* Milliseconds */ +#define DTLS_THREAS_TIME_TO_LIVE 1000 /* Milliseconds */ + //BEGIN FILE VERSION #define VER_FILEVERSION 8,6,5,0 //END FILE VERSION diff --git a/src/packetnetwork.cpp b/src/packetnetwork.cpp index eb77f6ce..643bf7d6 100755 --- a/src/packetnetwork.cpp +++ b/src/packetnetwork.cpp @@ -937,11 +937,13 @@ void PacketNetwork::packetToSend(Packet sendpacket) << connect(thread, SIGNAL(destroyed()), this, SLOT(disconnected())); if(settings.value("leaveSessionOpen").toString() == "true"){ + thread->persistentRequest=true; PersistentConnection * pcWindow = new PersistentConnection(); pcWindow->sendPacket = sendpacket; - pcWindow->init(); pcWindow->dthread = thread; + pcWindow->init(); + QDEBUG() << ": thread Connection attempt " << connect(pcWindow, SIGNAL(persistentPacketSend(Packet)), thread, SLOT(sendPersistant(Packet))) @@ -952,13 +954,18 @@ void PacketNetwork::packetToSend(Packet sendpacket) pcWindow->show(); thread->start(); + } else{ - thread->start(); + //connect(*(thread->dtlsAssociation), &QDtls::handshakeTimeout, *thread, &Dtlsthread::onHandshakeTimeout); + QTimer* timer = new QTimer(this); + //timer->setSingleShot(true); // Make the timer single-shot thread->timer = timer; connect(timer, SIGNAL(timeout()), thread, SLOT(onTimeout())); - timer->start(2000); + timer->start(1000); + thread->start(); + } dtlsthreadList.append(thread); diff --git a/src/persistentconnection.cpp b/src/persistentconnection.cpp index 6a21a962..daf43065 100755 --- a/src/persistentconnection.cpp +++ b/src/persistentconnection.cpp @@ -225,28 +225,69 @@ void PersistentConnection::cancelResends() reSendPacket.clear(); } +void PersistentConnection::initDTLS() +{ + + this->dthread = nullptr; + QString tcpOrSSL = "TCP"; + if (sendPacket.isSSL()) { + tcpOrSSL = "SSL"; + } + if(sendPacket.isDTLS()){ + tcpOrSSL = "DTLS"; + } + setWindowTitle(tcpOrSSL + "://" + sendPacket.toIP + ":" + QString::number(sendPacket.port)); + + + reSendPacket.clear(); + if (sendPacket.repeat > 0) { + QDEBUG() << "This packet is repeating"; + reSendPacket = sendPacket; + } else { + + ui->stopResendingButton->hide(); + } + + + QApplication::processEvents(); + + + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + bool appendCR = settings.value("appendCRcheck", true).toBool(); + ui->appendCRcheck->setChecked(appendCR); + + this->darkMode = settings.value("darkModeCheck", true).toBool(); + + + ui->stopResendingButton->setStyleSheet(PersistentConnection::RESEND_BUTTON_STYLE); + ui->stopResendingButton->setFlat(true); + ui->stopResendingButton->setCursor(Qt::PointingHandCursor); + ui->stopResendingButton->setIcon(QIcon(PSLOGO)); + + connect(ui->stopResendingButton, &QPushButton::clicked, this, &PersistentConnection::cancelResends); + +} void PersistentConnection::refreshTimerTimeout() { //QDEBUG(); - qint64 diff = startTime.msecsTo(QDateTime::currentDateTime()); - - if (thread->isRunning() && !thread->closeRequest) { - QString winTitle = windowTitle(); - if (winTitle.startsWith("TCP://") && thread->isEncrypted()) { - if(sendPacket.isDTLS()){ + QString winTitle = windowTitle(); + if (sendPacket.isDTLS()){ + if(winTitle.startsWith("TCP://")){ + if(dthread->handShakeDone){ winTitle.replace("TCP://", "DTLS://"); setWindowTitle(winTitle); - }else{ - winTitle.replace("TCP://", "SSL://"); - setWindowTitle(winTitle); } - } + } else{ + winTitle.replace("TCP://", "SSL://"); + setWindowTitle(winTitle); } + + qint64 hours = diff / (1000 * 60 * 60); qint64 diffRem = diff - hours * (1000 * 60 * 60); qint64 min = diffRem / (1000 * 60); diff --git a/src/persistentconnection.h b/src/persistentconnection.h index 45fa4031..0f112ba7 100755 --- a/src/persistentconnection.h +++ b/src/persistentconnection.h @@ -32,6 +32,7 @@ class PersistentConnection : public QDialog static const QString RESEND_BUTTON_STYLE; void init(); + void initDTLS(); void initWithThread(TCPThread *thethread, quint16 portNum); signals: diff --git a/src/settings.cpp b/src/settings.cpp index 06c81492..0e10ed7e 100755 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -131,6 +131,7 @@ Settings::Settings(QWidget *parent, MainWindow* mw) : on_genAuthCheck_clicked(false); //smart responses... + sendSmartResponse = ui->smartResponseEnableCheck; ui->smartResponseEnableCheck->setChecked(settings.value("smartResponseEnableCheck", false).toBool()); #define RESPONSEIF(NUM) ui->responseIfEdit##NUM->setText(settings.value("responseIfEdit" #NUM,"").toString()) @@ -423,6 +424,7 @@ void Settings::on_buttonBox_accepted() settings.setValue("sslPort", intListToPorts(sslList)); settings.setValue("sendReponse", ui->sendResponseSettingsCheck->isChecked()); + settings.setValue("sendSmartResponse", ui->smartResponseEnableCheck->isChecked()); settings.setValue("responseName", ui->responsePacketBox->currentText().trimmed()); settings.setValue("responseHex", ui->hexResponseEdit->text().trimmed()); diff --git a/src/settings.h b/src/settings.h index 702a32a4..d3603b9a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -68,6 +68,7 @@ class Settings : public QDialog public: MainWindow* rmw; QCheckBox* sendSimpleAck; + QCheckBox* sendSmartResponse; QLineEdit* sslLocalCertificatePath; QString initialSslLocalCertificatePath; QString initialSslCaPath;