Vidalia  0.2.17
TorSocket.cpp
Go to the documentation of this file.
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