Vidalia 0.2.10

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