Vidalia  0.2.17
TorControl.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
00004 **  you did not receive the LICENSE file with this file, you may obtain it
00005 **  from the Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
00007 **  including this file, may be copied, modified, propagated, or distributed 
00008 **  except according to the terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file TorControl.cpp
00013 ** \brief Object for interacting with the Tor process and control interface
00014 */
00015 
00016 #include "TorControl.h"
00017 #include "RouterDescriptor.h"
00018 #include "ProtocolInfo.h"
00019 #include "RouterStatus.h"
00020 #include "file.h"
00021 #include "stringutil.h"
00022 
00023 #include <QHostAddress>
00024 #include <QVariantMap>
00025 
00026 
00027 /** Default constructor */
00028 TorControl::TorControl(ControlMethod::Method method)
00029 {
00030 #define RELAY_SIGNAL(src, sig) \
00031   QObject::connect((src), (sig), this, (sig))
00032 
00033   /* Create a TorEvents object to receive and parse asynchronous events
00034    * from Tor's control port, and relay them as external signals from
00035    * this TorControl object. */
00036   _eventHandler = new TorEvents(this);
00037   RELAY_SIGNAL(_eventHandler, SIGNAL(circuitEstablished()));
00038   RELAY_SIGNAL(_eventHandler, SIGNAL(dangerousTorVersion(tc::TorVersionStatus,
00039                                                          QString, QStringList)));
00040   RELAY_SIGNAL(_eventHandler, SIGNAL(addressMapped(QString,QString,QDateTime)));
00041   RELAY_SIGNAL(_eventHandler, SIGNAL(bandwidthUpdate(quint64, quint64)));
00042   RELAY_SIGNAL(_eventHandler, SIGNAL(circuitStatusChanged(Circuit)));
00043   RELAY_SIGNAL(_eventHandler, SIGNAL(streamStatusChanged(Stream)));
00044   RELAY_SIGNAL(_eventHandler, SIGNAL(newDescriptors(QStringList)));
00045   RELAY_SIGNAL(_eventHandler, SIGNAL(logMessage(tc::Severity, QString)));
00046   RELAY_SIGNAL(_eventHandler, SIGNAL(dangerousPort(quint16, bool)));
00047   RELAY_SIGNAL(_eventHandler, SIGNAL(socksError(tc::SocksError, QString)));
00048   RELAY_SIGNAL(_eventHandler, SIGNAL(bootstrapStatusChanged(BootstrapStatus)));
00049   RELAY_SIGNAL(_eventHandler, SIGNAL(clockSkewed(int, QString)));
00050   RELAY_SIGNAL(_eventHandler, SIGNAL(bug(QString)));
00051   RELAY_SIGNAL(_eventHandler, SIGNAL(dnsHijacked()));
00052   RELAY_SIGNAL(_eventHandler, SIGNAL(dnsUseless()));
00053   RELAY_SIGNAL(_eventHandler,
00054                SIGNAL(externalAddressChanged(QHostAddress, QString)));
00055   RELAY_SIGNAL(_eventHandler,
00056                SIGNAL(checkingOrPortReachability(QHostAddress, quint16)));
00057   RELAY_SIGNAL(_eventHandler,
00058                SIGNAL(orPortReachabilityFinished(QHostAddress,quint16,bool)));
00059   RELAY_SIGNAL(_eventHandler,
00060                SIGNAL(checkingDirPortReachability(QHostAddress, quint16)));
00061   RELAY_SIGNAL(_eventHandler,
00062                SIGNAL(dirPortReachabilityFinished(QHostAddress,quint16,bool)));
00063   RELAY_SIGNAL(_eventHandler,
00064                SIGNAL(serverDescriptorRejected(QHostAddress, quint16, QString)));
00065   RELAY_SIGNAL(_eventHandler,
00066                SIGNAL(serverDescriptorAccepted(QHostAddress, quint16)));
00067   RELAY_SIGNAL(_eventHandler, SIGNAL(serverDescriptorAccepted()));
00068 
00069   /* Create an instance of a connection to Tor's control interface and give
00070    * it an object to use to handle asynchronous events. */
00071   _controlConn = new ControlConnection(method, _eventHandler);
00072   RELAY_SIGNAL(_controlConn, SIGNAL(connected()));
00073   RELAY_SIGNAL(_controlConn, SIGNAL(connectFailed(QString)));
00074   QObject::connect(_controlConn, SIGNAL(disconnected()),
00075                    this, SLOT(onDisconnected()));
00076 
00077   /* Create an object used to start and stop a Tor process. */
00078   _torProcess = new TorProcess(this);
00079   RELAY_SIGNAL(_torProcess, SIGNAL(started()));
00080   RELAY_SIGNAL(_torProcess, SIGNAL(startFailed(QString)));
00081   QObject::connect(_torProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
00082                    this, SLOT(onStopped(int, QProcess::ExitStatus)));
00083   QObject::connect(_torProcess, SIGNAL(log(QString, QString)),
00084                    this, SLOT(onLogStdout(QString, QString)));
00085 
00086 #if defined(Q_OS_WIN32)
00087   _torService = new TorService(this);
00088   RELAY_SIGNAL(_torService, SIGNAL(started()));
00089   RELAY_SIGNAL(_torService, SIGNAL(startFailed(QString)));
00090   QObject::connect(_torService, SIGNAL(finished(int, QProcess::ExitStatus)),
00091                    this, SLOT(onStopped(int, QProcess::ExitStatus)));
00092 #endif
00093 #undef RELAY_SIGNAL
00094   _method = method;
00095 }
00096 
00097 /** Default destructor */
00098 TorControl::~TorControl()
00099 {
00100   /* Disconnect the control socket */
00101   if (isConnected()) {
00102     disconnect();
00103   }
00104   /* If we started our own Tor, stop it now */
00105   if (isVidaliaRunningTor()) {
00106     stop();
00107   }
00108   delete _controlConn;
00109 }
00110 
00111 /** Start the Tor process using the executable <b>tor</b> and the list of
00112  * arguments in <b>args</b>. */
00113 void
00114 TorControl::start(const QString &tor, const QStringList &args)
00115 {
00116   if (isRunning()) {
00117     emit started();
00118   } else {
00119 #if defined(Q_OS_WIN32)
00120     /* If the Tor service is installed, run that. Otherwise, start a new
00121      * Tor process. */
00122     if (TorService::isSupported() && _torService->isInstalled())
00123       _torService->start();
00124     else
00125       _torProcess->start(expand_filename(tor), args);
00126 #else
00127     /* Start a new Tor process */
00128     _torProcess->start(expand_filename(tor), args);
00129 #endif
00130   }
00131 }
00132 
00133 /** Stop the Tor process. */
00134 bool
00135 TorControl::stop(QString *errmsg)
00136 {
00137   bool rc = false;
00138   if (_controlConn->isConnected())
00139     rc = signal(TorSignal::Halt, errmsg);
00140   if (!rc)
00141     rc = _torProcess->stop(errmsg);
00142   return rc;
00143 }
00144 
00145 /** Emits a signal that the Tor process stopped */
00146 void
00147 TorControl::onStopped(int exitCode, QProcess::ExitStatus exitStatus)
00148 {
00149   if (_controlConn->status() == ControlConnection::Connecting)
00150     _controlConn->cancelConnect();
00151 
00152   emit stopped();
00153   emit stopped(exitCode, exitStatus);
00154 }
00155 
00156 /** Detects if the Tor process is running under Vidalia. Returns true if
00157  * Vidalia owns the Tor process, or false if it was an independent Tor. */
00158 bool
00159 TorControl::isVidaliaRunningTor()
00160 {
00161   return (_torProcess->state() != QProcess::NotRunning);
00162 }
00163 
00164 /** Detect if the Tor process is running. */
00165 bool
00166 TorControl::isRunning()
00167 {
00168   return (_torProcess->state() != QProcess::NotRunning
00169             || _controlConn->isConnected());
00170 }
00171 
00172 /** Stops reading log messages from the Tor process's stdout. This has no
00173  * effect if isVidaliaRunningTor() is false. */
00174 void
00175 TorControl::closeTorStdout()
00176 {
00177   if (_torProcess)
00178     _torProcess->closeStdout();
00179 }
00180 
00181 /** Called when Tor has printed a log message to stdout. */
00182 void
00183 TorControl::onLogStdout(const QString &severity, const QString &message)
00184 {
00185   emit logMessage(tc::severityFromString(severity), message.trimmed());
00186 }
00187 
00188 /** Connect to Tor's control port. The control port to use is determined by
00189  * Vidalia's configuration file. */
00190 void
00191 TorControl::connect(const QHostAddress &address, quint16 port)
00192 {
00193   _controlConn->connect(address, port);
00194 }
00195 
00196 /** Connect to Tor's control socket. The control socket to use is determined by
00197  * Vidalia's configuration file. */
00198 void
00199 TorControl::connect(const QString &path)
00200 {
00201   _controlConn->connect(path);
00202 }
00203 
00204 /** Disconnect from Tor's control port */
00205 void
00206 TorControl::disconnect()
00207 {
00208   if (isConnected())
00209     _controlConn->disconnect();
00210 }
00211 
00212 void
00213 TorControl::getBootstrapPhase()
00214 {
00215   ControlCommand cmd("GETINFO", "status/bootstrap-phase");
00216   ControlReply reply;
00217   QString str;
00218 
00219   if (!send(cmd, reply, &str)) {
00220     return;
00221   }
00222 
00223   bool ok;
00224   QHash<QString, QString> args;
00225   args = string_parse_keyvals(reply.getMessage(), &ok);
00226 
00227   if(!ok)
00228     return;
00229 
00230   tc::Severity severity = tc::severityFromString(args.value("status/bootstrap-phase"));
00231   BootstrapStatus status
00232     = BootstrapStatus(severity,
00233                       BootstrapStatus::statusFromString(args.value("TAG")),
00234                       args.value("PROGRESS").toInt(),
00235                       args.value("SUMMARY"));
00236   emit bootstrapStatusChanged(status);
00237 }
00238 
00239 /** Emits a signal that the control socket disconnected from Tor */
00240 void
00241 TorControl::onDisconnected()
00242 {
00243   if (_torProcess) {
00244     /* If we're running a Tor process, then start reading logs from stdout
00245      * again, in case our control connection just died but Tor is still
00246      * running. In this case, there may be relevant information in the logs. */
00247     _torProcess->openStdout();
00248   }
00249   /* Tor isn't running, so it has no version */
00250   _torVersion = QString();
00251 
00252   /* Let interested parties know we lost our control connection */
00253   emit disconnected();
00254 }
00255 
00256 /** Check if the control socket is connected */
00257 bool
00258 TorControl::isConnected()
00259 {
00260   return _controlConn->isConnected();
00261 }
00262 
00263 /** Send a message to Tor and reads the response. If Vidalia was unable to
00264  * send the command to Tor or read its response, false is returned. If the
00265  * response was read and the status code is not 250 OK, false is also
00266  * returned. */
00267 bool
00268 TorControl::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
00269 {
00270   if (_controlConn->send(cmd, reply, errmsg)) {
00271     if (reply.getStatus() == "250") {
00272       return true;
00273     }
00274     if (errmsg) {
00275       *errmsg = reply.getMessage();
00276     }
00277   }
00278   return false;
00279 }
00280 
00281 /** Sends a message to Tor and discards the response. */
00282 bool
00283 TorControl::send(ControlCommand cmd, QString *errmsg)
00284 {
00285   ControlReply reply;
00286   return send(cmd, reply, errmsg);
00287 }
00288 
00289 /** Sends an authentication cookie to Tor. The syntax is:
00290  *
00291  *   "AUTHENTICATE" SP 1*HEXDIG CRLF
00292  */
00293 bool
00294 TorControl::authenticate(const QByteArray cookie, QString *errmsg)
00295 {
00296   ControlCommand cmd("AUTHENTICATE", base16_encode(cookie));
00297   ControlReply reply;
00298   QString str;
00299 
00300   if (!send(cmd, reply, &str)) {
00301     emit authenticationFailed(str);
00302     return err(errmsg, str);
00303   }
00304   onAuthenticated();
00305   return true;
00306 }
00307 
00308 /** Sends an authentication password to Tor. The syntax is:
00309  *
00310  *   "AUTHENTICATE" SP QuotedString CRLF
00311  */
00312 bool
00313 TorControl::authenticate(const QString &password, QString *errmsg)
00314 {
00315   ControlCommand cmd("AUTHENTICATE", string_escape(password));
00316   ControlReply reply;
00317   QString str;
00318 
00319   if (!send(cmd, reply, &str)) {
00320     emit authenticationFailed(str);
00321     return err(errmsg, str);
00322   }
00323   onAuthenticated();
00324   return true;
00325 }
00326 
00327 /** Called when the controller has successfully authenticated to Tor. */
00328 void
00329 TorControl::onAuthenticated()
00330 {
00331   /* The version of Tor isn't going to change while we're connected to it, so
00332    * save it for later. */
00333   getInfo("version", _torVersion);
00334   /* We want to use verbose names in events and GETINFO results. */
00335   useFeature("VERBOSE_NAMES");
00336   /* We want to use extended events in all async events */
00337   useFeature("EXTENDED_EVENTS");
00338 
00339   getBootstrapPhase();
00340 
00341   emit authenticated();
00342 }
00343 
00344 /** Sends a PROTOCOLINFO command to Tor and parses the response. */
00345 ProtocolInfo
00346 TorControl::protocolInfo(QString *errmsg)
00347 {
00348   ControlCommand cmd("PROTOCOLINFO", "1");
00349   ControlReply reply;
00350   ProtocolInfo pi;
00351   QString msg, topic;
00352   QHash<QString,QString> keyvals;
00353   int idx;
00354   bool ok;
00355 
00356   if (!send(cmd, reply, errmsg))
00357     return ProtocolInfo();
00358 
00359   foreach (ReplyLine line, reply.getLines()) {
00360     if (line.getStatus() != "250")
00361       continue;
00362 
00363     msg = line.getMessage().trimmed();
00364     idx = msg.indexOf(" ");
00365     topic = msg.mid(0, idx).toUpper();
00366 
00367     if (idx > 0) {
00368       keyvals = string_parse_keyvals(msg.mid(idx+1), &ok);
00369       if (!ok)
00370         continue; /* Ignore malformed lines */
00371     } else {
00372       keyvals = QHash<QString,QString>();
00373     }
00374 
00375     if (topic == "AUTH") {
00376       if (keyvals.contains("METHODS"))
00377         pi.setAuthMethods(keyvals.value("METHODS"));
00378       if (keyvals.contains("COOKIEFILE"))
00379         pi.setCookieAuthFile(keyvals.value("COOKIEFILE"));
00380     } else if (topic == "VERSION") {
00381       if (keyvals.contains("Tor"))
00382         pi.setTorVersion(keyvals.value("Tor"));
00383     }
00384   }
00385   return pi;
00386 }
00387 
00388 /** Tells Tor the controller wants to enable <b>feature</b> via the
00389  * USEFEATURE control command. Returns true if the given feature was
00390  * successfully enabled. */
00391 bool
00392 TorControl::useFeature(const QString &feature, QString *errmsg)
00393 {
00394   ControlCommand cmd("USEFEATURE", feature);
00395   return send(cmd, errmsg);
00396 }
00397 
00398 BootstrapStatus
00399 TorControl::bootstrapStatus(QString *errmsg)
00400 {
00401   QString str = getInfo("status/bootstrap-phase").toString();
00402   if (!str.isEmpty()) {
00403     tc::Severity severity = tc::severityFromString(str.section(' ', 0, 0));
00404     QHash<QString,QString> args = string_parse_keyvals(str);
00405     return BootstrapStatus(severity,
00406               BootstrapStatus::statusFromString(args.value("TAG")),
00407               args.value("PROGRESS").toInt(),
00408               args.value("SUMMARY"),
00409               args.value("WARNING"),
00410               tc::connectionStatusReasonFromString(args.value("REASON")),
00411               BootstrapStatus::actionFromString(
00412                 args.value("RECOMMENDATION")));
00413   }
00414   return BootstrapStatus();
00415 }
00416 
00417 /** Returns true if Tor either has an open circuit or (on Tor >=
00418  * 0.2.0.1-alpha) has previously decided it's able to establish a circuit. */
00419 bool
00420 TorControl::isCircuitEstablished()
00421 {
00422   /* If Tor is recent enough, we can 'getinfo status/circuit-established' to
00423    * see if Tor has an open circuit */
00424   if (getTorVersion() >= 0x020001) {
00425     QString tmp;
00426     if (getInfo("status/circuit-established", tmp))
00427       return (tmp == "1");
00428   }
00429 
00430   /* Either Tor was too old or our getinfo failed, so try to get a list of all
00431    * circuits and check their statuses. */
00432   CircuitList circs = getCircuits();
00433   foreach (Circuit circ, circs) {
00434     if (circ.status() == Circuit::Built)
00435       return true;
00436   }
00437   return false;
00438 }
00439 
00440 /** Sends a GETINFO message to Tor based on the given map of keyvals. The
00441  * syntax is:
00442  *
00443  *    "GETINFO" 1*(SP keyword) CRLF
00444  */
00445 bool
00446 TorControl::getInfo(QHash<QString,QString> &map, QString *errmsg)
00447 {
00448   ControlCommand cmd("GETINFO");
00449   ControlReply reply;
00450 
00451   /* Add the keys as arguments to the GETINFO message */
00452   foreach (QString key, map.keys()) {
00453     cmd.addArgument(key);
00454   }
00455 
00456   /* Ask Tor for the specified info values */
00457   if (send(cmd, reply, errmsg)) {
00458     /* Parse the response for the returned values */
00459     foreach (ReplyLine line, reply.getLines()) {
00460       /* Split the "key=val" line and map them */
00461       QStringList keyval = line.getMessage().split("=");
00462       if (keyval.size() == 2) {
00463         QString key = keyval.at(0);
00464         QString val = keyval.at(1);
00465         if (val.startsWith(QLatin1Char('\"')) &&
00466             val.endsWith(QLatin1Char('\"'))) {
00467           bool ok;
00468           val = string_unescape(val, &ok);
00469           if (! ok)
00470             continue;
00471         }
00472         map.insert(key, val);
00473       }
00474     }
00475     return true;
00476   }
00477   return false;
00478 }
00479 
00480 /** Sends a GETINFO message to Tor using the given list of <b>keys</b> and
00481  * returns a QVariantMap containing the specified keys and their values as
00482  * returned  by Tor. Returns a default constructed QVariantMap on failure. */
00483 QVariantMap
00484 TorControl::getInfo(const QStringList &keys, QString *errmsg)
00485 {
00486   ControlCommand cmd("GETINFO");
00487   ControlReply reply;
00488   QVariantMap infoMap;
00489 
00490   cmd.addArguments(keys);
00491   if (!send(cmd, reply, errmsg))
00492     return QVariantMap();
00493 
00494   foreach (ReplyLine line, reply.getLines()) {
00495     QString msg = line.getMessage();
00496     int index   = msg.indexOf("=");
00497     QString key = msg.mid(0, index);
00498     QStringList val;
00499 
00500     if (index > 0 && index < msg.length()-1) {
00501       QString str = msg.mid(index+1);
00502       if (str.startsWith(QLatin1Char('\"')) &&
00503           str.endsWith(QLatin1Char('\"'))) {
00504         bool ok;
00505         str = string_unescape(str, &ok);
00506         if (! ok)
00507           continue;
00508       }
00509       val << str;
00510     }
00511     if (line.hasData())
00512       val << line.getData();
00513 
00514     if (infoMap.contains(key)) {
00515       QStringList values = infoMap.value(key).toStringList();
00516       values << val;
00517       infoMap.insert(key, values);
00518     } else {
00519       infoMap.insert(key, val);
00520     }
00521   }
00522   return infoMap;
00523 }
00524 
00525 /** Sends a GETINFO message to Tor with a single <b>key</b> and returns a
00526  * QVariant containing the value returned by Tor. Returns a default
00527  * constructed QVariant on failure. */
00528 QVariant
00529 TorControl::getInfo(const QString &key, QString *errmsg)
00530 {
00531   QVariantMap map = getInfo(QStringList() << key, errmsg);
00532   return map.value(key);
00533 }
00534 
00535 /** Overloaded method to send a GETINFO command for a single info value */
00536 bool
00537 TorControl::getInfo(QString key, QString &val, QString *errmsg)
00538 {
00539   QHash<QString,QString> map;
00540   map.insert(key, "");
00541 
00542   if (getInfo(map, errmsg)) {
00543     val = map.value(key);
00544     return true;
00545   }
00546   return false;
00547 }
00548 
00549 /** Sends a signal to Tor */
00550 bool
00551 TorControl::signal(TorSignal::Signal sig, QString *errmsg)
00552 {
00553   ControlCommand cmd("SIGNAL");
00554   cmd.addArgument(TorSignal::toString(sig));
00555 
00556   if (sig == TorSignal::Shutdown || sig == TorSignal::Halt) {
00557     /* Tor closes the connection before giving us a response to any commands
00558      * asking it to stop running, so don't try to get a response. */
00559     return _controlConn->send(cmd, errmsg);
00560   }
00561   return send(cmd, errmsg);
00562 }
00563 
00564 /** Returns an address on which Tor is listening for application
00565  * requests. If none are available, a null QHostAddress is returned. */
00566 QHostAddress
00567 TorControl::getSocksAddress(QString *errmsg)
00568 {
00569   QHostAddress socksAddr;
00570 
00571   /* If SocksPort is 0, then Tor is not accepting any application requests. */
00572   if (getSocksPort() == 0) {
00573     return QHostAddress::Null;
00574   }
00575 
00576   /* Get a list of SocksListenAddress lines and return the first valid IP
00577    * address parsed from the list. */
00578   QStringList addrList = getSocksAddressList(errmsg);
00579   foreach (QString addr, addrList) {
00580     addr = addr.mid(0, addr.indexOf(":"));
00581     if (socksAddr.setAddress(addr)) {
00582       return socksAddr;
00583     }
00584   }
00585   /* Otherwise Tor is listening on its default 127.0.0.1 */
00586   return QHostAddress::LocalHost;
00587 }
00588 
00589 /** Returns a (possibly empty) list of all currently configured
00590  * SocksListenAddress entries. */
00591 QStringList
00592 TorControl::getSocksAddressList(QString *errmsg)
00593 {
00594   QStringList addrList;
00595   if (getConf("SocksListenAddress", addrList, errmsg)) {
00596     return addrList;
00597   }
00598   return QStringList();
00599 }
00600 
00601 /** Returns a valid SOCKS port for Tor, or 0 if Tor is not accepting
00602  * application requests. */
00603 quint16
00604 TorControl::getSocksPort(QString *errmsg)
00605 {
00606   QList<quint16> portList = getSocksPortList(errmsg);
00607   if (portList.size() > 0) {
00608     return portList.at(0);
00609   }
00610   return 0;
00611 }
00612 
00613 /** Returns a list of all currently configured SOCKS ports. If Tor is not
00614  * accepting any application connections, an empty list will be returned. */
00615 QList<quint16>
00616 TorControl::getSocksPortList(QString *errmsg)
00617 {
00618   bool valid;
00619   quint16 port, socksPort;
00620   QString portString;
00621   QList<quint16> portList;
00622 
00623   /* Get the value of the SocksPort configuration variable */
00624   if (getConf("SocksPort", portString, errmsg)) {
00625     socksPort = (quint16)portString.toUInt(&valid);
00626     if (valid) {
00627       if (socksPort == 0) {
00628         /* A SocksPort of 0 means Tor is not accepting any application
00629          * connections. */
00630         return QList<quint16>();
00631       }
00632     }
00633   }
00634   /* Get a list of SOCKS ports from SocksListenAddress entries */
00635   QStringList addrList = getSocksAddressList(errmsg);
00636   foreach (QString addr, addrList) {
00637     if (addr.contains(":")) {
00638       portString = addr.mid(addr.indexOf(":")+1);
00639       port = (quint16)portString.toUInt(&valid);
00640       if (valid) {
00641         portList << port;
00642       }
00643     }
00644   }
00645   /* If there were no SocksListenAddress entries, or one or more of them did
00646    * not specify a port, then add the value of SocksPort, too */
00647   if (!portList.size() || (portList.size() != addrList.size())) {
00648     portList << socksPort;
00649   }
00650   return portList;
00651 }
00652 
00653 /** Reeturns Tor's version as a string. */
00654 QString
00655 TorControl::getTorVersionString()
00656 {
00657   return _torVersion;
00658 }
00659 
00660 /** Returns Tor's version as a numeric value. Note that this discards any
00661  * version status flag, such as "-alpha" or "-rc". */
00662 quint32
00663 TorControl::getTorVersion()
00664 {
00665   static QString versionString;
00666   static quint32 version = 0;
00667   quint8 major, minor, micro, patch;
00668 
00669   /* Only recompute the version number if the version string changed */
00670   if (versionString == _torVersion)
00671     return version;
00672   versionString = _torVersion;
00673 
00674   /* Split the version string at either "." or "-" characters */
00675   QStringList parts = versionString.split(QRegExp("\\.|-|\\ "));
00676   if (parts.size() >= 4) {
00677     major = (quint8)parts.at(0).toUInt();
00678     minor = (quint8)parts.at(1).toUInt();
00679     micro = (quint8)parts.at(2).toUInt();
00680     patch = (quint8)parts.at(3).toUInt();
00681     version = ((major << 24) | (minor << 16) | (micro << 8) | patch);
00682   } else {
00683     /* Couldn't parse the version string */
00684     version = 0;
00685   }
00686   return version;
00687 }
00688 
00689 /** Sets an event and its handler. If add is true, then the event is added,
00690  * otherwise it is removed. If set is true, then the given event will be
00691  * registered with Tor. */
00692 bool
00693 TorControl::setEvent(TorEvents::Event e, bool add, bool set, QString *errmsg)
00694 {
00695   _events = (add ? (_events | e) : (_events & ~e));
00696   if (set && isConnected())
00697     return setEvents(errmsg);
00698   return true;
00699 }
00700 
00701 /** Register for the events currently in the event list */
00702 bool
00703 TorControl::setEvents(QString *errmsg)
00704 {
00705   ControlCommand cmd("SETEVENTS");
00706 
00707   for (TorEvents::Event e = TorEvents::EVENT_MIN; e <= TorEvents::EVENT_MAX;) {
00708     if (_events & e)
00709       cmd.addArgument(TorEvents::toString(e));
00710     e = static_cast<TorEvents::Event>(e << 1);
00711   }
00712   return send(cmd, errmsg);
00713 }
00714 
00715 /** Sets each configuration key in <b>map</b> to the value associated
00716  * with its key. */
00717 bool
00718 TorControl::setConf(QHash<QString,QString> map, QString *errmsg)
00719 {
00720   ControlCommand cmd("SETCONF");
00721 
00722   /* Add each keyvalue to the argument list */
00723   foreach (QString key, map.uniqueKeys()) {
00724     /* If a key has multiple values (e.g., a QMultiHash), they are stored
00725      * in order from most recently inserted to least recently inserted.
00726      * So, walk the list in reverse so that we append the configuration
00727      * values to the SETCONF command in the same order they were inserted
00728      * into the QHash. */
00729     QList<QString> values = map.values(key);
00730     for (int i = values.size()-1; i >= 0; i--) {
00731       QString value = values.at(i);
00732       if (value.length() > 0)
00733         cmd.addArgument(key + "=" + string_escape(value));
00734       else
00735         cmd.addArgument(key);
00736     }
00737   }
00738   return send(cmd, errmsg);
00739 }
00740 
00741 /** Sets a single configuration key to the given value. */
00742 bool
00743 TorControl::setConf(QString key, QString value, QString *errmsg)
00744 {
00745   QHash<QString,QString> map;
00746   map.insert(key, value);
00747   return setConf(map, errmsg);
00748 }
00749 
00750 /** Sets a single configuration string that is formatted <key=escaped value>.*/
00751 bool
00752 TorControl::setConf(QString keyAndValue, QString *errmsg)
00753 {
00754   QHash<QString,QString> map;
00755   map.insert(keyAndValue, "");
00756   return setConf(map, errmsg);
00757 }
00758 
00759 /** Gets values for a set of configuration keys, each of which has a single
00760  * value. */
00761 bool
00762 TorControl::getConf(QHash<QString,QString> &map, QString *errmsg)
00763 {
00764   QHash<QString,QStringList> multiMap;
00765   foreach (QString key, map.keys()) {
00766     multiMap.insert(key, QStringList());
00767   }
00768   if (getConf(multiMap, errmsg)) {
00769     foreach (QString key, multiMap.keys()) {
00770       if (map.contains(key)) {
00771         map.insert(key, multiMap.value(key).join("\n"));
00772       }
00773     }
00774   }
00775   return false;
00776 }
00777 
00778 /** Gets a set of configuration keyvalues and stores them in <b>map</b>. */
00779 bool
00780 TorControl::getConf(QHash<QString,QStringList> &map, QString *errmsg)
00781 {
00782   ControlCommand cmd("GETCONF");
00783   ControlReply reply;
00784   QStringList confValue;
00785   QString confKey;
00786 
00787   /* Add the keys as arguments to the GETINFO message */
00788   foreach (QString key, map.keys()) {
00789     cmd.addArgument(key);
00790   }
00791 
00792   /* Ask Tor for the specified info values */
00793   if (send(cmd, reply, errmsg)) {
00794     /* Parse the response for the returned values */
00795     foreach (ReplyLine line, reply.getLines()) {
00796       /* Split the "key=val" line and map them */
00797       QStringList keyval = line.getMessage().split("=");
00798       if (keyval.size() == 2) {
00799         confKey = keyval.at(0);
00800 
00801         if (map.contains(confKey)) {
00802           /* This configuration key has multiple values, so add this one to
00803            * the list. */
00804           confValue = map.value(confKey);
00805         }
00806         confValue << keyval.at(1);
00807         map.insert(keyval.at(0), confValue);
00808       }
00809     }
00810     return true;
00811   }
00812   return false;
00813 }
00814 
00815 /** Gets a single configuration value for <b>key</b>. */
00816 bool
00817 TorControl::getConf(QString key, QString &value, QString *errmsg)
00818 {
00819   QStringList confValues;
00820   if (getConf(key, confValues, errmsg)) {
00821     value = confValues.join("\n");
00822     return true;
00823   }
00824   return false;
00825 }
00826 
00827 /** Gets a list of configuration values for <b>key</b>. */
00828 bool
00829 TorControl::getConf(QString key, QStringList &value, QString *errmsg)
00830 {
00831   QHash<QString,QStringList> map;
00832   map.insert(key, QStringList());
00833 
00834   if (getConf(map, errmsg)) {
00835     value = map.value(key);
00836     return true;
00837   }
00838   return false;
00839 }
00840 
00841 /** Sends a GETICONF message to Tor using the given list of <b>keys</b> and
00842  * returns a QVariantMap containing the specified keys and their values as
00843  * returned  by Tor. Returns a default constructed QVariantMap on failure. */
00844 QVariantMap
00845 TorControl::getConf(const QStringList &keys, QString *errmsg)
00846 {
00847   ControlCommand cmd("GETCONF");
00848   ControlReply reply;
00849   QVariantMap confMap;
00850 
00851   cmd.addArguments(keys);
00852   if (!send(cmd, reply, errmsg))
00853     return QVariantMap();
00854 
00855   foreach (ReplyLine line, reply.getLines()) {
00856     QString msg = line.getMessage();
00857     int index   = msg.indexOf("=");
00858     QString key = msg.mid(0, index);
00859     QString val;
00860 
00861     if (index > 0 && index < msg.length()-1)
00862       val = msg.mid(index+1);
00863     if (val.startsWith(QLatin1Char('\"')) &&
00864         val.endsWith(QLatin1Char('\"'))) {
00865       bool ok;
00866       val = string_unescape(val, &ok);
00867       if (! ok)
00868         continue;
00869     }
00870 
00871     if (confMap.contains(key)) {
00872       QStringList values = confMap.value(key).toStringList();
00873       values << val;
00874       confMap.insert(key, values);
00875     } else {
00876       confMap.insert(key, val);
00877     }
00878   }
00879   return confMap;
00880 }
00881 
00882 /** Sends a GETCONF message to Tor with a single <b>key</b> and returns a
00883  * QVariant containing the value returned by Tor. Returns a default
00884  * constructed QVariant on failure. */
00885 QVariant
00886 TorControl::getConf(const QString &key, QString *errmsg)
00887 {
00888   QVariantMap map = getConf(QStringList() << key, errmsg);
00889   return map.value(key);
00890 }
00891 
00892 /** Sends a GETCONF message to Tor with the single key and returns a QString
00893  * containing the value returned by Tor */
00894 QString
00895 TorControl::getHiddenServiceConf(const QString &key, QString *errmsg)
00896 {
00897   ControlCommand cmd("GETCONF");
00898   ControlReply reply;
00899   QVariantMap confMap;
00900 
00901   cmd.addArgument(key);
00902   if (!send(cmd, reply, errmsg))
00903     return "";
00904 
00905   return reply.toString();
00906 }
00907 
00908 /** Asks Tor to save the current configuration to its torrc. */
00909 bool
00910 TorControl::saveConf(QString *errmsg)
00911 {
00912   ControlCommand cmd("SAVECONF");
00913   bool ret = send(cmd, errmsg);
00914 
00915   if(!ret) {
00916     QString err;
00917     setConf("__ReloadTorrcOnSIGHUP", "0", &err);
00918   }
00919 
00920   return ret;
00921 }
00922 
00923 /** Tells Tor to reset the given configuration keys back to defaults. */
00924 bool
00925 TorControl::resetConf(QStringList keys, QString *errmsg)
00926 {
00927   ControlCommand cmd("RESETCONF");
00928 
00929   /* Add each key to the argument list */
00930   foreach (QString key, keys) {
00931     cmd.addArgument(key);
00932   }
00933   return send(cmd, errmsg);
00934 }
00935 
00936 /** Tells Tor to reset a single given configuration key back to its default
00937  * value. */
00938 bool
00939 TorControl::resetConf(QString key, QString *errmsg)
00940 {
00941   return resetConf(QStringList() << key, errmsg);
00942 }
00943 
00944 /** Returns an unparsed router descriptor for the router whose fingerprint
00945  * matches <b>id</b>. The returned text can later be parsed by the
00946  * RouterDescriptor class. If <b>id</b> is invalid, then an empty
00947  * QStringList is returned. */
00948 QStringList
00949 TorControl::getRouterDescriptorText(const QString &id, QString *errmsg)
00950 {
00951   return getInfo("desc/id/" + id, errmsg).toStringList();
00952 }
00953 
00954 /** Returns the descriptor for the router whose fingerprint matches
00955  * <b>id</b>. If <b>id</b> is invalid or the router's descriptor cannot
00956  * be parsed, then an invalid RouterDescriptor is returned. */
00957 RouterDescriptor
00958 TorControl::getRouterDescriptor(const QString &id, QString *errmsg)
00959 {
00960   return RouterDescriptor(getRouterDescriptorText(id, errmsg));
00961 }
00962 
00963 /** Returns the status of the router whose fingerprint matches <b>id</b>. If
00964  * <b>id</b> is invalid or the router's status cannot be parsed, then an
00965  * invalid RouterStatus is returned. */
00966 RouterStatus
00967 TorControl::getRouterStatus(const QString &id, QString *errmsg)
00968 {
00969   QStringList status = getInfo("ns/id/" + id, errmsg).toStringList();
00970   return RouterStatus(status);
00971 }
00972 
00973 /** Returns a RouterStatus object for every known router in the network. If
00974  * the network status document cannot be parsed, then an empty NetworkStatus
00975  * is returned. */
00976 NetworkStatus
00977 TorControl::getNetworkStatus(QString *errmsg)
00978 {
00979   QStringList networkStatusLines = getInfo("ns/all", errmsg).toStringList();
00980   QList<RouterStatus> networkStatus;
00981   int len = networkStatusLines.size();
00982   int i = 0;
00983 
00984   while (i < len) {
00985     /* Extract the "r", "s", and whatever other status lines */
00986     QStringList routerStatusLines;
00987     do {
00988       routerStatusLines << networkStatusLines.at(i);
00989     } while (++i < len && ! networkStatusLines.at(i).startsWith("r "));
00990 
00991     /* Create a new RouterStatus object and add it to the network status, if
00992      * it's valid. */
00993     RouterStatus routerStatus(routerStatusLines);
00994     if (routerStatus.isValid())
00995       networkStatus << routerStatus;
00996   }
00997   return networkStatus;
00998 }
00999 
01000 /** Returns the annotations for the router whose fingerprint matches
01001  * <b>id</b>. If <b>id</b> is invalid or the router's annotations cannot be
01002  * parsed, then an empty DescriptorAnnotations is returned and <b>errmsg</b>
01003  * is set if it's not NULL. (Tor >= 0.2.0.13-alpha only) */
01004 DescriptorAnnotations
01005 TorControl::getDescriptorAnnotations(const QString &id, QString *errmsg)
01006 {
01007   QStringList lines = getInfo("desc-annotations/id/"+id, errmsg).toStringList();
01008   DescriptorAnnotations annotations;
01009   QString key, value;
01010 
01011   foreach (QString line, lines) {
01012     int idx = line.indexOf(" ");
01013 
01014     /* Extract the annotation key */
01015     key = line.mid(0, idx);
01016     if (key.startsWith("@"))
01017       key = key.remove(0, 1);
01018 
01019     /* Extract the annotation value (if present) */
01020     if (idx > 0 && idx < line.length()-1)
01021       annotations.insert(key, line.mid(idx + 1).trimmed());
01022     else
01023       annotations.insert(key, QString());
01024   }
01025   return annotations;
01026 }
01027 
01028 /** Gets a list of current circuits. */
01029 QList<Circuit>
01030 TorControl::getCircuits(QString *errmsg)
01031 {
01032   ControlCommand cmd("GETINFO", "circuit-status");
01033   ControlReply reply;
01034   CircuitList circuits;
01035 
01036   if (!send(cmd, reply, errmsg))
01037     return CircuitList();
01038 
01039   /* The rest of the circuits just come as data, one per line */
01040   foreach(QString line, reply.getData()) {
01041     Circuit circ(line);
01042     if (circ.isValid())
01043       circuits << circ;
01044   }
01045   return circuits;
01046 }
01047 
01048 /** Closes the circuit specified by <b>circId</b>. If <b>ifUnused</b> is
01049  * true, then the circuit will not be closed unless it is unused. */
01050 bool
01051 TorControl::closeCircuit(const CircuitId &circId, bool ifUnused, QString *errmsg)
01052 {
01053   ControlCommand cmd("CLOSECIRCUIT", circId);
01054   if (ifUnused) {
01055     cmd.addArgument("IfUnused");
01056   }
01057   return send(cmd, errmsg);
01058 }
01059 
01060 /** Gets a list of current streams. */
01061 QList<Stream>
01062 TorControl::getStreams(QString *errmsg)
01063 {
01064   ControlCommand cmd("GETINFO", "stream-status");
01065   ControlReply reply;
01066   QList<Stream> streams;
01067   Stream s;
01068 
01069   if (send(cmd, reply, errmsg)) {
01070     /* Sometimes there is a stream on the first message line */
01071     QString msg = reply.getMessage();
01072     s = Stream::fromString(msg.mid(msg.indexOf("=")+1));
01073     if (s.isValid())
01074       streams << s;
01075 
01076     /* The rest of the streams just come as data, one per line */
01077     foreach (QString line, reply.getData()) {
01078       s = Stream::fromString(line);
01079       if (s.isValid())
01080         streams << s;
01081     }
01082   }
01083   return streams;
01084 }
01085 
01086 /** Closes the stream specified by <b>streamId</b>. */
01087 bool
01088 TorControl::closeStream(const StreamId &streamId, QString *errmsg)
01089 {
01090   ControlCommand cmd("CLOSESTREAM", streamId);
01091   cmd.addArgument("1"); /* 1 == REASON_MISC (tor-spec.txt) */
01092   return send(cmd, errmsg);
01093 }
01094 
01095  /** Gets a list of address mappings of the type specified by <b>type</b>
01096   * (defaults to <i>AddressMapAll</i>. */
01097 AddressMap
01098 TorControl::getAddressMap(AddressMap::AddressMapType type, QString *errmsg)
01099 {
01100   AddressMap addressMap;
01101   QStringList entries;
01102 
01103   switch (type) {
01104     case AddressMap::AddressMapConfig:
01105       entries = getInfo("address-mappings/config").toStringList();
01106       break;
01107     case AddressMap::AddressMapCache:
01108       entries = getInfo("address-mappings/cache").toStringList();
01109       break;
01110     case AddressMap::AddressMapControl:
01111       entries = getInfo("address-mappings/control").toStringList();
01112       break;
01113     default:
01114       entries = getInfo("address-mappings/all").toStringList();
01115   }
01116 
01117   foreach (QString entry, entries) {
01118     addressMap.add(entry);
01119   }
01120   return addressMap;
01121 }
01122 
01123 /** Gets the ISO-3166 two-letter country code for <b>ip</b> from Tor.
01124  * Returns a default-constructed QString on failure or if a country code
01125  * is not known for <b>ip</b>. On failure, <b>errmsg</b> will be set if
01126  * it's not NULL. */
01127 QString
01128 TorControl::ipToCountry(const QHostAddress &ip, QString *errmsg)
01129 {
01130   QString request   = QString("ip-to-country/%1").arg(ip.toString());
01131   QVariant response = getInfo(request, errmsg);
01132   if (! response.isNull())
01133     return response.toString();
01134   return QString();
01135 }
01136 
01137 /** Takes ownership of the tor process it's communicating to */
01138 bool
01139 TorControl::takeOwnership(QString *errmsg)
01140 {
01141   ControlCommand cmd("TAKEOWNERSHIP");
01142   return send(cmd, errmsg);
01143 }