From 23aa78c405f82257e8578afb3d5d244aa27dcd74 Mon Sep 17 00:00:00 2001 From: Pieter Wuille 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/netbase.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 48709dc5c..a22d42a96 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 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 -- cgit v1.2.3 From d32148567f5866a7cd2a77a2f44f846134011c9c Mon Sep 17 00:00:00 2001 From: Pieter Wuille 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 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index a22d42a96..37e6120e7 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 -- cgit v1.2.3 From 090e5b40f1b3ac9ac6209f8996da4d686686a2ac Mon Sep 17 00:00:00 2001 From: Pieter Wuille 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/netbase.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 37e6120e7..4c852f5ee 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& 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()) -- cgit v1.2.3 From 623b987813acfc985ecca591e96ac0b84f5333e3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 4 May 2012 16:55:19 +0200 Subject: Add -noproxy to circumvent proxy for some network --- src/netbase.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 4c852f5ee..2c821c7ac 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& 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; -- cgit v1.2.3 From c5b3ffd8d5d61b0adb69882efd72f2d4e89f62d6 Mon Sep 17 00:00:00 2001 From: Pieter Wuille 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/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 2c821c7ac..7e9620d9f 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -772,40 +772,40 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const std::vector CNetAddr::GetGroup() const { std::vector 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 8f10a2889089af1b2ac64802360494b54c8c7ff1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 11 May 2012 15:28:59 +0200 Subject: Separate listening sockets, -bind= --- src/netbase.cpp | 103 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 47 deletions(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 7e9620d9f..ebf823e89 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 CService::GetKey() const { -- cgit v1.2.3