File indexing completed on 2024-05-12 04:58:51
0001 /** 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "lanlinkprovider.h" 0008 #include "core_debug.h" 0009 0010 #ifndef Q_OS_WIN 0011 #include <netdb.h> 0012 #include <netinet/in.h> 0013 #include <netinet/tcp.h> 0014 #include <sys/socket.h> 0015 #else 0016 #include <winsock2.h> 0017 // Winsock2 needs to be included before any other header 0018 #include <mstcpip.h> 0019 #endif 0020 0021 #if defined(Q_OS_WIN) || defined(Q_OS_FREEBSD) 0022 #include <QNetworkInterface> 0023 #endif 0024 0025 #include <QHostInfo> 0026 #include <QMetaEnum> 0027 #include <QNetworkProxy> 0028 #include <QSslCipher> 0029 #include <QSslConfiguration> 0030 #include <QSslKey> 0031 #include <QStringList> 0032 #include <QTcpServer> 0033 #include <QUdpSocket> 0034 0035 #include "daemon.h" 0036 #include "dbushelper.h" 0037 #include "kdeconnectconfig.h" 0038 #include "landevicelink.h" 0039 0040 static const int MAX_UNPAIRED_CONNECTIONS = 42; 0041 static const int MAX_REMEMBERED_IDENTITY_PACKETS = 42; 0042 0043 static const long MILLIS_DELAY_BETWEEN_CONNECTIONS_TO_SAME_DEVICE = 500; 0044 0045 LanLinkProvider::LanLinkProvider(bool testMode) 0046 : m_server(new Server(this)) 0047 , m_udpSocket(this) 0048 , m_tcpPort(0) 0049 , m_testMode(testMode) 0050 , m_combineNetworkChangeTimer(this) 0051 #ifdef KDECONNECT_MDNS 0052 , m_mdnsDiscovery(this) 0053 #endif 0054 { 0055 m_combineNetworkChangeTimer.setInterval(0); // increase this if waiting a single event-loop iteration is not enough 0056 m_combineNetworkChangeTimer.setSingleShot(true); 0057 connect(&m_combineNetworkChangeTimer, &QTimer::timeout, this, &LanLinkProvider::combinedOnNetworkChange); 0058 0059 connect(&m_udpSocket, &QIODevice::readyRead, this, &LanLinkProvider::udpBroadcastReceived); 0060 0061 m_server->setProxy(QNetworkProxy::NoProxy); 0062 connect(m_server, &QTcpServer::newConnection, this, &LanLinkProvider::newConnection); 0063 0064 m_udpSocket.setProxy(QNetworkProxy::NoProxy); 0065 0066 connect(&m_udpSocket, &QAbstractSocket::errorOccurred, [](QAbstractSocket::SocketError socketError) { 0067 qWarning() << "Error sending UDP packet:" << socketError; 0068 }); 0069 0070 #if QT_VERSION_MAJOR < 6 0071 QNetworkConfigurationManager *networkManager = new QNetworkConfigurationManager(this); 0072 connect(networkManager, &QNetworkConfigurationManager::configurationChanged, this, [this](QNetworkConfiguration config) { 0073 if (config.state() == QNetworkConfiguration::Active) { 0074 onNetworkChange(); 0075 } 0076 }); 0077 #else 0078 const auto checkNetworkChange = [this]() { 0079 if (QNetworkInformation::instance()->reachability() == QNetworkInformation::Reachability::Online) { 0080 onNetworkChange(); 0081 } 0082 }; 0083 // Detect when a network interface changes status, so we announce ourselves in the new network 0084 QNetworkInformation::instance()->loadBackendByFeatures(QNetworkInformation::Feature::Reachability); 0085 0086 // We want to know if our current network reachability has changed, or if we change from one network to another 0087 connect(QNetworkInformation::instance(), &QNetworkInformation::reachabilityChanged, this, checkNetworkChange); 0088 connect(QNetworkInformation::instance(), &QNetworkInformation::transportMediumChanged, this, checkNetworkChange); 0089 #endif 0090 } 0091 0092 LanLinkProvider::~LanLinkProvider() 0093 { 0094 } 0095 0096 void LanLinkProvider::onStart() 0097 { 0098 const QHostAddress bindAddress = m_testMode ? QHostAddress::LocalHost : QHostAddress::Any; 0099 0100 bool success = m_udpSocket.bind(bindAddress, UDP_PORT, QUdpSocket::ShareAddress); 0101 if (!success) { 0102 QAbstractSocket::SocketError sockErr = m_udpSocket.error(); 0103 // Refer to https://doc.qt.io/qt-5/qabstractsocket.html#SocketError-enum to decode socket error number 0104 QString errorMessage = QString::fromLatin1(QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey(sockErr)); 0105 qCritical(KDECONNECT_CORE) << "Failed to bind UDP socket on port" << UDP_PORT << "with error" << errorMessage; 0106 } 0107 Q_ASSERT(success); 0108 0109 m_tcpPort = MIN_TCP_PORT; 0110 while (!m_server->listen(bindAddress, m_tcpPort)) { 0111 m_tcpPort++; 0112 if (m_tcpPort > MAX_TCP_PORT) { // No ports available? 0113 qCritical(KDECONNECT_CORE) << "Error opening a port in range" << MIN_TCP_PORT << "-" << MAX_TCP_PORT; 0114 m_tcpPort = 0; 0115 return; 0116 } 0117 } 0118 0119 broadcastUdpIdentityPacket(); 0120 0121 #ifdef KDECONNECT_MDNS 0122 m_mdnsDiscovery.onStart(); 0123 #endif 0124 0125 qCDebug(KDECONNECT_CORE) << "LanLinkProvider started"; 0126 } 0127 0128 void LanLinkProvider::onStop() 0129 { 0130 #ifdef KDECONNECT_MDNS 0131 m_mdnsDiscovery.onStop(); 0132 #endif 0133 m_udpSocket.close(); 0134 m_server->close(); 0135 qCDebug(KDECONNECT_CORE) << "LanLinkProvider stopped"; 0136 } 0137 0138 void LanLinkProvider::onNetworkChange() 0139 { 0140 if (m_combineNetworkChangeTimer.isActive()) { 0141 qCDebug(KDECONNECT_CORE) << "Device discovery triggered too fast, ignoring"; 0142 return; 0143 } 0144 m_combineNetworkChangeTimer.start(); 0145 } 0146 0147 // I'm in a new network, let's be polite and introduce myself 0148 void LanLinkProvider::combinedOnNetworkChange() 0149 { 0150 if (!m_server->isListening()) { 0151 qWarning() << "TCP server not listening, not broadcasting"; 0152 return; 0153 } 0154 0155 Q_ASSERT(m_tcpPort != 0); 0156 0157 broadcastUdpIdentityPacket(); 0158 #ifdef KDECONNECT_MDNS 0159 m_mdnsDiscovery.onNetworkChange(); 0160 #endif 0161 } 0162 0163 void LanLinkProvider::broadcastUdpIdentityPacket() 0164 { 0165 if (qEnvironmentVariableIsSet("KDECONNECT_DISABLE_UDP_BROADCAST")) { 0166 qWarning() << "Not broadcasting UDP because KDECONNECT_DISABLE_UDP_BROADCAST is set"; 0167 return; 0168 } 0169 qCDebug(KDECONNECT_CORE) << "Broadcasting identity packet"; 0170 0171 QList<QHostAddress> addresses = getBroadcastAddresses(); 0172 0173 #if defined(Q_OS_WIN) || defined(Q_OS_FREEBSD) 0174 // On Windows and FreeBSD we need to broadcast from every local IP address to reach all networks 0175 QUdpSocket sendSocket; 0176 sendSocket.setProxy(QNetworkProxy::NoProxy); 0177 for (const QNetworkInterface &iface : QNetworkInterface::allInterfaces()) { 0178 if ((iface.flags() & QNetworkInterface::IsUp) && (iface.flags() & QNetworkInterface::IsRunning) && (iface.flags() & QNetworkInterface::CanBroadcast)) { 0179 for (const QNetworkAddressEntry &ifaceAddress : iface.addressEntries()) { 0180 QHostAddress sourceAddress = ifaceAddress.ip(); 0181 if (sourceAddress.protocol() == QAbstractSocket::IPv4Protocol && sourceAddress != QHostAddress::LocalHost) { 0182 qCDebug(KDECONNECT_CORE) << "Broadcasting as" << sourceAddress; 0183 sendSocket.bind(sourceAddress); 0184 sendUdpIdentityPacket(sendSocket, addresses); 0185 sendSocket.close(); 0186 } 0187 } 0188 } 0189 } 0190 #else 0191 sendUdpIdentityPacket(addresses); 0192 #endif 0193 } 0194 0195 QList<QHostAddress> LanLinkProvider::getBroadcastAddresses() 0196 { 0197 const QStringList customDevices = KdeConnectConfig::instance().customDevices(); 0198 0199 QList<QHostAddress> destinations; 0200 destinations.reserve(customDevices.length() + 1); 0201 0202 // Default broadcast address 0203 destinations.append(m_testMode ? QHostAddress::LocalHost : QHostAddress::Broadcast); 0204 0205 // Custom device addresses 0206 for (auto &customDevice : customDevices) { 0207 QHostAddress address(customDevice); 0208 if (address.isNull()) { 0209 qCWarning(KDECONNECT_CORE) << "Invalid custom device address" << customDevice; 0210 } else { 0211 destinations.append(address); 0212 } 0213 } 0214 0215 return destinations; 0216 } 0217 0218 void LanLinkProvider::sendUdpIdentityPacket(const QList<QHostAddress> &addresses) 0219 { 0220 sendUdpIdentityPacket(m_udpSocket, addresses); 0221 } 0222 0223 void LanLinkProvider::sendUdpIdentityPacket(QUdpSocket &socket, const QList<QHostAddress> &addresses) 0224 { 0225 DeviceInfo myDeviceInfo = KdeConnectConfig::instance().deviceInfo(); 0226 NetworkPacket identityPacket = myDeviceInfo.toIdentityPacket(); 0227 identityPacket.set(QStringLiteral("tcpPort"), m_tcpPort); 0228 const QByteArray payload = identityPacket.serialize(); 0229 0230 for (auto &address : addresses) { 0231 qint64 bytes = socket.writeDatagram(payload, address, UDP_PORT); 0232 if (bytes == -1 && socket.error() == QAbstractSocket::DatagramTooLargeError) { 0233 // On macOS and FreeBSD, UDP broadcasts larger than MTU get dropped. See: 0234 // https://opensource.apple.com/source/xnu/xnu-3789.1.32/bsd/netinet/ip_output.c.auto.html#:~:text=/*%20don%27t%20allow%20broadcast%20messages%20to%20be%20fragmented%20*/ 0235 // We remove the capabilities to reduce the size of the packet. 0236 // This should only happen for broadcasts, so UDP packets sent from MDNS discoveries should still work. 0237 qWarning() << "Identity packet to" << address << "got rejected because it was too large. Retrying without including the capabilities"; 0238 identityPacket.set(QStringLiteral("outgoingCapabilities"), QStringList()); 0239 identityPacket.set(QStringLiteral("incomingCapabilities"), QStringList()); 0240 const QByteArray smallPayload = identityPacket.serialize(); 0241 socket.writeDatagram(smallPayload, address, UDP_PORT); 0242 } 0243 } 0244 } 0245 0246 // I'm the existing device, a new device is kindly introducing itself. 0247 // I will create a TcpSocket and try to connect. This can result in either tcpSocketConnected() or connectError(). 0248 void LanLinkProvider::udpBroadcastReceived() 0249 { 0250 while (m_udpSocket.hasPendingDatagrams()) { 0251 QByteArray datagram; 0252 datagram.resize(m_udpSocket.pendingDatagramSize()); 0253 QHostAddress sender; 0254 0255 m_udpSocket.readDatagram(datagram.data(), datagram.size(), &sender); 0256 0257 if (sender.isLoopback() && !m_testMode) 0258 continue; 0259 0260 NetworkPacket *receivedPacket = new NetworkPacket(); 0261 bool success = NetworkPacket::unserialize(datagram, receivedPacket); 0262 0263 // qCDebug(KDECONNECT_CORE) << "Datagram " << datagram.data() ; 0264 0265 if (!success) { 0266 qCDebug(KDECONNECT_CORE) << "Could not unserialize UDP packet"; 0267 delete receivedPacket; 0268 continue; 0269 } 0270 0271 if (receivedPacket->type() != PACKET_TYPE_IDENTITY) { 0272 qCDebug(KDECONNECT_CORE) << "Received a UDP packet of wrong type" << receivedPacket->type(); 0273 delete receivedPacket; 0274 continue; 0275 } 0276 0277 QString deviceId = receivedPacket->get<QString>(QStringLiteral("deviceId")); 0278 0279 if (deviceId == KdeConnectConfig::instance().deviceId()) { 0280 // qCDebug(KDECONNECT_CORE) << "Ignoring my own broadcast"; 0281 delete receivedPacket; 0282 continue; 0283 } 0284 0285 qint64 now = QDateTime::currentMSecsSinceEpoch(); 0286 if (m_lastConnectionTime[deviceId] + MILLIS_DELAY_BETWEEN_CONNECTIONS_TO_SAME_DEVICE > now) { 0287 qCDebug(KDECONNECT_CORE) << "Discarding second UPD packet from the same device" << deviceId << "received too quickly"; 0288 delete receivedPacket; 0289 return; 0290 } 0291 m_lastConnectionTime[deviceId] = now; 0292 0293 int tcpPort = receivedPacket->get<int>(QStringLiteral("tcpPort")); 0294 if (tcpPort < MIN_TCP_PORT || tcpPort > MAX_TCP_PORT) { 0295 qCDebug(KDECONNECT_CORE) << "TCP port outside of kdeconnect's range"; 0296 delete receivedPacket; 0297 continue; 0298 } 0299 0300 // qCDebug(KDECONNECT_CORE) << "Received Udp identity packet from" << sender << " asking for a tcp connection on port " << tcpPort; 0301 0302 if (m_receivedIdentityPackets.size() > MAX_REMEMBERED_IDENTITY_PACKETS) { 0303 qCWarning(KDECONNECT_CORE) << "Too many remembered identities, ignoring" << receivedPacket->get<QString>(QStringLiteral("deviceId")) 0304 << "received via UDP"; 0305 delete receivedPacket; 0306 continue; 0307 } 0308 0309 QSslSocket *socket = new QSslSocket(this); 0310 socket->setProxy(QNetworkProxy::NoProxy); 0311 m_receivedIdentityPackets[socket].np = receivedPacket; 0312 m_receivedIdentityPackets[socket].sender = sender; 0313 connect(socket, &QAbstractSocket::connected, this, &LanLinkProvider::tcpSocketConnected); 0314 connect(socket, &QAbstractSocket::errorOccurred, this, &LanLinkProvider::connectError); 0315 connect(socket, &QObject::destroyed, this, [this, socket]() { 0316 delete m_receivedIdentityPackets.take(socket).np; 0317 }); 0318 socket->connectToHost(sender, tcpPort); 0319 } 0320 } 0321 0322 void LanLinkProvider::connectError(QAbstractSocket::SocketError socketError) 0323 { 0324 QSslSocket *socket = qobject_cast<QSslSocket *>(sender()); 0325 if (!socket) 0326 return; 0327 0328 qCDebug(KDECONNECT_CORE) << "Socket error" << socketError; 0329 qCDebug(KDECONNECT_CORE) << "Fallback (1), try reverse connection (send udp packet)" << socket->errorString(); 0330 NetworkPacket np = KdeConnectConfig::instance().deviceInfo().toIdentityPacket(); 0331 np.set(QStringLiteral("tcpPort"), m_tcpPort); 0332 m_udpSocket.writeDatagram(np.serialize(), m_receivedIdentityPackets[socket].sender, UDP_PORT); 0333 0334 // The socket we created didn't work, and we didn't manage 0335 // to create a LanDeviceLink from it, deleting everything. 0336 socket->deleteLater(); 0337 } 0338 0339 // We received a UDP packet and answered by connecting to them by TCP. This gets called on a successful connection. 0340 void LanLinkProvider::tcpSocketConnected() 0341 { 0342 QSslSocket *socket = qobject_cast<QSslSocket *>(sender()); 0343 0344 if (!socket) { 0345 return; 0346 } 0347 0348 disconnect(socket, &QAbstractSocket::errorOccurred, this, &LanLinkProvider::connectError); 0349 0350 configureSocket(socket); 0351 0352 // If socket disconnects due to any reason after connection, link on ssl failure 0353 connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); 0354 0355 NetworkPacket *receivedPacket = m_receivedIdentityPackets[socket].np; 0356 const QString &deviceId = receivedPacket->get<QString>(QStringLiteral("deviceId")); 0357 // qCDebug(KDECONNECT_CORE) << "tcpSocketConnected" << socket->isWritable(); 0358 0359 // If network is on ssl, do not believe when they are connected, believe when handshake is completed 0360 NetworkPacket np2 = KdeConnectConfig::instance().deviceInfo().toIdentityPacket(); 0361 socket->write(np2.serialize()); 0362 bool success = socket->waitForBytesWritten(); 0363 0364 if (success) { 0365 qCDebug(KDECONNECT_CORE) << "TCP connection done (i'm the existing device)"; 0366 0367 // if ssl supported 0368 bool isDeviceTrusted = KdeConnectConfig::instance().trustedDevices().contains(deviceId); 0369 configureSslSocket(socket, deviceId, isDeviceTrusted); 0370 0371 qCDebug(KDECONNECT_CORE) << "Starting server ssl (I'm the client TCP socket)"; 0372 0373 connect(socket, &QSslSocket::encrypted, this, &LanLinkProvider::encrypted); 0374 0375 connect(socket, &QSslSocket::sslErrors, this, &LanLinkProvider::sslErrors); 0376 0377 socket->startServerEncryption(); 0378 } else { 0379 // The socket doesn't seem to work, so we can't create the connection. 0380 0381 qCDebug(KDECONNECT_CORE) << "Fallback (2), try reverse connection (send udp packet)"; 0382 m_udpSocket.writeDatagram(np2.serialize(), m_receivedIdentityPackets[socket].sender, UDP_PORT); 0383 0384 // Disconnect should trigger deleteLater, which should remove the socket from m_receivedIdentityPackets 0385 socket->disconnectFromHost(); 0386 } 0387 } 0388 0389 void LanLinkProvider::encrypted() 0390 { 0391 qCDebug(KDECONNECT_CORE) << "Socket successfully established an SSL connection"; 0392 0393 QSslSocket *socket = qobject_cast<QSslSocket *>(sender()); 0394 if (!socket) 0395 return; 0396 0397 Q_ASSERT(socket->mode() != QSslSocket::UnencryptedMode); 0398 0399 NetworkPacket *identityPacket = m_receivedIdentityPackets[socket].np; 0400 0401 DeviceInfo deviceInfo = DeviceInfo::FromIdentityPacketAndCert(*identityPacket, socket->peerCertificate()); 0402 0403 // We don't delete the socket because now it's owned by the LanDeviceLink 0404 disconnect(socket, &QObject::destroyed, nullptr, nullptr); 0405 delete m_receivedIdentityPackets.take(socket).np; 0406 0407 addLink(socket, deviceInfo); 0408 } 0409 0410 void LanLinkProvider::sslErrors(const QList<QSslError> &errors) 0411 { 0412 QSslSocket *socket = qobject_cast<QSslSocket *>(sender()); 0413 if (!socket) 0414 return; 0415 0416 bool fatal = false; 0417 for (const QSslError &error : errors) { 0418 if (error.error() != QSslError::SelfSignedCertificate) { 0419 qCCritical(KDECONNECT_CORE) << "Disconnecting due to fatal SSL Error: " << error; 0420 fatal = true; 0421 } else { 0422 qCDebug(KDECONNECT_CORE) << "Ignoring self-signed cert error"; 0423 } 0424 } 0425 0426 if (fatal) { 0427 // Disconnect should trigger deleteLater, which should remove the socket from m_receivedIdentityPackets 0428 socket->disconnectFromHost(); 0429 } 0430 } 0431 0432 // I'm the new device and this is the answer to my UDP identity packet (no data received yet). They are connecting to us through TCP, and they should send an 0433 // identity. 0434 void LanLinkProvider::newConnection() 0435 { 0436 qCDebug(KDECONNECT_CORE) << "LanLinkProvider newConnection"; 0437 0438 while (m_server->hasPendingConnections()) { 0439 QSslSocket *socket = m_server->nextPendingConnection(); 0440 configureSocket(socket); 0441 // This socket is still managed by us (and child of the QTcpServer), if 0442 // it disconnects before we manage to pass it to a LanDeviceLink, it's 0443 // our responsibility to delete it. We do so with this connection. 0444 connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); 0445 connect(socket, &QIODevice::readyRead, this, &LanLinkProvider::dataReceived); 0446 0447 QTimer *timer = new QTimer(socket); 0448 timer->setSingleShot(true); 0449 timer->setInterval(1000); 0450 connect(socket, &QSslSocket::encrypted, timer, &QObject::deleteLater); 0451 connect(timer, &QTimer::timeout, socket, [socket] { 0452 qCWarning(KDECONNECT_CORE) << "LanLinkProvider/newConnection: Host timed out without sending any identity." << socket->peerAddress(); 0453 socket->disconnectFromHost(); 0454 }); 0455 timer->start(); 0456 } 0457 } 0458 0459 // I'm the new device and this is the TCP response to my UDP identity packet 0460 void LanLinkProvider::dataReceived() 0461 { 0462 QSslSocket *socket = qobject_cast<QSslSocket *>(sender()); 0463 // the size here is arbitrary and is now at 8192 bytes. It needs to be considerably long as it includes the capabilities but there needs to be a limit 0464 // Tested between my systems and I get around 2000 per identity package. 0465 if (socket->bytesAvailable() > 8192) { 0466 qCWarning(KDECONNECT_CORE) << "LanLinkProvider/newConnection: Suspiciously long identity package received. Closing connection." << socket->peerAddress() 0467 << socket->bytesAvailable(); 0468 socket->disconnectFromHost(); 0469 return; 0470 } 0471 0472 if (!socket->canReadLine()) { 0473 // This can happen if the packet is large enough to be split in two chunks 0474 return; 0475 } 0476 0477 const QByteArray data = socket->readLine(); 0478 0479 qCDebug(KDECONNECT_CORE) << "LanLinkProvider received reply:" << data; 0480 0481 NetworkPacket *np = new NetworkPacket(); 0482 bool success = NetworkPacket::unserialize(data, np); 0483 0484 if (!success) { 0485 delete np; 0486 return; 0487 } 0488 0489 if (np->type() != PACKET_TYPE_IDENTITY) { 0490 qCWarning(KDECONNECT_CORE) << "LanLinkProvider/newConnection: Expected identity, received " << np->type(); 0491 delete np; 0492 return; 0493 } 0494 0495 if (m_receivedIdentityPackets.size() > MAX_REMEMBERED_IDENTITY_PACKETS) { 0496 qCWarning(KDECONNECT_CORE) << "Too many remembered identities, ignoring" << np->get<QString>(QStringLiteral("deviceId")) << "received via TCP"; 0497 delete np; 0498 return; 0499 } 0500 0501 // Needed in "encrypted" if ssl is used, similar to "tcpSocketConnected" 0502 m_receivedIdentityPackets[socket].np = np; 0503 connect(socket, &QObject::destroyed, this, [this, socket]() { 0504 delete m_receivedIdentityPackets.take(socket).np; 0505 }); 0506 0507 const QString &deviceId = np->get<QString>(QStringLiteral("deviceId")); 0508 // qCDebug(KDECONNECT_CORE) << "Handshaking done (i'm the new device)"; 0509 0510 // This socket will now be owned by the LanDeviceLink or we don't want more data to be received, forget about it 0511 disconnect(socket, &QIODevice::readyRead, this, &LanLinkProvider::dataReceived); 0512 0513 bool isDeviceTrusted = KdeConnectConfig::instance().trustedDevices().contains(deviceId); 0514 configureSslSocket(socket, deviceId, isDeviceTrusted); 0515 0516 qCDebug(KDECONNECT_CORE) << "Starting client ssl (but I'm the server TCP socket)"; 0517 0518 connect(socket, &QSslSocket::encrypted, this, &LanLinkProvider::encrypted); 0519 0520 if (isDeviceTrusted) { 0521 connect(socket, &QSslSocket::sslErrors, this, &LanLinkProvider::sslErrors); 0522 } 0523 0524 socket->startClientEncryption(); 0525 } 0526 0527 void LanLinkProvider::onLinkDestroyed(const QString &deviceId, DeviceLink *oldPtr) 0528 { 0529 qCDebug(KDECONNECT_CORE) << "LanLinkProvider deviceLinkDestroyed" << deviceId; 0530 DeviceLink *link = m_links.take(deviceId); 0531 Q_ASSERT(link == oldPtr); 0532 } 0533 0534 void LanLinkProvider::configureSslSocket(QSslSocket *socket, const QString &deviceId, bool isDeviceTrusted) 0535 { 0536 // Configure for ssl 0537 QSslConfiguration sslConfig; 0538 sslConfig.setLocalCertificate(KdeConnectConfig::instance().certificate()); 0539 0540 QFile privateKeyFile(KdeConnectConfig::instance().privateKeyPath()); 0541 QSslKey privateKey; 0542 if (privateKeyFile.open(QIODevice::ReadOnly)) { 0543 privateKey = QSslKey(privateKeyFile.readAll(), QSsl::Rsa); 0544 } 0545 privateKeyFile.close(); 0546 sslConfig.setPrivateKey(privateKey); 0547 0548 if (isDeviceTrusted) { 0549 QSslCertificate certificate = KdeConnectConfig::instance().getTrustedDeviceCertificate(deviceId); 0550 sslConfig.setCaCertificates({certificate}); 0551 sslConfig.setPeerVerifyMode(QSslSocket::VerifyPeer); 0552 } else { 0553 sslConfig.setPeerVerifyMode(QSslSocket::QueryPeer); 0554 } 0555 socket->setSslConfiguration(sslConfig); 0556 socket->setPeerVerifyName(deviceId); 0557 0558 // Usually SSL errors are only bad for trusted devices. Uncomment this section to log errors in any case, for debugging. 0559 // QObject::connect(socket, static_cast<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors), [](const QList<QSslError>& errors) 0560 //{ 0561 // Q_FOREACH (const QSslError& error, errors) { 0562 // qCDebug(KDECONNECT_CORE) << "SSL Error:" << error.errorString(); 0563 // } 0564 // }); 0565 } 0566 0567 void LanLinkProvider::configureSocket(QSslSocket *socket) 0568 { 0569 socket->setProxy(QNetworkProxy::NoProxy); 0570 0571 socket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1)); 0572 0573 #ifdef TCP_KEEPIDLE 0574 // time to start sending keepalive packets (seconds) 0575 int maxIdle = 10; 0576 setsockopt(socket->socketDescriptor(), IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle)); 0577 #endif 0578 0579 #ifdef TCP_KEEPINTVL 0580 // interval between keepalive packets after the initial period (seconds) 0581 int interval = 5; 0582 setsockopt(socket->socketDescriptor(), IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)); 0583 #endif 0584 0585 #ifdef TCP_KEEPCNT 0586 // number of missed keepalive packets before disconnecting 0587 int count = 3; 0588 setsockopt(socket->socketDescriptor(), IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count)); 0589 #endif 0590 0591 #if defined(Q_OS_WIN) 0592 int maxIdle = 5 * 60 * 1000; // 5 minutes of idle before sending keep-alive 0593 int interval = 5 * 1000; // 5 seconds interval between probes after 5 minute delay 0594 DWORD nop; 0595 0596 // see https://learn.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals 0597 struct tcp_keepalive keepalive = {1 /* true */, maxIdle, interval}; 0598 0599 int rv = WSAIoctl(socket->socketDescriptor(), SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), nullptr, 0, &nop, nullptr, nullptr); 0600 if (!rv) { 0601 int error = WSAGetLastError(); 0602 qCDebug(KDECONNECT_CORE) << "Could not enable TCP Keep-Alive: " << error; 0603 } 0604 #endif 0605 } 0606 0607 void LanLinkProvider::addLink(QSslSocket *socket, const DeviceInfo &deviceInfo) 0608 { 0609 QString certDeviceId = socket->peerCertificate().subjectDisplayName(); 0610 DBusHelper::filterNonExportableCharacters(certDeviceId); 0611 if (deviceInfo.id != certDeviceId) { 0612 socket->disconnectFromHost(); 0613 qCWarning(KDECONNECT_CORE) << "DeviceID in cert doesn't match deviceID in identity packet. " << deviceInfo.id << " vs " << certDeviceId; 0614 return; 0615 } 0616 0617 // Socket disconnection will now be handled by LanDeviceLink 0618 disconnect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); 0619 0620 LanDeviceLink *deviceLink; 0621 // Do we have a link for this device already? 0622 QMap<QString, LanDeviceLink *>::iterator linkIterator = m_links.find(deviceInfo.id); 0623 if (linkIterator != m_links.end()) { 0624 deviceLink = linkIterator.value(); 0625 if (deviceLink->deviceInfo().certificate != deviceInfo.certificate) { 0626 qWarning() << "LanLink was asked to replace a socket but the certificate doesn't match, aborting"; 0627 return; 0628 } 0629 // qCDebug(KDECONNECT_CORE) << "Reusing link to" << deviceId; 0630 deviceLink->reset(socket); 0631 } else { 0632 deviceLink = new LanDeviceLink(deviceInfo, this, socket); 0633 // Socket disconnection will now be handled by LanDeviceLink 0634 disconnect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); 0635 bool isDeviceTrusted = KdeConnectConfig::instance().trustedDevices().contains(deviceInfo.id); 0636 if (!isDeviceTrusted && m_links.size() > MAX_UNPAIRED_CONNECTIONS) { 0637 qCWarning(KDECONNECT_CORE) << "Too many unpaired devices to remember them all. Ignoring " << deviceInfo.id; 0638 socket->disconnectFromHost(); 0639 socket->deleteLater(); 0640 return; 0641 } 0642 m_links[deviceInfo.id] = deviceLink; 0643 } 0644 Q_EMIT onConnectionReceived(deviceLink); 0645 } 0646 0647 #include "moc_lanlinkprovider.cpp"