Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

torcontrol: Create also a V3 ed25519-V3 onion address. #19485

Closed
wants to merge 1 commit into from

Conversation

Saibato
Copy link
Contributor

@Saibato Saibato commented Jul 10, 2020

While fiddling around with the path to ADDRv2 and #19031
I noticed that it might be useful if we have already ED25519-V3 onions for the node created in torcontrol.

@fanquake fanquake added the P2P label Jul 10, 2020
@luke-jr
Copy link
Member

luke-jr commented Jul 10, 2020

What's the point if we can't advertise the address?

Also, shouldn't it be possible to have both v2 and v3 addresses?

@Saibato
Copy link
Contributor Author

Saibato commented Jul 10, 2020

What's the point if we can't advertise the address?

Also, shouldn't it be possible to have both v2 and v3 addresses?

If BIP155 get merged... ?
I have a working patch for @vasild Tor v3/ADDRv2 implementation that i will post him now.

Btw. I use for myself a patch to tunnel V3 in V2 ADDR message that works ̶ ̶r̶i̶g̶h̶t̶ ̶n̶o̶w̶ ̶w̶i̶t̶h̶ ̶c̶u̶r̶r̶e̶n̶t̶ ̶m̶a̶s̶t̶e̶r̶.̶ on top of the current p2p ;protocol. The old nodes would barely notice and drop the new address, since they are unrouteable local ipv6. And only the patched nodes have full Tor v3 support.
It uses FC00/7 address that we ignore and resembles on the end to a v3 address to drop in and out from the peers.dat,
That should not even need a BIP since its fully transparent to the actual implementation, although a bit ugly and stealth.

Also, shouldn't it be possible to have both v2 and v3 addresses?

This PR create both V2 and V3 in one sweep.

@luke-jr
Copy link
Member

luke-jr commented Jul 10, 2020

It uses FC00/7 address that we ignore and resembles on the end to a v3 address to drop in and out from the peers.dat,
That should not even need a BIP since its fully transparent to the actual implementation, although a bit ugly and stealth.

I don't know why it wouldn't need a BIP... it's a protocol change at the p2p layer still.

@Saibato
Copy link
Contributor Author

Saibato commented Jul 10, 2020

I don't know why it wouldn't need a BIP... it's a protocol change at the p2p layer ...

So then we propose this ?
I posted this tunnel patch in the comment as diff.

This v3 tunnel protocol is unrelated to this PR , Here we just create the service descriptor and do effectively none with it, but sure you can i.e.
post the new v3 address grabbed from the log to your counterpart node and do a manual addnode on the remote side until BIP155 gets merged.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jul 11, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@Saibato
Copy link
Contributor Author

Saibato commented Jul 11, 2020

To add some fish here this POC tor v3 patch is in line with the current piggy pack of v2 onions in ipv6

Click here, to see the full diff of the POC ADDRv1 compatible tor v3 support

diff --git a/src/addrman.h b/src/addrman.h
index 8e82020df..4a810e53f 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -61,6 +61,7 @@ public:
     SERIALIZE_METHODS(CAddrInfo, obj)
     {
         READWRITEAS(CAddress, obj);
+        READWRITEAS(CNetAddr, obj);
         READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
     }
 
diff --git a/src/net.cpp b/src/net.cpp
index 244b0094d..36af03d33 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -156,6 +156,7 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
         struct in6_addr ip;
         memcpy(&ip, seed_in.addr, sizeof(ip));
         CAddress addr(CService(ip, seed_in.port), GetDesirableServiceFlags(NODE_NONE));
+        LogPrintf("seeds %s\n", CNetAddr(addr).ToString());
         addr.nTime = GetTime() - rng.randrange(nOneWeek) - nOneWeek;
         vSeedsOut.push_back(addr);
     }
@@ -368,6 +369,9 @@ static CAddress GetBindAddress(SOCKET sock)
     return addr_bind;
 }
 
