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);
222 qDebug() <<
"skipping hostname of len" << uint(pBuf[pos]);
223 pos += uchar(pBuf[pos]);
230 if (buf.size() - pos < 2) {
234 port = qFromBigEndian<quint16>(&pBuf[pos]);
275#ifndef QT_NO_UDPSOCKET
307QSocks5BindStore::QSocks5BindStore()
309 QCoreApplication *app = QCoreApplication::instance();
310 if (app && app->thread() != thread())
311 moveToThread(app->thread());
321 if (store.contains(socketDescriptor)) {
324 bindData->timeStamp.start();
325 store.insert(socketDescriptor, bindData);
328 if (!sweepTimer.isActive())
329 sweepTimer.start(1min,
this);
335 return store.contains(socketDescriptor);
341 const auto it = store.constFind(socketDescriptor);
342 if (it == store.cend())
347 if (bindData->controlSocket->thread() != QThread::currentThread()) {
348 qWarning(
"Cannot access socks5 bind data from different thread");
363 if (event->id() == sweepTimer.id()) {
365 for (
auto it = store.begin(), end = store.end(); it != end;) {
366 if (it.value()->timeStamp.hasExpired(350000)) {
368 it = store.erase(it);
417 return unSeal(sealedSocket->readAll(), buf);
422 this->userName = userName;
423 this->password = password;
434 QByteArray uname = userName.toLatin1();
435 QByteArray passwd = password.toLatin1();
436 QByteArray dataBuf(3 + uname.size() + passwd.size(), 0);
437 char *buf = dataBuf.data();
440 buf[pos++] = uname.size();
441 memcpy(&buf[pos], uname.data(), uname.size());
443 buf[pos++] = passwd.size();
444 memcpy(&buf[pos], passwd.data(), passwd.size());
445 return socket->write(dataBuf) == dataBuf.size();
452 if (socket->bytesAvailable() < 2)
455 QByteArray buf = socket->read(2);
468 return "Socks5 user name or password incorrect"_L1;
478 , socketDescriptor(-1)
481#ifndef QT_NO_UDPSOCKET
500 Q_Q(QSocks5SocketEngine);
506#ifndef QT_NO_UDPSOCKET
510 udpData->udpSocket =
new QUdpSocket(q);
511 udpData->udpSocket->setProxy(QNetworkProxy::NoProxy);
512 QObject::connect(udpData->udpSocket, SIGNAL(readyRead()),
513 q, SLOT(_q_udpSocketReadNotification()),
514 Qt::DirectConnection);
521 data->controlSocket =
new QTcpSocket(q);
522 data->controlSocket->setProxy(QNetworkProxy::NoProxy);
523 QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()),
524 Qt::DirectConnection);
525 QObject::connect(data->controlSocket, SIGNAL(readyRead()), q, SLOT(_q_controlSocketReadNotification()),
526 Qt::DirectConnection);
527 QObject::connect(data->controlSocket, SIGNAL(bytesWritten(qint64)), q, SLOT(_q_controlSocketBytesWritten()),
528 Qt::DirectConnection);
529 QObject::connect(data->controlSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
530 q, SLOT(_q_controlSocketErrorOccurred(QAbstractSocket::SocketError)),
531 Qt::DirectConnection);
532 QObject::connect(data->controlSocket, SIGNAL(disconnected()), q, SLOT(_q_controlSocketDisconnected()),
533 Qt::DirectConnection);
534 QObject::connect(data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
535 q, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
536 Qt::DirectConnection);
538 if (!proxyInfo.user().isEmpty() || !proxyInfo.password().isEmpty()) {
539 QSOCKS5_D_DEBUG <<
"using username/password authentication; user =" << proxyInfo.user();
540 data->authenticator =
new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
549 Q_Q(QSocks5SocketEngine);
566 switch (controlSocketError) {
567 case QAbstractSocket::ConnectionRefusedError:
568 q->setError(QAbstractSocket::ProxyConnectionRefusedError,
569 QSocks5SocketEngine::tr(
"Connection to proxy refused"));
571 case QAbstractSocket::RemoteHostClosedError:
572 q->setError(QAbstractSocket::ProxyConnectionClosedError,
573 QSocks5SocketEngine::tr(
"Connection to proxy closed prematurely"));
575 case QAbstractSocket::HostNotFoundError:
576 q->setError(QAbstractSocket::ProxyNotFoundError,
577 QSocks5SocketEngine::tr(
"Proxy host not found"));
579 case QAbstractSocket::SocketTimeoutError:
581 q->setError(QAbstractSocket::ProxyConnectionTimeoutError,
582 QSocks5SocketEngine::tr(
"Connection to proxy timed out"));
587 q->setError(controlSocketError, data->controlSocket->errorString());
591 q->setError(controlSocketError, data->controlSocket->errorString());
596 case AuthenticatingError:
597 q->setError(QAbstractSocket::ProxyAuthenticationRequiredError,
598 extraMessage.isEmpty() ?
599 QSocks5SocketEngine::tr(
"Proxy authentication failed") :
600 QSocks5SocketEngine::tr(
"Proxy authentication failed: %1").arg(extraMessage));
608 q->setError(QAbstractSocket::ProxyProtocolError,
609 QSocks5SocketEngine::tr(
"SOCKS version 5 protocol error"));
612 case HostNameLookupError:
613 q->setError(QAbstractSocket::HostNotFoundError,
614 QAbstractSocket::tr(
"Host not found"));
618 q->setState(QAbstractSocket::UnconnectedState);
624 Q_Q(QSocks5SocketEngine);
625 switch (socks5error) {
627 q->setError(QAbstractSocket::NetworkError,
628 QSocks5SocketEngine::tr(
"General SOCKSv5 server failure"));
630 case ConnectionNotAllowed:
631 q->setError(QAbstractSocket::SocketAccessError,
632 QSocks5SocketEngine::tr(
"Connection not allowed by SOCKSv5 server"));
634 case NetworkUnreachable:
635 q->setError(QAbstractSocket::NetworkError,
636 QAbstractSocket::tr(
"Network unreachable"));
638 case HostUnreachable:
639 q->setError(QAbstractSocket::HostNotFoundError,
640 QAbstractSocket::tr(
"Host not found"));
642 case ConnectionRefused:
643 q->setError(QAbstractSocket::ConnectionRefusedError,
644 QAbstractSocket::tr(
"Connection refused"));
647 q->setError(QAbstractSocket::NetworkError,
648 QSocks5SocketEngine::tr(
"TTL expired"));
650 case CommandNotSupported:
651 q->setError(QAbstractSocket::UnsupportedSocketOperationError,
652 QSocks5SocketEngine::tr(
"SOCKSv5 command not supported"));
654 case AddressTypeNotSupported:
655 q->setError(QAbstractSocket::UnsupportedSocketOperationError,
656 QSocks5SocketEngine::tr(
"Address type not supported"));
660 q->setError(QAbstractSocket::UnknownSocketError,
661 QSocks5SocketEngine::tr(
"Unknown SOCKSv5 proxy error code 0x%1").arg(
int(socks5error), 16));
670 Q_Q(QSocks5SocketEngine);
674 q->proxyAuthenticationRequired(proxyInfo, &auth);
676 if (!auth.user().isEmpty() || !auth.password().isEmpty()) {
678 QSOCKS5_DEBUG <<
"authentication failure: retrying connection";
682 proxyInfo.setUser(auth.user());
683 proxyInfo.setPassword(auth.password());
684 data->authenticator =
new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
690 data->controlSocket->connectToHost(proxyInfo.hostName(), proxyInfo.port());
715 bool authComplete =
false;
723 setErrorState(AuthenticatingError,
"Socks5 host did not support authentication method."_L1);
724 socketError = QAbstractSocket::SocketAccessError;
737 bool authComplete =
false;
748 QHostAddress address;
753 address = peerAddress;
757 address = localAddress;
760#ifndef QT_NO_UDPSOCKET
762 address = localAddress;
772 if (peerName.isEmpty() && !qt_socks5_set_host_address_and_port(address, port, &buf)) {
773 QSOCKS5_DEBUG <<
"error setting address" << address <<
" : " << port;
776 }
else if (!peerName.isEmpty() && !qt_socks5_set_host_name_and_port(peerName, port, &buf)) {
777 QSOCKS5_DEBUG <<
"error setting peer name" << peerName <<
" : " << port;
782 QByteArray sealedBuf;
793 Q_Q(QSocks5SocketEngine);
803 inBuf.prepend(receivedHeaderFragment);
804 receivedHeaderFragment.clear();
806 if (inBuf.size() < 3) {
807 QSOCKS5_DEBUG <<
"need more data for request reply header .. put this data somewhere";
808 receivedHeaderFragment = inBuf;
812 QHostAddress address;
815 if (inBuf.at(0) !=
S5_VERSION_5 || inBuf.at(2) != 0x00) {
821 if ((socks5Error == SocksFailure || socks5Error == ConnectionNotAllowed)
822 && !peerName.isEmpty()) {
831 int err = qt_socks5_get_host_address_and_port(inBuf, &address, &port, &pos);
835 }
else if (err == 0) {
837 receivedHeaderFragment = inBuf;
840 inBuf.remove(0, pos);
841 for (
int i = inBuf.size() - 1; i >= 0 ; --i)
848 localAddress = address;
855 q->setState(QAbstractSocket::ConnectedState);
859 q->setState(QAbstractSocket::ListeningState);
878 Q_Q(QSocks5SocketEngine);
882 QPointer<QSocks5SocketEngine> qq = q;
883 q->readNotification();
887 if (data && data->controlSocket->state() == QAbstractSocket::UnconnectedState
888 && data->controlSocket->error() == QAbstractSocket::RemoteHostClosedError) {
897 Q_Q(QSocks5SocketEngine);
902 QMetaObject::invokeMethod(q,
"_q_emitPendingReadNotification", Qt::QueuedConnection);
909 Q_Q(QSocks5SocketEngine);
912 q->writeNotification();
918 Q_Q(QSocks5SocketEngine);
923 QMetaObject::invokeMethod(q,
"_q_emitPendingWriteNotification", Qt::QueuedConnection);
930 Q_Q(QSocks5SocketEngine);
932 q->connectionNotification();
937 Q_Q(QSocks5SocketEngine);
940 QMetaObject::invokeMethod(q,
"_q_emitPendingConnectionNotification", Qt::QueuedConnection);
943QSocks5SocketEngine::QSocks5SocketEngine(QObject *parent)
944:QAbstractSocketEngine(*
new QSocks5SocketEnginePrivate(), parent)
948QSocks5SocketEngine::~QSocks5SocketEngine()
950 Q_D(QSocks5SocketEngine);
953 delete d->data->authenticator;
954 delete d->data->controlSocket;
957 delete d->connectData;
958#ifndef QT_NO_UDPSOCKET
960 delete d->udpData->udpSocket;
970 Q_CONSTINIT
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
971 return 1 + counter.fetchAndAddRelaxed(1);
974bool QSocks5SocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
976 Q_D(QSocks5SocketEngine);
978 d->socketDescriptor = nextDescriptor();
980 d->socketType = type;
981 d->socketProtocol = protocol;
986bool QSocks5SocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState)
988 Q_D(QSocks5SocketEngine);
994 if (socketState != QAbstractSocket::ConnectedState) {
999 QSocks5BindData *bindData = socks5BindStore()->retrieve(socketDescriptor);
1002 d->socketState = QAbstractSocket::ConnectedState;
1003 d->socketType = QAbstractSocket::TcpSocket;
1004 d->connectData =
new QSocks5ConnectData;
1005 d->data = d->connectData;
1006 d->mode = QSocks5SocketEnginePrivate::ConnectMode;
1007 d->data->controlSocket = bindData->controlSocket;
1008 bindData->controlSocket =
nullptr;
1009 d->data->controlSocket->setParent(
this);
1010 d->socketProtocol = d->data->controlSocket->localAddress().protocol();
1011 d->data->authenticator = bindData->authenticator;
1012 bindData->authenticator =
nullptr;
1013 d->localPort = bindData->localPort;
1014 d->localAddress = bindData->localAddress;
1015 d->peerPort = bindData->peerPort;
1016 d->peerAddress = bindData->peerAddress;
1017 d->inboundStreamCount = d->outboundStreamCount = 1;
1020 QObject::connect(d->data->controlSocket, SIGNAL(connected()),
this, SLOT(_q_controlSocketConnected()),
1021 Qt::DirectConnection);
1022 QObject::connect(d->data->controlSocket, SIGNAL(readyRead()),
this, SLOT(_q_controlSocketReadNotification()),
1023 Qt::DirectConnection);
1024 QObject::connect(d->data->controlSocket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_controlSocketBytesWritten()),
1025 Qt::DirectConnection);
1026 QObject::connect(d->data->controlSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
this, SLOT(_q_controlSocketErrorOccurred(QAbstractSocket::SocketError)),
1027 Qt::DirectConnection);
1028 QObject::connect(d->data->controlSocket, SIGNAL(disconnected()),
this, SLOT(_q_controlSocketDisconnected()),
1029 Qt::DirectConnection);
1030 QObject::connect(d->data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
1031 this, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
1032 Qt::DirectConnection);
1034 d->socks5State = QSocks5SocketEnginePrivate::Connected;
1036 if (d->data->controlSocket->bytesAvailable() != 0)
1037 d->_q_controlSocketReadNotification();
1043void QSocks5SocketEngine::setProxy(
const QNetworkProxy &networkProxy)
1045 Q_D(QSocks5SocketEngine);
1046 d->proxyInfo = networkProxy;
1049qintptr QSocks5SocketEngine::socketDescriptor()
const
1051 Q_D(
const QSocks5SocketEngine);
1052 return d->socketDescriptor;
1055bool QSocks5SocketEngine::isValid()
const
1057 Q_D(
const QSocks5SocketEngine);
1058 return d->socketType != QAbstractSocket::UnknownSocketType
1059 && d->socks5State != QSocks5SocketEnginePrivate::SocksError
1060 && (d->socketError == QAbstractSocket::UnknownSocketError
1061 || d->socketError == QAbstractSocket::SocketTimeoutError
1062 || d->socketError == QAbstractSocket::UnfinishedSocketOperationError);
1065bool QSocks5SocketEngine::connectInternal()
1067 Q_D(QSocks5SocketEngine);
1070 if (socketType() == QAbstractSocket::TcpSocket) {
1071 d->initialize(QSocks5SocketEnginePrivate::ConnectMode);
1072#ifndef QT_NO_UDPSOCKET
1073 }
else if (socketType() == QAbstractSocket::UdpSocket) {
1074 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1076 if (!bind(QHostAddress(
"0.0.0.0"_L1), 0))
1079 setState(QAbstractSocket::ConnectedState);
1083 qFatal(
"QSocks5SocketEngine::connectToHost: in QTcpServer mode");
1088 if (d->socketState != QAbstractSocket::ConnectingState) {
1089 if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized
1091 || d->socks5State == QSocks5SocketEnginePrivate::AuthenticatingError) {
1092 setState(QAbstractSocket::ConnectingState);
1094 d->data->controlSocket->setReadBufferSize(65536);
1097 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1103bool QSocks5SocketEngine::connectToHost(
const QHostAddress &address, quint16 port)
1105 Q_D(QSocks5SocketEngine);
1108 setPeerAddress(address);
1110 d->peerName.clear();
1112 return connectInternal();
1115bool QSocks5SocketEngine::connectToHostByName(
const QString &hostname, quint16 port)
1117 Q_D(QSocks5SocketEngine);
1119 setPeerAddress(QHostAddress());
1121 d->peerName = hostname;
1123 return connectInternal();
1129 QByteArray buf(3, 0);
1139 QSOCKS5_D_DEBUG <<
"_q_controlSocketReadNotification socks5state" << s5StateToString(socks5State)
1140 <<
"bytes available" << data->controlSocket->bytesAvailable();
1143 QSOCKS5_D_DEBUG <<
"########## bogus read why do we get these ... on windows only";
1180 qWarning(
"QSocks5SocketEnginePrivate::_q_controlSocketReadNotification: "
1181 "Unexpectedly received data while in state=%d and mode=%d",
1205 if (error == QAbstractSocket::SocketTimeoutError)
1208 if (error == QAbstractSocket::RemoteHostClosedError
1209 && socks5State == Connected) {
1242#ifndef QT_NO_UDPSOCKET
1248 if (!
udpData->udpSocket->hasPendingDatagrams()) {
1253 while (
udpData->udpSocket->hasPendingDatagrams()) {
1254 QByteArray sealedBuf(
udpData->udpSocket->pendingDatagramSize(), 0);
1256 udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size());
1264 const char *buf = inBuf.constData();
1265 if (inBuf.size() < 4) {
1270 if (buf[pos++] != 0 || buf[pos++] != 0) {
1274 if (buf[pos++] != 0) {
1278 if (qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos) != 1) {
1282 datagram.data = QByteArray(&buf[pos], inBuf.size() - pos);
1283 udpData->pendingDatagrams.enqueue(datagram);
1289bool QSocks5SocketEngine::bind(
const QHostAddress &addr, quint16 port)
1291 Q_D(QSocks5SocketEngine);
1295 QHostAddress address;
1296 if (addr.protocol() == QAbstractSocket::AnyIPProtocol)
1297 address = QHostAddress::AnyIPv4;
1302 if (socketType() == QAbstractSocket::TcpSocket) {
1303 d->initialize(QSocks5SocketEnginePrivate::BindMode);
1304#ifndef QT_NO_UDPSOCKET
1305 }
else if (socketType() == QAbstractSocket::UdpSocket) {
1306 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1314#ifndef QT_NO_UDPSOCKET
1315 if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1316 if (!d->udpData->udpSocket->bind(address, port)) {
1318 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1321 d->localAddress = d->udpData->udpSocket->localAddress();
1322 d->localPort = d->udpData->udpSocket->localPort();
1325 if (d->mode == QSocks5SocketEnginePrivate::BindMode) {
1326 d->localAddress = address;
1327 d->localPort = port;
1333 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1334 if (!d->waitForConnected(QDeadlineTimer{Socks5BlockingBindTimeout},
nullptr) ||
1335 d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1337 QSOCKS5_Q_DEBUG <<
"waitForConnected to proxy server" << d->data->controlSocket->errorString();
1340 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
1341 setState(QAbstractSocket::BoundState);
1343#ifndef QT_NO_UDPSOCKET
1344 }
else if (d->socks5State == QSocks5SocketEnginePrivate::UdpAssociateSuccess) {
1345 setState(QAbstractSocket::BoundState);
1346 d->udpData->associateAddress = d->localAddress;
1347 d->localAddress = QHostAddress();
1348 d->udpData->associatePort = d->localPort;
1355 setError(QAbstractSocket::SocketTimeoutError,
1356 QLatin1StringView(QT_TRANSLATE_NOOP(
"QSocks5SocketEngine",
"Network operation timed out")));
1364bool QSocks5SocketEngine::listen(
int backlog)
1366 Q_D(QSocks5SocketEngine);
1372 if (d->socketState == QAbstractSocket::BoundState) {
1373 d->socketState = QAbstractSocket::ListeningState;
1376 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1377 d->emitReadNotification();
1384qintptr QSocks5SocketEngine::accept()
1386 Q_D(QSocks5SocketEngine);
1392 switch (d->socks5State) {
1393 case QSocks5SocketEnginePrivate::BindSuccess:
1394 QSOCKS5_Q_DEBUG <<
"BindSuccess adding" << d->socketDescriptor <<
"to the bind store";
1395 d->data->controlSocket->disconnect();
1396 d->data->controlSocket->setParent(
nullptr);
1397 d->bindData->localAddress = d->localAddress;
1398 d->bindData->localPort = d->localPort;
1399 sd = d->socketDescriptor;
1400 socks5BindStore()->add(sd, d->bindData);
1402 d->bindData =
nullptr;
1403 d->socketDescriptor = 0;
1406 d->socks5State = QSocks5SocketEnginePrivate::Uninitialized;
1407 d->socketState = QAbstractSocket::UnconnectedState;
1409 case QSocks5SocketEnginePrivate::ControlSocketError:
1410 setError(QAbstractSocket::ProxyProtocolError,
"Control socket error"_L1);
1413 setError(QAbstractSocket::ProxyProtocolError,
"SOCKS5 proxy error"_L1);
1419void QSocks5SocketEngine::close()
1422 Q_D(QSocks5SocketEngine);
1423 if (d->data && d->data->controlSocket) {
1424 if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
1425 QDeadlineTimer deadline(100ms);
1426 while (!d->data->controlSocket->bytesToWrite()) {
1427 if (!d->data->controlSocket->waitForBytesWritten(deadline.remainingTime()))
1431 d->data->controlSocket->close();
1433 d->inboundStreamCount = d->outboundStreamCount = 0;
1434#ifndef QT_NO_UDPSOCKET
1435 if (d->udpData && d->udpData->udpSocket)
1436 d->udpData->udpSocket->close();
1440qint64 QSocks5SocketEngine::bytesAvailable()
const
1442 Q_D(
const QSocks5SocketEngine);
1443 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1444 return d->connectData->readBuffer.size();
1445#ifndef QT_NO_UDPSOCKET
1446 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
1447 && !d->udpData->pendingDatagrams.isEmpty())
1448 return d->udpData->pendingDatagrams.constFirst().data.size();
1453qint64 QSocks5SocketEngine::read(
char *data, qint64 maxlen)
1455 Q_D(QSocks5SocketEngine);
1457 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1458 if (d->connectData->readBuffer.isEmpty()) {
1459 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1462 setError(QAbstractSocket::RemoteHostClosedError,
1463 "Remote host closed connection"_L1);
1464 setState(QAbstractSocket::UnconnectedState);
1470 const qint64 copy = d->connectData->readBuffer.read(data, maxlen);
1473#ifndef QT_NO_UDPSOCKET
1474 }
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1475 return readDatagram(data, maxlen);
1481qint64 QSocks5SocketEngine::write(
const char *data, qint64 len)
1483 Q_D(QSocks5SocketEngine);
1486 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1488 len = qMin<qint64>(len, MaxWriteBufferSize) - d->data->controlSocket->bytesToWrite();
1492 QByteArray buf = QByteArray::fromRawData(data, len);
1493 QByteArray sealedBuf;
1494 if (!d->data->authenticator->seal(buf, &sealedBuf)) {
1501 qint64 written = d->data->controlSocket->write(sealedBuf.constData(), sealedBuf.size());
1507 d->data->controlSocket->waitForBytesWritten(0);
1510#ifndef QT_NO_UDPSOCKET
1511 }
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1513 return writeDatagram(data, len, QIpPacketHeader(d->peerAddress, d->peerPort));
1520#ifndef QT_NO_UDPSOCKET
1521#ifndef QT_NO_NETWORKINTERFACE
1522bool QSocks5SocketEngine::joinMulticastGroup(
const QHostAddress &,
1523 const QNetworkInterface &)
1525 setError(QAbstractSocket::UnsupportedSocketOperationError,
1526 "Operation on socket is not supported"_L1);
1530bool QSocks5SocketEngine::leaveMulticastGroup(
const QHostAddress &,
1531 const QNetworkInterface &)
1533 setError(QAbstractSocket::UnsupportedSocketOperationError,
1534 "Operation on socket is not supported"_L1);
1539QNetworkInterface QSocks5SocketEngine::multicastInterface()
const
1541 return QNetworkInterface();
1544bool QSocks5SocketEngine::setMulticastInterface(
const QNetworkInterface &)
1546 setError(QAbstractSocket::UnsupportedSocketOperationError,
1547 "Operation on socket is not supported"_L1);
1552bool QSocks5SocketEngine::hasPendingDatagrams()
const
1554 Q_D(
const QSocks5SocketEngine);
1557 return !d->udpData->pendingDatagrams.isEmpty();
1560qint64 QSocks5SocketEngine::pendingDatagramSize()
const
1562 Q_D(
const QSocks5SocketEngine);
1564 if (!d->udpData->pendingDatagrams.isEmpty())
1565 return d->udpData->pendingDatagrams.head().data.size();
1570qint64 QSocks5SocketEngine::readDatagram(
char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
1572#ifndef QT_NO_UDPSOCKET
1573 Q_D(QSocks5SocketEngine);
1575 if (d->udpData->pendingDatagrams.isEmpty())
1578 QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
1579 int copyLen = qMin<
int>(maxlen, datagram.data.size());
1580 memcpy(data, datagram.data.constData(), copyLen);
1582 header->senderAddress = datagram.address;
1583 header->senderPort = datagram.port;
1594qint64 QSocks5SocketEngine::writeDatagram(
const char *data, qint64 len,
const QIpPacketHeader &header)
1596#ifndef QT_NO_UDPSOCKET
1597 Q_D(QSocks5SocketEngine);
1601 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1603 if (!bind(QHostAddress(
"0.0.0.0"_L1), 0)) {
1610 outBuf.reserve(270 + len);
1611 outBuf.append(3,
'\0');
1612 if (!qt_socks5_set_host_address_and_port(header.destinationAddress, header.destinationPort, &outBuf)) {
1613 QSOCKS5_DEBUG <<
"error setting address" << header.destinationAddress <<
" : "
1614 << header.destinationPort;
1618 outBuf += QByteArray(data, len);
1620 QByteArray sealedBuf;
1621 if (!d->data->authenticator->seal(outBuf, &sealedBuf)) {
1623 setError(QAbstractSocket::SocketAccessError, d->data->authenticator->errorString());
1626 if (d->udpData->udpSocket->writeDatagram(sealedBuf, d->udpData->associateAddress, d->udpData->associatePort) != sealedBuf.size()) {
1628 if (d->udpData->udpSocket->error() == QAbstractSocket::DatagramTooLargeError)
1629 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1643qint64 QSocks5SocketEngine::bytesToWrite()
const
1645 Q_D(
const QSocks5SocketEngine);
1646 if (d->data && d->data->controlSocket) {
1647 return d->data->controlSocket->bytesToWrite();
1653int QSocks5SocketEngine::option(SocketOption option)
const
1655 Q_D(
const QSocks5SocketEngine);
1656 if (d->data && d->data->controlSocket) {
1658 if (option == QAbstractSocketEngine::LowDelayOption)
1659 return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
1660 if (option == QAbstractSocketEngine::KeepAliveOption)
1661 return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
1666bool QSocks5SocketEngine::setOption(SocketOption option,
int value)
1668 Q_D(QSocks5SocketEngine);
1669 if (d->data && d->data->controlSocket) {
1671 if (option == QAbstractSocketEngine::LowDelayOption)
1672 d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
1673 if (option == QAbstractSocketEngine::KeepAliveOption)
1674 d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
1682 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1692 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1696 if (timedOut && data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1705bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline,
bool *timedOut)
1707 Q_D(QSocks5SocketEngine);
1708 QSOCKS5_DEBUG <<
"waitForRead" << deadline.remainingTimeAsDuration();
1710 d->readNotificationActivated =
false;
1713 if (!d->waitForConnected(deadline, timedOut))
1715 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1717 if (bytesAvailable() && d->readNotificationPending) {
1724 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
1725 d->mode == QSocks5SocketEnginePrivate::BindMode) {
1726 while (!d->readNotificationActivated) {
1727 if (!d->data->controlSocket->waitForReadyRead(deadline.remainingTime())) {
1728 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1731 setError(d->data->controlSocket->error(), d->data->controlSocket->errorString());
1732 if (timedOut && d->data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1737#ifndef QT_NO_UDPSOCKET
1739 while (!d->readNotificationActivated) {
1740 if (!d->udpData->udpSocket->waitForReadyRead(deadline.remainingTime())) {
1741 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1742 if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
1751 bool ret = d->readNotificationActivated;
1752 d->readNotificationActivated =
false;
1759bool QSocks5SocketEngine::waitForWrite(QDeadlineTimer deadline,
bool *timedOut)
1761 Q_D(QSocks5SocketEngine);
1762 QSOCKS5_DEBUG <<
"waitForWrite" << deadline.remainingTimeAsDuration();
1765 if (!d->waitForConnected(deadline, timedOut))
1767 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1773 if (d->data->controlSocket->bytesToWrite())
1774 d->data->controlSocket->waitForBytesWritten(deadline.remainingTime());
1776 auto shouldWriteBytes = [&]() {
1777 return d->data->controlSocket->state() == QAbstractSocket::ConnectedState
1778 && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize;
1781 qint64 remainingTime = deadline.remainingTime();
1782 for (; remainingTime > 0 && shouldWriteBytes(); remainingTime = deadline.remainingTime())
1783 d->data->controlSocket->waitForBytesWritten(remainingTime);
1784 return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
1787bool QSocks5SocketEngine::waitForReadOrWrite(
bool *readyToRead,
bool *readyToWrite,
1788 bool checkRead,
bool checkWrite,
1789 QDeadlineTimer deadline,
bool *timedOut)
1791 Q_UNUSED(checkRead);
1793 bool canRead = waitForRead(deadline, timedOut);
1795 *readyToRead = canRead;
1799 bool canWrite = waitForWrite(deadline, timedOut);
1801 *readyToWrite = canWrite;
1805bool QSocks5SocketEngine::isReadNotificationEnabled()
const
1807 Q_D(
const QSocks5SocketEngine);
1808 return d->readNotificationEnabled;
1811void QSocks5SocketEngine::setReadNotificationEnabled(
bool enable)
1813 Q_D(QSocks5SocketEngine);
1817 bool emitSignal =
false;
1818 if (!d->readNotificationEnabled
1820 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1821 emitSignal = !d->connectData->readBuffer.isEmpty();
1822#ifndef QT_NO_UDPSOCKET
1823 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode)
1824 emitSignal = !d->udpData->pendingDatagrams.isEmpty();
1826 else if (d->mode == QSocks5SocketEnginePrivate::BindMode
1827 && d->socketState == QAbstractSocket::ListeningState
1828 && d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1832 d->readNotificationEnabled = enable;
1835 d->emitReadNotification();
1838bool QSocks5SocketEngine::isWriteNotificationEnabled()
const
1840 Q_D(
const QSocks5SocketEngine);
1841 return d->writeNotificationEnabled;
1844void QSocks5SocketEngine::setWriteNotificationEnabled(
bool enable)
1846 Q_D(QSocks5SocketEngine);
1847 d->writeNotificationEnabled = enable;
1848 if (enable && d->socketState == QAbstractSocket::ConnectedState) {
1849 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode && d->data->controlSocket->bytesToWrite())
1851 d->emitWriteNotification();
1852 d->writeNotificationActivated =
false;
1856bool QSocks5SocketEngine::isExceptionNotificationEnabled()
const
1858 Q_D(
const QSocks5SocketEngine);
1859 return d->exceptNotificationEnabled;
1862void QSocks5SocketEngine::setExceptionNotificationEnabled(
bool enable)
1864 Q_D(QSocks5SocketEngine);
1865 d->exceptNotificationEnabled = enable;
1868QAbstractSocketEngine *
1869QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,
1870 const QNetworkProxy &proxy, QObject *parent)
1872 Q_UNUSED(socketType);
1875 if (proxy.type() != QNetworkProxy::Socks5Proxy) {
1879 auto engine = std::make_unique<QSocks5SocketEngine>(parent);
1880 engine->setProxy(proxy);
1881 return engine.release();
1884QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(qintptr socketDescriptor, QObject *parent)
1887 if (socks5BindStore()->contains(socketDescriptor)) {
1889 return new QSocks5SocketEngine(parent);
1896#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