From 23aa78c405f82257e8578afb3d5d244aa27dcd74 Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Sat, 31 Mar 2012 17:58:25 +0200
Subject: IPv6 node support

This will make bitcoin relay valid routable IPv6 addresses, and when
USE_IPV6 is enabled, listen on IPv6 interfaces and attempt connections
to IPv6 addresses.
---
 src/main.cpp             |  3 ---
 src/makefile.linux-mingw |  2 +-
 src/makefile.mingw       |  2 +-
 src/makefile.osx         |  2 +-
 src/makefile.unix        |  2 +-
 src/net.cpp              | 56 ++++++++++++++++++++++++++++++++----------------
 src/netbase.cpp          | 54 ++++++++++++++++++++++++++++++++++++----------
 src/netbase.h            |  1 +
 8 files changed, 85 insertions(+), 37 deletions(-)

(limited to 'src')

diff --git a/src/main.cpp b/src/main.cpp
index b0ed28aa14..f9691a5d52 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2424,9 +2424,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         {
             if (fShutdown)
                 return true;
-            // ignore IPv6 for now, since it isn't implemented anyway
-            if (!addr.IsIPv4())
-                continue;
             if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
                 addr.nTime = nNow - 5 * 24 * 60 * 60;
             pfrom->AddAddressKnown(addr);
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 645f0a16e4..373b49ab0a 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -27,7 +27,7 @@ LIBS= \
  -l ssl \
  -l crypto
 
-DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB
+DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DUSE_IPV6
 DEBUGFLAGS=-g
 CFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
 
diff --git a/src/makefile.mingw b/src/makefile.mingw
index bb6466954f..156eb17cc1 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -23,7 +23,7 @@ LIBS= \
  -l ssl \
  -l crypto
 
-DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB
+DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DUSE_IPV6
 DEBUGFLAGS=-g
 CFLAGS=-mthreads -O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
 
diff --git a/src/makefile.osx b/src/makefile.osx
index eb9ae4ba7f..9c05d500ae 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -53,7 +53,7 @@ LIBS += \
 TESTDEFS += -DBOOST_TEST_DYN_LINK
 endif
 
-DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0
+DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DUSE_IPV6
 
 ifdef RELEASE
 # Compile for maximum compatibility and smallest size.
diff --git a/src/makefile.unix b/src/makefile.unix
index 53fb1f0b8d..ce8b55cdf6 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -4,7 +4,7 @@
 
 USE_UPNP:=0
 
-DEFS=
+DEFS=-DUSE_IPV6
 
 DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
 LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
diff --git a/src/net.cpp b/src/net.cpp
index 8603514f91..75c8bbabaf 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -733,7 +733,11 @@ void ThreadSocketHandler2(void* parg)
         //
         if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
         {
+#ifdef USE_IPV6
+            struct sockaddr_in6 sockaddr;
+#else
             struct sockaddr_in sockaddr;
+#endif
             socklen_t len = sizeof(sockaddr);
             SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
             CAddress addr;
@@ -1390,7 +1394,7 @@ void ThreadOpenConnections2(void* parg)
             CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
 
             // if we selected an invalid address, restart
-            if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
+            if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
                 break;
 
             nTries++;
@@ -1620,6 +1624,7 @@ void ThreadMessageHandler2(void* parg)
 
 bool BindListenPort(string& strError)
 {
+    unsigned short nPort = GetListenPort();
     strError = "";
     int nOne = 1;
 
@@ -1636,7 +1641,12 @@ bool BindListenPort(string& strError)
 #endif
 
     // Create socket for listening for incoming connections
-    hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+#ifdef USE_IPV6
+    int nFamily = AF_INET6;
+#else
+    int nFamily = AF_INET;
+#endif
+    hListenSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
     if (hListenSocket == INVALID_SOCKET)
     {
         strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
@@ -1669,22 +1679,36 @@ bool BindListenPort(string& strError)
 
     // The sockaddr_in structure specifies the address family,
     // IP address, and port for the socket that is being bound
-    struct sockaddr_in sockaddr;
+#ifdef USE_IPV6
+    struct sockaddr_in6 sockaddr = sockaddr_in6();
+    memset(&sockaddr, 0, sizeof(sockaddr));
+    sockaddr.sin6_family = AF_INET6;
+    sockaddr.sin6_addr = in6addr_any;   // bind to all IPs on this computer
+    sockaddr.sin6_port = htons(nPort);
+#  ifdef WIN32
+    int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
+    int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
+    // this call is allowed to fail
+    setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
+#  endif
+#else
+    struct sockaddr_in sockaddr = sockaddr_in();
     memset(&sockaddr, 0, sizeof(sockaddr));
     sockaddr.sin_family = AF_INET;
     sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
-    sockaddr.sin_port = htons(GetListenPort());
+    sockaddr.sin_port = htons(nPort);
+#endif
     if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
     {
         int nErr = WSAGetLastError();
         if (nErr == WSAEADDRINUSE)
-            strError = strprintf(_("Unable to bind to port %d on this computer.  Bitcoin is probably already running."), ntohs(sockaddr.sin_port));
+            strError = strprintf(_("Unable to bind to port %d on this computer.  Bitcoin is probably already running."), nPort);
         else
-            strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
+            strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d, %s)", nPort, nErr, strerror(nErr));
         printf("%s\n", strError.c_str());
         return false;
     }
-    printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
+    printf("Bound to port %d\n", (int)nPort);
 
     // Listen for incoming connections
     if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
@@ -1727,28 +1751,22 @@ void static Discover()
             if ((ifa->ifa_flags & IFF_UP) == 0) continue;
             if (strcmp(ifa->ifa_name, "lo") == 0) continue;
             if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
-            char pszIP[100];
             if (ifa->ifa_addr->sa_family == AF_INET)
             {
                 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
-                if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
-                    printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
-
-                // Take the first IP that isn't loopback 127.x.x.x
                 CNetAddr addr(s4->sin_addr);
-                AddLocal(addr, LOCAL_IF);
+                if (AddLocal(addr, LOCAL_IF))
+                    printf("ipv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
             }
+#ifdef USE_IPV6
             else if (ifa->ifa_addr->sa_family == AF_INET6)
             {
                 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
-                if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
-                    printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
-
-#ifdef USE_IPV6
                 CNetAddr addr(s6->sin6_addr);
-                AddLocal(addr, LOCAL_IF);
-#endif
+                if (AddLocal(addr, LOCAL_IF))
+                    printf("ipv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
             }
+#endif
         }
         freeifaddrs(myaddrs);
     }
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 48709dc5c6..a22d42a967 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -305,7 +305,37 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
 {
     hSocketRet = INVALID_SOCKET;
 
-    SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    struct sockaddr_storage sockaddr;
+    int nFamily = 0;
+    size_t nSockAddrLen = 0;
+
+    if (addrConnect.IsIPv4())
+    {
+        // Use IPv4 stack to connect to IPv4 addresses
+        struct sockaddr_in sockaddr4;
+        if (!addrConnect.GetSockAddr(&sockaddr4))
+            return false;
+        memcpy(&sockaddr, &sockaddr4, sizeof(sockaddr4));
+        nSockAddrLen = sizeof(sockaddr4);
+        nFamily = AF_INET;
+    }
+#ifdef USE_IPV6
+    else if (addrConnect.IsIPv6())
+    {
+        struct sockaddr_in6 sockaddr6;
+        if (!addrConnect.GetSockAddr6(&sockaddr6))
+            return false;
+        memcpy(&sockaddr, &sockaddr6, sizeof(sockaddr6));
+        nSockAddrLen = sizeof(sockaddr6);
+        nFamily = AF_INET6;
+    }
+#endif
+    else {
+        printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str());
+        return false;
+    }
+
+    SOCKET hSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
     if (hSocket == INVALID_SOCKET)
         return false;
 #ifdef SO_NOSIGPIPE
@@ -313,13 +343,6 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
     setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
 #endif
 
-    struct sockaddr_in sockaddr;
-    if (!addrConnect.GetSockAddr(&sockaddr))
-    {
-        closesocket(hSocket);
-        return false;
-    }
-
 #ifdef WIN32
     u_long fNonblock = 1;
     if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
@@ -332,7 +355,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
         return false;
     }
 
-    if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
+    if (connect(hSocket, (struct sockaddr*)&sockaddr, nSockAddrLen) == SOCKET_ERROR)
     {
         // WSAEINVAL is here because some legacy version of winsock uses it
         if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
@@ -531,6 +554,11 @@ bool CNetAddr::IsIPv4() const
     return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
 }
 
+bool CNetAddr::IsIPv6() const
+{
+    return (!IsIPv4());
+}
+
 bool CNetAddr::IsRFC1918() const
 {
     return IsIPv4() && (
@@ -919,12 +947,16 @@ std::vector<unsigned char> CService::GetKey() const
 
 std::string CService::ToStringPort() const
 {
-    return strprintf(":%i", port);
+    return strprintf("%i", port);
 }
 
 std::string CService::ToStringIPPort() const
 {
-    return ToStringIP() + ToStringPort();
+    if (IsIPv4()) {
+        return ToStringIP() + ":" + ToStringPort();
+    } else {
+        return "[" + ToStringIP() + "]:" + ToStringPort();
+    }
 }
 
 std::string CService::ToString() const
diff --git a/src/netbase.h b/src/netbase.h
index e5c466e4f0..acbcc36d18 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -31,6 +31,7 @@ class CNetAddr
         void Init();
         void SetIP(const CNetAddr& ip);
         bool IsIPv4() const;    // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
+        bool IsIPv6() const;    // IPv6 address (not IPv4)
         bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
         bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
         bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
-- 
cgit v1.2.3


From d32148567f5866a7cd2a77a2f44f846134011c9c Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Mon, 2 Apr 2012 17:06:11 +0200
Subject: Preliminary support for Tor/I2P hidden services

There are plans to let Bitcoin function as Tor/I2P hidden service.
To do so, we could use the established encoding provided by OnionCat
and GarliCat (without actually using those tools) to embed Tor/I2P
addresses in IPv6.

This patch makes these addresses considered routable, so they can
travel over the Bitcoin network in 'addr' messages. This will hopefully
make it easier to deploy real hidden service support later.
---
 src/netbase.cpp | 14 +++++++++++++-
 src/netbase.h   |  2 ++
 2 files changed, 15 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/netbase.cpp b/src/netbase.cpp
index a22d42a967..37e6120e7f 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -615,6 +615,18 @@ bool CNetAddr::IsRFC4843() const
     return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
 }
 
+bool CNetAddr::IsOnionCat() const
+{
+    static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
+    return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
+}
+
+bool CNetAddr::IsGarliCat() const
+{
+    static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};
+    return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0);
+}
+
 bool CNetAddr::IsLocal() const
 {
     // IPv4 loopback
@@ -673,7 +685,7 @@ bool CNetAddr::IsValid() const
 
 bool CNetAddr::IsRoutable() const
 {
-    return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || IsRFC4193() || IsRFC4843() || IsLocal());
+    return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsOnionCat() && !IsGarliCat()) || IsRFC4843() || IsLocal());
 }
 
 std::string CNetAddr::ToStringIP() const
