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/net.cpp | 56 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 19 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8603514f9..75c8bbaba 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); } -- 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/net.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 75c8bbaba..d407e6642 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 mapLocalHost; +static CCriticalSection cs_mapLocalHost; +static map mapLocalHost; +static bool vfReachable[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64 nLocalHostNonce = 0; array 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) { -- cgit v1.2.3 From 457754d2c24f7e53c55f4b68155a5fa702552327 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 4 May 2012 16:46:22 +0200 Subject: Add -blocknet to prevent connections to a given network --- src/net.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index d407e6642..79d0a8ddb 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 mapLocalHost; static bool vfReachable[NET_MAX] = {}; +static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64 nLocalHostNonce = 0; array 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; -- cgit v1.2.3 From 7fa4443f77a659031e277337770b506fcf954d69 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 10 May 2012 20:35:13 +0200 Subject: Keep port information for local addresses --- src/net.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 79d0a8ddb..a43b76d79 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 mapLocalHost; +static map 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::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) + for (map::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; -- 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/net.cpp | 86 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 37 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a43b76d79..28667166e 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 vnThreadsRunning; -static SOCKET hListenSocket = INVALID_SOCKET; +static std::vector vhListenSocket; CAddrMan addrman; vector 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 -- cgit v1.2.3