torsocket.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006,  Matt Edman, Justin Hipple
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00019  *  Boston, MA  02110-1301, USA.
00020  ****************************************************************/
00021 
00022 /** 
00023  * \file torsocket.cpp
00024  * \version $Id: torsocket.cpp 1238 2006-09-25 17:50:57Z edmanm $
00025  * \brief A QTcpSocket that makes requests over Tor
00026  */
00027 
00028 #include <QDataStream>
00029 
00030 #include "torsocket.h"
00031 
00032 #define SOCKS_VERSION             0x04 /**< SOCKS version. */
00033 #define SOCKS_CONNECT             0x01 /**< SOCKS connect command ID. */
00034 #define SOCKS_FAKE_IP             0x00000001 /**< Bogus IP. */
00035 #define SOCKS_RESPONSE_LEN        0x08 /**< SOCKS server response length. */
00036 #define SOCKS_RESPONSE_VERSION    0x00 /**< SOCKS server response version. */
00037 #define SOCKS_CONNECT_STATUS_OK   0x5A /**< SOCKS server response status. */
00038 #define LOCAL_CONNECT_TIMEOUT     3000 /**< Time to wait for a connection to
00039                                             the local SOCKS proxy. */
00040 
00041 /** Constructor. */
00042 TorSocket::TorSocket(QHostAddress socksAddr, quint16 socksPort, QObject *parent)
00043 : QTcpSocket(parent),
00044   _socksAddr(socksAddr),
00045   _socksPort(socksPort)
00046 {
00047   QObject::connect(this, SIGNAL(error(QAbstractSocket::SocketError)),
00048                    this, SLOT(onError(QAbstractSocket::SocketError)));
00049 }
00050 
00051 /** Connects to the specified hostname and port via Tor. */
00052 void
00053 TorSocket::connectToHost(const QString &remoteHost, quint16 remotePort)
00054 {
00055   /* Connect to the local socks proxy. */
00056   QTcpSocket::connectToHost(_socksAddr, _socksPort);
00057   
00058   /* Wait for the local connection. */
00059   if (waitForConnected(LOCAL_CONNECT_TIMEOUT)) {
00060     /* Signal that we connected to Tor. */
00061     emit connectedToTor();
00062     
00063     /* We're connected to the proxy, so send our part of the handshake. */
00064     QObject::connect(this, SIGNAL(readyRead()),
00065                      this, SLOT(onHandshakeResponse()));
00066     sendSocksHandshake(remoteHost, remotePort);
00067   }
00068 }
00069 
00070 /** Called when a connection error has occurred. */
00071 void
00072 TorSocket::onError(QAbstractSocket::SocketError error)
00073 {
00074   Q_UNUSED(error);
00075   emit socketError(errorString());
00076 }
00077 
00078 /** Sends the first part of a Socks4a handshake, using the remote hostname and
00079  * port specified in the previous call to connectToHost(). The message should
00080  * be formatted as follows:
00081  *
00082  *   0x04                 (socks version)
00083  *   0x01                 (connect)
00084  *   PORT                 (two bytes, most significant byte first)
00085  *   0x00 0x00 0x00 0x01  (fake IP address: tells proxy to use SOCKS4a)
00086  *   0x00                 (empty username field)
00087  *   HOSTNAME             (target hostname)
00088  *   0x00                 (marks the end of the hostname field)
00089  */
00090 void
00091 TorSocket::sendSocksHandshake(const QString &remoteHost, quint16 remotePort)
00092 {
00093   QDataStream sock(this);
00094   sock << (quint8)SOCKS_VERSION;
00095   sock << (quint8)SOCKS_CONNECT;
00096   sock << (quint16)remotePort;
00097   sock << (quint32)SOCKS_FAKE_IP;
00098   sock << (quint8)0;
00099   sock.writeRawData(qPrintable(remoteHost), remoteHost.length());
00100   sock << (quint8)0;
00101 }
00102 
00103 /** Handles the second half of the handshake, received from the SOCKS 
00104  * proxy server. The response should be formatted as follows: 
00105  * 
00106  *    0x00                 (response version)
00107  *    STATUS               (0x5A means success; other values mean failure)
00108  *    PORT                 (not set)
00109  *    ADDRESS              (not set)
00110  */
00111 void
00112 TorSocket::onHandshakeResponse()
00113 {
00114   QByteArray response;
00115   if (bytesAvailable() >= SOCKS_RESPONSE_LEN) {
00116     /* We've received our response, so stop waiting for it. */
00117     QObject::disconnect(this, SIGNAL(readyRead()),
00118                         this, SLOT(onHandshakeResponse()));
00119     
00120     /* Read the 8-byte response off the socket. */
00121     response = read(SOCKS_RESPONSE_LEN);
00122     
00123     /* Check to make sure we got a good response from the proxy. */
00124     if ((uchar)response[0] == (uchar)SOCKS_RESPONSE_VERSION &&
00125         (uchar)response[1] == (uchar)SOCKS_CONNECT_STATUS_OK) {
00126       /* Connection status was okay. */
00127       emit connectedToHost();
00128     } else {
00129       /* Remote connection failed, so close the connection to the proxy. */
00130       disconnectFromHost();
00131     }
00132   }
00133 }
00134 

Generated on Mon Oct 23 20:08:16 2006 for Vidalia by  doxygen 1.5.0