20#include "private/qiodevice_p.h"
21#include "private/qringbuffer_p.h"
23#include <qnetworkinterface.h>
25#include <QtCore/qbasictimer.h>
26#include <QtCore/qpointer.h>
32using namespace Qt::StringLiterals;
33using namespace std::chrono_literals;
39#define MAX_DATA_DUMP 256
42#define Q_INIT_CHECK(returnValue) do {
47#define S5_VERSION_5 0x05
48#define S5_CONNECT 0x01
50#define S5_UDP_ASSOCIATE 0x03
52#define S5_DOMAINNAME 0x03
54#define S5_SUCCESS 0x00
55#define S5_R_ERROR_SOCKS_FAILURE 0x01
56#define S5_R_ERROR_CON_NOT_ALLOWED 0x02
57#define S5_R_ERROR_NET_UNREACH 0x03
58#define S5_R_ERROR_HOST_UNREACH 0x04
59#define S5_R_ERROR_CONN_REFUSED 0x05
60#define S5_R_ERROR_TTL 0x06
61#define S5_R_ERROR_CMD_NOT_SUPPORTED 0x07
62#define S5_R_ERROR_ADD_TYPE_NOT_SUPORTED 0x08
64#define S5_AUTHMETHOD_NONE 0x00
65#define S5_AUTHMETHOD_PASSWORD 0x02
66#define S5_AUTHMETHOD_NOTACCEPTABLE 0xFF
68#define S5_PASSWORDAUTH_VERSION 0x01
70#ifdef QSOCKS5SOCKETLAYER_DEBUG
71# define QSOCKS5_Q_DEBUG qDebug() << this
72# define QSOCKS5_D_DEBUG qDebug() << q_ptr
73# define QSOCKS5_DEBUG qDebug() << "[QSocks5]"
74static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State s)
77 case QSocks5SocketEnginePrivate::Uninitialized:
return "Uninitialized"_L1;
78 case QSocks5SocketEnginePrivate::ConnectError:
return "ConnectError"_L1;
79 case QSocks5SocketEnginePrivate::AuthenticationMethodsSent:
return "AuthenticationMethodsSent"_L1;
80 case QSocks5SocketEnginePrivate::Authenticating:
return "Authenticating"_L1;
81 case QSocks5SocketEnginePrivate::AuthenticatingError:
return "AuthenticatingError"_L1;
82 case QSocks5SocketEnginePrivate::RequestMethodSent:
return "RequestMethodSent"_L1;
83 case QSocks5SocketEnginePrivate::RequestError:
return "RequestError"_L1;
84 case QSocks5SocketEnginePrivate::Connected:
return "Connected"_L1;
85 case QSocks5SocketEnginePrivate::UdpAssociateSuccess:
return "UdpAssociateSuccess"_L1;
86 case QSocks5SocketEnginePrivate::BindSuccess:
return "BindSuccess"_L1;
87 case QSocks5SocketEnginePrivate::ControlSocketError:
return "ControlSocketError"_L1;
88 case QSocks5SocketEnginePrivate::SocksError:
return "SocksError"_L1;
89 case QSocks5SocketEnginePrivate::HostNameLookupError:
return "HostNameLookupError"_L1;
92 return "unknown state"_L1;
95static QString dump(
const QByteArray &buf)
98 for (
int i = 0; i < qMin<
int>(MAX_DATA_DUMP, buf.size()); ++i) {
100 uint val = (
unsigned char)buf.at(i);
102 data += QString::number(val);
104 if (buf.size() > MAX_DATA_DUMP)
107 return QString::fromLatin1(
"size: %1 data: { %2 }").arg(buf.size()).arg(data);
111# define QSOCKS5_DEBUG if (0
) qDebug()
112# define QSOCKS5_Q_DEBUG if (0
) qDebug()
113# define QSOCKS5_D_DEBUG if (0
) qDebug()
116static inline QString dump(
const QByteArray &) {
return QString(); }
120
121
122
125 QSOCKS5_DEBUG <<
"setting [" << address <<
':' << port <<
']';
135 if (address.protocol() == QAbstractSocket::IPv4Protocol) {
136 data.ipv4 = qToBigEndian<quint32>(address.toIPv4Address());
138 pBuf->append(QByteArray::fromRawData(&data.ptr,
sizeof data.ipv4));
139 }
else if (address.protocol() == QAbstractSocket::IPv6Protocol) {
140 data.ipv6 = address.toIPv6Address();
142 pBuf->append(QByteArray::fromRawData(&data.ptr,
sizeof data.ipv6));
148 data.port = qToBigEndian<quint16>(port);
149 pBuf->append(QByteArray::fromRawData(&data.ptr,
sizeof data.port));
154
155
158 QSOCKS5_DEBUG <<
"setting [" << hostname <<
':' << port <<
']';
160 QByteArray encodedHostName = QUrl::toAce(hostname);
161 QByteArray &buf = *pBuf;
163 if (encodedHostName.size() > 255)
167 buf.append(uchar(encodedHostName.size()));
168 buf.append(encodedHostName);
175 data.port = qToBigEndian<quint16>(port);
176 buf.append(QByteArray::fromRawData(&data.ptr,
sizeof data.port));
183
184
185
186
191 const unsigned char *pBuf =
reinterpret_cast<
const unsigned char*>(buf.constData());
192 QHostAddress address;
195 if (buf.size() - pos < 1) {
201 if (buf.size() - pos < 4) {
205 address.setAddress(qFromBigEndian<quint32>(&pBuf[pos]));
210 if (buf.size() - pos < 16) {
215 for (
int i = 0; i < 16; ++i)
217 address.setAddress(add);
221 if (buf.size() - pos < 1) {
225 const int hostNameLen = uchar(pBuf[pos]);
227 if (buf.size() - pos < hostNameLen) {
243 if (buf.size() - pos < 2) {
247 port = qFromBigEndian<quint16>(&pBuf[pos]);
288#ifndef QT_NO_UDPSOCKET
320QSocks5BindStore::QSocks5BindStore()
322 QCoreApplication *app = QCoreApplication::instance();
323 if (app && app->thread() != thread())
324 moveToThread(app->thread());
334 if (store.contains(socketDescriptor)) {
337 bindData->timeStamp.start();
338 store.insert(socketDescriptor, bindData);
341 if (!sweepTimer.isActive())
342 sweepTimer.start(1min,
this);
348 return store.contains(socketDescriptor);
354 const auto it = store.constFind(socketDescriptor);
355 if (it == store.cend())
360 if (bindData->controlSocket->thread() != QThread::currentThread()) {
361 qWarning(
"Cannot access socks5 bind data from different thread");
376 if (event->id() == sweepTimer.id()) {
378 for (
auto it = store.begin(), end = store.end(); it != end;) {
379 if (it.value()->timeStamp.hasExpired(350000)) {
381 it = store.erase(it);
430 return unSeal(sealedSocket->readAll(), buf);
435 this->userName = userName;
436 this->password = password;
447 QByteArray uname = userName.toLatin1();
448 QByteArray passwd = password.toLatin1();
449 QByteArray dataBuf(3 + uname.size() + passwd.size(), 0);
450 char *buf = dataBuf.data();
453 buf[pos++] = uname.size();
454 memcpy(&buf[pos], uname.data(), uname.size());
456 buf[pos++] = passwd.size();
457 memcpy(&buf[pos], passwd.data(), passwd.size());
458 return socket->write(dataBuf) == dataBuf.size();
465 if (socket->bytesAvailable() < 2)
468 QByteArray buf = socket->read(2);
481 return "Socks5 user name or password incorrect"_L1;
491 , socketDescriptor(-1)
494#ifndef QT_NO_UDPSOCKET
513 Q_Q(QSocks5SocketEngine);
519#ifndef QT_NO_UDPSOCKET
523 udpData->udpSocket =
new QUdpSocket(q);
524 udpData->udpSocket->setProxy(QNetworkProxy::NoProxy);
525 QObject::connect(udpData->udpSocket, SIGNAL(readyRead()),
526 q, SLOT(_q_udpSocketReadNotification()),
527 Qt::DirectConnection);
534 data->controlSocket =
new QTcpSocket(q);
536 QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()),
537 Qt::DirectConnection);
538 QObject::connect(data->controlSocket, SIGNAL(readyRead()), q, SLOT(_q_controlSocketReadNotification()),
539 Qt::DirectConnection);
540 QObject::connect(data->controlSocket, SIGNAL(bytesWritten(qint64)), q, SLOT(_q_controlSocketBytesWritten()),
541 Qt::DirectConnection);
542 QObject::connect(data->controlSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
543 q, SLOT(_q_controlSocketErrorOccurred(QAbstractSocket::SocketError)),
544 Qt::DirectConnection);
545 QObject::connect(data->controlSocket, SIGNAL(disconnected()), q, SLOT(_q_controlSocketDisconnected()),
546 Qt::DirectConnection);
547 QObject::connect(data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
548 q, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
549 Qt::DirectConnection);
551 if (!proxyInfo.user().isEmpty() || !proxyInfo.password().isEmpty()) {
552 QSOCKS5_D_DEBUG <<
"using username/password authentication; user =" << proxyInfo.user();
553 data->authenticator =
new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
562 Q_Q(QSocks5SocketEngine);
579 switch (controlSocketError) {
580 case QAbstractSocket::ConnectionRefusedError:
581 q->setError(QAbstractSocket::ProxyConnectionRefusedError,
582 QSocks5SocketEngine::tr(
"Connection to proxy refused"));
584 case QAbstractSocket::RemoteHostClosedError:
585 q->setError(QAbstractSocket::ProxyConnectionClosedError,
586 QSocks5SocketEngine::tr(
"Connection to proxy closed prematurely"));
588 case QAbstractSocket::HostNotFoundError:
589 q->setError(QAbstractSocket::ProxyNotFoundError,
590 QSocks5SocketEngine::tr(
"Proxy host not found"));
592 case QAbstractSocket::SocketTimeoutError:
594 q->setError(QAbstractSocket::ProxyConnectionTimeoutError,
595 QSocks5SocketEngine::tr(
"Connection to proxy timed out"));
600 q->setError(controlSocketError, data->controlSocket->errorString());
604 q->setError(controlSocketError, data->controlSocket->errorString());
609 case AuthenticatingError:
610 q->setError(QAbstractSocket::ProxyAuthenticationRequiredError,
611 extraMessage.isEmpty() ?
612 QSocks5SocketEngine::tr(
"Proxy authentication failed") :
613 QSocks5SocketEngine::tr(
"Proxy authentication failed: %1").arg(extraMessage));
621 q->setError(QAbstractSocket::ProxyProtocolError,
622 QSocks5SocketEngine::tr(
"SOCKS version 5 protocol error"));
625 case HostNameLookupError:
626 q->setError(QAbstractSocket::HostNotFoundError,
627 QAbstractSocket::tr(
"Host not found"));
631 q->setState(QAbstractSocket::UnconnectedState);
637 Q_Q(QSocks5SocketEngine);
638 switch (socks5error) {
640 q->setError(QAbstractSocket::NetworkError,
641 QSocks5SocketEngine::tr(
"General SOCKSv5 server failure"));
643 case ConnectionNotAllowed:
644 q->setError(QAbstractSocket::SocketAccessError,
645 QSocks5SocketEngine::tr(
"Connection not allowed by SOCKSv5 server"));
647 case NetworkUnreachable:
648 q->setError(QAbstractSocket::NetworkError,
649 QAbstractSocket::tr(
"Network unreachable"));
651 case HostUnreachable:
652 q->setError(QAbstractSocket::HostNotFoundError,
653 QAbstractSocket::tr(
"Host not found"));
655 case ConnectionRefused:
656 q->setError(QAbstractSocket::ConnectionRefusedError,
657 QAbstractSocket::tr(
"Connection refused"));
660 q->setError(QAbstractSocket::NetworkError,
661 QSocks5SocketEngine::tr(
"TTL expired"));
663 case CommandNotSupported:
664 q->setError(QAbstractSocket::UnsupportedSocketOperationError,
665 QSocks5SocketEngine::tr(
"SOCKSv5 command not supported"));
667 case AddressTypeNotSupported:
668 q->setError(QAbstractSocket::UnsupportedSocketOperationError,
669 QSocks5SocketEngine::tr(
"Address type not supported"));
673 q->setError(QAbstractSocket::UnknownSocketError,
674 QSocks5SocketEngine::tr(
"Unknown SOCKSv5 proxy error code 0x%1").arg(
int(socks5error), 16));
683 Q_Q(QSocks5SocketEngine);
687 q->proxyAuthenticationRequired(proxyInfo, &auth);
689 if (!auth.user().isEmpty() || !auth.password().isEmpty()) {
691 QSOCKS5_DEBUG <<
"authentication failure: retrying connection";
695 proxyInfo.setUser(auth.user());
696 proxyInfo.setPassword(auth.password());
697 data->authenticator =
new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
728 bool authComplete =
false;
737 socketError = QAbstractSocket::SocketAccessError;
750 bool authComplete =
false;
761 QHostAddress address;
766 address = peerAddress;
770 address = localAddress;
773#ifndef QT_NO_UDPSOCKET
775 address = localAddress;
785 if (peerName.isEmpty() && !qt_socks5_set_host_address_and_port(address, port, &buf)) {
786 QSOCKS5_DEBUG <<
"error setting address" << address <<
" : " << port;
789 }
else if (!peerName.isEmpty() && !qt_socks5_set_host_name_and_port(peerName, port, &buf)) {
790 QSOCKS5_DEBUG <<
"error setting peer name" << peerName <<
" : " << port;
795 QByteArray sealedBuf;
806 Q_Q(QSocks5SocketEngine);
816 inBuf.prepend(receivedHeaderFragment);
817 receivedHeaderFragment.clear();
819 if (inBuf.size() < 3) {
820 QSOCKS5_DEBUG <<
"need more data for request reply header .. put this data somewhere";
821 receivedHeaderFragment = inBuf;
825 QHostAddress address;
828 if (inBuf.at(0) !=
S5_VERSION_5 || inBuf.at(2) != 0x00) {
834 if ((socks5Error == SocksFailure || socks5Error == ConnectionNotAllowed)
835 && !peerName.isEmpty()) {
844 int err = qt_socks5_get_host_address_and_port(inBuf, &address, &port, &pos);
848 }
else if (err == 0) {
850 receivedHeaderFragment = inBuf;
853 inBuf.remove(0, pos);
854 for (
int i = inBuf.size() - 1; i >= 0 ; --i)
861 localAddress = address;
865 inboundStreamCount = outboundStreamCount = 1;
868 q->setState(QAbstractSocket::ConnectedState);
872 q->setState(QAbstractSocket::ListeningState);
891 Q_Q(QSocks5SocketEngine);
895 QPointer<QSocks5SocketEngine> qq = q;
896 q->readNotification();
900 if (data && data->controlSocket->state() == QAbstractSocket::UnconnectedState
901 && data->controlSocket->error() == QAbstractSocket::RemoteHostClosedError) {
910 Q_Q(QSocks5SocketEngine);
915 QMetaObject::invokeMethod(q,
"_q_emitPendingReadNotification", Qt::QueuedConnection);
922 Q_Q(QSocks5SocketEngine);
925 q->writeNotification();
931 Q_Q(QSocks5SocketEngine);
936 QMetaObject::invokeMethod(q,
"_q_emitPendingWriteNotification", Qt::QueuedConnection);
943 Q_Q(QSocks5SocketEngine);
945 q->connectionNotification();
950 Q_Q(QSocks5SocketEngine);
953 QMetaObject::invokeMethod(q,
"_q_emitPendingConnectionNotification", Qt::QueuedConnection);
956QSocks5SocketEngine::QSocks5SocketEngine(QObject *parent)
957:QAbstractSocketEngine(*
new QSocks5SocketEnginePrivate(), parent)
961QSocks5SocketEngine::~QSocks5SocketEngine()
963 Q_D(QSocks5SocketEngine);
966 delete d->data->authenticator;
967 delete d->data->controlSocket;
970 delete d->connectData;
971#ifndef QT_NO_UDPSOCKET
973 delete d->udpData->udpSocket;
983 Q_CONSTINIT
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
984 return 1 + counter.fetchAndAddRelaxed(1);
987bool QSocks5SocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
989 Q_D(QSocks5SocketEngine);
991 d->socketDescriptor = nextDescriptor();
993 d->socketType = type;
994 d->socketProtocol = protocol;
999bool QSocks5SocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState)
1001 Q_D(QSocks5SocketEngine);
1007 if (socketState != QAbstractSocket::ConnectedState) {
1012 QSocks5BindData *bindData = socks5BindStore()->retrieve(socketDescriptor);
1015 d->socketState = QAbstractSocket::ConnectedState;
1016 d->socketType = QAbstractSocket::TcpSocket;
1017 d->connectData =
new QSocks5ConnectData;
1018 d->data = d->connectData;
1019 d->mode = QSocks5SocketEnginePrivate::ConnectMode;
1020 d->data->controlSocket = bindData->controlSocket;
1021 bindData->controlSocket =
nullptr;
1022 d->data->controlSocket->setParent(
this);
1023 d->socketProtocol = d->data->controlSocket->localAddress().protocol();
1024 d->data->authenticator = bindData->authenticator;
1025 bindData->authenticator =
nullptr;
1026 d->localPort = bindData->localPort;
1027 d->localAddress = bindData->localAddress;
1028 d->peerPort = bindData->peerPort;
1029 d->peerAddress = bindData->peerAddress;
1030 d->inboundStreamCount = d->outboundStreamCount = 1;
1033 QObject::connect(d->data->controlSocket, SIGNAL(connected()),
this, SLOT(_q_controlSocketConnected()),
1034 Qt::DirectConnection);
1035 QObject::connect(d->data->controlSocket, SIGNAL(readyRead()),
this, SLOT(_q_controlSocketReadNotification()),
1036 Qt::DirectConnection);
1037 QObject::connect(d->data->controlSocket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_controlSocketBytesWritten()),
1038 Qt::DirectConnection);
1039 QObject::connect(d->data->controlSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
this, SLOT(_q_controlSocketErrorOccurred(QAbstractSocket::SocketError)),
1040 Qt::DirectConnection);
1041 QObject::connect(d->data->controlSocket, SIGNAL(disconnected()),
this, SLOT(_q_controlSocketDisconnected()),
1042 Qt::DirectConnection);
1043 QObject::connect(d->data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
1044 this, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
1045 Qt::DirectConnection);
1047 d->socks5State = QSocks5SocketEnginePrivate::Connected;
1049 if (d->data->controlSocket->bytesAvailable() != 0)
1050 d->_q_controlSocketReadNotification();
1056void QSocks5SocketEngine::setProxy(
const QNetworkProxy &networkProxy)
1058 Q_D(QSocks5SocketEngine);
1059 d->proxyInfo = networkProxy;
1062qintptr QSocks5SocketEngine::socketDescriptor()
const
1064 Q_D(
const QSocks5SocketEngine);
1065 return d->socketDescriptor;
1068bool QSocks5SocketEngine::isValid()
const
1070 Q_D(
const QSocks5SocketEngine);
1071 return d->socketType != QAbstractSocket::UnknownSocketType
1072 && d->socks5State != QSocks5SocketEnginePrivate::SocksError
1073 && (d->socketError == QAbstractSocket::UnknownSocketError
1074 || d->socketError == QAbstractSocket::SocketTimeoutError
1075 || d->socketError == QAbstractSocket::UnfinishedSocketOperationError);
1078bool QSocks5SocketEngine::connectInternal()
1080 Q_D(QSocks5SocketEngine);
1083 if (socketType() == QAbstractSocket::TcpSocket) {
1084 d->initialize(QSocks5SocketEnginePrivate::ConnectMode);
1085#ifndef QT_NO_UDPSOCKET
1086 }
else if (socketType() == QAbstractSocket::UdpSocket) {
1087 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1089 if (!bind(QHostAddress(
"0.0.0.0"_L1), 0))
1092 setState(QAbstractSocket::ConnectedState);
1096 qFatal(
"QSocks5SocketEngine::connectToHost: in QTcpServer mode");
1101 if (d->socketState != QAbstractSocket::ConnectingState) {
1102 if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized
1104 || d->socks5State == QSocks5SocketEnginePrivate::AuthenticatingError) {
1105 setState(QAbstractSocket::ConnectingState);
1107 d->data->controlSocket->setReadBufferSize(65536);
1110 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1116bool QSocks5SocketEngine::connectToHost(
const QHostAddress &address, quint16 port)
1118 Q_D(QSocks5SocketEngine);
1121 setPeerAddress(address);
1123 d->peerName.clear();
1125 return connectInternal();
1128bool QSocks5SocketEngine::connectToHostByName(
const QString &hostname, quint16 port)
1130 Q_D(QSocks5SocketEngine);
1132 setPeerAddress(QHostAddress());
1134 d->peerName = hostname;
1136 return connectInternal();
1142 QByteArray buf(3, 0);
1152 QSOCKS5_D_DEBUG <<
"_q_controlSocketReadNotification socks5state" << s5StateToString(socks5State)
1153 <<
"bytes available" << data->controlSocket->bytesAvailable();
1156 QSOCKS5_D_DEBUG <<
"########## bogus read why do we get these ... on windows only";
1193 qWarning(
"QSocks5SocketEnginePrivate::_q_controlSocketReadNotification: "
1194 "Unexpectedly received data while in state=%d and mode=%d",
1218 if (error == QAbstractSocket::SocketTimeoutError)
1221 if (error == QAbstractSocket::RemoteHostClosedError
1222 && socks5State == Connected) {
1255#ifndef QT_NO_UDPSOCKET
1261 if (!
udpData->udpSocket->hasPendingDatagrams()) {
1266 while (
udpData->udpSocket->hasPendingDatagrams()) {
1267 QByteArray sealedBuf(
udpData->udpSocket->pendingDatagramSize(), 0);
1269 udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size());
1277 const char *buf = inBuf.constData();
1278 if (inBuf.size() < 4) {
1283 if (buf[pos++] != 0 || buf[pos++] != 0) {
1287 if (buf[pos++] != 0) {
1291 if (qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos) != 1) {
1295 datagram.data = QByteArray(&buf[pos], inBuf.size() - pos);
1296 udpData->pendingDatagrams.enqueue(datagram);
1302bool QSocks5SocketEngine::bind(
const QHostAddress &addr, quint16 port)
1304 Q_D(QSocks5SocketEngine);
1308 QHostAddress address;
1309 if (addr.protocol() == QAbstractSocket::AnyIPProtocol)
1310 address = QHostAddress::AnyIPv4;
1315 if (socketType() == QAbstractSocket::TcpSocket) {
1316 d->initialize(QSocks5SocketEnginePrivate::BindMode);
1317#ifndef QT_NO_UDPSOCKET
1318 }
else if (socketType() == QAbstractSocket::UdpSocket) {
1319 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1327#ifndef QT_NO_UDPSOCKET
1328 if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1329 if (!d->udpData->udpSocket->bind(address, port)) {
1331 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1334 d->localAddress = d->udpData->udpSocket->localAddress();
1335 d->localPort = d->udpData->udpSocket->localPort();
1338 if (d->mode == QSocks5SocketEnginePrivate::BindMode) {
1339 d->localAddress = address;
1340 d->localPort = port;
1346 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1347 if (!d->waitForConnected(QDeadlineTimer{Socks5BlockingBindTimeout},
nullptr) ||
1348 d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1350 QSOCKS5_Q_DEBUG <<
"waitForConnected to proxy server" << d->data->controlSocket->errorString();
1353 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
1354 setState(QAbstractSocket::BoundState);
1356#ifndef QT_NO_UDPSOCKET
1357 }
else if (d->socks5State == QSocks5SocketEnginePrivate::UdpAssociateSuccess) {
1358 setState(QAbstractSocket::BoundState);
1359 d->udpData->associateAddress = d->localAddress;
1360 d->localAddress = QHostAddress();
1361 d->udpData->associatePort = d->localPort;
1368 setError(QAbstractSocket::SocketTimeoutError,
1369 QLatin1StringView(QT_TRANSLATE_NOOP(
"QSocks5SocketEngine",
"Network operation timed out")));
1377bool QSocks5SocketEngine::listen(
int backlog)
1379 Q_D(QSocks5SocketEngine);
1385 if (d->socketState == QAbstractSocket::BoundState) {
1386 d->socketState = QAbstractSocket::ListeningState;
1389 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1390 d->emitReadNotification();
1397qintptr QSocks5SocketEngine::accept()
1399 Q_D(QSocks5SocketEngine);
1405 switch (d->socks5State) {
1406 case QSocks5SocketEnginePrivate::BindSuccess:
1407 QSOCKS5_Q_DEBUG <<
"BindSuccess adding" << d->socketDescriptor <<
"to the bind store";
1408 d->data->controlSocket->disconnect();
1409 d->data->controlSocket->setParent(
nullptr);
1410 d->bindData->localAddress = d->localAddress;
1411 d->bindData->localPort = d->localPort;
1412 sd = d->socketDescriptor;
1413 socks5BindStore()->add(sd, d->bindData);
1415 d->bindData =
nullptr;
1416 d->socketDescriptor = 0;
1419 d->socks5State = QSocks5SocketEnginePrivate::Uninitialized;
1420 d->socketState = QAbstractSocket::UnconnectedState;
1422 case QSocks5SocketEnginePrivate::ControlSocketError:
1423 setError(QAbstractSocket::ProxyProtocolError,
"Control socket error"_L1);
1426 setError(QAbstractSocket::ProxyProtocolError,
"SOCKS5 proxy error"_L1);
1432void QSocks5SocketEngine::close()
1435 Q_D(QSocks5SocketEngine);
1436 if (d->data && d->data->controlSocket) {
1437 if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
1438 QDeadlineTimer deadline(100ms);
1439 while (!d->data->controlSocket->bytesToWrite()) {
1440 if (!d->data->controlSocket->waitForBytesWritten(deadline.remainingTime()))
1444 d->data->controlSocket->close();
1446 d->inboundStreamCount = d->outboundStreamCount = 0;
1447#ifndef QT_NO_UDPSOCKET
1448 if (d->udpData && d->udpData->udpSocket)
1449 d->udpData->udpSocket->close();
1453qint64 QSocks5SocketEngine::bytesAvailable()
const
1455 Q_D(
const QSocks5SocketEngine);
1456 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1457 return d->connectData->readBuffer.size();
1458#ifndef QT_NO_UDPSOCKET
1459 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
1460 && !d->udpData->pendingDatagrams.isEmpty())
1461 return d->udpData->pendingDatagrams.constFirst().data.size();
1466qint64 QSocks5SocketEngine::read(
char *data, qint64 maxlen)
1468 Q_D(QSocks5SocketEngine);
1470 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1471 if (d->connectData->readBuffer.isEmpty()) {
1472 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1475 setError(QAbstractSocket::RemoteHostClosedError,
1476 "Remote host closed connection"_L1);
1477 setState(QAbstractSocket::UnconnectedState);
1483 const qint64 copy = d->connectData->readBuffer.read(data, maxlen);
1486#ifndef QT_NO_UDPSOCKET
1487 }
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1488 return readDatagram(data, maxlen);
1494qint64 QSocks5SocketEngine::write(
const char *data, qint64 len)
1496 Q_D(QSocks5SocketEngine);
1499 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1501 len = qMin<qint64>(len, MaxWriteBufferSize) - d->data->controlSocket->bytesToWrite();
1505 QByteArray buf = QByteArray::fromRawData(data, len);
1506 QByteArray sealedBuf;
1507 if (!d->data->authenticator->seal(buf, &sealedBuf)) {
1514 qint64 written = d->data->controlSocket->write(sealedBuf.constData(), sealedBuf.size());
1520 d->data->controlSocket->waitForBytesWritten(0);
1523#ifndef QT_NO_UDPSOCKET
1524 }
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1526 return writeDatagram(data, len, QIpPacketHeader(d->peerAddress, d->peerPort));
1533#ifndef QT_NO_UDPSOCKET
1534#ifndef QT_NO_NETWORKINTERFACE
1535bool QSocks5SocketEngine::joinMulticastGroup(
const QHostAddress &,
1536 const QNetworkInterface &)
1538 setError(QAbstractSocket::UnsupportedSocketOperationError,
1539 "Operation on socket is not supported"_L1);
1543bool QSocks5SocketEngine::leaveMulticastGroup(
const QHostAddress &,
1544 const QNetworkInterface &)
1546 setError(QAbstractSocket::UnsupportedSocketOperationError,
1547 "Operation on socket is not supported"_L1);
1552QNetworkInterface QSocks5SocketEngine::multicastInterface()
const
1554 return QNetworkInterface();
1557bool QSocks5SocketEngine::setMulticastInterface(
const QNetworkInterface &)
1559 setError(QAbstractSocket::UnsupportedSocketOperationError,
1560 "Operation on socket is not supported"_L1);
1565bool QSocks5SocketEngine::hasPendingDatagrams()
const
1567 Q_D(
const QSocks5SocketEngine);
1570 return !d->udpData->pendingDatagrams.isEmpty();
1573qint64 QSocks5SocketEngine::pendingDatagramSize()
const
1575 Q_D(
const QSocks5SocketEngine);
1577 if (!d->udpData->pendingDatagrams.isEmpty())
1578 return d->udpData->pendingDatagrams.head().data.size();
1583qint64 QSocks5SocketEngine::readDatagram(
char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
1585#ifndef QT_NO_UDPSOCKET
1586 Q_D(QSocks5SocketEngine);
1588 if (d->udpData->pendingDatagrams.isEmpty())
1591 QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
1592 int copyLen = qMin<
int>(maxlen, datagram.data.size());
1593 memcpy(data, datagram.data.constData(), copyLen);
1595 header->senderAddress = datagram.address;
1596 header->senderPort = datagram.port;
1607qint64 QSocks5SocketEngine::writeDatagram(
const char *data, qint64 len,
const QIpPacketHeader &header)
1609#ifndef QT_NO_UDPSOCKET
1610 Q_D(QSocks5SocketEngine);
1614 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1616 if (!bind(QHostAddress(
"0.0.0.0"_L1), 0)) {
1623 outBuf.reserve(270 + len);
1624 outBuf.append(3,
'\0');
1625 if (!qt_socks5_set_host_address_and_port(header.destinationAddress, header.destinationPort, &outBuf)) {
1626 QSOCKS5_DEBUG <<
"error setting address" << header.destinationAddress <<
" : "
1627 << header.destinationPort;
1631 outBuf += QByteArray(data, len);
1633 QByteArray sealedBuf;
1634 if (!d->data->authenticator->seal(outBuf, &sealedBuf)) {
1636 setError(QAbstractSocket::SocketAccessError, d->data->authenticator->errorString());
1639 if (d->udpData->udpSocket->writeDatagram(sealedBuf, d->udpData->associateAddress, d->udpData->associatePort) != sealedBuf.size()) {
1641 if (d->udpData->udpSocket->error() == QAbstractSocket::DatagramTooLargeError)
1642 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1656qint64 QSocks5SocketEngine::bytesToWrite()
const
1658 Q_D(
const QSocks5SocketEngine);
1659 if (d->data && d->data->controlSocket) {
1660 return d->data->controlSocket->bytesToWrite();
1666int QSocks5SocketEngine::option(SocketOption option)
const
1668 Q_D(
const QSocks5SocketEngine);
1669 if (d->data && d->data->controlSocket) {
1671 if (option == QAbstractSocketEngine::LowDelayOption)
1672 return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
1673 if (option == QAbstractSocketEngine::KeepAliveOption)
1674 return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
1679bool QSocks5SocketEngine::setOption(SocketOption option,
int value)
1681 Q_D(QSocks5SocketEngine);
1682 if (d->data && d->data->controlSocket) {
1684 if (option == QAbstractSocketEngine::LowDelayOption)
1685 d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
1686 if (option == QAbstractSocketEngine::KeepAliveOption)
1687 d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
1695 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1705 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1709 if (timedOut && data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1718bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline,
bool *timedOut)
1720 Q_D(QSocks5SocketEngine);
1721 QSOCKS5_DEBUG <<
"waitForRead" << deadline.remainingTimeAsDuration();
1723 d->readNotificationActivated =
false;
1726 if (!d->waitForConnected(deadline, timedOut))
1728 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1730 if (bytesAvailable() && d->readNotificationPending) {
1737 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
1738 d->mode == QSocks5SocketEnginePrivate::BindMode) {
1739 while (!d->readNotificationActivated) {
1740 if (!d->data->controlSocket->waitForReadyRead(deadline.remainingTime())) {
1741 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1744 setError(d->data->controlSocket->error(), d->data->controlSocket->errorString());
1745 if (timedOut && d->data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1750#ifndef QT_NO_UDPSOCKET
1752 while (!d->readNotificationActivated) {
1753 if (!d->udpData->udpSocket->waitForReadyRead(deadline.remainingTime())) {
1754 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1755 if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
1764 bool ret = d->readNotificationActivated;
1765 d->readNotificationActivated =
false;
1772bool QSocks5SocketEngine::waitForWrite(QDeadlineTimer deadline,
bool *timedOut)
1774 Q_D(QSocks5SocketEngine);
1775 QSOCKS5_DEBUG <<
"waitForWrite" << deadline.remainingTimeAsDuration();
1778 if (!d->waitForConnected(deadline, timedOut))
1780 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1786 if (d->data->controlSocket->bytesToWrite())
1787 d->data->controlSocket->waitForBytesWritten(deadline.remainingTime());
1789 auto shouldWriteBytes = [&]() {
1790 return d->data->controlSocket->state() == QAbstractSocket::ConnectedState
1791 && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize;
1794 qint64 remainingTime = deadline.remainingTime();
1795 for (; remainingTime > 0 && shouldWriteBytes(); remainingTime = deadline.remainingTime())
1796 d->data->controlSocket->waitForBytesWritten(remainingTime);
1797 return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
1800bool QSocks5SocketEngine::waitForReadOrWrite(
bool *readyToRead,
bool *readyToWrite,
1801 bool checkRead,
bool checkWrite,
1802 QDeadlineTimer deadline,
bool *timedOut)
1804 Q_UNUSED(checkRead);
1806 bool canRead = waitForRead(deadline, timedOut);
1808 *readyToRead = canRead;
1812 bool canWrite = waitForWrite(deadline, timedOut);
1814 *readyToWrite = canWrite;
1818bool QSocks5SocketEngine::isReadNotificationEnabled()
const
1820 Q_D(
const QSocks5SocketEngine);
1821 return d->readNotificationEnabled;
1824void QSocks5SocketEngine::setReadNotificationEnabled(
bool enable)
1826 Q_D(QSocks5SocketEngine);
1830 bool emitSignal =
false;
1831 if (!d->readNotificationEnabled
1833 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1834 emitSignal = !d->connectData->readBuffer.isEmpty();
1835#ifndef QT_NO_UDPSOCKET
1836 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode)
1837 emitSignal = !d->udpData->pendingDatagrams.isEmpty();
1839 else if (d->mode == QSocks5SocketEnginePrivate::BindMode
1840 && d->socketState == QAbstractSocket::ListeningState
1841 && d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1845 d->readNotificationEnabled = enable;
1848 d->emitReadNotification();
1851bool QSocks5SocketEngine::isWriteNotificationEnabled()
const
1853 Q_D(
const QSocks5SocketEngine);
1854 return d->writeNotificationEnabled;
1857void QSocks5SocketEngine::setWriteNotificationEnabled(
bool enable)
1859 Q_D(QSocks5SocketEngine);
1860 d->writeNotificationEnabled = enable;
1861 if (enable && d->socketState == QAbstractSocket::ConnectedState) {
1862 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode && d->data->controlSocket->bytesToWrite())
1864 d->emitWriteNotification();
1865 d->writeNotificationActivated =
false;
1869bool QSocks5SocketEngine::isExceptionNotificationEnabled()
const
1871 Q_D(
const QSocks5SocketEngine);
1872 return d->exceptNotificationEnabled;
1875void QSocks5SocketEngine::setExceptionNotificationEnabled(
bool enable)
1877 Q_D(QSocks5SocketEngine);
1878 d->exceptNotificationEnabled = enable;
1881QAbstractSocketEngine *
1882QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,
1883 const QNetworkProxy &proxy, QObject *parent)
1885 Q_UNUSED(socketType);
1888 if (proxy.type() != QNetworkProxy::Socks5Proxy) {
1892 auto engine = std::make_unique<QSocks5SocketEngine>(parent);
1893 engine->setProxy(proxy);
1894 return engine.release();
1897QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(qintptr socketDescriptor, QObject *parent)
1900 if (socks5BindStore()->contains(socketDescriptor)) {
1902 return new QSocks5SocketEngine(parent);
1909#include "moc_qsocks5socketengine_p.cpp"
virtual bool beginAuthenticate(QTcpSocket *socket, bool *completed)
virtual bool continueAuthenticate(QTcpSocket *socket, bool *completed)
bool seal(const QByteArray &buf, QByteArray *sealedBuf)
virtual ~QSocks5Authenticator()
bool unSeal(QTcpSocket *sealedSocket, QByteArray *buf)
bool unSeal(const QByteArray &sealedBuf, QByteArray *buf)
void add(qintptr socketDescriptor, QSocks5BindData *bindData)
QHash< qintptr, QSocks5BindData * > store
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
QSocks5BindData * retrieve(qintptr socketDescriptor)
bool contains(qintptr socketDescriptor)
bool beginAuthenticate(QTcpSocket *socket, bool *completed) override
bool continueAuthenticate(QTcpSocket *socket, bool *completed) override
QSocks5PasswordAuthenticator(const QString &userName, const QString &password)
QString errorString() override
QSocks5UdpAssociateData * udpData
void parseRequestMethodReply()
void _q_controlSocketReadNotification()
void setErrorState(Socks5State state, const QString &extraMessage=QString())
void _q_controlSocketStateChanged(QAbstractSocket::SocketState)
bool readNotificationActivated
bool writeNotificationEnabled
void _q_controlSocketDisconnected()
void emitReadNotification()
void _q_emitPendingReadNotification()
@ AuthenticationMethodsSent
void _q_emitPendingWriteNotification()
~QSocks5SocketEnginePrivate()
QSocks5ConnectData * connectData
void parseAuthenticatingReply()
void _q_controlSocketErrorOccurred(QAbstractSocket::SocketError)
bool readNotificationEnabled
bool connectionNotificationPending
bool writeNotificationActivated
QSocks5BindData * bindData
bool readNotificationPending
void _q_controlSocketConnected()
bool writeNotificationPending
void emitConnectionNotification()
void setErrorState(Socks5State state, Socks5Error socks5error)
void emitWriteNotification()
void _q_emitPendingConnectionNotification()
void parseAuthenticationMethodReply()
void _q_controlSocketBytesWritten()
void _q_udpSocketReadNotification()
bool exceptNotificationEnabled
void initialize(Socks5Mode socks5Mode)
static int qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddress *pAddress, quint16 *pPort, int *pPos)
#define S5_AUTHMETHOD_NONE
static const int MaxWriteBufferSize
static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf)
static QString dump(const QByteArray &)
#define S5_PASSWORDAUTH_VERSION
#define Q_INIT_CHECK(returnValue)
#define S5_AUTHMETHOD_NOTACCEPTABLE
static int nextDescriptor()
static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State)
static constexpr auto Socks5BlockingBindTimeout
static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 port, QByteArray *pBuf)
QHostAddress localAddress
QSocks5Authenticator * authenticator
QTcpSocket * controlSocket
QQueue< QSocks5RevivedDatagram > pendingDatagrams
QHostAddress associateAddress