[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[vidalia-svn] r2149: Add a TorSslSocket that is capable of making encrypted reque (in trunk: . src/util)



Author: edmanm
Date: 2007-12-01 02:40:00 -0500 (Sat, 01 Dec 2007)
New Revision: 2149

Added:
   trunk/src/util/torsslsocket.cpp
   trunk/src/util/torsslsocket.h
Modified:
   trunk/
   trunk/src/util/util.pri
Log:
 r2178@lysithea:  edmanm | 2007-12-01 02:38:32 -0500
 Add a TorSslSocket that is capable of making encrypted requests over Tor.
 Since it is based on QSslSocket, this is only available on Qt >= 4.3.



Property changes on: trunk
___________________________________________________________________
 svk:merge ticket from /local/vidalia/trunk [r2178] on 0108964c-5b0b-4c9e-969f-e2288315d100

Added: trunk/src/util/torsslsocket.cpp
===================================================================
--- trunk/src/util/torsslsocket.cpp	                        (rev 0)
+++ trunk/src/util/torsslsocket.cpp	2007-12-01 07:40:00 UTC (rev 2149)
@@ -0,0 +1,174 @@
+/****************************************************************
+ *  Vidalia is distributed under the following license:
+ *
+ *  Copyright (C) 2006,  Matt Edman, Justin Hipple
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ *  Boston, MA  02110-1301, USA.
+ ****************************************************************/
+
+/** 
+ * \file torsslsocket.cpp
+ * \version $Id: /local/vidalia/trunk/src/util/torsocket.cpp 1564 2006-12-26T06:06:04.965088Z edmanm  $
+ * \brief A QSslSocket that makes encrypted requests over Tor
+ */
+
+#include "torsslsocket.h"
+#if QT_VERSION >= 0x040300
+#include <QDataStream>
+#include <QStringList>
+
+
+#define SOCKS_VERSION             0x04 /**< SOCKS version. */
+#define SOCKS_CONNECT             0x01 /**< SOCKS connect command ID. */
+#define SOCKS_FAKE_IP             0x00000001 /**< Bogus IP. */
+#define SOCKS_RESPONSE_LEN        0x08 /**< SOCKS server response length. */
+#define SOCKS_RESPONSE_VERSION    0x00 /**< SOCKS server response version. */
+#define SOCKS_CONNECT_STATUS_OK   0x5A /**< SOCKS server response status. */
+
+
+/** Constructor. */
+TorSslSocket::TorSslSocket(const QHostAddress &socksAddr,
+                           quint16 socksPort, QObject *parent)
+: QSslSocket(parent),
+  _socksAddr(socksAddr),
+  _socksPort(socksPort)
+{
+  QObject::connect(this, SIGNAL(sslErrors(QList<QSslError>)),
+                   this, SLOT(onSslErrors(QList<QSslError>)));
+  QObject::connect(this, SIGNAL(error(QAbstractSocket::SocketError)),
+                   this, SLOT(onError(QAbstractSocket::SocketError)));
+  QObject::connect(this, SIGNAL(readyRead()),
+                   this, SLOT(onHandshakeResponse()));
+  QObject::connect(this, SIGNAL(connected()),
+                   this, SLOT(connectedToProxy()));
+  QObject::connect(this, SIGNAL(encrypted()),
+                   this, SLOT(onEncrypted()));
+}
+
+/** Connects to the specified hostname and port via Tor. */
+void
+TorSslSocket::connectToRemoteHost(const QString &remoteHost, quint16 remotePort,
+                                  bool encrypted)
+{
+  _remoteHost = remoteHost;
+  _remotePort = remotePort;
+  _encrypted  = encrypted;
+  QTcpSocket::connectToHost(_socksAddr, _socksPort);
+}
+
+/** Called when a connection error has occurred. */
+void
+TorSslSocket::onError(QAbstractSocket::SocketError error)
+{
+  Q_UNUSED(error);
+  emit socketError(errorString());
+}
+
+/** Called when one or more SSL errors occur on the socket. */
+void
+TorSslSocket::onSslErrors(const QList<QSslError> &errors)
+{
+  QStringList errorStrings;
+  foreach (QSslError error, errors) {
+    errorStrings << "\"" + error.errorString() + "\"";
+  }
+  emit socketError(errorStrings.join(","));
+}
+
+/** Called when a connection has been established to the proxy host and starts
+ * a Socks4a handshake. */
+void
+TorSslSocket::connectedToProxy()
+{
+  sendSocksHandshake(_remoteHost, _remotePort);
+}
+
+/** Called when an encrypted connection has been established to the remote
+ * host. */
+void
+TorSslSocket::onEncrypted()
+{
+  emit connectedToRemoteHost();
+}
+
+/** Sends the first part of a Socks4a handshake, using the remote hostname and
+ * port specified in the previous call to connectToHost(). The message should
+ * be formatted as follows:
+ *
+ *   0x04                 (socks version)
+ *   0x01                 (connect)
+ *   PORT                 (two bytes, most significant byte first)
+ *   0x00 0x00 0x00 0x01  (fake IP address: tells proxy to use SOCKS4a)
+ *   0x00                 (empty username field)
+ *   HOSTNAME             (target hostname)
+ *   0x00                 (marks the end of the hostname field)
+ */
+void
+TorSslSocket::sendSocksHandshake(const QString &remoteHost, quint16 remotePort)
+{
+  QDataStream sock(this);
+  sock << (quint8)SOCKS_VERSION;
+  sock << (quint8)SOCKS_CONNECT;
+  sock << (quint16)remotePort;
+  sock << (quint32)SOCKS_FAKE_IP;
+  sock << (quint8)0;
+  sock.writeRawData(qPrintable(remoteHost), remoteHost.length());
+  sock << (quint8)0;
+}
+
+/** Handles the second half of the handshake, received from the SOCKS 
+ * proxy server. The response should be formatted as follows: 
+ * 
+ *    0x00                 (response version)
+ *    STATUS               (0x5A means success; other values mean failure)
+ *    PORT                 (not set)
+ *    ADDRESS              (not set)
+ */
+void
+TorSslSocket::onHandshakeResponse()
+{
+  QByteArray response;
+  if (bytesAvailable() >= SOCKS_RESPONSE_LEN) {
+    /* We've received our response, so stop waiting for it. */
+    QObject::disconnect(this, SIGNAL(readyRead()),
+                        this, SLOT(onHandshakeResponse()));
+    
+    /* Read the 8-byte response off the socket. */
+    response = read(SOCKS_RESPONSE_LEN);
+    
+    /* Check to make sure we got a good response from the proxy. */
+    if ((uchar)response[0] == (uchar)SOCKS_RESPONSE_VERSION &&
+        (uchar)response[1] == (uchar)SOCKS_CONNECT_STATUS_OK) {
+      if (_encrypted) {
+        /* Connection status was okay, so start client encryption. */
+        /* We first need to set the peer name to the intended remote host,
+         * otherwise Qt will use the proxy (e.g., 127.0.0.1) as the peer name
+         * when validating the server certificate. */
+        setPeerName(_remoteHost);
+        startClientEncryption();
+      } else {
+        /* Caller wanted an unencrypted, unauthenticated, uncool conn. */
+        emit connectedToRemoteHost();
+      }
+    } else {
+      /* Remote connection failed, so close the connection to the proxy. */
+      disconnectFromHost();
+    }
+  }
+}
+
+#endif
+

Added: trunk/src/util/torsslsocket.h
===================================================================
--- trunk/src/util/torsslsocket.h	                        (rev 0)
+++ trunk/src/util/torsslsocket.h	2007-12-01 07:40:00 UTC (rev 2149)
@@ -0,0 +1,87 @@
+/****************************************************************
+ *  Vidalia is distributed under the following license:
+ *
+ *  Copyright (C) 2006,  Matt Edman, Justin Hipple
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ *  Boston, MA  02110-1301, USA.
+ ****************************************************************/
+
+/** 
+ * \file torsslsocket.h
+ * \version $Id: /local/vidalia/trunk/src/util/torsocket.h 1564 2006-12-26T06:06:04.965088Z edmanm  $
+ * \brief A QSslSocket that makes encrypted requests over Tor
+ */
+
+#ifndef _TORSSLSOCKET_H
+#define _TORSSLSOCKET_H
+
+#include <QtGlobal>
+#if QT_VERSION >= 0x040300
+/* XXX: We should do some autoconf magic to and define a HAVE_QSSLSOCKET_H
+ * appropriately. */
+#include <QSslSocket>
+#include <QHostAddress>
+
+
+class TorSslSocket : public QSslSocket
+{
+  Q_OBJECT
+  
+public:
+  /** Constructor. */
+  TorSslSocket(const QHostAddress &socksAddr,
+               quint16 socksPort, QObject *parent = 0);
+
+  /** Connects to the specified hostname and port via Tor. */
+  void connectToRemoteHost(const QString &remoteHost, quint16 remotePort,
+                           bool encrypted);
+
+signals:
+  /** Emitted when a connection has been established through Tor to the remote
+   * host specified in a prior call to connectToHost(). */
+  void connectedToRemoteHost();
+  /** Emmitted when a connection error has occurred. */
+  void socketError(QString errmsg);
+    
+private slots:
+  /** Called when the socket is connected to the proxy and sends our
+   * half of a Socks4a handshake. */
+  void connectedToProxy();
+  /** Called when an encrypted connection has been established to the remote
+   * host. */
+  void onEncrypted();
+  /** Handles the server's response part of a Socks4a handshake. */
+  void onHandshakeResponse();
+  /** Called when a connection error has occurred. */
+  void onError(QAbstractSocket::SocketError error);
+  /** Called when one or more SSL errors occur on the socket. */
+  void onSslErrors(const QList<QSslError> &errors);
+  
+private:
+  /** Sends the client part of a Socks4a handshake with a proxy server. */
+  void sendSocksHandshake(const QString &remoteHost, quint16 remotePort);
+  
+  QHostAddress _socksAddr; /**< Address of Tor's SOCKS listener. */
+  QString _remoteHost;     /**< Remote hostname. */
+  quint16 _socksPort;      /**< Port of Tor's SOCKS listener. */
+  quint16 _remotePort;     /**< Remote host port. */
+  bool    _encrypted;      /**< Set to true if the connection to the remote
+                                host should be encrypted. */
+};
+
+#endif
+#endif
+

Modified: trunk/src/util/util.pri
===================================================================
--- trunk/src/util/util.pri	2007-12-01 07:39:48 UTC (rev 2148)
+++ trunk/src/util/util.pri	2007-12-01 07:40:00 UTC (rev 2149)
@@ -26,6 +26,7 @@
 HEADERS += $$PWD/net.h \
            $$PWD/stringutil.h \
            $$PWD/torsocket.h \
+           $$PWD/torsslsocket.h \
            $$PWD/html.h \
            $$PWD/process.h \
            $$PWD/file.h \
@@ -36,6 +37,7 @@
 SOURCES += $$PWD/net.cpp \
            $$PWD/stringutil.cpp \
            $$PWD/torsocket.cpp \
+           $$PWD/torsslsocket.cpp \
            $$PWD/html.cpp \
            $$PWD/process.cpp \
            $$PWD/file.cpp \