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