00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <QHostAddress>
00029 #include <config/torsettings.h>
00030 #include <util/net.h>
00031 #include <util/file.h>
00032 #include "torcontrol.h"
00033
00034
00035
00036 TorControl::TorControl()
00037 {
00038
00039
00040
00041
00042
00043 _torProcess = 0;
00044 _torService = 0;
00045
00046
00047
00048 _controlConn = new ControlConnection(&_torEvents);
00049
00050
00051 QObject::connect(_controlConn, SIGNAL(connected()),
00052 this, SLOT(onConnected()));
00053 QObject::connect(_controlConn, SIGNAL(connectFailed(QString)),
00054 this, SLOT(onConnectFailed(QString)));
00055 QObject::connect(_controlConn, SIGNAL(disconnected()),
00056 this, SLOT(onDisconnected()));
00057 }
00058
00059
00060 TorControl::~TorControl()
00061 {
00062
00063 if (isConnected()) {
00064 disconnect();
00065 }
00066
00067 if (isVidaliaRunningTor()) {
00068 stop();
00069 }
00070 delete _controlConn;
00071 }
00072
00073
00074
00075 void
00076 TorControl::start()
00077 {
00078 if (isRunning()) {
00079 emit started();
00080 } else {
00081 TorSettings settings;
00082
00083
00084
00085 touch_file(settings.getTorrc(), true);
00086
00087 if (TorService::isSupported() && settings.getUseService()) {
00088 _torService = new TorService(settings.getExecutable(),
00089 settings.getTorrc(), this);
00090
00091 QObject::connect(_torService, SIGNAL(started()),
00092 this, SLOT(onStarted()), Qt::QueuedConnection);
00093 QObject::connect(_torService, SIGNAL(finished()),
00094 this, SLOT(onStopped()));
00095 QObject::connect(_torService, SIGNAL(startFailed(QString)),
00096 this, SLOT(onStartFailed(QString)),
00097 Qt::QueuedConnection);
00098
00099 _torService->start();
00100
00101 } else {
00102 _torProcess = new TorProcess;
00103
00104
00105 QObject::connect(_torProcess, SIGNAL(started()),
00106 this, SLOT(onStarted()), Qt::QueuedConnection);
00107 QObject::connect(_torProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
00108 this, SLOT(onStopped(int, QProcess::ExitStatus)));
00109 QObject::connect(_torProcess, SIGNAL(startFailed(QString)),
00110 this, SLOT(onStartFailed(QString)), Qt::QueuedConnection);
00111 QObject::connect(_torProcess, SIGNAL(log(QString, QString)),
00112 this, SLOT(onLogStdout(QString, QString)));
00113
00114
00115 _torProcess->start(settings.getExecutable(),
00116 settings.getArguments());
00117 }
00118 }
00119 }
00120
00121
00122 void
00123 TorControl::onStarted()
00124 {
00125 emit started();
00126 }
00127
00128
00129
00130 void
00131 TorControl::onStartFailed(QString errmsg)
00132 {
00133
00134 closeTorProcess();
00135
00136 emit startFailed(errmsg);
00137 }
00138
00139
00140 bool
00141 TorControl::stop(QString *errmsg)
00142 {
00143
00144 if (!isRunning()) {
00145 return true;
00146 }
00147
00148 if (!_torProcess) {
00149 if (!this->signal(TorSignal::Shutdown)) {
00150 return false;
00151 }
00152 emit stopped(0, QProcess::NormalExit);
00153 return true;
00154 } else {
00155
00156 return _torProcess->stop(errmsg);
00157 }
00158 }
00159
00160
00161 void
00162 TorControl::onStopped(int exitCode, QProcess::ExitStatus exitStatus)
00163 {
00164 closeTorProcess();
00165
00166 if (_controlConn->status() == ControlConnection::Connecting) {
00167 _controlConn->cancelConnect();
00168 } else {
00169 disconnect();
00170 }
00171
00172 emit stopped(exitCode, exitStatus);
00173 }
00174
00175
00176 void
00177 TorControl::closeTorProcess()
00178 {
00179 if (_torProcess) {
00180 QObject::disconnect(_torProcess, 0, 0, 0);
00181 delete _torProcess;
00182 _torProcess = 0;
00183 }
00184 if (_torService) {
00185 QObject::disconnect(_torService, 0, 0, 0);
00186 }
00187 }
00188
00189
00190
00191 bool
00192 TorControl::isVidaliaRunningTor()
00193 {
00194 if (_torProcess) {
00195 return (_torProcess->pid() != 0);
00196 }
00197 return false;
00198 }
00199
00200
00201 bool
00202 TorControl::isRunning()
00203 {
00204 if (_torProcess) {
00205 return (_torProcess->pid() != 0);
00206 }
00207
00208 TorSettings settings;
00209 if (net_test_connect(settings.getControlAddress(),
00210 settings.getControlPort(), 250)) {
00211 return true;
00212 }
00213 return false;
00214 }
00215
00216
00217 void
00218 TorControl::onLogStdout(QString severity, QString message)
00219 {
00220 LogEvent::Severity s = LogEvent::toSeverity(severity);
00221 _torEvents.dispatch(TorEvents::toTorEvent(s), new LogEvent(s, message));
00222 }
00223
00224
00225
00226 void
00227 TorControl::connect()
00228 {
00229 TorSettings settings;
00230 _controlConn->connect(settings.getControlAddress(),
00231 settings.getControlPort());
00232 }
00233
00234
00235
00236 void
00237 TorControl::onConnected()
00238 {
00239 QString errmsg;
00240
00241
00242 if (!authenticate(&errmsg) || !setEvents(&errmsg)) {
00243 emit connectFailed(errmsg);
00244 stop();
00245 return;
00246 }
00247
00248 if (_torProcess) {
00249 _torProcess->closeStdout();
00250 }
00251
00252
00253 getInfo("version", _torVersion);
00254
00255
00256 emit connected();
00257 emit connected(true);
00258 }
00259
00260
00261 void
00262 TorControl::onConnectFailed(QString errmsg)
00263 {
00264 emit connectFailed(errmsg);
00265 }
00266
00267
00268 void
00269 TorControl::disconnect()
00270 {
00271 if (isConnected()) {
00272 _controlConn->disconnect();
00273 }
00274 }
00275
00276
00277 void
00278 TorControl::onDisconnected()
00279 {
00280 if (_torProcess) {
00281
00282
00283
00284 _torProcess->openStdout();
00285 }
00286
00287 _torVersion = QString();
00288
00289
00290 emit disconnected();
00291 emit connected(false);
00292
00293 if (!isVidaliaRunningTor()) {
00294
00295
00296 emit stopped(0, QProcess::NormalExit);
00297 }
00298 }
00299
00300
00301 bool
00302 TorControl::isConnected()
00303 {
00304 return (_controlConn->status() == ControlConnection::Connected);
00305 }
00306
00307
00308
00309
00310
00311 bool
00312 TorControl::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
00313 {
00314 if (_controlConn->send(cmd, reply, errmsg)) {
00315 if (reply.getStatus() == "250") {
00316 return true;
00317 }
00318 if (errmsg) {
00319 *errmsg = reply.getMessage();
00320 }
00321 }
00322 return false;
00323 }
00324
00325
00326 bool
00327 TorControl::send(ControlCommand cmd, QString *errmsg)
00328 {
00329 ControlReply reply;
00330 return send(cmd, reply, errmsg);
00331 }
00332
00333
00334
00335
00336
00337
00338 bool
00339 TorControl::authenticate(QString *errmsg)
00340 {
00341 TorSettings settings;
00342 ControlCommand cmd("AUTHENTICATE", QString(settings.getAuthToken()));
00343 return send(cmd, errmsg);
00344 }
00345
00346
00347
00348
00349
00350
00351 bool
00352 TorControl::getInfo(QHash<QString,QString> &map, QString *errmsg)
00353 {
00354 ControlCommand cmd("GETINFO");
00355 ControlReply reply;
00356
00357
00358 foreach (QString key, map.keys()) {
00359 cmd.addArgument(key);
00360 }
00361
00362
00363 if (send(cmd, reply, errmsg)) {
00364
00365 foreach (ReplyLine line, reply.getLines()) {
00366
00367 QStringList keyval = line.getMessage().split("=");
00368 if (keyval.size() == 2) {
00369 map.insert(keyval.at(0), keyval.at(1));
00370 }
00371 }
00372 return true;
00373 }
00374 return false;
00375 }
00376
00377
00378 bool
00379 TorControl::getInfo(QString key, QString &val, QString *errmsg)
00380 {
00381 QHash<QString,QString> map;
00382 map.insert(key, "");
00383
00384 if (getInfo(map, errmsg)) {
00385 val = map.value(key);
00386 return true;
00387 }
00388 return false;
00389 }
00390
00391
00392 bool
00393 TorControl::signal(TorSignal::Signal sig, QString *errmsg)
00394 {
00395 ControlCommand cmd("SIGNAL");
00396 cmd.addArgument(TorSignal::toString(sig));
00397 if (sig == TorSignal::Shutdown || sig == TorSignal::Halt) {
00398 return _controlConn->send(cmd, errmsg);
00399 }
00400 return send(cmd, errmsg);
00401 }
00402
00403
00404 QString
00405 TorControl::getTorVersionString()
00406 {
00407 return _torVersion;
00408 }
00409
00410
00411
00412 quint32
00413 TorControl::getTorVersion()
00414 {
00415 quint8 major, minor, micro, patch;
00416 quint32 version = 0;
00417
00418 QStringList parts = getTorVersionString().split(".");
00419 if (parts.size() >= 4) {
00420 major = (quint8)parts.at(0).toUInt();
00421 minor = (quint8)parts.at(1).toUInt();
00422 micro = (quint8)parts.at(2).toUInt();
00423 patch = (quint8)parts.at(3).toUInt();
00424 version = ((major << 24) | (minor << 16) | (micro << 8) | patch);
00425 }
00426 return version;
00427 }
00428
00429
00430
00431
00432 bool
00433 TorControl::setEvent(TorEvents::TorEvent e, QObject *obj,
00434 bool add, bool set, QString *errmsg)
00435 {
00436 if (add) {
00437 _torEvents.add(e, obj);
00438 } else {
00439 _torEvents.remove(e, obj);
00440 }
00441 if (set && isConnected()) {
00442 return setEvents(errmsg);
00443 }
00444 return true;
00445 }
00446
00447
00448
00449
00450 bool
00451 TorControl::setLogEvents(uint filter, QObject *obj, QString *errmsg)
00452 {
00453 setEvent(TorEvents::LogError , obj, filter & LogEvent::Error , false);
00454 setEvent(TorEvents::LogWarn , obj, filter & LogEvent::Warn , false);
00455 setEvent(TorEvents::LogNotice, obj, filter & LogEvent::Notice, false);
00456 setEvent(TorEvents::LogInfo , obj, filter & LogEvent::Info , false);
00457 setEvent(TorEvents::LogDebug , obj, filter & LogEvent::Debug , false);
00458 return (isConnected() ? setEvents(errmsg) : true);
00459 }
00460
00461
00462 bool
00463 TorControl::setEvents(QString *errmsg)
00464 {
00465 ControlCommand cmd("SETEVENTS");
00466
00467
00468 foreach (TorEvents::TorEvent e, _torEvents.eventList()) {
00469 cmd.addArgument(TorEvents::toString(e));
00470 }
00471 return send(cmd, errmsg);
00472 }
00473
00474
00475
00476 bool
00477 TorControl::setConf(QHash<QString,QString> map, QString *errmsg)
00478 {
00479 ControlCommand cmd("SETCONF");
00480 QString arg, value;
00481
00482
00483 foreach (QString key, map.keys()) {
00484 arg = key;
00485 value = map.value(key);
00486 if (value.length() > 0) {
00487 arg += "=\"" + value + "\"";
00488 }
00489 cmd.addArgument(arg);
00490 }
00491 return send(cmd, errmsg);
00492 }
00493
00494
00495 bool
00496 TorControl::setConf(QString key, QString value, QString *errmsg)
00497 {
00498 QHash<QString,QString> map;
00499 map.insert(key, value);
00500 return setConf(map, errmsg);
00501 }
00502
00503
00504 bool
00505 TorControl::getConf(QHash<QString,QString> &map, QString *errmsg)
00506 {
00507 ControlCommand cmd("GETCONF");
00508 ControlReply reply;
00509
00510
00511 foreach (QString key, map.keys()) {
00512 cmd.addArgument(key);
00513 }
00514
00515
00516 if (send(cmd, reply, errmsg)) {
00517
00518 foreach (ReplyLine line, reply.getLines()) {
00519
00520 QStringList keyval = line.getMessage().split("=");
00521 if (keyval.size() == 2) {
00522 map.insert(keyval.at(0), keyval.at(1));
00523 }
00524 }
00525 return true;
00526 }
00527 return false;
00528 }
00529
00530
00531 bool
00532 TorControl::getConf(QString key, QString &value, QString *errmsg)
00533 {
00534 QHash<QString,QString> map;
00535 map.insert(key, "");
00536
00537 if (getConf(map, errmsg)) {
00538 value = map.value(key);
00539 return true;
00540 }
00541 return false;
00542 }
00543
00544
00545 bool
00546 TorControl::saveConf(QString *errmsg)
00547 {
00548 ControlCommand cmd("SAVECONF");
00549 return send(cmd, errmsg);
00550 }
00551
00552
00553 bool
00554 TorControl::resetConf(QStringList keys, QString *errmsg)
00555 {
00556 ControlCommand cmd("RESETCONF");
00557
00558
00559 foreach (QString key, keys) {
00560 cmd.addArgument(key);
00561 }
00562 return send(cmd, errmsg);
00563 }
00564
00565
00566
00567 bool
00568 TorControl::resetConf(QString key, QString *errmsg)
00569 {
00570 return resetConf(QStringList() << key, errmsg);
00571 }
00572
00573
00574 RouterDescriptor
00575 TorControl::getDescriptorByName(QString name, QString *errmsg)
00576 {
00577 QList<RouterDescriptor> rdlist;
00578 RouterDescriptor rd;
00579
00580 rdlist = getDescriptorListByName(QStringList() << name, errmsg);
00581 if (!rdlist.isEmpty()) {
00582 rd = (RouterDescriptor)rdlist.takeFirst();
00583 return rd;
00584 }
00585 return RouterDescriptor();
00586 }
00587
00588
00589 RouterDescriptor
00590 TorControl::getDescriptorById(QString id, QString *errmsg)
00591 {
00592 QList<RouterDescriptor> rdlist;
00593 RouterDescriptor rd;
00594
00595 rdlist = getDescriptorListById(QStringList() << id, errmsg);
00596 if (!rdlist.isEmpty()) {
00597 rd = (RouterDescriptor)rdlist.takeFirst();
00598 return rd;
00599 }
00600 return RouterDescriptor();
00601 }
00602
00603
00604 QList<RouterDescriptor>
00605 TorControl::getDescriptorListByName(QStringList nameList, QString *errmsg)
00606 {
00607 ControlCommand cmd("GETINFO");
00608 ControlReply reply;
00609 QList<RouterDescriptor> rdlist;
00610
00611
00612 if (nameList.isEmpty()) {
00613 return QList<RouterDescriptor>();
00614 }
00615
00616
00617 foreach (QString name, nameList) {
00618 cmd.addArgument("desc/name/"+ name);
00619 }
00620
00621
00622 if (send(cmd, reply, errmsg)) {
00623 foreach (ReplyLine line, reply.getLines()) {
00624
00625 if (line.getStatus() == "250" && !line.getData().isEmpty()) {
00626
00627 rdlist << RouterDescriptor(line.getData());
00628 }
00629 }
00630 }
00631 return rdlist;
00632 }
00633
00634
00635 QList<RouterDescriptor>
00636 TorControl::getDescriptorListById(QStringList idlist, QString *errmsg)
00637 {
00638 ControlCommand cmd("GETINFO");
00639 ControlReply reply;
00640 QHash<QString,bool> offline;
00641 QList<RouterDescriptor> rdlist;
00642
00643
00644 if (idlist.isEmpty()) {
00645 return QList<RouterDescriptor>();
00646 }
00647
00648
00649 foreach (QString id, idlist) {
00650 if (id.startsWith("!")) {
00651
00652
00653 id = id.remove("!");
00654 offline.insert(id, true);
00655 }
00656 cmd.addArgument("desc/id/"+ id);
00657 }
00658
00659
00660 if (send(cmd, reply, errmsg)) {
00661 foreach (ReplyLine line, reply.getLines()) {
00662
00663 if (line.getStatus() == "250" && !line.getData().isEmpty()) {
00664
00665 RouterDescriptor rd(line.getData());
00666 rd.setOffline(!offline.isEmpty() && offline.contains(rd.id()));
00667 rdlist << rd;
00668 }
00669 }
00670 }
00671 return rdlist;
00672 }
00673
00674
00675
00676 QList<RouterDescriptor>
00677 TorControl::getRouterList(QString *errmsg)
00678 {
00679
00680 QStringList idList = getRouterIDList(errmsg);
00681
00682 return getDescriptorListById(idList, errmsg);
00683 }
00684
00685
00686 QStringList
00687 TorControl::getRouterIDList(QString *errmsg)
00688 {
00689 ControlCommand cmd("GETINFO", "network-status");
00690 ControlReply reply;
00691 QStringList idList;
00692
00693 if (send(cmd, reply, errmsg)) {
00694 QString routerIDs = reply.getMessage().remove(0,qstrlen("network-status="));
00695
00696
00697 QStringList routers = routerIDs.split(" ");
00698 foreach (QString router, routers) {
00699
00700 QString id = router.mid(router.indexOf("=")+1);
00701 id = id.replace("$", "");
00702
00703 if (router.startsWith("!") && !id.startsWith("!")) {
00704 id.prepend("!");
00705 }
00706
00707 idList << id;
00708 }
00709 }
00710 return idList;
00711 }
00712
00713
00714 QList<Circuit>
00715 TorControl::getCircuits(QString *errmsg)
00716 {
00717 ControlCommand cmd("GETINFO", "circuit-status");
00718 ControlReply reply;
00719 QList<Circuit> circuits;
00720 Circuit c;
00721
00722 if (send(cmd, reply, errmsg)) {
00723
00724 QString msg = reply.getMessage();
00725 c = Circuit::fromString(msg.mid(msg.indexOf("=")+1));
00726 if (!c.isEmpty()) {
00727 circuits << c;
00728 }
00729
00730
00731 foreach(QString line, reply.getData()) {
00732 c = Circuit::fromString(line);
00733 if (!c.isEmpty()) {
00734 circuits << Circuit::fromString(line);
00735 }
00736 }
00737 }
00738 return circuits;
00739 }
00740
00741
00742 QList<Stream>
00743 TorControl::getStreams(QString *errmsg)
00744 {
00745 ControlCommand cmd("GETINFO", "stream-status");
00746 ControlReply reply;
00747 QList<Stream> streams;
00748 Stream s;
00749
00750 if (send(cmd, reply, errmsg)) {
00751
00752 QString msg = reply.getMessage();
00753 s = Stream::fromString(msg.mid(msg.indexOf("=")+1));
00754 if (!s.isEmpty()) {
00755 streams << s;
00756 }
00757
00758
00759 foreach (QString line, reply.getData()) {
00760 s = Stream::fromString(line);
00761 if (!s.isEmpty()) {
00762 streams << s;
00763 }
00764 }
00765 }
00766 return streams;
00767 }
00768