+static CAddress getadrr(std::string name) {
+       return CAddress(CService(name,18444), NODE_NONE);
+}
 CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection, bool block_relay_only)
 {
     if (pszDest == nullptr) {
@@ -384,16 +388,23 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
     }
 
     /// debug print
-    LogPrint(BCLog::NET, "trying connection %s lastseen=%.1fhrs\n",
-        pszDest ? pszDest : addrConnect.ToString(),
+    LogPrint(BCLog::NET, "trying connection %s unresolved address %s lastseen=%.1fhrs\n",
+        pszDest ? pszDest:"", addrConnect.ToString(),
         pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
 
+    std::string strName = std::string( pszDest ? pszDest:"");
     // Resolve
     const int default_port = Params().GetDefaultPort();
     if (pszDest) {
         std::vector<CService> resolved;
         if (Lookup(pszDest, resolved,  default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
+
+       // dont resolv local the onions
+       if (!strName.find(".onion")) {
+
             addrConnect = CAddress(resolved[GetRand(resolved.size())], NODE_NONE);
+
+
             if (!addrConnect.IsValid()) {
                 LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToString(), pszDest);
                 return nullptr;
@@ -410,6 +421,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
                 LogPrintf("Failed to open new connection, already connected\n");
                 return nullptr;
             }
+            }
         }
     }
 
@@ -417,7 +429,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
     bool connected = false;
     SOCKET hSocket = INVALID_SOCKET;
     proxyType proxy;
-    if (addrConnect.IsValid()) {
+    if (addrConnect.IsValid() && addrConnect.IsTor() && !pszDest) {
         bool proxyConnectionFailed = false;
 
         if (GetProxy(addrConnect.GetNetwork(), proxy)) {
@@ -425,14 +437,21 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
             if (hSocket == INVALID_SOCKET) {
                 return nullptr;
             }
-            connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, proxyConnectionFailed);
+
+        if (addrConnect.ToStringIP() != "") {
+                connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, proxyConnectionFailed);
+        } else return nullptr;
+
         } else {
-            // no proxy needed (none set for target network)
+            // no proxy needed (none set for tastrName.find(".onion")rget network)
             hSocket = CreateSocket(addrConnect);
             if (hSocket == INVALID_SOCKET) {
                 return nullptr;
             }
-            connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout, manual_connection);
+
+            if (addrConnect.ToString() != "") {
+                connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout, manual_connection);
+            } else return nullptr;
         }
         if (!proxyConnectionFailed) {
             // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
@@ -444,14 +463,24 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
         if (hSocket == INVALID_SOCKET) {
             return nullptr;
         }
+
         std::string host;
         int port = default_port;
         SplitHostPort(std::string(pszDest), port, host);
         bool proxyConnectionFailed;
-        connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, proxyConnectionFailed);
+        connected = false;
+        //proxyConnectionFailed = true;
+
+
+    if (strlen(pszDest) > 0) //strName.find(".onion"))
+        {
+        LogPrintf("Address to connect over proxz  %s %d\n", host, port);
+            connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, proxyConnectionFailed);
+        } else return nullptr;
+
     }
     if (!connected) {
-        CloseSocket(hSocket);
+        if (hSocket) CloseSocket(hSocket);
         return nullptr;
     }
 
@@ -1705,17 +1734,6 @@ void CConnman::ThreadDNSAddressSeed()
     LogPrintf("%d addresses found from DNS seeds\n", found);
 }
 
-
-
-
-
-
-
-
-
-
-
-
 void CConnman::DumpAddresses()
 {
     int64_t nStart = GetTimeMillis();
@@ -2057,6 +2075,8 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
         }
     } else if (FindNode(std::string(pszDest)))
         return;
+    // will "":port ever work?
+    if(!pszDest && (addrConnect.ToStringIP() == "")) return;
 
     CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, manual_connection, block_relay_only);
 
@@ -2756,6 +2776,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
     // peers (to prevent adversaries from inferring these links from addr
     // traffic).
     m_addr_known{block_relay_only ? nullptr : MakeUnique<CRollingBloomFilter>(5000, 0.001)},
