summaryrefslogtreecommitdiffstats
path: root/src/torclient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/torclient.cpp')
-rw-r--r--src/torclient.cpp1536
1 files changed, 1536 insertions, 0 deletions
diff --git a/src/torclient.cpp b/src/torclient.cpp
new file mode 100644
index 0000000..a29051a
--- /dev/null
+++ b/src/torclient.cpp
@@ -0,0 +1,1536 @@
+/****************************************************************************
+ ** $Id: torclient.cpp,v 1.138 2009/10/13 20:19:51 hoganrobert Exp $
+ * Copyright (C) 2006 - 2008 Robert Hogan *
+ * robert@roberthogan.net *
+ * *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+
+#include <qsocket.h>
+#include <qtextstream.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include "torclient.h"
+#include "tork.h"
+#include "torkconfig.h"
+#include "dndlistview.h"
+#include "functions.h"
+
+#include <qtimer.h>
+#include <klocale.h>
+#include <assert.h>
+#include <qfile.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <kstandarddirs.h>
+#include <qdir.h>
+#include "crypto.h"
+
+#ifndef EXTERNAL_GEOIP
+# include "GeoIP-1.4.0/libGeoIP/GeoIP.h"
+#else
+# include <GeoIP.h>
+#endif
+
+/* Linux-specific includes */
+#include <dirent.h>
+#include <unistd.h>
+
+using namespace tk;
+
+
+TorClient::TorClient( const QString &host, Q_UINT16 port )
+{
+ // create the socket and connect various of its signals
+ socket = new QSocket( this );
+ connect( socket, SIGNAL(connected()),
+ SLOT(socketConnected()) );
+ connect( socket, SIGNAL(connectionClosed()),
+ SLOT(socketConnectionClosed()) );
+ connect( socket, SIGNAL(readyRead()),
+ SLOT(socketReadyRead()) );
+ connect( socket, SIGNAL(error(int)),
+ SLOT(socketError(int)) );
+
+ // connect to the server
+ //infoText->append( tr("Trying to connect to the server\n") );
+ socket->connectToHost( host, port );
+ m_expectingCircuitInfo= false;
+ m_expectingStreamInfo= false;
+ m_expectingOrconnInfo= false;
+ m_expectingGuardsInfo= false;
+ m_expectingDirStatus= false;
+ m_expectingServerInfo= false;
+ m_controllerWorking= false;
+ m_firstloadcomplete = false;
+ m_resolvingServerAddress = false;
+
+ clearServers();
+
+ serverReport.append("<font color='#990000'>Status Not Known</font>");
+ clientReport.append("<font color='#990000'>Status Not Known</font>");
+ serverStatus["DANGEROUS_VERSION"] = "<font color='#990000'>Server Requires Upgrade</font>";
+ serverStatus["TOO_MANY_CONNECTIONS"] = "<font color='#990000'>Recently Exceeded Local Connection Limit. Check Local System</font>";
+ serverStatus["CLOCK_SKEW"] = "<font color='#990000'>Your Local Clock Is Skewed. Check Local System.</font>";
+ serverStatus["BAD_LIBEVENT"] = "<font color='#990000'>Libevent Installation Requires Upgrade</font>";
+ serverStatus["DIR_ALL_UNREACHABLE"] = "<font color='#990000'>Tor Network Unreachable.</font>";
+// serverStatus["NAMESERVER_ALL_DOWN"] = "Your DNS Servers are down.";
+ serverStatus["DNS_HIJACKED"] = "<font color='#990000'>Your Provider is Hijacking DNS Requests.</font>";
+ serverStatus["DNS_USELESS"] = "<font color='#990000'>Your Provider is Hijacking DNS Requests.</font>";
+ serverStatus["EXTERNAL_ADDRESS"] = "Using Address ADDRESS";
+
+ serverStatus["REACHABILITY_SUCCEEDED"] = "Reachable By Tor Network";
+ serverStatus["REACHABILITY_FAILED"] = "<font color='#990000'>Reachability Tests Failed. Trying again..</font>";
+ serverStatus["BAD_SERVER_DESCRIPTOR"] = "<font color='#990000'>Server Not Accepted By Tor Network Yet.</font>";
+ serverStatus["GOOD_SERVER_DESCRIPTOR"] = "Accepted By Tor Network";
+
+ serverStatusIcon["REACHABILITY_SUCCEEDED"] = "tork_green";
+ serverStatusIcon["REACHABILITY_FAILED"] = "tork_orange";
+ serverStatusIcon["BAD_SERVER_DESCRIPTOR"] = "tork_little";
+ serverStatusIcon["GOOD_SERVER_DESCRIPTOR"] = "tork_green";
+ serverStatusIcon["DIR_ALL_UNREACHABLE"] = "tork_red";
+
+ clientStatus["NOT_ENOUGH_DIR_INFO"] = "<font color='#990000'>Not Enough Info To Try Network Yet</font>";
+ clientStatus["ENOUGH_DIR_INFO"] = "Enough Info To Try Network";
+ clientStatus["CIRCUIT_ESTABLISHED"] = "Connected to Network.";
+ clientStatus["CIRCUIT_NOT_ESTABLISHED"] = "<font color='#990000'>Still Trying Network</font>";
+
+ clientStatusIcon[clientStatus["NOT_ENOUGH_DIR_INFO"]] = "tork_red";
+ clientStatusIcon[clientStatus["ENOUGH_DIR_INFO"]] = "tork_little";
+ clientStatusIcon[clientStatus["CIRCUIT_ESTABLISHED"]] = "tork_green";
+ clientStatusIcon[clientStatus["CIRCUIT_NOT_ESTABLISHED"]] = "tork_orange";
+
+ portMessage["23"] = " Port 23 is used by telnet, which transmits usernames "
+ "and passwords unencrypted.";
+ portMessage["110"] = " Port 110 is used to download email, so your login "
+ "details can be transmitted unencrypted.";
+ portMessage["109"] = " Port 109 is used to download email, so your login "
+ "details can be transmitted unencrypted.";
+ portMessage["143"] = " Port 143 is used to download email, so your login "
+ "details can be transmitted unencrypted.";
+
+
+ statusMessage["DANGEROUS_PORT"] = "QUESTIONMESSAGETraffic on Port PORT "
+ "has been rejected by Tor.";
+ statusMessage["DANGEROUS_VERSION"] = "QUESTIONMESSAGEYou are using Tor CURRENT."
+ " This version is REASON. "
+ "You should use Tor RECOMMENDED instead";
+ statusMessage["TOO_MANY_CONNECTIONS"] = "MESSAGETor has reached its native"
+ " limit on file descriptors: CURRENT. ";
+ statusMessage["BUG"] = "WARNINGMESSAGETor encountered an unexpected error: REASON. ";
+ statusMessage["CLOCK_SKEW"] = "WARNINGMESSAGEYour local clock is skewed by SKEW seconds. ";
+ statusMessage["BAD_LIBEVENT"] = "WARNINGMESSAGEYour version of libevent, VERSION, is BADNESS. ";
+ statusMessage["DIR_ALL_UNREACHABLE"] = "WARNINGMESSAGEAll known directory servers are unreachable. ";
+ statusMessage["ENOUGH_DIR_INFO"] = "WARNINGMESSAGETor has gathered enough info to start working. ";
+ statusMessage["NOT_ENOUGH_DIR_INFO"] = "WARNINGMESSAGETor does not have enough info to work. ";
+ statusMessage["CIRCUIT_ESTABLISHED"] = "WARNINGMESSAGETor has gathered enough info to start working. ";
+ statusMessage["CIRCUIT_NOT_ESTABLISHED"] = "WARNINGMESSAGETor does not have enough info to work. ";
+ statusMessage["SOCKS_BAD_HOSTNAME"] = "WARNINGMESSAGESome application gave us"
+ " a funny-looking hostname."
+ "Perhaps it is broken?";
+ statusMessage["NAMESERVER_ALL_DOWN"] = "WARNINGMESSAGEAll your configured nameservers appear to be down.";
+ statusMessage["DNS_HIJACKED"] = "WARNINGMESSAGEYour DNS requests are being hijacked by your provider.";
+ statusMessage["DNS_USELESS"] = "WARNINGMESSAGEYour DNS requests are being hijacked by your provider.";
+ statusMessage["BAD_SERVER_DESCRIPTOR"] = "WARNINGMESSAGEYour descriptor was rejected by DIRAUTH "
+ "because of REASON.";
+
+ m_statustip = i18n("<b>Name:</b> $SERVERNAME<br>"
+ "<b>IP:</b> $IP ($HOSTNAME) <b>Port:</b> $PORT<br>"
+ "<b>Country:</b> $COUNTRY <br>"
+ "<b>Version:</b> $VERSION <b>OS:</b> $OS<br>"
+ "<b>Published:</b> $PUBLISHED <b>Up Time:</b> $UPTIME minutes<br>"
+ "<center><b>Avg BW up to $INTERVALTIME</b></center>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
+ "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>24 hrs</b>"
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;<b>12 hrs</b>"
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;<b>6 hrs</b>"
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;<b>1 hr</b><br>"
+ "<b>Up</b>"
+ "&nbsp;&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;&nbsp;" // 1 space
+ "<font color='#990000'>$BWUP</font><br>"
+ "<b>Down</b>"
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "&nbsp;&nbsp;&nbsp;" // 1 space
+ "<font color='#1c9a1c'>$BWDN</font><br>"
+ );
+
+}
+
+void TorClient::configureServer( int orPort, int dirPort)
+{
+
+ sendToServer(QString("SETCONF ContactInfo=%1").arg(TorkConfig::contactInfo())) ;
+
+ sendToServer(QString("SETCONF ClientOnly=%1").arg(TorkConfig::clientOnly())) ;
+
+
+ if (TorkConfig::middleMan())
+ ( sendToServer(QString("SETCONF ExitPolicy=%1").arg(("\"reject *:*\"")))) ;
+ else
+ ( sendToServer(QString("SETCONF ExitPolicy=\"%2\"").arg( TorkConfig::exitPolicy().join(","))));
+
+ sendToServer(QString("SETCONF NickName=%1").arg(TorkConfig::nickName())) ;
+ if (!TorkConfig::clientOnly()){
+ //We send the orport configs together to avoid error messages from Tor
+ //telling us that one cannot be set without the other.
+ sendToServer(QString("SETCONF ORPort=%1 "
+ "ORListenAddress=0.0.0.0:%2")
+ .arg(orPort)
+ .arg(TorkConfig::oRListenAddress())) ;
+ //We send the dirport configs together to avoid error messages from Tor
+ //telling us that one cannot be set without the other.
+ sendToServer(QString("SETCONF DIRPort=%1 "
+ "DIRListenAddress=0.0.0.0:%2")
+ .arg(dirPort)
+ .arg(TorkConfig::dirListenAddress())) ;
+ sendToServer(QString("SETCONF BridgeRelay=%1").arg(TorkConfig::bridgeRelay())) ;
+ setBandwidth(QString("%1").arg(TorkConfig::bandwidthRate()),
+ QString("%1").arg(TorkConfig::bandwidthBurst()),
+ QString("%1").arg(TorkConfig::maxAdvertisedBandwidth()));
+ }else{
+ sendToServer(QString("SETCONF ORPort= ORListenAddress=")) ;
+ sendToServer(QString("SETCONF DirPort= DirListenAddress=")) ;
+ sendToServer(QString("SETCONF BridgeRelay=")) ;
+ }
+
+ if (TorkConfig::clientOnly())
+ resetClientReport();
+ TorkConfig::writeConfig();
+}
+void TorClient::clearNodes( )
+{
+
+ sendToServer("SETCONF ExcludeNodes=");
+ sendToServer("SETCONF ExitNodes=");
+ sendToServer("SETCONF EntryNodes=");
+ TorkConfig::setCurrentExcludeNodes("");
+ TorkConfig::setCurrentEntryNodes("");
+ TorkConfig::setCurrentExitNodes("");
+ emit copyOldConfig();
+}
+
+void TorClient::updateExcludeNodes( )
+{
+ ////kdDebug() << "SETCONF ExcludeNodes=" + TorkConfig::currentExcludeNodes().join(",") << endl;
+ sendToServer("SETCONF ExcludeNodes=" + TorkConfig::currentExcludeNodes().join(","));
+ sendToServer("GETCONF ExcludeNodes");
+ sendToServer("signal newnym");
+
+}
+
+void TorClient::updateExitNodes( )
+{
+ ////kdDebug() << "SETCONF ExitNodes=" + TorkConfig::currentExitNodes().join(",") << endl;
+ sendToServer("SETCONF ExitNodes=" + TorkConfig::currentExitNodes().join(","));
+ sendToServer("GETCONF ExitNodes");
+ sendToServer("signal newnym");
+
+}
+
+void TorClient::strictExitNodes( bool strict )
+{
+ if (strict)
+ sendToServer("SETCONF StrictExitNodes=1");
+ else
+ sendToServer("SETCONF StrictExitNodes=0");
+
+}
+
+void TorClient::safeLogging( bool safe )
+{
+ if (safe)
+ sendToServer("SETCONF SafeLogging=1");
+ else
+ sendToServer("SETCONF SafeLogging=0");
+
+}
+
+void TorClient::updateEntryNodes( )
+{
+ ////kdDebug() << "SETCONF EntryNodes=" + TorkConfig::currentEntryNodes().join(",") << endl;
+ sendToServer("SETCONF EntryNodes=" + TorkConfig::currentEntryNodes().join(","));
+ sendToServer("GETCONF EntryNodes");
+ sendToServer("signal newnym");
+
+}
+
+void TorClient::enableDNS( bool set )
+{
+ if (set)
+ sendToServer("SETCONF DNSPort=9999");
+ else
+ sendToServer("SETCONF DNSPort=");
+
+}
+
+void TorClient::enableTransPort( bool set )
+{
+ if (set)
+ sendToServer("SETCONF TransPort=9040");
+ else
+ sendToServer("SETCONF TransPort=");
+
+}
+
+void TorClient::fetchServerInfo( const QString & server)
+{
+
+ QString fp = getFPFromFPDigest(server);
+ fp.replace("$","");
+
+ kdDebug() << fp << endl;
+// emit showServerBW(fp);
+
+ sendToServer("GETINFO dir/server/fp/" + fp);
+}
+
+void TorClient::fetchServerInfoByNick( const QString & server)
+{
+
+
+ QString fp = getFPFromNickName(server);
+ fp.replace("$","");
+
+ sendToServer("GETINFO dir/server/fp/" + fp);
+}
+
+void TorClient::slotCheckTorNet()
+{
+ sendToServer("GETINFO ns/all");
+}
+
+void TorClient::slotCheckGuards()
+{
+
+ sendToServer("GETINFO entry-guards");
+
+}
+
+void TorClient::terminateTor()
+{
+
+ sendToServer("SIGNAL SHUTDOWN");
+
+}
+
+void TorClient::createService(const QString &dir, const QString &port)
+{
+ sendToServer(QString("setconf hiddenservicedir=\"%1\" hiddenserviceport=\"%2\"").arg(dir).arg(port));
+}
+
+void TorClient::authenticate()
+{
+
+// if (TorkConfig::defaultRunningNormalOptions()){
+// sendToServer("AUTHENTICATE");
+// return;
+// }
+
+ if (TorkConfig::cookieAuthentication()){
+ if (!readCookie()){
+ emit processQuestion("cookienotfound",
+ QString("Couldn't find authentication"
+ " cookie in %1/.tor!").arg(getenv("HOME")));
+ emit fatalError();
+ }
+ }else if (!TorkConfig::hashedControlPassword().isEmpty())
+ sendToServer(QString("AUTHENTICATE \"%1\"").arg(TorkConfig::hashedControlPassword()));
+ else{
+ sendToServer("AUTHENTICATE");
+ /* Lock the control port */
+ if (TorkConfig::generateRandomPassword()){
+ crypto_seed_rng();
+ sendToServer(QString("setconf HashedControlPassword=16:%2")
+ .arg(hashPassword(crypto_rand_string(16))));
+ }
+ }
+
+}
+
+
+bool TorClient::readCookie()
+{
+
+ QString hex;
+ char hx[2];
+
+ QStringList cookieCandidates;
+ cookieCandidates << QString("%1/.tor/control_auth_cookie").arg(getenv("HOME"));
+ cookieCandidates << QString("/var/lib/tor/control_auth_cookie");
+
+ for ( QStringList::Iterator it = cookieCandidates.begin(); it != cookieCandidates.end(); ++it ) {
+ QFile inf((*it));
+ if ( inf.open(IO_ReadOnly) ) {
+ QByteArray array = inf.readAll();
+ inf.close();
+ if (array.size() != 32)
+ continue;
+ for ( unsigned int i = 0; i < array.size(); i++ ) {
+ sprintf(hx,"%02x",array[i]);
+ hex += QString(hx).right(2);
+ }
+ sendToServer(QString("AUTHENTICATE %1").arg(hex));
+ return true;
+
+ }
+ }
+
+ return false;
+
+}
+
+void TorClient::readRouters()
+{
+
+ QFile inf(QString("%1/.tor/cached-status/7EA6EAD6FD83083C538F44038BBFA077587DD755").arg(getenv("HOME")));
+ if ( inf.open(IO_ReadOnly) ) {
+ QTextStream stream( &inf );
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine(); // line of text excluding '\n'
+ parseDirStatus(line);
+ }
+ inf.close();
+ }
+
+
+}
+
+void TorClient::newIdentity()
+{
+ kdDebug() << "changing id" << endl;
+ sendToServer("signal newnym");
+
+}
+
+void TorClient::bandwidth()
+{
+
+ sendToServer("usefeature verbose_names");
+ sendToServer("usefeature extended_events");
+ sendToServer("GETINFO ns/all");
+ sendToServer("GETINFO circuit-status");
+ sendToServer("GETINFO stream-status");
+ sendToServer("GETINFO orconn-status");
+ sendToServer("GETINFO version");
+ sendToServer("GETINFO status/enough-dir-info");
+ sendToServer("GETINFO status/good-server-descriptor");
+ sendToServer("GETINFO status/reachability-succeeded/or");
+
+ //Always enable for each session, user can disable through yes/no
+ //interface when warned - but only for that session.
+ m_portsToReject.clear();
+ m_portsToReject << "23" << "109" << "110" << "143";
+ sendToServer(QString("SETCONF WarnPlainTextPorts=%1")
+ .arg(m_portsToReject.join(",")));
+ sendToServer(QString("SETCONF RejectPlainTextPorts=%1")
+ .arg(m_portsToReject.join(",")));
+ sendToServer("SETEVENTS EXTENDED CIRC STREAM ORCONN NOTICE "
+ "WARN ERR ADDRMAP BW STREAM_BW NS STATUS_GENERAL "
+ "STATUS_CLIENT STATUS_SERVER GUARD");
+ sendToServer(QString("SETCONF __ReloadTorrcOnSIGHUP=0"));
+
+
+}
+
+void TorClient::handle250(const QString &lin)
+{
+
+
+ QString line = lin;
+
+ if ((line.contains("250-circuit-status="))){
+ if (line != ".")
+ parseEvent("CIRC",line.replace("250-circuit-status=",""));
+ else
+ m_expectingCircuitInfo = false;
+ }else if ((line.contains("250-orconn-status="))){
+ if (line != ".")
+ parseEvent("ORCONN",line.replace("250-orconn-status=",""));
+ else
+ m_expectingOrconnInfo = false;
+ }else if ((line.contains("250-stream-status="))){
+ if (line != ".")
+ parseEvent("STREAM",line.replace("250-stream-status=",""));
+ else
+ m_expectingStreamInfo = false;
+ }else if (line.contains("250+circuit-status="))
+ m_expectingCircuitInfo= true;
+ else if (line.contains("250+orconn-status="))
+ m_expectingOrconnInfo= true;
+ else if (line.contains("250+stream-status="))
+ m_expectingStreamInfo= true;
+ else if (line.contains("250+entry-guards="))
+ m_expectingGuardsInfo= true;
+ else if (line.contains("250+dir/server/fp/"))
+ m_expectingServerInfo= true;
+ else if (line.contains("250+extra-info/digest/"))
+ m_expectingServerInfo= true;
+ else if (line.contains("250+ns/all=")){
+ m_expectingDirStatus= true;
+ emit whatImDoing("Inspecting the Tor network..");
+ }else if (line.contains("250-ns/all=")){
+ emit warnNoServerInfo();
+ emit shouldIApplySettings();
+ }else if (line.contains("250-version="))
+ handleTorVersion(line.section("=",1,1));
+ else if (line.contains("250 BandwidthRate="))
+ m_CurBandwidthRate = line.section("=",1,1).toInt();
+ else if (line.contains("250 BandwidthBurst="))
+ m_CurBandwidthBurst = line.section("=",1,1).toInt();
+ else if (line.contains("250 MaxAdvertisedBandwidth="))
+ m_CurMaxAdvertisedBandwidth = line.section("=",1,1).toInt();
+ else if (line.contains("250 ExcludeNodes="))
+ TorkConfig::setCurrentExcludeNodes(QStringList::split(",",line.replace("250 ExcludeNodes=","")));
+ else if (line.contains("250 EntryNodes="))
+ TorkConfig::setCurrentEntryNodes(QStringList::split(",",line.replace("250 EntryNodes=","")));
+ else if (line.contains("250 ExitNodes="))
+ TorkConfig::setCurrentExitNodes(QStringList::split(",",line.replace("250 ExitNodes=","")));
+ else if (line.contains("250-status/circuit-established=1"))
+ updateClientReport("CIRCUIT_ESTABLISHED");
+ else if (line.contains("250-status/circuit-established=0"))
+ updateClientReport("CIRCUIT_NOT_ESTABLISHED");
+ else if (line.contains("250-status/enough-dir-info=1")){
+ updateClientReport("ENOUGH_DIR_INFO");
+ sendToServer("GETINFO status/circuit-established");
+ }else if (line.contains("250-status/enough-dir-info=0"))
+ updateClientReport("NOT_ENOUGH_DIR_INFO");
+ else if (line.contains("250-status/good-server-descriptor=1"))
+ updateServerReport("GOOD_SERVER_DESCRIPTOR", QString());
+ else if (line.contains("250-status/good-server-descriptor=0"))
+ updateServerReport("BAD_SERVER_DESCRIPTOR", QString());
+ else if (line.contains("250-status/reachability-succeeded/or=1"))
+ updateServerReport("REACHABILITY_SUCCEEDED", QString());
+ else if (line.contains("250-status/reachability-succeeded/or=0"))
+ updateServerReport("REACHABILITY_FAILED", QString());
+
+}
+
+void TorClient::socketReadyRead()
+{
+ QString line;
+ // read from the server
+ while ( socket->canReadLine() ) {
+
+ line = (socket->readLine()).stripWhiteSpace();
+
+ if (line.contains("250 OK")){
+ if (!m_controllerWorking){
+ bandwidth();
+ emit authenticated();
+ m_controllerWorking = true;
+ }
+ continue;
+ }
+
+ if (m_expectingDirStatus){
+ if (!(line == ".")){
+ parseDirStatus(line);
+ }else{
+ m_expectingDirStatus = false;
+ sendToServer("GETINFO entry-guards");
+ if (!m_firstloadcomplete)
+ emit shouldIApplySettings();
+ m_firstloadcomplete = true;
+ }
+ continue;
+ }else if ((m_expectingCircuitInfo)){
+ if (line != "."){
+ parseEvent("CIRC",line);
+ }else
+ m_expectingCircuitInfo = false;
+ continue;
+ }else if ((m_expectingOrconnInfo)){
+ if (line != "."){
+ parseEvent("ORCONN",line);
+ }else
+ m_expectingOrconnInfo = false;
+ continue;
+ }else if ((m_expectingStreamInfo)){
+ if (line != "."){
+ parseEvent("STREAM",line);
+ }else
+ m_expectingStreamInfo = false;
+ continue;
+ }else if (m_expectingServerInfo){
+ if (line != "."){
+ parseEvent("SERVER",line);
+ }else
+ m_expectingServerInfo = false;
+ continue;
+ }else if (m_expectingGuardsInfo){
+ if (line != "."){
+ parseEvent("GUARDS",line);
+ emit whatImDoing(i18n("Ready for use."));
+ }else{
+ m_expectingGuardsInfo = false;
+ }
+ continue;
+ }
+
+ if (line.contains("552 Unrecognized key \"ns/all\"")){
+ emit needAlphaVersion();
+ emit shouldIApplySettings();
+ continue;
+ }
+
+ QString code = line.left(3);
+
+ if (code == "250")
+ handle250(line);
+ else if (code == "650"){
+ if (line.contains("650+NS")){
+ m_expectingDirStatus= true;
+ continue;
+ }
+ QString eventType = line.section(" ",1,1);
+ QString eventInfo = line.section(" ",2);
+ if (eventInfo.contains("circuit_testing_failed"))
+ emit serverError();
+ parseEvent(eventType,eventInfo);
+ }else if (code == "552"){
+ QString eventInfo = line.section(" ",1);
+ emit displayError("Sorry!", eventInfo);
+ }else if (code == "514"){
+ QString eventInfo = line.section(" ",1);
+ emit processWarning("authenticationrequired", eventInfo);
+ emit fatalError();
+ }else if (code == "515"){
+ QString eventInfo = line.section(" ",1);
+ if (eventInfo.contains("Wrong length"))
+ emit processQuestion("cookierequired", eventInfo);
+ else{
+ if (TorkConfig::generateRandomPassword())
+ emit processQuestion("passwordlost", eventInfo);
+ else
+ emit processWarning("authenticationfailed", eventInfo);
+ }
+ //Only used by the first-run wizard
+ emit authenticationFailed();
+ }
+
+
+ }
+}
+
+void TorClient::parseEvent(const QString &type, const QString &info)
+{
+
+ if (info.isEmpty())
+ return;
+
+ if (type == "STREAM")
+ parseStream(info);
+ else if (type == "ORCONN")
+ parseORConn(info);
+ else if (type == "CIRC")
+ parseCircuit(info);
+ else if (type == "GUARDS")
+ parseGuards(info);
+ else if (type == "GUARD")
+ parseGuards(info.section(" ",1));
+ else if (type == "SERVER")
+ parseServer(info);
+ else if (type == "DIRSTATUS")
+ parseDirStatus(info);
+ else if (type == "BW")
+ parseBW(info);
+ else if (type == "STREAM_BW")
+ parseStreamBW(info);
+ else if (type.contains( "STATUS_"))
+ parseStatusGeneral(info);
+ else if (type == "ADDRMAP")
+ parseAddrmap(info);
+/* else if (type == "STREAM_PORT")
+ parseStreamPort(info);*/
+ else if ((type == "WARN") || (type == "NOTICE") || (type == "ERR"))
+ parseInfo(type,info);
+}
+
+void TorClient::parseStatusGeneral(const QString &info)
+{
+ QString severity = info.section(" ",0,0);
+ QString action = info.section(" ",1,1);
+ QString message = statusMessage[action];
+
+ if (!serverStatus[action].isEmpty())
+ updateServerReport(action, info);
+
+ if (!clientStatus[action].isEmpty())
+ updateClientReport(action);
+
+/* kdDebug() << info << endl;
+ kdDebug() << info.section(" ",2) << endl;*/
+ populateMessageFromStatusDetail(info.section(" ",2), message);
+
+ if (message.left(14) == "WARNINGMESSAGE"){
+ message.replace("WARNINGMESSAGE","");
+ emit processWarning(action, message);
+ }else{
+ message.replace("QUESTIONMESSAGE","");
+ emit processQuestion(action, message);
+ }
+
+}
+
+void TorClient::populateMessageFromStatusDetail(const QString &line, QString &message)
+{
+ QRegExp rx("[\\sA-Z0-9]+[=]([\\-\\:\\.\\(\\)a-zA-Z0-9]+|\\\"[\\-\\.\\,a-zA-Z0-9\\s]+\\\")");
+ int pos = 0;
+ while ( (pos = rx.search(line, pos)) != -1 ) {
+/* kdDebug() << rx.cap(0) << endl;*/
+ QString keyword = rx.cap(0).section("=",0,0).stripWhiteSpace();
+ QString value = rx.cap(0).section("=",1,1).stripWhiteSpace();
+ message.replace(keyword,value);
+ pos += rx.matchedLength();
+ if (keyword=="PORT"){
+ m_WarnedPorts << value;
+ message.append(portMessage[value]);
+ }
+ }
+}
+
+void TorClient::updateServerReport(const QString &message, const QString &info)
+{
+// kdDebug() << serverStatusIcon[message] << endl;
+// kdDebug() << message << endl;
+
+ //If we're back to being a client, ensure the server symbol is removed from the tray icon
+ if (TorkConfig::clientOnly()){
+ emit updateTrayIcon(serverStatusIcon[message].replace("server",""));
+ return;
+ }
+ if (!serverStatusIcon[message].isEmpty())
+ emit updateTrayIcon(serverStatusIcon[message]);
+
+ serverReport.remove("<font color='#990000'>Status Not Known</font>");
+ QString msg = serverStatus[message];
+
+ if (message.contains("EXTERNAL_ADDRESS")){
+ for ( QStringList::Iterator it = serverReport.begin(); it != serverReport.end(); ++it )
+ {
+ // XXX Fixme
+ if ((*it).contains("Using Address")){
+ serverReport.remove((*it));
+ break;
+ }
+ }
+ populateMessageFromStatusDetail(info.section(" ",2),msg);
+ }else if (message.contains("REACHABILITY")){
+ serverReport.remove(serverStatus["REACHABILITY_FAILED"]);
+ serverReport.remove(serverStatus["REACHABILITY_SUCCEEDED"]);
+ }else if (message.contains("SERVER_DESCRIPTOR")){
+ serverReport.remove(serverStatus["DIR_ALL_UNREACHABLE"]);
+ serverReport.remove(serverStatus["BAD_SERVER_DESCRIPTOR"]);
+ serverReport.remove(serverStatus["GOOD_SERVER_DESCRIPTOR"]);
+ }else // Prevent multiple reports
+ serverReport.remove(msg);
+
+ serverReport.append(msg);
+}
+
+void TorClient::updateClientReport(const QString &message)
+{
+ if (!clientStatusIcon[message].isEmpty() && (TorkConfig::clientOnly()))
+ emit updateTrayIcon(clientStatusIcon[clientStatus[message]]);
+ clientReport.clear();
+ clientReport.append(clientStatus[message]);
+}
+
+void TorClient::resetClientReport()
+{
+ emit updateTrayIcon(clientStatusIcon[clientReport.first()]);
+}
+
+void TorClient::parseBW(const QString &info)
+{
+
+ QString in = info.section(" ",0,0);
+ QString out = info.section(" ",1,1);
+
+ emit bwUpdate(in, out);
+
+}
+
+
+void TorClient::parseStreamBW(const QString &info)
+{
+
+ QString stream = info.section(" ",0,0);
+ /* Tor spec had it wrong way round! */
+ QString out = info.section(" ",1,1);
+ QString in = info.section(" ",2,2);
+
+ emit streamBwUpdate(stream, in, out);
+
+}
+
+
+void TorClient::parseStream(const QString &info)
+{
+
+
+ QString streamID = info.section(" ",0,0);
+ QString status = info.section(" ",1,1);
+ QString circID = info.section(" ",2,2);
+ QString Target = info.section(" ",3,3);
+
+ //We ignore REMAPs because we don't do anything with them
+ if (status == "REMAP")
+ return;
+
+ emit streamStatusUpdate(streamID, status, circID, Target, info);
+
+}
+
+void TorClient::parseServer(const QString &info)
+{
+
+ kdDebug() << "server info " << info << endl;
+ if (info.left(7) == "router "){
+ QString ip = info.section(" ",2,2);
+ QString cc;
+
+ GeoIP * gi = 0;
+
+ if (geoip_db)
+#ifndef EXTERNAL_GEOIP
+ gi = GeoIP_open(locate("data", "tork/geoip/GeoIP.dat").ascii(),0);
+#else
+ gi = GeoIP_new(GEOIP_STANDARD);
+#endif
+
+ if (gi){
+ int country_id = 0;
+ country_id = GeoIP_id_by_name(gi, ip);
+ cc = GeoIP_country_name[country_id];
+ GeoIP_delete(gi);
+ }else
+ cc = "a1";
+
+ m_statustiptmp = m_statustip;
+ m_statustipIP = ip;
+
+ m_statustiptmp.replace("$SERVERNAME",info.section(" ",1,1));
+ m_statustiptmp.replace("$IP",ip);
+ m_statustiptmp.replace("$PORT",info.section(" ",3,3));
+ m_statustiptmp.replace("$COUNTRY",cc);
+
+ }else if (info.left(8) == "platform"){
+ m_statustiptmp.replace("$VERSION",info.section(" ",1,2));
+ m_statustiptmp.replace("$OS",info.section(" ",4).section("{",0,0));
+
+ }else if (info.left(9) == "published"){
+ m_statustiptmp.replace("$PUBLISHED",info.section(" ",1));
+
+ }else if (info.left(6) == "uptime"){
+ //from the clever ktorrent
+ KLocale* loc = KGlobal::locale();
+ QTime t;
+ int nsecs = info.section(" ",1).toInt();
+ int ndays = (nsecs) / 86400;
+ t = t.addSecs(nsecs % 86400);
+ QString s = loc->formatTime(t,true,true);
+ if (ndays > 0)
+ s = i18n("1 day ","%n days ",ndays) + s;
+
+ m_statustiptmp.replace("$UPTIME",s);
+
+
+ }else if (info.left(20).contains("write-history")){
+ QStringList bwlist = QStringList::split(",",info.section(" ",-1));
+
+ QValueList<int> bws;
+ bws << 4 << 24 << 48 << bwlist.count();
+
+ QString bwup;
+ QString avgbw;
+ for ( QValueList<int>::Iterator it = bws.begin(); it != bws.end(); ++it ){
+ avgbw = calcBW(bwlist, (*it));
+ for (int i = avgbw.length(); i < 14; i++)
+ avgbw.append("&nbsp;&nbsp;");
+ bwup.append(avgbw);
+ }
+
+ m_statustiptmp.replace("$BWUP",bwup);
+
+ m_statustiptmp.replace("$INTERVALTIME", info.section(" ",2,3));
+
+ }else if (info.left(20).contains("read-history")){
+ QStringList bwlist = QStringList::split(",",info.section(" ",-1));
+ QValueList<int> bws;
+ bws << 4 << 24 << 48 << bwlist.count();
+
+ QString bwup;
+ QString avgbw;
+ for ( QValueList<int>::Iterator it = bws.begin(); it != bws.end(); ++it ){
+ avgbw = calcBW(bwlist, (*it));
+ for (int i = avgbw.length(); i < 14; i++)
+ avgbw.append("&nbsp;&nbsp;");
+ bwup.append(avgbw);
+ }
+ m_statustiptmp.replace("$BWDN",bwup);
+
+
+ if (m_currentTorVersion.left(3) == "0.2"){
+ m_resolvingServerAddress=true;
+ sendToServer("RESOLVE mode=reverse " + m_statustipIP);
+ }else{
+ m_statustiptmp.replace("($HOSTNAME)","");
+ emit displayServer("Server Info", m_statustiptmp);
+ }
+ }else if (info.left(25).contains("opt extra-info-digest")){
+ if (m_currentTorVersion.left(3) == "0.2"){
+ sendToServer("GETINFO extra-info/digest/" + info.section(" ",2));
+ }else{
+ m_statustiptmp.replace("($HOSTNAME)","");
+ m_statustiptmp.replace("$BWDN","Unavailable");
+ m_statustiptmp.replace("$BWUP","Unavailable");
+ m_statustiptmp.replace("$INTERVALTIME", "Unavailable");
+ emit displayServer("Server Info", m_statustiptmp);
+ }
+
+ }
+}
+
+void TorClient::parseAddrmap(const QString &info)
+{
+
+
+ QString type = info.section(" ",0,0);
+ QString address = info.section(" ",1,1);
+
+ // If this is a request to resolve a hostname/address from the traffic
+ // logs
+ if (logResolveList.contains(type)){
+ emit resolvedAddress(info);
+ logResolveList.remove(logResolveList.find(type));
+ return;
+ }
+
+ if (!m_resolvingServerAddress)
+ return;
+
+ // If this is a request to resolve a node name from the server list
+ if (type.startsWith("REVERSE")){
+ m_statustiptmp.replace("$HOSTNAME",address);
+ }else
+ m_statustiptmp.replace("$HOSTNAME","Cannot Resolve Hostname.");
+
+ emit displayServer("Server Info", m_statustiptmp);
+ m_resolvingServerAddress = false;
+
+}
+
+void TorClient::parseGuards(const QString &info)
+{
+
+ QString fp_identity = info.section(" ",0,0);
+ QString status = info.section(" ",1,1);
+ QRegExp rx("(\\$[A-Z0-9]{40})");
+ rx.search(fp_identity);
+ QString server = getNickNameFromFP(rx.cap(0));
+
+ if (!server.isEmpty()){
+ emit guardStatusUpdate(server, status);
+ }
+}
+
+void TorClient::parseCircuit(const QString &info)
+{
+
+ if (info.contains("FAILED"))
+ emit displayError("Circuit Failed - "+info.section(" ",3,3).replace("REASON=",""), "Circuit: " + info.section(" ",2,2));
+
+ QString circuitID = info.section(" ",0,0).stripWhiteSpace();
+ QString status = info.section(" ",1,1).stripWhiteSpace();
+ QString path = info.section(" ",2,2).stripWhiteSpace();
+
+ //Get the FP Digest (if any) of the last server in the circuit
+ QString exit;
+ QRegExp rx("(\\$[A-Z0-9]{40})");
+ int count = 0;
+ int pos = 0;
+ while ( (pos = rx.search(path, pos)) != -1 ) {
+ count++;
+ pos += rx.matchedLength();
+ exit = rx.cap(0);
+ }
+ if (!exit.isEmpty())
+ exit = getFPDigestFromFP(exit);
+ //Strip out the FPs from the circuit, if any
+ path.replace(QRegExp("(\\$[A-Z0-9]{40})(~|=)"),"");
+
+ emit circuitStatusUpdate(circuitID, status, path, exit);
+
+}
+
+void TorClient::parseORConn(const QString &info)
+{
+ QString serverID = info.section(" ",0,0);
+ QString status = info.section(" ",1,1);
+
+ if (serverID.startsWith("$")){
+ QString server = getNickNameFromFP(serverID);
+ if (!server.isEmpty())
+ serverID = server;
+ }
+
+ if (!status.contains("NEW")){
+ serverID.replace(QRegExp("^[A-Z0-9$=~]{42}"),"");
+ emit ORStatusUpdate(serverID, status);
+ }
+}
+
+void TorClient::parseInfo(const QString &type,const QString &info)
+{
+
+ QString message = info;
+ message.replace(QRegExp("^[a-zA-Z0-9_]+\\(\\):"),"");
+// QString summary = info.section(":",0,0);
+// QString data = info.section(":",1);
+
+ if (info.contains("Servers unavailable"))
+ emit displayServer("Server Info", "<b>Server appears to be down!</b>");
+ emit infoUpdate(type, message, QString());
+
+}
+
+void TorClient::updateCandidateServers(const QString &path)
+{
+
+ QStringList servers = QStringList::split(",", path);
+ QStringList existingServers = TorkConfig::serversHistory();
+ for ( QStringList::Iterator it = servers.begin(); it != servers.end(); ++it )
+ {
+ if ((*it).isEmpty())
+ continue;
+ if (existingServers.find(*it) == existingServers.end())
+ existingServers.append(*it);
+ }
+ TorkConfig::setServersHistory(existingServers);
+
+ TorkConfig::writeConfig();
+}
+
+void TorClient::attemptAttach(const QString &circid, const QString &streamid)
+{
+
+ QStringList streams = QStringList::split( " ", streamid);
+ for ( QStringList::Iterator it = streams.begin(); it != streams.end(); ++it )
+ {
+ if ((*it).isEmpty())
+ continue;
+ sendToServer(QString("ATTACHSTREAM %1 %2").arg(*it).arg(circid));
+ }
+
+}
+
+void TorClient::attemptExtendCircuit(const QString &circid, const QString &serverlist, bool usefp)
+{
+
+
+ QStringList servers = QStringList::split( " ", serverlist);
+ QStringList circuitlist;
+ for ( QStringList::Iterator it = servers.begin(); it != servers.end(); ++it )
+ {
+ if ((*it).isEmpty())
+ continue;
+ if (usefp)
+ circuitlist.append(getFPFromFPDigest((*it)));
+ else
+ circuitlist.append((*it));
+ }
+
+ QString circuit = circuitlist.join(",");
+ sendToServer(QString("EXTENDCIRCUIT %1 %2").arg(circid).arg(circuit));
+}
+
+void TorClient::attemptCreateCircuit(const QString &serverlist, bool usefp)
+{
+
+ QStringList servers = QStringList::split( " ", serverlist);
+ QStringList circuitlist;
+ for ( QStringList::Iterator it = servers.begin(); it != servers.end(); ++it )
+ {
+ if ((*it).isEmpty())
+ continue;
+ if (usefp)
+ circuitlist.append(getFPFromFPDigest((*it)));
+ else
+ circuitlist.append((*it));
+ }
+
+ QString circuit = circuitlist.join(",");
+ sendToServer(QString("EXTENDCIRCUIT 0 %1").arg(circuit));
+}
+
+void TorClient::attemptCloseStream(const QString &streamid)
+{
+ sendToServer(QString("CLOSESTREAM %1 1").arg(streamid));
+}
+
+void TorClient::attemptAttachStreams( bool attachStreams)
+{
+ sendToServer(QString("SETCONF __LeaveStreamsUnattached=%1").arg(attachStreams));
+}
+
+void TorClient::attemptCloseCircuit(const QString &circuitid)
+{
+ sendToServer(QString("CLOSECIRCUIT %1").arg(circuitid));
+}
+
+
+void TorClient::updatePrevConfig(PrevConfig::PrevConfigList prevlist)
+{
+
+ m_previtems = prevlist;
+}
+
+
+void TorClient::applySettingsToRunningTor()
+{
+
+ //FIXME: use function pointers and a list to do this
+
+
+ switch (TorkConfig::quickConfigure()) {
+ case 0 : //Tor client and server with default settings
+ return;
+ case 1 : //Tor client with default settings
+ return;
+ case 2 : //Tor server with default settings
+ return;
+ case 3 : //Tor server with default settings
+ return;
+ case 4 : //Tor server with default settings
+ return;
+ default:
+ break;
+ }
+
+// kdDebug() << "1" << endl;
+ KConfigSkeletonItem::List items = TorkConfig::self()->items();
+ KConfigSkeletonItem::List::ConstIterator it;
+
+ for( it = items.begin(); it != items.end(); ++it ) {
+ if (elementShouldBeUsed((*it))){
+ if (noSpecialProcessing((*it))){
+ PrevConfig::PrevConfigList::iterator mit;
+ QVariant oldvalue;
+ for( mit = m_previtems.begin(); mit != m_previtems.end(); ++mit ) {
+ if ((*mit).name() == (*it)->name()){
+ oldvalue = (*mit).property();
+ continue;
+ }
+ }
+
+
+ if ( (*it)->property().type() == QVariant::String ) {
+ if ((oldvalue !=(*it)->property())){
+ ( sendToServer(QString("SETCONF %1=%2").arg((*it)->name()).arg((*it)->property().toString())));
+ }
+ }else if ( (*it)->property().type() == QVariant::StringList ) {
+ if ((oldvalue !=(*it)->property())){
+ ( sendToServer(QString("SETCONF %1=\"%2\"").arg((*it)->name()).arg( (*it)->property().toStringList().join(","))));
+ }
+ }else if ( (*it)->property().type() == QVariant::Int ) {
+ if ((oldvalue !=(*it)->property())){
+ ( sendToServer(QString("SETCONF %1=%2").arg((*it)->name()).arg( (*it)->property().toString())));
+ }
+ }else if ( (*it)->property().type() == QVariant::Bool ) {
+ if ((oldvalue !=(*it)->property())){
+ ( sendToServer(QString("SETCONF %1=%2").arg((*it)->name()).arg( (*it)->property().toInt())));
+ }
+ }
+
+ }
+ }
+ }
+
+ if (TorkConfig::useProxy()){
+ if ((TorkConfig::httpProxyPort() > 0) && (!TorkConfig::httpProxyHost().isEmpty()))
+ ( sendToServer(QString("SETCONF HttpProxy=%1:%2").arg(TorkConfig::httpProxyHost()).arg(TorkConfig::httpProxyPort()))) ;
+ if ((TorkConfig::httpsProxyPort() > 0) && (!TorkConfig::httpsProxyHost().isEmpty()))
+ ( sendToServer(QString("SETCONF HttpsProxy=%1:%2").arg(TorkConfig::httpsProxyHost()).arg(TorkConfig::httpsProxyPort()))) ;
+
+ if ((!TorkConfig::httpProxyAuthenticatorUserName().isEmpty()) && (!TorkConfig::httpProxyAuthenticatorPassword().isEmpty()))
+ ( sendToServer(QString("SETCONF HttpProxyAuthenticator=%1:%2").arg(TorkConfig::httpProxyAuthenticatorUserName()).arg(TorkConfig::httpProxyAuthenticatorPassword())));
+
+ if ((!TorkConfig::httpsProxyAuthenticatorUserName().isEmpty()) && (!TorkConfig::httpsProxyAuthenticatorPassword().isEmpty()))
+ ( sendToServer(QString("SETCONF HttpsProxyAuthenticator=%1:%2").arg(TorkConfig::httpsProxyAuthenticatorUserName() ).arg(TorkConfig::httpsProxyAuthenticatorPassword())));
+ }else{
+ ( sendToServer(QString("SETCONF HttpProxy=")));
+ ( sendToServer(QString("SETCONF HttpsProxy=")));
+ ( sendToServer(QString("SETCONF HttpProxyAuthenticator=")));
+ ( sendToServer(QString("SETCONF HttpsProxyAuthenticator=")));
+ }
+
+ if ((!TorkConfig::sOCKSBindAddressHost().isEmpty()) && (TorkConfig::sOCKSBindAddressPort() > -1))
+ ( sendToServer(QString("SETCONF SOCKSListenAddress=%1:%2").arg(TorkConfig::sOCKSBindAddressHost()).arg( TorkConfig::sOCKSBindAddressPort()))) ;
+
+ if ((TorkConfig::sOCKSBindAddressHost().isEmpty()) && (TorkConfig::sOCKSBindAddressPort() > -1))
+ ( sendToServer(QString("SETCONF SOCKSPort=%2").arg(TorkConfig::sOCKSBindAddressPort()))) ;
+
+ emit copyOldConfig();
+ emit makeTorkStoppable();
+ sendToServer(QString("GETCONF ExcludeNodes")) ;
+ sendToServer(QString("GETCONF ExitNodes")) ;
+ sendToServer(QString("GETCONF EntryNodes")) ;
+
+}
+
+bool TorClient::elementShouldBeUsed(const KConfigSkeletonItem* it)
+{
+
+ //Maxmin Settings are always applied, defaults if 'let Tor decide' selected.
+ if (((*it).group() == "MaxMin") ||
+ ((!(TorkConfig::clientOnly())) && ((*it).group() == "DefaultServerAddress")) ||
+ ((*it).group() == "FirewallEvasion") ||
+ ((*it).group() == "Censorship") ||
+ (((*it).group() == "RunningSpecial")) ||
+ (((*it).group() == "Servers")) ||
+ // Server settings are applied by calling configureServer() later
+ //(((*it).group() == "MyServer")) ||
+ (((*it).group() == "Usability")) ||
+ (((*it).group() == "UsingTor")) ||
+ (((*it).group() == "MyHiddenServices")) ||
+ //Serverperformance Settings are always applied, defaults if 'let Tor decide' selected.
+ (((*it).group() == "ServerPerformance")))
+ return true;
+
+
+ //Excluded:
+ //((*it).group() == "RunningNormal")) - Because they aren't appropriate for a running Tor
+
+ return false;
+}
+
+bool TorClient::noSpecialProcessing(const KConfigSkeletonItem* it)
+{
+
+ if (((*it).name() == "PublishServerDescriptor") && (TorkConfig::bridgeRelay())){
+ sendToServer(QString("setconf PublishServerDescriptor=bridge"));
+ return false;
+ }
+
+ if ((*it).name() == "HashedControlPassword"){
+ if ((*it).property().toString().isEmpty() &&
+ (!TorkConfig::cookieAuthentication()) &&
+ TorkConfig::generateRandomPassword()){
+ crypto_seed_rng();
+ sendToServer(QString("setconf %1=16:%2")
+ .arg((*it).name())
+ .arg(hashPassword(crypto_rand_string(16))));
+ return false;
+ }
+ return true;
+ }
+
+ if ((*it).group() == "DefaultServerAddress"){
+ if ((*it).name() == "ORPort")
+ ( sendToServer(QString("SETCONF %1=%2").arg((*it).name())
+ .arg( (*it).property().toString())));
+ return false;
+ }
+
+ if (((*it).name() == "BandwidthBurst") || ((*it).name() == "BandwidthRate")){
+ ( sendToServer(QString("SETCONF BandwidthBurst=%1KB BandwidthRate=%2KB")
+ .arg(TorkConfig::bandwidthBurst()).arg(TorkConfig::bandwidthRate())));
+ getBandwidth();
+ return false;
+ }
+
+ if ((*it).name() == "MaxAdvertisedBandwidth"){
+ ( sendToServer(QString("SETCONF %1=%2KB").arg((*it).name()).arg( (*it).property().toString())));
+ getBandwidth();
+ return false;
+ }
+
+ if ((*it).name() == "AccountingMax"){
+ ( sendToServer(QString("SETCONF %1=\"%2 bytes\"").arg((*it).name()).arg( ((*it).property().toInt() * 1024 * 1024))));
+ return false;
+ }
+
+ if ((*it).name() == "AccountingStart"){
+ if ((*it).property().toString() == "day")
+ ( sendToServer(QString("SETCONF %1=\"%2 00:00\"").arg((*it).name()).arg( (*it).property().toString())));
+ else
+ ( sendToServer(QString("SETCONF %1=\"%2 1 00:00\"").arg((*it).name()).arg( (*it).property().toString())));
+ return false;
+ }
+
+
+ if ((*it).name() == "KeepalivePeriod"){
+ if (!TorkConfig::reachableAddresses().isEmpty()){
+ ( sendToServer(QString("SETCONF %1=%2").arg((*it).name()).arg( ((*it).property().toInt() * 60)))) ;
+ }
+ return false;
+ }
+
+ if ((*it).name() == "TrackHostExits"){
+ if (!TorkConfig::trackHostExits().isEmpty()){
+ ( sendToServer(QString("SETCONF %1=%2").arg((*it).name()).arg( ((*it).property().toStringList().join(","))))) ;
+ if (TorkConfig::trackHostExitsExpire() > 0)
+ ( sendToServer(QString("SETCONF TrackHostExitsExpire=%2").arg((TorkConfig::trackHostExitsExpire() * 60)))) ;
+ }
+ return false;
+ }
+
+
+ if ((*it).name() == "SOCKSBindAddressMany"){
+
+ if (!TorkConfig::sOCKSBindAddressMany().isEmpty()){
+ QStringList socksbind = TorkConfig::sOCKSBindAddressMany();
+ for ( QStringList::Iterator it = (socksbind).begin(); it != (socksbind).end(); it++ )
+ {
+ if ((*it).isEmpty())
+ continue;
+ ( sendToServer(QString("SETCONF SOCKSListenAddress=%2").arg((*it)))) ;
+ }
+ }
+ return false;
+ }
+
+ if ((*it).name() == "ExitPolicy"){
+ if (TorkConfig::middleMan())
+ ( sendToServer(QString("SETCONF ExitPolicy=%1").arg(("\"reject *:*\"")))) ;
+ else
+ ( sendToServer(QString("SETCONF %1=\"%2\"").arg((*it).name()).arg( (*it).property().toStringList().join(","))));
+ return false;
+ }
+
+
+ if ((*it).name() == "HiddenServices"){
+ QStringList hiddenServices = TorkConfig::hiddenServices();
+ QString allservices;
+ for ( QStringList::Iterator it = (hiddenServices).begin(); it != (hiddenServices).end(); it++ )
+ {
+ if ((*it).isEmpty())
+ continue;
+ allservices += (QString("HiddenServiceDir=\"%1\" HiddenServicePort=\"%2 %3\" ").arg((*it).section("\n",-1)).arg((*it).section("\n",-4,-4)).arg((*it).section("\n",-3,-3))) ;
+ }
+ if (!allservices.isEmpty())
+ ( sendToServer(QString("SETCONF %1").arg(allservices))) ;
+ else
+ ( sendToServer(QString("SETCONF HiddenServiceDir= HiddenServicePort="))) ;
+
+ return false;
+ }
+
+ if ((TorkConfig::useBridges()) && ((*it).name() == "Bridge")){
+
+ QStringList bridges = TorkConfig::bridge();
+ QString allbridges;
+ for ( QStringList::Iterator it = (bridges).begin(); it != (bridges).end(); it++ )
+ {
+ if ((*it).isEmpty())
+ continue;
+ allbridges += (QString("Bridge=\"%1\" ")
+ .arg((*it))) ;
+ }
+ if (!allbridges.isEmpty())
+ ( sendToServer(QString("SETCONF %1").arg(allbridges))) ;
+ else
+ ( sendToServer(QString("SETCONF Bridge="))) ;
+
+ return false;
+ }
+
+ if ((*it).name() == "MyFamily"){
+
+ QStringList family = TorkConfig::myFamily();
+ QStringList allfamily;
+ for ( QStringList::Iterator it = (family).begin(); it != (family).end(); it++ )
+ {
+ if ((*it).isEmpty())
+ continue;
+ QString node = "$"+getFPFromFPDigest((*it).section("-",1,1));
+ allfamily.append(node) ;
+ }
+ if (!allfamily.isEmpty())
+ ( sendToServer(QString("SETCONF MyFamily=%1").arg(allfamily.join(",")))) ;
+ else
+ ( sendToServer(QString("SETCONF MyFamily="))) ;
+
+ return false;
+ }
+
+ if ((*it).name() == "MapAddress"){
+
+ QStringList maps = TorkConfig::mapAddress();
+ for ( QStringList::Iterator it = (maps).begin();
+ it != (maps).end(); it++ )
+ {
+ if ((*it).isEmpty())
+ continue;
+ ( sendToServer(QString("SETCONF MapAddress=%2").arg((*it)))) ;
+ }
+ return false;
+ }
+
+ if ((!TorkConfig::fascistFirewall()) && ((*it).name() == "ReachableAddresses")){
+ ( sendToServer(QString("SETCONF ReachableAddresses="))) ;
+ return false;
+ }
+ return true;
+}
+
+
+void TorClient::cleanUp()
+{
+
+ if (TorkConfig::hashedControlPassword().isEmpty() &&
+ (!TorkConfig::cookieAuthentication()) &&
+ TorkConfig::generateRandomPassword()){
+ sendToServer(QString("setconf HashedControlPassword="));
+ socket->flush();
+ }
+}
+
+TorClient::~TorClient()
+{
+
+}
+
+void TorClient::parseDirStatus(const QString &info)
+{
+
+
+ if (info.left(2) == "r "){
+ ds_identity = info.section(" ",2,2);
+ ds_ip = info.section(" ",6,6);
+ ds_server = info.section(" ",1,1);
+ ds_date = info.section(" ",4,4);
+ return;
+ }
+
+ if (info.left(2) == "s "){
+
+ if (QDate::currentDate().daysTo(QDate(ds_date.left(4).toInt(),
+ ds_date.mid(5,2).toInt(),ds_date.right(2).toInt())) > -30) {
+ if (server(ds_identity).isEmpty())
+ storeServer(ds_server,ds_identity);
+
+ ds_statuses = info;
+ emit updateServerStatus(ds_ip, ds_identity, ds_server, ds_statuses);
+ }
+ }
+
+}
+
+bool TorClient::isControllerWorking()
+{
+ return m_controllerWorking;
+
+}
+
+void TorClient::setBandwidth(const QString &rate, const QString &burst, const QString &max)
+{
+ ( sendToServer(QString("SETCONF BandwidthRate=%2KB BandwidthBurst=%2KB")
+ .arg(rate).arg(burst)));
+ if (!max.isEmpty())
+ ( sendToServer(QString("SETCONF MaxAdvertisedBandwidth=%2KB").arg(max)));
+ getBandwidth();
+}
+
+void TorClient::getBandwidth()
+{
+ ( sendToServer(QString("GETCONF BandwidthRate")));
+ ( sendToServer(QString("GETCONF BandwidthBurst")));
+ ( sendToServer(QString("GETCONF MaxAdvertisedBandwidth")));
+}
+
+void TorClient::handleTorVersion( const QString &caption)
+{
+ m_currentTorVersion = caption;
+ if (m_currentTorVersion.left(3) == "0.2")
+ sendToServer("SETCONF DownloadExtraInfo=1");
+ emit setTorCaption(caption);
+}
+
+void TorClient::closeAllCircuits( QListView* &circuitList)
+{
+ QListViewItemIterator cit(circuitList);
+ while ( cit.current() ) {
+ attemptCloseCircuit(cit.current()->text(0));
+ ++cit;
+ }
+}
+
+void TorClient::assignPortToRemove()
+{
+ //called by the warning message to get the port to remove in case
+ // user requests it.
+ if (m_WarnedPorts[0].isNull())
+ return;
+ kdDebug() << "warnedports " << m_WarnedPorts[0] << endl;
+ m_portToRemove = m_WarnedPorts[0];
+ kdDebug() << "porttoremove" << m_portToRemove << endl;
+ m_WarnedPorts.pop_front();
+ kdDebug() << "porttoremove" << m_portToRemove << endl;
+
+}
+
+void TorClient::allowPlainTextPorts()
+{
+
+ kdDebug() << "m_portsToReject " << m_portsToReject << endl;
+
+ m_portsToReject.remove(m_portsToReject.find(m_portToRemove));
+ sendToServer(QString("SETCONF WarnPlainTextPorts=%1")
+ .arg(m_portsToReject.join(",")));
+ sendToServer(QString("SETCONF RejectPlainTextPorts=%1")
+ .arg(m_portsToReject.join(",")));
+}
+
+void TorClient::resolveAddress(const QString &address)
+{
+ QRegExp rx("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
+ rx.search(address);
+ QString tmp = rx.cap(0);
+ if (tmp.isEmpty()) {
+ sendToServer("RESOLVE " + address);
+ logResolveList << address;
+ }else{
+ sendToServer("RESOLVE mode=reverse " + tmp);
+ logResolveList << QString("REVERSE[%1]").arg(tmp);
+ }
+
+}
+
+#include "torclient.moc"
+