diff --git a/src/netbase.h b/src/netbase.h
index acbcc36d18..1b6d8d59bb 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -42,6 +42,8 @@ class CNetAddr
         bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
         bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
         bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
+        bool IsOnionCat() const;
+        bool IsGarliCat() const;
         bool IsLocal() const;
         bool IsRoutable() const;
         bool IsValid() const;
-- 
cgit v1.2.3


From 090e5b40f1b3ac9ac6209f8996da4d686686a2ac Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Tue, 10 Apr 2012 20:22:04 +0200
Subject: Limited relaying/storing of foreign addresses

Introduce a boolean variable for each "network" (ipv4, ipv6, tor, i2p),
and track whether we are likely to able to connect to it. Addresses in
"addr" messages outside of our network get limited relaying and are not
stored in addrman.
---
 src/main.cpp    |  9 +++++++--
 src/net.cpp     | 14 ++++++++++++--
 src/net.h       |  2 ++
 src/netbase.cpp | 25 +++++++++++++++++++++++++
 src/netbase.h   | 14 ++++++++++++++
 5 files changed, 60 insertions(+), 4 deletions(-)

(limited to 'src')

diff --git a/src/main.cpp b/src/main.cpp
index f9691a5d52..5f16378b41 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2418,6 +2418,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         }
 
         // Store the new addresses