+
     id(idIn),
     nLocalHostNonce(nLocalHostNonceIn),
     nLocalServices(nLocalServicesIn),
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index bfc60b18f..ecd83188e 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2454,14 +2454,47 @@ void ProcessMessage(
         std::vector<CAddress> vAddrOk;
         int64_t nNow = GetAdjustedTime();
         int64_t nSince = nNow - 10 * 60;
+        int i = 0;
+        size_t len = 10;
+        CAddress Tor = CAddress(vAddr[0]);
+        char rawaddr[256] = {};
+
         for (CAddress& addr : vAddr)
         {
             if (interruptMsgProc)
                 return;
 
+        if (addr.IsTorSequence(i)) {
+            if (i == 0 ) {
+                // LogPrintf("Adrress addr V3 raw  rec =");
+                Tor = addr;
+            }
+            //V3sequence())
+            addr.SetSpecial_v3(addr, 256); //fill hostdata from ip;
+            memcpy(&rawaddr[i*10], &addr.fqdn.c_str()[0], 10);
+            i++;
+            if (i != 8) {
+                continue;
+            }
+        } else addr.fqdn = {};
+
+        //LogPrintf("\nAdrress add raw? %s\n",  &rawaddr[0]);
+
+        if (i == 8) {
+            Tor.SetSpecial_v3(addr, 255); // set clasic tor flag
+            Tor.fqdn = rawaddr;
+            if ( i == 8 ) Tor.fqdn = rawaddr;
+            addr = Tor;
+        }
+
+        if (addr.IsTor() && strlen(addr.fqdn.c_str()) < 32) addr.SetSpecial_v3(addr, 255); // v2 stzle
+        LogPrint(BCLog::NET, "Adrress add? %s\n",  addr.ToString());
+
+
             // We only bother storing full nodes, though this may include
             // things which we would not make an outbound connection to, in
             // part because we may make feeler connections to them.
+
             if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices))
                 continue;
 
@@ -3901,12 +3934,25 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
             std::vector<CAddress> vAddr;
             vAddr.reserve(pto->vAddrToSend.size());
             assert(pto->m_addr_known);
+            CAddress addr_add;
             for (const CAddress& addr : pto->vAddrToSend)
             {
                 if (!pto->m_addr_known->contains(addr.GetKey()))
                 {
                     pto->m_addr_known->insert(addr.GetKey());
-                    vAddr.push_back(addr);
+                    if (!addr.IsTor()) vAddr.push_back(addr);
+                    if (addr.IsTor()) LogPrint(BCLog::NET, "Try to send onion address = %s\n", addr.fqdn);
+
+                    if (addr.IsTor() && strlen(addr.fqdn.c_str()) > 32) {
+                        for (int i=0;i<8;i++) {
+                            addr_add = addr;
+                            addr_add.SetSpecial_v3(addr, (i)*10);
+
+                            vAddr.push_back(addr_add);
+
+                        }
+                    } else  vAddr.push_back(addr); //v2 tor
+
                     // receiver rejects addr messages larger than 1000
                     if (vAddr.size() >= 1000)
                     {
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 674439161..8c8bad0f8 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -5,13 +5,17 @@
 
 #include <cstdint>
 #include <netaddress.h>
+#include <netbase.h>
+
 #include <hash.h>
 #include <util/strencodings.h>
 #include <util/asmap.h>
 #include <tinyformat.h>
+#include <util/system.h>
 
 static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
 static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
+static const unsigned char pchOnionSeq[] = {0xFD,'l','o','r','3',0x00};
 
 // 0xFD + sha256("bitcoin")[0:5]
 static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
@@ -47,6 +51,11 @@ void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
     }
 }
 
+void CNetAddr::SetRawByte(char p , int pos)
+{
+    ip[6+pos] = p;
+}
+
 /**
  * Try to make this a dummy address that maps the specified name into IPv6 like
  * so: (0xFD + %sha256("bitcoin")[0:5]) + %sha256(name)[0:10]. Such dummy
@@ -70,6 +79,7 @@ bool CNetAddr::SetInternal(const std::string &name)
     CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash);
     memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
     memcpy(ip + sizeof(g_internal_prefix), hash, sizeof(ip) - sizeof(g_internal_prefix));
+    fqdn = name;
     return true;
 }
 
@@ -83,20 +93,51 @@ bool CNetAddr::SetInternal(const std::string &name)
  *
  * @see CNetAddr::IsTor(), CNetAddr::IsRFC4193()
  */
-bool CNetAddr::SetSpecial(const std::string &strName)
+bool CNetAddr::SetSpecial(const std::string &strName, int flag)
 {
     if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
-        std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
-        if (vchAddr.size() != 16-sizeof(pchOnionCat))
+        std::vector<unsigned char> vchAddr =  DecodeBase32(strName.substr(flag*10, strName.size() - 6).c_str());
+        if (vchAddr.size() != 16-sizeof(pchOnionCat) && vchAddr.size() != 35)
             return false;
         memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
         for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)
             ip[i + sizeof(pchOnionCat)] = vchAddr[i];
+        fqdn = strName;
+        LogPrint(BCLog::NET, "setspecail called with %s %d\n", strName, flag);
         return true;
     }
     return false;
 }
 
