Implement IPv6 listening

With this commit IPv6-v3 surpass v0.6-IPv6-2 in term of features
  obsoleting it.
p3BitDht handle gracefully unwanted non IPv4 addresses
rsUdpStack handle gracefully unwanted non IPv4 addresses
pqissludp handle gracefully unwanted non IPv4 addresses
Move single address limitation workaround from
  p3discovery2::sendOwnContactInfo to better
  place p3PeerMgrIMPL::UpdateOwnAddress this way local address list is
  queried less often and only id there is some suggestion that it may
  have changed (probably ir will not be called all the times there is a
  changes in local network interfaces but is good enough)
Implement crossplatform rs_setsockopt to avoid too much ifdef around
Implement sockaddr_storage_copy to safely copy sockaddr_storage objects
This commit is contained in:
Gioacchino Mazzurco 2018-02-24 14:07:25 +01:00
parent b3c7d195c8
commit 4a138e07b9
No known key found for this signature in database
GPG key ID: A1FBCA3872E87051
14 changed files with 618 additions and 378 deletions

View file

@ -88,14 +88,26 @@ std::string rs_inet_ntoa(struct in_addr in);
/***************************/
// sockaddr_storage fns.
// Standard bind, on OSX anyway will not accept a longer socklen for IPv4.
// so hidding details behind function.
int universal_bind(int fd, const struct sockaddr *addr, socklen_t socklen);
int rs_bind(int fd, const sockaddr_storage& addr);
void sockaddr_storage_clear(struct sockaddr_storage &addr);
// mods.
bool sockaddr_storage_zeroip(struct sockaddr_storage &addr);
/**
* @brief Use this function to copy sockaddr_storage.
*
* POSIX does not require that objects of type sockaddr_storage can be copied
* as aggregates thus it is unsafe to aggregate copy ( operator = )
* sockaddr_storage and unexpected behaviors may happens due to padding
* and alignment.
*
* @see https://sourceware.org/bugzilla/show_bug.cgi?id=20111
* @see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71120
*/
bool sockaddr_storage_copy(const sockaddr_storage& src, sockaddr_storage& dst);
bool sockaddr_storage_copyip(struct sockaddr_storage &dst, const struct sockaddr_storage &src);
uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr);
bool sockaddr_storage_setport(struct sockaddr_storage &addr, uint16_t port);
@ -103,10 +115,14 @@ bool sockaddr_storage_setport(struct sockaddr_storage &addr, uint16_t port);
bool sockaddr_storage_setipv4(struct sockaddr_storage &addr, const sockaddr_in *addr_ipv4);
bool sockaddr_storage_setipv6(struct sockaddr_storage &addr, const sockaddr_in6 *addr_ipv6);
bool sockaddr_storage_inet_pton( sockaddr_storage &addr,
const std::string& ipStr );
bool sockaddr_storage_ipv4_aton(struct sockaddr_storage &addr, const char *name);
bool sockaddr_storage_ipv4_setport(struct sockaddr_storage &addr, const uint16_t port);
bool sockaddr_storage_ipv4_to_ipv6(sockaddr_storage &addr);
bool sockaddr_storage_ipv6_to_ipv4(sockaddr_storage &addr);
// comparisons.
bool operator<(const struct sockaddr_storage &a, const struct sockaddr_storage &b);
@ -132,8 +148,12 @@ 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);
bool sockaddr_storage_isLinkLocalNet(const struct sockaddr_storage &addr);
bool sockaddr_storage_ipv6_isLinkLocalNet(const sockaddr_storage &addr);
bool sockaddr_storage_isExternalNet(const struct sockaddr_storage &addr);
bool rs_inet_ntop(const sockaddr_storage &addr, std::string &dst);
bool sockaddr_storage_inet_ntop(const sockaddr_storage &addr, std::string &dst);
int rs_setsockopt( int sockfd, int level, int optname,
const uint8_t *optval, uint32_t optlen );
#endif /* RS_UNIVERSAL_NETWORK_HEADER */

View file

