diff --git a/src/PacketSender.pro b/src/PacketSender.pro index 6812c530..fb4cadc4 100755 --- a/src/PacketSender.pro +++ b/src/PacketSender.pro @@ -18,6 +18,9 @@ TRANSLATIONS += languages/packetsender_en.ts \ languages/packetsender_it.ts SOURCES += mainwindow.cpp \ + association.cpp \ + dtlsserver.cpp \ + dtlsthread.cpp \ languagechooser.cpp \ panel.cpp \ sendpacketbutton.cpp \ @@ -35,6 +38,9 @@ SOURCES += mainwindow.cpp \ persistenthttp.cpp HEADERS += mainwindow.h \ + association.h \ + dtlsserver.h \ + dtlsthread.h \ languagechooser.h \ panel.h \ sendpacketbutton.h \ diff --git a/src/association.cpp b/src/association.cpp new file mode 100644 index 00000000..88368182 --- /dev/null +++ b/src/association.cpp @@ -0,0 +1,248 @@ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "association.h" +#include "packet.h" + +DtlsAssociation::DtlsAssociation(QHostAddress &address, quint16 port, + const QString &connectionName, std::vector cmdComponents) + : name(connectionName), + crypto(QSslSocket::SslClientMode) +{ + + + QFile certFile(cmdComponents[4]);//4 + if(!certFile.open(QIODevice::ReadOnly)){ + return; + } + QSsl::EncodingFormat format = getCertFormat(certFile); + QSslCertificate certificate(&certFile, format); + if (certificate.isNull()) { + packetToSend.errorString += "Your local certificate content isn't structured as any certificate format"; + } + + //key + QFile keyFile(cmdComponents[3]);//3 + if(!keyFile.open(QIODevice::ReadOnly)){ + return; + } + QSslKey privateKey = getPrivateKey(keyFile); + + //ca-cert + QFile caCertFile(cmdComponents[5]);//5 + if(!caCertFile.open(QIODevice::ReadOnly)){ + return; + } + //getCertFormat + QSsl::EncodingFormat formatCa = getCertFormat(caCertFile); + QSslCertificate caCertificate(&caCertFile, formatCa); + if (caCertificate.isNull()) { + packetToSend.errorString += "Your ca-certificate content isn't structured as any certificate format"; + } + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QString hostName = settings.value("hostNameEdit").toString(); + + //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]; + } + + } + } + } + + configuration.setLocalCertificate(certificate); + configuration.setPrivateKey(privateKey); + configuration.setCaCertificates(QList() << caCertificate); + + configuration.setPeerVerifyMode(QSslSocket::VerifyPeer); + crypto.setPeer(address, port); + crypto.setPeerVerificationName(hostName); + crypto.setDtlsConfiguration(configuration); + + hostName = ""; + connect(&crypto, &QDtls::pskRequired, this, &DtlsAssociation::pskRequired); + //! [3] + socket.connectToHost(address.toString(), port); + socket.waitForConnected(); + //! [3] + //! [13] + connect(&socket, &QUdpSocket::readyRead, this, &DtlsAssociation::readyRead); + //! [13] + +} + +//! [12] +DtlsAssociation::~DtlsAssociation() +{ + if (crypto.isConnectionEncrypted()) + crypto.shutdown(&socket); +} +//! [12] + +//! [5] +void DtlsAssociation::startHandshake() +{ + if (socket.state() != QAbstractSocket::ConnectedState) { + emit infoMessage(tr("%1: connecting UDP socket first ...").arg(name)); + connect(&socket, &QAbstractSocket::connected, this, &DtlsAssociation::udpSocketConnected); + return; + } + + if (!crypto.doHandshake(&socket)){ + 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(); + if(crypto.isConnectionEncrypted() || closeRequest){ + + break; + + } + } + emit infoMessage(tr("%1: starting a handshake").arg(name)); + } + +} +//! [5] + +void DtlsAssociation::udpSocketConnected() +{ + emit infoMessage(tr("%1: UDP socket is now in ConnectedState, continue with handshake ...").arg(name)); + startHandshake(); +} + + +void DtlsAssociation::readyRead() +{ + + if (socket.pendingDatagramSize() <= 0) { + emit warningMessage(tr("%1: spurious read notification?").arg(name)); + return; + } + + //! [6] + QByteArray dgram(socket.pendingDatagramSize(), Qt::Uninitialized); + const qint64 bytesRead = socket.readDatagram(dgram.data(), dgram.size()); + if (bytesRead <= 0) { + emit warningMessage(tr("%1: spurious read notification?").arg(name)); + return; + } + + dgram.resize(bytesRead); + //! [6] + //! [7] + if (crypto.isConnectionEncrypted()) { + const QByteArray plainText = crypto.decryptDatagram(&socket, dgram); + if (plainText.size()) { + emit receivedDatagram(plainText); + return; + } + + if (crypto.dtlsError() == QDtlsError::RemoteClosedConnectionError) { + packetToSend.errorString += " Shutdown alert received"; + emit errorMessage(tr("%1: shutdown alert received").arg(name)); + socket.close(); + pingTimer.stop(); + return; + } + + emit warningMessage(tr("%1: zero-length datagram received?").arg(name)); + } else { + //! [7] + //! [8] + 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); + //! [9] + if (crypto.isConnectionEncrypted()) { + emit infoMessage(tr("%1: encrypted connection established!").arg(name)); + emit handShakeComplited(); + } else { + //! [9] + emit infoMessage(tr("%1: continuing with handshake ...").arg(name)); + } + + } + + +} + + +//! [11] +void DtlsAssociation::handshakeTimeout() +{ + emit warningMessage(tr("%1: handshake timeout, trying to re-transmit").arg(name)); + if (!crypto.handleTimeout(&socket)) + packetToSend.errorString += " Failed to re-transmit "; + + emit errorMessage(tr("%1: failed to re-transmit - %2").arg(name, crypto.dtlsErrorString())); +} +//! [11] + +//! [14] +void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth) +{ + Q_ASSERT(auth); + + emit infoMessage(tr("%1: providing pre-shared key ...").arg(name)); + auth->setIdentity(name.toLatin1()); + auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f")); +} + + +void DtlsAssociation::setCipher(QString chosenCipher) { + configuration.setCiphers(chosenCipher); + crypto.setDtlsConfiguration(configuration); +} + +QSsl::EncodingFormat DtlsAssociation::getCertFormat(QFile& certFile){ + QFileInfo fileInfo(certFile.fileName()); + QString fileExtension = fileInfo.suffix().toLower(); + QSsl::EncodingFormat format; + + if (fileExtension == "pem") { + format = QSsl::Pem; + } else if (fileExtension == "der") { + format = QSsl::Der; + } + return format; +} + +QSslKey DtlsAssociation::getPrivateKey(QFile& keyFile){ + QList keyTypes = { QSsl::Dh, QSsl::Dsa, QSsl::Ec, QSsl::Rsa }; + QSslKey privateKey; + foreach (QSsl::KeyAlgorithm type, keyTypes) { + QSslKey key(&keyFile, type); + if (!key.isNull()) { + privateKey = key; + break; + } + keyFile.reset(); + } + if(privateKey.isNull()){ + packetToSend.errorString += "Your key isn't one of the known key's types: Dh, Dsa, Ec, Rsa"; + } + return privateKey; +} + + + + diff --git a/src/association.h b/src/association.h new file mode 100644 index 00000000..b6d8c5f3 --- /dev/null +++ b/src/association.h @@ -0,0 +1,56 @@ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#ifndef ASSOCIATION_H +#define ASSOCIATION_H + +#include +#include +#include "packet.h" + +//! [0] +class DtlsAssociation : public QObject +{ + Q_OBJECT + +public: + DtlsAssociation(QHostAddress &address, quint16 port, + const QString &connectionName, std::vector cmdComponents); + ~DtlsAssociation(); + void startHandshake(); + void setCipher(QString chosenCipher); + QSsl::EncodingFormat getCertFormat(QFile& certFile); + QSslKey getPrivateKey(QFile& keyFile); + + + QSslConfiguration configuration = QSslConfiguration::defaultDtlsConfiguration(); + QDtls crypto; + QUdpSocket socket; + QString name; + Packet packetToSend; + + bool closeRequest; + +signals: + void errorMessage(const QString &message); + void warningMessage(const QString &message); + void infoMessage(const QString &message); + void handShakeComplited(); + void receivedDatagram(QByteArray plainText); + +private slots: + void udpSocketConnected(); + void readyRead(); + void pskRequired(QSslPreSharedKeyAuthenticator *auth); + void handshakeTimeout(); + +private: + + + QTimer pingTimer; + unsigned ping = 0; + + Q_DISABLE_COPY(DtlsAssociation) +}; + + +#endif // ASSOCIATION_H diff --git a/src/cmd_dtls_client.bat b/src/cmd_dtls_client.bat new file mode 100644 index 00000000..9d832d03 --- /dev/null +++ b/src/cmd_dtls_client.bat @@ -0,0 +1,15 @@ +@echo off + +rem Set environment variables for dataStr, toIP, port, sslPrivateKeyPath, sslLocalCertificatePath, and sslCaPath +@echo dataStr=%1 +@echo toIP=%2 +@echo port=%3 +@echo sslPrivateKeyPath=%4 +@echo sslLocalCertificatePath=%5 +@echo sslCaPath=%6 + +rem Create an empty "session.pem" file +type nul > session.pem + +rem Run your long OpenSSL command +echo %dataStr% | openssl s_client -dtls1_2 -connect %toIP%:%port% -sess_out session.pem -key %sslPrivateKeyPath% -cert %sslLocalCertificatePath% -CAfile %sslCaPath% -verify 2 -cipher AES256-GCM-SHA384 diff --git a/src/cmd_dtls_client.txt b/src/cmd_dtls_client.txt new file mode 100644 index 00000000..48fe3730 --- /dev/null +++ b/src/cmd_dtls_client.txt @@ -0,0 +1,15 @@ +@echo off + +rem Set environment variables for dataStr, toIP, port, sslPrivateKeyPath, sslLocalCertificatePath, and sslCaPath +set dataStr=%1 +set toIP=%2 +set port=%3 +set sslPrivateKeyPath=%4 +set sslLocalCertificatePath=%5 +set sslCaPath=%6 + +rem Create an empty "session.pem" file +type nul > session.pem + +rem Run your long OpenSSL command +echo %dataStr% | openssl s_client -dtls1_2 -connect %toIP%:%port% -sess_out session.pem -key %sslPrivateKeyPath% -cert %sslLocalCertificatePath% -CAfile %sslCaPath% -verify 2 -cipher AES256-GCM-SHA384 diff --git a/src/dtlsserver.cpp b/src/dtlsserver.cpp new file mode 100644 index 00000000..c7feb777 --- /dev/null +++ b/src/dtlsserver.cpp @@ -0,0 +1,525 @@ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "dtlsserver.h" + +#include +#include + + +namespace { + +QString peer_info(const QHostAddress &address, quint16 port) +{ + const static QString info = QStringLiteral("(%1:%2)"); + return info.arg(address.toString()).arg(port); +} + + +QString connection_info(QDtls *connection) +{ + QString info(DtlsServer::tr("Session cipher: ")); + info += connection->sessionCipher().name(); + + info += DtlsServer::tr("; session protocol: "); + switch (connection->sessionProtocol()) { + case QSsl::DtlsV1_2: + info += DtlsServer::tr("DTLS 1.2."); + break; + default: + info += DtlsServer::tr("Unknown protocol."); + } + + return info; +} + +} // unnamed namespace + +//! [1] +DtlsServer::DtlsServer() +{ + connect(&serverSocket, &QAbstractSocket::readyRead, this, &DtlsServer::readyRead); + loadKeyLocalCertCaCert(); +} +//! [1] + +DtlsServer::~DtlsServer() +{ + shutdown(); +} + +//! [2] +bool DtlsServer::listen(const QHostAddress &address, quint16 port) +{ + if (address != serverSocket.localAddress() || port != serverSocket.localPort()) { + shutdown(); + listening = serverSocket.bind(address, port); + if (!listening) + QMessageBox::critical(nullptr, "Bind Error", "The server can't bind " + QString::number(serverSocket.localPort()) + serverSocket.errorString()); + } else { + listening = true; + } + + return listening; +} +//! [2] + +bool DtlsServer::isListening() const +{ + return listening; +} + +void DtlsServer::close() +{ + listening = false; +} + +void DtlsServer::readyRead() +{ + + //! [3] + const qint64 bytesToRead = serverSocket.pendingDatagramSize(); + if (bytesToRead <= 0) { + emit warningMessage(tr("A spurious read notification")); + return; + } + + QByteArray dgram(bytesToRead, Qt::Uninitialized); + QHostAddress peerAddress; + quint16 peerPort = 0; + const qint64 bytesRead = serverSocket.readDatagram(dgram.data(), dgram.size(), + &peerAddress, &peerPort); + if (bytesRead <= 0) { + emit warningMessage(tr("Failed to read a datagram: ") + serverSocket.errorString()); + return; + } + + dgram.resize(bytesRead); + //! [3] + //! [4] + if (peerAddress.isNull() || !peerPort) { + emit warningMessage(tr("Failed to extract peer info (address, port)")); + return; + } + + const auto client = std::find_if(knownClients.begin(), knownClients.end(), + [&](const std::unique_ptr &connection){ + return connection->peerAddress() == peerAddress + && connection->peerPort() == peerPort; + }); + //! [4] + + //! [5] + if (client == knownClients.end()) + return handleNewConnection(peerAddress, peerPort, dgram); + //! [5] + + //! [6] + if ((*client)->isConnectionEncrypted()) { + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + + + QDtls * dtlsServer = client->get(); + dgram = dtlsServer->decryptDatagram(&serverSocket, dgram); + + std::vector recievedPacketInfo = createInfoVect(dtlsServer->peerAddress(), dtlsServer->peerPort(), serverSocket.localAddress(), serverSocket.localPort()); + Packet recivedPacket = createPacket(recievedPacketInfo, dgram); + emit serverPacketReceived(recivedPacket); + + if(settings.value("sendSimpleAck").toString() == "true"){ + sendAck(dtlsServer, dgram); + } + + bool sendResponse = settings.value("sendReponse", false).toBool(); + bool sendSmartResponse = settings.value("sendReponse", false).toBool(); + + + smartData.clear(); + + if (sendSmartResponse) { + QList smartList; + smartList.append(Packet::fetchSmartConfig(1, SETTINGSFILE)); + smartList.append(Packet::fetchSmartConfig(2, SETTINGSFILE)); + smartList.append(Packet::fetchSmartConfig(3, SETTINGSFILE)); + smartList.append(Packet::fetchSmartConfig(4, SETTINGSFILE)); + smartList.append(Packet::fetchSmartConfig(5, SETTINGSFILE)); + + smartData = Packet::smartResponseMatch(smartList, dgram); + } + + if (sendResponse || !smartData.isEmpty()) { + if(serverResonse(client->get())){ +// QMessageBox::critical(nullptr, "Connection Error", "server response can't be sent."); + } + + } + + + if ((*client)->dtlsError() == QDtlsError::RemoteClosedConnectionError) + knownClients.erase(client); + return; + } + //! [6] + + //! [7] + doHandshake(client->get(), dgram); + //! [7] +} + +//! [13] +void DtlsServer::pskRequired(QSslPreSharedKeyAuthenticator *auth) +{ + Q_ASSERT(auth); + + emit infoMessage(tr("PSK callback, received a client's identity: '%1'") + .arg(QString::fromLatin1(auth->identity()))); + auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f")); +} +//! [13] + +//! [8] +void DtlsServer::handleNewConnection(const QHostAddress &peerAddress, + quint16 peerPort, const QByteArray &clientHello) +{ + if (!listening) + return; + + const QString peerInfo = peer_info(peerAddress, peerPort); + if (cookieSender.verifyClient(&serverSocket, clientHello, peerAddress, peerPort)) { + emit infoMessage(peerInfo + tr(": verified, starting a handshake")); + //! [8] + //! [9] + std::unique_ptr newConnection{new QDtls{QSslSocket::SslServerMode}}; + newConnection->setDtlsConfiguration(serverConfiguration); + newConnection->setPeer(peerAddress, peerPort); + newConnection->connect(newConnection.get(), &QDtls::pskRequired, + this, &DtlsServer::pskRequired); + knownClients.push_back(std::move(newConnection)); + doHandshake(knownClients.back().get(), clientHello); + //! [9] + } else if (cookieSender.dtlsError() != QDtlsError::NoError) { + emit errorMessage(tr("DTLS error: ") + cookieSender.dtlsErrorString()); + } else { + emit infoMessage(peerInfo + tr(": not verified yet")); + } +} + +//! [11] +void DtlsServer::doHandshake(QDtls *newConnection, const QByteArray &clientHello) +{ + const bool result = newConnection->doHandshake(&serverSocket, clientHello); + if (!result) { + emit errorMessage(newConnection->dtlsErrorString()); + return; + } + + const QString peerInfo = peer_info(newConnection->peerAddress(), + newConnection->peerPort()); + switch (newConnection->handshakeState()) { + case QDtls::HandshakeInProgress: + emit infoMessage(peerInfo + tr(": handshake is in progress ...")); + break; + case QDtls::HandshakeComplete: + emit infoMessage(tr("Connection with %1 encrypted. %2") + .arg(peerInfo, connection_info(newConnection))); + break; + default: + Q_UNREACHABLE(); + } +} +//! [11] + +//! [12] +void DtlsServer::sendAck(QDtls *connection, const QByteArray &clientMessage) +{ + Q_ASSERT(connection->isConnectionEncrypted()); + + const QString peerInfo = peer_info(connection->peerAddress(), connection->peerPort()); + const QString serverInfo = peer_info(serverSocket.localAddress(), serverSocket.localPort()); + + 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); + } + } else if (connection->dtlsError() == QDtlsError::NoError) { + emit warningMessage(peerInfo + ": " + tr("0 byte dgram, could be a re-connect attempt?")); + } else { + emit errorMessage(peerInfo + ": " + connection->dtlsErrorString()); + } +} +//! [12] + +//! [14] +void DtlsServer::shutdown() +{ + for (const auto &connection : std::exchange(knownClients, {})) + connection->shutdown(&serverSocket); + + serverSocket.close(); +} +//! [14] + +//this function using for creation packet that can be sent to packetReceivedECHO +Packet DtlsServer::createPacket(const std::vector& packetInfo, const QByteArray& dgram){ + + Packet recPacket; + recPacket.init(); + recPacket.fromIP = packetInfo[0]; + recPacket.fromPort = packetInfo[1].toUInt(); + recPacket.toIP = packetInfo[2]; + recPacket.port = packetInfo[3].toUInt(); + QString massageFromTheOtherPeer = QString::fromUtf8(dgram); + recPacket.hexString = recPacket.ASCIITohex(massageFromTheOtherPeer); + recPacket.tcpOrUdp = "DTLS"; + + if(packetInfo[0] == "0.0.0.0"){ + recPacket.fromIP = "you"; + } + if(packetInfo[2] == "0.0.0.0"){ + recPacket.toIP = "127.0.0.1"; + } + + return recPacket; + + +} + +std::vector DtlsServer::createInfoVect(const QHostAddress &fromAddress, quint16 fromPort, const QHostAddress &toAddress, quint16 toPort){ + std::vector infoVect; + infoVect.push_back(fromAddress.toString()); + infoVect.push_back(QString::number(fromPort)); + infoVect.push_back(toAddress.toString()); + infoVect.push_back(QString::number(toPort)); + return infoVect; + +} + +bool DtlsServer::serverResonse(QDtls* dtlsServer){ + + Packet responsePacket; + responsePacket.init(); + + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QString responseData = (settings.value("responseHex", "")).toString(); + + responsePacket.timestamp = QDateTime::currentDateTime(); + responsePacket.name = responsePacket.timestamp.toString(DATETIMEFORMAT); + responsePacket.tcpOrUdp = "DTLS"; + responsePacket.fromIP = "You"; + bool isIPv6 = IPv6Enabled(); + if (isIPv6) { + responsePacket.toIP = Packet::removeIPv6Mapping(dtlsServer->peerAddress()); + + } else { + responsePacket.toIP = (dtlsServer->peerAddress()).toString(); + } + responsePacket.port = dtlsServer->peerPort(); + responsePacket.fromPort = serverSocket.localPort(); + responsePacket.hexString = responseData; + QString testMacro = Packet::macroSwap(responsePacket.asciiString()); + responsePacket.hexString = Packet::ASCIITohex(testMacro); + + if (!smartData.isEmpty()) { + responsePacket.hexString = Packet::byteArrayToHex(smartData); + } + + 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; + + } + + +} + + + +bool DtlsServer::IPv6Enabled() +{ + return !IPv4Enabled(); +} + +bool DtlsServer::IPv4Enabled() +{ + QString ipMode = getIPmode(); + if(ipMode == "4") { + return true; + } + return (ipMode.contains("v4") || ipMode.contains(".")); +} + +QString DtlsServer::getIPmode() +{ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QString ipMode = settings.value("ipMode", "4").toString(); + + QHostAddress iph = Packet::IPV4_IPV6_ANY(ipMode); + + if(iph == QHostAddress::AnyIPv4) { + return "IPv4 Mode"; + } + if(iph == QHostAddress::AnyIPv6) { + return "IPv6 Mode"; + } + + return ipMode; +} + +QHostAddress DtlsServer::resolveDNS(QString hostname) +{ + + QHostAddress address(hostname); + if (QAbstractSocket::IPv4Protocol == address.protocol()) { + return address; + } + + if (QAbstractSocket::IPv6Protocol == address.protocol()) { + return address; + } + + QHostInfo info = QHostInfo::fromName(hostname); + if (info.error() != QHostInfo::NoError) { + return QHostAddress(); + } else { + + return info.addresses().at(0); + } +} + +void DtlsServer::loadKeyLocalCertCaCert(){ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + settings.value("sslCaPath", SETTINGSPATH + "cert.pem"); + + QString localCertPath = settings.value("sslLocalCertificatePath", SETTINGSPATH + "cert.pem").toString(); + QFile certFile(localCertPath); + + if(!certFile.open(QIODevice::ReadOnly) && !(localCertPath.isEmpty())){ + QMessageBox::critical(nullptr, "Certificate Error", "Local certificate path can't opened."); + return; + } + + //getCertFormat + QSsl::EncodingFormat format = getCertFormat(certFile); + QSslCertificate currentCertificate(&certFile, format); + certificate = currentCertificate; + if (currentCertificate.isNull() && !(localCertPath.isEmpty())) { + QMessageBox::critical(nullptr, "Certificate Error", "Local certificate is not valid."); + return; + } + + QString keyPath = settings.value("sslPrivateKeyPath", SETTINGSPATH + "key.pem").toString(); + QFile keyFile(keyPath); + + if(!keyFile.open(QIODevice::ReadOnly) && !(keyPath.isEmpty())){ + QMessageBox::critical(nullptr, "Key Error", "Key path can't opened."); + return; + } + + privateKey = getPrivateKey(keyFile); + + + + //get the full path to to ca-signed-cert.pem file + QString fullCaCertPath = getFullPathToCaCert(); + QFile caCertFile(fullCaCertPath); + + if(!caCertFile.open(QIODevice::ReadOnly) && !(fullCaCertPath.isEmpty())){ + QMessageBox::critical(nullptr, "Ca-Certificate Error", "Ca-Certificate path can't opened."); + return; + } + + QSsl::EncodingFormat formatCa = getCertFormat(caCertFile); + QSslCertificate currentCaCertificate(&caCertFile, formatCa); + caCertificate = currentCaCertificate; + + if (currentCaCertificate.isNull() && !(fullCaCertPath.isEmpty())) { + QMessageBox::critical(nullptr, "Ca-Certificate Error", "Ca-Certificate is not valid."); + return; + } + + setConfiguration(); +} + +void DtlsServer::setConfiguration(){ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + serverConfiguration = QSslConfiguration::defaultDtlsConfiguration(); + serverConfiguration.setLocalCertificate(certificate); + serverConfiguration.setPrivateKey(privateKey); + serverConfiguration.setCaCertificates(QList() << caCertificate); + if(settings.value("twoVerify").toString() == "true"){ + serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer); + } else{ + serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); + } +} + +void DtlsServer::on_signedCert_textChanged(){ + loadKeyLocalCertCaCert(); +} + +QSsl::EncodingFormat DtlsServer::getCertFormat(QFile& certFile){ + QFileInfo fileInfo(certFile.fileName()); + QString fileExtension = fileInfo.suffix().toLower(); + QSsl::EncodingFormat format; + + if (fileExtension == "pem") { + format = QSsl::Pem; + } else if (fileExtension == "der") { + format = QSsl::Der; + } + return format; +} + +QSslKey DtlsServer::getPrivateKey(QFile& keyFile){ + QList keyTypes = { QSsl::Dh, QSsl::Dsa, QSsl::Ec, QSsl::Rsa }; + QSslKey privateKey; + foreach (QSsl::KeyAlgorithm type, keyTypes) { + QSslKey key(&keyFile, type); + if (!key.isNull()) { + privateKey = key; + break; + } + keyFile.reset(); + } + if(privateKey.isNull() && keyFile.isOpen()){ + QMessageBox::critical(nullptr, "Key Error", "Key is not valid."); + return QSslKey(); + } + return privateKey; +} + +QString DtlsServer::getFullPathToCaCert(){ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QString caCertFolder = settings.value("sslCaPath", SETTINGSPATH + "cert.pem").toString(); + QString fullCaCertPath; + QDir dir(caCertFolder); + if (dir.exists()) { + QStringList nameFilters; + nameFilters << "*.pem" << "*.der"; // Filter for .txt files + + dir.setNameFilters(nameFilters); + QStringList fileList = dir.entryList(); + + if (!fileList.isEmpty()) { + // Select the first file that matches the filter + fullCaCertPath = dir.filePath(fileList.first()); + } else { + qDebug() << "No matching files found."; + } + } else { + qDebug() << "Directory does not exist."; + } + return fullCaCertPath; +} diff --git a/src/dtlsserver.h b/src/dtlsserver.h new file mode 100644 index 00000000..b5ef01e2 --- /dev/null +++ b/src/dtlsserver.h @@ -0,0 +1,96 @@ + +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#ifndef SERVER_H +#define SERVER_H + +#include +#include + +#include +#include +#include "packet.h" + +//! [0] +class DtlsServer : public QObject +{ + Q_OBJECT + +public: + QSslCertificate certificate; + QSslKey privateKey; + QSslCertificate caCertificate; + + QSslConfiguration serverConfiguration; + DtlsServer(); + ~DtlsServer(); + + + + bool listen(const QHostAddress &address, quint16 port); + bool isListening() const; + void close(); + Packet createPacket(const std::vector& packetInfo, const QByteArray& dgram); + std::vector createInfoVect(const QHostAddress &fromAddress, quint16 fromPort, const QHostAddress &toAddress, quint16 toPort); + bool serverResonse(QDtls* dtlsServer); + void loadKeyLocalCertCaCert(); + void setConfiguration(); + QSsl::EncodingFormat getCertFormat(QFile& certFile); + QSslKey getPrivateKey(QFile& keyFile); + QString getFullPathToCaCert(); + + + QString getIPmode(); + bool IPv4Enabled(); + bool IPv6Enabled(); + QHostAddress resolveDNS(QString hostname); + + + + + + + + + QUdpSocket serverSocket; + QByteArray smartData; + + +signals: + void serverPacketReceived(Packet); + void serverPacketSent(Packet); + + + void errorMessage(const QString &message); + void warningMessage(const QString &message); + void infoMessage(const QString &message); + + //void serverDatagramReceived(const QString &peerInfo, const QByteArray &cipherText, const QByteArray &plainText); + +private slots: + void readyRead(); + void pskRequired(QSslPreSharedKeyAuthenticator *auth); + +public slots: + void on_signedCert_textChanged(); + //void serverReceivedDatagram(const QString& peerInfo, const QByteArray &clientMessage, const QByteArray& dgram); + +private: + void handleNewConnection(const QHostAddress &peerAddress, quint16 peerPort, + const QByteArray &clientHello); + + void doHandshake(QDtls *newConnection, const QByteArray &clientHello); + void sendAck(QDtls *connection, const QByteArray &clientMessage); + void shutdown(); + + bool listening = false; + + QDtlsClientVerifier cookieSender; + std::vector> knownClients; + + Q_DISABLE_COPY(DtlsServer) +}; +//! [0] + +#endif // SERVER_H + diff --git a/src/dtlsthread.cpp b/src/dtlsthread.cpp new file mode 100644 index 00000000..df742eec --- /dev/null +++ b/src/dtlsthread.cpp @@ -0,0 +1,306 @@ + +#include "dtlsthread.h" +#include "packet.h" +#include "association.h" +#include "packetnetwork.h" +//#include "QSettings" + + +Dtlsthread::Dtlsthread(Packet sendpacket, QObject *parent) + : QThread(parent), sendpacket(sendpacket) +{} + +Dtlsthread::~Dtlsthread() { + // Destructor implementation (can be empty for this example) +} + + +void Dtlsthread::run() +{ + handShakeDone = false; + dtlsAssociation = initDtlsAssociation(); + dtlsAssociation->closeRequest = false; + connect(dtlsAssociation, &DtlsAssociation::handShakeComplited,this, &Dtlsthread::handShakeComplited); + + dtlsAssociation->startHandshake(); + writeMassage(sendpacket, dtlsAssociation); + persistentConnectionLoop(); + connectStatus("Connected"); +} + + +std::vector Dtlsthread::getCmdInput(Packet sendpacket, QSettings& settings){ + //the array of cmdComponents: dataStr, toIp, toPort, sslPrivateKeyPath, sslLocalCertificatePath, sslCaFullPath + std::vector cmdComponents; + + //get the data of the packet + cmdComponents.push_back(QString::fromUtf8(sendpacket.getByteArray())); + cmdComponents.push_back(sendpacket.toIP); + cmdComponents.push_back(QString::number(sendpacket.port)); + + //get the pathes for verification from the settings + cmdComponents.push_back(settings.value("sslPrivateKeyPath", "default").toString()); + cmdComponents.push_back(settings.value("sslLocalCertificatePath", "default").toString()); + QString sslCaPath = settings.value("sslCaPath", "default").toString(); + + //get the full path to to ca-signed-cert.pem file + QDir dir(sslCaPath); + if (dir.exists()) { + QStringList nameFilters; + nameFilters << "*.pem"; // Filter for .txt files + + dir.setNameFilters(nameFilters); + QStringList fileList = dir.entryList(); + + if (!fileList.isEmpty()) { + // Select the first file that matches the filter + cmdComponents.push_back(dir.filePath(fileList.first())); + } else { + qDebug() << "No matching files found."; + } + } else { + qDebug() << "Directory does not exist."; + } + cmdComponents.push_back(settings.value("cipher", "AES256-GCM-SHA384").toString()); + return cmdComponents; +} + + + + +void Dtlsthread::handShakeComplited(){ + handShakeDone = true; +} + +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()){ + emit packetSent(packetToSend); + } + return; + } + emit packetSent(packetToSend); +} + + + +void Dtlsthread::persistentConnectionLoop() +{ + + QUdpSocket* clientConnection = &(dtlsAssociation->socket); + QDEBUG() << "Entering the forever loop"; + int ipMode = 4; + QHostAddress theAddress(sendpacket.toIP); + if (QAbstractSocket::IPv6Protocol == theAddress.protocol()) { + ipMode = 6; + } + + int count = 0; + while (clientConnection->state() == QAbstractSocket::ConnectedState && !(dtlsAssociation->closeRequest)) { + insidePersistent = true; + + + if (sendpacket.hexString.isEmpty() /*&& sendpacket.persistent */ && (clientConnection->bytesAvailable() == 0)) { + count++; + if (count % 10 == 0) { + emit connectStatus("Connected and idle."); + } + clientConnection->waitForReadyRead(200); + continue; + } + + if (clientConnection->state() != QAbstractSocket::ConnectedState /*&& sendPacket.persistent*/) { + QDEBUG() << "Connection broken."; + emit connectStatus("Connection broken"); + + break; + } + + if (sendpacket.receiveBeforeSend) { + QDEBUG() << "Wait for data before sending..."; + emit connectStatus("Waiting for data"); + clientConnection->waitForReadyRead(500); + + Packet tcpRCVPacket; + tcpRCVPacket.hexString = Packet::byteArrayToHex(clientConnection->readAll()); + if (!tcpRCVPacket.hexString.trimmed().isEmpty()) { + QDEBUG() << "Received: " << tcpRCVPacket.hexString; + emit connectStatus("Received " + QString::number((tcpRCVPacket.hexString.size() / 3) + 1)); + + tcpRCVPacket.timestamp = QDateTime::currentDateTime(); + tcpRCVPacket.name = QDateTime::currentDateTime().toString(DATETIMEFORMAT); + tcpRCVPacket.tcpOrUdp = "DTLS"; + + if (ipMode < 6) { + tcpRCVPacket.fromIP = Packet::removeIPv6Mapping(clientConnection->peerAddress()); + } else { + tcpRCVPacket.fromIP = (clientConnection->peerAddress()).toString(); + } + + + QDEBUGVAR(tcpRCVPacket.fromIP); + tcpRCVPacket.toIP = "You"; + tcpRCVPacket.port = sendpacket.fromPort; + tcpRCVPacket.fromPort = clientConnection->peerPort(); + if (tcpRCVPacket.hexString.size() > 0) { + emit packetSent(tcpRCVPacket); + + // Do I need to reply? + writeMassage(tcpRCVPacket, dtlsAssociation); + + } + + } else { + QDEBUG() << "No pre-emptive receive data"; + } + + } // end receive before send + + if(sendpacket.getByteArray().size() > 0) { + emit connectStatus("Sending data:" + sendpacket.asciiString()); + QDEBUG() << "Attempting write data"; + } + + Packet tcpPacket; + tcpPacket.timestamp = QDateTime::currentDateTime(); + tcpPacket.name = QDateTime::currentDateTime().toString(DATETIMEFORMAT); + tcpPacket.tcpOrUdp = "DTLS"; + + + if (ipMode < 6) { + tcpPacket.fromIP = Packet::removeIPv6Mapping(clientConnection->peerAddress()); + + } else { + tcpPacket.fromIP = (clientConnection->peerAddress()).toString(); + + } + QDEBUGVAR(tcpPacket.fromIP); + + tcpPacket.toIP = "You"; + tcpPacket.port = dtlsAssociation->socket.localPort(); + tcpPacket.fromPort = sendpacket.port; + + clientConnection->waitForReadyRead(500); + emit connectStatus("Waiting to receive"); + tcpPacket.hexString.clear(); + + while (clientConnection->bytesAvailable()) { + tcpPacket.hexString.append(" "); + tcpPacket.hexString.append(Packet::byteArrayToHex(clientConnection->readAll())); + tcpPacket.hexString = tcpPacket.hexString.simplified(); + clientConnection->waitForReadyRead(100); + } + + QDEBUG() << "packetSent " << tcpPacket.name << tcpPacket.hexString.size(); + + if (sendpacket.receiveBeforeSend) { + if (!tcpPacket.hexString.isEmpty()) { + emit packetSent(tcpPacket); + } + } else { + //emit packetSent(tcpPacket); + } + + emit connectStatus("Reading response"); + + tcpPacket.hexString = recievedMassage; + + tcpPacket.timestamp = QDateTime::currentDateTime(); + tcpPacket.name = QDateTime::currentDateTime().toString(DATETIMEFORMAT); + + + if (tcpPacket.hexString.size() > 0) { + tcpPacket.hexString = ""; + recievedMassage = ""; + sendpacket.hexString = ""; + } + + } // end while connected + if (dtlsAssociation->closeRequest) { + clientConnection->close(); + clientConnection->waitForDisconnected(100); + //quit(); + } + + insidePersistent = false; + +} +void Dtlsthread::receivedDatagram(QByteArray plainText){ + recievedMassage = QString::fromUtf8(plainText); + Packet recPacket; + recPacket.init(); + recPacket.fromIP = dtlsAssociation->crypto.peerAddress().toString(); + recPacket.fromPort = dtlsAssociation->crypto.peerPort(); + QString massageFromTheOtherPeer = QString::fromUtf8(plainText); + recPacket.hexString = recPacket.ASCIITohex(massageFromTheOtherPeer); + recPacket.toIP = dtlsAssociation->socket.localAddress().toString(); + recPacket.port = dtlsAssociation->socket.localPort(); + recPacket.tcpOrUdp = "DTLS"; + emit packetReceived(recPacket); +} + + +void Dtlsthread::sendPersistant(Packet sendpacket) +{ + QUdpSocket* clientConnection = &(dtlsAssociation->socket); + + if ((!sendpacket.hexString.isEmpty()) && (clientConnection->state() == QAbstractSocket::ConnectedState)) { + QDEBUGVAR(sendpacket.hexString); + sendpacket.fromPort = clientConnection->localPort(); + writeMassage(sendpacket,dtlsAssociation); + + sendpacket.fromIP = "You"; + + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + int ipMode = settings.value("ipMode", 4).toInt(); + + + if (ipMode < 6) { + sendpacket.toIP = Packet::removeIPv6Mapping(clientConnection->peerAddress()); + } else { + sendpacket.toIP = (clientConnection->peerAddress()).toString(); + } + + sendpacket.port = clientConnection->peerPort(); + sendpacket.fromPort = clientConnection->localPort(); + sendpacket.tcpOrUdp = "DTLS"; + + } +} + +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); + } +} + +DtlsAssociation* Dtlsthread::initDtlsAssociation(){ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + if (settings.status() != QSettings::NoError) { + sendpacket.errorString ="Can't open settings file."; + } + //the vector of cmdComponents contains: dataStr, toIp, toPort, sslPrivateKeyPath, sslLocalCertificatePath, sslCaFullPath, chosen cipher + std::vector cmdComponents = getCmdInput(sendpacket, settings); + const QString ipAddress = cmdComponents[1]; + QHostAddress ipAddressHost; + ipAddressHost.setAddress(ipAddress); + quint16 port = cmdComponents[2].toUShort(); + DtlsAssociation *dtlsAssociationP = new DtlsAssociation(ipAddressHost, port, sendpacket.fromIP, cmdComponents); + 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))); + dtlsAssociationP->setCipher(settings.value("cipher", "cipher suit doesn't found").toString()); + + return dtlsAssociationP; +} + + + + diff --git a/src/dtlsthread.h b/src/dtlsthread.h new file mode 100644 index 00000000..da01c7ef --- /dev/null +++ b/src/dtlsthread.h @@ -0,0 +1,75 @@ +#ifndef BASETHREAD_H +#define BASETHREAD_H + +#include +#include "packet.h" +#include "QSettings" +#include "association.h" +//#include "QTimer" + +class Dtlsthread : public QThread +{ + Q_OBJECT + +public: + Dtlsthread(Packet sendPacket, QObject *parent); + DtlsAssociation* initDtlsAssociation(); + virtual ~Dtlsthread(); + void persistentConnectionLoop(); + void run() override; // Pure virtual function making this class abstract + std::vector getCmdInput(Packet sendpacket, QSettings& settings); + void writeMassage(Packet packetToSend, DtlsAssociation* dtlsAssociation); + + QTimer* timer; + std::vector dtlsAssociations; + DtlsAssociation* dtlsAssociation; + QString recievedMassage; + Packet sendpacket; + + + bool closeRequest; + bool handShakeDone; + bool insidePersistent; + +public slots: + void onTimeout(); + void sendPersistant(Packet sendpacket); + void handShakeComplited(); + void receivedDatagram(QByteArray plainText); + +signals: + void toStatusBar(const QString & message, int timeout = 0, bool override = false); + void connectStatus(QString); + void packetSent(Packet); + void packetReceived(Packet); + + +}; + +#endif // BASETHREAD_H + + + + +//#ifndef DTLSTHREAD_H +//#define DTLSTHREAD_H +//#include "packet.h" +//#include + +//class Dtlsthread : public QThread +//{ +// Q_OBJECT + +//public: +// Packet sendPacket; + + +// Dtlsthread(Packet sendPacket, QObject *parent); +// void run() override; // Entry point for the thread +//// void setParameters(int param); // Setter for parameters + +////private: +//// int m_param; // Parameter to be used in the thread +//}; +//#endif + diff --git a/src/globals.h b/src/globals.h index 30a520b5..62e9e780 100755 --- a/src/globals.h +++ b/src/globals.h @@ -49,7 +49,8 @@ #define PANELSFILE ((QFile::exists("ps_panels.json") || QFile::exists("portablemode.txt") ) ? ("ps_panels.json") : ((SETTINGSPATH) + "ps_panels.json")) #define NAMEINIKEY "NAMES" - +#define DTLSSENDICON ":icons/tx_dtls.png" +#define DTLSRXICON ":icons/rx_dtls.png" #define UDPSENDICON ":icons/tx_udp.png" #define TCPSENDICON ":icons/tx_tcp.png" #define UDPRXICON ":icons/rx_udp.png" diff --git a/src/icons/rx_dtls.png b/src/icons/rx_dtls.png new file mode 100644 index 00000000..dd279d6b Binary files /dev/null and b/src/icons/rx_dtls.png differ diff --git a/src/icons/tx_dtls.png b/src/icons/tx_dtls.png new file mode 100644 index 00000000..d9843f34 Binary files /dev/null and b/src/icons/tx_dtls.png differ diff --git a/src/main.cpp b/src/main.cpp index 8669bd03..1717a2c4 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,6 +95,8 @@ void myMessageOutputDisable(QtMsgType type, const QMessageLogContext &context, c int main(int argc, char *argv[]) { + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + settings.setValue("leaveSessionOpen", "false"); int debugMode = DEBUGMODE; if (QFile::exists("DEBUGMODE")) { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index da82e430..62b952fd 100755 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,8 @@ #include +#include + #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) @@ -57,6 +60,7 @@ #include "postdatagen.h" #include "panelgenerator.h" +int MainWindow::isSessionOpen = false; int hexToInt(QChar hex); void parserMajorMinorBuild(QString sw, unsigned int &major, unsigned int &minor, unsigned int &build); extern void themeTheButton(QPushButton * button); @@ -67,10 +71,57 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { + ui->setupUi(this); + QCheckBox* leaveSessionOpen; + QCheckBox* twoVerify; + //QLineEdit* hostName = ui->hostName; + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + //leaveSessionOpen + if(settings.value("leaveSessionOpen").toString() == "false"){ + ui->leaveSessionOpen->setChecked(false); + } else { + ui->leaveSessionOpen->setChecked(true); + } + + leaveSessionOpen = ui->leaveSessionOpen; + connect(leaveSessionOpen, &QCheckBox::toggled, this, &MainWindow::on_leaveSessionOpen_StateChanged); + + //twoVerify + if(settings.value("twoVerify").toString() == "false"){ + ui->twoVerify->setChecked(false); + } else { + ui->twoVerify->setChecked(true); + } + + twoVerify = ui->twoVerify; + connect(twoVerify, &QCheckBox::toggled, &packetNetwork , &PacketNetwork::on_twoVerify_StateChanged); + + //hostName + connect(ui->hostName, QLineEdit::editingFinished, this, MainWindow::on_hostName_editingFinished); + + + //cipher comboBox + cipherCb = ui->cipherCb; + //add the combobox the correct cipher suites + QList ciphers = QSslConfiguration::supportedCiphers(); + for (const QSslCipher &cipher : ciphers) { + cipherCb->addItem(cipher.name()); + } + + if ( ui->udptcpComboBox->currentText().toLower() != "dtls"){ + ui->leaveSessionOpen->hide(); + ui->twoVerify->hide(); + cipherCb->hide(); + ui->CipherLable->hide(); + ui->hostName->hide(); + + } + + connect(cipherCb, &QComboBox::editTextChanged, this, &MainWindow::on_cipherCb_currentIndexChanged); QIcon mIcon(":pslogo.png"); @@ -158,6 +209,9 @@ MainWindow::MainWindow(QWidget *parent) : connect(&packetNetwork, SIGNAL(packetSent(Packet)), this, SLOT(toTrafficLog(Packet))); + connect(&packetNetwork, SIGNAL(packetReceived(Packet)), this, SLOT(toTrafficLog(Packet))); + + if( !QFile::exists(PACKETSFILE)) { // Packets file does not exist. Load starter set. QFile starterfile(":/starter_set.json"); @@ -243,6 +297,16 @@ MainWindow::MainWindow(QWidget *parent) : stopResendingButton->hide(); + dtlsServerStatus = new QPushButton("DTLS:" + packetNetwork.getDTLSPortString()); + themeTheButton(dtlsServerStatus); + dtlsServerStatus->setIcon(QIcon(DTLSRXICON)); + + connect(dtlsServerStatus, SIGNAL(clicked()), + this, SLOT(toggleDTLSServer())); + + + statusBar()->insertPermanentWidget(2, dtlsServerStatus); + udpServerStatus = new QPushButton("UDP:" + packetNetwork.getUDPPortString()); themeTheButton(udpServerStatus); udpServerStatus->setIcon(QIcon(UDPRXICON)); @@ -251,7 +315,7 @@ MainWindow::MainWindow(QWidget *parent) : this, SLOT(toggleUDPServer())); - statusBar()->insertPermanentWidget(2, udpServerStatus); + statusBar()->insertPermanentWidget(3, udpServerStatus); //updatewidget @@ -271,15 +335,17 @@ MainWindow::MainWindow(QWidget *parent) : this, SLOT(toggleSSLServer())); - statusBar()->insertPermanentWidget(3, tcpServerStatus); + statusBar()->insertPermanentWidget(4, tcpServerStatus); + + + statusBar()->insertPermanentWidget(5, sslServerStatus); - statusBar()->insertPermanentWidget(4, sslServerStatus); //ipmode toggle IPmodeButton = new QPushButton("IPv4 Mode"); themeTheButton(IPmodeButton); - statusBar()->insertPermanentWidget(5, IPmodeButton); + statusBar()->insertPermanentWidget(6, IPmodeButton); setIPMode(); @@ -288,7 +354,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(IPmodeButton, SIGNAL(clicked()), this, SLOT(toggleIPv4_IPv6())); - + DTLSServerStatus(); UDPServerStatus(); TCPServerStatus(); SSLServerStatus(); @@ -478,6 +544,13 @@ MainWindow::MainWindow(QWidget *parent) : +void MainWindow::toggleDTLSServer() +{ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + settings.setValue("dtlsServerEnable", !settings.value("dtlsServerEnable", true).toBool()); + applyNetworkSettings(); +} + void MainWindow::toggleUDPServer() { QSettings settings(SETTINGSFILE, QSettings::IniFormat); @@ -747,6 +820,28 @@ void MainWindow::toTrafficLog(Packet logPacket) } +void MainWindow::DTLSServerStatus() +{ + + if (packetNetwork.DTLSListening()) { + QString ports = packetNetwork.getDTLSPortString(); + int portcount = packetNetwork.getDTLSPortsBound().size(); + dtlsServerStatus->setToolTip(ports); + if(portcount > 3) { + dtlsServerStatus->setText("DTLS: " + QString::number(portcount) + tr(" Ports")); + } else { + dtlsServerStatus->setText("DTLS:" + ports); + } + + } else { + dtlsServerStatus->setText(tr("DTLS Server Disabled")); + + } + + //updatewidget + + +} void MainWindow::UDPServerStatus() { @@ -1926,6 +2021,7 @@ void MainWindow::applyNetworkSettings() ui->persistentTCPCheck->setChecked(settings.value("persistentTCPCheck", false).toBool()); on_persistentTCPCheck_clicked(ui->persistentTCPCheck->isChecked()); + DTLSServerStatus(); UDPServerStatus(); TCPServerStatus(); SSLServerStatus(); @@ -2235,9 +2331,37 @@ void MainWindow::on_actionHelp_triggered() QDesktopServices::openUrl(QUrl("https://packetsender.com/documentation")); } + + +void MainWindow::on_leaveSessionOpen_StateChanged(){ + //ui.checkBox->setChecked(checkBoxState); + + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QString leaveSessionOpen = settings.value("leaveSessionOpen", "false").toString(); + if(leaveSessionOpen == "false"){ + settings.setValue("leaveSessionOpen", "true"); + } + else{ + settings.setValue("leaveSessionOpen", "false"); + } +} + +void MainWindow::on_sendSimpleAck_StateChanged(){ + //ui.checkBox->setChecked(checkBoxState); + + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QString sendSimpleAck = settings.value("sendSimpleAck", "false").toString(); + if(sendSimpleAck == "false"){ + settings.setValue("sendSimpleAck", "true"); + } + else{ + settings.setValue("sendSimpleAck", "false"); + } +} + void MainWindow::on_actionSettings_triggered() { - Settings settings; + Settings settings(this); int accepted = settings.exec(); if (accepted) { setIPMode(); @@ -2574,6 +2698,7 @@ void MainWindow::on_loadFileButton_clicked() } + void MainWindow::on_actionDonate_Thank_You_triggered() { @@ -2588,6 +2713,28 @@ void MainWindow::on_udptcpComboBox_currentIndexChanged(const QString &arg1) auto isHttp = selectedText.contains("http"); auto isPost = selectedText.contains("post") && isHttp; + /////////////////////////////////dtls add line edit for adding path for cert + + if ( ui->udptcpComboBox->currentText().toLower() == "dtls") { + ui->leaveSessionOpen->show(); + cipherCb->show(); + ui->CipherLable->show(); + ui->twoVerify->show(); + ui->hostName->show(); + + + } else { + ui->leaveSessionOpen->hide(); + cipherCb->hide(); + ui->CipherLable->hide(); + ui->twoVerify->hide(); + ui->hostName->hide(); + + + + } + + if(isHttp) { ui->asciiLabel->setText("Data"); } else { @@ -2619,6 +2766,15 @@ void MainWindow::on_udptcpComboBox_currentIndexChanged(const QString &arg1) ui->genPostDataButton->setVisible(isPost); } +void MainWindow::on_cipherCb_currentIndexChanged(){ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + settings.setValue("cipher", cipherCb->currentText()); + //create new session even if the leave open session checkbox is pushed create new session, because the cipher has been changed + isSessionOpen = false; + +} + + void MainWindow::on_genPostDataButton_clicked() { PostDataGen * phttp = new PostDataGen(this, ui->packetASCIIEdit->text()); @@ -2784,3 +2940,9 @@ void MainWindow::on_udptcpComboBox_currentIndexChanged(int index) on_udptcpComboBox_currentIndexChanged(""); } +void MainWindow::on_hostName_editingFinished(){ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + settings.setValue("hostNameEdit", ui->hostName->text()); + +} + diff --git a/src/mainwindow.h b/src/mainwindow.h index 4da01674..9a08ce74 100755 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -10,6 +10,7 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include #include #include #include @@ -40,6 +41,8 @@ class PreviewFilter : public QObject Q_OBJECT public: + + explicit PreviewFilter(QObject * parent, QLineEdit * asciiEdit, QLineEdit * hexEdit) : QObject{parent}, asciiEdit{asciiEdit}, hexEdit{hexEdit} { @@ -72,33 +75,37 @@ class MainWindow : public QMainWindow explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); + PacketNetwork packetNetwork; QString ASCIITohex(QString &ascii); QString hexToASCII(QString &hex); - - void loadPacketsTable(); - - + void loadPacketsTable(); QPushButton *generatePSLink(); QPushButton *generateDNLink(); void populateTableRow(int rowCounter, Packet tempPacket); void removePacketfromMemory(Packet thepacket); + void DTLSServerStatus(); void UDPServerStatus(); void TCPServerStatus(); int findColumnIndex(QListWidget *lw, QString search); void packetTable_checkMultiSelected(); void generateConnectionMenu(); - void updateManager(QByteArray response); + QComboBox* cipherCb; + static int isSessionOpen; + signals: void sendPacket(Packet sendpacket); public slots: + void on_hostName_editingFinished(); + //void on_twoVerify_StateChanged(); + void on_sendSimpleAck_StateChanged(); + void on_leaveSessionOpen_StateChanged(); void toTrafficLog(Packet logPacket); void cancelResends(); void applyNetworkSettings(); - - + void toggleDTLSServer(); void toggleUDPServer(); void toggleTCPServer(); void toggleSSLServer(); @@ -210,11 +217,14 @@ class MainWindow : public QMainWindow void on_loadFileButton_clicked(); + void on_actionDonate_Thank_You_triggered(); void on_udptcpComboBox_currentIndexChanged(const QString &arg1); + void on_cipherCb_currentIndexChanged(); + void on_requestPathEdit_editingFinished(); void on_genPostDataButton_clicked(); @@ -236,11 +246,11 @@ class MainWindow : public QMainWindow QList packetsSaved; QList packetsRepeat; int stopResending; - PacketNetwork packetNetwork; QNetworkAccessManager * http; QTimer refreshTimer; QTimer slowRefreshTimer; bool tableActive; + QPushButton * dtlsServerStatus; QPushButton * udpServerStatus; QPushButton * tcpServerStatus; QPushButton * sslServerStatus; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 48ed25e2..46fc58e9 100755 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -236,34 +236,43 @@ - UDP + HTTPS Post - :/icons/tx_udp.png:/icons/tx_udp.png + :/icons/tx_http.png:/icons/tx_http.png - SSL + DTLS - :/icons/tx_ssl.png:/icons/tx_ssl.png + :/icons/tx_dtls.png:/icons/tx_dtls.png - HTTP Get + UDP - :/icons/tx_http.png:/icons/tx_http.png + :/icons/tx_udp.png:/icons/tx_udp.png - HTTP Post + SSL + + + + :/icons/tx_ssl.png:/icons/tx_ssl.png + + + + + HTTP Get @@ -272,7 +281,7 @@ - HTTPS Get + HTTP Post @@ -281,7 +290,7 @@ - HTTPS Post + HTTPS Get @@ -308,6 +317,209 @@ + + + + true + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + 0 + 0 + 851 + 31 + + + + + QLayout::SetMinAndMaxSize + + + 0 + + + + + Cipher Suites: + + + + + + + + AES256-GCM-SHA384 + + + + + AES128-GCM-SHA256 + + + + + AES256-GCM-SHA384 + + + + + AES128-GCM-SHA256 + + + + + AES128-SHA256 + + + + + AES256-SHA384 + + + + + AES128-SHA + + + + + AES256-SHA + + + + + CHACHA20-POLY1305-SHA256 + + + + + RC4-MD5 + + + + + RC4-SHA + + + + + CAMELLIA128-SHA256 + + + + + CAMELLIA256-SHA + + + + + ECDHE-RSA-AES128-GCM-SHA256 + + + + + ECDHE-RSA-AES256-GCM-SHA384 + + + + + ECDHE-ECDSA-AES128-GCM-SHA256 + + + + + ECDHE-ECDSA-AES256-GCM-SHA384 + + + + + DHE-RSA-AES128-GCM-SHA256 + + + + + DHE-RSA-AES256-GCM-SHA384 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Host Name (CN) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Persistent DTLS + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add Server Verification of The Client + + + + + + + @@ -353,7 +565,6 @@ - 75 true diff --git a/src/packet.cpp b/src/packet.cpp index c46fbf8e..ffde06e0 100755 --- a/src/packet.cpp +++ b/src/packet.cpp @@ -60,6 +60,12 @@ void Packet::clear() init(); } +bool Packet::isDTLS() +{ + return ((tcpOrUdp.trimmed().toLower() == "dtls")); +} + + bool Packet::isSSL() { return (tcpOrUdp.trimmed().toLower().contains("ssl")); @@ -295,6 +301,17 @@ QIcon Packet::getIcon() } + if (isDTLS()) { + if (fromIP.toUpper().contains("YOU")) { + QIcon myIcon(DTLSSENDICON); + return myIcon; + } else { + QIcon myIcon(DTLSRXICON); + return myIcon; + } + + } + if (isTCP()) { diff --git a/src/packet.h b/src/packet.h index 5e3a6ce5..0089a9a4 100755 --- a/src/packet.h +++ b/src/packet.h @@ -62,6 +62,7 @@ class Packet bool incoming; void init(); void clear(); + bool isDTLS(); bool isTCP(); bool isSSL(); bool isUDP(); diff --git a/src/packetnetwork.cpp b/src/packetnetwork.cpp index 4c5272bf..a99f726d 100755 --- a/src/packetnetwork.cpp +++ b/src/packetnetwork.cpp @@ -11,6 +11,7 @@ #include "packetnetwork.h" #include "globals.h" #include "settings.h" +#include #include #include #include @@ -21,6 +22,16 @@ #include #include #include +#include +#include +#include "association.h" +#include +#include "dtlsthread.h" +#include "dtlsserver.h" + + + + #ifdef CONSOLE_BUILD class QMessageBox { public: @@ -145,6 +156,19 @@ QString PacketNetwork::getIPmode() return ipMode; } +bool PacketNetwork::DTLSListening() +{ + QUdpSocket * dtls; + QDEBUGVAR(dtlsServers.size()); + foreach(dtls, dtlsServers) { + QDEBUGVAR(dtls->state()); + if(dtls->state() == QAbstractSocket::BoundState) { + return true; + } + } + return false; +} + bool PacketNetwork::UDPListening() { QUdpSocket * udp; @@ -152,7 +176,6 @@ bool PacketNetwork::UDPListening() foreach(udp, udpServers) { QDEBUGVAR(udp->state()); if(udp->state() == QAbstractSocket::BoundState) { - //if(udp->state() == QAbstractSocket::ConnectedState) { return true; } } @@ -219,7 +242,7 @@ void PacketNetwork::init() static bool erroronce = false; - + dtlsServers.clear(); tcpServers.clear(); udpServers.clear(); sslServers.clear(); @@ -231,11 +254,13 @@ void PacketNetwork::init() QSettings settings(SETTINGSFILE, QSettings::IniFormat); - QList udpPortList, tcpPortList, sslPortList; + QList udpPortList, tcpPortList, sslPortList, dtlsPortList; + int dtlsPort = 0; int udpPort = 0; int tcpPort = 0; int sslPort = 0; + dtlsPortList = Settings::portsToIntList(settings.value("dtlsPort", "0").toString()); udpPortList = Settings::portsToIntList(settings.value("udpPort", "0").toString()); tcpPortList = Settings::portsToIntList(settings.value("tcpPort", "0").toString()); sslPortList = Settings::portsToIntList(settings.value("sslPort", "0").toString()); @@ -256,9 +281,49 @@ void PacketNetwork::init() #endif - QUdpSocket *udpSocket; + QUdpSocket *udpSocket, *dtlsSocket; ThreadedTCPServer *ssl, *tcp; + + + + foreach (dtlsPort, dtlsPortList) { + bool bindResult = dtlsServer.listen(IPV4_OR_IPV6, dtlsPort); + + + dtlsSocket = &(dtlsServer.serverSocket); + + dtlsSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 128); + + if ((!bindResult) && (!erroronce)) { + QDEBUGVAR(dtlsPort); + erroronce = true; + if ((dtlsPort < 1024) && (dtlsPort > 0)) { + QString msgText = lowPortText; + msgText.replace("[PORT]", QString::number(dtlsPort)); + msgBoxBindError.setText(msgText); + msgBoxBindError.exec(); + + } else { + QString msgText = portConsumedText; + msgText.replace("[PORT]", QString::number(dtlsPort)); + msgBoxBindError.setText(msgText); + msgBoxBindError.exec(); + + } + dtlsSocket->close(); + dtlsSocket->deleteLater(); + + } + + if(bindResult) { + dtlsServers.append(dtlsSocket); + } + + } + reJoinMulticast(); + + foreach (udpPort, udpPortList) { @@ -273,7 +338,7 @@ void PacketNetwork::init() if ((!bindResult) && (!erroronce)) { QDEBUGVAR(udpPort); erroronce = true; - if (udpPort < 1024 && udpPort > 0) { + if ((udpPort < 1024) && (udpPort > 0)) { QString msgText = lowPortText; msgText.replace("[PORT]", QString::number(udpPort)); msgBoxBindError.setText(msgText); @@ -348,6 +413,7 @@ void PacketNetwork::init() sendResponse = settings.value("sendReponse", false).toBool(); responseData = (settings.value("responseHex", "")).toString(); + activateDTLS = settings.value("dtlsServerEnable", true).toBool(); activateUDP = settings.value("udpServerEnable", true).toBool(); activateTCP = settings.value("tcpServerEnable", true).toBool(); activateSSL = settings.value("sslServerEnable", true).toBool(); @@ -373,12 +439,31 @@ void PacketNetwork::init() delayAfterConnect = 500; } + if (activateDTLS) { + foreach (dtlsSocket, dtlsServers) { + connect(&dtlsServer, SIGNAL(serverPacketReceived(Packet)), this, SLOT(packetReceivedECHO(Packet)),Qt::UniqueConnection); + connect(&dtlsServer, SIGNAL(serverPacketSent(Packet)), this, SLOT(packetSentECHO(Packet)),Qt::UniqueConnection); + } + + } else { + QDEBUG() << "udp server disable"; + foreach (dtlsSocket, dtlsServers) { + dtlsSocket->close(); + } + dtlsServers.clear(); + + } + + + if (activateUDP) { + foreach (udpSocket, udpServers) { QDEBUG() << "signal/slot datagram connect: " << connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); } + } else { QDEBUG() << "udp server disable"; foreach (udpSocket, udpServers) { @@ -415,6 +500,27 @@ void PacketNetwork::init() //TODO add timed event feature? +QList PacketNetwork::getDTLSPortsBound() +{ + QList pList; + pList.clear(); + QUdpSocket * dtlsServer; + foreach (dtlsServer, dtlsServers) { + if(dtlsServer->BoundState == QAbstractSocket::BoundState) { + if(dtlsServer){ + pList.append(dtlsServer->localPort()); + } + } + } + return pList; + +} + +QString PacketNetwork::getDTLSPortString() +{ + + return Settings::intListToPorts(getDTLSPortsBound()); +} QList PacketNetwork::getUDPPortsBound() { @@ -602,7 +708,6 @@ void PacketNetwork::readPendingDatagrams() senderPort = theDatagram.senderPort(); QDEBUG() << "data size is" << datagram.size(); - // QDEBUG() << debugQByteArray(datagram); Packet udpPacket; udpPacket.timestamp = QDateTime::currentDateTime(); @@ -677,6 +782,7 @@ void PacketNetwork::readPendingDatagrams() } + QString PacketNetwork::debugQByteArray(QByteArray debugArray) { QString outString = ""; @@ -822,6 +928,44 @@ void PacketNetwork::packetToSend(Packet sendpacket) sendpacket.timestamp = QDateTime::currentDateTime(); sendpacket.name = sendpacket.timestamp.toString(DATETIMEFORMAT); + + if(sendpacket.isDTLS()){ + Dtlsthread * thread = new Dtlsthread(sendpacket, this); + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QDEBUG() << connect(thread, SIGNAL(packetReceived(Packet)), this, SLOT(packetReceivedECHO(Packet))) + << connect(thread, SIGNAL(toStatusBar(QString, int, bool)), this, SLOT(toStatusBarECHO(QString, int, bool))) + << connect(thread, SIGNAL(packetSent(Packet)), this, SLOT(packetSentECHO(Packet))) + << connect(thread, SIGNAL(destroyed()), this, SLOT(disconnected())); + + if(settings.value("leaveSessionOpen").toString() == "true"){ + PersistentConnection * pcWindow = new PersistentConnection(); + + pcWindow->sendPacket = sendpacket; + pcWindow->init(); + pcWindow->dthread = thread; + + QDEBUG() << ": thread Connection attempt " + << connect(pcWindow, SIGNAL(persistentPacketSend(Packet)), thread, SLOT(sendPersistant(Packet))) + << connect(pcWindow, SIGNAL(closeConnection()), thread, SLOT(closeConnection())) + << connect(thread, SIGNAL(connectStatus(QString)), pcWindow, SLOT(statusReceiver(QString))) + << connect(thread, SIGNAL(packetSent(Packet)), pcWindow, SLOT(packetSentSlot(Packet))); + + pcWindow->show(); + thread->start(); + + } + else{ + thread->start(); + QTimer* timer = new QTimer(this); + thread->timer = timer; + connect(timer, SIGNAL(timeout()), thread, SLOT(onTimeout())); + timer->start(2000); + } + + dtlsthreadList.append(thread); + } + + if (sendpacket.isUDP()) { QUdpSocket * sendUDP; bool oneoff = false; @@ -940,10 +1084,9 @@ void PacketNetwork::packetToSend(Packet sendpacket) } - - } + void PacketNetwork::httpError(QNetworkRequest* pReply) { QDEBUGVAR(pReply); @@ -1062,3 +1205,58 @@ QList PacketNetwork::allTCPServers() return theServers; } +std::vector PacketNetwork::getCmdInput(Packet sendpacket, QSettings& settings){ + //the array of cmdComponents: dataStr, toIp, toPort, sslPrivateKeyPath, sslLocalCertificatePath, sslCaFullPath + std::vector cmdComponents; + + //get the data of the packet + cmdComponents.push_back(QString::fromUtf8(sendpacket.getByteArray())); + cmdComponents.push_back(sendpacket.toIP); + cmdComponents.push_back(QString::number(sendpacket.port)); + + //get the pathes for verification from the settings + cmdComponents.push_back(settings.value("sslPrivateKeyPath", "default").toString()); + cmdComponents.push_back(settings.value("sslLocalCertificatePath", "default").toString()); + QString sslCaPath = settings.value("sslCaPath", "default").toString(); + + //get the full path to to ca-signed-cert.pem file + QDir dir(sslCaPath); + if (dir.exists()) { + QStringList nameFilters; + nameFilters << "*.pem"; // Filter for .txt files + + dir.setNameFilters(nameFilters); + QStringList fileList = dir.entryList(); + + if (!fileList.isEmpty()) { + // Select the first file that matches the filter + cmdComponents.push_back(dir.filePath(fileList.first())); + } else { + qDebug() << "No matching files found."; + } + } else { + qDebug() << "Directory does not exist."; + } + cmdComponents.push_back(settings.value("cipher", "AES256-GCM-SHA384").toString()); + return cmdComponents; +} + + + + +void PacketNetwork::on_twoVerify_StateChanged(){ + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + QString twoVerify = settings.value("twoVerify", "false").toString(); + if(twoVerify == "false"){ + settings.setValue("twoVerify", "true"); + dtlsServer.serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer); + } + else{ + settings.setValue("twoVerify", "false"); + dtlsServer.serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); + + } +} + + + diff --git a/src/packetnetwork.h b/src/packetnetwork.h index 2a30d066..b79dc7e2 100755 --- a/src/packetnetwork.h +++ b/src/packetnetwork.h @@ -30,20 +30,35 @@ #include "persistentconnection.h" #endif #include +#include +#include +#include "dtlsthread.h" +#include "dtlsserver.h" + + + class PacketNetwork : public QObject { Q_OBJECT public: + QList dtlsServers; + DtlsServer dtlsServer; + QString keyPath; + QString certPath; explicit PacketNetwork(QObject *parent = nullptr); void init(); + std::vector getCmdInput(Packet sendpacket, QSettings &settings); + QString debugQByteArray(QByteArray debugArray); + QString getDTLSPortString(); QString getUDPPortString(); QString getTCPPortString(); QString getSSLPortString(); + QList getDTLSPortsBound(); QList getUDPPortsBound(); QList getTCPPortsBound(); QList getSSLPortsBound(); @@ -56,6 +71,7 @@ class PacketNetwork : public QObject QString responseData; bool sendResponse; bool sendSmartResponse; + bool activateDTLS; bool activateUDP; bool activateTCP; bool activateSSL; @@ -67,6 +83,7 @@ class PacketNetwork : public QObject void setIPmode(int mode); static QString getIPmode(); + bool DTLSListening(); bool UDPListening(); bool TCPListening(); bool SSLListening(); @@ -100,12 +117,15 @@ public slots: void readPendingDatagrams(); void disconnected(); void packetToSend(Packet sendpacket); + void on_twoVerify_StateChanged(); + private slots: void httpFinished(QNetworkReply* pReply); void httpError(QNetworkRequest* pReply); void sslErrorsSlot(QNetworkReply *reply, const QList &errors); + private: //mapping of joined multicast groups //format is 239.255.120.19:5009, 239.255.120.23:5009 @@ -114,6 +134,7 @@ private slots: QList allTCPServers(); QList httpList; + QList dtlsthreadList; QList tcpthreadList; #ifdef CONSOLE_BUILD @@ -126,6 +147,7 @@ private slots: QList sslServers; QList udpServers; + }; #endif // PACKETNETWORK_H diff --git a/src/packetsender.qrc b/src/packetsender.qrc index ff269300..4e776e5c 100755 --- a/src/packetsender.qrc +++ b/src/packetsender.qrc @@ -52,5 +52,7 @@ packetsender.css iris_and_marigold.jpg ps_panels.json + icons/tx_dtls.png + icons/rx_dtls.png diff --git a/src/persistentconnection.cpp b/src/persistentconnection.cpp index e5f407a3..db8270f3 100755 --- a/src/persistentconnection.cpp +++ b/src/persistentconnection.cpp @@ -32,8 +32,8 @@ PersistentConnection::PersistentConnection(QWidget *parent) : QDEBUG(); sendPacket.clear(); - QDEBUG() << ": refreshTimer Connection attempt " << - connect(&refreshTimer, SIGNAL(timeout()), this, SLOT(refreshTimerTimeout())) + QDEBUG() /*<< ": refreshTimer Connection attempt " << + connect(&refreshTimer, SIGNAL(timeout()), this, SLOT(refreshTimerTimeout()))*/ << connect(this, SIGNAL(rejected()), this, SLOT(aboutToClose())) << connect(this, SIGNAL(accepted()), this, SLOT(aboutToClose())) << connect(this, SIGNAL(dialogIsClosing()), this, SLOT(aboutToClose())); @@ -172,6 +172,9 @@ void PersistentConnection::init() if (sendPacket.isSSL()) { tcpOrSSL = "SSL"; } + if(sendPacket.isDTLS()){ + tcpOrSSL = "DTLS"; + } setWindowTitle(tcpOrSSL + "://" + sendPacket.toIP + ":" + QString::number(sendPacket.port)); @@ -222,8 +225,14 @@ void PersistentConnection::refreshTimerTimeout() if (thread->isRunning() && !thread->closeRequest) { QString winTitle = windowTitle(); if (winTitle.startsWith("TCP://") && thread->isEncrypted()) { - winTitle.replace("TCP://", "SSL://"); - setWindowTitle(winTitle); + if(sendPacket.isDTLS()){ + winTitle.replace("TCP://", "DTLS://"); + setWindowTitle(winTitle); + }else{ + winTitle.replace("TCP://", "SSL://"); + setWindowTitle(winTitle); + } + } } @@ -258,7 +267,6 @@ void PersistentConnection::refreshTimerTimeout() - // QDEBUG() <<"Diff:" << diff; @@ -343,6 +351,8 @@ void PersistentConnection::socketDisconnected() statusReceiver("not connected"); } +//connect(pcWindow, SIGNAL(persistentPacketSend(Packet)), thread, SLOT(sendPersistant(Packet))) + void PersistentConnection::on_asciiSendButton_clicked() { QString ascii = ui->asciiLineEdit->text(); diff --git a/src/persistentconnection.h b/src/persistentconnection.h index e6ace23e..45fa4031 100755 --- a/src/persistentconnection.h +++ b/src/persistentconnection.h @@ -7,6 +7,7 @@ #include "packet.h" #include "tcpthread.h" +#include "dtlsthread.h" namespace Ui { @@ -26,6 +27,7 @@ class PersistentConnection : public QDialog Packet sendPacket; Packet reSendPacket; TCPThread *thread; + Dtlsthread *dthread; static const QString RESEND_BUTTON_STYLE; diff --git a/src/settings.cpp b/src/settings.cpp index 4f26f573..06c81492 100755 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #ifndef CONSOLE_BUILD @@ -84,20 +85,39 @@ const QString Settings::HTTPHEADERINDEX = "HTTPHeader:"; #ifndef CONSOLE_BUILD -Settings::Settings(QWidget *parent) : +Settings::Settings(QWidget *parent, MainWindow* mw) : QDialog(parent), + rmw(mw), ui(new Ui::Settings) { ui->setupUi(this); setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); + QSettings settings(SETTINGSFILE, QSettings::IniFormat); + //not working yet... ui->multiSendDelayLabel->hide(); ui->multiSendDelayEdit->hide(); + initialSslLocalCertificatePath = settings.value("sslLocalCertificatePath", "").toString(); + initialSslCaPath = settings.value("sslCaPath", "").toString(); + initialSslPrivateKeyPath = settings.value("sslPrivateKeyPath", "").toString(); + + MainWindow *mainWindow = dynamic_cast(parent); + DtlsServer& dtlsServer = mainWindow->packetNetwork.dtlsServer; + + connect(this, &Settings::loadingCertsAgain, &dtlsServer, &DtlsServer::on_signedCert_textChanged); + + if(settings.value("sendSimpleAck").toString() == "false"){ + ui->sendSimpleAck->setChecked(false); + } else { + ui->sendSimpleAck->setChecked(true); + } + + sendSimpleAck = ui->sendSimpleAck; + connect(sendSimpleAck, &QCheckBox::toggled, dynamic_cast(parent), &MainWindow::on_sendSimpleAck_StateChanged); - QSettings settings(SETTINGSFILE, QSettings::IniFormat); QIcon mIcon(":pslogo.png"); setWindowTitle("Packet Sender "+tr("Settings")); @@ -107,7 +127,6 @@ Settings::Settings(QWidget *parent) : ui->displayOrderListTraffic->hide(); ui->displayGroupBoxTraffic->setTitle(""); - loadCredentialTable(); on_genAuthCheck_clicked(false); @@ -175,6 +194,7 @@ Settings::Settings(QWidget *parent) : ui->timeFormatExample->setText(now.toString(timeFormat)); + connect(ui->dateFormat, &QLineEdit::textChanged, this, [=](QString val) { // use action as you wish QDateTime now = QDateTime::currentDateTime(); @@ -197,6 +217,7 @@ Settings::Settings(QWidget *parent) : ui->resolveDNSOnInputCheck->setChecked(settings.value("resolveDNSOnInputCheck", false).toBool()); + QList dtlsList = portsToIntList(settings.value("dtlsPort", "0").toString()); QList udpList = portsToIntList(settings.value("udpPort", "0").toString()); QList tcpList = portsToIntList(settings.value("tcpPort", "0").toString()); QList sslList = portsToIntList(settings.value("sslPort", "0").toString()); @@ -204,11 +225,15 @@ Settings::Settings(QWidget *parent) : ui->udpServerPortEdit->setText(intListToPorts(udpList)); ui->tcpServerPortEdit->setText(intListToPorts(tcpList)); ui->sslServerPortEdit->setText(intListToPorts(sslList)); + ui->dtlsServerPortEdit->setText(intListToPorts(dtlsList)); + ui->udpServerEnableCheck->setChecked(settings.value("udpServerEnable", true).toBool()); ui->tcpServerEnableCheck->setChecked(settings.value("tcpServerEnable", true).toBool()); ui->sslServerEnableCheck->setChecked(settings.value("sslServerEnable", true).toBool()); + ui->dtlsServerEnableCheck->setChecked(settings.value("dtlsServerEnable", true).toBool()); + ui->serverSnakeOilCheck->setChecked(settings.value("serverSnakeOilCheck", true).toBool()); @@ -340,6 +365,7 @@ void Settings::statusBarMessage(QString msg) } + void Settings::on_buttonBox_accepted() { QSettings settings(SETTINGSFILE, QSettings::IniFormat); @@ -347,6 +373,8 @@ void Settings::on_buttonBox_accepted() QList udpList = Settings::portsToIntList(ui->udpServerPortEdit->text()); QList tcpList = Settings::portsToIntList(ui->tcpServerPortEdit->text()); QList sslList = Settings::portsToIntList(ui->sslServerPortEdit->text()); + QList dtlsList = Settings::portsToIntList(ui->dtlsServerPortEdit->text()); + if(ui->ipSpecificRadio->isChecked()) { QHostAddress address(ui->bindIPAddress->text()); @@ -389,7 +417,7 @@ void Settings::on_buttonBox_accepted() } - + settings.setValue("dtlsPort", intListToPorts(dtlsList)); settings.setValue("udpPort", intListToPorts(udpList)); settings.setValue("tcpPort", intListToPorts(tcpList)); settings.setValue("sslPort", intListToPorts(sslList)); @@ -401,6 +429,8 @@ void Settings::on_buttonBox_accepted() settings.setValue("udpServerEnable", ui->udpServerEnableCheck->isChecked()); settings.setValue("tcpServerEnable", ui->tcpServerEnableCheck->isChecked()); settings.setValue("sslServerEnable", ui->sslServerEnableCheck->isChecked()); + settings.setValue("dtlsServerEnable", ui->dtlsServerEnableCheck->isChecked()); + settings.setValue("serverSnakeOilCheck", ui->serverSnakeOilCheck->isChecked()); @@ -510,6 +540,16 @@ void Settings::on_buttonBox_accepted() ENCODEMACROSAVE(4); ENCODEMACROSAVE(5); + if((initialSslLocalCertificatePath != settings.value("sslLocalCertificatePath", "").toString()) || + (initialSslCaPath != settings.value("sslCaPath", "").toString()) || + (initialSslPrivateKeyPath != settings.value("sslPrivateKeyPath", "").toString())){ + + initialSslLocalCertificatePath = settings.value("sslLocalCertificatePath", "").toString(); + initialSslCaPath = settings.value("sslCaPath", "").toString(); + initialSslPrivateKeyPath = settings.value("sslPrivateKeyPath", "").toString(); + emit loadingCertsAgain(); + } + } @@ -744,7 +784,7 @@ void Settings::on_sslLocalCertificatePathBrowseButton_clicked() } QString fileName = QFileDialog::getOpenFileName(this, - tr("Choose Cert"), home, tr("Certs (*.pem)")); + tr("Choose Cert"), home, tr("*.*")); if (QFile::exists(fileName)) { ui->sslLocalCertificatePath->setText(fileName); @@ -760,7 +800,7 @@ void Settings::on_sslPrivateKeyPathBrowseButton_clicked() } QString fileName = QFileDialog::getOpenFileName(this, - tr("Choose Key"), home, tr("Keys (*.key, *.pem)")); + tr("Choose Key"), home, tr("*.*")); if (QFile::exists(fileName)) { ui->sslPrivateKeyPath->setText(fileName); diff --git a/src/settings.h b/src/settings.h index 5907cf94..702a32a4 100644 --- a/src/settings.h +++ b/src/settings.h @@ -2,6 +2,7 @@ #define SETTINGS_H #include "globals.h" +#include "mainwindow.h" #ifndef CONSOLE_BUILD #include @@ -9,6 +10,7 @@ #endif #include #include +#include #ifdef CONSOLE_BUILD @@ -64,7 +66,14 @@ class Settings : public QDialog Q_OBJECT public: - explicit Settings(QWidget *parent = nullptr); + MainWindow* rmw; + QCheckBox* sendSimpleAck; + QLineEdit* sslLocalCertificatePath; + QString initialSslLocalCertificatePath; + QString initialSslCaPath; + QString initialSslPrivateKeyPath; + + explicit Settings(QWidget *parent = nullptr, MainWindow* mw = nullptr); ~Settings(); static QStringList defaultPacketTableHeader(); @@ -102,6 +111,8 @@ class Settings : public QDialog static QString logHeaderTranslate(QString txt); private slots: + + void on_buttonBox_accepted(); void on_asciiResponseEdit_textEdited(const QString &arg1); @@ -136,6 +147,7 @@ private slots: void on_chooseLanguageButton_clicked(); private: + QWidget *parentWidget; Ui::Settings *ui; QList packetsSaved; QStringList packetTableHeaders; @@ -151,7 +163,8 @@ private slots: void deleteHTTPHeader(QString host, QString header); void clearHTTPHeaders(QString host); static QPair header2keyvalue(QString header); - + signals: + void loadingCertsAgain(); }; #endif diff --git a/src/settings.ui b/src/settings.ui index 6a1fe613..32f431a2 100755 --- a/src/settings.ui +++ b/src/settings.ui @@ -7,7 +7,7 @@ 0 0 1013 - 583 + 601 @@ -17,7 +17,7 @@ - 3 + 0 @@ -105,6 +105,40 @@ + + + + Enable DTLS Servers + + + + + + + + + + 0 + 0 + + + + DTLS Server Port (comma-separated, 0 for random) + + + + + + + Qt::LeftToRight + + + 0 + + + + + @@ -126,6 +160,13 @@ + + + + Send simple Acknowledge (for DTLS server only) + + + @@ -175,19 +216,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -334,7 +362,7 @@ - SSL CA Certificates + SSL/DTLS CA Certificates @@ -359,7 +387,7 @@ - SSL Local Certificate + SSL/DTLS Local Certificate @@ -384,7 +412,7 @@ - SSL Private Key + SSL/DTLS Private Key diff --git a/src/tx_dtls.png b/src/tx_dtls.png new file mode 100644 index 00000000..e895137e Binary files /dev/null and b/src/tx_dtls.png differ