+bool CNetAddr::SetSpecial_v3(CNetAddr ref , int flag)
+{
+    //fqdn.resize(256);
+    std::string cp = ref.fqdn;
+    cp.resize(256);
+    if( flag < 254 ) {  memcpy(ip, pchOnionSeq, sizeof(pchOnionSeq));
+        for (unsigned int i=0; i<16-sizeof(pchOnionSeq); i++) {
+            ip[i + sizeof(pchOnionSeq)] = cp.c_str()[flag+i];
+        }
+        fqdn = cp.substr(flag,10);
+    }
+    if (flag == 255) { // backward comp
+        std::string name = EncodeBase32(&ip[6], 10) + ".onion";
+        fqdn = name;
+    }
+    if (flag == 256) {
+        for (unsigned int i=0; i<16-sizeof(pchOnionSeq); i++) {
+            fqdn[i] = char(ip[i + sizeof(pchOnionSeq)]);
+        }
+    }
+    return true;
+}
+
+CNetAddr::CNetAddr(const std::string &strName)
+{
+    SetSpecial(strName);
+    LogPrint(BCLog::NET,  "CNetAddr internal setspecail called from addr by name\n");
+}
+
 CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
 {
     SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);
@@ -224,7 +265,15 @@ bool CNetAddr::IsHeNet() const
  */
 bool CNetAddr::IsTor() const
 {
-    return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
+    return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0) || IsTorSequence(0x0);
+}
+
+/**
+ * @see CNetAddr::SetSpecial(const std::string &)
+ */
+bool CNetAddr::IsTorSequence(char seq) const
+{
+    return  memcmp(ip, pchOnionSeq, sizeof(pchOnionSeq)) == 0;
 }
 
 bool CNetAddr::IsLocal() const
@@ -333,8 +382,9 @@ enum Network CNetAddr::GetNetwork() const
 
 std::string CNetAddr::ToStringIP() const
 {
-    if (IsTor())
-        return EncodeBase32(&ip[6], 10) + ".onion";
+    if (IsTor()) {
+        return fqdn;
+    }
     if (IsInternal())
         return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal";
     CService serv(*this, 0);
@@ -640,6 +690,10 @@ CService::CService(const struct in6_addr& ipv6Addr, uint16_t portIn) : CNetAddr(
 {
 }
 
+CService::CService(const std::string fqdn, uint16_t portIn) : CNetAddr(fqdn), port(portIn)
+{
+}
+
 CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
 {
     assert(addr.sin_family == AF_INET);
diff --git a/src/netaddress.h b/src/netaddress.h
index c20101215..e18cc31a1 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -38,16 +38,18 @@ class CNetAddr
         CNetAddr();
         explicit CNetAddr(const struct in_addr& ipv4Addr);
         void SetIP(const CNetAddr& ip);
+        std::string fqdn = {};
 
         /**
          * Set raw IPv4 or IPv6 address (in network byte order)
-         * @note Only NET_IPV4 and NET_IPV6 are allowed for network.
+         * @note void SetRawBytes(const uint8_t *ip_in);Only NET_IPV4 and NET_IPV6 are allowed for network.
          */
         void SetRaw(Network network, const uint8_t *data);
-
+               void SetRawByte(char b, int pos);
         bool SetInternal(const std::string& name);
 
-        bool SetSpecial(const std::string &strName); // for Tor addresses
+        bool SetSpecial_v3(CNetAddr ref , int flag); // for Tor addresses
+        bool SetSpecial(const std::string &strName, int flag = 0);
         bool IsBindAny() const; // INADDR_ANY equivalent
         bool IsIPv4() const;    // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
         bool IsIPv6() const;    // IPv6 address (not mapped IPv4, not Tor)
@@ -67,6 +69,7 @@ class CNetAddr
         bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) (actually defined in RFC2765)
         bool IsHeNet() const;   // IPv6 Hurricane Electric - https://he.net (2001:0470::/36)
         bool IsTor() const;
+        bool IsTorSequence(char pseq) const;
         bool IsLocal() const;
         bool IsRoutable() const;
         bool IsInternal() const;
@@ -94,13 +97,14 @@ class CNetAddr
         int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
 
         explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
+        CNetAddr(const std::string &strName);
         bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
 
         friend bool operator==(const CNetAddr& a, const CNetAddr& b);
         friend bool operator!=(const CNetAddr& a, const CNetAddr& b) { return !(a == b); }
         friend bool operator<(const CNetAddr& a, const CNetAddr& b);
 
-        SERIALIZE_METHODS(CNetAddr, obj) { READWRITE(obj.ip); }
+        SERIALIZE_METHODS(CNetAddr, obj) { READWRITE(obj.ip, obj.fqdn); }
 
         friend class CSubNet;
 };
@@ -144,7 +148,8 @@ class CService : public CNetAddr
     public:
         CService();
         CService(const CNetAddr& ip, uint16_t port);
-        CService(const struct in_addr& ipv4Addr, uint16_t port);
+        CService(const struct in_addr& ipv4Addr, uint16_t port);;
+        CService(const std::string, uint16_t port);
         explicit CService(const struct sockaddr_in& addr);
         uint16_t GetPort() const;
         bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 3a3b5f3e6..816d66228 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -4,6 +4,7 @@
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <netbase.h>
+#include <net.h>
 
 #include <sync.h>
 #include <tinyformat.h>
@@ -69,17 +70,18 @@ bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, un
         return false;
     }
 
