Improve Tor support
authorCryptoManiac <balthazar@yandex.ru>
Sun, 25 Jan 2015 21:08:42 +0000 (00:08 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Sun, 25 Jan 2015 21:08:42 +0000 (00:08 +0300)
* Add list of seed nodes;
* Implement Tor settings in the GUI client;
* Disable DNS and IRC seeding, public IP discovery in -onlynet=tor mode;
* Fix mapMultiArgs issue in SoftSetArg function.

src/init.cpp
src/net.cpp
src/qt/forms/optionsdialog.ui
src/qt/optionsdialog.cpp
src/qt/optionsdialog.h
src/qt/optionsmodel.cpp
src/qt/optionsmodel.h
src/rpcnet.cpp
src/util.cpp

index 34cb698..b934e1c 100644 (file)
@@ -661,12 +661,21 @@ bool AppInit2()
     }
 
     // see Step 2: parameter interactions for more information about these
-    fNoListen = !GetBoolArg("-listen", true);
-    fDiscover = GetBoolArg("-discover", true);
-    fNameLookup = GetBoolArg("-dns", true);
+    if (!IsLimited(NET_IPV4) || !IsLimited(NET_IPV6))
+    {
+        fNoListen = !GetBoolArg("-listen", true);
+        fDiscover = GetBoolArg("-discover", true);
+        fNameLookup = GetBoolArg("-dns", true);
 #ifdef USE_UPNP
-    fUseUPnP = GetBoolArg("-upnp", USE_UPNP);
+        fUseUPnP = GetBoolArg("-upnp", USE_UPNP);
 #endif
+    } else {
+        // Don't listen, discover addresses or search for nodes if IPv4 and IPv6 networking is disabled.
+        fNoListen = true;
+        fDiscover = fNameLookup = fUseUPnP = false;
+        SoftSetBoolArg("-irc", false);
+        SoftSetBoolArg("-dnsseed", false);
+    }
 
     bool fBound = false;
     if (!fNoListen)
index 9e82413..9220122 100644 (file)
@@ -1172,6 +1172,22 @@ uint32_t pnSeed[] =
     0x4d226805,
 };
 
