00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00029 TorControl::TorControl()
00030 {
00031 #define RELAY_SIGNAL(src, sig) \
00032 QObject::connect((src), (sig), this, (sig))
00033
00034
00035
00036
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
00071
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
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
00098 TorControl::~TorControl()
00099 {
00100
00101 if (isConnected()) {
00102 disconnect();
00103 }
00104
00105 if (isVidaliaRunningTor()) {
00106 stop();
00107 }
00108 delete _controlConn;
00109 }
00110
00111
00112
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
00121
00122 if (TorService::isSupported() && _torService->isInstalled())
00123 _torService->start();
00124 else
00125 _torProcess->start(expand_filename(tor), args);
00126 #else
00127
00128 _torProcess->start(expand_filename(tor), args);
00129 #endif
00130 }
00131 }
00132
00133
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
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
00157
00158 bool
00159 TorControl::isVidaliaRunningTor()
00160 {
00161 return (_torProcess->state() != QProcess::NotRunning);
00162 }
00163
00164
00165 bool
00166 TorControl::isRunning()
00167 {
00168 return (_torProcess->state() != QProcess::NotRunning
00169 || _controlConn->isConnected());
00170 }
00171
00172
00173
00174 void
00175 TorControl::closeTorStdout()
00176 {
00177 if (_torProcess)
00178 _torProcess->closeStdout();
00179 }
00180
00181
00182 void
00183 TorControl::onLogStdout(const QString &severity, const QString &message)
00184 {
00185 emit logMessage(tc::severityFromString(severity), message.trimmed());
00186 }
00187
00188
00189
00190 void
00191 TorControl::connect(const QHostAddress &address, quint16 port)
00192 {
00193 _controlConn->connect(address, port);
00194 }
00195
00196
00197 void
00198 TorControl::disconnect()
00199 {
00200 if (isConnected())
00201 _controlConn->disconnect();
00202 }
00203
00204
00205 void
00206 TorControl::onDisconnected()
00207 {
00208 if (_torProcess) {
00209
00210
00211
00212 _torProcess->openStdout();
00213 }
00214
00215 _torVersion = QString();
00216
00217
00218 emit disconnected();
00219 }
00220
00221
00222 bool
00223 TorControl::isConnected()
00224 {
00225 return _controlConn->isConnected();
00226 }
00227
00228
00229
00230
00231
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
00247 bool
00248 TorControl::send(ControlCommand cmd, QString *errmsg)
00249 {
00250 ControlReply reply;
00251 return send(cmd, reply, errmsg);
00252 }
00253
00254
00255
00256
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
00274
00275
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
00293 void
00294 TorControl::onAuthenticated()
00295 {
00296
00297
00298 getInfo("version", _torVersion);
00299
00300 useFeature("VERBOSE_NAMES");
00301
00302 useFeature("EXTENDED_EVENTS");
00303
00304 emit authenticated();
00305 }
00306
00307
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;
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
00352
00353
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
00381
00382 bool
00383 TorControl::isCircuitEstablished()
00384 {
00385
00386
00387 if (getTorVersion() >= 0x020001) {
00388 QString tmp;
00389 if (getInfo("status/circuit-established", tmp))
00390 return (tmp == "1");
00391 }
00392
00393
00394
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
00404
00405
00406
00407
00408 bool
00409 TorControl::getInfo(QHash<QString,QString> &map, QString *errmsg)
00410 {
00411 ControlCommand cmd("GETINFO");
00412 ControlReply reply;
00413
00414
00415 foreach (QString key, map.keys()) {
00416 cmd.addArgument(key);
00417 }
00418
00419
00420 if (send(cmd, reply, errmsg)) {
00421
00422 foreach (ReplyLine line, reply.getLines()) {
00423
00424 QStringList keyval = line.getMessage().split("=");
00425 if (keyval.size() == 2) {
00426 map.insert(keyval.at(0), keyval.at(1));
00427 }
00428 }
00429 return true;
00430 }
00431 return false;
00432 }
00433
00434
00435
00436
00437 QVariantMap
00438 TorControl::getInfo(const QStringList &keys, QString *errmsg)
00439 {
00440 ControlCommand cmd("GETINFO");
00441 ControlReply reply;
00442 QVariantMap infoMap;
00443
00444 cmd.addArguments(keys);
00445 if (!send(cmd, reply, errmsg))
00446 return QVariantMap();
00447
00448 foreach (ReplyLine line, reply.getLines()) {
00449 QString msg = line.getMessage();
00450 int index = msg.indexOf("=");
00451 QString key = msg.mid(0, index);
00452 QStringList val;
00453
00454 if (index > 0 && index < msg.length()-1)
00455 val << msg.mid(index+1);
00456 if (line.hasData())
00457 val << line.getData();
00458
00459 if (infoMap.contains(key)) {
00460 QStringList values = infoMap.value(key).toStringList();
00461 values << val;
00462 infoMap.insert(key, values);
00463 } else {
00464 infoMap.insert(key, val);
00465 }
00466 }
00467 return infoMap;
00468 }
00469
00470
00471
00472
00473 QVariant
00474 TorControl::getInfo(const QString &key, QString *errmsg)
00475 {
00476 QVariantMap map = getInfo(QStringList() << key, errmsg);
00477 return map.value(key);
00478 }
00479
00480
00481 bool
00482 TorControl::getInfo(QString key, QString &val, QString *errmsg)
00483 {
00484 QHash<QString,QString> map;
00485 map.insert(key, "");
00486
00487 if (getInfo(map, errmsg)) {
00488 val = map.value(key);
00489 return true;
00490 }
00491 return false;
00492 }
00493
00494
00495 bool
00496 TorControl::signal(TorSignal::Signal sig, QString *errmsg)
00497 {
00498 ControlCommand cmd("SIGNAL");
00499 cmd.addArgument(TorSignal::toString(sig));
00500
00501 if (sig == TorSignal::Shutdown || sig == TorSignal::Halt) {
00502
00503
00504 return _controlConn->send(cmd, errmsg);
00505 }
00506 return send(cmd, errmsg);
00507 }
00508
00509
00510
00511 QHostAddress
00512 TorControl::getSocksAddress(QString *errmsg)
00513 {
00514 QHostAddress socksAddr;
00515
00516
00517 if (getSocksPort() == 0) {
00518 return QHostAddress::Null;
00519 }
00520
00521
00522
00523 QStringList addrList = getSocksAddressList(errmsg);
00524 foreach (QString addr, addrList) {
00525 addr = addr.mid(0, addr.indexOf(":"));
00526 if (socksAddr.setAddress(addr)) {
00527 return socksAddr;
00528 }
00529 }
00530
00531 return QHostAddress::LocalHost;
00532 }
00533
00534
00535
00536 QStringList
00537 TorControl::getSocksAddressList(QString *errmsg)
00538 {
00539 QStringList addrList;
00540 if (getConf("SocksListenAddress", addrList, errmsg)) {
00541 return addrList;
00542 }
00543 return QStringList();
00544 }
00545
00546
00547
00548 quint16
00549 TorControl::getSocksPort(QString *errmsg)
00550 {
00551 QList<quint16> portList = getSocksPortList(errmsg);
00552 if (portList.size() > 0) {
00553 return portList.at(0);
00554 }
00555 return 0;
00556 }
00557
00558
00559
00560 QList<quint16>
00561 TorControl::getSocksPortList(QString *errmsg)
00562 {
00563 bool valid;
00564 quint16 port, socksPort;
00565 QString portString;
00566 QList<quint16> portList;
00567
00568
00569 if (getConf("SocksPort", portString, errmsg)) {
00570 socksPort = (quint16)portString.toUInt(&valid);
00571 if (valid) {
00572 if (socksPort == 0) {
00573
00574
00575 return QList<quint16>();
00576 }
00577 }
00578 }
00579
00580 QStringList addrList = getSocksAddressList(errmsg);
00581 foreach (QString addr, addrList) {
00582 if (addr.contains(":")) {
00583 portString = addr.mid(addr.indexOf(":")+1);
00584 port = (quint16)portString.toUInt(&valid);
00585 if (valid) {
00586 portList << port;
00587 }
00588 }
00589 }
00590
00591
00592 if (!portList.size() || (portList.size() != addrList.size())) {
00593 portList << socksPort;
00594 }
00595 return portList;
00596 }
00597
00598
00599 QString
00600 TorControl::getTorVersionString()
00601 {
00602 return _torVersion;
00603 }
00604
00605
00606
00607 quint32
00608 TorControl::getTorVersion()
00609 {
00610 static QString versionString;
00611 static quint32 version = 0;
00612 quint8 major, minor, micro, patch;
00613
00614
00615 if (versionString == _torVersion)
00616 return version;
00617 versionString = _torVersion;
00618
00619
00620 QStringList parts = versionString.split(QRegExp("\\.|-|\\ "));
00621 if (parts.size() >= 4) {
00622 major = (quint8)parts.at(0).toUInt();
00623 minor = (quint8)parts.at(1).toUInt();
00624 micro = (quint8)parts.at(2).toUInt();
00625 patch = (quint8)parts.at(3).toUInt();
00626 version = ((major << 24) | (minor << 16) | (micro << 8) | patch);
00627 } else {
00628
00629 version = 0;
00630 }
00631 return version;
00632 }
00633
00634
00635
00636
00637 bool
00638 TorControl::setEvent(TorEvents::Event e, bool add, bool set, QString *errmsg)
00639 {
00640 _events = (add ? (_events | e) : (_events & ~e));
00641 if (set && isConnected())
00642 return setEvents(errmsg);
00643 return true;
00644 }
00645
00646
00647 bool
00648 TorControl::setEvents(QString *errmsg)
00649 {
00650 ControlCommand cmd("SETEVENTS");
00651
00652 for (TorEvents::Event e = TorEvents::EVENT_MIN; e <= TorEvents::EVENT_MAX;) {
00653 if (_events & e)
00654 cmd.addArgument(TorEvents::toString(e));
00655 e = static_cast<TorEvents::Event>(e << 1);
00656 }
00657 return send(cmd, errmsg);
00658 }
00659
00660
00661
00662 bool
00663 TorControl::setConf(QHash<QString,QString> map, QString *errmsg)
00664 {
00665 ControlCommand cmd("SETCONF");
00666
00667
00668 foreach (QString key, map.uniqueKeys()) {
00669
00670
00671
00672
00673
00674 QList<QString> values = map.values(key);
00675 for (int i = values.size()-1; i >= 0; i--) {
00676 QString value = values.at(i);
00677 if (value.length() > 0)
00678 cmd.addArgument(key + "=" + string_escape(value));
00679 else
00680 cmd.addArgument(key);
00681 }
00682 }
00683 return send(cmd, errmsg);
00684 }
00685
00686
00687 bool
00688 TorControl::setConf(QString key, QString value, QString *errmsg)
00689 {
00690 QHash<QString,QString> map;
00691 map.insert(key, value);
00692 return setConf(map, errmsg);
00693 }
00694
00695
00696 bool
00697 TorControl::setConf(QString keyAndValue, QString *errmsg)
00698 {
00699 QHash<QString,QString> map;
00700 map.insert(keyAndValue, "");
00701 return setConf(map, errmsg);
00702 }
00703
00704
00705
00706 bool
00707 TorControl::getConf(QHash<QString,QString> &map, QString *errmsg)
00708 {
00709 QHash<QString,QStringList> multiMap;
00710 foreach (QString key, map.keys()) {
00711 multiMap.insert(key, QStringList());
00712 }
00713 if (getConf(multiMap, errmsg)) {
00714 foreach (QString key, multiMap.keys()) {
00715 if (map.contains(key)) {
00716 map.insert(key, multiMap.value(key).join("\n"));
00717 }
00718 }
00719 }
00720 return false;
00721 }
00722
00723
00724 bool
00725 TorControl::getConf(QHash<QString,QStringList> &map, QString *errmsg)
00726 {
00727 ControlCommand cmd("GETCONF");
00728 ControlReply reply;
00729 QStringList confValue;
00730 QString confKey;
00731
00732
00733 foreach (QString key, map.keys()) {
00734 cmd.addArgument(key);
00735 }
00736
00737
00738 if (send(cmd, reply, errmsg)) {
00739
00740 foreach (ReplyLine line, reply.getLines()) {
00741
00742 QStringList keyval = line.getMessage().split("=");
00743 if (keyval.size() == 2) {
00744 confKey = keyval.at(0);
00745
00746 if (map.contains(confKey)) {
00747
00748
00749 confValue = map.value(confKey);
00750 }
00751 confValue << keyval.at(1);
00752 map.insert(keyval.at(0), confValue);
00753 }
00754 }
00755 return true;
00756 }
00757 return false;
00758 }
00759
00760
00761 bool
00762 TorControl::getConf(QString key, QString &value, QString *errmsg)
00763 {
00764 QStringList confValues;
00765 if (getConf(key, confValues, errmsg)) {
00766 value = confValues.join("\n");
00767 return true;
00768 }
00769 return false;
00770 }
00771
00772
00773 bool
00774 TorControl::getConf(QString key, QStringList &value, QString *errmsg)
00775 {
00776 QHash<QString,QStringList> map;
00777 map.insert(key, QStringList());
00778
00779 if (getConf(map, errmsg)) {
00780 value = map.value(key);
00781 return true;
00782 }
00783 return false;
00784 }
00785
00786
00787
00788
00789 QVariantMap
00790 TorControl::getConf(const QStringList &keys, QString *errmsg)
00791 {
00792 ControlCommand cmd("GETCONF");
00793 ControlReply reply;
00794 QVariantMap confMap;
00795
00796 cmd.addArguments(keys);
00797 if (!send(cmd, reply, errmsg))
00798 return QVariantMap();
00799
00800 foreach (ReplyLine line, reply.getLines()) {
00801 QString msg = line.getMessage();
00802 int index = msg.indexOf("=");
00803 QString key = msg.mid(0, index);
00804 QString val;
00805
00806 if (index > 0 && index < msg.length()-1)
00807 val = msg.mid(index+1);
00808
00809 if (confMap.contains(key)) {
00810 QStringList values = confMap.value(key).toStringList();
00811 values << val;
00812 confMap.insert(key, values);
00813 } else {
00814 confMap.insert(key, val);
00815 }
00816 }
00817 return confMap;
00818 }
00819
00820
00821
00822
00823 QVariant
00824 TorControl::getConf(const QString &key, QString *errmsg)
00825 {
00826 QVariantMap map = getConf(QStringList() << key, errmsg);
00827 return map.value(key);
00828 }
00829
00830
00831
00832 QString
00833 TorControl::getHiddenServiceConf(const QString &key, QString *errmsg)
00834 {
00835 ControlCommand cmd("GETCONF");
00836 ControlReply reply;
00837 QVariantMap confMap;
00838
00839 cmd.addArgument(key);
00840 if (!send(cmd, reply, errmsg))
00841 return "";
00842
00843 return reply.toString();
00844 }
00845
00846
00847 bool
00848 TorControl::saveConf(QString *errmsg)
00849 {
00850 ControlCommand cmd("SAVECONF");
00851 return send(cmd, errmsg);
00852 }
00853
00854
00855 bool
00856 TorControl::resetConf(QStringList keys, QString *errmsg)
00857 {
00858 ControlCommand cmd("RESETCONF");
00859
00860
00861 foreach (QString key, keys) {
00862 cmd.addArgument(key);
00863 }
00864 return send(cmd, errmsg);
00865 }
00866
00867
00868
00869 bool
00870 TorControl::resetConf(QString key, QString *errmsg)
00871 {
00872 return resetConf(QStringList() << key, errmsg);
00873 }
00874
00875
00876
00877
00878
00879 QStringList
00880 TorControl::getRouterDescriptorText(const QString &id, QString *errmsg)
00881 {
00882 return getInfo("desc/id/" + id, errmsg).toStringList();
00883 }
00884
00885
00886
00887
00888 RouterDescriptor
00889 TorControl::getRouterDescriptor(const QString &id, QString *errmsg)
00890 {
00891 return RouterDescriptor(getRouterDescriptorText(id, errmsg));
00892 }
00893
00894
00895
00896
00897 RouterStatus
00898 TorControl::getRouterStatus(const QString &id, QString *errmsg)
00899 {
00900 QStringList status = getInfo("ns/id/" + id, errmsg).toStringList();
00901 return RouterStatus(status);
00902 }
00903
00904
00905
00906
00907 NetworkStatus
00908 TorControl::getNetworkStatus(QString *errmsg)
00909 {
00910 QStringList networkStatusLines = getInfo("ns/all", errmsg).toStringList();
00911 QList<RouterStatus> networkStatus;
00912 int len = networkStatusLines.size();
00913 int i = 0;
00914
00915 while (i < len) {
00916
00917 QStringList routerStatusLines;
00918 do {
00919 routerStatusLines << networkStatusLines.at(i);
00920 } while (++i < len && ! networkStatusLines.at(i).startsWith("r "));
00921
00922
00923
00924 RouterStatus routerStatus(routerStatusLines);
00925 if (routerStatus.isValid())
00926 networkStatus << routerStatus;
00927 }
00928 return networkStatus;
00929 }
00930
00931
00932
00933
00934
00935 DescriptorAnnotations
00936 TorControl::getDescriptorAnnotations(const QString &id, QString *errmsg)
00937 {
00938 QStringList lines = getInfo("desc-annotations/id/"+id, errmsg).toStringList();
00939 DescriptorAnnotations annotations;
00940 QString key, value;
00941
00942 foreach (QString line, lines) {
00943 int idx = line.indexOf(" ");
00944
00945
00946 key = line.mid(0, idx);
00947 if (key.startsWith("@"))
00948 key = key.remove(0, 1);
00949
00950
00951 if (idx > 0 && idx < line.length()-1)
00952 annotations.insert(key, line.mid(idx + 1).trimmed());
00953 else
00954 annotations.insert(key, QString());
00955 }
00956 return annotations;
00957 }
00958
00959
00960 QList<Circuit>
00961 TorControl::getCircuits(QString *errmsg)
00962 {
00963 ControlCommand cmd("GETINFO", "circuit-status");
00964 ControlReply reply;
00965 CircuitList circuits;
00966
00967 if (!send(cmd, reply, errmsg))
00968 return CircuitList();
00969
00970
00971 foreach(QString line, reply.getData()) {
00972 Circuit circ(line);
00973 if (circ.isValid())
00974 circuits << circ;
00975 }
00976 return circuits;
00977 }
00978
00979
00980
00981 bool
00982 TorControl::closeCircuit(const CircuitId &circId, bool ifUnused, QString *errmsg)
00983 {
00984 ControlCommand cmd("CLOSECIRCUIT", circId);
00985 if (ifUnused) {
00986 cmd.addArgument("IfUnused");
00987 }
00988 return send(cmd, errmsg);
00989 }
00990
00991
00992 QList<Stream>
00993 TorControl::getStreams(QString *errmsg)
00994 {
00995 ControlCommand cmd("GETINFO", "stream-status");
00996 ControlReply reply;
00997 QList<Stream> streams;
00998 Stream s;
00999
01000 if (send(cmd, reply, errmsg)) {
01001
01002 QString msg = reply.getMessage();
01003 s = Stream::fromString(msg.mid(msg.indexOf("=")+1));
01004 if (s.isValid())
01005 streams << s;
01006
01007
01008 foreach (QString line, reply.getData()) {
01009 s = Stream::fromString(line);
01010 if (s.isValid())
01011 streams << s;
01012 }
01013 }
01014 return streams;
01015 }
01016
01017
01018 bool
01019 TorControl::closeStream(const StreamId &streamId, QString *errmsg)
01020 {
01021 ControlCommand cmd("CLOSESTREAM", streamId);
01022 cmd.addArgument("1");
01023 return send(cmd, errmsg);
01024 }
01025
01026
01027
01028 AddressMap
01029 TorControl::getAddressMap(AddressMap::AddressMapType type, QString *errmsg)
01030 {
01031 AddressMap addressMap;
01032 QStringList entries;
01033
01034 switch (type) {
01035 case AddressMap::AddressMapConfig:
01036 entries = getInfo("address-mappings/config").toStringList();
01037 break;
01038 case AddressMap::AddressMapCache:
01039 entries = getInfo("address-mappings/cache").toStringList();
01040 break;
01041 case AddressMap::AddressMapControl:
01042 entries = getInfo("address-mappings/control").toStringList();
01043 break;
01044 default:
01045 entries = getInfo("address-mappings/all").toStringList();
01046 }
01047
01048 foreach (QString entry, entries) {
01049 addressMap.add(entry);
01050 }
01051 return addressMap;
01052 }
01053