@ -26,6 +26,24 @@
#include <sstream>
#include <iomanip>
#include <cstdlib>
#ifdef WINDOWS_SYS
# include <Winsock2.h>
/** Provides Linux like accessor for in6_addr.s6_addr16 for Windows.
* Yet Windows doesn't provide 32 bits accessors so there is no way to use
* in6_addr.s6_addr32 crossplatform.
*/
# define s6_addr16 u.Word
#else
# include <netinet/in.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef __APPLE__
/// Provides Linux like accessor for in6_addr.s6_addr16 for Mac.
# define s6_addr16 __u6_addr.__u6_addr16
#endif // __APPLE__
#endif // WINDOWS_SYS
#include "util/rsnet.h"
#include "util/rsstring.h"
@ -90,17 +108,14 @@ bool sockaddr_storage_ipv6_isExternalNet(const struct sockaddr_storage &addr);
/******************************** Socket Fns ***********************************/
// Standard bind, on OSX anyway will not accept a longer socklen for IPv4.
// so hidding details behind function.
int universal_bind(int fd, const struct sockaddr *addr, socklen_t socklen)
int rs_bind(int fd, const sockaddr_storage& addr)
{
#ifdef SS_DEBUG
std::cerr << "universal_bind()";
std::cerr << std::endl;
std::cerr << __PRETTY_FUNCTION__ << std::endl;
#endif
const struct sockaddr_storage *ss_addr = (struct sockaddr_storage *) addr;
socklen_t len = socklen;
switch (ss_addr->ss_family)
socklen_t len = 0;
switch (addr.ss_family)
{
case AF_INET:
len = sizeof(struct sockaddr_in);
@ -110,13 +125,7 @@ int universal_bind(int fd, const struct sockaddr *addr, socklen_t socklen)
break;
}
if (len > socklen)
{
std::cerr << "universal_bind() ERROR len > socklen" << std::endl;
len = socklen;
}
return bind(fd, addr, len);
return bind(fd, reinterpret_cast<const struct sockaddr *>(&addr), len);
}
@ -252,6 +261,58 @@ bool sockaddr_storage_setipv6(struct sockaddr_storage &addr, const sockaddr_in6
return true;
}
#ifdef WINDOWS_SYS
int inet_pton(int af, const char *src, void *dst)
{
sockaddr_storage ss;
int size = sizeof(ss);
char src_copy[INET6_ADDRSTRLEN+1];
ZeroMemory(&ss, sizeof(ss));
/* stupid non-const API */
strncpy (src_copy, src, INET6_ADDRSTRLEN+1);
src_copy[INET6_ADDRSTRLEN] = 0;
if (WSAStringToAddressA(src_copy, af, NULL, (sockaddr *)&ss, &size) == 0)
{
switch(af)
{
case AF_INET:
*(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
return 1;
case AF_INET6:
*(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
return 1;
}
}
return 0;
}
#endif
bool sockaddr_storage_inet_pton( sockaddr_storage &addr,
const std::string& ipStr )
{
#ifdef SS_DEBUG
std::cerr << __PRETTY_FUNCTION__ << std::endl;
#endif
struct sockaddr_in6 * addrv6p = (struct sockaddr_in6 *) &addr;
struct sockaddr_in * addrv4p = (struct sockaddr_in *) &addr;
if ( 1 == inet_pton(AF_INET6, ipStr.c_str(), &(addrv6p->sin6_addr)) )
{
addr.ss_family = AF_INET6;
return true;
}
else if ( 1 == inet_pton(AF_INET, ipStr.c_str(), &(addrv4p->sin_addr)) )
{
addr.ss_family = AF_INET;
return sockaddr_storage_ipv4_to_ipv6(addr);
}
return false;
}
bool sockaddr_storage_ipv4_aton(struct sockaddr_storage &addr, const char *name)
{
@ -278,21 +339,59 @@ bool sockaddr_storage_ipv4_to_ipv6(sockaddr_storage &addr)
sockaddr_in & addr_ipv4 = (sockaddr_in &) addr;
sockaddr_in6 & addr_ipv6 = (sockaddr_in6 &) addr;
u_int32_t ip = addr_ipv4.sin_addr.s_addr;
u_int16_t port = addr_ipv4.sin_port;
uint32_t ip = addr_ipv4.sin_addr.s_addr;
uint16_t port = addr_ipv4.sin_port;
sockaddr_storage_clear(addr);
addr_ipv6.sin6_family = AF_INET6;
addr_ipv6.sin6_port = port;
addr_ipv6.sin6_addr.s6_addr32[3] = ip;
addr_ipv6.sin6_addr.s6_addr16[5] = (u_int16_t) 0xffff;
addr_ipv6.sin6_addr.s6_addr16[5] = htons(0xffff);
memmove( reinterpret_cast<void*>(&(addr_ipv6.sin6_addr.s6_addr16[6])),
reinterpret_cast<void*>(&ip), 4 );
return true;
}
return false;
}
bool sockaddr_storage_ipv6_to_ipv4(sockaddr_storage &addr)
{
#ifdef SS_DEBUG
std::cerr << __PRETTY_FUNCTION__ << std::endl;
#endif
if ( addr.ss_family == AF_INET ) return true;
if ( addr.ss_family == AF_INET6 )
{
sockaddr_in6 & addr_ipv6 = (sockaddr_in6 &) addr;
bool ipv4m = addr_ipv6.sin6_addr.s6_addr16[5] == htons(0xffff);
for ( int i = 0; ipv4m && i < 5 ; ++i )
ipv4m &= addr_ipv6.sin6_addr.s6_addr16[i] == htons(0x0000);
if(ipv4m)
{
uint32_t ip;
memmove( reinterpret_cast<void*>(&ip),
reinterpret_cast<void*>(&(addr_ipv6.sin6_addr.s6_addr16[6])),
4 );
uint16_t port = addr_ipv6.sin6_port;
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;
return true;
}
}
return false;
}
/******************************** Comparisions **********************************/
bool operator<(const struct sockaddr_storage &a, const struct sockaddr_storage &b)
@ -397,15 +496,20 @@ std::string sockaddr_storage_tostring(const struct sockaddr_storage &addr)
switch(addr.ss_family)
{
case AF_INET:
case AF_INET6:
output += "=";
output += sockaddr_storage_iptostring(addr);
output += ":";
output += sockaddr_storage_porttostring(addr);
break;
default:
break;
case AF_INET:
output += "=";
output += sockaddr_storage_iptostring(addr);
output += ":";
output += sockaddr_storage_porttostring(addr);
break;
case AF_INET6:
output += "=[";
output += sockaddr_storage_iptostring(addr);
output += "]:";
output += sockaddr_storage_porttostring(addr);
break;
default:
break;
}
return output;
}
@ -433,7 +537,7 @@ void sockaddr_storage_dump(const sockaddr_storage & addr, std::string * outputSt
{
const sockaddr_in6 * in6 = (const sockaddr_in6 *) & addr;
std::string addrStr = "INVALID_IPV6";
rs_inet_ntop(addr, addrStr);
sockaddr_storage_inet_ntop(addr, addrStr);
output << "addr.ss_family = AF_INET6";
output << " in6->sin6_addr = ";
output << addrStr;
@ -449,7 +553,8 @@ void sockaddr_storage_dump(const sockaddr_storage & addr, std::string * outputSt
const uint8_t * buf = reinterpret_cast<const uint8_t *>(&addr);
for( uint32_t i = 0; i < sizeof(addr); ++i )
output << std::setw(2) << std::setfill('0') << std::hex << +buf[i];
// The unary +buf[i] operation forces a no-op type conversion to an int with the correct sign
/* The unary +buf[i] operation forces a no-op type conversion to an int
* with the correct sign */
}
}
@ -477,6 +582,10 @@ std::string sockaddr_storage_familytostring(const struct sockaddr_storage &addr)
break;
default:
output = "AF_INVALID";
std::cerr << __PRETTY_FUNCTION__ << " Got invalid address!"
<< std::endl;
sockaddr_storage_dump(addr);
print_stacktrace();
break;
}
return output;
@ -487,15 +596,18 @@ std::string sockaddr_storage_iptostring(const struct sockaddr_storage &addr)
std::string output;
switch(addr.ss_family)
{
case AF_INET:
output = sockaddr_storage_ipv4_iptostring(addr);
break;
case AF_INET6:
output = sockaddr_storage_ipv6_iptostring(addr);
break;
default:
output = "INVALID_IP";
break;
case AF_INET:
output = sockaddr_storage_ipv4_iptostring(addr);
break;
case AF_INET6:
output = sockaddr_storage_ipv6_iptostring(addr);
break;
default:
output = "INVALID_IP";
std::cerr << __PRETTY_FUNCTION__ << " Got invalid IP:" << std::endl;
sockaddr_storage_dump(addr);
print_stacktrace();
break;
}
return output;
}
@ -619,9 +731,7 @@ bool sockaddr_storage_isLinkLocalNet(const struct sockaddr_storage &addr)
case AF_INET:
return isLinkLocalNet(&(to_const_ipv4_ptr(addr)->sin_addr));
case AF_INET6:
std::cerr << __PRETTY_FUNCTION__ << " for AF_INET6 not implemented"
<< std::endl;
break;
return sockaddr_storage_ipv6_isLinkLocalNet(addr);
default:
#ifdef SS_DEBUG
std::cerr << __PRETTY_FUNCTION__ <<" INVALID Family:" << std::endl;
@ -633,6 +743,16 @@ bool sockaddr_storage_isLinkLocalNet(const struct sockaddr_storage &addr)
return false;
}
bool sockaddr_storage_ipv6_isLinkLocalNet(const sockaddr_storage &addr)
{
if(addr.ss_family != AF_INET6) return false;
const sockaddr_in6 * addr6 = (const sockaddr_in6 *) &addr;
uint16_t mask = htons(0xffc0);
uint16_t llPrefix = htons(0xfe80);
return ((addr6->sin6_addr.s6_addr16[0] & mask ) == llPrefix);
}
bool sockaddr_storage_isExternalNet(const struct sockaddr_storage &addr)
{
@ -695,6 +815,51 @@ const struct sockaddr_in6 *to_const_ipv6_ptr(const struct sockaddr_storage &addr
/******************************** Set / Clear ***********************************/
bool sockaddr_storage_copy(const sockaddr_storage& src, sockaddr_storage& dst)
{
if(&src == &dst) return true;
switch(src.ss_family)
{
case AF_INET:
{
sockaddr_storage_clear(dst);
const sockaddr_in& ins(reinterpret_cast<const sockaddr_in&>(src));
sockaddr_in& ind(reinterpret_cast<sockaddr_in&>(dst));
ind.sin_family = AF_INET;
ind.sin_addr.s_addr = ins.sin_addr.s_addr;
ind.sin_port = ins.sin_port;
return true;
}
case AF_INET6:
{
sockaddr_storage_clear(dst);
const sockaddr_in6& ins6(reinterpret_cast<const sockaddr_in6&>(src));
sockaddr_in6& ind6(reinterpret_cast<sockaddr_in6&>(dst));
ind6.sin6_family = AF_INET6;
for(int i=0; i<8; ++i)
ind6.sin6_addr.s6_addr16[i] = ins6.sin6_addr.s6_addr16[i];
ind6.sin6_flowinfo = ins6.sin6_flowinfo;
ind6.sin6_port = ins6.sin6_port;
ind6.sin6_scope_id = ins6.sin6_scope_id;
return true;
}
default:
#ifdef SS_DEBUG
std::cerr << __PRETTY_FUNCTION__ << " Attempt to copy unknown family! "
<< src.ss_family << " defaulting to memmove!" << std::endl;
sockaddr_storage_dump(src);
print_stacktrace();
#endif // SS_DEBUG
memmove(&dst, &src, sizeof(sockaddr_storage));
return true;
}
}
bool sockaddr_storage_ipv4_zeroip(struct sockaddr_storage &addr)
{
#ifdef SS_DEBUG
@ -917,7 +1082,7 @@ std::string sockaddr_storage_ipv4_iptostring(const struct sockaddr_storage &addr
std::string sockaddr_storage_ipv6_iptostring(const struct sockaddr_storage & addr)
{
std::string addrStr;
rs_inet_ntop(addr, addrStr);
sockaddr_storage_inet_ntop(addr, addrStr);
return addrStr;
}
@ -1006,62 +1171,58 @@ bool sockaddr_storage_ipv4_isExternalNet(const struct sockaddr_storage &addr)
}
bool sockaddr_storage_ipv6_isnull(const struct sockaddr_storage &/*addr*/)
bool sockaddr_storage_ipv6_isnull(const struct sockaddr_storage& addr)
{
#ifdef SS_DEBUG
std::cerr << "sockaddr_storage_ipv6_isnull() TODO";
std::cerr << std::endl;
#endif
const sockaddr_in6& addr6 = reinterpret_cast<const sockaddr_in6&>(addr);
return false;
uint16_t nZero = htons(0); // anyway 0 should be the same in host and net
bool isZero = (addr6.sin6_addr.s6_addr16[7] == nZero);
for (int i=0; isZero && i<7; ++i)
isZero &= (addr6.sin6_addr.s6_addr16[i] == nZero);
return nZero;
}
bool sockaddr_storage_ipv6_isValidNet(const struct sockaddr_storage &/*addr*/)
bool sockaddr_storage_ipv6_isValidNet(const struct sockaddr_storage& addr)
{
#ifdef SS_DEBUG
std::cerr << "sockaddr_storage_ipv6_isValidNet() TODO";
std::cerr << std::endl;
#endif
return false;
return !sockaddr_storage_ipv6_isnull(addr);
}
bool sockaddr_storage_ipv6_isLoopbackNet(const struct sockaddr_storage &/*addr*/)
bool sockaddr_storage_ipv6_isLoopbackNet(const struct sockaddr_storage& addr)
{
const sockaddr_in6& addr6 = reinterpret_cast<const sockaddr_in6&>(addr);
bool isLoopBack = (addr6.sin6_addr.s6_addr16[7] == htons(0x0001));
uint16_t nZero = htons(0); // anyway 0 should be the same in host and net
for (int i=0; isLoopBack && i<7; ++i)
isLoopBack &= (addr6.sin6_addr.s6_addr16[i] == nZero);
#ifdef SS_DEBUG
std::cerr << "sockaddr_storage_ipv6_isLoopbackNet() TODO";
std::cerr << std::endl;
std::cerr << __PRETTY_FUNCTION__ << " " << sockaddr_storage_tostring(addr)
<< " " << isLoopBack << std::endl;
#endif
return false;
return isLoopBack;
}
bool sockaddr_storage_ipv6_isPrivateNet(const struct sockaddr_storage &/*addr*/)
{
#ifdef SS_DEBUG
std::cerr << "sockaddr_storage_ipv6_isPrivateNet() TODO";
std::cerr << std::endl;
#endif
/* It is unlikely that we end up connecting to an IPv6 address behind NAT
* W.R.T. RS it is probably better to consider all IPv6 as internal/local
* addresses as direct connection should be always possible. */
return false;
return true;
}
bool sockaddr_storage_ipv6_isExternalNet(const struct sockaddr_storage &/*addr*/)
{
#ifdef SS_DEBUG
std::cerr << "sockaddr_storage_ipv6_isExternalNet() TODO";
std::cerr << std::endl;
#endif
/* It is unlikely that we end up connecting to an IPv6 address behind NAT
* W.R.T. RS it is probably better to consider all IPv6 as internal/local
* addresses as direct connection should be always possible. */
return false;
}
#ifdef WINDOWS_SYS
#include <cstdlib>
#include <Winsock2.h>
#endif
bool rs_inet_ntop (const sockaddr_storage &addr, std::string &dst)
bool sockaddr_storage_inet_ntop (const sockaddr_storage &addr, std::string &dst)
{
bool success = false;
char ipStr[255];
@ -1098,3 +1259,15 @@ bool rs_inet_ntop (const sockaddr_storage &addr, std::string &dst)
dst = ipStr;
return success;
}
int rs_setsockopt( int sockfd, int level, int optname,
const uint8_t *optval, uint32_t optlen )
{
#ifdef WINDOWS_SYS
return setsockopt( sockfd, level, optname,
reinterpret_cast<const char*>(optval), optlen );
#else
return setsockopt( sockfd, level, optname,
reinterpret_cast<const void*>(optval), optlen );
#endif // WINDOWS_SYS
}

View file

@ -169,11 +169,14 @@ void RsTickingThread::fullstop()
void RsThread::start(const std::string &threadName)
{
if(isRunning())
{
std::cerr << "(EE) RsThread \"" << threadName << "\" is already running. Will not start twice!" << std::endl;
return ;
}
if(isRunning())
{
std::cerr << "(EE) RsThread \"" << threadName
<< "\" is already running. Will not start twice!"
<< std::endl;
print_stacktrace();
return;
}
pthread_t tid;
void *data = (void *)this ;