+const char* pchTorSeed[] = 
+{
+    "seedp4knqnoei57u.onion",
+    "seedr3hhlepyi7fd.onion",
+    "seed3uuomkclbiz4.onion",
+    "seedeh7qck3ouff5.onion",
+    "5rg3vq4jagckeckf.onion",
+    "seedt3sraf53ajiy.onion",
+    "seedg4qyccsg42oq.onion",
+    "novaqrtoywpg7jly.onion",
+    "seed3d5wolqbgrcb.onion",
+    "seed24u5dwph3qw4.onion",
+    "mj26ulzbs2oskgym.onion",
+    "eqon4usunavt76m7.onion",
+};
+
 void DumpAddresses()
 {
     int64_t nStart = GetTimeMillis();
@@ -1316,7 +1332,7 @@ void ThreadOpenConnections2(void* parg)
             return;
 
         // Add seed nodes if IRC isn't working
-        if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
+        if (!IsLimited(NET_IPV4) && addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
         {
             std::vector<CAddress> vAdd;
             for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
@@ -1335,6 +1351,20 @@ void ThreadOpenConnections2(void* parg)
             addrman.Add(vAdd, CNetAddr("127.0.0.1"));
         }
 
+        // Add Tor nodes if we have connection with onion router
+        if (mapArgs.count("-tor"))
+        {
+            std::vector<CAddress> vAdd;
+            for (unsigned int i = 0; i < ARRAYLEN(pchTorSeed); i++)
+            {
+                const int64_t nOneWeek = 7*24*60*60;
+                CAddress addr(CService(pchTorSeed[i], GetDefaultPort()));
+                addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
+                vAdd.push_back(addr);
+            }
+            addrman.Add(vAdd, CNetAddr("dummyaddress.onion"));
+        }
+
         //
         // Choose an address to connect to based on most recently seen
         //
@@ -1855,12 +1885,17 @@ void StartNode(void* parg)
             printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
 
     // Map ports with UPnP
-    if (fUseUPnP)
+    if (!fUseUPnP)
+        printf("UPNP port mapping is disabled\n");
+    else
         MapPort();
 
     // Get addresses from IRC and advertise ours
-    if (!NewThread(ThreadIRCSeed, NULL))
-        printf("Error: NewThread(ThreadIRCSeed) failed\n");
+    if (!GetBoolArg("-irc", true))
+        printf("IRC seeding disabled\n");
+    else
+        if (!NewThread(ThreadIRCSeed, NULL))
+            printf("Error: NewThread(ThreadIRCSeed) failed\n");
 
     // Send and receive from sockets, accept connections
     if (!NewThread(ThreadSocketHandler, NULL))
index 73e4801..d5da8e3 100644 (file)
@@ -23,7 +23,7 @@
       <enum>QTabWidget::North</enum>
      </property>
      <property name="currentIndex">
-      <number>0</number>
+      <number>1</number>
      </property>
      <widget class="QWidget" name="tabMain">
       <attribute name="title">
         </layout>
        </item>
        <item>
+        <widget class="QCheckBox" name="connectTor">
+         <property name="text">
+          <string>Connect through &amp;Tor:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_Tor">
+         <item>
+          <widget class="QLabel" name="torIpLabel">
+           <property name="minimumSize">
+            <size>
+             <width>60</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Tor IP:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QValidatedLineEdit" name="torIp">
+           <property name="maximumSize">
+            <size>
+             <width>130</width>
+             <height>16777215</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLabel" name="torPortLabel">
+           <property name="text">
+            <string>Port:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="torPort">
+           <property name="maximumSize">
+            <size>
+             <width>55</width>
+             <height>16777215</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="TorOnly">
+           <property name="text">
+            <string>Use Tor only</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+       <item>
         <spacer name="verticalSpacer_Network">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
index c69ad82..671b18c 100644 (file)
@@ -20,9 +20,11 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
     model(0),
     mapper(0),
     fRestartWarningDisplayed_Proxy(false),
+    fRestartWarningDisplayed_Tor(false),
     fRestartWarningDisplayed_Lang(false),
     fRestartWarningDisplayed_URL(false),
-    fProxyIpValid(true)
+    fProxyIpValid(true),
+    fTorIpValid(true)
 {
     ui->setupUi(this);
 
@@ -35,6 +37,11 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
     ui->proxyPort->setEnabled(false);
     ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
 
+    ui->torIp->setEnabled(false);
+    ui->torPort->setEnabled(false);
+    ui->torPort->setValidator(new QIntValidator(1, 65535, this));
+    ui->TorOnly->setEnabled(false);
+
     ui->socksVersion->setEnabled(false);
     ui->socksVersion->addItem("5", 5);
     ui->socksVersion->addItem("4", 4);
@@ -45,7 +52,14 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
     connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));
     connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy()));
 
+    connect(ui->connectTor, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Tor()));
+    connect(ui->connectTor, SIGNAL(toggled(bool)), ui->torIp, SLOT(setEnabled(bool)));
+    connect(ui->connectTor, SIGNAL(toggled(bool)), ui->torPort, SLOT(setEnabled(bool)));
+    connect(ui->connectTor, SIGNAL(toggled(bool)), ui->TorOnly, SLOT(setEnabled(bool)));
+    connect(ui->TorOnly, SIGNAL(toggled(bool)), ui->connectSocks, SLOT(setDisabled(bool)));
+
     ui->proxyIp->installEventFilter(this);
+    ui->torIp->installEventFilter(this);
 
     /* Window elements init */
 #ifdef Q_OS_MAC
@@ -100,6 +114,8 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
     connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApplyButton()));
     /* setup/change UI elements when proxy IP is invalid/valid */
     connect(this, SIGNAL(proxyIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleProxyIpValid(QValidatedLineEdit *, bool)));
+    /* setup/change UI elements when Tor IP is invalid/valid */
+    connect(this, SIGNAL(torIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleTorIpValid(QValidatedLineEdit *, bool)));
 }
 
 OptionsDialog::~OptionsDialog()
@@ -146,6 +162,11 @@ void OptionsDialog::setMapper()
     mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
     mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);
 