-    {
-        CNetAddr addr;
-        // From our perspective, onion addresses are not hostnames but rather
-        // direct encodings of CNetAddr much like IPv4 dotted-decimal notation
-        // or IPv6 colon-separated hextet notation. Since we can't use
-        // getaddrinfo to decode them and it wouldn't make sense to resolve
-        // them, we return a network address representing it instead. See
-        // CNetAddr::SetSpecial(const std::string&) for more details.
-        if (addr.SetSpecial(name)) {
+    CNetAddr addr;
+    // From our perspective, onion addresses are not hostnames but rather
+    // direct encodings of CNetAddr much like IPv4 dotted-decimal notation
+    // or IPv6 colon-separated hextet notation. Since we can't use
+    // getaddrinfo to decode them and it wouldn't make sense to resolve
+    // them, we return a network address representing it instead. See
+    // CNetAddr::SetSpecial(const std::string&) for more details.
+
+    if (name.find(".onion")) {
+        if (addr.SetSpecial(name,0)) {
             vIP.push_back(addr);
-            return true;
+            return false;
         }
     }
 
@@ -97,12 +99,19 @@ bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, un
     // If we don't allow lookups, then use the AI_NUMERICHOST flag for
     // getaddrinfo to only decode numerical network addresses and suppress
     // hostname lookups.
-    aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
+    aiHint.ai_flags = fAllowLookup && !HaveNameProxy() ? AI_ADDRCONFIG : AI_NUMERICHOST;
     struct addrinfo *aiRes = nullptr;
     int nErr = getaddrinfo(name.c_str(), nullptr, &aiHint, &aiRes);
-    if (nErr)
-        return false;
 
+    LogPrintf("Resolver :%s error = %d  local resolve allowed %s  %s\n", name.c_str() ,nErr,fAllowLookup, nErr?"fail":"local resolved");
+    if (nErr ) {
+        CNetAddr resolved;
+        resolved.SetInternal(name);
+        if (resolved.IsInternal()) {
+            vIP.push_back(resolved);
+        }
+        return false;
+    }
     // Traverse the linked list starting with aiTrav, add all non-internal
     // IPv4,v6 addresses to vIP while respecting nMaxSolutions.
     struct addrinfo *aiTrav = aiRes;
@@ -182,7 +191,7 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup)
     addr = vIP.front();
     return true;
 }
