From d40a9002fade213a9bc2e351ffc5fa6e81202b9e Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 1 May 2015 13:14:25 +0000 Subject: [PATCH] improved IPv6 handling (Patch 19a39b42c4bb6256363b1624520c200835a9b93e from G10H4ck) git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.6-IPv6@8198 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/dht/p3bitdht_peers.cc | 26 +++--- libretroshare/src/pqi/p3peermgr.cc | 42 ++++----- libretroshare/src/pqi/pqinetwork.cc | 18 ++-- libretroshare/src/pqi/pqissl.cc | 5 +- libretroshare/src/rsserver/p3peers.cc | 4 +- libretroshare/src/util/rsnet.h | 4 +- libretroshare/src/util/rsnet_ss.cc | 112 +++++++++++++++--------- 7 files changed, 124 insertions(+), 87 deletions(-) diff --git a/libretroshare/src/dht/p3bitdht_peers.cc b/libretroshare/src/dht/p3bitdht_peers.cc index ad5126e28..4056bb43d 100644 --- a/libretroshare/src/dht/p3bitdht_peers.cc +++ b/libretroshare/src/dht/p3bitdht_peers.cc @@ -219,29 +219,23 @@ int p3BitDht::addBadPeer(const struct sockaddr_storage &addr, uint32_t /*reason* int p3BitDht::addKnownPeer(const RsPeerId &pid, const struct sockaddr_storage &addr, uint32_t flags) { struct sockaddr_in addrv4; + sockaddr_storage tmpAddr = addr; - if (addr.ss_family != AF_INET) + if (!sockaddr_storage_ipv6_to_ipv4(tmpAddr)) { - std::cerr << "p3BitDht::addKnownPeer() Warning! Non IPv4 Address - Cannot handle IPV6 Yet. addr.ss_family=" << addr.ss_family; - std::cerr << std::endl; - sockaddr_clear(&addrv4); - - - if (flags & NETASSIST_KNOWN_PEER_ONLINE) - { - std::cerr << "p3BitDht::addKnownPeer() Non IPv4 Address & ONLINE. Abort()ing."; - std::cerr << std::endl; - return 0; // TODO:IPV6 - } - - +#ifdef DEBUG_BITDHT + std::cerr << "p3BitDht::addKnownPeer() Warning! Cannot add non IPv4 Address" << std::endl; + sockaddr_storage_dump(addr); +#endif + return 0; // TODO:IPV6 } else { // convert. - struct sockaddr_in *ap = (struct sockaddr_in *) &addr; - + struct sockaddr_in *ap = (struct sockaddr_in *) &tmpAddr; + + sockaddr_clear(&addrv4); addrv4.sin_family = ap->sin_family; addrv4.sin_addr = ap->sin_addr; addrv4.sin_port = ap->sin_port; diff --git a/libretroshare/src/pqi/p3peermgr.cc b/libretroshare/src/pqi/p3peermgr.cc index b51ead9db..0a5947ac0 100644 --- a/libretroshare/src/pqi/p3peermgr.cc +++ b/libretroshare/src/pqi/p3peermgr.cc @@ -975,31 +975,34 @@ bool p3PeerMgrIMPL::UpdateOwnAddress(const struct sockaddr_storage &localAddr, c std::cerr << ")" << std::endl; #endif + std::list lAddrs; + getLocalAddresses(lAddrs); // Better to have this outside mutex + { /****** STACK LOCK MUTEX *******/ - RsStackMutex stack(mPeerMtx); (void)stack; - - mOwnState.localaddr = localAddr; + RS_STACK_MUTEX(mPeerMtx); // update ip address list + uint16_t port = 0; + if(!sockaddr_storage_isnull(localAddr)) + { + lAddrs.push_front(localAddr); + port = sockaddr_storage_port(localAddr); + } + + if (!lAddrs.empty()) + mOwnState.localaddr = lAddrs.front(); + std::list::iterator it; - std::list lAddrs; - getLocalAddresses(lAddrs); - lAddrs.push_front(localAddr); for ( it = lAddrs.begin(); it != lAddrs.end(); ++it) { pqiIpAddress ipAddressTimed; ipAddressTimed.mAddr = *it; - sockaddr_storage_setport(ipAddressTimed.mAddr, sockaddr_storage_port(localAddr)); + sockaddr_storage_setport(ipAddressTimed.mAddr, port); ipAddressTimed.mSeenTime = time(NULL); - ipAddressTimed.mSrc = 0 ; + ipAddressTimed.mSrc = 0; mOwnState.ipAddrs.updateLocalAddrs(ipAddressTimed); } - } - - - { - RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ //update ip address list pqiIpAddress ipAddressTimed; @@ -1015,7 +1018,7 @@ bool p3PeerMgrIMPL::UpdateOwnAddress(const struct sockaddr_storage &localAddr, c * This should keep people happy, and allow for misconfiguration! */ - if (mOwnState.netMode & RS_NET_MODE_TRY_EXT) + if (mOwnState.netMode & RS_NET_MODE_TRY_EXT) { /**** THIS CASE SHOULD NOT BE TRIGGERED ****/ std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress() Disabling Update of Server Port "; @@ -1025,10 +1028,10 @@ bool p3PeerMgrIMPL::UpdateOwnAddress(const struct sockaddr_storage &localAddr, c std::cerr << sockaddr_storage_tostring(mOwnState.serveraddr); std::cerr << std::endl; } - else if (mOwnState.netMode & RS_NET_MODE_EXT) + else if (mOwnState.netMode & RS_NET_MODE_EXT) { - sockaddr_storage_copyip(mOwnState.serveraddr,extAddr); - + sockaddr_storage_copyip(mOwnState.serveraddr, extAddr); + std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress() Disabling Update of Server Port "; std::cerr << " as MANUAL FORWARD Mode"; std::cerr << std::endl; @@ -1037,10 +1040,9 @@ bool p3PeerMgrIMPL::UpdateOwnAddress(const struct sockaddr_storage &localAddr, c std::cerr << std::endl; } else - { mOwnState.serveraddr = extAddr; - } - } + + } // end RS_STACK_MUTEX(mPeerMtx); IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ mLinkMgr->setLocalAddress(localAddr); diff --git a/libretroshare/src/pqi/pqinetwork.cc b/libretroshare/src/pqi/pqinetwork.cc index 22509356d..7eaca022f 100644 --- a/libretroshare/src/pqi/pqinetwork.cc +++ b/libretroshare/src/pqi/pqinetwork.cc @@ -371,21 +371,25 @@ in_addr_t inet_network(const char *inet_name) bool getLocalAddresses(std::list & addrs) { struct ifaddrs *ifsaddrs, *ifa; - if(getifaddrs(&ifsaddrs) != 0) exit(1); + if(getifaddrs(&ifsaddrs) != 0) + { + freeifaddrs(ifsaddrs); + return false; + } addrs.clear(); for ( ifa = ifsaddrs; ifa; ifa = ifa->ifa_next ) if ( (ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_LOOPBACK) ) { - sockaddr_storage * tmp = new sockaddr_storage; - if (sockaddr_storage_copyip(* tmp, * (const struct sockaddr_storage *) ifa->ifa_addr)) - addrs.push_back(*tmp); - else delete tmp; + const sockaddr_storage & ifaaddr = * (const struct sockaddr_storage *) ifa->ifa_addr; + if (sockaddr_storage_isLinkLocal(ifaaddr)) continue; + sockaddr_storage tmp; + if (sockaddr_storage_copyip(tmp, ifaaddr)) addrs.push_back(tmp); } - freeifaddrs(ifsaddrs); - return (!addrs.empty()); + freeifaddrs(ifsaddrs); + return !addrs.empty(); } diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 642570e59..e24a5c084 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -604,12 +604,12 @@ int pqissl::Delay_Connection() } rslog(RSL_WARNING, pqisslzone, - "pqissl::Initiate_Connection() Already Attempt in Progress!"); + "pqissl::Delay_Connection() Already Attempt in Progress!"); return -1; } -int pqissl::Initiate_Connection() +int pqissl::Initiate_Connection() { int err; struct sockaddr_storage addr = remote_addr; @@ -750,6 +750,7 @@ int pqissl::Initiate_Connection() { std::string out; rs_sprintf(out, "pqissl::Initiate_Connection() connect returns:%d -> errno: %d error: %s\n", err, errno, socket_errorType(errno).c_str()); + sockaddr_storage_dump(addr, &out); if (errno == EINPROGRESS) { diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index 948f2cd59..bd31de18d 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -894,7 +894,9 @@ bool p3Peers::setVisState(const RsPeerId &id, uint16_t vs_disc, uint16_t vs_dht) bool p3Peers::getProxyServer(std::string &addr, uint16_t &port, uint32_t &status) { - std::cerr << "p3Peers::getProxyServer()" << std::endl; +#ifdef P3PEERS_DEBUG + std::cerr << "p3Peers::getProxyServer()" << std::endl; +#endif struct sockaddr_storage proxy_addr; mPeerMgr->getProxyServerAddress(proxy_addr); diff --git a/libretroshare/src/util/rsnet.h b/libretroshare/src/util/rsnet.h index ee23b5752..a0eccc4ab 100644 --- a/libretroshare/src/util/rsnet.h +++ b/libretroshare/src/util/rsnet.h @@ -110,7 +110,7 @@ std::string sockaddr_storage_tostring(const struct sockaddr_storage &addr); std::string sockaddr_storage_familytostring(const struct sockaddr_storage &addr); std::string sockaddr_storage_iptostring(const struct sockaddr_storage &addr); std::string sockaddr_storage_porttostring(const struct sockaddr_storage &addr); -void sockaddr_storage_dump(const sockaddr_storage & addr); +void sockaddr_storage_dump(const sockaddr_storage & addr, std::string * outputString = NULL); // output //void sockaddr_storage_output(const struct sockaddr_storage &addr, std::ostream &out); @@ -118,6 +118,8 @@ void sockaddr_storage_dump(const sockaddr_storage & addr); // net checks. bool sockaddr_storage_isnull(const struct sockaddr_storage &addr); +bool sockaddr_storage_isLinkLocal(const struct sockaddr_storage &addr); +bool sockaddr_storage_isIPv4Mapped(const struct sockaddr_storage &addr); bool sockaddr_storage_isValidNet(const struct sockaddr_storage &addr); bool sockaddr_storage_isLoopbackNet(const struct sockaddr_storage &addr); bool sockaddr_storage_isPrivateNet(const struct sockaddr_storage &addr); diff --git a/libretroshare/src/util/rsnet_ss.cc b/libretroshare/src/util/rsnet_ss.cc index a1f50d060..365d9e861 100644 --- a/libretroshare/src/util/rsnet_ss.cc +++ b/libretroshare/src/util/rsnet_ss.cc @@ -27,6 +27,7 @@ #include "util/rsnet.h" #include "util/rsstring.h" +#include "util/stacktrace.h" #include "pqi/pqinetwork.h" /***************************** Internal Helper Fns ******************************/ @@ -180,8 +181,7 @@ bool sockaddr_storage_copyip(struct sockaddr_storage &dst, const struct sockaddr uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr) { #ifdef SS_DEBUG - std::cerr << "sockaddr_storage_port()"; - std::cerr << std::endl; + std::cerr << "sockaddr_storage_port()" << std::endl; #endif switch(addr.ss_family) { @@ -192,8 +192,9 @@ uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr) return sockaddr_storage_ipv6_port(addr); break; default: - std::cerr << "sockaddr_storage_port() invalid addr.ss_family" << std::endl; + std::cerr << "sockaddr_storage_port() invalid addr.ss_family "; sockaddr_storage_dump(addr); + //print_stacktrace(); break; } return 0; @@ -310,27 +311,20 @@ bool sockaddr_storage_ipv6_to_ipv4(sockaddr_storage &addr) if ( addr.ss_family == AF_INET ) return true; - if ( addr.ss_family == AF_INET6 ) + if(sockaddr_storage_isIPv4Mapped(addr)) { sockaddr_in6 & addr_ipv6 = (sockaddr_in6 &) addr; - bool ipv4m = addr_ipv6.sin6_addr.s6_addr16[5] == (u_int16_t) 0xffff; - for ( int i = 0; ipv4m && i < 5 ; ++i ) - ipv4m &= addr_ipv6.sin6_addr.s6_addr16[i] == (u_int16_t) 0x0000; + u_int32_t ip = addr_ipv6.sin6_addr.s6_addr32[3]; + u_int16_t port = addr_ipv6.sin6_port; - if(ipv4m) - { - u_int32_t ip = addr_ipv6.sin6_addr.s6_addr32[3]; - u_int16_t port = addr_ipv6.sin6_port; + sockaddr_in & addr_ipv4 = (sockaddr_in &) addr; - sockaddr_in & addr_ipv4 = (sockaddr_in &) addr; + sockaddr_storage_clear(addr); + addr_ipv4.sin_family = AF_INET; + addr_ipv4.sin_port = port; + addr_ipv4.sin_addr.s_addr = ip; - sockaddr_storage_clear(addr); - addr_ipv4.sin_family = AF_INET; - addr_ipv4.sin_port = port; - addr_ipv4.sin_addr.s_addr = ip; - - return true; - } + return true; } return false; @@ -478,26 +472,54 @@ std::string sockaddr_storage_porttostring(const struct sockaddr_storage &addr) bool sockaddr_storage_isnull(const struct sockaddr_storage &addr) { #ifdef SS_DEBUG - std::cerr << "sockaddr_storage_isnull()"; - std::cerr << std::endl; + std::cerr << "sockaddr_storage_isnull()" << std::endl; #endif - if (addr.ss_family == 0) - return true; - switch(addr.ss_family) { case AF_INET: return sockaddr_storage_ipv4_isnull(addr); - break; case AF_INET6: return sockaddr_storage_ipv6_isnull(addr); - break; default: return true; - break; } - return true; +} + +bool sockaddr_storage_isLinkLocal(const struct sockaddr_storage &addr) +{ +#ifdef SS_DEBUG + std::cerr << "sockaddr_storage_isLinkLocal()" << std::endl; +#endif + + switch(addr.ss_family) + { + case AF_INET: + return false; // TODO:IPv4 + case AF_INET6: + { + const sockaddr_in6 * addr6 = (const sockaddr_in6 *) &addr; + u_int16_t mask = 0xc0ff; // Mask end prefix inverted because of IPv6 is big endian + return ((addr6->sin6_addr.s6_addr16[0] & mask ) == 0x80fe); + } + + default: + return false; + } +} + +bool sockaddr_storage_isIPv4Mapped(const struct sockaddr_storage &addr) +{ + if (addr.ss_family == AF_INET6) + { + sockaddr_in6 & addr_ipv6 = (sockaddr_in6 &) addr; + bool ipv4m = addr_ipv6.sin6_addr.s6_addr16[5] == (u_int16_t) 0xffff; + for ( int i = 0; ipv4m && i < 5 ; ++i ) + ipv4m &= addr_ipv6.sin6_addr.s6_addr16[i] == (u_int16_t) 0x0000; + return ipv4m; + } + + return false; } bool sockaddr_storage_isValidNet(const struct sockaddr_storage &addr) @@ -587,8 +609,7 @@ bool sockaddr_storage_isExternalNet(const struct sockaddr_storage &addr) return sockaddr_storage_ipv6_isExternalNet(addr); break; default: - std::cerr << "sockaddr_storage_isExternalNet() INVALID Family - error"; - std::cerr << std::endl; + std::cerr << "sockaddr_storage_isExternalNet() INVALID Family - error" << std::endl; break; } return false; @@ -703,14 +724,14 @@ bool sockaddr_storage_ipv6_copyip(struct sockaddr_storage &dst, const struct soc dst_ptr->sin6_family = AF_INET6; memcpy(&(dst_ptr->sin6_addr), &(src_ptr->sin6_addr), sizeof(src_ptr->sin6_addr)); + dst_ptr->sin6_scope_id = src_ptr->sin6_scope_id; return true; } uint16_t sockaddr_storage_ipv6_port(const struct sockaddr_storage &addr) { #ifdef SS_DEBUG - std::cerr << "sockaddr_storage_ipv6_port()"; - std::cerr << std::endl; + std::cerr << "sockaddr_storage_ipv6_port()" << std::endl; #endif const struct sockaddr_in6 *ipv6_ptr = to_const_ipv6_ptr(addr); uint16_t port = ntohs(ipv6_ptr->sin6_port); @@ -719,8 +740,9 @@ uint16_t sockaddr_storage_ipv6_port(const struct sockaddr_storage &addr) bool sockaddr_storage_ipv6_setport(struct sockaddr_storage &addr, uint16_t port) { - std::cerr << "sockaddr_storage_ipv6_setport()"; - std::cerr << std::endl; +#ifdef SS_DEBUG + std::cerr << "sockaddr_storage_ipv6_setport()" << std::endl; +#endif struct sockaddr_in6 *ipv6_ptr = to_ipv6_ptr(addr); ipv6_ptr->sin6_port = htons(port); @@ -866,7 +888,7 @@ std::string sockaddr_storage_iptostring(const struct sockaddr_storage & addr) return output; } -void sockaddr_storage_dump(const sockaddr_storage & addr) +void sockaddr_storage_dump(const sockaddr_storage & addr, std::string * outputString) { // This function must not rely on others sockaddr_storage_* @@ -892,6 +914,8 @@ void sockaddr_storage_dump(const sockaddr_storage & addr) output << "addr.ss_family = AF_INET6"; output << " in6->sin6_addr = "; output << addrStr; + output << " in6->sin6_scope_id = "; + output << in6->sin6_scope_id; output << " in6->sin6_port = "; output << in6->sin6_port; break; @@ -906,7 +930,15 @@ void sockaddr_storage_dump(const sockaddr_storage & addr) output << addr.__ss_padding; }} - std::cerr << output.str() << std::endl; + if(outputString) + { + outputString->append(output.str() + "\n"); +#ifdef SS_DEBUG + std::cerr << output.str() << std::endl; +#endif + } + else + std::cerr << output.str() << std::endl; } /********************************* Net Checks ***********************************/ @@ -1013,9 +1045,9 @@ bool sockaddr_storage_ipv6_isValidNet(const struct sockaddr_storage & ) bool sockaddr_storage_ipv6_isLoopbackNet(const struct sockaddr_storage & addr ) { sockaddr_in6 & addr6 = (sockaddr_in6 &) addr; - bool isLp = (addr6.sin6_addr.s6_addr32[3] == 0x1); + bool isLp = (addr6.sin6_addr.s6_addr32[3] == 0x10000000); // IPv6 is big endian for (int i=0; isLp && i<3; ++i) - isLp &= (addr6.sin6_addr.s6_addr32[i] == 0x0); + isLp &= (addr6.sin6_addr.s6_addr32[i] == 0x00000000); #ifdef SS_DEBUG sockaddr_storage_dump(addr); @@ -1034,13 +1066,13 @@ bool sockaddr_storage_ipv6_isPrivateNet(const struct sockaddr_storage &) return false; } -bool sockaddr_storage_ipv6_isExternalNet(const struct sockaddr_storage &) +bool sockaddr_storage_ipv6_isExternalNet(const struct sockaddr_storage & addr) { #ifdef SS_DEBUG std::cerr << "sockaddr_storage_ipv6_isExternalNet() TODO" << std::endl; #endif - return true; + return !sockaddr_storage_isLinkLocal(addr); }