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