+        vector<CAddress> vAddrOk;
         int64 nNow = GetAdjustedTime();
         int64 nSince = nNow - 10 * 60;
         BOOST_FOREACH(CAddress& addr, vAddr)
@@ -2427,6 +2428,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
                 addr.nTime = nNow - 5 * 24 * 60 * 60;
             pfrom->AddAddressKnown(addr);
+            bool fReachable = IsReachable(addr);
             if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
             {
                 // Relay to a limited number of other nodes
@@ -2451,13 +2453,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
                         hashKey = Hash(BEGIN(hashKey), END(hashKey));
                         mapMix.insert(make_pair(hashKey, pnode));
                     }
-                    int nRelayNodes = 2;
+                    int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
                     for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
                         ((*mi).second)->PushAddress(addr);
                 }
             }
+            // Do not store addresses outside our network
+            if (fReachable)
+                vAddrOk.push_back(addr);
         }
-        addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60);
+        addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
         if (vAddr.size() < 1000)
             pfrom->fGetAddr = false;
         if (pfrom->fOneShot)
diff --git a/src/net.cpp b/src/net.cpp
index 75c8bbabaf..d407e66420 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -45,8 +45,9 @@ bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest = NU
 bool fClient = false;
 static bool fUseUPnP = false;
 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
-CCriticalSection cs_mapLocalHost;
-map<CNetAddr, int> mapLocalHost;
+static CCriticalSection cs_mapLocalHost;
+static map<CNetAddr, int> mapLocalHost;
+static bool vfReachable[NET_MAX] = {};
 static CNode* pnodeLocalHost = NULL;
 uint64 nLocalHostNonce = 0;
 array<int, THREAD_MAX> vnThreadsRunning;
@@ -214,6 +215,9 @@ bool AddLocal(const CNetAddr& addr, int nScore)
     {
         LOCK(cs_mapLocalHost);
         mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0);
+        enum Network net = addr.GetNetwork();
+        vfReachable[net] = true;
+        if (net == NET_IPV6) vfReachable[NET_IPV4] = true;
     }
 
     AdvertizeLocal();
@@ -243,6 +247,12 @@ bool IsLocal(const CNetAddr& addr)
     return mapLocalHost.count(addr) > 0;
 }
 
+// check whether a given address is in a network we can probably connect to
+bool IsReachable(const CNetAddr& addr)
+{
+    LOCK(cs_mapLocalHost);
+    return vfReachable[addr.GetNetwork()];
+}
 
 bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
 {
diff --git a/src/net.h b/src/net.h
index a00dd1b8cc..63f8712040 100644
--- a/src/net.h
+++ b/src/net.h
@@ -58,8 +58,10 @@ bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
 bool SeenLocal(const CNetAddr& addr);
 bool IsLocal(const CNetAddr& addr);
 bool GetLocal(CNetAddr &addr, const CNetAddr *paddrPeer = NULL);
+bool IsReachable(const CNetAddr &addr);
 CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
 
+
 enum
 {
     MSG_TX = 1,
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 37e6120e7f..4c852f5eee 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -25,6 +25,14 @@ int nConnectTimeout = 5000;
 
 static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
 
+enum Network ParseNetwork(std::string net) {
+    if (net == "ipv4") return NET_IPV4;
+    if (net == "ipv6") return NET_IPV6;
+    if (net == "tor")  return NET_TOR;
+    if (net == "i2p")  return NET_I2P;
+    return NET_UNROUTABLE;
+}
+
 bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
 {
     vIP.clear();
@@ -688,6 +696,23 @@ bool CNetAddr::IsRoutable() const
     return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsOnionCat() && !IsGarliCat()) || IsRFC4843() || IsLocal());
 }
 
+enum Network CNetAddr::GetNetwork() const
+{
+    if (!IsRoutable())
+        return NET_UNROUTABLE;
+
+    if (IsIPv4())
+        return NET_IPV4;
+
+    if (IsOnionCat())
+        return NET_TOR;
+
+    if (IsGarliCat())
+        return NET_I2P;
+
+    return NET_IPV6;
+}
+
 std::string CNetAddr::ToStringIP() const
 {
     if (IsIPv4())
diff --git a/src/netbase.h b/src/netbase.h
index 1b6d8d59bb..998f8eaf14 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -17,6 +17,19 @@ extern int nConnectTimeout;
 #undef SetPort
 #endif
 
+enum Network
+{
+    NET_UNROUTABLE,
+    NET_IPV4,
+    NET_IPV6,
+    NET_TOR,
+    NET_I2P,
+
+    NET_MAX
+};
+
+enum Network ParseNetwork(std::string net);
+
 /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
 class CNetAddr
 {
@@ -48,6 +61,7 @@ class CNetAddr
         bool IsRoutable() const;
         bool IsValid() const;
         bool IsMulticast() const;
+        enum Network GetNetwork() const;
         std::string ToString() const;
         std::string ToStringIP() const;
         int GetByte(int n) const;
-- 
cgit v1.2.3


From 623b987813acfc985ecca591e96ac0b84f5333e3 Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Fri, 4 May 2012 16:55:19 +0200
Subject: Add -noproxy to circumvent proxy for some network

---
 src/init.cpp    | 13 +++++++++++++
 src/netbase.cpp |  8 +++++++-
 src/netbase.h   |  1 +
 3 files changed, 21 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/init.cpp b/src/init.cpp
index 60927f20b3..03b47b3efa 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -180,6 +180,7 @@ bool AppInit2(int argc, char* argv[])
             "  -timeout=<n>     \t  "   + _("Specify connection timeout (in milliseconds)") + "\n" +
             "  -proxy=<ip:port> \t  "   + _("Connect through socks proxy") + "\n" +
             "  -socks=<n>       \t  "   + _("Select the version of socks proxy to use (4 or 5, 5 is default)") + "\n" +
+            "  -noproxy=<net>   \t  "   + _("Do not use proxy for connections to network net (ipv4 or ipv6)") + "\n" +
             "  -dns             \t  "   + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" +
             "  -proxydns        \t  "   + _("Pass DNS requests to (SOCKS5) proxy") + "\n" +
             "  -port=<port>     \t\t  " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" +
@@ -532,6 +533,18 @@ bool AppInit2(int argc, char* argv[])
         }
     }
 
