📄 qsocks5socketengine.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtNetwork module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qsocks5socketengine_p.h"#ifndef QT_NO_SOCKS5#include "qtcpsocket.h"#include "qudpsocket.h"#include "qtcpserver.h"#include "qdebug.h"#include "qhash.h"#include "qqueue.h"#include "qdatetime.h"#include "qmutex.h"#include "qthread.h"#include "qcoreapplication.h"#include <qendian.h>//#define QSOCKS5SOCKETLAYER_DEBUG#define MAX_DATA_DUMP 256#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000#define Q_INIT_CHECK(returnValue) do { \ if (!d->data) { \ return returnValue; \ } } while (0)#ifdef QSOCKS5SOCKETLAYER_DEBUG# define QSOCKS5_Q_DEBUG qDebug() << this# define QSOCKS5_D_DEBUG qDebug() << q_ptr# define QSOCKS5_DEBUG qDebug() << "[QSocks5]"#else# define QSOCKS5_DEBUG if (0) qDebug()# define QSOCKS5_Q_DEBUG if (0) qDebug()# define QSOCKS5_D_DEBUG if (0) qDebug()#endif#define S5_VERSION_5 0x05#define S5_CONNECT 0x01#define S5_BIND 0x02#define S5_UDP_ASSOCIATE 0x03#define S5_IP_V4 0x01#define S5_DOMAINNAME 0x03#define S5_IP_V6 0x04#define S5_SUCCESS 0x00#define S5_R_ERROR_SOCKS_FAILURE 0x01#define S5_R_ERROR_CON_NOT_ALLOWED 0x02#define S5_R_ERROR_NET_UNREACH 0x03#define S5_R_ERROR_HOST_UNREACH 0x04#define S5_R_ERROR_CONN_REFUSED 0x05#define S5_R_ERROR_TTL 0x06#define S5_R_ERROR_CMD_NOT_SUPPORTED 0x07#define S5_R_ERROR_ADD_TYPE_NOT_SUPORTED 0x08static QString s5RequestErrorToString(int s5_r_error){ QString ret; switch(s5_r_error) { case 0x01 : ret = QLatin1String("general SOCKS server failure"); break; case 0x02 : ret = QLatin1String("connection not allowed by ruleset"); break; case 0x03 : ret = QLatin1String("Network unreachable"); break; case 0x04 : ret = QLatin1String("Host unreachable"); break; case 0x05 : ret = QLatin1String("Connection refused"); break; case 0x06 : ret = QLatin1String("TTL expired"); break; case 0x07 : ret = QLatin1String("Command not supported"); break; case 0x08 : ret = QLatin1String("Address type not supported"); break; default : ret = QLatin1String("unassigned error code"); break; } return ret;}static QString makeErrorString(const QString & e){ return QLatin1String("Socks 5 - ") + e;}static QAbstractSocket::SocketError s5RAsSocketError(int s5_r_error){ QAbstractSocket::SocketError ret; switch(s5_r_error) { case 0x01 : ret = QAbstractSocket::NetworkError; break; case 0x02 : ret = QAbstractSocket::SocketAccessError; break; case 0x03 : ret = QAbstractSocket::NetworkError; break; case 0x04 : ret = QAbstractSocket::HostNotFoundError; break; case 0x05 : ret = QAbstractSocket::ConnectionRefusedError; break; case 0x06 : ret = QAbstractSocket::NetworkError; break; case 0x07 : ret = QAbstractSocket::UnsupportedSocketOperationError; break; case 0x08 : ret = QAbstractSocket::UnsupportedSocketOperationError; break; default : ret = QAbstractSocket::NetworkError; break; } return ret;}static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State s){ switch (s) { case QSocks5SocketEnginePrivate::unInitialized: return QLatin1String("unInitialized"); case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return QLatin1String("AuthenticationMethodsSent"); case QSocks5SocketEnginePrivate::Authenticating: return QLatin1String("Authenticating"); case QSocks5SocketEnginePrivate::RequestMethodSent: return QLatin1String("RequestMethodSent"); case QSocks5SocketEnginePrivate::RequestSuccess: return QLatin1String("RequestSuccess"); case QSocks5SocketEnginePrivate::RequestError: return QLatin1String("RequestError"); case QSocks5SocketEnginePrivate::Connected: return QLatin1String("Connected"); case QSocks5SocketEnginePrivate::ConnectError: return QLatin1String("BindSuccess"); case QSocks5SocketEnginePrivate::BindSuccess: return QLatin1String("unInitialized"); case QSocks5SocketEnginePrivate::BindError: return QLatin1String("BindError"); case QSocks5SocketEnginePrivate::ControlSocketError: return QLatin1String("ControlSocketError"); case QSocks5SocketEnginePrivate::SocksError: return QLatin1String("SocksError"); default: break; } return QLatin1String("unknown state");}static QString dump(const QByteArray &buf){ QString data; for (int i = 0; i < qMin<int>(MAX_DATA_DUMP, buf.size()); ++i) { if (i) data += QLatin1Char(' '); uint val = (unsigned char)buf.at(i); // data += QString("0x%1").arg(val, 3, 16, QLatin1Char('0')); data += QString::number(val); } if (buf.size() > MAX_DATA_DUMP) data += QLatin1String(" ..."); return QString::fromLatin1("size: %1 data: { %2 }").arg(buf.size()).arg(data);}/* inserets the host address in buf at pos and updates pos. if the func fails the data in buf and the vallue of pos is undefined*/static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf, int *pPos){ bool ret = false; int pos = *pPos; QSOCKS5_DEBUG << "setting [" << address << ":" << port << "]"; if (address.protocol() == QAbstractSocket::IPv4Protocol) { int spaceAvailable = pBuf->size() - pos; if (spaceAvailable < int(sizeof(quint32) + 1)) pBuf->resize(pBuf->size() + sizeof(quint32) + 1 - spaceAvailable); unsigned char *buf = reinterpret_cast<unsigned char *>(pBuf->data()); buf[pos++] = S5_IP_V4; qToUnaligned(qToBigEndian<quint32>(address.toIPv4Address()), &buf[pos]); pos += sizeof(quint32); ret = true; } else if (address.protocol() == QAbstractSocket::IPv6Protocol) { int spaceAvailable = pBuf->size() - pos; if (spaceAvailable < 17) pBuf->resize(pBuf->size() + 17 - spaceAvailable); char *buf = pBuf->data(); buf[pos++] = S5_IP_V6; QIPv6Address ipv6 = address.toIPv6Address(); for (int i = 0; i < 16; ++i) buf[pos++] = ipv6[i]; ret = true; } else { // domain name. ret = false; } if (ret) { int spaceAvailable = pBuf->size() - pos; if (spaceAvailable < int(sizeof(quint16))) pBuf->resize(pBuf->size() + sizeof(quint16) - spaceAvailable); unsigned char *buf = reinterpret_cast<unsigned char *>(pBuf->data()); qToUnaligned(qToBigEndian<quint16>(port), &buf[pos]); pos += sizeof(quint16); } if (ret) *pPos = pos; return ret;}/* retrives the host address in buf at pos and updates pos. if the func fails the value of the address and the pos is undefined*/static bool qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddress *pAddress, quint16 *pPort, int *pPos){ bool ret = false; int pos = *pPos; const unsigned char *pBuf = reinterpret_cast<const unsigned char*>(buf.constData()); QHostAddress address; quint16 port = 0; if (buf.size() - pos < 1) { QSOCKS5_DEBUG << "need more data address/port"; return false; } if (pBuf[pos] == S5_IP_V4) { pos++; if (buf.size() - pos < 4) { QSOCKS5_DEBUG << "need more data for ip4 address"; return false; } address.setAddress(qFromBigEndian<quint32>(&pBuf[pos])); pos += 4; ret = true; } else if (pBuf[pos] == S5_IP_V6) { pos++; if (buf.size() - pos < 16) { QSOCKS5_DEBUG << "need more data for ip6 address"; return false; } QIPv6Address add; for (int i = 0; i < 16; ++i) add[i] = buf[pos++]; ret = true; } else if (pBuf[pos] == S5_DOMAINNAME){ pos++; // domain name. ret = false; } else { QSOCKS5_DEBUG << "invalid address type" << (int)pBuf[pos]; ret = false; } if (ret) { if (buf.size() - pos < 2) { QSOCKS5_DEBUG << "need more data for port"; return false; } port = qFromBigEndian<quint16>(&pBuf[pos]); pos += 2; } if (ret) { QSOCKS5_DEBUG << "got [" << address << ":" << port << "]"; *pAddress = address; *pPort = port; *pPos = pos; } return ret;}/* Returns the difference between msecs and elapsed. If msecs is -1, however, -1 is returned.*/static int qt_timeout_value(int msecs, int elapsed){ if (msecs == -1) return -1; int timeout = msecs - elapsed; return timeout < 0 ? 0 : timeout;}struct QSocks5Data{ QTcpSocket *controlSocket; QSocks5Authenticator *authenticator;};struct QSocks5ConnectData : public QSocks5Data{ QByteArray readBuffer;};struct QSocks5BindData : public QSocks5Data{ QHostAddress localAddress; quint16 localPort; QHostAddress peerAddress; quint16 peerPort; QDateTime timeStamp;};struct QSocks5RevivedDatagram{ QByteArray data; QHostAddress address; quint16 port;};#ifndef QT_NO_UDPSOCKETstruct QSocks5UdpAssociateData : public QSocks5Data{ QUdpSocket *udpSocket; QHostAddress associateAddress; quint16 associatePort; QQueue<QSocks5RevivedDatagram> pendingDatagrams;};#endif// needs to be thread safeclass QSocks5BindStore : public QObject{public: QSocks5BindStore(); ~QSocks5BindStore(); void add(int socketDescriptor, QSocks5BindData *bindData); bool contains(int socketDescriptor); QSocks5BindData *retrieve(int socketDescriptor);protected: void timerEvent(QTimerEvent * event); QMutex mutex; int sweepTimerId; //socket descriptor, data, timestamp QHash<int, QSocks5BindData *> store;};Q_GLOBAL_STATIC(QSocks5BindStore, socks5BindStore);QSocks5BindStore::QSocks5BindStore() : mutex(QMutex::Recursive) , sweepTimerId(-1){ QCoreApplication *app = QCoreApplication::instance(); if (app && app->thread() != thread()) moveToThread(app->thread());}QSocks5BindStore::~QSocks5BindStore(){}void QSocks5BindStore::add(int socketDescriptor, QSocks5BindData *bindData){ QMutexLocker lock(&mutex); if (store.contains(socketDescriptor)) { // qDebug() << "delete it"; } bindData->timeStamp = QDateTime::currentDateTime(); store.insert(socketDescriptor, bindData); // start sweep timer if not started if (sweepTimerId == -1) sweepTimerId = startTimer(60000);}bool QSocks5BindStore::contains(int socketDescriptor){ QMutexLocker lock(&mutex); return store.contains(socketDescriptor);}QSocks5BindData *QSocks5BindStore::retrieve(int socketDescriptor){ QMutexLocker lock(&mutex); if (!store.contains(socketDescriptor)) return 0; QSocks5BindData *bindData = store.take(socketDescriptor); if (bindData) { if (bindData->controlSocket->thread() != QThread::currentThread()) { qWarning("Can not access socks5 bind data from different thread"); return 0; } } else { QSOCKS5_DEBUG << "__ERROR__ binddata == 0"; } // stop the sweep timer if not needed if (store.isEmpty()) { killTimer(sweepTimerId); sweepTimerId = -1; } return bindData;}void QSocks5BindStore::timerEvent(QTimerEvent * event){ QMutexLocker lock(&mutex); if (event->timerId() == sweepTimerId) { QSOCKS5_DEBUG << "QSocks5BindStore performing sweep"; QMutableHashIterator<int, QSocks5BindData *> it(store); while (it.hasNext()) { it.next(); if (it.value()->timeStamp.secsTo(QDateTime::currentDateTime()) > 350) { QSOCKS5_DEBUG << "QSocks5BindStore removing JJJJ"; it.remove(); } } }}QSocks5Authenticator::QSocks5Authenticator(){}QSocks5Authenticator::~QSocks5Authenticator(){}char QSocks5Authenticator::methodId(){ return 0x00;}bool QSocks5Authenticator::beginAuthenticate(QTcpSocket *socket, bool *completed){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -