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