-
+;
 /**
  * Resolve a service string to its corresponding service.
  *
@@ -214,8 +223,17 @@ bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefau
 
     std::vector<CNetAddr> vIP;
     bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup);
-    if (!fRet)
-        return false;
+    if (vIP[0].IsTor()) {
+        vAddr.resize(hostname.size());
+        vAddr[0] = CService(hostname, port);
+        return true;
+    }
+    if (!fRet) // mayby just a name  and only onion we do not resovel so use tor
+    {
+        vAddr.resize(hostname.size());
+        vAddr[0] = CService(hostname, port);
+        return true;
+    }
     vAddr.resize(vIP.size());
     for (unsigned int i = 0; i < vIP.size(); i++)
         vAddr[i] = CService(vIP[i], port);

does the QD job of tunnel v3 onion in ipv6 standard bitcoin ADDR format packets as we do with v2. This is a working Proof Of Concept . And can sure be optimized in many ways, And used on top of this PR to easy test on the fly v3 tor onions.

i.e On a cruft with a running open tor browser you can generate v3 onions on the fly. Use
` bitcoin-qt -proxy=127.0.0.1:9150 -torcontrol=127.0.0.1:9151 -listen -onion=127.0.0.1:9150

Btw the tor browser like Orbot sits at 9150/9151 not 9050/9051
Note, if the bugfix #19358 gets merged bitcoin-qt -proxy=127.0.0.1:9150 -torcontrol=127.0.0.1:9151 -listen
is sufficient and more intuitive. since you want to do a proxy onion outbound and hidden
inbound
edit: with adding -onlynet=onion -dns=0 and -dnsseed=0 your onion v3 test will stay in tor and not touch the tor ipv4 exitnodes to ping hello to the seeders.

@Saibato Saibato changed the title torcontrol: Add V3 ED25519-V3 onions. torcontrol: Create also a V3 ed25519-V3 onion address. Jul 13, 2020
@laanwj
Copy link
Member

laanwj commented Jul 15, 2020

Concept ACK. I thought about advertising both kinds of addresses for a bit and I think it does make sense. Tor that is unable to connect to v3 addresses is sufficiently old that running it is a security risk in itself, so that's not a valid reason to keep suporting v2 addresses, However with regard to advertising on the bitcoin P2P network it makes sense during the transition period to addrv2 , becuase older node versions won't be able to receive (and thus use) the new Tor addresses.

At some point in the future when everyone supports bitcoin addrv2 mesages, we could stop creating and advertising a Tor v2 address.

@jonatack
Copy link
Contributor

Concept ACK. Would you mind adding test coverage (and perhaps clang-format the changes)?

@Saibato
Copy link
Contributor Author

Saibato commented Jul 23, 2020

fixup-update: clang-format source

@Saibato
Copy link
Contributor Author

Saibato commented Jul 28, 2020

fixup:
Add -ephemeraltoronion option,to generate v3 onions that are ADDRv2 prepared.
Now we can generate ephemeral tor v3 onion addresses on node reboot.

edit@saibato
Now a single PR #19635

Copy link
Member

@luke-jr luke-jr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this code hard to follow.

I think you should abstract the hidden service out of TorController, and have one for each of v2/v3.

@Saibato
Copy link
Contributor Author

Saibato commented Jul 30, 2020

@luke-jr yes, quite ugly and just works and in the side show comments a little bit maxwell style ;-).

@Rspigler
Copy link
Contributor

Tor is planning to deprecate v2 onion addresses by September 15th, no longer support by July 15th 2021 (0.4.6), and disable by October 15th 2021.

https://blog.torproject.org/v2-deprecation-timeline

@Saibato
Copy link
Contributor Author

Saibato commented Jul 31, 2020

Tor is planning to deprecate v2 onion addresses by September 15th, no longer support by July

@Rspigler yes we have some work here, the plan was to have from now on v3 and v2 in parallel and by that allow easy testing the transition. And then fade out v2 by change v3 to default. And then way later refactor.

If the Tor version supports this, from now on we
also create also ED25519-V3 in torcontrol.
@Saibato
Copy link
Contributor Author

Saibato commented Aug 15, 2020

rebased cb8f28a

@Saibato
Copy link
Contributor Author

Saibato commented Sep 11, 2020

Concept ACK. Would you mind adding test coverage ...

@jonatack In general i thnk the coder who wrote a feature should not write the test.

There is a. lot of success bias and b. "Most makers are bad breakers", 💇‍♀️

@laanwj
Copy link
Member

laanwj commented Sep 30, 2020

I'm closing this in favor of #19954, which seems to include the same behvavior.

@laanwj laanwj closed this Sep 30, 2020
@Saibato
Copy link
Contributor Author

Saibato commented Oct 1, 2020

I'm closing this in favor of #19954, which seems to include the same behvavior.

It does not, when 19954 get merged as is, some old Tor only nodes will startup if updated without v2 and will not be reachable for some time inbound, before there new v3 is widely known
AFAICS u and @Sjors where in favor of a dual stack i.e. with option to select for some time, but what is partly acked now is a plain v3 and has the potential as i was wary all the time to let old not updated nodes behind and unable to connect to there used known nodes and force thereby a kind of softfork, when we merge this as is and not provide the same functionality as before at least optional for some time.

Btw. At least i know now that mastodon Avatar is not a bot, ;-)

@Sjors
Copy link
Member

Sjors commented Oct 1, 2020

I'm not opposed to dual stack. It might be worth discussing in a separate issue / PR. But it generally takes a while for people to upgrade their Bitcoin node, so I suspect there'll be plenty of v2 nodes left when that's shut down.

@Saibato
Copy link
Contributor Author

Saibato commented Oct 1, 2020

I'm not opposed to dual stack. It might be worth discussing in a separate issue / PR

But, this PR here is a dual stack and provides Tor v2 and v3 in parallel and @vasild what is so complicated to just grab from here and do this from day one?
So that i can close this here.
I could live with this better if u could also add an option -useonlyv3service, that we then deprecate later to default, for those who know the dire implications, if they have a solely v3 node created on startup by the service call now, 🤷‍♀️

@laanwj This whole thing might not be hanging that high, when we would not have the long awaited TAPROOT in the pipeline and then, in my view, we will have a lot of nodes that seek or hope for privacy might want to update fast.

So before -onlynet=onion is also respected outbound and seeders add also there v3 addresses to chainparsms.cpp instead of using outbound there FQDN over Tor exit nodes to bootstrap onion nodes, i will not consent.

I hoped since i addressed that and other Tor related problems now in multiple PR's that one of the core team silent picks this up and does the right thing, but if nothing happens over month that;s also a message.

If u ask users ( and also some core members ) if there onion bootstrap is in Tor, i guess most will say sure because seeding is just over DNS UDP and that is not possible over Tor, so they believe that, but in fact what Bitcoin does is making outbound plain ipv4 calls to the seeders real nodes over the exit nodes to bootstrap pure onion nodes. So a. some doxing here and b. how many honest exit nodes are out there, that give u correct ADDR/ADDVv2 response messages?

Not even talking here about v3 Edwards and what that means for onions created over the service api, AFAICS we have here some profound misconceptions how Tor has changed from v2 to v3 and is about to change. imho.

We have socks5 name services and not socks4 and so one could have had just add .onion or FQDN as long domain names and relay them in simple messages to other nodes they then can or can not over socks5 proxy's call the nodes outbound like any ip.
btw that will be funny with i2p, good luck to create an "outbound" socks5 proxy relay for i2p ( maybe in java?) to even compare i2p with Tor is btw a joke imo.

To use only ip in ADDR messages in the original design, was to make sure there is no DNS like or address translation that can be tampered, since Satoshis probably knew that u can not stop the INTERNET (TCP/IP) but u can hijack DNS,Tor,i2p etc.?

The way the architecture seams to want to progress forward and is now in parts moved from the first design. is to treat other forms of transports also like IP addresses, but that is utterly wrong since those "addresses names" do not even exist without outbound/inbound proxy's or programs and "address name" to IP directory's, they are more like DNS names and can easy be hooked or hijacked and worse the ones that seek privacy might be the ones that easy end up on a premined alternative chain that verify;s "correctly" and reports there hooked balances correct on the screen and RPC but has nothing to do with the original chain.

BTW: In no way, when i do "not" comment on other PR's, that does mean approve or that i even have red a PR. Since i am independent of anyone on this planet,
an ACK is an ACK and if there is no ACK do not assume there is and or that i had interest in silent review bcs an PR tangent my assumed interests and just forgot to ACK or comment. DYOR verify not trust ;-)

@Saibato
Copy link
Contributor Author

Saibato commented Jan 10, 2021

Probably no one ever reads that, but I still can only urge to have a dual stack as long as possible and all issues in Tor V3 are fixed and proven mature stable.
The effect on the consensus is a know issue but who knows what else is there not disclosed yet.
Don't be reckless.
First 2021 full V3 Tor address outage.

https://bitcoinhackers.org/web/statuses/105531638557051583

https://darknetdaily.com/?p=1030

@Rspigler
Copy link
Contributor

I agree that having peers.dat backwards incompatible seems less of a conservative approach than is usually taken. A dual stack (advertising both addresses) seems supported by @laanwj (#19485 (comment)) as well.

@vasild
Copy link
Contributor

vasild commented Jan 11, 2021

With current master, one can have his node behind the old, Tor v2 address by:

  • Configure the onion service in torrc and run bitcoind with -listenonion=0 -bind=127.0.0.1:8334=onion, torrc:
HiddenServiceDir /var/db/tor/bitcoind-torv2/
HiddenServiceVersion 2               
HiddenServicePort 8333 127.0.0.1:8334

or

  • Copy the old (v2) onion_private_key over onion_v3_private_key

@jonatack
Copy link
Contributor

jonatack commented Jan 11, 2021

FWIW, the 0.21 release notes draft is at https://github.com/bitcoin-core/bitcoin-devwiki/wiki/0.21.0-Release-Notes-Draft and currently states:

"The Tor onion service that is automatically created by setting the -listenonion configuration parameter will now be created as a Tor v3 service instead of Tor v2. The private key that was used for Tor v2 (if any) will be left untouched in the onion_private_key file in the data directory (see -datadir) and can be removed if not needed. Bitcoin Core will no longer attempt to read it. The private key for the Tor v3 service will be saved in a file named onion_v3_private_key. To use the deprecated Tor v2 service (not recommended), the onion_private_key can be copied over onion_v3_private_key, e.g. cp -f onion_private_key onion_v3_private_key. (#19954)"

The wiki is publicly editable if anyone feels it could be more clear or complete.

@Saibato
Copy link
Contributor Author

Saibato commented Jan 11, 2021

With current master, one can have his node behind the old, Tor v2 address by:

sure, most experienced user will have Tor anyway defined pure in torrc.and use multiple externalip= and addnode in conf and not expose the Tor service api anyway.

But if the mantra is that average Joe must not get screwed and not run into i..e. eclipse like things, we should keep v2 also in torcontrol as long as possible, 64 bit brute is cheap in reach and v2 address have also other problems but at least they work for ppl / nodes who just need to tunnel easy behind NAT's and serve from there i.e. phones and termuxe's or VM's and do not care much about privacy.
They often use things out of the box with standard settings.

btw for instance in c-LNs Tor implementation we have an option to let at least the user decide what kind of auto onion he wants to have and we can use v3 whiteout clamping the key that generates the address by user defined blobs.or derive them from the node key and also on softreboots we can easy create new addresses while keeping the old ones what is anyway a good idea for v3 until it is mature

@sipa
Copy link
Member

sipa commented Jan 11, 2021

I don't think there is anything to do here. By the time current master is released, TorV2 will be dead and gone.

@Saibato
Copy link
Contributor Author

Saibato commented Jan 12, 2021

I don't think there is anything to do here. By the time current master is released, TorV2 will be dead and gone.

I know they say i am hard to understand and often vage.but let me repharse with no intend of if a than b I don't and will not.

But, if u don;t Ithink there is anything to do here. By the time v0.21.0 is released, TorV3 will be dead and gone.

@sipa
Copy link
Member

sipa commented Jan 12, 2021

Current master will become 22.0. 0.21.0 will be out imminently.

@Saibato
Copy link
Contributor Author

Saibato commented Jan 12, 2021

0.21.0 will be out imminently.

rc6 anyway...?

btw we should skip 22 and 23 to obvious or misleading how about 24,0?

deadalnix pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Feb 9, 2021
Summary:
```
Move the class `HasReason` from `miner_tests.cpp` to
`setup_common.h` so that it can be reused by other tests.
```

Partial backport (2/4) of core [[bitcoin/bitcoin#19485 | PR19485]]:
bitcoin/bitcoin@fe42411

Depends on D9186.

Test Plan:
  ninja check-bitcoin-miner_tests

Reviewers: #bitcoin_abc, majcosta

Reviewed By: #bitcoin_abc, majcosta

Differential Revision: https://reviews.bitcoinabc.org/D9187
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants