Vidalia 0.2.10
|
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