+    mapper->addMapping(ui->connectTor, OptionsModel::TorUse);
+    mapper->addMapping(ui->torIp, OptionsModel::TorIP);
+    mapper->addMapping(ui->torPort, OptionsModel::TorPort);
+    mapper->addMapping(ui->TorOnly, OptionsModel::TorOnly);
+
     /* Window */
 #ifndef Q_OS_MAC
     mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
@@ -173,7 +194,7 @@ void OptionsDialog::disableApplyButton()
 void OptionsDialog::enableSaveButtons()
 {
     /* prevent enabling of the save buttons when data modified, if there is an invalid proxy address present */
-    if(fProxyIpValid)
+    if(fProxyIpValid && fTorIpValid)
         setSaveButtonState(true);
 }
 
@@ -214,6 +235,15 @@ void OptionsDialog::showRestartWarning_Proxy()
     }
 }
 
+void OptionsDialog::showRestartWarning_Tor()
+{
+    if(!fRestartWarningDisplayed_Proxy)
+    {
+        QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting NovaCoin."), QMessageBox::Ok);
+        fRestartWarningDisplayed_Tor = true;
+    }
+}
+
 void OptionsDialog::showRestartWarning_Lang()
 {
     if(!fRestartWarningDisplayed_Lang)
@@ -261,6 +291,25 @@ void OptionsDialog::handleProxyIpValid(QValidatedLineEdit *object, bool fState)
     }
 }
 
+void OptionsDialog::handleTorIpValid(QValidatedLineEdit *object, bool fState)
+{
+    // this is used in a check before re-enabling the save buttons
+    fTorIpValid = fState;
+
+    if(fTorIpValid)
+    {
+        enableSaveButtons();
+        ui->statusLabel->clear();
+    }
+    else
+    {
+        disableSaveButtons();
+        object->setValid(fTorIpValid);
+        ui->statusLabel->setStyleSheet("QLabel { color: red; }");
+        ui->statusLabel->setText(tr("The supplied tor address is invalid."));
+    }
+}
+
 bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
 {
     if(event->type() == QEvent::FocusOut)
@@ -271,6 +320,13 @@ bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
             /* Check proxyIp for a valid IPv4/IPv6 address and emit the proxyIpValid signal */
             emit proxyIpValid(ui->proxyIp, LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr));
         }
+
+        if(object == ui->torIp)
+        {
+            CService addr;
+            /* Check proxyIp for a valid IPv4/IPv6 address and emit the torIpValid signal */
+            emit torIpValid(ui->torIp, LookupNumeric(ui->torIp->text().toStdString().c_str(), addr));
+        }
     }
     return QDialog::eventFilter(object, event);
 }
index 5d75e06..c2a11df 100644 (file)
@@ -41,22 +41,27 @@ private slots:
     void on_applyButton_clicked();
 
     void showRestartWarning_Proxy();
+    void showRestartWarning_Tor();
     void showRestartWarning_Lang();
     void showRestartWarning_URL();
     void updateDisplayUnit();
     void handleProxyIpValid(QValidatedLineEdit *object, bool fState);
+    void handleTorIpValid(QValidatedLineEdit *object, bool fState);
 
 signals:
     void proxyIpValid(QValidatedLineEdit *object, bool fValid);
+    void torIpValid(QValidatedLineEdit *object, bool fValid);
 
 private:
     Ui::OptionsDialog *ui;
     OptionsModel *model;
     MonitoredDataMapper *mapper;
     bool fRestartWarningDisplayed_Proxy;
+    bool fRestartWarningDisplayed_Tor;
     bool fRestartWarningDisplayed_Lang;
     bool fRestartWarningDisplayed_URL;
     bool fProxyIpValid;
+    bool fTorIpValid;
 };
 
 #endif // OPTIONSDIALOG_H
index d946352..07a2072 100644 (file)
@@ -24,6 +24,7 @@ bool static ApplyProxySettings()
     }
     if (nSocksVersion && !addrProxy.IsValid())
         return false;
