Vidalia
0.2.15
|
00001 /* 00002 ** This file is part of Vidalia, and is subject to the license terms in the 00003 ** LICENSE file, found in the top level directory of this distribution. If you 00004 ** did not receive the LICENSE file with this file, you may obtain it from the 00005 ** Vidalia source package distributed by the Vidalia Project at 00006 ** http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 00007 ** including this file, may be copied, modified, propagated, or distributed 00008 ** except according to the terms described in the LICENSE file. 00009 */ 00010 00011 /* 00012 ** \file TorSocket.cpp 00013 ** \brief A QTcpSocket that makes requests over Tor 00014 */ 00015 00016 #include "TorSocket.h" 00017 00018 #include <QDataStream> 00019 00020 #define SOCKS_VERSION 0x04 /**< SOCKS version. */ 00021 #define SOCKS_CONNECT 0x01 /**< SOCKS connect command ID. */ 00022 #define SOCKS_FAKE_IP 0x00000001 /**< Bogus IP. */ 00023 #define SOCKS_RESPONSE_LEN 0x08 /**< SOCKS server response length. */ 00024 #define SOCKS_RESPONSE_VERSION 0x00 /**< SOCKS server response version. */ 00025 #define SOCKS_CONNECT_STATUS_OK 0x5A /**< SOCKS server response status. */ 00026 00027 00028 /** Constructor. */ 00029 TorSocket::TorSocket(const QHostAddress &socksAddr, 00030 quint16 socksPort, QObject *parent) 00031 : QTcpSocket(parent), 00032 _socksAddr(socksAddr), 00033 _socksPort(socksPort) 00034 { 00035 QObject::connect(this, SIGNAL(error(QAbstractSocket::SocketError)), 00036 this, SLOT(onError(QAbstractSocket::SocketError))); 00037 QObject::connect(this, SIGNAL(readyRead()), 00038 this, SLOT(onHandshakeResponse())); 00039 QObject::connect(this, SIGNAL(connected()), 00040 this, SLOT(connectedToProxy())); 00041 } 00042 00043 /** Connects to the specified hostname and port via Tor. */ 00044 void 00045 TorSocket::connectToRemoteHost(const QString &remoteHost, quint16 remotePort) 00046 { 00047 _remoteHost = remoteHost; 00048 _remotePort = remotePort; 00049 QTcpSocket::connectToHost(_socksAddr, _socksPort); 00050 } 00051 00052 /** Called when a connection error has occurred. */ 00053 void 00054 TorSocket::onError(QAbstractSocket::SocketError error) 00055 { 00056 Q_UNUSED(error); 00057 emit socketError(errorString()); 00058 } 00059 00060 /** Called when the socket is connected to the proxy and sends our 00061 * half of a Socks4a handshake. */ 00062 void 00063 TorSocket::connectedToProxy() 00064 { 00065 sendSocksHandshake(_remoteHost, _remotePort); 00066 } 00067 00068 /** Sends the first part of a Socks4a handshake, using the remote hostname and 00069 * port specified in the previous call to connectToHost(). The message should 00070 * be formatted as follows: 00071 * 00072 * 0x04 (socks version) 00073 * 0x01 (connect) 00074 * PORT (two bytes, most significant byte first) 00075 * 0x00 0x00 0x00 0x01 (fake IP address: tells proxy to use SOCKS4a) 00076 * 0x00 (empty username field) 00077 * HOSTNAME (target hostname) 00078 * 0x00 (marks the end of the hostname field) 00079 */ 00080 void 00081 TorSocket::sendSocksHandshake(const QString &remoteHost, quint16 remotePort) 00082 { 00083 QDataStream sock(this); 00084 sock << (quint8)SOCKS_VERSION; 00085 sock << (quint8)SOCKS_CONNECT; 00086 sock << (quint16)remotePort; 00087 sock << (quint32)SOCKS_FAKE_IP; 00088 sock << (quint8)0; 00089 sock.writeRawData(qPrintable(remoteHost), remoteHost.length()); 00090 sock << (quint8)0; 00091 } 00092 00093 /** Handles the second half of the handshake, received from the SOCKS 00094 * proxy server. The response should be formatted as follows: 00095 * 00096 * 0x00 (response version) 00097 * STATUS (0x5A means success; other values mean failure) 00098 * PORT (not set) 00099 * ADDRESS (not set) 00100 */ 00101 void 00102 TorSocket::onHandshakeResponse() 00103 { 00104 QByteArray response; 00105 if (bytesAvailable() >= SOCKS_RESPONSE_LEN) { 00106 /* We've received our response, so stop waiting for it. */ 00107 QObject::disconnect(this, SIGNAL(readyRead()), 00108 this, SLOT(onHandshakeResponse())); 00109 00110 /* Read the 8-byte response off the socket. */ 00111 response = read(SOCKS_RESPONSE_LEN); 00112 00113 /* Check to make sure we got a good response from the proxy. */ 00114 if ((uchar)response[0] == (uchar)SOCKS_RESPONSE_VERSION && 00115 (uchar)response[1] == (uchar)SOCKS_CONNECT_STATUS_OK) { 00116 /* Connection status was okay. */ 00117 emit connectedToRemoteHost(); 00118 } else { 00119 /* Remote connection failed, so close the connection to the proxy. */ 00120 disconnectFromHost(); 00121 } 00122 } 00123 } 00124