Vidalia  0.3.1
TorSocket.cpp
Go to the documentation of this file.
1 /*
2 ** This file is part of Vidalia, and is subject to the license terms in the
3 ** LICENSE file, found in the top level directory of this distribution. If you
4 ** did not receive the LICENSE file with this file, you may obtain it from the
5 ** Vidalia source package distributed by the Vidalia Project at
6 ** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7 ** including this file, may be copied, modified, propagated, or distributed
8 ** except according to the terms described in the LICENSE file.
9 */
10 
11 /*
12 ** \file TorSocket.cpp
13 ** \brief A QTcpSocket that makes requests over Tor
14 */
15 
16 #include "TorSocket.h"
17 
18 #include <QDataStream>
19 
20 #define SOCKS_VERSION 0x04 /**< SOCKS version. */
21 #define SOCKS_CONNECT 0x01 /**< SOCKS connect command ID. */
22 #define SOCKS_FAKE_IP 0x00000001 /**< Bogus IP. */
23 #define SOCKS_RESPONSE_LEN 0x08 /**< SOCKS server response length. */
24 #define SOCKS_RESPONSE_VERSION 0x00 /**< SOCKS server response version. */
25 #define SOCKS_CONNECT_STATUS_OK 0x5A /**< SOCKS server response status. */
26 
27 
28 /** Constructor. */
29 TorSocket::TorSocket(const QHostAddress &socksAddr,
30  quint16 socksPort, QObject *parent)
31 : QTcpSocket(parent),
32  _socksAddr(socksAddr),
33  _socksPort(socksPort)
34 {
35  QObject::connect(this, SIGNAL(error(QAbstractSocket::SocketError)),
36  this, SLOT(onError(QAbstractSocket::SocketError)));
37  QObject::connect(this, SIGNAL(readyRead()),
38  this, SLOT(onHandshakeResponse()));
39  QObject::connect(this, SIGNAL(connected()),
40  this, SLOT(connectedToProxy()));
41 }
42 
43 /** Connects to the specified hostname and port via Tor. */
44 void
45 TorSocket::connectToRemoteHost(const QString &remoteHost, quint16 remotePort)
46 {
47  _remoteHost = remoteHost;
48  _remotePort = remotePort;
49  QTcpSocket::connectToHost(_socksAddr, _socksPort);
50 }
51 
52 /** Called when a connection error has occurred. */
53 void
54 TorSocket::onError(QAbstractSocket::SocketError error)
55 {
56  Q_UNUSED(error);
57  emit socketError(errorString());
58 }
59 
60 /** Called when the socket is connected to the proxy and sends our
61  * half of a Socks4a handshake. */
62 void
64 {
66 }
67 
68 /** Sends the first part of a Socks4a handshake, using the remote hostname and
69  * port specified in the previous call to connectToHost(). The message should
70  * be formatted as follows:
71  *
72  * 0x04 (socks version)
73  * 0x01 (connect)
74  * PORT (two bytes, most significant byte first)
75  * 0x00 0x00 0x00 0x01 (fake IP address: tells proxy to use SOCKS4a)
76  * 0x00 (empty username field)
77  * HOSTNAME (target hostname)
78  * 0x00 (marks the end of the hostname field)
79  */
80 void
81 TorSocket::sendSocksHandshake(const QString &remoteHost, quint16 remotePort)
82 {
83  QDataStream sock(this);
84  sock << (quint8)SOCKS_VERSION;
85  sock << (quint8)SOCKS_CONNECT;
86  sock << (quint16)remotePort;
87  sock << (quint32)SOCKS_FAKE_IP;
88  sock << (quint8)0;
89  sock.writeRawData(qPrintable(remoteHost), remoteHost.length());
90  sock << (quint8)0;
91 }
92 
93 /** Handles the second half of the handshake, received from the SOCKS
94  * proxy server. The response should be formatted as follows:
95  *
96  * 0x00 (response version)
97  * STATUS (0x5A means success; other values mean failure)
98  * PORT (not set)
99  * ADDRESS (not set)
100  */
101 void
103 {
104  QByteArray response;
105  if (bytesAvailable() >= SOCKS_RESPONSE_LEN) {
106  /* We've received our response, so stop waiting for it. */
107  QObject::disconnect(this, SIGNAL(readyRead()),
108  this, SLOT(onHandshakeResponse()));
109 
110  /* Read the 8-byte response off the socket. */
111  response = read(SOCKS_RESPONSE_LEN);
112 
113  /* Check to make sure we got a good response from the proxy. */
114  if ((uchar)response[0] == (uchar)SOCKS_RESPONSE_VERSION &&
115  (uchar)response[1] == (uchar)SOCKS_CONNECT_STATUS_OK) {
116  /* Connection status was okay. */
117  emit connectedToRemoteHost();
118  } else {
119  /* Remote connection failed, so close the connection to the proxy. */
120  disconnectFromHost();
121  }
122  }
123 }
124