+
     if (!IsLimited(NET_IPV4))
         SetProxy(NET_IPV4, addrProxy, nSocksVersion);
     if (nSocksVersion > 4) {
@@ -31,8 +32,27 @@ bool static ApplyProxySettings()
         if (!IsLimited(NET_IPV6))
             SetProxy(NET_IPV6, addrProxy, nSocksVersion);
 #endif
-        SetNameProxy(addrProxy, nSocksVersion);
     }
+
+    SetNameProxy(addrProxy, nSocksVersion);
+
+    return true;
+}
+
+bool static ApplyTorSettings()
+{
+    QSettings settings;
+    CService addrTor(settings.value("addrTor", "127.0.0.1:9050").toString().toStdString());
+    if (!settings.value("fUseTor", false).toBool()) {
+        addrTor = CService();
+        return false;
+    }
+    if (!addrTor.IsValid())
+        return false;
+
+    SetProxy(NET_TOR, addrTor, 5);
+    SetReachable(NET_TOR);
+
     return true;
 }
 
@@ -60,10 +80,19 @@ void OptionsModel::Init()
     // command-line options to override the GUI settings:
     if (settings.contains("fUseUPnP"))
         SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool());
-    if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool())
-        SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
-    if (settings.contains("nSocksVersion") && settings.value("fUseProxy").toBool())
-        SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString());
+    if ( !(settings.value("fTorOnly").toBool() && settings.contains("addrTor")) ) {
+        if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool())
+            SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
+        if (settings.contains("nSocksVersion") && settings.value("fUseProxy").toBool())
+            SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString());
+    }
+
+    if (settings.contains("addrTor") && settings.value("fUseTor").toBool()) {
+        SoftSetArg("-tor", settings.value("addrTor").toString().toStdString());
+        if (settings.value("fTorOnly").toBool())
+            SoftSetArg("-onlynet", "tor");
+    }
+
     if (settings.contains("detachDB"))
         SoftSetBoolArg("-detachdb", settings.value("detachDB").toBool());
     if (!language.isEmpty())
@@ -94,7 +123,7 @@ bool OptionsModel::Upgrade()
         }
     }
     QList<QString> boolOptions;
-    boolOptions << "bDisplayAddresses" << "fMinimizeToTray" << "fMinimizeOnClose" << "fUseProxy" << "fUseUPnP";
+    boolOptions << "bDisplayAddresses" << "fMinimizeToTray" << "fMinimizeOnClose" << "fUseProxy" << "fUseTor" << "fTorOnly" << "fUseUPnP";
     foreach(QString key, boolOptions)
     {
         bool value = false;
@@ -106,24 +135,38 @@ bool OptionsModel::Upgrade()
     }
     try
     {
-        CAddress addrProxyAddress;
+        CAddress addrProxyAddress, addrTorAddress;
         if (walletdb.ReadSetting("addrProxy", addrProxyAddress))
         {
             settings.setValue("addrProxy", addrProxyAddress.ToStringIPPort().c_str());
             walletdb.EraseSetting("addrProxy");
         }
+
+        if (walletdb.ReadSetting("addrTor", addrTorAddress))
+        {
+            settings.setValue("addrTor", addrTorAddress.ToStringIPPort().c_str());
+            walletdb.EraseSetting("addrTor");
+        }
     }
     catch (std::ios_base::failure &e)
     {
         // 0.6.0rc1 saved this as a CService, which causes failure when parsing as a CAddress
-        CService addrProxy;
+        CService addrProxy, addrTor;
         if (walletdb.ReadSetting("addrProxy", addrProxy))
         {
             settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
             walletdb.EraseSetting("addrProxy");
         }
+
+        if (walletdb.ReadSetting("addrTor", addrTor))
+        {
+            settings.setValue("addrTor", addrTor.ToStringIPPort().c_str());
+            walletdb.EraseSetting("addrTor");
+        }
     }
+
     ApplyProxySettings();
+    ApplyTorSettings();
     Init();
 
     return true;
@@ -168,6 +211,24 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
         }
         case ProxySocksVersion:
             return settings.value("nSocksVersion", 5);
