Vidalia 0.3.1
TorControl.cpp
Go to the documentation of this file.
1/*
2** This file is part of Vidalia, and is subject to the license terms in the
3** LICENSE file, found in the top level directory of this distribution. If
4** you did not receive the LICENSE file with this file, you may obtain it
5** from the Vidalia source package distributed by the Vidalia Project at
6** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7** including this file, may be copied, modified, propagated, or distributed
8** except according to the terms described in the LICENSE file.
9*/
10
11/*
12** \file TorControl.cpp
13** \brief Object for interacting with the Tor process and control interface
14*/
15
16#include "TorControl.h"
17#include "RouterDescriptor.h"
18#include "ProtocolInfo.h"
19#include "RouterStatus.h"
20#include "file.h"
21#include "stringutil.h"
22
23#include <QHostAddress>
24#include <QVariantMap>
25
26
27/** Default constructor */
29{
30#define RELAY_SIGNAL(src, sig) \
31 QObject::connect((src), (sig), this, (sig))
32
33 /* Create a TorEvents object to receive and parse asynchronous events
34 * from Tor's control port, and relay them as external signals from
35 * this TorControl object. */
36 _eventHandler = new TorEvents(this);
39 QString, QStringList)));
40 RELAY_SIGNAL(_eventHandler, SIGNAL(addressMapped(QString,QString,QDateTime)));
41 RELAY_SIGNAL(_eventHandler, SIGNAL(bandwidthUpdate(quint64, quint64)));
44 RELAY_SIGNAL(_eventHandler, SIGNAL(newDescriptors(QStringList)));
46 RELAY_SIGNAL(_eventHandler, SIGNAL(dangerousPort(quint16, bool)));
49 RELAY_SIGNAL(_eventHandler, SIGNAL(clockSkewed(int, QString)));
50 RELAY_SIGNAL(_eventHandler, SIGNAL(bug(QString)));
54 SIGNAL(externalAddressChanged(QHostAddress, QString)));
56 SIGNAL(checkingOrPortReachability(QHostAddress, quint16)));
58 SIGNAL(orPortReachabilityFinished(QHostAddress,quint16,bool)));
60 SIGNAL(checkingDirPortReachability(QHostAddress, quint16)));
62 SIGNAL(dirPortReachabilityFinished(QHostAddress,quint16,bool)));
64 SIGNAL(serverDescriptorRejected(QHostAddress, quint16, QString)));
66 SIGNAL(serverDescriptorAccepted(QHostAddress, quint16)));
68
69 /* Create an instance of a connection to Tor's control interface and give
70 * it an object to use to handle asynchronous events. */
73 RELAY_SIGNAL(_controlConn, SIGNAL(connectFailed(QString)));
75 this, SLOT(onDisconnected()));
76
77 /* Create an object used to start and stop a Tor process. */
78 _torProcess = new TorProcess(this);
80 RELAY_SIGNAL(_torProcess, SIGNAL(startFailed(QString)));
81 QObject::connect(_torProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
82 this, SLOT(onStopped(int, QProcess::ExitStatus)));
83 QObject::connect(_torProcess, SIGNAL(log(QString, QString)),
84 this, SLOT(onLogStdout(QString, QString)));
85
86#if defined(Q_OS_WIN32)
87 _torService = new TorService(this);
88 RELAY_SIGNAL(_torService, SIGNAL(started()));
89 RELAY_SIGNAL(_torService, SIGNAL(startFailed(QString)));
90 QObject::connect(_torService, SIGNAL(finished(int, QProcess::ExitStatus)),
91 this, SLOT(onStopped(int, QProcess::ExitStatus)));
92#endif
93#undef RELAY_SIGNAL
94 _method = method;
95}
96
97/** Default destructor */
99{
100 /* If we started our own Tor, stop it now */
101 if (isVidaliaRunningTor()) {
102 stop();
103 }
104 delete _controlConn;
105}
106
107/** Start the Tor process using the executable <b>tor</b> and the list of
108 * arguments in <b>args</b>. */
109void
110TorControl::start(const QString &tor, const QStringList &args)
111{
112 if (isRunning()) {
113 emit started();
114 } else {
115#if defined(Q_OS_WIN32)
116 /* If the Tor service is installed, run that. Otherwise, start a new
117 * Tor process. */
118 if (TorService::isSupported() && _torService->isInstalled())
119 _torService->start();
120 else
121 _torProcess->start(expand_filename(tor), args);
122#else
123 /* Start a new Tor process */
124 _torProcess->start(expand_filename(tor), args);
125#endif
126 }
127}
128
129/** Stop the Tor process. */
130bool
131TorControl::stop(QString *errmsg)
132{
133 bool rc = false;
134
135 if (!isVidaliaRunningTor()) {
136 *errmsg = tr("Vidalia has not started Tor. "
137 "You need to stop Tor through the interface you started it.");
138 return rc;
139 } else {
141 rc = signal(TorSignal::Halt, errmsg);
142 if (!rc)
143 rc = _torProcess->stop(errmsg);
144 }
145
146 return rc;
147}
148
149/** Emits a signal that the Tor process stopped */
150void
151TorControl::onStopped(int exitCode, QProcess::ExitStatus exitStatus)
152{
155
156 emit stopped();
157 emit stopped(exitCode, exitStatus);
158}
159
160/** Detects if the Tor process is running under Vidalia. Returns true if
161 * Vidalia owns the Tor process, or false if it was an independent Tor. */
162bool
164{
165 return (_torProcess->state() != QProcess::NotRunning);
166}
167
168/** Detect if the Tor process is running. */
169bool
171{
172 return (_torProcess->state() != QProcess::NotRunning
174}
175
176/** Stops reading log messages from the Tor process's stdout. This has no
177 * effect if isVidaliaRunningTor() is false. */
178void
180{
181 if (_torProcess)
183}
184
185/** Called when Tor has printed a log message to stdout. */
186void
187TorControl::onLogStdout(const QString &severity, const QString &message)
188{
189 emit logMessage(tc::severityFromString(severity), message.trimmed());
190}
191
192/** Connect to Tor's control port. The control port to use is determined by
193 * Vidalia's configuration file. */
194void
195TorControl::connect(const QHostAddress &address, quint16 port)
196{
197 _controlConn->connect(address, port);
198}
199
200/** Connect to Tor's control socket. The control socket to use is determined by
201 * Vidalia's configuration file. */
202void
203TorControl::connect(const QString &path)
204{
205 _controlConn->connect(path);
206}
207
208/** Disconnect from Tor's control port */
209void
211{
212 if (isConnected())
214}
215
216void
218{
219 ControlCommand cmd("GETINFO", "status/bootstrap-phase");
220 ControlReply reply;
221 QString str;
222
223 if (!send(cmd, reply, &str)) {
224 return;
225 }
226
227 bool ok;
228 QHash<QString, QString> args;
229 args = string_parse_keyvals(reply.getMessage(), &ok);
230
231 if(!ok)
232 return;
233
234 tc::Severity severity = tc::severityFromString(args.value("status/bootstrap-phase"));
235 BootstrapStatus status
236 = BootstrapStatus(severity,
237 BootstrapStatus::statusFromString(args.value("TAG")),
238 args.value("PROGRESS").toInt(),
239 args.value("SUMMARY"));
240 emit bootstrapStatusChanged(status);
241}
242
243/** Emits a signal that the control socket disconnected from Tor */
244void
246{
247 if (_torProcess) {
248 /* If we're running a Tor process, then start reading logs from stdout
249 * again, in case our control connection just died but Tor is still
250 * running. In this case, there may be relevant information in the logs. */
252 }
253 /* Tor isn't running, so it has no version */
254 _torVersion = QString();
255
256 /* Let interested parties know we lost our control connection */
257 emit disconnected();
258}
259
260/** Check if the control socket is connected */
261bool
263{
264 return _controlConn->isConnected();
265}
266
267/** Send a message to Tor and reads the response. If Vidalia was unable to
268 * send the command to Tor or read its response, false is returned. If the
269 * response was read and the status code is not 250 OK, false is also
270 * returned. */
271bool
272TorControl::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
273{
274 if (_controlConn->send(cmd, reply, errmsg)) {
275 if (reply.getStatus() == "250") {
276 return true;
277 }
278 if (errmsg) {
279 *errmsg = reply.getMessage();
280 }
281 }
282 return false;
283}
284
285/** Sends a message to Tor and discards the response. */
286bool
287TorControl::send(ControlCommand cmd, QString *errmsg)
288{
289 ControlReply reply;
290 return send(cmd, reply, errmsg);
291}
292
293/** Sends an authentication cookie to Tor. The syntax is:
294 *
295 * "AUTHENTICATE" SP 1*HEXDIG CRLF
296 */
297bool
298TorControl::authenticate(const QByteArray cookie, QString *errmsg)
299{
300 ControlCommand cmd("AUTHENTICATE", base16_encode(cookie));
301 ControlReply reply;
302 QString str;
303
304 if (!send(cmd, reply, &str)) {
305 emit authenticationFailed(str);
306 return err(errmsg, str);
307 }
309 return true;
310}
311
312/** Sends an authentication password to Tor. The syntax is:
313 *
314 * "AUTHENTICATE" SP QuotedString CRLF
315 */
316bool
317TorControl::authenticate(const QString &password, QString *errmsg)
318{
319 ControlCommand cmd("AUTHENTICATE", string_escape(password));
320 ControlReply reply;
321 QString str;
322
323 if (!send(cmd, reply, &str)) {
324 emit authenticationFailed(str);
325 return err(errmsg, str);
326 }
328 return true;
329}
330
331/** Called when the controller has successfully authenticated to Tor. */
332void
334{
335 /* The version of Tor isn't going to change while we're connected to it, so
336 * save it for later. */
337 getInfo("version", _torVersion);
338 /* We want to use verbose names in events and GETINFO results. */
339 useFeature("VERBOSE_NAMES");
340 /* We want to use extended events in all async events */
341 useFeature("EXTENDED_EVENTS");
342
344
345 emit authenticated();
346}
347
348/** Sends a PROTOCOLINFO command to Tor and parses the response. */
351{
352 ControlCommand cmd("PROTOCOLINFO", "1");
353 ControlReply reply;
354 ProtocolInfo pi;
355 QString msg, topic;
356 QHash<QString,QString> keyvals;
357 int idx;
358 bool ok;
359
360 if (!send(cmd, reply, errmsg))
361 return ProtocolInfo();
362
363 foreach (ReplyLine line, reply.getLines()) {
364 if (line.getStatus() != "250")
365 continue;
366
367 msg = line.getMessage().trimmed();
368 idx = msg.indexOf(" ");
369 topic = msg.mid(0, idx).toUpper();
370
371 if (idx > 0) {
372 keyvals = string_parse_keyvals(msg.mid(idx+1), &ok);
373 if (!ok)
374 continue; /* Ignore malformed lines */
375 } else {
376 keyvals = QHash<QString,QString>();
377 }
378
379 if (topic == "AUTH") {
380 if (keyvals.contains("METHODS"))
381 pi.setAuthMethods(keyvals.value("METHODS"));
382 if (keyvals.contains("COOKIEFILE"))
383 pi.setCookieAuthFile(keyvals.value("COOKIEFILE"));
384 } else if (topic == "VERSION") {
385 if (keyvals.contains("Tor"))
386 pi.setTorVersion(keyvals.value("Tor"));
387 }
388 }
389 return pi;
390}
391
392/** Tells Tor the controller wants to enable <b>feature</b> via the
393 * USEFEATURE control command. Returns true if the given feature was
394 * successfully enabled. */
395bool
396TorControl::useFeature(const QString &feature, QString *errmsg)
397{
398 ControlCommand cmd("USEFEATURE", feature);
399 return send(cmd, errmsg);
400}
401
404{
405 QString str = getInfo("status/bootstrap-phase").toString();
406 if (!str.isEmpty()) {
407 tc::Severity severity = tc::severityFromString(str.section(' ', 0, 0));
408 QHash<QString,QString> args = string_parse_keyvals(str);
409 return BootstrapStatus(severity,
410 BootstrapStatus::statusFromString(args.value("TAG")),
411 args.value("PROGRESS").toInt(),
412 args.value("SUMMARY"),
413 args.value("WARNING"),
414 tc::connectionStatusReasonFromString(args.value("REASON")),
416 args.value("RECOMMENDATION")));
417 }
418 return BootstrapStatus();
419}
420
421/** Returns true if Tor either has an open circuit or (on Tor >=
422 * 0.2.0.1-alpha) has previously decided it's able to establish a circuit. */
423bool
425{
426 /* If Tor is recent enough, we can 'getinfo status/circuit-established' to
427 * see if Tor has an open circuit */
428 if (getTorVersion() >= 0x020001) {
429 QString tmp;
430 if (getInfo("status/circuit-established", tmp))
431 return (tmp == "1");
432 }
433
434 /* Either Tor was too old or our getinfo failed, so try to get a list of all
435 * circuits and check their statuses. */
436 CircuitList circs = getCircuits();
437 foreach (Circuit circ, circs) {
438 if (circ.status() == Circuit::Built)
439 return true;
440 }
441 return false;
442}
443
444/** Sends a GETINFO message to Tor based on the given map of keyvals. The
445 * syntax is:
446 *
447 * "GETINFO" 1*(SP keyword) CRLF
448 */
449bool
450TorControl::getInfo(QHash<QString,QString> &map, QString *errmsg)
451{
452 ControlCommand cmd("GETINFO");
453 ControlReply reply;
454
455 /* Add the keys as arguments to the GETINFO message */
456 foreach (QString key, map.keys()) {
457 cmd.addArgument(key);
458 }
459
460 /* Ask Tor for the specified info values */
461 if (send(cmd, reply, errmsg)) {
462 /* Parse the response for the returned values */
463 foreach (ReplyLine line, reply.getLines()) {
464 /* Split the "key=val" line and map them */
465 QStringList keyval = line.getMessage().split("=");
466 if (keyval.size() == 2) {
467 QString key = keyval.at(0);
468 QString val = keyval.at(1);
469 if (val.startsWith(QLatin1Char('\"')) &&
470 val.endsWith(QLatin1Char('\"'))) {
471 bool ok;
472 val = string_unescape(val, &ok);
473 if (! ok)
474 continue;
475 }
476 map.insert(key, val);
477 }
478 }
479 return true;
480 }
481 return false;
482}
483
484/** Sends a GETINFO message to Tor using the given list of <b>keys</b> and
485 * returns a QVariantMap containing the specified keys and their values as
486 * returned by Tor. Returns a default constructed QVariantMap on failure. */
487QVariantMap
488TorControl::getInfo(const QStringList &keys, QString *errmsg)
489{
490 ControlCommand cmd("GETINFO");
491 ControlReply reply;
492 QVariantMap infoMap;
493
494 cmd.addArguments(keys);
495 if (!send(cmd, reply, errmsg))
496 return QVariantMap();
497
498 foreach (ReplyLine line, reply.getLines()) {
499 QString msg = line.getMessage();
500 int index = msg.indexOf("=");
501 QString key = msg.mid(0, index);
502 QStringList val;
503
504 if (index > 0 && index < msg.length()-1) {
505 QString str = msg.mid(index+1);
506 if (str.startsWith(QLatin1Char('\"')) &&
507 str.endsWith(QLatin1Char('\"'))) {
508 bool ok;
509 str = string_unescape(str, &ok);
510 if (! ok)
511 continue;
512 }
513 val << str;
514 }
515 if (line.hasData())
516 val << line.getData();
517
518 if (infoMap.contains(key)) {
519 QStringList values = infoMap.value(key).toStringList();
520 values << val;
521 infoMap.insert(key, values);
522 } else {
523 infoMap.insert(key, val);
524 }
525 }
526 return infoMap;
527}
528
529/** Sends a GETINFO message to Tor with a single <b>key</b> and returns a
530 * QVariant containing the value returned by Tor. Returns a default
531 * constructed QVariant on failure. */
533TorControl::getInfo(const QString &key, QString *errmsg)
534{
535 QVariantMap map = getInfo(QStringList() << key, errmsg);
536 return map.value(key);
537}
538
539/** Overloaded method to send a GETINFO command for a single info value */
540bool
541TorControl::getInfo(QString key, QString &val, QString *errmsg)
542{
543 QHash<QString,QString> map;
544 map.insert(key, "");
545
546 if (getInfo(map, errmsg)) {
547 val = map.value(key);
548 return true;
549 }
550 return false;
551}
552
553/** Sends a signal to Tor */
554bool
556{
557 ControlCommand cmd("SIGNAL");
559
560 if (sig == TorSignal::Shutdown || sig == TorSignal::Halt) {
561 /* Tor closes the connection before giving us a response to any commands
562 * asking it to stop running, so don't try to get a response. */
563 return _controlConn->send(cmd, errmsg);
564 }
565 return send(cmd, errmsg);
566}
567
568/** Returns an address on which Tor is listening for application
569 * requests. If none are available, a null QHostAddress is returned. */
570QHostAddress
572{
573 QHostAddress socksAddr;
574
575 /* If SocksPort is 0, then Tor is not accepting any application requests. */
576 if (getSocksPort() == 0) {
577 return QHostAddress::Null;
578 }
579
580 /* Get a list of SocksListenAddress lines and return the first valid IP
581 * address parsed from the list. */
582 QStringList addrList = getSocksAddressList(errmsg);
583 foreach (QString addr, addrList) {
584 addr = addr.mid(0, addr.indexOf(":"));
585 if (socksAddr.setAddress(addr)) {
586 return socksAddr;
587 }
588 }
589 /* Otherwise Tor is listening on its default 127.0.0.1 */
590 return QHostAddress::LocalHost;
591}
592
593/** Returns a (possibly empty) list of all currently configured
594 * SocksListenAddress entries. */
595QStringList
597{
598 QStringList addrList;
599 if (getConf("SocksListenAddress", addrList, errmsg)) {
600 return addrList;
601 }
602 return QStringList();
603}
604
605/** Returns a valid SOCKS port for Tor, or 0 if Tor is not accepting
606 * application requests. */
607quint16
609{
610 QList<quint16> portList = getSocksPortList(errmsg);
611 if (portList.size() > 0) {
612 return portList.at(0);
613 }
614 return 0;
615}
616
617/** Returns a list of all currently configured SOCKS ports. If Tor is not
618 * accepting any application connections, an empty list will be returned. */
619QList<quint16>
621{
622 bool valid;
623 quint16 port, socksPort;
624 QString portString;
625 QList<quint16> portList;
626
627 /* Get the value of the SocksPort configuration variable */
628 if (getConf("SocksPort", portString, errmsg)) {
629 socksPort = (quint16)portString.toUInt(&valid);
630 if (valid) {
631 if (socksPort == 0) {
632 /* A SocksPort of 0 means Tor is not accepting any application
633 * connections. */
634 return QList<quint16>();
635 }
636 }
637 }
638 /* Get a list of SOCKS ports from SocksListenAddress entries */
639 QStringList addrList = getSocksAddressList(errmsg);
640 foreach (QString addr, addrList) {
641 if (addr.contains(":")) {
642 portString = addr.mid(addr.indexOf(":")+1);
643 port = (quint16)portString.toUInt(&valid);
644 if (valid) {
645 portList << port;
646 }
647 }
648 }
649 /* If there were no SocksListenAddress entries, or one or more of them did
650 * not specify a port, then add the value of SocksPort, too */
651 if (!portList.size() || (portList.size() != addrList.size())) {
652 portList << socksPort;
653 }
654 return portList;
655}
656
657/** Reeturns Tor's version as a string. */
658QString
660{
661 return _torVersion;
662}
663
664/** Returns Tor's version as a numeric value. Note that this discards any
665 * version status flag, such as "-alpha" or "-rc". */
668{
669 static QString versionString;
670 static quint32 version = 0;
671 quint8 major, minor, micro, patch;
672
673 /* Only recompute the version number if the version string changed */
674 if (versionString == _torVersion)
675 return version;
676 versionString = _torVersion;
677
678 /* Split the version string at either "." or "-" characters */
679 QStringList parts = versionString.split(QRegExp("\\.|-|\\ "));
680 if (parts.size() >= 4) {
681 major = (quint8)parts.at(0).toUInt();
682 minor = (quint8)parts.at(1).toUInt();
683 micro = (quint8)parts.at(2).toUInt();
684 patch = (quint8)parts.at(3).toUInt();
685 version = ((major << 24) | (minor << 16) | (micro << 8) | patch);
686 } else {
687 /* Couldn't parse the version string */
688 version = 0;
689 }
690 return version;
691}
692
693/** Sets an event and its handler. If add is true, then the event is added,
694 * otherwise it is removed. If set is true, then the given event will be
695 * registered with Tor. */
696bool
697TorControl::setEvent(TorEvents::Event e, bool add, bool set, QString *errmsg)
698{
699 _events = (add ? (_events | e) : (_events & ~e));
700 if (set && isConnected())
701 return setEvents(errmsg);
702 return true;
703}
704
705/** Register for the events currently in the event list */
706bool
707TorControl::setEvents(QString *errmsg)
708{
709 ControlCommand cmd("SETEVENTS");
710
712 if (_events & e)
714 e = static_cast<TorEvents::Event>(e << 1);
715 }
716 return send(cmd, errmsg);
717}
718
719/** Sets each configuration key in <b>map</b> to the value associated
720 * with its key. */
721bool
722TorControl::setConf(QHash<QString,QString> map, QString *errmsg)
723{
724 ControlCommand cmd("SETCONF");
725
726 /* Add each keyvalue to the argument list */
727 foreach (QString key, map.uniqueKeys()) {
728 /* If a key has multiple values (e.g., a QMultiHash), they are stored
729 * in order from most recently inserted to least recently inserted.
730 * So, walk the list in reverse so that we append the configuration
731 * values to the SETCONF command in the same order they were inserted
732 * into the QHash. */
733 QList<QString> values = map.values(key);
734 for (int i = values.size()-1; i >= 0; i--) {
735 QString value = values.at(i);
736 if (value.length() > 0)
737 cmd.addArgument(key + "=" + string_escape(value));
738 else
739 cmd.addArgument(key);
740 }
741 }
742 return send(cmd, errmsg);
743}
744
745/** Sets a single configuration key to the given value. */
746bool
747TorControl::setConf(QString key, QString value, QString *errmsg)
748{
749 QHash<QString,QString> map;
750 map.insert(key, value);
751 return setConf(map, errmsg);
752}
753
754/** Sets a single configuration string that is formatted <key=escaped value>.*/
755bool
756TorControl::setConf(QString keyAndValue, QString *errmsg)
757{
758 QHash<QString,QString> map;
759 map.insert(keyAndValue, "");
760 return setConf(map, errmsg);
761}
762
763/** Gets values for a set of configuration keys, each of which has a single
764 * value. */
765bool
766TorControl::getConf(QHash<QString,QString> &map, QString *errmsg)
767{
768 QHash<QString,QStringList> multiMap;
769 foreach (QString key, map.keys()) {
770 multiMap.insert(key, QStringList());
771 }
772 if (getConf(multiMap, errmsg)) {
773 foreach (QString key, multiMap.keys()) {
774 if (map.contains(key)) {
775 map.insert(key, multiMap.value(key).join("\n"));
776 }
777 }
778 }
779 return false;
780}
781
782/** Gets a set of configuration keyvalues and stores them in <b>map</b>. */
783bool
784TorControl::getConf(QHash<QString,QStringList> &map, QString *errmsg)
785{
786 ControlCommand cmd("GETCONF");
787 ControlReply reply;
788 QStringList confValue;
789 QString confKey;
790
791 /* Add the keys as arguments to the GETINFO message */
792 foreach (QString key, map.keys()) {
793 cmd.addArgument(key);
794 }
795
796 /* Ask Tor for the specified info values */
797 if (send(cmd, reply, errmsg)) {
798 /* Parse the response for the returned values */
799 foreach (ReplyLine line, reply.getLines()) {
800 /* Split the "key=val" line and map them */
801 QStringList keyval = line.getMessage().split("=");
802 if (keyval.size() == 2) {
803 confKey = keyval.at(0);
804
805 if (map.contains(confKey)) {
806 /* This configuration key has multiple values, so add this one to
807 * the list. */
808 confValue = map.value(confKey);
809 }
810 confValue << keyval.at(1);
811 map.insert(keyval.at(0), confValue);
812 }
813 }
814 return true;
815 }
816 return false;
817}
818
819/** Gets a single configuration value for <b>key</b>. */
820bool
821TorControl::getConf(QString key, QString &value, QString *errmsg)
822{
823 QStringList confValues;
824 if (getConf(key, confValues, errmsg)) {
825 value = confValues.join("\n");
826 return true;
827 }
828 return false;
829}
830
831/** Gets a list of configuration values for <b>key</b>. */
832bool
833TorControl::getConf(QString key, QStringList &value, QString *errmsg)
834{
835 QHash<QString,QStringList> map;
836 map.insert(key, QStringList());
837
838 if (getConf(map, errmsg)) {
839 value = map.value(key);
840 return true;
841 }
842 return false;
843}
844
845/** Sends a GETICONF message to Tor using the given list of <b>keys</b> and
846 * returns a QVariantMap containing the specified keys and their values as
847 * returned by Tor. Returns a default constructed QVariantMap on failure. */
848QVariantMap
849TorControl::getConf(const QStringList &keys, QString *errmsg)
850{
851 ControlCommand cmd("GETCONF");
852 ControlReply reply;
853 QVariantMap confMap;
854
855 cmd.addArguments(keys);
856 if (!send(cmd, reply, errmsg))
857 return QVariantMap();
858
859 foreach (ReplyLine line, reply.getLines()) {
860 QString msg = line.getMessage();
861 int index = msg.indexOf("=");
862 QString key = msg.mid(0, index);
863 QString val;
864
865 if (index > 0 && index < msg.length()-1)
866 val = msg.mid(index+1);
867 if (val.startsWith(QLatin1Char('\"')) &&
868 val.endsWith(QLatin1Char('\"'))) {
869 bool ok;
870 val = string_unescape(val, &ok);
871 if (! ok)
872 continue;
873 }
874
875 if (confMap.contains(key)) {
876 QStringList values = confMap.value(key).toStringList();
877 values << val;
878 confMap.insert(key, values);
879 } else {
880 confMap.insert(key, val);
881 }
882 }
883 return confMap;
884}
885
886/** Sends a GETCONF message to Tor with a single <b>key</b> and returns a
887 * QVariant containing the value returned by Tor. Returns a default
888 * constructed QVariant on failure. */
890TorControl::getConf(const QString &key, QString *errmsg)
891{
892 QVariantMap map = getConf(QStringList() << key, errmsg);
893 return map.value(key);
894}
895
896/** Sends a GETCONF message to Tor with the single key and returns a QString
897 * containing the value returned by Tor */
898QString
899TorControl::getHiddenServiceConf(const QString &key, QString *errmsg)
900{
901 ControlCommand cmd("GETCONF");
902 ControlReply reply;
903 QVariantMap confMap;
904
905 cmd.addArgument(key);
906 if (!send(cmd, reply, errmsg))
907 return "";
908
909 return reply.toString();
910}
911
912/** Asks Tor to save the current configuration to its torrc. */
913bool
914TorControl::saveConf(QString *errmsg)
915{
916 ControlCommand cmd("SAVECONF");
917 bool ret = send(cmd, errmsg);
918
919 if(!ret) {
920 QString err;
921 setConf("__ReloadTorrcOnSIGHUP", "0", &err);
922 }
923
924 return ret;
925}
926
927/** Tells Tor to reset the given configuration keys back to defaults. */
928bool
929TorControl::resetConf(QStringList keys, QString *errmsg)
930{
931 ControlCommand cmd("RESETCONF");
932
933 /* Add each key to the argument list */
934 foreach (QString key, keys) {
935 cmd.addArgument(key);
936 }
937 return send(cmd, errmsg);
938}
939
940/** Tells Tor to reset a single given configuration key back to its default
941 * value. */
942bool
943TorControl::resetConf(QString key, QString *errmsg)
944{
945 return resetConf(QStringList() << key, errmsg);
946}
947
948/** Returns an unparsed router descriptor for the router whose fingerprint
949 * matches <b>id</b>. The returned text can later be parsed by the
950 * RouterDescriptor class. If <b>id</b> is invalid, then an empty
951 * QStringList is returned. */
952QStringList
953TorControl::getRouterDescriptorText(const QString &id, QString *errmsg)
954{
955 return getInfo("desc/id/" + id, errmsg).toStringList();
956}
957
958/** Returns the descriptor for the router whose fingerprint matches
959 * <b>id</b>. If <b>id</b> is invalid or the router's descriptor cannot
960 * be parsed, then an invalid RouterDescriptor is returned. */
962TorControl::getRouterDescriptor(const QString &id, QString *errmsg)
963{
964 return RouterDescriptor(getRouterDescriptorText(id, errmsg));
965}
966
967/** Returns the status of the router whose fingerprint matches <b>id</b>. If
968 * <b>id</b> is invalid or the router's status cannot be parsed, then an
969 * invalid RouterStatus is returned. */
971TorControl::getRouterStatus(const QString &id, QString *errmsg)
972{
973 QStringList status = getInfo("ns/id/" + id, errmsg).toStringList();
974 return RouterStatus(status);
975}
976
977/** Returns a RouterStatus object for every known router in the network. If
978 * the network status document cannot be parsed, then an empty NetworkStatus
979 * is returned. */
982{
983 QStringList networkStatusLines = getInfo("ns/all", errmsg).toStringList();
984 QList<RouterStatus> networkStatus;
985 int len = networkStatusLines.size();
986 int i = 0;
987
988 while (i < len) {
989 /* Extract the "r", "s", and whatever other status lines */
990 QStringList routerStatusLines;
991 do {
992 routerStatusLines << networkStatusLines.at(i);
993 } while (++i < len && ! networkStatusLines.at(i).startsWith("r "));
994
995 /* Create a new RouterStatus object and add it to the network status, if
996 * it's valid. */
997 RouterStatus routerStatus(routerStatusLines);
998 if (routerStatus.isValid())
999 networkStatus << routerStatus;
1000 }
1001 return networkStatus;
1002}
1003
1004/** Returns the annotations for the router whose fingerprint matches
1005 * <b>id</b>. If <b>id</b> is invalid or the router's annotations cannot be
1006 * parsed, then an empty DescriptorAnnotations is returned and <b>errmsg</b>
1007 * is set if it's not NULL. (Tor >= 0.2.0.13-alpha only) */
1009TorControl::getDescriptorAnnotations(const QString &id, QString *errmsg)
1010{
1011 QStringList lines = getInfo("desc-annotations/id/"+id, errmsg).toStringList();
1012 DescriptorAnnotations annotations;
1013 QString key, value;
1014
1015 foreach (QString line, lines) {
1016 int idx = line.indexOf(" ");
1017
1018 /* Extract the annotation key */
1019 key = line.mid(0, idx);
1020 if (key.startsWith("@"))
1021 key = key.remove(0, 1);
1022
1023 /* Extract the annotation value (if present) */
1024 if (idx > 0 && idx < line.length()-1)
1025 annotations.insert(key, line.mid(idx + 1).trimmed());
1026 else
1027 annotations.insert(key, QString());
1028 }
1029 return annotations;
1030}
1031
1032/** Gets a list of current circuits. */
1033QList<Circuit>
1035{
1036 ControlCommand cmd("GETINFO", "circuit-status");
1037 ControlReply reply;
1038 CircuitList circuits;
1039
1040 if (!send(cmd, reply, errmsg))
1041 return CircuitList();
1042
1043 /* The rest of the circuits just come as data, one per line */
1044 foreach(QString line, reply.getData()) {
1045 Circuit circ(line);
1046 if (circ.isValid())
1047 circuits << circ;
1048 }
1049 return circuits;
1050}
1051
1052/** Closes the circuit specified by <b>circId</b>. If <b>ifUnused</b> is
1053 * true, then the circuit will not be closed unless it is unused. */
1054bool
1055TorControl::closeCircuit(const CircuitId &circId, bool ifUnused, QString *errmsg)
1056{
1057 ControlCommand cmd("CLOSECIRCUIT", circId);
1058 if (ifUnused) {
1059 cmd.addArgument("IfUnused");
1060 }
1061 return send(cmd, errmsg);
1062}
1063
1064/** Gets a list of current streams. */
1065QList<Stream>
1067{
1068 ControlCommand cmd("GETINFO", "stream-status");
1069 ControlReply reply;
1070 QList<Stream> streams;
1071 Stream s;
1072
1073 if (send(cmd, reply, errmsg)) {
1074 /* Sometimes there is a stream on the first message line */
1075 QString msg = reply.getMessage();
1076 s = Stream::fromString(msg.mid(msg.indexOf("=")+1));
1077 if (s.isValid())
1078 streams << s;
1079
1080 /* The rest of the streams just come as data, one per line */
1081 foreach (QString line, reply.getData()) {
1082 s = Stream::fromString(line);
1083 if (s.isValid())
1084 streams << s;
1085 }
1086 }
1087 return streams;
1088}
1089
1090/** Closes the stream specified by <b>streamId</b>. */
1091bool
1092TorControl::closeStream(const StreamId &streamId, QString *errmsg)
1093{
1094 ControlCommand cmd("CLOSESTREAM", streamId);
1095 cmd.addArgument("1"); /* 1 == REASON_MISC (tor-spec.txt) */
1096 return send(cmd, errmsg);
1097}
1098
1099 /** Gets a list of address mappings of the type specified by <b>type</b>
1100 * (defaults to <i>AddressMapAll</i>. */
1103{
1104 AddressMap addressMap;
1105 QStringList entries;
1106
1107 switch (type) {
1109 entries = getInfo("address-mappings/config").toStringList();
1110 break;
1112 entries = getInfo("address-mappings/cache").toStringList();
1113 break;
1115 entries = getInfo("address-mappings/control").toStringList();
1116 break;
1117 default:
1118 entries = getInfo("address-mappings/all").toStringList();
1119 }
1120
1121 foreach (QString entry, entries) {
1122 addressMap.add(entry);
1123 }
1124 return addressMap;
1125}
1126
1127/** Gets the ISO-3166 two-letter country code for <b>ip</b> from Tor.
1128 * Returns a default-constructed QString on failure or if a country code
1129 * is not known for <b>ip</b>. On failure, <b>errmsg</b> will be set if
1130 * it's not NULL. */
1131QString
1132TorControl::ipToCountry(const QHostAddress &ip, QString *errmsg)
1133{
1134 QString request = QString("ip-to-country/%1").arg(ip.toString());
1135 QVariant response = getInfo(request, errmsg);
1136 if (! response.isNull())
1137 return response.toString();
1138 return QString();
1139}
1140
1141/** Takes ownership of the tor process it's communicating to */
1142bool
1144{
1145 ControlCommand cmd("TAKEOWNERSHIP");
1146 return send(cmd, errmsg);
1147}
QList< Circuit > CircuitList
Definition: Circuit.h:81
QString CircuitId
Definition: Circuit.h:24
QList< RouterStatus > NetworkStatus
Definition: RouterStatus.h:97
QString StreamId
Definition: Stream.h:28
#define RELAY_SIGNAL(src, sig)
QHash< QString, QString > DescriptorAnnotations
Definition: TorControl.h:42
stop errmsg connect(const QHostAddress &address, quint16 port)
stop errmsg QVariant
@ AddressMapCache
Definition: AddressMap.h:35
@ AddressMapControl
Definition: AddressMap.h:36
@ AddressMapConfig
Definition: AddressMap.h:34
void add(const QString &from, const QString &to, const QDateTime &expires)
Definition: AddressMap.cpp:29
static Status statusFromString(const QString &tag)
static Recommendation actionFromString(const QString &str)
bool isValid() const
Definition: Circuit.h:48
@ Built
Definition: Circuit.h:36
Status status() const
Definition: Circuit.h:53
void addArgument(const QString &arg)
void addArguments(const QStringList &args)
void connect(const QHostAddress &addr, quint16 port)
bool send(const ControlCommand &cmd, ControlReply &reply, QString *errmsg=0)
QString getMessage() const
QString toString() const
QStringList getData() const
QList< ReplyLine > getLines() const
QString getStatus() const
void setTorVersion(const QString torVersion)
Definition: ProtocolInfo.h:44
void setCookieAuthFile(const QString cookieAuthFile)
Definition: ProtocolInfo.h:38
void setAuthMethods(const QString methods)
QString getMessage() const
Definition: ReplyLine.cpp:64
QString getStatus() const
Definition: ReplyLine.cpp:50
QStringList getData() const
Definition: ReplyLine.cpp:78
bool hasData() const
Definition: ReplyLine.h:44
bool isValid() const
Definition: RouterStatus.h:74
Definition: Stream.h:32
bool isValid() const
Definition: Stream.cpp:146
static Stream fromString(const QString &stream)
Definition: Stream.cpp:63
void dnsUseless()
bool saveConf(QString *errmsg=0)
Definition: TorControl.cpp:914
void externalAddressChanged(const QHostAddress &ip, const QString &hostname)
void onAuthenticated()
Definition: TorControl.cpp:333
void getBootstrapPhase()
Definition: TorControl.cpp:217
BootstrapStatus bootstrapStatus(QString *errmsg=0)
Definition: TorControl.cpp:403
RouterStatus getRouterStatus(const QString &id, QString *errmsg=0)
Definition: TorControl.cpp:971
void circuitEstablished()
bool authenticate(const QByteArray cookie, QString *errmsg=0)
Definition: TorControl.cpp:298
void checkingDirPortReachability(const QHostAddress &ip, quint16 port)
bool isCircuitEstablished()
Definition: TorControl.cpp:424
bool takeOwnership(QString *errmsg)
bool send(ControlCommand cmd, ControlReply &reply, QString *errmsg=0)
Definition: TorControl.cpp:272
QHostAddress getSocksAddress(QString *errmsg=0)
Definition: TorControl.cpp:571
bool setEvents(QString *errmsg=0)
Definition: TorControl.cpp:707
void newDescriptors(const QStringList &ids)
bool signal(TorSignal::Signal sig, QString *errmsg=0)
Definition: TorControl.cpp:555
void stopped()
void connected()
bool isVidaliaRunningTor()
Definition: TorControl.cpp:163
AddressMap getAddressMap(AddressMap::AddressMapType type=AddressMap::AddressMapAll, QString *errmsg=0)
NetworkStatus getNetworkStatus(QString *errmsg=0)
Definition: TorControl.cpp:981
void addressMapped(const QString &from, const QString &to, const QDateTime &expires)
void start(const QString &tor, const QStringList &args)
Definition: TorControl.cpp:110
QStringList getRouterDescriptorText(const QString &id, QString *errmsg=0)
Definition: TorControl.cpp:953
void authenticated()
void connect(const QHostAddress &address, quint16 port)
Definition: TorControl.cpp:195
void dangerousTorVersion(tc::TorVersionStatus reason, const QString &version, const QStringList &recommended)
void connectFailed(QString errmsg)
bool isConnected()
Definition: TorControl.cpp:262
void circuitStatusChanged(const Circuit &circuit)
void disconnect()
Definition: TorControl.cpp:210
TorProcess * _torProcess
Definition: TorControl.h:383
ControlMethod::Method _method
Definition: TorControl.h:389
QString getHiddenServiceConf(const QString &key, QString *errmsg=0)
Definition: TorControl.cpp:899
void startFailed(QString errmsg)
bool closeCircuit(const CircuitId &circId, bool ifUnused=false, QString *errmsg=0)
void socksError(tc::SocksError type, const QString &destination)
bool getInfo(QHash< QString, QString > &map, QString *errmsg=0)
Definition: TorControl.cpp:450
void checkingOrPortReachability(const QHostAddress &ip, quint16 port)
void bandwidthUpdate(quint64 bytesReceived, quint64 bytesSent)
void authenticationFailed(QString errmsg)
TorControl(ControlMethod::Method method=ControlMethod::Port)
Definition: TorControl.cpp:28
QList< quint16 > getSocksPortList(QString *errmsg=0)
Definition: TorControl.cpp:620
void onStopped(int exitCode, QProcess::ExitStatus exitStatus)
Definition: TorControl.cpp:151
DescriptorAnnotations getDescriptorAnnotations(const QString &id, QString *errmsg=0)
void logMessage(tc::Severity level, const QString &msg)
void dangerousPort(quint16 port, bool rejected)
QString _torVersion
Definition: TorControl.h:388
void bootstrapStatusChanged(const BootstrapStatus &status)
void bug(const QString &reason)
void streamStatusChanged(const Stream &stream)
bool closeStream(const StreamId &streamId, QString *errmsg=0)
CircuitList getCircuits(QString *errmsg=0)
bool setEvent(TorEvents::Event e, bool add=true, bool set=true, QString *errmsg=0)
Definition: TorControl.cpp:697
void started()
void serverDescriptorAccepted()
bool resetConf(QStringList keys, QString *errmsg=0)
Definition: TorControl.cpp:929
bool isRunning()
Definition: TorControl.cpp:170
void dnsHijacked()
void disconnected()
bool useFeature(const QString &feature, QString *errmsg=0)
Definition: TorControl.cpp:396
quint16 getSocksPort(QString *errmsg=0)
Definition: TorControl.cpp:608
ControlConnection * _controlConn
Definition: TorControl.h:381
bool setConf(QHash< QString, QString > map, QString *errmsg=0)
Definition: TorControl.cpp:722
quint32 getTorVersion()
Definition: TorControl.cpp:667
bool getConf(QHash< QString, QString > &map, QString *errmsg=0)
Definition: TorControl.cpp:766
void clockSkewed(int skew, const QString &source)
RouterDescriptor getRouterDescriptor(const QString &id, QString *errmsg=0)
Definition: TorControl.cpp:962
void onDisconnected()
Definition: TorControl.cpp:245
void orPortReachabilityFinished(const QHostAddress &ip, quint16 port, bool reachable)
StreamList getStreams(QString *errmsg=0)
void onLogStdout(const QString &severity, const QString &message)
Definition: TorControl.cpp:187
bool stop(QString *errmsg=0)
Definition: TorControl.cpp:131
QString ipToCountry(const QHostAddress &ip, QString *errmsg=0)
TorEvents * _eventHandler
Definition: TorControl.h:385
ProtocolInfo protocolInfo(QString *errmsg=0)
Definition: TorControl.cpp:350
void serverDescriptorRejected(const QHostAddress &ip, quint16 port, const QString &reason)
QString getTorVersionString()
Definition: TorControl.cpp:659
TorEvents::Events _events
Definition: TorControl.h:386
void dirPortReachabilityFinished(const QHostAddress &ip, quint16 port, bool reachable)
QStringList getSocksAddressList(QString *errmsg=0)
Definition: TorControl.cpp:596
void closeTorStdout()
Definition: TorControl.cpp:179
static const Event EVENT_MAX
Definition: TorEvents.h:61
static const Event EVENT_MIN
Definition: TorEvents.h:60
static QString toString(TorEvents::Event e)
Definition: TorEvents.cpp:51
void start(const QString &app, const QStringList &args)
Definition: TorProcess.cpp:56
void openStdout()
Definition: TorProcess.cpp:129
bool stop(QString *errmsg=0)
Definition: TorProcess.cpp:85
void closeStdout()
Definition: TorProcess.cpp:138
static bool isSupported()
Definition: TorService.cpp:48
@ Shutdown
Definition: TorSignal.h:28
static QString toString(Signal signal)
Definition: TorSignal.cpp:21
QString expand_filename(const QString &filename)
Definition: file.cpp:108
QString i(QString str)
Definition: html.cpp:32
TorVersionStatus
Definition: tcglobal.h:86
SocksError
Definition: tcglobal.h:79
Severity severityFromString(const QString &str)
Definition: tcglobal.cpp:82
Severity
Definition: tcglobal.h:69
ConnectionStatusReason connectionStatusReasonFromString(const QString &str)
Definition: tcglobal.cpp:55
QString string_escape(const QString &str)
Definition: stringutil.cpp:131
QString base16_encode(const QByteArray &buf)
Definition: stringutil.cpp:115
QString string_unescape(const QString &str, bool *ok)
Definition: stringutil.cpp:177
bool err(QString *str, const QString &errmsg)
Definition: stringutil.cpp:37
QHash< QString, QString > string_parse_keyvals(const QString &str, bool *ok)
Definition: stringutil.cpp:244