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