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 4100 2009-09-01 13:54:27Z 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         map.insert(keyval.at(0), keyval.at(1));
00427       }
00428     }
00429     return true;
00430   }
00431   return false;
00432 }
00433 
00434 /** Sends a GETINFO message to Tor using the given list of <b>keys</b> and
00435  * returns a QVariantMap containing the specified keys and their values as
00436  * returned  by Tor. Returns a default constructed QVariantMap on failure. */
00437 QVariantMap
00438 TorControl::getInfo(const QStringList &keys, QString *errmsg)
00439 {
00440   ControlCommand cmd("GETINFO");
00441   ControlReply reply;
00442   QVariantMap infoMap;
00443 
00444   cmd.addArguments(keys);
00445   if (!send(cmd, reply, errmsg))
00446     return QVariantMap();
00447 
00448   foreach (ReplyLine line, reply.getLines()) {
00449     QString msg = line.getMessage();
00450     int index   = msg.indexOf("=");
00451     QString key = msg.mid(0, index);
00452     QStringList val;
00453 
00454     if (index > 0 && index < msg.length()-1)
00455       val << msg.mid(index+1);
00456     if (line.hasData())
00457       val << line.getData();
00458 
00459     if (infoMap.contains(key)) {
00460       QStringList values = infoMap.value(key).toStringList();
00461       values << val;
00462       infoMap.insert(key, values);
00463     } else {
00464       infoMap.insert(key, val);
00465     }
00466   }
00467   return infoMap;
00468 }
00469 
00470 /** Sends a GETINFO message to Tor with a single <b>key</b> and returns a
00471  * QVariant containing the value returned by Tor. Returns a default
00472  * constructed QVariant on failure. */
00473 QVariant
00474 TorControl::getInfo(const QString &key, QString *errmsg)
00475 {
00476   QVariantMap map = getInfo(QStringList() << key, errmsg);
00477   return map.value(key);
00478 }
00479 
00480 /** Overloaded method to send a GETINFO command for a single info value */
00481 bool
00482 TorControl::getInfo(QString key, QString &val, QString *errmsg)
00483 {
00484   QHash<QString,QString> map;
00485   map.insert(key, "");
00486 
00487   if (getInfo(map, errmsg)) {
00488     val = map.value(key);
00489     return true;
00490   }
00491   return false;
00492 }
00493 
00494 /** Sends a signal to Tor */
00495 bool
00496 TorControl::signal(TorSignal::Signal sig, QString *errmsg)
00497 {
00498   ControlCommand cmd("SIGNAL");
00499   cmd.addArgument(TorSignal::toString(sig));
00500 
00501   if (sig == TorSignal::Shutdown || sig == TorSignal::Halt) {
00502     /* Tor closes the connection before giving us a response to any commands
00503      * asking it to stop running, so don't try to get a response. */
00504     return _controlConn->send(cmd, errmsg);
00505   }
00506   return send(cmd, errmsg);
00507 }
00508 
00509 /** Returns an address on which Tor is listening for application
00510  * requests. If none are available, a null QHostAddress is returned. */
00511 QHostAddress
00512 TorControl::getSocksAddress(QString *errmsg)
00513 {
00514   QHostAddress socksAddr;
00515 
00516   /* If SocksPort is 0, then Tor is not accepting any application requests. */
00517   if (getSocksPort() == 0) {
00518     return QHostAddress::Null;
00519   }
00520 
00521   /* Get a list of SocksListenAddress lines and return the first valid IP
00522    * address parsed from the list. */
00523   QStringList addrList = getSocksAddressList(errmsg);
00524   foreach (QString addr, addrList) {
00525     addr = addr.mid(0, addr.indexOf(":"));
00526     if (socksAddr.setAddress(addr)) {
00527       return socksAddr;
00528     }
00529   }
00530   /* Otherwise Tor is listening on its default 127.0.0.1 */
00531   return QHostAddress::LocalHost;
00532 }
00533 
00534 /** Returns a (possibly empty) list of all currently configured
00535  * SocksListenAddress entries. */
00536 QStringList
00537 TorControl::getSocksAddressList(QString *errmsg)
00538 {
00539   QStringList addrList;
00540   if (getConf("SocksListenAddress", addrList, errmsg)) {
00541     return addrList;
00542   }
00543   return QStringList();
00544 }
00545 
00546 /** Returns a valid SOCKS port for Tor, or 0 if Tor is not accepting
00547  * application requests. */
00548 quint16
00549 TorControl::getSocksPort(QString *errmsg)
00550 {
00551   QList<quint16> portList = getSocksPortList(errmsg);
00552   if (portList.size() > 0) {
00553     return portList.at(0);
00554   }
00555   return 0;
00556 }
00557 
00558 /** Returns a list of all currently configured SOCKS ports. If Tor is not
00559  * accepting any application connections, an empty list will be returned. */
00560 QList<quint16>
00561 TorControl::getSocksPortList(QString *errmsg)
00562 {
00563   bool valid;
00564   quint16 port, socksPort;
00565   QString portString;
00566   QList<quint16> portList;
00567 
00568   /* Get the value of the SocksPort configuration variable */
00569   if (getConf("SocksPort", portString, errmsg)) {
00570     socksPort = (quint16)portString.toUInt(&valid);
00571     if (valid) {
00572       if (socksPort == 0) {
00573         /* A SocksPort of 0 means Tor is not accepting any application
00574          * connections. */
00575         return QList<quint16>();
00576       }
00577     }
00578   }
00579   /* Get a list of SOCKS ports from SocksListenAddress entries */
00580   QStringList addrList = getSocksAddressList(errmsg);
00581   foreach (QString addr, addrList) {
00582     if (addr.contains(":")) {
00583       portString = addr.mid(addr.indexOf(":")+1);
00584       port = (quint16)portString.toUInt(&valid);
00585       if (valid) {
00586         portList << port;
00587       }
00588     }
00589   }
00590   /* If there were no SocksListenAddress entries, or one or more of them did
00591    * not specify a port, then add the value of SocksPort, too */
00592   if (!portList.size() || (portList.size() != addrList.size())) {
00593     portList << socksPort;
00594   }
00595   return portList;
00596 }
00597 
00598 /** Reeturns Tor's version as a string. */
00599 QString
00600 TorControl::getTorVersionString()
00601 {
00602   return _torVersion;
00603 }
00604 
00605 /** Returns Tor's version as a numeric value. Note that this discards any
00606  * version status flag, such as "-alpha" or "-rc". */
00607 quint32
00608 TorControl::getTorVersion()
00609 {
00610   static QString versionString;
00611   static quint32 version = 0;
00612   quint8 major, minor, micro, patch;
00613 
00614   /* Only recompute the version number if the version string changed */
00615   if (versionString == _torVersion)
00616     return version;
00617   versionString = _torVersion;
00618 
00619   /* Split the version string at either "." or "-" characters */
00620   QStringList parts = versionString.split(QRegExp("\\.|-|\\ "));
00621   if (parts.size() >= 4) {
00622     major = (quint8)parts.at(0).toUInt();
00623     minor = (quint8)parts.at(1).toUInt();
00624     micro = (quint8)parts.at(2).toUInt();
00625     patch = (quint8)parts.at(3).toUInt();
00626     version = ((major << 24) | (minor << 16) | (micro << 8) | patch);
00627   } else {
00628     /* Couldn't parse the version string */
00629     version = 0;
00630   }
00631   return version;
00632 }
00633 
00634 /** Sets an event and its handler. If add is true, then the event is added,
00635  * otherwise it is removed. If set is true, then the given event will be
00636  * registered with Tor. */
00637 bool
00638 TorControl::setEvent(TorEvents::Event e, bool add, bool set, QString *errmsg)
00639 {
00640   _events = (add ? (_events | e) : (_events & ~e));
00641   if (set && isConnected())
00642     return setEvents(errmsg);
00643   return true;
00644 }
00645 
00646 /** Register for the events currently in the event list */
00647 bool
00648 TorControl::setEvents(QString *errmsg)
00649 {
00650   ControlCommand cmd("SETEVENTS");
00651 
00652   for (TorEvents::Event e = TorEvents::EVENT_MIN; e <= TorEvents::EVENT_MAX;) {
00653     if (_events & e)
00654       cmd.addArgument(TorEvents::toString(e));
00655     e = static_cast<TorEvents::Event>(e << 1);
00656   }
00657   return send(cmd, errmsg);
00658 }
00659 
00660 /** Sets each configuration key in <b>map</b> to the value associated
00661  * with its key. */
00662 bool
00663 TorControl::setConf(QHash<QString,QString> map, QString *errmsg)
00664 {
00665   ControlCommand cmd("SETCONF");
00666 
00667   /* Add each keyvalue to the argument list */
00668   foreach (QString key, map.uniqueKeys()) {
00669     /* If a key has multiple values (e.g., a QMultiHash), they are stored
00670      * in order from most recently inserted to least recently inserted.
00671      * So, walk the list in reverse so that we append the configuration
00672      * values to the SETCONF command in the same order they were inserted
00673      * into the QHash. */
00674     QList<QString> values = map.values(key);
00675     for (int i = values.size()-1; i >= 0; i--) {
00676       QString value = values.at(i);
00677       if (value.length() > 0)
00678         cmd.addArgument(key + "=" + string_escape(value));
00679       else
00680         cmd.addArgument(key);
00681     }
00682   }
00683   return send(cmd, errmsg);
00684 }
00685 
00686 /** Sets a single configuration key to the given value. */
00687 bool
00688 TorControl::setConf(QString key, QString value, QString *errmsg)
00689 {
00690   QHash<QString,QString> map;
00691   map.insert(key, value);
00692   return setConf(map, errmsg);
00693 }
00694 
00695 /** Sets a single configuration string that is formatted <key=escaped value>.*/
00696 bool
00697 TorControl::setConf(QString keyAndValue, QString *errmsg)
00698 {
00699   QHash<QString,QString> map;
00700   map.insert(keyAndValue, "");
00701   return setConf(map, errmsg);
00702 }
00703 
00704 /** Gets values for a set of configuration keys, each of which has a single
00705  * value. */
00706 bool
00707 TorControl::getConf(QHash<QString,QString> &map, QString *errmsg)
00708 {
00709   QHash<QString,QStringList> multiMap;
00710   foreach (QString key, map.keys()) {
00711     multiMap.insert(key, QStringList());
00712   }
00713   if (getConf(multiMap, errmsg)) {
00714     foreach (QString key, multiMap.keys()) {
00715       if (map.contains(key)) {
00716         map.insert(key, multiMap.value(key).join("\n"));
00717       }
00718     }
00719   }
00720   return false;
00721 }
00722 
00723 /** Gets a set of configuration keyvalues and stores them in <b>map</b>. */
00724 bool
00725 TorControl::getConf(QHash<QString,QStringList> &map, QString *errmsg)
00726 {
00727   ControlCommand cmd("GETCONF");
00728   ControlReply reply;
00729   QStringList confValue;
00730   QString confKey;
00731 
00732   /* Add the keys as arguments to the GETINFO message */
00733   foreach (QString key, map.keys()) {
00734     cmd.addArgument(key);
00735   }
00736 
00737   /* Ask Tor for the specified info values */
00738   if (send(cmd, reply, errmsg)) {
00739     /* Parse the response for the returned values */
00740     foreach (ReplyLine line, reply.getLines()) {
00741       /* Split the "key=val" line and map them */
00742       QStringList keyval = line.getMessage().split("=");
00743       if (keyval.size() == 2) {
00744         confKey = keyval.at(0);
00745 
00746         if (map.contains(confKey)) {
00747           /* This configuration key has multiple values, so add this one to
00748            * the list. */
00749           confValue = map.value(confKey);
00750         }
00751         confValue << keyval.at(1);
00752         map.insert(keyval.at(0), confValue);
00753       }
00754     }
00755     return true;
00756   }
00757   return false;
00758 }
00759 
00760 /** Gets a single configuration value for <b>key</b>. */
00761 bool
00762 TorControl::getConf(QString key, QString &value, QString *errmsg)
00763 {
00764   QStringList confValues;
00765   if (getConf(key, confValues, errmsg)) {
00766     value = confValues.join("\n");
00767     return true;
00768   }
00769   return false;
00770 }
00771 
00772 /** Gets a list of configuration values for <b>key</b>. */
00773 bool
00774 TorControl::getConf(QString key, QStringList &value, QString *errmsg)
00775 {
00776   QHash<QString,QStringList> map;
00777   map.insert(key, QStringList());
00778 
00779   if (getConf(map, errmsg)) {
00780     value = map.value(key);
00781     return true;
00782   }
00783   return false;
00784 }
00785 
00786 /** Sends a GETICONF message to Tor using the given list of <b>keys</b> and
00787  * returns a QVariantMap containing the specified keys and their values as
00788  * returned  by Tor. Returns a default constructed QVariantMap on failure. */
00789 QVariantMap
00790 TorControl::getConf(const QStringList &keys, QString *errmsg)
00791 {
00792   ControlCommand cmd("GETCONF");
00793   ControlReply reply;
00794   QVariantMap confMap;
00795 
00796   cmd.addArguments(keys);
00797   if (!send(cmd, reply, errmsg))
00798     return QVariantMap();
00799 
00800   foreach (ReplyLine line, reply.getLines()) {
00801     QString msg = line.getMessage();
00802     int index   = msg.indexOf("=");
00803     QString key = msg.mid(0, index);
00804     QString val;
00805 
00806     if (index > 0 && index < msg.length()-1)
00807       val = msg.mid(index+1);
00808 
00809     if (confMap.contains(key)) {
00810       QStringList values = confMap.value(key).toStringList();
00811       values << val;
00812       confMap.insert(key, values);
00813     } else {
00814       confMap.insert(key, val);
00815     }
00816   }
00817   return confMap;
00818 }
00819 
00820 /** Sends a GETCONF message to Tor with a single <b>key</b> and returns a
00821  * QVariant containing the value returned by Tor. Returns a default
00822  * constructed QVariant on failure. */
00823 QVariant
00824 TorControl::getConf(const QString &key, QString *errmsg)
00825 {
00826   QVariantMap map = getConf(QStringList() << key, errmsg);
00827   return map.value(key);
00828 }
00829 
00830 /** Sends a GETCONF message to Tor with the single key and returns a QString
00831  * containing the value returned by Tor */
00832 QString
00833 TorControl::getHiddenServiceConf(const QString &key, QString *errmsg)
00834 {
00835   ControlCommand cmd("GETCONF");
00836   ControlReply reply;
00837   QVariantMap confMap;
00838 
00839   cmd.addArgument(key);
00840   if (!send(cmd, reply, errmsg))
00841     return "";
00842 
00843   return reply.toString();
00844 }
00845 
00846 /** Asks Tor to save the current configuration to its torrc. */
00847 bool
00848 TorControl::saveConf(QString *errmsg)
00849 {
00850   ControlCommand cmd("SAVECONF");
00851   return send(cmd, errmsg);
00852 }
00853 
00854 /** Tells Tor to reset the given configuration keys back to defaults. */
00855 bool
00856 TorControl::resetConf(QStringList keys, QString *errmsg)
00857 {
00858   ControlCommand cmd("RESETCONF");
00859 
00860   /* Add each key to the argument list */
00861   foreach (QString key, keys) {
00862     cmd.addArgument(key);
00863   }
00864   return send(cmd, errmsg);
00865 }
00866 
00867 /** Tells Tor to reset a single given configuration key back to its default
00868  * value. */
00869 bool
00870 TorControl::resetConf(QString key, QString *errmsg)
00871 {
00872   return resetConf(QStringList() << key, errmsg);
00873 }
00874 
00875 /** Returns an unparsed router descriptor for the router whose fingerprint
00876  * matches <b>id</b>. The returned text can later be parsed by the
00877  * RouterDescriptor class. If <b>id</b> is invalid, then an empty
00878  * QStringList is returned. */
00879 QStringList
00880 TorControl::getRouterDescriptorText(const QString &id, QString *errmsg)
00881 {
00882   return getInfo("desc/id/" + id, errmsg).toStringList();
00883 }
00884 
00885 /** Returns the descriptor for the router whose fingerprint matches
00886  * <b>id</b>. If <b>id</b> is invalid or the router's descriptor cannot
00887  * be parsed, then an invalid RouterDescriptor is returned. */
00888 RouterDescriptor
00889 TorControl::getRouterDescriptor(const QString &id, QString *errmsg)
00890 {
00891   return RouterDescriptor(getRouterDescriptorText(id, errmsg));
00892 }
00893 
00894 /** Returns the status of the router whose fingerprint matches <b>id</b>. If
00895  * <b>id</b> is invalid or the router's status cannot be parsed, then an
00896  * invalid RouterStatus is returned. */
00897 RouterStatus
00898 TorControl::getRouterStatus(const QString &id, QString *errmsg)
00899 {
00900   QStringList status = getInfo("ns/id/" + id, errmsg).toStringList();
00901   return RouterStatus(status);
00902 }
00903 
00904 /** Returns a RouterStatus object for every known router in the network. If
00905  * the network status document cannot be parsed, then an empty NetworkStatus
00906  * is returned. */
00907 NetworkStatus
00908 TorControl::getNetworkStatus(QString *errmsg)
00909 {
00910   QStringList networkStatusLines = getInfo("ns/all", errmsg).toStringList();
00911   QList<RouterStatus> networkStatus;
00912   int len = networkStatusLines.size();
00913   int i = 0;
00914 
00915   while (i < len) {
00916     /* Extract the "r", "s", and whatever other status lines */
00917     QStringList routerStatusLines;
00918     do {
00919       routerStatusLines << networkStatusLines.at(i);
00920     } while (++i < len && ! networkStatusLines.at(i).startsWith("r "));
00921 
00922     /* Create a new RouterStatus object and add it to the network status, if
00923      * it's valid. */
00924     RouterStatus routerStatus(routerStatusLines);
00925     if (routerStatus.isValid())
00926       networkStatus << routerStatus;
00927   }
00928   return networkStatus;
00929 }
00930 
00931 /** Returns the annotations for the router whose fingerprint matches
00932  * <b>id</b>. If <b>id</b> is invalid or the router's annotations cannot be
00933  * parsed, then an empty DescriptorAnnotations is returned and <b>errmsg</b>
00934  * is set if it's not NULL. (Tor >= 0.2.0.13-alpha only) */
00935 DescriptorAnnotations
00936 TorControl::getDescriptorAnnotations(const QString &id, QString *errmsg)
00937 {
00938   QStringList lines = getInfo("desc-annotations/id/"+id, errmsg).toStringList();
00939   DescriptorAnnotations annotations;
00940   QString key, value;
00941 
00942   foreach (QString line, lines) {
00943     int idx = line.indexOf(" ");
00944 
00945     /* Extract the annotation key */
00946     key = line.mid(0, idx);
00947     if (key.startsWith("@"))
00948       key = key.remove(0, 1);
00949 
00950     /* Extract the annotation value (if present) */
00951     if (idx > 0 && idx < line.length()-1)
00952       annotations.insert(key, line.mid(idx + 1).trimmed());
00953     else
00954       annotations.insert(key, QString());
00955   }
00956   return annotations;
00957 }
00958 
00959 /** Gets a list of current circuits. */
00960 QList<Circuit>
00961 TorControl::getCircuits(QString *errmsg)
00962 {
00963   ControlCommand cmd("GETINFO", "circuit-status");
00964   ControlReply reply;
00965   CircuitList circuits;
00966 
00967   if (!send(cmd, reply, errmsg))
00968     return CircuitList();
00969 
00970   /* The rest of the circuits just come as data, one per line */
00971   foreach(QString line, reply.getData()) {
00972     Circuit circ(line);
00973     if (circ.isValid())
00974       circuits << circ;
00975   }
00976   return circuits;
00977 }
00978 
00979 /** Closes the circuit specified by <b>circId</b>. If <b>ifUnused</b> is
00980  * true, then the circuit will not be closed unless it is unused. */
00981 bool
00982 TorControl::closeCircuit(const CircuitId &circId, bool ifUnused, QString *errmsg)
00983 {
00984   ControlCommand cmd("CLOSECIRCUIT", circId);
00985   if (ifUnused) {
00986     cmd.addArgument("IfUnused");
00987   }
00988   return send(cmd, errmsg);
00989 }
00990 
00991 /** Gets a list of current streams. */
00992 QList<Stream>
00993 TorControl::getStreams(QString *errmsg)
00994 {
00995   ControlCommand cmd("GETINFO", "stream-status");
00996   ControlReply reply;
00997   QList<Stream> streams;
00998   Stream s;
00999 
01000   if (send(cmd, reply, errmsg)) {
01001     /* Sometimes there is a stream on the first message line */
01002     QString msg = reply.getMessage();
01003     s = Stream::fromString(msg.mid(msg.indexOf("=")+1));
01004     if (s.isValid())
01005       streams << s;
01006 
01007     /* The rest of the streams just come as data, one per line */
01008     foreach (QString line, reply.getData()) {
01009       s = Stream::fromString(line);
01010       if (s.isValid())
01011         streams << s;
01012     }
01013   }
01014   return streams;
01015 }
01016 
01017 /** Closes the stream specified by <b>streamId</b>. */
01018 bool
01019 TorControl::closeStream(const StreamId &streamId, QString *errmsg)
01020 {
01021   ControlCommand cmd("CLOSESTREAM", streamId);
01022   cmd.addArgument("1"); /* 1 == REASON_MISC (tor-spec.txt) */
01023   return send(cmd, errmsg);
01024 }
01025 
01026  /** Gets a list of address mappings of the type specified by <b>type</b>
01027   * (defaults to <i>AddressMapAll</i>. */
01028 AddressMap
01029 TorControl::getAddressMap(AddressMap::AddressMapType type, QString *errmsg)
01030 {
01031   AddressMap addressMap;
01032   QStringList entries;
01033 
01034   switch (type) {
01035     case AddressMap::AddressMapConfig:
01036       entries = getInfo("address-mappings/config").toStringList();
01037       break;
01038     case AddressMap::AddressMapCache:
01039       entries = getInfo("address-mappings/cache").toStringList();
01040       break;
01041     case AddressMap::AddressMapControl:
01042       entries = getInfo("address-mappings/control").toStringList();
01043       break;
01044     default:
01045       entries = getInfo("address-mappings/all").toStringList();
01046   }
01047 
01048   foreach (QString entry, entries) {
01049     addressMap.add(entry);
01050   }
01051   return addressMap;
01052 }
01053 
Generated on Mon Aug 30 23:09:51 2010 for Vidalia by  doxygen 1.6.3