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.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 2362 2008-02-29 04:30:11Z edmanm $
00014 ** \brief A QTcpSocket that makes requests over Tor
00015 */
00016 
00017 #include <QDataStream>
00018 
00019 #include "torsocket.h"
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 

Generated on 28 Dec 2009 for Vidalia by  doxygen 1.6.1