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 (QThread *thr = bindData->controlSocket->thread(); thr && !thr->isCurrentThread()) {
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();
909 if (data && data->controlSocket->state() == QAbstractSocket::UnconnectedState
910 && data->controlSocket->error() == QAbstractSocket::RemoteHostClosedError) {
919 Q_Q(QSocks5SocketEngine);
924 QMetaObject::invokeMethod(q,
"_q_emitPendingReadNotification", Qt::QueuedConnection);
931 Q_Q(QSocks5SocketEngine);
934 q->writeNotification();
940 Q_Q(QSocks5SocketEngine);
945 QMetaObject::invokeMethod(q,
"_q_emitPendingWriteNotification", Qt::QueuedConnection);
952 Q_Q(QSocks5SocketEngine);
954 q->connectionNotification();
959 Q_Q(QSocks5SocketEngine);
962 QMetaObject::invokeMethod(q,
"_q_emitPendingConnectionNotification", Qt::QueuedConnection);
965QSocks5SocketEngine::QSocks5SocketEngine(QObject *parent)
966:QAbstractSocketEngine(*
new QSocks5SocketEnginePrivate(), parent)
970QSocks5SocketEngine::~QSocks5SocketEngine()
972 Q_D(QSocks5SocketEngine);
975 delete d->data->authenticator;
976 delete d->data->controlSocket;
979 delete d->connectData;
980#ifndef QT_NO_UDPSOCKET
982 delete d->udpData->udpSocket;
992 Q_CONSTINIT
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
993 return 1 + counter.fetchAndAddRelaxed(1);
996bool QSocks5SocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
998 Q_D(QSocks5SocketEngine);
1000 d->socketDescriptor = nextDescriptor();
1002 d->socketType = type;
1003 d->socketProtocol = protocol;
1008bool QSocks5SocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState)
1010 Q_D(QSocks5SocketEngine);
1016 if (socketState != QAbstractSocket::ConnectedState) {
1021 QSocks5BindData *bindData = socks5BindStore()->retrieve(socketDescriptor);
1024 d->socketState = QAbstractSocket::ConnectedState;
1025 d->socketType = QAbstractSocket::TcpSocket;
1026 d->connectData =
new QSocks5ConnectData;
1027 d->data = d->connectData;
1028 d->mode = QSocks5SocketEnginePrivate::ConnectMode;
1029 d->data->controlSocket = bindData->controlSocket;
1030 bindData->controlSocket =
nullptr;
1031 d->data->controlSocket->setParent(
this);
1032 d->socketProtocol = d->data->controlSocket->localAddress().protocol();
1033 d->data->authenticator = bindData->authenticator;
1034 bindData->authenticator =
nullptr;
1035 d->localPort = bindData->localPort;
1036 d->localAddress = bindData->localAddress;
1037 d->peerPort = bindData->peerPort;
1038 d->peerAddress = bindData->peerAddress;
1039 d->inboundStreamCount = d->outboundStreamCount = 1;
1042 QObject::connect(d->data->controlSocket, SIGNAL(connected()),
this, SLOT(_q_controlSocketConnected()),
1043 Qt::DirectConnection);
1044 QObject::connect(d->data->controlSocket, SIGNAL(readyRead()),
this, SLOT(_q_controlSocketReadNotification()),
1045 Qt::DirectConnection);
1046 QObject::connect(d->data->controlSocket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_controlSocketBytesWritten()),
1047 Qt::DirectConnection);
1048 QObject::connect(d->data->controlSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
this, SLOT(_q_controlSocketErrorOccurred(QAbstractSocket::SocketError)),
1049 Qt::DirectConnection);
1050 QObject::connect(d->data->controlSocket, SIGNAL(disconnected()),
this, SLOT(_q_controlSocketDisconnected()),
1051 Qt::DirectConnection);
1052 QObject::connect(d->data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
1053 this, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
1054 Qt::DirectConnection);
1056 d->socks5State = QSocks5SocketEnginePrivate::Connected;
1058 if (d->data->controlSocket->bytesAvailable() != 0)
1059 d->_q_controlSocketReadNotification();
1065void QSocks5SocketEngine::setProxy(
const QNetworkProxy &networkProxy)
1067 Q_D(QSocks5SocketEngine);
1068 d->proxyInfo = networkProxy;
1071qintptr QSocks5SocketEngine::socketDescriptor()
const
1073 Q_D(
const QSocks5SocketEngine);
1074 return d->socketDescriptor;
1077bool QSocks5SocketEngine::isValid()
const
1079 Q_D(
const QSocks5SocketEngine);
1080 return d->socketType != QAbstractSocket::UnknownSocketType
1081 && d->socks5State != QSocks5SocketEnginePrivate::SocksError
1082 && (d->socketError == QAbstractSocket::UnknownSocketError
1083 || d->socketError == QAbstractSocket::SocketTimeoutError
1084 || d->socketError == QAbstractSocket::UnfinishedSocketOperationError);
1087bool QSocks5SocketEngine::connectInternal()
1089 Q_D(QSocks5SocketEngine);
1092 if (socketType() == QAbstractSocket::TcpSocket) {
1093 d->initialize(QSocks5SocketEnginePrivate::ConnectMode);
1094#ifndef QT_NO_UDPSOCKET
1095 }
else if (socketType() == QAbstractSocket::UdpSocket) {
1096 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1098 if (!bind(QHostAddress(
"0.0.0.0"_L1), 0))
1101 setState(QAbstractSocket::ConnectedState);
1105 qFatal(
"QSocks5SocketEngine::connectToHost: in QTcpServer mode");
1110 if (d->socketState != QAbstractSocket::ConnectingState) {
1111 if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized
1113 || d->socks5State == QSocks5SocketEnginePrivate::AuthenticatingError) {
1114 setState(QAbstractSocket::ConnectingState);
1116 d->data->controlSocket->setReadBufferSize(65536);
1119 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1125bool QSocks5SocketEngine::connectToHost(
const QHostAddress &address, quint16 port)
1127 Q_D(QSocks5SocketEngine);
1130 setPeerAddress(address);
1132 d->peerName.clear();
1134 return connectInternal();
1137bool QSocks5SocketEngine::connectToHostByName(
const QString &hostname, quint16 port)
1139 Q_D(QSocks5SocketEngine);
1141 setPeerAddress(QHostAddress());
1143 d->peerName = hostname;
1145 return connectInternal();
1151 QByteArray buf(3, 0);
1161 QSOCKS5_D_DEBUG <<
"_q_controlSocketReadNotification socks5state" << s5StateToString(socks5State)
1162 <<
"bytes available" << data->controlSocket->bytesAvailable();
1165 QSOCKS5_D_DEBUG <<
"########## bogus read why do we get these ... on windows only";
1202 qWarning(
"QSocks5SocketEnginePrivate::_q_controlSocketReadNotification: "
1203 "Unexpectedly received data while in state=%d and mode=%d",
1227 if (error == QAbstractSocket::SocketTimeoutError)
1230 if (error == QAbstractSocket::RemoteHostClosedError
1231 && socks5State == Connected) {
1263#ifndef QT_NO_UDPSOCKET
1269 if (!
udpData->udpSocket->hasPendingDatagrams()) {
1274 while (
udpData->udpSocket->hasPendingDatagrams()) {
1275 QByteArray sealedBuf(
udpData->udpSocket->pendingDatagramSize(), 0);
1277 udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size());
1285 const char *buf = inBuf.constData();
1286 if (inBuf.size() < 4) {
1291 if (buf[pos++] != 0 || buf[pos++] != 0) {
1295 if (buf[pos++] != 0) {
1299 if (qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos) != 1) {
1303 datagram.data = QByteArray(&buf[pos], inBuf.size() - pos);
1304 udpData->pendingDatagrams.enqueue(datagram);
1310bool QSocks5SocketEngine::bind(
const QHostAddress &addr, quint16 port)
1312 Q_D(QSocks5SocketEngine);
1316 QHostAddress address;
1317 if (addr.protocol() == QAbstractSocket::AnyIPProtocol)
1318 address = QHostAddress::AnyIPv4;
1323 if (socketType() == QAbstractSocket::TcpSocket) {
1324 d->initialize(QSocks5SocketEnginePrivate::BindMode);
1325#ifndef QT_NO_UDPSOCKET
1326 }
else if (socketType() == QAbstractSocket::UdpSocket) {
1327 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1335#ifndef QT_NO_UDPSOCKET
1336 if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1337 if (!d->udpData->udpSocket->bind(address, port)) {
1339 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1342 d->localAddress = d->udpData->udpSocket->localAddress();
1343 d->localPort = d->udpData->udpSocket->localPort();
1346 if (d->mode == QSocks5SocketEnginePrivate::BindMode) {
1347 d->localAddress = address;
1348 d->localPort = port;
1354 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1355 if (!d->waitForConnected(QDeadlineTimer{Socks5BlockingBindTimeout},
nullptr) ||
1356 d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1358 QSOCKS5_Q_DEBUG <<
"waitForConnected to proxy server" << d->data->controlSocket->errorString();
1361 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
1362 setState(QAbstractSocket::BoundState);
1364#ifndef QT_NO_UDPSOCKET
1365 }
else if (d->socks5State == QSocks5SocketEnginePrivate::UdpAssociateSuccess) {
1366 setState(QAbstractSocket::BoundState);
1367 d->udpData->associateAddress = d->localAddress;
1368 d->localAddress = QHostAddress();
1369 d->udpData->associatePort = d->localPort;
1376 setError(QAbstractSocket::SocketTimeoutError,
1377 QLatin1StringView(QT_TRANSLATE_NOOP(
"QSocks5SocketEngine",
"Network operation timed out")));
1385bool QSocks5SocketEngine::listen(
int backlog)
1387 Q_D(QSocks5SocketEngine);
1393 if (d->socketState == QAbstractSocket::BoundState) {
1394 d->socketState = QAbstractSocket::ListeningState;
1397 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1398 d->emitReadNotification();
1405qintptr QSocks5SocketEngine::accept()
1407 Q_D(QSocks5SocketEngine);
1413 switch (d->socks5State) {
1414 case QSocks5SocketEnginePrivate::BindSuccess:
1415 QSOCKS5_Q_DEBUG <<
"BindSuccess adding" << d->socketDescriptor <<
"to the bind store";
1416 d->data->controlSocket->disconnect();
1417 d->data->controlSocket->setParent(
nullptr);
1418 d->bindData->localAddress = d->localAddress;
1419 d->bindData->localPort = d->localPort;
1420 sd = d->socketDescriptor;
1421 socks5BindStore()->add(sd, d->bindData);
1423 d->bindData =
nullptr;
1424 d->socketDescriptor = 0;
1427 d->socks5State = QSocks5SocketEnginePrivate::Uninitialized;
1428 d->socketState = QAbstractSocket::UnconnectedState;
1430 case QSocks5SocketEnginePrivate::ControlSocketError:
1431 setError(QAbstractSocket::ProxyProtocolError,
"Control socket error"_L1);
1434 setError(QAbstractSocket::ProxyProtocolError,
"SOCKS5 proxy error"_L1);
1440void QSocks5SocketEngine::close()
1443 Q_D(QSocks5SocketEngine);
1444 if (d->data && d->data->controlSocket) {
1445 if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
1446 QDeadlineTimer deadline(100ms);
1447 while (!d->data->controlSocket->bytesToWrite()) {
1448 if (!d->data->controlSocket->waitForBytesWritten(deadline.remainingTime()))
1452 d->data->controlSocket->close();
1454 d->inboundStreamCount = d->outboundStreamCount = 0;
1455#ifndef QT_NO_UDPSOCKET
1456 if (d->udpData && d->udpData->udpSocket)
1457 d->udpData->udpSocket->close();
1461qint64 QSocks5SocketEngine::bytesAvailable()
const
1463 Q_D(
const QSocks5SocketEngine);
1464 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1465 return d->connectData->readBuffer.size();
1466#ifndef QT_NO_UDPSOCKET
1467 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
1468 && !d->udpData->pendingDatagrams.isEmpty())
1469 return d->udpData->pendingDatagrams.constFirst().data.size();
1474qint64 QSocks5SocketEngine::read(
char *data, qint64 maxlen)
1476 Q_D(QSocks5SocketEngine);
1478 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1479 if (d->connectData->readBuffer.isEmpty()) {
1480 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1483 setError(QAbstractSocket::RemoteHostClosedError,
1484 "Remote host closed connection"_L1);
1485 setState(QAbstractSocket::UnconnectedState);
1491 const qint64 copy = d->connectData->readBuffer.read(data, maxlen);
1494#ifndef QT_NO_UDPSOCKET
1495 }
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1496 return readDatagram(data, maxlen);
1502qint64 QSocks5SocketEngine::write(
const char *data, qint64 len)
1504 Q_D(QSocks5SocketEngine);
1507 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1509 len = qMin<qint64>(len, MaxWriteBufferSize) - d->data->controlSocket->bytesToWrite();
1513 QByteArray buf = QByteArray::fromRawData(data, len);
1514 QByteArray sealedBuf;
1515 if (!d->data->authenticator->seal(buf, &sealedBuf)) {
1522 qint64 written = d->data->controlSocket->write(sealedBuf.constData(), sealedBuf.size());
1528 d->data->controlSocket->waitForBytesWritten(0);
1531#ifndef QT_NO_UDPSOCKET
1532 }
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1534 return writeDatagram(data, len, QIpPacketHeader(d->peerAddress, d->peerPort));
1541#ifndef QT_NO_UDPSOCKET
1542#ifndef QT_NO_NETWORKINTERFACE
1543bool QSocks5SocketEngine::joinMulticastGroup(
const QHostAddress &,
1544 const QNetworkInterface &)
1546 setError(QAbstractSocket::UnsupportedSocketOperationError,
1547 "Operation on socket is not supported"_L1);
1551bool QSocks5SocketEngine::leaveMulticastGroup(
const QHostAddress &,
1552 const QNetworkInterface &)
1554 setError(QAbstractSocket::UnsupportedSocketOperationError,
1555 "Operation on socket is not supported"_L1);
1560QNetworkInterface QSocks5SocketEngine::multicastInterface()
const
1562 return QNetworkInterface();
1565bool QSocks5SocketEngine::setMulticastInterface(
const QNetworkInterface &)
1567 setError(QAbstractSocket::UnsupportedSocketOperationError,
1568 "Operation on socket is not supported"_L1);
1573bool QSocks5SocketEngine::hasPendingDatagrams()
const
1575 Q_D(
const QSocks5SocketEngine);
1578 return !d->udpData->pendingDatagrams.isEmpty();
1581qint64 QSocks5SocketEngine::pendingDatagramSize()
const
1583 Q_D(
const QSocks5SocketEngine);
1585 if (!d->udpData->pendingDatagrams.isEmpty())
1586 return d->udpData->pendingDatagrams.head().data.size();
1591qint64 QSocks5SocketEngine::readDatagram(
char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
1593#ifndef QT_NO_UDPSOCKET
1594 Q_D(QSocks5SocketEngine);
1596 if (d->udpData->pendingDatagrams.isEmpty())
1599 QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
1600 int copyLen = qMin<
int>(maxlen, datagram.data.size());
1601 memcpy(data, datagram.data.constData(), copyLen);
1603 header->senderAddress = datagram.address;
1604 header->senderPort = datagram.port;
1615qint64 QSocks5SocketEngine::writeDatagram(
const char *data, qint64 len,
const QIpPacketHeader &header)
1617#ifndef QT_NO_UDPSOCKET
1618 Q_D(QSocks5SocketEngine);
1622 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1624 if (!bind(QHostAddress(
"0.0.0.0"_L1), 0)) {
1631 outBuf.reserve(270 + len);
1632 outBuf.append(3,
'\0');
1633 if (!qt_socks5_set_host_address_and_port(header.destinationAddress, header.destinationPort, &outBuf)) {
1634 QSOCKS5_DEBUG <<
"error setting address" << header.destinationAddress <<
" : "
1635 << header.destinationPort;
1639 outBuf += QByteArray(data, len);
1641 QByteArray sealedBuf;
1642 if (!d->data->authenticator->seal(outBuf, &sealedBuf)) {
1644 setError(QAbstractSocket::SocketAccessError, d->data->authenticator->errorString());
1647 if (d->udpData->udpSocket->writeDatagram(sealedBuf, d->udpData->associateAddress, d->udpData->associatePort) != sealedBuf.size()) {
1649 if (d->udpData->udpSocket->error() == QAbstractSocket::DatagramTooLargeError)
1650 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1664qint64 QSocks5SocketEngine::bytesToWrite()
const
1666 Q_D(
const QSocks5SocketEngine);
1667 if (d->data && d->data->controlSocket) {
1668 return d->data->controlSocket->bytesToWrite();
1674int QSocks5SocketEngine::option(SocketOption option)
const
1676 Q_D(
const QSocks5SocketEngine);
1677 if (d->data && d->data->controlSocket) {
1679 if (option == QAbstractSocketEngine::LowDelayOption)
1680 return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
1681 if (option == QAbstractSocketEngine::KeepAliveOption)
1682 return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
1687bool QSocks5SocketEngine::setOption(SocketOption option,
int value)
1689 Q_D(QSocks5SocketEngine);
1690 if (d->data && d->data->controlSocket) {
1692 if (option == QAbstractSocketEngine::LowDelayOption)
1693 d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
1694 if (option == QAbstractSocketEngine::KeepAliveOption)
1695 d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
1703 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1713 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1717 if (timedOut && data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1726bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline,
bool *timedOut)
1728 Q_D(QSocks5SocketEngine);
1729 QSOCKS5_DEBUG <<
"waitForRead" << deadline.remainingTimeAsDuration();
1731 d->readNotificationActivated =
false;
1734 if (!d->waitForConnected(deadline, timedOut))
1736 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1738 if (bytesAvailable() && d->readNotificationPending) {
1745 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
1746 d->mode == QSocks5SocketEnginePrivate::BindMode) {
1747 while (!d->readNotificationActivated) {
1748 if (!d->data->controlSocket->waitForReadyRead(deadline.remainingTime())) {
1749 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1752 setError(d->data->controlSocket->error(), d->data->controlSocket->errorString());
1753 if (timedOut && d->data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1758#ifndef QT_NO_UDPSOCKET
1760 while (!d->readNotificationActivated) {
1761 if (!d->udpData->udpSocket->waitForReadyRead(deadline.remainingTime())) {
1762 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1763 if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
1772 bool ret = d->readNotificationActivated;
1773 d->readNotificationActivated =
false;
1780bool QSocks5SocketEngine::waitForWrite(QDeadlineTimer deadline,
bool *timedOut)
1782 Q_D(QSocks5SocketEngine);
1783 QSOCKS5_DEBUG <<
"waitForWrite" << deadline.remainingTimeAsDuration();
1786 if (!d->waitForConnected(deadline, timedOut))
1788 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1794 if (d->data->controlSocket->bytesToWrite())
1795 d->data->controlSocket->waitForBytesWritten(deadline.remainingTime());
1797 auto shouldWriteBytes = [&]() {
1798 return d->data->controlSocket->state() == QAbstractSocket::ConnectedState
1799 && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize;
1802 qint64 remainingTime = deadline.remainingTime();
1803 for (; remainingTime > 0 && shouldWriteBytes(); remainingTime = deadline.remainingTime())
1804 d->data->controlSocket->waitForBytesWritten(remainingTime);
1805 return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
1808bool QSocks5SocketEngine::waitForReadOrWrite(
bool *readyToRead,
bool *readyToWrite,
1809 bool checkRead,
bool checkWrite,
1810 QDeadlineTimer deadline,
bool *timedOut)
1812 Q_UNUSED(checkRead);
1814 bool canRead = waitForRead(deadline, timedOut);
1816 *readyToRead = canRead;
1820 bool canWrite = waitForWrite(deadline, timedOut);
1822 *readyToWrite = canWrite;
1826bool QSocks5SocketEngine::isReadNotificationEnabled()
const
1828 Q_D(
const QSocks5SocketEngine);
1829 return d->readNotificationEnabled;
1832void QSocks5SocketEngine::setReadNotificationEnabled(
bool enable)
1834 Q_D(QSocks5SocketEngine);
1838 bool emitSignal =
false;
1839 if (!d->readNotificationEnabled
1841 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1842 emitSignal = !d->connectData->readBuffer.isEmpty()
1843 || (d->socks5State == QSocks5SocketEnginePrivate::Connected
1844 && d->data->controlSocket->state() == QAbstractSocket::UnconnectedState);
1845#ifndef QT_NO_UDPSOCKET
1846 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode)
1847 emitSignal = !d->udpData->pendingDatagrams.isEmpty();
1849 else if (d->mode == QSocks5SocketEnginePrivate::BindMode
1850 && d->socketState == QAbstractSocket::ListeningState
1851 && d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1855 d->readNotificationEnabled = enable;
1858 d->emitReadNotification();
1861bool QSocks5SocketEngine::isWriteNotificationEnabled()
const
1863 Q_D(
const QSocks5SocketEngine);
1864 return d->writeNotificationEnabled;
1867void QSocks5SocketEngine::setWriteNotificationEnabled(
bool enable)
1869 Q_D(QSocks5SocketEngine);
1870 d->writeNotificationEnabled = enable;
1871 if (enable && d->socketState == QAbstractSocket::ConnectedState) {
1872 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode && d->data->controlSocket->bytesToWrite())
1874 d->emitWriteNotification();
1875 d->writeNotificationActivated =
false;
1879bool QSocks5SocketEngine::isExceptionNotificationEnabled()
const
1881 Q_D(
const QSocks5SocketEngine);
1882 return d->exceptNotificationEnabled;
1885void QSocks5SocketEngine::setExceptionNotificationEnabled(
bool enable)
1887 Q_D(QSocks5SocketEngine);
1888 d->exceptNotificationEnabled = enable;
1891QAbstractSocketEngine *
1892QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,
1893 const QNetworkProxy &proxy, QObject *parent)
1895 Q_UNUSED(socketType);
1898 if (proxy.type() != QNetworkProxy::Socks5Proxy) {
1902 auto engine = std::make_unique<QSocks5SocketEngine>(parent);
1903 engine->setProxy(proxy);
1904 return engine.release();
1907QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(qintptr socketDescriptor, QObject *parent)
1910 if (socks5BindStore()->contains(socketDescriptor)) {
1912 return new QSocks5SocketEngine(parent);
1919#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