+        case TorUse:
+            return settings.value("fUseTor", false);
+        case TorIP: {
+            proxyType proxy;
+            if (GetProxy(NET_TOR, proxy))
+                return QVariant(QString::fromStdString(proxy.first.ToStringIP()));
+            else
+                return QVariant(QString::fromStdString("127.0.0.1"));
+        }
+        case TorPort: {
+            proxyType proxy;
+            if (GetProxy(NET_TOR, proxy))
+                return QVariant(proxy.first.GetPort());
+            else
+                return QVariant(9050);
+        }
+        case TorOnly:
+            return settings.value("fTorOnly", false);
         case Fee:
             return QVariant(static_cast<qlonglong>(nTransactionFee));
         case DisplayUnit:
@@ -248,6 +309,37 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
             successful = ApplyProxySettings();
         }
         break;
+        case TorUse: {
+            settings.setValue("fUseTor", value.toBool());
+            ApplyTorSettings();
+        }
+        break;
+        case TorIP: {
+            proxyType proxy;
+            proxy.first = CService("127.0.0.1", 9050);
+            GetProxy(NET_IPV4, proxy);
+
+            CNetAddr addr(value.toString().toStdString());
+            proxy.first.SetIP(addr);
+            settings.setValue("addrTor", proxy.first.ToStringIPPort().c_str());
+            successful = ApplyTorSettings();
+        }
+        break;
+        case TorPort: {
+            proxyType proxy;
+            proxy.first = CService("127.0.0.1", 9050);
+            GetProxy(NET_IPV4, proxy);
+
+            proxy.first.SetPort(value.toInt());
+            settings.setValue("addrTor", proxy.first.ToStringIPPort().c_str());
+            successful = ApplyTorSettings();
+        }
+        break;
+        case TorOnly: {
+            settings.setValue("fTorOnly", value.toBool());
+            ApplyTorSettings();
+        }
+        break;
         case Fee:
             nTransactionFee = value.toLongLong();
             settings.setValue("nTransactionFee", static_cast<qlonglong>(nTransactionFee));
index e3f73b2..09197f7 100644 (file)
@@ -25,6 +25,10 @@ public:
         ProxyIP,           // QString
         ProxyPort,         // int
         ProxySocksVersion, // int
+        TorUse,            // bool
+        TorIP,             // QString
+        TorPort,           // int
+        TorOnly,           // bool
         Fee,               // qint64
         DisplayUnit,       // BitcoinUnits::Unit
         DisplayAddresses,  // bool
index 1ce14cd..4b4448a 100644 (file)
@@ -56,7 +56,7 @@ Value getaddrmaninfo(const Array& params, bool fHelp)
     // Sort by the GetChance result backwardly
     sort(vAddr.begin(), vAddr.end(), addrManItemSort());
 
-    string strFilterNetType = "ipv4";
+    string strFilterNetType = "";
     if (params.size() == 1)
         strFilterNetType = params[0].get_str();
 
@@ -71,9 +71,9 @@ Value getaddrmaninfo(const Array& params, bool fHelp)
         string strNetType;
         switch(addr.GetNetwork())
         {
-//            case NET_TOR:
-//                strNetType = "tor";
-//            break;
+            case NET_TOR:
+                strNetType = "tor";
+            break;
 //            case NET_I2P:
 //                strNetType = "i2p";
 //            break;
@@ -86,7 +86,7 @@ Value getaddrmaninfo(const Array& params, bool fHelp)
 
         }
 
-        if (strNetType != strFilterNetType)
+        if (strFilterNetType.size() != 0 && strNetType != strFilterNetType)
             continue;
 
         addrManItem.push_back(Pair("chance", addr.GetChance(GetTime())));
index be1339f..197e562 100644 (file)
@@ -600,9 +600,11 @@ bool GetBoolArg(const std::string& strArg, bool fDefault)
 
 bool SoftSetArg(const std::string& strArg, const std::string& strValue)
 {
-    if (mapArgs.count(strArg))
+    if (mapArgs.count(strArg) || mapMultiArgs.count(strArg))
         return false;
     mapArgs[strArg] = strValue;
+    mapMultiArgs[strArg].push_back(strValue);
+
     return true;
 }