2013-08-07 10:29:56 +01:00
/**
2020-08-17 10:48:10 +01:00
* SPDX - FileCopyrightText : 2013 Albert Vaca < albertvaka @ gmail . com >
2013-08-07 10:29:56 +01:00
*
2020-08-17 10:48:10 +01:00
* SPDX - License - Identifier : GPL - 2.0 - only OR GPL - 3.0 - only OR LicenseRef - KDE - Accepted - GPL
2013-08-07 10:29:56 +01:00
*/
2013-08-28 22:47:39 +01:00
# include "lanlinkprovider.h"
2014-09-21 23:59:34 +01:00
# include "core_debug.h"
2013-08-07 10:29:56 +01:00
2015-09-10 14:51:38 +01:00
# ifndef Q_OS_WIN
2022-09-10 22:23:52 +01:00
# include <netdb.h>
2013-10-30 00:18:25 +00:00
# include <netinet/in.h>
# include <netinet/tcp.h>
2022-09-10 22:23:52 +01:00
# include <sys/socket.h>
2023-03-04 13:06:55 +00:00
# else
2023-07-16 15:20:34 +01:00
# include <winsock2.h>
2023-07-16 17:01:13 +01:00
// Winsock2 needs to be included before any other header
# include <mstcpip.h>
2015-09-10 14:51:38 +01:00
# endif
2013-10-30 00:18:25 +00:00
2013-08-07 10:29:56 +01:00
# include <QHostInfo>
2019-06-03 05:13:58 +01:00
# include <QMetaEnum>
2022-09-10 22:23:52 +01:00
# include <QNetworkConfigurationManager>
2017-03-06 21:01:46 +00:00
# include <QNetworkProxy>
2015-06-14 21:29:00 +01:00
# include <QNetworkSession>
2016-07-05 13:27:53 +01:00
# include <QSslCipher>
# include <QSslConfiguration>
2020-08-07 09:59:17 +01:00
# include <QSslKey>
2020-09-12 07:53:54 +01:00
# include <QStringList>
2022-09-10 22:23:52 +01:00
# include <QTcpServer>
# include <QUdpSocket>
2013-08-07 10:29:56 +01:00
2016-07-05 13:27:53 +01:00
# include "daemon.h"
2022-09-10 22:23:52 +01:00
# include "kdeconnectconfig.h"
2013-09-09 17:35:56 +01:00
# include "landevicelink.h"
2019-12-09 22:14:19 +00:00
# include "qtcompat_p.h"
2013-08-12 15:09:52 +01:00
2020-09-24 16:13:34 +01:00
static const int MAX_UNPAIRED_CONNECTIONS = 42 ;
2020-09-24 16:16:02 +01:00
static const int MAX_REMEMBERED_IDENTITY_PACKETS = 42 ;
2020-09-24 16:13:34 +01:00
2022-09-10 22:23:52 +01:00
LanLinkProvider : : LanLinkProvider ( bool testMode , quint16 udpBroadcastPort , quint16 udpListenPort )
2019-05-01 22:26:07 +01:00
: m_server ( new Server ( this ) )
, m_udpSocket ( this )
, m_tcpPort ( 0 )
2019-06-05 16:14:50 +01:00
, m_udpBroadcastPort ( udpBroadcastPort )
, m_udpListenPort ( udpListenPort )
2018-11-03 01:17:25 +00:00
, m_testMode ( testMode )
2018-10-29 15:47:49 +00:00
, m_combineBroadcastsTimer ( this )
2013-08-07 10:29:56 +01:00
{
2017-09-03 20:39:44 +01:00
m_combineBroadcastsTimer . setInterval ( 0 ) ; // increase this if waiting a single event-loop iteration is not enough
m_combineBroadcastsTimer . setSingleShot ( true ) ;
connect ( & m_combineBroadcastsTimer , & QTimer : : timeout , this , & LanLinkProvider : : broadcastToNetwork ) ;
2016-06-02 11:18:51 +01:00
2019-05-04 14:10:27 +01:00
connect ( & m_udpSocket , & QIODevice : : readyRead , this , & LanLinkProvider : : udpBroadcastReceived ) ;
2013-08-07 10:29:56 +01:00
2017-09-03 20:39:44 +01:00
m_server - > setProxy ( QNetworkProxy : : NoProxy ) ;
2019-05-04 18:27:04 +01:00
connect ( m_server , & QTcpServer : : newConnection , this , & LanLinkProvider : : newConnection ) ;
2013-08-07 10:29:56 +01:00
2017-09-03 20:39:44 +01:00
m_udpSocket . setProxy ( QNetworkProxy : : NoProxy ) ;
2017-03-06 21:01:46 +00:00
2022-09-10 22:23:52 +01:00
// Detect when a network interface changes status, so we announce ourselves in the new network
QNetworkConfigurationManager * networkManager = new QNetworkConfigurationManager ( this ) ;
2015-09-08 08:05:06 +01:00
connect ( networkManager , & QNetworkConfigurationManager : : configurationChanged , this , & LanLinkProvider : : onNetworkConfigurationChanged ) ;
2023-06-25 20:58:50 +01:00
connect ( & m_udpSocket , & QAbstractSocket : : errorOccurred , [ ] ( QAbstractSocket : : SocketError socketError ) {
qWarning ( ) < < " Error sending UDP packet: " < < socketError ;
} ) ;
2015-09-08 08:05:06 +01:00
}
2022-09-10 22:23:52 +01:00
void LanLinkProvider : : onNetworkConfigurationChanged ( const QNetworkConfiguration & config )
2015-09-08 08:05:06 +01:00
{
2015-12-06 00:19:20 +00:00
if ( m_lastConfig ! = config & & config . state ( ) = = QNetworkConfiguration : : Active ) {
2015-09-08 08:05:06 +01:00
m_lastConfig = config ;
2015-06-14 21:29:00 +01:00
onNetworkChange ( ) ;
2015-09-08 08:05:06 +01:00
}
2013-08-07 10:29:56 +01:00
}
2015-04-04 18:05:55 +01:00
LanLinkProvider : : ~ LanLinkProvider ( )
{
}
2013-08-28 22:47:39 +01:00
void LanLinkProvider : : onStart ( )
2013-08-07 10:29:56 +01:00
{
2022-09-10 22:23:52 +01:00
const QHostAddress bindAddress = m_testMode ? QHostAddress : : LocalHost : QHostAddress : : Any ;
2015-12-02 17:49:00 +00:00
2019-06-05 16:14:50 +01:00
bool success = m_udpSocket . bind ( bindAddress , m_udpListenPort , QUdpSocket : : ShareAddress ) ;
2019-06-03 05:13:58 +01:00
if ( ! success ) {
2019-06-03 05:24:10 +01:00
QAbstractSocket : : SocketError sockErr = m_udpSocket . error ( ) ;
2019-06-03 05:13:58 +01:00
// Refer to https://doc.qt.io/qt-5/qabstractsocket.html#SocketError-enum to decode socket error number
2019-06-10 15:40:28 +01:00
QString errorMessage = QString : : fromLatin1 ( QMetaEnum : : fromType < QAbstractSocket : : SocketError > ( ) . valueToKey ( sockErr ) ) ;
2022-09-10 22:23:52 +01:00
qCritical ( KDECONNECT_CORE ) < < QLatin1String ( " Failed to bind UDP socket on port " ) < < m_udpListenPort < < QLatin1String ( " with error " ) < < errorMessage ;
2019-06-03 05:13:58 +01:00
}
2015-12-02 17:49:00 +00:00
Q_ASSERT ( success ) ;
2013-08-08 03:11:20 +01:00
2017-09-03 20:39:44 +01:00
m_tcpPort = MIN_TCP_PORT ;
while ( ! m_server - > listen ( bindAddress , m_tcpPort ) ) {
m_tcpPort + + ;
2022-09-10 22:23:52 +01:00
if ( m_tcpPort > MAX_TCP_PORT ) { // No ports available?
2017-02-14 22:03:59 +00:00
qCritical ( KDECONNECT_CORE ) < < " Error opening a port in range " < < MIN_TCP_PORT < < " - " < < MAX_TCP_PORT ;
2017-09-03 20:39:44 +01:00
m_tcpPort = 0 ;
2015-03-22 06:11:50 +00:00
return ;
}
2014-04-14 20:45:41 +01:00
}
2013-08-07 10:29:56 +01:00
2015-04-05 00:32:15 +01:00
onNetworkChange ( ) ;
2019-05-26 19:30:39 +01:00
qCDebug ( KDECONNECT_CORE ) < < " LanLinkProvider started " ;
2013-08-07 10:29:56 +01:00
}
2013-08-28 22:47:39 +01:00
void LanLinkProvider : : onStop ( )
2013-08-07 10:29:56 +01:00
{
2017-09-03 20:39:44 +01:00
m_udpSocket . close ( ) ;
m_server - > close ( ) ;
2019-05-26 19:30:39 +01:00
qCDebug ( KDECONNECT_CORE ) < < " LanLinkProvider stopped " ;
2013-08-07 10:29:56 +01:00
}
2015-04-05 00:32:15 +01:00
void LanLinkProvider : : onNetworkChange ( )
2013-08-08 03:11:20 +01:00
{
2017-09-03 20:39:44 +01:00
if ( m_combineBroadcastsTimer . isActive ( ) ) {
2020-08-18 15:55:48 +01:00
qCDebug ( KDECONNECT_CORE ) < < " Preventing duplicate broadcasts " ;
2016-06-02 11:18:51 +01:00
return ;
}
2017-09-03 20:39:44 +01:00
m_combineBroadcastsTimer . start ( ) ;
2016-06-02 11:18:51 +01:00
}
2022-09-10 22:23:52 +01:00
// I'm in a new network, let's be polite and introduce myself
2016-06-02 11:18:51 +01:00
void LanLinkProvider : : broadcastToNetwork ( )
{
2017-09-03 20:39:44 +01:00
if ( ! m_server - > isListening ( ) ) {
2022-09-10 22:23:52 +01:00
// Not started
2014-04-14 20:45:41 +01:00
return ;
}
2013-10-03 16:25:17 +01:00
2017-09-03 20:39:44 +01:00
Q_ASSERT ( m_tcpPort ! = 0 ) ;
2015-04-04 18:05:55 +01:00
2015-06-14 21:29:00 +01:00
qCDebug ( KDECONNECT_CORE ( ) ) < < " Broadcasting identity packet " ;
2016-11-20 03:24:28 +00:00
2020-08-18 15:55:48 +01:00
QList < QHostAddress > destinations = getBroadcastAddresses ( ) ;
2016-11-20 03:24:28 +00:00
2023-06-27 12:10:59 +01:00
NetworkPacket np = KdeConnectConfig : : instance ( ) . deviceInfo ( ) . toIdentityPacket ( ) ;
2017-09-03 20:39:44 +01:00
np . set ( QStringLiteral ( " tcpPort " ) , m_tcpPort ) ;
2022-07-11 21:51:18 +01:00
# if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
2022-09-10 22:23:52 +01:00
// On macOS and FreeBSD, the too large UDP packet (larger than MTU) causes
// incomplete transmission.
// We remove the capacitilities to reduce the discovery packet to the min
// MTU of the interfaces with broadcast feature.
2022-07-11 21:51:18 +01:00
int mtu = 1500 ;
2022-09-10 22:23:52 +01:00
for ( const QNetworkInterface & iface : QNetworkInterface : : allInterfaces ( ) ) {
if ( ( iface . flags ( ) & QNetworkInterface : : IsUp ) & & ( iface . flags ( ) & QNetworkInterface : : IsRunning ) & & ( iface . flags ( ) & QNetworkInterface : : CanBroadcast ) ) {
2022-07-11 21:51:18 +01:00
int ifaceMtu = iface . maximumTransmissionUnit ( ) ;
if ( ifaceMtu < mtu & & ifaceMtu > 0 ) {
mtu = ifaceMtu ;
}
}
}
QByteArray payload = np . serialize ( ) ;
if ( payload . length ( ) > mtu ) {
2022-09-10 22:23:52 +01:00
// First try to drop the less important outgoing capabilities
2022-07-11 21:51:18 +01:00
np . set ( QStringLiteral ( " outgoingCapabilities " ) , QStringList ( ) ) ;
payload = np . serialize ( ) ;
}
if ( payload . length ( ) > mtu ) {
2022-09-10 22:23:52 +01:00
// If still too large, drop the incoming capabilities
2022-07-11 21:51:18 +01:00
np . set ( QStringLiteral ( " incomingCapabilities " ) , QStringList ( ) ) ;
payload = np . serialize ( ) ;
}
2020-09-12 07:53:54 +01:00
# endif
2016-11-20 03:24:28 +00:00
2022-07-19 11:14:35 +01:00
# if defined(Q_OS_WIN) || defined(Q_OS_FREEBSD)
2022-09-10 22:23:52 +01:00
// On Windows and FreeBSD we need to broadcast from every local IP address to reach all networks
2016-11-20 03:24:28 +00:00
QUdpSocket sendSocket ;
2017-03-06 21:01:46 +00:00
sendSocket . setProxy ( QNetworkProxy : : NoProxy ) ;
2022-09-10 22:23:52 +01:00
for ( const QNetworkInterface & iface : QNetworkInterface : : allInterfaces ( ) ) {
if ( ( iface . flags ( ) & QNetworkInterface : : IsUp ) & & ( iface . flags ( ) & QNetworkInterface : : IsRunning ) & & ( iface . flags ( ) & QNetworkInterface : : CanBroadcast ) ) {
for ( const QNetworkAddressEntry & ifaceAddress : iface . addressEntries ( ) ) {
2016-11-20 03:24:28 +00:00
QHostAddress sourceAddress = ifaceAddress . ip ( ) ;
if ( sourceAddress . protocol ( ) = = QAbstractSocket : : IPv4Protocol & & sourceAddress ! = QHostAddress : : LocalHost ) {
qCDebug ( KDECONNECT_CORE ( ) ) < < " Broadcasting as " < < sourceAddress ;
2022-09-15 20:14:22 +01:00
sendSocket . bind ( sourceAddress ) ;
2020-08-18 15:55:48 +01:00
sendBroadcasts ( sendSocket , np , destinations ) ;
2016-11-20 03:24:28 +00:00
sendSocket . close ( ) ;
}
}
}
}
# else
2020-08-18 15:55:48 +01:00
sendBroadcasts ( m_udpSocket , np , destinations ) ;
2016-11-20 03:24:28 +00:00
# endif
2020-08-18 15:55:48 +01:00
}
QList < QHostAddress > LanLinkProvider : : getBroadcastAddresses ( )
{
const QStringList customDevices = KdeConnectConfig : : instance ( ) . customDevices ( ) ;
QList < QHostAddress > destinations ;
destinations . reserve ( customDevices . length ( ) + 1 ) ;
// Default broadcast address
destinations . append ( m_testMode ? QHostAddress : : LocalHost : QHostAddress : : Broadcast ) ;
// Custom device addresses
2022-09-10 22:23:52 +01:00
for ( auto & customDevice : customDevices ) {
2020-08-18 15:55:48 +01:00
QHostAddress address ( customDevice ) ;
if ( address . isNull ( ) ) {
qCWarning ( KDECONNECT_CORE ) < < " Invalid custom device address " < < customDevice ;
} else {
destinations . append ( address ) ;
}
}
return destinations ;
}
2016-11-20 03:24:28 +00:00
2022-09-10 22:23:52 +01:00
void LanLinkProvider : : sendBroadcasts ( QUdpSocket & socket , const NetworkPacket & np , const QList < QHostAddress > & addresses )
2020-08-18 15:55:48 +01:00
{
const QByteArray payload = np . serialize ( ) ;
2022-09-10 22:23:52 +01:00
for ( auto & address : addresses ) {
2020-08-18 15:55:48 +01:00
socket . writeDatagram ( payload , address , m_udpBroadcastPort ) ;
}
2013-08-07 10:29:56 +01:00
}
2022-09-10 22:23:52 +01:00
// I'm the existing device, a new device is kindly introducing itself.
// I will create a TcpSocket and try to connect. This can result in either tcpSocketConnected() or connectError().
2019-05-04 14:10:27 +01:00
void LanLinkProvider : : udpBroadcastReceived ( )
2013-08-07 10:29:56 +01:00
{
2017-09-03 20:39:44 +01:00
while ( m_udpSocket . hasPendingDatagrams ( ) ) {
2013-08-07 10:29:56 +01:00
QByteArray datagram ;
2017-09-03 20:39:44 +01:00
datagram . resize ( m_udpSocket . pendingDatagramSize ( ) ) ;
2013-08-07 10:29:56 +01:00
QHostAddress sender ;
2017-09-03 20:39:44 +01:00
m_udpSocket . readDatagram ( datagram . data ( ) , datagram . size ( ) , & sender ) ;
2013-08-07 10:29:56 +01:00
2017-09-03 20:39:44 +01:00
if ( sender . isLoopback ( ) & & ! m_testMode )
2015-12-06 00:19:55 +00:00
continue ;
2023-06-27 12:10:59 +01:00
NetworkPacket * receivedPacket = new NetworkPacket ( ) ;
2018-03-04 19:48:51 +00:00
bool success = NetworkPacket : : unserialize ( datagram , receivedPacket ) ;
2013-08-07 10:29:56 +01:00
2022-09-10 22:23:52 +01:00
// qCDebug(KDECONNECT_CORE) << "Datagram " << datagram.data() ;
2015-07-05 14:23:53 +01:00
2019-05-04 17:34:59 +01:00
if ( ! success ) {
qCDebug ( KDECONNECT_CORE ) < < " Could not unserialize UDP packet " ;
delete receivedPacket ;
continue ;
}
if ( receivedPacket - > type ( ) ! = PACKET_TYPE_IDENTITY ) {
qCDebug ( KDECONNECT_CORE ) < < " Received a UDP packet of wrong type " < < receivedPacket - > type ( ) ;
2018-03-04 19:48:51 +00:00
delete receivedPacket ;
2015-05-05 00:04:50 +01:00
continue ;
2014-04-14 20:45:41 +01:00
}
2013-08-07 12:40:39 +01:00
2019-09-08 16:09:52 +01:00
if ( receivedPacket - > get < QString > ( QStringLiteral ( " deviceId " ) ) = = KdeConnectConfig : : instance ( ) . deviceId ( ) ) {
2022-09-10 22:23:52 +01:00
// qCDebug(KDECONNECT_CORE) << "Ignoring my own broadcast";
2018-03-04 19:48:51 +00:00
delete receivedPacket ;
2015-05-05 00:04:50 +01:00
continue ;
2014-04-14 20:45:41 +01:00
}
2013-08-16 04:35:00 +01:00
2018-03-04 19:48:51 +00:00
int tcpPort = receivedPacket - > get < int > ( QStringLiteral ( " tcpPort " ) ) ;
2020-09-24 16:18:06 +01:00
if ( tcpPort < MIN_TCP_PORT | | tcpPort > MAX_TCP_PORT ) {
qCDebug ( KDECONNECT_CORE ) < < " TCP port outside of kdeconnect's range " ;
delete receivedPacket ;
continue ;
}
2013-08-08 03:11:20 +01:00
2022-09-10 22:23:52 +01:00
// qCDebug(KDECONNECT_CORE) << "Received Udp identity packet from" << sender << " asking for a tcp connection on port " << tcpPort;
2013-08-08 03:11:20 +01:00
2020-09-24 16:16:02 +01:00
if ( m_receivedIdentityPackets . size ( ) > MAX_REMEMBERED_IDENTITY_PACKETS ) {
2022-09-10 22:23:52 +01:00
qCWarning ( KDECONNECT_CORE ) < < " Too many remembered identities, ignoring " < < receivedPacket - > get < QString > ( QStringLiteral ( " deviceId " ) )
< < " received via UDP " ;
2020-09-24 16:16:02 +01:00
delete receivedPacket ;
continue ;
}
2022-09-10 22:23:52 +01:00
QSslSocket * socket = new QSslSocket ( this ) ;
2017-03-06 21:01:46 +00:00
socket - > setProxy ( QNetworkProxy : : NoProxy ) ;
2018-03-04 19:48:51 +00:00
m_receivedIdentityPackets [ socket ] . np = receivedPacket ;
m_receivedIdentityPackets [ socket ] . sender = sender ;
2019-05-04 14:10:27 +01:00
connect ( socket , & QAbstractSocket : : connected , this , & LanLinkProvider : : tcpSocketConnected ) ;
2022-09-10 22:23:52 +01:00
# if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
2019-05-01 22:42:24 +01:00
connect ( socket , QOverload < QAbstractSocket : : SocketError > : : of ( & QAbstractSocket : : error ) , this , & LanLinkProvider : : connectError ) ;
2020-05-09 15:54:22 +01:00
# else
connect ( socket , & QAbstractSocket : : errorOccurred , this , & LanLinkProvider : : connectError ) ;
# endif
2014-04-14 20:45:41 +01:00
socket - > connectToHost ( sender , tcpPort ) ;
2013-08-07 12:40:39 +01:00
}
}
2013-08-07 10:29:56 +01:00
2019-05-26 19:36:35 +01:00
void LanLinkProvider : : connectError ( QAbstractSocket : : SocketError socketError )
2013-08-07 12:40:39 +01:00
{
2022-09-10 22:23:52 +01:00
QSslSocket * socket = qobject_cast < QSslSocket * > ( sender ( ) ) ;
if ( ! socket )
return ;
2013-08-07 10:29:56 +01:00
2019-05-26 19:36:35 +01:00
qCDebug ( KDECONNECT_CORE ) < < " Socket error " < < socketError ;
2015-09-09 19:12:16 +01:00
qCDebug ( KDECONNECT_CORE ) < < " Fallback (1), try reverse connection (send udp packet) " < < socket - > errorString ( ) ;
2023-06-27 12:10:59 +01:00
NetworkPacket np = KdeConnectConfig : : instance ( ) . deviceInfo ( ) . toIdentityPacket ( ) ;
2017-09-03 20:39:44 +01:00
np . set ( QStringLiteral ( " tcpPort " ) , m_tcpPort ) ;
2019-06-05 16:14:50 +01:00
m_udpSocket . writeDatagram ( np . serialize ( ) , m_receivedIdentityPackets [ socket ] . sender , m_udpBroadcastPort ) ;
2013-08-07 12:40:39 +01:00
2022-09-10 22:23:52 +01:00
// The socket we created didn't work, and we didn't manage
// to create a LanDeviceLink from it, deleting everything.
2018-03-04 19:48:51 +00:00
delete m_receivedIdentityPackets . take ( socket ) . np ;
2020-09-24 16:03:06 +01:00
socket - > deleteLater ( ) ;
2013-08-07 12:40:39 +01:00
}
2022-09-10 22:23:52 +01:00
// We received a UDP packet and answered by connecting to them by TCP. This gets called on a successful connection.
2019-05-04 14:10:27 +01:00
void LanLinkProvider : : tcpSocketConnected ( )
2013-08-07 12:40:39 +01:00
{
2022-09-10 22:23:52 +01:00
QSslSocket * socket = qobject_cast < QSslSocket * > ( sender ( ) ) ;
2017-07-07 16:26:55 +01:00
2023-03-04 22:14:31 +00:00
if ( ! socket ) {
2022-09-10 22:23:52 +01:00
return ;
2023-03-04 22:14:31 +00:00
}
2022-09-10 22:23:52 +01:00
# if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
2019-05-01 22:42:24 +01:00
disconnect ( socket , QOverload < QAbstractSocket : : SocketError > : : of ( & QAbstractSocket : : error ) , this , & LanLinkProvider : : connectError ) ;
2020-05-09 15:54:22 +01:00
# else
disconnect ( socket , & QAbstractSocket : : errorOccurred , this , & LanLinkProvider : : connectError ) ;
# endif
2019-05-01 22:42:24 +01:00
2013-10-30 00:18:25 +00:00
configureSocket ( socket ) ;
2018-03-03 19:29:18 +00:00
// If socket disconnects due to any reason after connection, link on ssl failure
2016-11-26 14:12:38 +00:00
connect ( socket , & QAbstractSocket : : disconnected , socket , & QObject : : deleteLater ) ;
2015-07-07 19:52:10 +01:00
2022-09-10 22:23:52 +01:00
NetworkPacket * receivedPacket = m_receivedIdentityPackets [ socket ] . np ;
const QString & deviceId = receivedPacket - > get < QString > ( QStringLiteral ( " deviceId " ) ) ;
// qCDebug(KDECONNECT_CORE) << "tcpSocketConnected" << socket->isWritable();
2013-08-07 12:40:39 +01:00
2015-07-05 14:23:53 +01:00
// If network is on ssl, do not believe when they are connected, believe when handshake is completed
2023-06-27 12:10:59 +01:00
NetworkPacket np2 = KdeConnectConfig : : instance ( ) . deviceInfo ( ) . toIdentityPacket ( ) ;
2015-07-05 14:23:53 +01:00
socket - > write ( np2 . serialize ( ) ) ;
bool success = socket - > waitForBytesWritten ( ) ;
2013-08-07 12:40:39 +01:00
if ( success ) {
2016-06-17 00:59:53 +01:00
qCDebug ( KDECONNECT_CORE ) < < " TCP connection done (i'm the existing device) " ;
2015-07-05 14:23:53 +01:00
// if ssl supported
2023-06-27 12:10:59 +01:00
bool isDeviceTrusted = KdeConnectConfig : : instance ( ) . trustedDevices ( ) . contains ( deviceId ) ;
configureSslSocket ( socket , deviceId , isDeviceTrusted ) ;
2016-07-04 18:52:28 +01:00
2023-06-27 12:10:59 +01:00
qCDebug ( KDECONNECT_CORE ) < < " Starting server ssl (I'm the client TCP socket) " ;
2016-07-04 18:52:28 +01:00
2023-06-27 12:10:59 +01:00
connect ( socket , & QSslSocket : : encrypted , this , & LanLinkProvider : : encrypted ) ;
2016-06-22 13:25:12 +01:00
2023-06-27 12:10:59 +01:00
connect ( socket , QOverload < const QList < QSslError > & > : : of ( & QSslSocket : : sslErrors ) , this , & LanLinkProvider : : sslErrors ) ;
2013-08-16 05:22:37 +01:00
2023-06-27 12:10:59 +01:00
socket - > startServerEncryption ( ) ;
2013-08-07 12:40:39 +01:00
} else {
2023-06-27 12:10:59 +01:00
// The socket doesn't seem to work, so we can't create the connection.
2015-04-05 00:32:15 +01:00
qCDebug ( KDECONNECT_CORE ) < < " Fallback (2), try reverse connection (send udp packet) " ;
2019-06-05 16:14:50 +01:00
m_udpSocket . writeDatagram ( np2 . serialize ( ) , m_receivedIdentityPackets [ socket ] . sender , m_udpBroadcastPort ) ;
2013-08-07 10:29:56 +01:00
2023-06-27 12:10:59 +01:00
// Cleanup the network packet now. The socket should be deleted via the disconnected() signal.
// We don't do this on success, because it is done later in the encrypted() slot.
delete m_receivedIdentityPackets . take ( socket ) . np ;
}
2013-08-07 10:29:56 +01:00
}
2015-07-14 13:04:04 +01:00
void LanLinkProvider : : encrypted ( )
{
2018-06-02 19:20:15 +01:00
qCDebug ( KDECONNECT_CORE ) < < " Socket successfully established an SSL connection " ;
2015-07-13 15:25:22 +01:00
2022-09-10 22:23:52 +01:00
QSslSocket * socket = qobject_cast < QSslSocket * > ( sender ( ) ) ;
if ( ! socket )
return ;
2015-07-05 14:23:53 +01:00
2016-07-05 11:42:39 +01:00
Q_ASSERT ( socket - > mode ( ) ! = QSslSocket : : UnencryptedMode ) ;
2023-06-27 12:10:59 +01:00
NetworkPacket * identityPacket = m_receivedIdentityPackets [ socket ] . np ;
2015-07-05 14:23:53 +01:00
2023-06-27 12:10:59 +01:00
DeviceInfo deviceInfo = DeviceInfo : : FromIdentityPacketAndCert ( * identityPacket , socket - > peerCertificate ( ) ) ;
2020-09-24 17:46:57 +01:00
2023-06-27 12:10:59 +01:00
addLink ( socket , deviceInfo ) ;
2015-07-05 14:23:53 +01:00
2023-06-27 12:10:59 +01:00
// We don't delete the socket because now it's owned by the LanDeviceLink
2018-03-04 19:48:51 +00:00
delete m_receivedIdentityPackets . take ( socket ) . np ;
2015-07-05 14:23:53 +01:00
}
2022-09-10 22:23:52 +01:00
void LanLinkProvider : : sslErrors ( const QList < QSslError > & errors )
2015-07-05 14:23:53 +01:00
{
2022-09-10 22:23:52 +01:00
QSslSocket * socket = qobject_cast < QSslSocket * > ( sender ( ) ) ;
if ( ! socket )
return ;
2016-07-04 18:52:28 +01:00
2020-09-24 15:59:22 +01:00
bool fatal = false ;
2022-09-10 22:23:52 +01:00
for ( const QSslError & error : errors ) {
2020-09-24 15:59:22 +01:00
if ( error . error ( ) ! = QSslError : : SelfSignedCertificate ) {
qCCritical ( KDECONNECT_CORE ) < < " Disconnecting due to fatal SSL Error: " < < error ;
fatal = true ;
} else {
qCDebug ( KDECONNECT_CORE ) < < " Ignoring self-signed cert error " ;
}
2015-07-07 19:52:10 +01:00
}
2020-09-24 15:59:22 +01:00
if ( fatal ) {
socket - > disconnectFromHost ( ) ;
delete m_receivedIdentityPackets . take ( socket ) . np ;
}
2015-07-05 14:23:53 +01:00
}
2022-09-10 22:23:52 +01:00
// 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
// identity.
2015-07-09 23:27:27 +01:00
void LanLinkProvider : : newConnection ( )
2013-08-07 10:29:56 +01:00
{
2018-10-23 08:30:48 +01:00
qCDebug ( KDECONNECT_CORE ) < < " LanLinkProvider newConnection " ;
2013-08-07 10:29:56 +01:00
2017-09-03 20:39:44 +01:00
while ( m_server - > hasPendingConnections ( ) ) {
2022-09-10 22:23:52 +01:00
QSslSocket * socket = m_server - > nextPendingConnection ( ) ;
2015-07-09 23:27:27 +01:00
configureSocket ( socket ) ;
2022-09-10 22:23:52 +01:00
// This socket is still managed by us (and child of the QTcpServer), if
// it disconnects before we manage to pass it to a LanDeviceLink, it's
// our responsibility to delete it. We do so with this connection.
connect ( socket , & QAbstractSocket : : disconnected , socket , & QObject : : deleteLater ) ;
connect ( socket , & QIODevice : : readyRead , this , & LanLinkProvider : : dataReceived ) ;
QTimer * timer = new QTimer ( socket ) ;
2020-09-16 01:44:38 +01:00
timer - > setSingleShot ( true ) ;
timer - > setInterval ( 1000 ) ;
2022-09-10 22:23:52 +01:00
connect ( socket , & QSslSocket : : encrypted , timer , & QObject : : deleteLater ) ;
2020-09-16 01:44:38 +01:00
connect ( timer , & QTimer : : timeout , socket , [ socket ] {
qCWarning ( KDECONNECT_CORE ) < < " LanLinkProvider/newConnection: Host timed out without sending any identity. " < < socket - > peerAddress ( ) ;
socket - > disconnectFromHost ( ) ;
} ) ;
timer - > start ( ) ;
2015-07-09 23:27:27 +01:00
}
2013-08-07 10:29:56 +01:00
}
2023-07-10 16:58:56 +01:00
// I'm the new device and this is the TCP response to my UDP identity packet
2013-08-28 22:47:39 +01:00
void LanLinkProvider : : dataReceived ( )
2013-08-07 10:29:56 +01:00
{
2022-09-10 22:23:52 +01:00
QSslSocket * socket = qobject_cast < QSslSocket * > ( sender ( ) ) ;
// 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
// Tested between my systems and I get around 2000 per identity package.
2020-09-16 01:28:58 +01:00
if ( socket - > bytesAvailable ( ) > 8192 ) {
2022-09-10 22:23:52 +01:00
qCWarning ( KDECONNECT_CORE ) < < " LanLinkProvider/newConnection: Suspiciously long identity package received. Closing connection. " < < socket - > peerAddress ( )
< < socket - > bytesAvailable ( ) ;
2020-09-16 01:28:58 +01:00
socket - > disconnectFromHost ( ) ;
return ;
}
2023-07-10 16:58:56 +01:00
if ( ! socket - > canReadLine ( ) ) {
// This can happen if the packet is large enough to be split in two chunks
2019-12-09 22:14:19 +00:00
return ;
2023-07-10 16:58:56 +01:00
}
2013-08-07 10:29:56 +01:00
2014-04-14 20:45:41 +01:00
const QByteArray data = socket - > readLine ( ) ;
2013-08-07 10:29:56 +01:00
2018-10-23 08:30:48 +01:00
qCDebug ( KDECONNECT_CORE ) < < " LanLinkProvider received reply: " < < data ;
2013-08-07 10:29:56 +01:00
2023-06-27 12:10:59 +01:00
NetworkPacket * np = new NetworkPacket ( ) ;
2018-03-04 19:48:51 +00:00
bool success = NetworkPacket : : unserialize ( data , np ) ;
2015-07-13 15:25:22 +01:00
2019-12-09 22:14:19 +00:00
if ( ! success ) {
delete np ;
return ;
}
2016-06-02 11:17:07 +01:00
2018-03-04 19:48:51 +00:00
if ( np - > type ( ) ! = PACKET_TYPE_IDENTITY ) {
2016-06-02 11:17:07 +01:00
qCWarning ( KDECONNECT_CORE ) < < " LanLinkProvider/newConnection: Expected identity, received " < < np - > type ( ) ;
delete np ;
2014-04-14 20:45:41 +01:00
return ;
}
2013-08-07 10:29:56 +01:00
2020-09-24 16:16:02 +01:00
if ( m_receivedIdentityPackets . size ( ) > MAX_REMEMBERED_IDENTITY_PACKETS ) {
qCWarning ( KDECONNECT_CORE ) < < " Too many remembered identities, ignoring " < < np - > get < QString > ( QStringLiteral ( " deviceId " ) ) < < " received via TCP " ;
delete np ;
return ;
}
2019-05-04 14:10:27 +01:00
// Needed in "encrypted" if ssl is used, similar to "tcpSocketConnected"
2018-03-04 19:48:51 +00:00
m_receivedIdentityPackets [ socket ] . np = np ;
2015-07-14 13:04:04 +01:00
2022-09-10 22:23:52 +01:00
const QString & deviceId = np - > get < QString > ( QStringLiteral ( " deviceId " ) ) ;
// qCDebug(KDECONNECT_CORE) << "Handshaking done (i'm the new device)";
2013-08-16 05:22:37 +01:00
2022-09-10 22:23:52 +01:00
// This socket will now be owned by the LanDeviceLink or we don't want more data to be received, forget about it
2016-11-26 14:12:38 +00:00
disconnect ( socket , & QIODevice : : readyRead , this , & LanLinkProvider : : dataReceived ) ;
2013-08-16 05:22:37 +01:00
2023-06-27 12:10:59 +01:00
bool isDeviceTrusted = KdeConnectConfig : : instance ( ) . trustedDevices ( ) . contains ( deviceId ) ;
configureSslSocket ( socket , deviceId , isDeviceTrusted ) ;
2013-08-07 10:29:56 +01:00
2023-06-27 12:10:59 +01:00
qCDebug ( KDECONNECT_CORE ) < < " Starting client ssl (but I'm the server TCP socket) " ;
2016-07-04 18:52:28 +01:00
2023-06-27 12:10:59 +01:00
connect ( socket , & QSslSocket : : encrypted , this , & LanLinkProvider : : encrypted ) ;
2016-06-22 13:25:12 +01:00
2023-06-27 12:10:59 +01:00
if ( isDeviceTrusted ) {
connect ( socket , QOverload < const QList < QSslError > & > : : of ( & QSslSocket : : sslErrors ) , this , & LanLinkProvider : : sslErrors ) ;
2015-07-05 14:23:53 +01:00
}
2023-06-27 12:10:59 +01:00
socket - > startClientEncryption ( ) ;
2013-08-07 10:29:56 +01:00
}
2023-06-27 12:10:59 +01:00
void LanLinkProvider : : onLinkDestroyed ( const QString & deviceId , DeviceLink * oldPtr )
2013-08-07 10:29:56 +01:00
{
2023-06-27 12:10:59 +01:00
qCDebug ( KDECONNECT_CORE ) < < " LanLinkProvider deviceLinkDestroyed " < < deviceId ;
DeviceLink * link = m_links . take ( deviceId ) ;
Q_ASSERT ( link = = oldPtr ) ;
2013-08-07 10:29:56 +01:00
}
2022-09-10 22:23:52 +01:00
void LanLinkProvider : : configureSslSocket ( QSslSocket * socket , const QString & deviceId , bool isDeviceTrusted )
2013-08-07 10:29:56 +01:00
{
2015-07-05 14:23:53 +01:00
// Configure for ssl
2016-04-30 16:09:34 +01:00
QSslConfiguration sslConfig ;
2020-08-07 09:59:17 +01:00
sslConfig . setLocalCertificate ( KdeConnectConfig : : instance ( ) . certificate ( ) ) ;
2016-04-30 16:09:34 +01:00
2020-08-07 09:59:17 +01:00
QFile privateKeyFile ( KdeConnectConfig : : instance ( ) . privateKeyPath ( ) ) ;
QSslKey privateKey ;
if ( privateKeyFile . open ( QIODevice : : ReadOnly ) ) {
privateKey = QSslKey ( privateKeyFile . readAll ( ) , QSsl : : Rsa ) ;
}
privateKeyFile . close ( ) ;
sslConfig . setPrivateKey ( privateKey ) ;
2016-06-22 13:25:12 +01:00
if ( isDeviceTrusted ) {
2023-06-27 12:10:59 +01:00
QSslCertificate certificate = KdeConnectConfig : : instance ( ) . getTrustedDeviceCertificate ( deviceId ) ;
sslConfig . setCaCertificates ( { certificate } ) ;
2020-08-07 09:59:17 +01:00
sslConfig . setPeerVerifyMode ( QSslSocket : : VerifyPeer ) ;
2016-06-22 13:25:12 +01:00
} else {
2020-08-07 09:59:17 +01:00
sslConfig . setPeerVerifyMode ( QSslSocket : : QueryPeer ) ;
2016-06-22 13:25:12 +01:00
}
2020-08-07 09:59:17 +01:00
socket - > setSslConfiguration ( sslConfig ) ;
socket - > setPeerVerifyName ( deviceId ) ;
2022-09-10 22:23:52 +01:00
// Usually SSL errors are only bad for trusted devices. Uncomment this section to log errors in any case, for debugging.
// QObject::connect(socket, static_cast<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors), [](const QList<QSslError>& errors)
2016-07-12 11:49:21 +01:00
//{
2022-09-10 22:23:52 +01:00
// Q_FOREACH (const QSslError& error, errors) {
// qCDebug(KDECONNECT_CORE) << "SSL Error:" << error.errorString();
// }
// });
2016-06-22 13:25:12 +01:00
}
2022-09-10 22:23:52 +01:00
void LanLinkProvider : : configureSocket ( QSslSocket * socket )
{
2017-03-06 21:01:46 +00:00
socket - > setProxy ( QNetworkProxy : : NoProxy ) ;
2016-06-09 01:36:02 +01:00
socket - > setSocketOption ( QAbstractSocket : : KeepAliveOption , QVariant ( 1 ) ) ;
2016-06-22 13:25:12 +01:00
2020-08-07 09:59:58 +01:00
# ifdef TCP_KEEPIDLE
// time to start sending keepalive packets (seconds)
int maxIdle = 10 ;
setsockopt ( socket - > socketDescriptor ( ) , IPPROTO_TCP , TCP_KEEPIDLE , & maxIdle , sizeof ( maxIdle ) ) ;
# endif
# ifdef TCP_KEEPINTVL
// interval between keepalive packets after the initial period (seconds)
int interval = 5 ;
setsockopt ( socket - > socketDescriptor ( ) , IPPROTO_TCP , TCP_KEEPINTVL , & interval , sizeof ( interval ) ) ;
# endif
# ifdef TCP_KEEPCNT
// number of missed keepalive packets before disconnecting
int count = 3 ;
setsockopt ( socket - > socketDescriptor ( ) , IPPROTO_TCP , TCP_KEEPCNT , & count , sizeof ( count ) ) ;
# endif
2023-03-04 13:06:55 +00:00
# if defined(Q_OS_WIN)
int maxIdle = 5 * 60 * 1000 ; // 5 minutes of idle before sending keep-alives
int interval = 5 * 1000 ; // 5 seconds interval between probes after 5 minute delay
DWORD nop ;
// see https://learn.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals
2023-07-16 15:20:34 +01:00
struct tcp_keepalive keepalive = { 1 /* true */ , maxIdle , interval } ;
int rv = WSAIoctl ( socket - > socketDescriptor ( ) , SIO_KEEPALIVE_VALS , & keepalive , sizeof ( keepalive ) , nullptr , 0 , & nop , nullptr , nullptr ) ;
2023-03-04 13:06:55 +00:00
if ( ! rv ) {
int error = WSAGetLastError ( ) ;
qCDebug ( KDECONNECT_CORE ) < < " Could not enable TCP Keep-Alive: " < < error ;
}
# endif
2013-08-07 10:29:56 +01:00
}
2015-07-05 14:23:53 +01:00
2023-06-27 12:10:59 +01:00
void LanLinkProvider : : addLink ( QSslSocket * socket , const DeviceInfo & deviceInfo )
2015-11-30 18:36:01 +00:00
{
2023-06-27 12:10:59 +01:00
QString certDeviceId = socket - > peerCertificate ( ) . subjectDisplayName ( ) ;
if ( deviceInfo . id ! = certDeviceId ) {
socket - > disconnectFromHost ( ) ;
qCWarning ( KDECONNECT_CORE ) < < " DeviceID in cert doesn't match deviceID in identity packet. " < < deviceInfo . id < < " vs " < < certDeviceId ;
return ;
}
2015-07-07 19:52:10 +01:00
// Socket disconnection will now be handled by LanDeviceLink
2016-11-26 14:12:38 +00:00
disconnect ( socket , & QAbstractSocket : : disconnected , socket , & QObject : : deleteLater ) ;
2015-07-07 19:52:10 +01:00
2022-09-10 22:23:52 +01:00
LanDeviceLink * deviceLink ;
// Do we have a link for this device already?
2023-06-27 12:10:59 +01:00
QMap < QString , LanDeviceLink * > : : iterator linkIterator = m_links . find ( deviceInfo . id ) ;
2017-09-03 20:39:44 +01:00
if ( linkIterator ! = m_links . end ( ) ) {
2015-12-11 01:11:48 +00:00
deviceLink = linkIterator . value ( ) ;
2023-06-27 12:10:59 +01:00
if ( deviceLink - > deviceInfo ( ) . certificate ! = deviceInfo . certificate ) {
qWarning ( ) < < " LanLink was asked to replace a socket but the certificate doesn't match, aborting " ;
return ;
}
// qCDebug(KDECONNECT_CORE) << "Reusing link to" << deviceId;
deviceLink - > reset ( socket ) ;
2015-12-11 01:11:48 +00:00
} else {
2023-06-27 12:10:59 +01:00
deviceLink = new LanDeviceLink ( deviceInfo , this , socket ) ;
2020-09-24 16:13:34 +01:00
// Socket disconnection will now be handled by LanDeviceLink
disconnect ( socket , & QAbstractSocket : : disconnected , socket , & QObject : : deleteLater ) ;
2023-06-27 12:10:59 +01:00
bool isDeviceTrusted = KdeConnectConfig : : instance ( ) . trustedDevices ( ) . contains ( deviceInfo . id ) ;
2020-09-24 16:13:34 +01:00
if ( ! isDeviceTrusted & & m_links . size ( ) > MAX_UNPAIRED_CONNECTIONS ) {
2023-06-27 12:10:59 +01:00
qCWarning ( KDECONNECT_CORE ) < < " Too many unpaired devices to remember them all. Ignoring " < < deviceInfo . id ;
2020-09-24 16:13:34 +01:00
socket - > disconnectFromHost ( ) ;
socket - > deleteLater ( ) ;
return ;
}
2023-06-27 12:10:59 +01:00
m_links [ deviceInfo . id ] = deviceLink ;
2015-07-05 14:23:53 +01:00
}
2023-06-27 12:10:59 +01:00
Q_EMIT onConnectionReceived ( deviceLink ) ;
2015-09-11 16:25:23 +01:00
}