+    if (mapArgs.count("-noproxy"))
+    {
+        BOOST_FOREACH(std::string snet, mapMultiArgs["-noproxy"]) {
+            enum Network net = ParseNetwork(snet);
+            if (net == NET_UNROUTABLE) {
+                ThreadSafeMessageBox(_("Unknown network specified in -noproxy"), _("Bitcoin"), wxOK | wxMODAL);
+                return false;
+            }
+            SetNoProxy(net);
+        }
+    }
+
     if (mapArgs.count("-connect"))
         SoftSetBoolArg("-dnsseed", false);
  
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 4c852f5eee..2c821c7acd 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -21,6 +21,7 @@ bool fProxyNameLookup = false;
 bool fNameLookup = false;
 CService addrProxy("127.0.0.1",9050);
 int nConnectTimeout = 5000;
+static bool vfNoProxy[NET_MAX] = {};
 
 
 static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
@@ -33,6 +34,11 @@ enum Network ParseNetwork(std::string net) {
     return NET_UNROUTABLE;
 }
 
+void SetNoProxy(enum Network net, bool fNoProxy) {
+    assert(net >= 0 && net < NET_MAX);
+    vfNoProxy[net] = fNoProxy;
+}
+
 bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
 {
     vIP.clear();
@@ -440,7 +446,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
 bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
 {
     SOCKET hSocket = INVALID_SOCKET;
-    bool fProxy = (fUseProxy && addrDest.IsRoutable());
+    bool fProxy = (fUseProxy && addrDest.IsRoutable() && !vfNoProxy[addrDest.GetNetwork()]);
 
     if (!ConnectSocketDirectly(fProxy ? addrProxy : addrDest, hSocket, nTimeout))
         return false;
diff --git a/src/netbase.h b/src/netbase.h
index 998f8eaf14..bd62c42e32 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -29,6 +29,7 @@ enum Network
 };
 
 enum Network ParseNetwork(std::string net);
+void SetNoProxy(enum Network net, bool fNoProxy = true);
 
 /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
 class CNetAddr
-- 
cgit v1.2.3


From c5b3ffd8d5d61b0adb69882efd72f2d4e89f62d6 Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Sun, 29 Apr 2012 02:19:23 +0200
Subject: Use NET_ identifiers in CNetAddr::GetGroup()

---
 src/netbase.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'src')

diff --git a/src/netbase.cpp b/src/netbase.cpp
index 2c821c7acd..7e9620d9ff 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -772,40 +772,40 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
 std::vector<unsigned char> CNetAddr::GetGroup() const
 {
     std::vector<unsigned char> vchRet;
-    int nClass = 0; // 0=IPv6, 1=IPv4, 254=local, 255=unroutable
+    int nClass = NET_IPV6;
     int nStartByte = 0;
     int nBits = 16;
 
     // all local addresses belong to the same group
     if (IsLocal())
     {
-        nClass = 254;
+        nClass = 255;
         nBits = 0;
     }
 
     // all unroutable addresses belong to the same group
     if (!IsRoutable())
     {
-        nClass = 255;
+        nClass = NET_UNROUTABLE;
         nBits = 0;
     }
     // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
     // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
     else if (IsIPv4() || IsRFC6145() || IsRFC6052())
     {
-        nClass = 1;
+        nClass = NET_IPV4;
         nStartByte = 12;
     }
     // for 6to4 tunneled addresses, use the encapsulated IPv4 address
     else if (IsRFC3964())
     {
-        nClass = 1;
+        nClass = NET_IPV4;
         nStartByte = 2;
     }
     // for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address
     else if (IsRFC4380())
     {
-        vchRet.push_back(1);
+        vchRet.push_back(NET_IPV4);
         vchRet.push_back(GetByte(3) ^ 0xFF);
         vchRet.push_back(GetByte(2) ^ 0xFF);
         return vchRet;
-- 
cgit v1.2.3


From 457754d2c24f7e53c55f4b68155a5fa702552327 Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Fri, 4 May 2012 16:46:22 +0200
Subject: Add -blocknet to prevent connections to a given network

---
 src/init.cpp | 12 ++++++++++++
 src/net.cpp  | 26 ++++++++++++++++++++++----
 src/net.h    |  2 ++
 3 files changed, 36 insertions(+), 4 deletions(-)

(limited to 'src')

diff --git a/src/init.cpp b/src/init.cpp
index 03b47b3efa..202d513677 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -189,6 +189,7 @@ bool AppInit2(int argc, char* argv[])
             "  -connect=<ip>    \t\t  " + _("Connect only to the specified node") + "\n" +
             "  -seednode=<ip>   \t\t  " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" +
             "  -externalip=<ip> \t  "   + _("Specify your own public address") + "\n" +
+            "  -blocknet=<net>  \t  "   + _("Do not connect to addresses in network net (ipv4, ipv6)") + "\n" +
             "  -discover        \t  "   + _("Try to discover public IP address (default: 1)") + "\n" +
             "  -irc             \t  "   + _("Find peers using internet relay chat (default: 0)") + "\n" +
             "  -listen          \t  "   + _("Accept connections from outside (default: 1)") + "\n" +
@@ -560,6 +561,17 @@ bool AppInit2(int argc, char* argv[])
         SoftSetBoolArg("-discover", false);
     }
 
+    if (mapArgs.count("-blocknet")) {
+        BOOST_FOREACH(std::string snet, mapMultiArgs["-blocknet"]) {
+            enum Network net = ParseNetwork(snet);
+            if (net == NET_UNROUTABLE) {
+                ThreadSafeMessageBox(_("Unknown network specified in -blocknet"), _("Bitcoin"), wxOK | wxMODAL);
+                return false;
+            }
+            SetLimited(net);
+        }
+    }
+
     fNameLookup = GetBoolArg("-dns");
     fProxyNameLookup = GetBoolArg("-proxydns");
     if (fProxyNameLookup)
diff --git a/src/net.cpp b/src/net.cpp
index d407e66420..79d0a8ddbc 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -48,6 +48,7 @@ uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
 static CCriticalSection cs_mapLocalHost;
 static map<CNetAddr, int> mapLocalHost;
 static bool vfReachable[NET_MAX] = {};
+static bool vfLimited[NET_MAX] = {};
 static CNode* pnodeLocalHost = NULL;
 uint64 nLocalHostNonce = 0;
 array<int, THREAD_MAX> vnThreadsRunning;
@@ -225,7 +226,20 @@ bool AddLocal(const CNetAddr& addr, int nScore)
     return true;
 }
 
