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);
79  RELAY_SIGNAL(_torProcess, SIGNAL(started()));
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>. */
109 void
110 TorControl::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. */
130 bool
131 TorControl::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 {
140  if (_controlConn->isConnected())
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 */
150 void
151 TorControl::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. */
162 bool
164 {
165  return (_torProcess->state() != QProcess::NotRunning);
166 }
167 
168 /** Detect if the Tor process is running. */
169 bool
171 {
172  return (_torProcess->state() != QProcess::NotRunning
173  || _controlConn->isConnected());
174 }
175 
176 /** Stops reading log messages from the Tor process's stdout. This has no
177  * effect if isVidaliaRunningTor() is false. */
178 void
180 {
181  if (_torProcess)
183 }
184 
185 /** Called when Tor has printed a log message to stdout. */
186 void
187 TorControl::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. */
194 void
195 TorControl::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. */
202 void
203 TorControl::connect(const QString &path)
204 {
205  _controlConn->connect(path);
206 }
207 
208 /** Disconnect from Tor's control port */
209 void
211 {
212  if (isConnected())
214 }
215 
216 void
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 */
244 void
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 */
261 bool
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. */
271 bool
272 TorControl::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. */
286 bool
287 TorControl::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  */
297 bool
298 TorControl::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  }
308  onAuthenticated();
309  return true;
310 }
311 
312 /** Sends an authentication password to Tor. The syntax is:
313  *
314  * "AUTHENTICATE" SP QuotedString CRLF
315  */
316 bool
317 TorControl::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  }
327  onAuthenticated();
328  return true;
329 }
330 
331 /** Called when the controller has successfully authenticated to Tor. */
332 void
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. */
350 TorControl::protocolInfo(QString *errmsg)
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. */
395 bool
396 TorControl::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. */
423 bool
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  */
449 bool
450 TorControl::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. */
487 QVariantMap
488 TorControl::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. */
532 QVariant
533 TorControl::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 */
540 bool
541 TorControl::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 */
554 bool
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. */
570 QHostAddress
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. */
595 QStringList
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. */
607 quint16
608 TorControl::getSocksPort(QString *errmsg)
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. */
619 QList<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. */
658 QString
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". */
666 quint32
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. */
696 bool
697 TorControl::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 */
706 bool
707 TorControl::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. */
721 bool
722 TorControl::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. */
746 bool
747 TorControl::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>.*/
755 bool
756 TorControl::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. */
765 bool
766 TorControl::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>. */
783 bool
784 TorControl::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>. */
820 bool
821 TorControl::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>. */
832 bool
833 TorControl::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. */
848 QVariantMap
849 TorControl::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. */
889 QVariant
890 TorControl::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 */
898 QString
899 TorControl::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. */
913 bool
914 TorControl::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. */
928 bool
929 TorControl::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. */
942 bool
943 TorControl::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. */
952 QStringList
953 TorControl::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. */
962 TorControl::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. */
971 TorControl::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) */
1009 TorControl::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. */
1033 QList<Circuit>
1034 TorControl::getCircuits(QString *errmsg)
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. */
1054 bool
1055 TorControl::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. */
1065 QList<Stream>
1066 TorControl::getStreams(QString *errmsg)
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>. */
1091 bool
1092 TorControl::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>. */
1101 AddressMap
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. */
1131 QString
1132 TorControl::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 */
1142 bool
1144 {
1145  ControlCommand cmd("TAKEOWNERSHIP");
1146  return send(cmd, errmsg);
1147 }