-// vote for a local address
+/** Make a particular network entirely off-limits (no automatic connects to it) */
+void SetLimited(enum Network net, bool fLimited)
+{
+    LOCK(cs_mapLocalHost);
+    vfLimited[net] = fLimited;
+}
+
+bool IsLimited(const CNetAddr& addr)
+{
+    LOCK(cs_mapLocalHost);
+    return vfLimited[addr.GetNetwork()];
+}
+
+/** vote for a local address */
 bool SeenLocal(const CNetAddr& addr)
 {
     {
@@ -240,18 +254,19 @@ bool SeenLocal(const CNetAddr& addr)
     return true;
 }
 
-// check whether a given address is potentially local
+/** check whether a given address is potentially local */
 bool IsLocal(const CNetAddr& addr)
 {
     LOCK(cs_mapLocalHost);
     return mapLocalHost.count(addr) > 0;
 }
 
-// check whether a given address is in a network we can probably connect to
+/** check whether a given address is in a network we can probably connect to */
 bool IsReachable(const CNetAddr& addr)
 {
     LOCK(cs_mapLocalHost);
-    return vfReachable[addr.GetNetwork()];
+    enum Network net = addr.GetNetwork();
+    return vfReachable[net] && !vfLimited[net];
 }
 
 bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
@@ -1409,6 +1424,9 @@ void ThreadOpenConnections2(void* parg)
 
             nTries++;
 
+            if (IsLimited(addr))
+                continue;
+
             // only consider very recently tried nodes after 30 failed attempts
             if (nANow - addr.nLastTry < 600 && nTries < 30)
                 continue;
diff --git a/src/net.h b/src/net.h
index 63f8712040..be167b001f 100644
--- a/src/net.h
+++ b/src/net.h
@@ -54,6 +54,8 @@ enum
     LOCAL_MAX
 };
 
+void SetLimited(enum Network net, bool fLimited = true);
+bool IsLimited(const CNetAddr& addr);
 bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
 bool SeenLocal(const CNetAddr& addr);
 bool IsLocal(const CNetAddr& addr);
-- 
cgit v1.2.3


From 7fa4443f77a659031e277337770b506fcf954d69 Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Thu, 10 May 2012 20:35:13 +0200
Subject: Keep port information for local addresses

---
 src/irc.cpp |  2 +-
 src/net.cpp | 26 ++++++++++++++++----------
 src/net.h   | 23 ++++++++++++-----------
 3 files changed, 29 insertions(+), 22 deletions(-)

(limited to 'src')

diff --git a/src/irc.cpp b/src/irc.cpp
index f20152495e..525bd7a8da 100644
--- a/src/irc.cpp
+++ b/src/irc.cpp
@@ -246,7 +246,7 @@ void ThreadIRCSeed2(void* parg)
                 return;
         }
 
-        CNetAddr addrLocal;
+        CService addrLocal;
         string strMyName;
         if (GetLocal(addrLocal, &addrConnect))
             strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
diff --git a/src/net.cpp b/src/net.cpp
index 79d0a8ddbc..a43b76d79c 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -46,7 +46,7 @@ bool fClient = false;
 static bool fUseUPnP = false;
 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
 static CCriticalSection cs_mapLocalHost;
-static map<CNetAddr, int> mapLocalHost;
+static map<CService, int> mapLocalHost;
 static bool vfReachable[NET_MAX] = {};
 static bool vfLimited[NET_MAX] = {};
 static CNode* pnodeLocalHost = NULL;
@@ -96,7 +96,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
 }
 
 // find 'best' local address for a particular peer
-bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
+bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
 {
     if (fUseProxy || mapArgs.count("-connect") || fNoListen)
         return false;
@@ -105,7 +105,7 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
     int nBestReachability = -1;
     {
         LOCK(cs_mapLocalHost);
-        for (map<CNetAddr, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
+        for (map<CService, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
         {
             int nCount = (*it).second;
             int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
@@ -124,11 +124,10 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
 CAddress GetLocalAddress(const CNetAddr *paddrPeer)
 {
     CAddress ret(CService("0.0.0.0",0),0);
-    CNetAddr addr;
+    CService addr;
     if (GetLocal(addr, paddrPeer))
     {
-        ret.SetIP(addr);
-        ret.SetPort(GetListenPort());
+        ret = CAddress(addr);
         ret.nServices = nLocalServices;
         ret.nTime = GetAdjustedTime();
     }
@@ -196,7 +195,7 @@ void static AdvertizeLocal()
         if (pnode->fSuccessfullyConnected)
         {
             CAddress addrLocal = GetLocalAddress(&pnode->addr);
-            if (addrLocal.IsRoutable() && (CNetAddr)addrLocal != (CNetAddr)pnode->addrLocal)
+            if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal)
             {
                 pnode->PushAddress(addrLocal);
                 pnode->addrLocal = addrLocal;
@@ -206,7 +205,7 @@ void static AdvertizeLocal()
 }
 
 // learn a new local address
-bool AddLocal(const CNetAddr& addr, int nScore)
+bool AddLocal(const CService& addr, int nScore)
 {
     if (!addr.IsRoutable())
         return false;
@@ -226,6 +225,13 @@ bool AddLocal(const CNetAddr& addr, int nScore)
     return true;
 }
 
+bool AddLocal(const CNetAddr& addr, int nScore, int port)
+{
+    if (port == -1)
+        port = GetListenPort();
+    return AddLocal(CService(addr, port), nScore);
+}
+
 /** Make a particular network entirely off-limits (no automatic connects to it) */
 void SetLimited(enum Network net, bool fLimited)
 {
@@ -240,7 +246,7 @@ bool IsLimited(const CNetAddr& addr)
 }
 
 /** vote for a local address */
-bool SeenLocal(const CNetAddr& addr)
+bool SeenLocal(const CService& addr)
 {
     {
         LOCK(cs_mapLocalHost);
@@ -255,7 +261,7 @@ bool SeenLocal(const CNetAddr& addr)
 }
 
 /** check whether a given address is potentially local */
-bool IsLocal(const CNetAddr& addr)
+bool IsLocal(const CService& addr)
 {
     LOCK(cs_mapLocalHost);
     return mapLocalHost.count(addr) > 0;
diff --git a/src/net.h b/src/net.h
index be167b001f..398b89dcfc 100644
--- a/src/net.h
+++ b/src/net.h
@@ -44,22 +44,23 @@ bool StopNode();
 
 enum
 {
-    LOCAL_NONE,
-    LOCAL_IF,
-    LOCAL_UPNP,
-    LOCAL_IRC,
-    LOCAL_HTTP,
-    LOCAL_MANUAL,
+    LOCAL_NONE,   // unknown
+    LOCAL_IF,     // address a local interface listens on
+    LOCAL_UPNP,   // address reported by UPnP
+    LOCAL_IRC,    // address reported by IRC (deprecated)
+    LOCAL_HTTP,   // address reported by whatismyip.com and similars
+    LOCAL_MANUAL, // address explicitly specified (-externalip=)
 
     LOCAL_MAX
 };
 
 void SetLimited(enum Network net, bool fLimited = true);
 bool IsLimited(const CNetAddr& addr);
-bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
-bool SeenLocal(const CNetAddr& addr);
-bool IsLocal(const CNetAddr& addr);
-bool GetLocal(CNetAddr &addr, const CNetAddr *paddrPeer = NULL);
+bool AddLocal(const CService& addr, int nScore = LOCAL_NONE);
+bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE, int port = -1);
+bool SeenLocal(const CService& addr);
+bool IsLocal(const CService& addr);
+bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
 bool IsReachable(const CNetAddr &addr);
 CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
 
@@ -142,7 +143,7 @@ public:
     unsigned int nMessageStart;
     CAddress addr;
     std::string addrName;
-    CNetAddr addrLocal;
+    CService addrLocal;
     int nVersion;
     std::string strSubVer;
     bool fOneShot;
-- 
cgit v1.2.3


From 8f10a2889089af1b2ac64802360494b54c8c7ff1 Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Fri, 11 May 2012 15:28:59 +0200
Subject: Separate listening sockets, -bind=<addr>

---
 src/init.cpp    |  36 +++++++++++++++++---
 src/net.cpp     |  86 ++++++++++++++++++++++++++--------------------
 src/net.h       |   3 +-
 src/netbase.cpp | 103 ++++++++++++++++++++++++++++++--------------------------
 src/netbase.h   |   4 +--
 5 files changed, 140 insertions(+), 92 deletions(-)

(limited to 'src')

diff --git a/src/init.cpp b/src/init.cpp
index 202d513677..877b1d471f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -119,6 +119,18 @@ bool AppInit(int argc, char* argv[])
     return fRet;
 }
 
+bool static Bind(const CService &addr) {
+    if (IsLimited(addr))
+        return false;
+    std::string strError;
+    if (!BindListenPort(addr, strError))
+    {
+        ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
+        return false;
+    }
+    return true;
+}
+
 bool AppInit2(int argc, char* argv[])
 {
 #ifdef _MSC_VER
@@ -193,6 +205,7 @@ bool AppInit2(int argc, char* argv[])
             "  -discover        \t  "   + _("Try to discover public IP address (default: 1)") + "\n" +
             "  -irc             \t  "   + _("Find peers using internet relay chat (default: 0)") + "\n" +
             "  -listen          \t  "   + _("Accept connections from outside (default: 1)") + "\n" +
+            "  -bind=<addr>     \t  "   + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
 #ifdef QT_GUI
             "  -lang=<lang>     \t\t  " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
 #endif
@@ -548,7 +561,11 @@ bool AppInit2(int argc, char* argv[])
 
     if (mapArgs.count("-connect"))
         SoftSetBoolArg("-dnsseed", false);
- 
+
+    // even in Tor mode, if -bind is specified, you really want -listen
+    if (mapArgs.count("-bind"))
+        SoftSetBoolArg("-listen", true);
+
     bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
     if (fTor)
     {
@@ -588,14 +605,23 @@ bool AppInit2(int argc, char* argv[])
     const char* pszP2SH = "/P2SH/";
     COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
 
+    bool fBound = false;
     if (!fNoListen)
     {
         std::string strError;
-        if (!BindListenPort(strError))
-        {
-            ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
-            return false;
+        if (mapArgs.count("-bind")) {
+            BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
+                fBound |= Bind(CService(strBind, GetDefaultPort(), false));
+            }
+        } else {
+            struct in_addr inaddr_any = {s_addr: INADDR_ANY};
+            fBound |= Bind(CService(inaddr_any, GetDefaultPort()));
+#ifdef USE_IPV6
+            fBound |= Bind(CService(in6addr_any, GetDefaultPort()));
+#endif
         }
+        if (!fBound)
+            return false;
     }
 
     if (mapArgs.count("-externalip"))
diff --git a/src/net.cpp b/src/net.cpp
index a43b76d79c..28667166e6 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -52,7 +52,7 @@ static bool vfLimited[NET_MAX] = {};
 static CNode* pnodeLocalHost = NULL;
 uint64 nLocalHostNonce = 0;
 array<int, THREAD_MAX> vnThreadsRunning;
-static SOCKET hListenSocket = INVALID_SOCKET;
+static std::vector<SOCKET> vhListenSocket;
 CAddrMan addrman;
 
 vector<CNode*> vNodes;
@@ -719,9 +719,10 @@ void ThreadSocketHandler2(void* parg)
         FD_ZERO(&fdsetError);
         SOCKET hSocketMax = 0;
 
-        if(hListenSocket != INVALID_SOCKET)
+        BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
             FD_SET(hListenSocket, &fdsetRecv);
-        hSocketMax = max(hSocketMax, hListenSocket);
+            hSocketMax = max(hSocketMax, hListenSocket);
+        }
         {
             LOCK(cs_vNodes);
             BOOST_FOREACH(CNode* pnode, vNodes)
@@ -762,12 +763,13 @@ void ThreadSocketHandler2(void* parg)
         //
         // Accept new connections
         //
+        BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
         if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
         {
 #ifdef USE_IPV6
-            struct sockaddr_in6 sockaddr;
+            struct sockaddr_storage sockaddr;
 #else
-            struct sockaddr_in sockaddr;
+            struct sockaddr sockaddr;
 #endif
             socklen_t len = sizeof(sockaddr);
             SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
@@ -775,7 +777,8 @@ void ThreadSocketHandler2(void* parg)
             int nInbound = 0;
 
             if (hSocket != INVALID_SOCKET)
-                addr = CAddress(sockaddr);
+                if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+                    printf("warning: unknown socket family\n");
 
             {
                 LOCK(cs_vNodes);
@@ -1656,9 +1659,8 @@ void ThreadMessageHandler2(void* parg)
 
 
 
-bool BindListenPort(string& strError)
+bool BindListenPort(const CService &addrBind, string& strError)
 {
-    unsigned short nPort = GetListenPort();
     strError = "";
     int nOne = 1;
 
@@ -1676,11 +1678,19 @@ bool BindListenPort(string& strError)
 
     // Create socket for listening for incoming connections
 #ifdef USE_IPV6
-    int nFamily = AF_INET6;
+    struct sockaddr_storage sockaddr;
 #else
-    int nFamily = AF_INET;
+    struct sockaddr sockaddr;
 #endif
-    hListenSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
+    socklen_t len = sizeof(sockaddr);
+    if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
+    {
+        strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
+        printf("%s\n", strError.c_str());
+        return false;
+    }
+
+    SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
     if (hListenSocket == INVALID_SOCKET)
     {
         strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
@@ -1699,6 +1709,7 @@ bool BindListenPort(string& strError)
     setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
 #endif
 
+
 #ifdef WIN32
     // Set to nonblocking, incoming connections will also inherit this
     if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
@@ -1711,38 +1722,33 @@ bool BindListenPort(string& strError)
         return false;
     }
 
-    // The sockaddr_in structure specifies the address family,
-    // IP address, and port for the socket that is being bound
 #ifdef USE_IPV6
-    struct sockaddr_in6 sockaddr = sockaddr_in6();
-    memset(&sockaddr, 0, sizeof(sockaddr));
-    sockaddr.sin6_family = AF_INET6;
-    sockaddr.sin6_addr = in6addr_any;   // bind to all IPs on this computer
-    sockaddr.sin6_port = htons(nPort);
-#  ifdef WIN32
-    int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
-    int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
-    // this call is allowed to fail
-    setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
-#  endif
-#else
-    struct sockaddr_in sockaddr = sockaddr_in();
-    memset(&sockaddr, 0, sizeof(sockaddr));
-    sockaddr.sin_family = AF_INET;
-    sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
-    sockaddr.sin_port = htons(nPort);
+    // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
+    // and enable it by default or not. Try to enable it, if possible.
+    if (addrBind.IsIPv6()) {
+#ifdef IPV6_V6ONLY
+        setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
 #endif
-    if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
+#ifdef WIN32
+        int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
+        int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
+        // this call is allowed to fail
+        setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
+#endif
+    }
+#endif
+
+    if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
     {
         int nErr = WSAGetLastError();
         if (nErr == WSAEADDRINUSE)
-            strError = strprintf(_("Unable to bind to port %d on this computer.  Bitcoin is probably already running."), nPort);
+            strError = strprintf(_("Unable to bind to %s on this computer.  Bitcoin is probably already running."), addrBind.ToString().c_str());
         else
-            strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d, %s)", nPort, nErr, strerror(nErr));
+            strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
         printf("%s\n", strError.c_str());
         return false;
     }
-    printf("Bound to port %d\n", (int)nPort);
+    printf("Bound to %s\n", addrBind.ToString().c_str());
 
     // Listen for incoming connections
     if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
@@ -1752,6 +1758,11 @@ bool BindListenPort(string& strError)
         return false;
     }
 
+    vhListenSocket.push_back(hListenSocket);
+
+    if (addrBind.IsRoutable() && GetBoolArg("-discover", true))
+        AddLocal(addrBind, LOCAL_BIND);
+
     return true;
 }
 
@@ -1915,9 +1926,10 @@ public:
         BOOST_FOREACH(CNode* pnode, vNodes)
             if (pnode->hSocket != INVALID_SOCKET)
                 closesocket(pnode->hSocket);
-        if (hListenSocket != INVALID_SOCKET)
-            if (closesocket(hListenSocket) == SOCKET_ERROR)
-                printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
+        BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
+            if (hListenSocket != INVALID_SOCKET)
+                if (closesocket(hListenSocket) == SOCKET_ERROR)
+                    printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
 
 #ifdef WIN32
         // Shutdown Windows Sockets
diff --git a/src/net.h b/src/net.h
index 398b89dcfc..d62f512716 100644
--- a/src/net.h
+++ b/src/net.h
@@ -38,7 +38,7 @@ CNode* FindNode(const CNetAddr& ip);
 CNode* FindNode(const CService& ip);
 CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0);
 void MapPort(bool fMapPort);
-bool BindListenPort(std::string& strError=REF(std::string()));
+bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
 void StartNode(void* parg);
 bool StopNode();
 
@@ -46,6 +46,7 @@ enum
 {
     LOCAL_NONE,   // unknown
     LOCAL_IF,     // address a local interface listens on
+    LOCAL_BIND,   // address explicit bound to
     LOCAL_UPNP,   // address reported by UPnP
     LOCAL_IRC,    // address reported by IRC (deprecated)
     LOCAL_HTTP,   // address reported by whatismyip.com and similars
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 7e9620d9ff..ebf823e899 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -183,7 +183,12 @@ bool static Socks4(const CService &addrDest, SOCKET& hSocket)
     }
     char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
     struct sockaddr_in addr;
-    addrDest.GetSockAddr(&addr);
+    socklen_t len = sizeof(addr);
+    if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET)
+    {
+        closesocket(hSocket);
+        return error("Cannot get proxy destination address");
+    }
     memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
     memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
     char* pszSocks4 = pszSocks4IP;
@@ -319,37 +324,18 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
 {
     hSocketRet = INVALID_SOCKET;
 
-    struct sockaddr_storage sockaddr;
-    int nFamily = 0;
-    size_t nSockAddrLen = 0;
-
-    if (addrConnect.IsIPv4())
-    {
-        // Use IPv4 stack to connect to IPv4 addresses
-        struct sockaddr_in sockaddr4;
-        if (!addrConnect.GetSockAddr(&sockaddr4))
-            return false;
-        memcpy(&sockaddr, &sockaddr4, sizeof(sockaddr4));
-        nSockAddrLen = sizeof(sockaddr4);
-        nFamily = AF_INET;
-    }
 #ifdef USE_IPV6
-    else if (addrConnect.IsIPv6())
-    {
-        struct sockaddr_in6 sockaddr6;
-        if (!addrConnect.GetSockAddr6(&sockaddr6))
-            return false;
-        memcpy(&sockaddr, &sockaddr6, sizeof(sockaddr6));
-        nSockAddrLen = sizeof(sockaddr6);
-        nFamily = AF_INET6;
-    }
+    struct sockaddr_storage sockaddr;
+#else
+    struct sockaddr sockaddr;
 #endif
-    else {
+    socklen_t len = sizeof(sockaddr);
+    if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
         printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str());
         return false;
     }
 
-    SOCKET hSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
+    SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
     if (hSocket == INVALID_SOCKET)
         return false;
 #ifdef SO_NOSIGPIPE
@@ -369,7 +355,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
         return false;
     }
 
-    if (connect(hSocket, (struct sockaddr*)&sockaddr, nSockAddrLen) == SOCKET_ERROR)
+    if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
     {
         // WSAEINVAL is here because some legacy version of winsock uses it
         if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
@@ -902,6 +888,22 @@ CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr),
 }
 #endif
 
+bool CService::SetSockAddr(const struct sockaddr *paddr)
+{
+    switch (paddr->sa_family) {
+    case AF_INET:
+        *this = CService(*(const struct sockaddr_in*)paddr);
+        return true;
+#ifdef USE_IPV6
+    case AF_INET6:
+        *this = CService(*(const struct sockaddr_in6*)paddr);
+        return true;
+#endif
+    default:
+        return false;
+    }
+}
+
 CService::CService(const char *pszIpPort, bool fAllowLookup)
 {
     Init();
@@ -954,29 +956,36 @@ bool operator<(const CService& a, const CService& b)
     return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
 }
 
-bool CService::GetSockAddr(struct sockaddr_in* paddr) const
+bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
 {
-    if (!IsIPv4())
-        return false;
-    memset(paddr, 0, sizeof(struct sockaddr_in));
-    if (!GetInAddr(&paddr->sin_addr))
-        return false;
-    paddr->sin_family = AF_INET;
-    paddr->sin_port = htons(port);
-    return true;
-}
-
+    if (IsIPv4()) {
+        if (*addrlen < sizeof(struct sockaddr_in))
+            return false;
+        *addrlen = sizeof(struct sockaddr_in);
+        struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
+        memset(paddrin, 0, *addrlen);
+        if (!GetInAddr(&paddrin->sin_addr))
+            return false;
+        paddrin->sin_family = AF_INET;
+        paddrin->sin_port = htons(port);
+        return true;
+    }
 #ifdef USE_IPV6
-bool CService::GetSockAddr6(struct sockaddr_in6* paddr) const
-{
-    memset(paddr, 0, sizeof(struct sockaddr_in6));
-    if (!GetIn6Addr(&paddr->sin6_addr))
-        return false;
-    paddr->sin6_family = AF_INET6;
-    paddr->sin6_port = htons(port);
-    return true;
-}
+    if (IsIPv6()) {
+        if (*addrlen < sizeof(struct sockaddr_in6))
+            return false;
+        *addrlen = sizeof(struct sockaddr_in6);
+        struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;
+        memset(paddrin6, 0, *addrlen);
+        if (!GetIn6Addr(&paddrin6->sin6_addr))
+            return false;
+        paddrin6->sin6_family = AF_INET6;
+        paddrin6->sin6_port = htons(port);
+        return true;
+    }
 #endif
+    return false;
+}
 
 std::vector<unsigned char> CService::GetKey() const
 {
diff --git a/src/netbase.h b/src/netbase.h
index bd62c42e32..514a1ae950 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -105,7 +105,8 @@ class CService : public CNetAddr
         void Init();
         void SetPort(unsigned short portIn);
         unsigned short GetPort() const;
-        bool GetSockAddr(struct sockaddr_in* paddr) const;
+        bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
+        bool SetSockAddr(const struct sockaddr* paddr);
         friend bool operator==(const CService& a, const CService& b);
         friend bool operator!=(const CService& a, const CService& b);
         friend bool operator<(const CService& a, const CService& b);
@@ -117,7 +118,6 @@ class CService : public CNetAddr
 
 #ifdef USE_IPV6
         CService(const struct in6_addr& ipv6Addr, unsigned short port);
-        bool GetSockAddr6(struct sockaddr_in6* paddr) const;
         CService(const struct sockaddr_in6& addr);
 #endif
 
-- 
cgit v1.2.3