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

@ -4,6 +4,7 @@
* BitDht interface for RetroShare. * BitDht interface for RetroShare.
* *
* Copyright 2009-2010 by Robert Fernie. * Copyright 2009-2010 by Robert Fernie.
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -184,18 +185,24 @@ bool p3BitDht::dropPeer(const RsPeerId& pid)
********************************* Basic Peer Details ************************************* ********************************* Basic Peer Details *************************************
******************************************************************************************/ ******************************************************************************************/
int p3BitDht::addBadPeer(const struct sockaddr_storage &addr, uint32_t /*reason*/, uint32_t /*flags*/, uint32_t /*age*/) int p3BitDht::addBadPeer( const sockaddr_storage &addr, uint32_t /*reason*/,
uint32_t /*flags*/, uint32_t /*age*/ )
{ {
//mUdpBitDht->updateKnownPeer(&id, 0, bdflags); //mUdpBitDht->updateKnownPeer(&id, 0, bdflags);
struct sockaddr_in addrv4; sockaddr_in addrv4;
if (addr.ss_family != AF_INET) sockaddr_storage tmpaddr;
sockaddr_storage_copy(addr, tmpaddr);
if(!sockaddr_storage_ipv6_to_ipv4(tmpaddr))
{ {
std::cerr << "p3BitDht::addBadPeer() cannot handle IPV6 Yet, aborting"; std::cerr << __PRETTY_FUNCTION__ << " Error: got non IPv4 address!"
std::cerr << std::endl; << std::endl;
abort(); sockaddr_storage_dump(addr);
print_stacktrace();
return -EINVAL;
} }
struct sockaddr_in *ap = (struct sockaddr_in *) &addr;
struct sockaddr_in *ap = (struct sockaddr_in *) &tmpaddr;
// convert. // convert.
addrv4.sin_family = ap->sin_family; addrv4.sin_family = ap->sin_family;
@ -216,38 +223,29 @@ 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) int p3BitDht::addKnownPeer( const RsPeerId &pid,
const sockaddr_storage &addr, uint32_t flags )
{ {
struct sockaddr_in addrv4; sockaddr_in addrv4;
sockaddr_clear(&addrv4); sockaddr_clear(&addrv4);
if (addr.ss_family != AF_INET) sockaddr_storage tmpaddr;
sockaddr_storage_copy(addr, tmpaddr);
if( !sockaddr_storage_isnull(addr) &&
!sockaddr_storage_ipv6_to_ipv4(tmpaddr) )
{ {
if(addr.ss_family != AF_UNSPEC) std::cerr << __PRETTY_FUNCTION__ << " Error: got non IPv4 address!"
{ << std::endl;
std::cerr << "p3BitDht::addKnownPeer() Warning! Non IPv4 Address - Cannot handle IPV6 Yet. addr.ss_family=" << addr.ss_family; sockaddr_storage_dump(addr);
std::cerr << std::endl; print_stacktrace();
return -EINVAL;
} }
if (flags & NETASSIST_KNOWN_PEER_ONLINE)
{
std::cerr << "p3BitDht::addKnownPeer() Non IPv4 Address & ONLINE. Abort()ing.";
std::cerr << std::endl;
abort();
}
}
else
{
// convert. // convert.
struct sockaddr_in *ap = (struct sockaddr_in *) &addr; struct sockaddr_in *ap = (struct sockaddr_in *) &tmpaddr;
addrv4.sin_family = ap->sin_family; addrv4.sin_family = ap->sin_family;
addrv4.sin_addr = ap->sin_addr; addrv4.sin_addr = ap->sin_addr;
addrv4.sin_port = ap->sin_port; addrv4.sin_port = ap->sin_port;
}
int p3type = 0; int p3type = 0;
int bdflags = 0; int bdflags = 0;
@ -295,7 +293,7 @@ int p3BitDht::addKnownPeer(const RsPeerId &pid, const struct sockaddr_storage &a
if (!isOwnId) if (!isOwnId)
{ {
RsStackMutex stack(dhtMtx); /********* LOCKED *********/ RS_STACK_MUTEX(dhtMtx);
DhtPeerDetails *dpd = addInternalPeer_locked(pid, p3type); DhtPeerDetails *dpd = addInternalPeer_locked(pid, p3type);

View File

@ -1038,12 +1038,15 @@ bool p3NetMgrIMPL::checkNetAddress()
} }
/* If no satisfactory local address has been found yet relax and /* If no satisfactory local address has been found yet relax and
* accept also link local addresses */ * accept also IPv4 link local addresses, IPv6 link local is not
* accepted because of sin6_scope_id that depends on the host using
* it as an outgoing connection endpoint */
if(!validAddr) for (auto it = addrs.begin(); it!=addrs.end(); ++it) if(!validAddr) for (auto it = addrs.begin(); it!=addrs.end(); ++it)
{ {
sockaddr_storage& addr(*it); sockaddr_storage& addr(*it);
if( sockaddr_storage_isValidNet(addr) && if( sockaddr_storage_isValidNet(addr) &&
!sockaddr_storage_isLoopbackNet(addr) ) !sockaddr_storage_isLoopbackNet(addr) &&
!sockaddr_storage_ipv6_isLinkLocalNet(addr) )
{ {
prefAddr = addr; prefAddr = addr;
validAddr = true; validAddr = true;

View File

@ -4,6 +4,7 @@
* 3P/PQI network interface for RetroShare. * 3P/PQI network interface for RetroShare.
* *
* Copyright 2007-2011 by Robert Fernie. * Copyright 2007-2011 by Robert Fernie.
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -23,6 +24,9 @@
* *
*/ */
#include <vector> // for std::vector
#include <algorithm> // for std::random_shuffle
#include "rsserver/p3face.h" #include "rsserver/p3face.h"
#include "util/rsnet.h" #include "util/rsnet.h"
#include "pqi/authgpg.h" #include "pqi/authgpg.h"
@ -32,6 +36,7 @@
#include "pqi/p3linkmgr.h" #include "pqi/p3linkmgr.h"
#include "pqi/p3netmgr.h" #include "pqi/p3netmgr.h"
#include "pqi/p3historymgr.h" #include "pqi/p3historymgr.h"
#include "pqi/pqinetwork.h" // for getLocalAddresses
//#include "pqi/p3dhtmgr.h" // Only need it for constants. //#include "pqi/p3dhtmgr.h" // Only need it for constants.
//#include "tcponudp/tou.h" //#include "tcponudp/tou.h"
@ -1227,38 +1232,85 @@ void p3PeerMgrIMPL::printPeerLists(std::ostream &out)
* as it doesn't call back to there. * as it doesn't call back to there.
*/ */
bool p3PeerMgrIMPL::UpdateOwnAddress(const struct sockaddr_storage &localAddr, const struct sockaddr_storage &extAddr) bool p3PeerMgrIMPL::UpdateOwnAddress( const sockaddr_storage& localAddr,
const sockaddr_storage& extAddr )
{ {
#ifdef PEER_DEBUG #ifdef PEER_DEBUG
std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress("; std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress("
std::cerr << sockaddr_storage_tostring(localAddr); << sockaddr_storage_tostring(localAddr) << ", "
std::cerr << ", "; << sockaddr_storage_tostring(extAddr) << ")" << std::endl;
std::cerr << sockaddr_storage_tostring(extAddr);
std::cerr << ")" << std::endl;
#endif #endif
if((rsBanList != NULL) && !rsBanList->isAddressAccepted(localAddr, RSBANLIST_CHECKING_FLAGS_BLACKLIST)) if( rsBanList &&
!rsBanList->isAddressAccepted(localAddr,
RSBANLIST_CHECKING_FLAGS_BLACKLIST) )
{ {
std::cerr << "(SS) Trying to set own IP to a banned IP " << sockaddr_storage_iptostring(localAddr) << ". This probably means that a friend in under traffic re-routing attack." << std::endl; std::cerr << "(SS) Trying to set own IP to a banned IP "
return false ; << sockaddr_storage_iptostring(localAddr) << ". This probably"
<< "means that a friend in under traffic re-routing attack."
<< std::endl;
return false;
} }
{ {
RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ RS_STACK_MUTEX(mPeerMtx);
//update ip address list //update ip address list
pqiIpAddress ipAddressTimed; pqiIpAddress ipAddressTimed;
ipAddressTimed.mAddr = localAddr; ipAddressTimed.mAddr = localAddr;
ipAddressTimed.mSeenTime = time(NULL); ipAddressTimed.mSeenTime = time(NULL);
ipAddressTimed.mSrc = 0 ; ipAddressTimed.mSrc = 0;
mOwnState.ipAddrs.updateLocalAddrs(ipAddressTimed); mOwnState.ipAddrs.updateLocalAddrs(ipAddressTimed);
if(!mOwnState.hiddenNode)
{
/* Workaround to spread multiple local ip addresses when presents.
* This is needed because RS wrongly assumes that there is just one
* active local ip address at time. */
std::vector<sockaddr_storage> addrs;
if(getLocalAddresses(addrs))
{
/* To work around MAX_ADDRESS_LIST_SIZE addresses limitation,
* let's shuffle the list of local addresses in the hope that
* with enough time every local address is advertised to
* trusted nodes so they may try to connect to all of them
* including the most convenient if a local connection exists.
*/
std::random_shuffle(addrs.begin(), addrs.end());
for (auto it = addrs.begin(); it!=addrs.end(); ++it)
{
sockaddr_storage& addr(*it);
if( sockaddr_storage_isValidNet(addr) &&
!sockaddr_storage_isLoopbackNet(addr) &&
/* Avoid IPv6 link local addresses as we don't have
* implemented the logic needed to handle sin6_scope_id.
* To properly handle sin6_scope_id it would probably
* require deep reenginering of the RetroShare
* networking stack */
!sockaddr_storage_ipv6_isLinkLocalNet(addr) )
{
pqiIpAddress pqiIp;
sockaddr_storage_clear(pqiIp.mAddr);
pqiIp.mAddr.ss_family = addr.ss_family;
sockaddr_storage_copyip(pqiIp.mAddr, addr);
sockaddr_storage_setport(
pqiIp.mAddr,
sockaddr_storage_port(localAddr) );
pqiIp.mSeenTime = time(nullptr);
pqiIp.mSrc = 0;
mOwnState.ipAddrs.updateLocalAddrs(pqiIp);
}
}
}
}
mOwnState.localaddr = localAddr; mOwnState.localaddr = localAddr;
} }
{ {
RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ RS_STACK_MUTEX(mPeerMtx);
//update ip address list //update ip address list
pqiIpAddress ipAddressTimed; pqiIpAddress ipAddressTimed;

View File

@ -41,6 +41,7 @@
#include "util/rsdebug.h" #include "util/rsdebug.h"
#include "util/rsstring.h" #include "util/rsstring.h"
#include "util/rsnet.h" #include "util/rsnet.h"
#include "util/stacktrace.h"
static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"}; static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"};
#define pqinetzone &pqinetzoneInfo #define pqinetzone &pqinetzoneInfo
@ -335,15 +336,17 @@ bool getLocalAddresses(std::vector<sockaddr_storage>& addrs)
struct ifaddrs *ifsaddrs, *ifa; struct ifaddrs *ifsaddrs, *ifa;
if(getifaddrs(&ifsaddrs) != 0) if(getifaddrs(&ifsaddrs) != 0)
{ {
std::cerr << "FATAL ERROR: getLocalAddresses failed!" << std::endl; std::cerr << __PRETTY_FUNCTION__ << " FATAL ERROR: " << errno << " "
return false ; << strerror(errno) << std::endl;
print_stacktrace();
return false;
} }
for ( ifa = ifsaddrs; ifa; ifa = ifa->ifa_next ) for ( ifa = ifsaddrs; ifa; ifa = ifa->ifa_next )
if ( ifa->ifa_addr && (ifa->ifa_flags & IFF_UP) ) if ( ifa->ifa_addr && (ifa->ifa_flags & IFF_UP) )
{ {
sockaddr_storage tmp; sockaddr_storage tmp;
sockaddr_storage_clear(tmp); sockaddr_storage_clear(tmp);
if (sockaddr_storage_copyip(tmp, * reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr))) if (sockaddr_storage_copyip(tmp, *reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr)))
addrs.push_back(tmp); addrs.push_back(tmp);
} }
freeifaddrs(ifsaddrs); freeifaddrs(ifsaddrs);

View File

@ -60,14 +60,15 @@ static struct RsLog::logInfo pqisslzoneInfo = {RsLog::Default, "pqisslzone"};
#define PQISSL_PASSIVE 0x00 #define PQISSL_PASSIVE 0x00
#define PQISSL_ACTIVE 0x01 #define PQISSL_ACTIVE 0x01
#define PQISSL_DEBUG 1
#define PQISSL_LOG_DEBUG 1
const int PQISSL_LOCAL_FLAG = 0x01; const int PQISSL_LOCAL_FLAG = 0x01;
const int PQISSL_REMOTE_FLAG = 0x02; const int PQISSL_REMOTE_FLAG = 0x02;
const int PQISSL_UDP_FLAG = 0x02; const int PQISSL_UDP_FLAG = 0x02;
***********/ ***********/
//#define PQISSL_DEBUG 1
//#define PQISSL_LOG_DEBUG 1
static const int PQISSL_MAX_READ_ZERO_COUNT = 20; static const int PQISSL_MAX_READ_ZERO_COUNT = 20;
static const time_t PQISSL_MAX_READ_ZERO_TIME = 15; // 15 seconds of no data => reset. (atm HeartBeat pkt sent 5 secs) static const time_t PQISSL_MAX_READ_ZERO_TIME = 15; // 15 seconds of no data => reset. (atm HeartBeat pkt sent 5 secs)
@ -123,6 +124,7 @@ pqissl::pqissl(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm) :
int pqissl::connect(const struct sockaddr_storage &raddr) int pqissl::connect(const struct sockaddr_storage &raddr)
{ {
RS_STACK_MUTEX(mSslMtx); RS_STACK_MUTEX(mSslMtx);
remote_addr = raddr; remote_addr = raddr;
return ConnectAttempt(); return ConnectAttempt();
} }
@ -171,8 +173,7 @@ int pqissl::close()
// put back on the listening queue. // put back on the listening queue.
int pqissl::reset() int pqissl::reset()
{ {
RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ RS_STACK_MUTEX(mSslMtx);
return reset_locked(); return reset_locked();
} }
@ -355,7 +356,7 @@ int pqissl::status()
out += " active: \n"; out += " active: \n";
// print out connection. // print out connection.
out += "Connected TO : " + PeerId() + "\n"; out += "Connected TO : " + PeerId().toStdString() + "\n";
// print out cipher. // print out cipher.
rs_sprintf_append(out, "\t\tSSL Cipher:%s", SSL_get_cipher(ssl_connection)); rs_sprintf_append(out, "\t\tSSL Cipher:%s", SSL_get_cipher(ssl_connection));
rs_sprintf_append(out, " (%d:%d)", SSL_get_cipher_bits(ssl_connection, &alg), alg); rs_sprintf_append(out, " (%d:%d)", SSL_get_cipher_bits(ssl_connection, &alg), alg);
@ -551,7 +552,7 @@ int pqissl::Delay_Connection()
#ifdef PQISSL_LOG_DEBUG #ifdef PQISSL_LOG_DEBUG
{ {
std::string out; std::string out;
rs_sprintf(out, "pqissl::Delay_Connection() Delaying Connection to %s for %lu seconds", PeerId().c_str(), mConnectDelay); rs_sprintf(out, "pqissl::Delay_Connection() Delaying Connection to %s for %lu seconds", PeerId().toStdString(), mConnectDelay);
rslog(RSL_DEBUG_BASIC, pqisslzone, out); rslog(RSL_DEBUG_BASIC, pqisslzone, out);
} }
#endif #endif
@ -564,7 +565,7 @@ int pqissl::Delay_Connection()
#ifdef PQISSL_LOG_DEBUG #ifdef PQISSL_LOG_DEBUG
{ {
std::string out; std::string out;
rs_sprintf(out, "pqissl::Delay_Connection() Connection to %s starting in %ld seconds", PeerId().c_str(), mConnectTS - time(NULL)); rs_sprintf(out, "pqissl::Delay_Connection() Connection to %s starting in %ld seconds", PeerId().toStdString(), mConnectTS - time(NULL));
rslog(RSL_DEBUG_BASIC, pqisslzone, out); rslog(RSL_DEBUG_BASIC, pqisslzone, out);
} }
#endif #endif
@ -710,10 +711,12 @@ int pqissl::Initiate_Connection()
* will support IPv6 only and not IPv4 */ * will support IPv6 only and not IPv4 */
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
int no = 0; int no = 0;
err = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&no, sizeof(no)); err = rs_setsockopt( osock, IPPROTO_IPV6, IPV6_V6ONLY,
reinterpret_cast<uint8_t*>(&no), sizeof(no) );
#ifdef PQISSL_DEBUG #ifdef PQISSL_DEBUG
if (err) std::cerr << __PRETTY_FUNCTION__ if (err) std::cerr << __PRETTY_FUNCTION__
<< " Error setting IPv6 socket dual stack" << std::endl; << " Error setting IPv6 socket dual stack: "
<< errno << " " << strerror(errno) << std::endl;
else std::cerr << __PRETTY_FUNCTION__ else std::cerr << __PRETTY_FUNCTION__
<< " Setting IPv6 socket dual stack" << std::endl; << " Setting IPv6 socket dual stack" << std::endl;
#endif // PQISSL_DEBUG #endif // PQISSL_DEBUG
@ -1233,25 +1236,19 @@ int pqissl::Extract_Failed_SSL_Certificate()
int pqissl::Authorise_SSL_Connection() int pqissl::Authorise_SSL_Connection()
{ {
#ifdef PQISSL_LOG_DEBUG #ifdef PQISSL_DEBUG
rslog(RSL_DEBUG_BASIC, pqisslzone, std::cerr << __PRETTY_FUNCTION__ << std::endl;
"pqissl::Authorise_SSL_Connection()");
#endif #endif
if (time(NULL) > ssl_connect_timeout) if (time(NULL) > ssl_connect_timeout)
{ {
rslog(RSL_WARNING, pqisslzone, std::cerr << __PRETTY_FUNCTION__ << " Connection timed out reset!"
"pqissl::Authorise_SSL_Connection() Connection Timed Out!"); << std::endl;
/* as sockfd is valid, this should close it all up */
rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()");
reset_locked(); reset_locked();
} }
int err; int err;
if (0 >= (err = SSL_Connection_Complete())) if (0 >= (err = SSL_Connection_Complete())) return err;
{
return err;
}
#ifdef PQISSL_LOG_DEBUG #ifdef PQISSL_LOG_DEBUG
rslog(RSL_DEBUG_BASIC, pqisslzone, rslog(RSL_DEBUG_BASIC, pqisslzone,
@ -1336,36 +1333,54 @@ int pqissl::Authorise_SSL_Connection()
/* This function is public, and callable from pqilistener - so must be mutex protected */ /* This function is public, and callable from pqilistener - so must be mutex protected */
int pqissl::accept(SSL *ssl, int fd, const struct sockaddr_storage &foreign_addr) // initiate incoming connection. int pqissl::accept( SSL *ssl, int fd,
const sockaddr_storage &foreign_addr)
{ {
#ifdef PQISSL_DEBUG #ifdef PQISSL_DEBUG
std::cerr << "pqissl::accept()"; std::cerr << __PRETTY_FUNCTION__ << std::endl;
std::cerr << std::endl;
#endif #endif
RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ RS_STACK_MUTEX(mSslMtx);
return accept_locked(ssl, fd, foreign_addr); return accept_locked(ssl, fd, foreign_addr);
} }
int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &foreign_addr) // initiate incoming connection. int pqissl::accept_locked( SSL *ssl, int fd,
const sockaddr_storage &foreign_addr )
{ {
#ifdef PQISSL_DEBUG
std::cerr << __PRETTY_FUNCTION__ << std::endl;
#endif
uint32_t check_result; uint32_t check_result;
uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST; uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST;
if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL) if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL)
checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST; checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST;
if(rsBanList!=NULL && !rsBanList->isAddressAccepted(foreign_addr,checking_flags,&check_result)) if( rsBanList && !rsBanList->isAddressAccepted( foreign_addr,
checking_flags,
&check_result ) )
{ {
std::cerr << "(SS) refusing incoming SSL connection from blacklisted foreign address " << sockaddr_storage_iptostring(foreign_addr) std::cerr << __PRETTY_FUNCTION__
<< " (SS) refusing incoming SSL connection from blacklisted "
<< "foreign address "
<< sockaddr_storage_iptostring(foreign_addr)
<< ". Reason: " << check_result << "." << std::endl; << ". Reason: " << check_result << "." << std::endl;
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(foreign_addr), "", "", check_result);
RsServer::notify()->AddFeedItem(
RS_FEED_ITEM_SEC_IP_BLACKLISTED,
PeerId().toStdString(),
sockaddr_storage_iptostring(foreign_addr), "", "",
check_result);
reset_locked(); reset_locked();
return -1; return -1;
} }
if (waiting != WAITING_NOT) if (waiting != WAITING_NOT)
{ {
rslog(RSL_WARNING, pqisslzone, "pqissl::accept() Peer: " + PeerId().toStdString() + " - Two connections in progress - Shut 1 down!"); std::cerr << __PRETTY_FUNCTION__ << " Peer: " << PeerId().toStdString()
<< " - Two connections in progress - Shut 1 down!"
<< std::endl;
// outgoing connection in progress. // outgoing connection in progress.
// shut this baby down. // shut this baby down.
@ -1376,70 +1391,51 @@ int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &forei
switch(waiting) switch(waiting)
{ {
case WAITING_SOCK_CONNECT: case WAITING_SOCK_CONNECT:
#ifdef PQISSL_DEBUG
#ifdef PQISSL_LOG_DEBUG std::cerr << __PRETTY_FUNCTION__ << " STATE = Waiting Sock Connect "
rslog(RSL_DEBUG_BASIC, pqisslzone, << "- close the socket" << std::endl;
"pqissl::accept() STATE = Waiting Sock Connect - close the socket");
#endif #endif
break; break;
case WAITING_SSL_CONNECTION: case WAITING_SSL_CONNECTION:
#ifdef PQISSL_DEBUG
#ifdef PQISSL_LOG_DEBUG std::cerr << __PRETTY_FUNCTION__ << " STATE = Waiting SSL "
rslog(RSL_DEBUG_BASIC, pqisslzone, << "Connection - close sockfd + ssl_conn" << std::endl;
"pqissl::accept() STATE = Waiting SSL Connection - close sockfd + ssl_conn");
#endif #endif
break; break;
case WAITING_SSL_AUTHORISE: case WAITING_SSL_AUTHORISE:
#ifdef PQISSL_DEBUG
#ifdef PQISSL_LOG_DEBUG std::cerr << __PRETTY_FUNCTION__ << " STATE = Waiting SSL Authorise"
rslog(RSL_DEBUG_BASIC, pqisslzone, << " - close sockfd + ssl_conn" << std::endl;
"pqissl::accept() STATE = Waiting SSL Authorise - close sockfd + ssl_conn");
#endif #endif
break; break;
case WAITING_FAIL_INTERFACE: case WAITING_FAIL_INTERFACE:
#ifdef PQISSL_DEBUG
#ifdef PQISSL_LOG_DEBUG std::cerr << __PRETTY_FUNCTION__ << " STATE = Failed, ignore?"
rslog(RSL_DEBUG_BASIC, pqisslzone, << std::endl;
"pqissl::accept() STATE = Failed, ignore?");
#endif #endif
break; break;
default: default:
rslog(RSL_ALERT, pqisslzone, std::cerr << __PRETTY_FUNCTION__ << " STATE = Unknown - resetting!"
"pqissl::accept() STATE = Unknown - ignore?"); << std::endl;
rslog(RSL_ALERT, pqisslzone, "pqissl::accept() -> calling reset()");
reset_locked(); reset_locked();
break; break;
} }
//waiting = WAITING_FAIL_INTERFACE;
//return -1;
} }
/* shutdown existing - in all cases use the new one */ /* shutdown existing - in all cases use the new one */
if ((ssl_connection) && (ssl_connection != ssl)) if ((ssl_connection) && (ssl_connection != ssl))
{ {
rslog(RSL_ALERT, pqisslzone, std::cerr << __PRETTY_FUNCTION__
"pqissl::accept() closing Previous/Existing ssl_connection"); << " closing Previous/Existing ssl_connection" << std::endl;
SSL_shutdown(ssl_connection); SSL_shutdown(ssl_connection);
SSL_free (ssl_connection); SSL_free (ssl_connection);
} }
if ((sockfd > -1) && (sockfd != fd)) if ((sockfd > -1) && (sockfd != fd))
{ {
rslog(RSL_ALERT, pqisslzone, std::cerr << __PRETTY_FUNCTION__ << " closing Previous/Existing sockfd"
"pqissl::accept() closing Previous/Existing sockfd"); << std::endl;
net_internal_close(sockfd); net_internal_close(sockfd);
} }
@ -1452,54 +1448,39 @@ int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &forei
/* if we connected - then just writing the same over, /* if we connected - then just writing the same over,
* but if from ssllistener then we need to save the address. * but if from ssllistener then we need to save the address.
*/ */
remote_addr = foreign_addr; sockaddr_storage_copy(foreign_addr, remote_addr);
/* check whether it is on the same LAN */ std::cerr << __PRETTY_FUNCTION__ << " SUCCESSFUL connection to: "
<< PeerId().toStdString() << " remoteaddr: "
<< sockaddr_storage_iptostring(remote_addr) << std::endl;
struct sockaddr_storage localaddr; #ifdef PQISSL_DEBUG
mLinkMgr->getLocalAddress(localaddr);
{
std::string out = "pqissl::accept() SUCCESSFUL connection to: " + PeerId().toStdString();
out += " localaddr: " + sockaddr_storage_iptostring(localaddr);
out += " remoteaddr: " + sockaddr_storage_iptostring(remote_addr);
rslog(RSL_WARNING, pqisslzone, out);
}
// establish the ssl details.
// cipher name.
int err;
#ifdef PQISSL_LOG_DEBUG
{ {
int alg; int alg;
std::string out; std::cerr << __PRETTY_FUNCTION__ << "SSL Cipher: "
rs_sprintf(out, "SSL Cipher:%s\n", SSL_get_cipher(ssl)); << SSL_get_cipher(ssl) << std::endl << "SSL Cipher Bits: "
rs_sprintf_append(out, "SSL Cipher Bits:%d - %d\n", SSL_get_cipher_bits(ssl, &alg), alg); << SSL_get_cipher_bits(ssl, &alg) << " - " << alg
rs_sprintf_append(out, "SSL Cipher Version:%s\n", SSL_get_cipher_version(ssl)); << std::endl;
rslog(RSL_DEBUG_BASIC, pqisslzone, out);
} }
#endif #endif
// make non-blocking / or check..... // make non-blocking / or check.....
int err;
if ((err = net_internal_fcntl_nonblock(sockfd)) < 0) if ((err = net_internal_fcntl_nonblock(sockfd)) < 0)
{ {
rslog(RSL_ALERT, pqisslzone, "Error: Cannot make socket NON-Blocking: "); std::cerr << __PRETTY_FUNCTION__ << "Cannot make socket NON-Blocking "
<< "reset!" << std::endl;
active = false; active = false;
waiting = WAITING_FAIL_INTERFACE; waiting = WAITING_FAIL_INTERFACE; // failed completely.
// failed completely.
rslog(RSL_ALERT, pqisslzone, "pqissl::accept() -> calling reset()");
reset_locked(); reset_locked();
return -1; return -1;
} }
else #ifdef PQISSL_DEBUG
{ else std::cerr << __PRETTY_FUNCTION__ << " Socket made non-nlocking!"
#ifdef PQISSL_LOG_DEBUG << std::endl;
rslog(RSL_DEBUG_BASIC, pqisslzone, "pqissl::accept() Socket Made Non-Blocking!");
#endif #endif
}
// we want to continue listening - incase this socket is crap, and they try again. // we want to continue listening - incase this socket is crap, and they try again.
//stoplistening(); //stoplistening();
@ -1508,15 +1489,16 @@ int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &forei
waiting = WAITING_NOT; waiting = WAITING_NOT;
#ifdef PQISSL_DEBUG #ifdef PQISSL_DEBUG
std::cerr << "pqissl::accept_locked() connection complete - notifying parent"; std::cerr << __PRETTY_FUNCTION__ << "connection complete - notifying parent"
std::cerr << std::endl; << std::endl;
#endif #endif
// Notify the pqiperson.... (Both Connect/Receive) // Notify the pqiperson.... (Both Connect/Receive)
if (parent()) if (parent())
{ {
struct sockaddr_storage addr = remote_addr; // Is the copy necessary?
parent() -> notifyEvent(this, NET_CONNECT_SUCCESS, addr); sockaddr_storage addr; sockaddr_storage_copy(remote_addr, addr);
parent()->notifyEvent(this, NET_CONNECT_SUCCESS, addr);
} }
return 1; return 1;
} }
@ -1612,29 +1594,33 @@ int pqissl::senddata(void *data, int len)
int pqissl::readdata(void *data, int len) int pqissl::readdata(void *data, int len)
{ {
RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ RS_STACK_MUTEX(mSslMtx);
#ifdef PQISSL_DEBUG #ifdef PQISSL_DEBUG
std::cout << "Reading data thread=" << pthread_self() << ", ssl=" << (void*)this << std::endl ; std::cout << "Reading data thread=" << pthread_self() << ", ssl="
<< (void*)this << std::endl;
#endif #endif
// Safety check. Apparently this avoids some SIGSEGV. // Safety check. Apparently this avoids some SIGSEGV.
// if (ssl_connection == NULL) return -1;
if (ssl_connection == NULL)
return -1 ;
// There is a do, because packets can be splitted into multiple ssl buffers // There is a do, because packets can be splitted into multiple ssl buffers
// when they are larger than 16384 bytes. Such packets have to be read in // when they are larger than 16384 bytes. Such packets have to be read in
// multiple slices. // multiple slices.
do do
{ {
int tmppktlen ; int tmppktlen;
#ifdef PQISSL_DEBUG #ifdef PQISSL_DEBUG
std::cerr << "calling SSL_read. len=" << len << ", total_len=" << total_len << std::endl ; std::cerr << "calling SSL_read. len=" << len << ", total_len="
<< total_len << std::endl;
#endif #endif
ERR_clear_error() ; ERR_clear_error();
tmppktlen = SSL_read(ssl_connection,
(void*)( &(((uint8_t*)data)[total_len])),
len-total_len);
tmppktlen = SSL_read(ssl_connection, (void*)( &(((uint8_t*)data)[total_len])), len-total_len) ;
#ifdef PQISSL_DEBUG #ifdef PQISSL_DEBUG
std::cerr << "have read " << tmppktlen << " bytes" << std::endl ; std::cerr << "have read " << tmppktlen << " bytes" << std::endl ;
std::cerr << "data[0] = " std::cerr << "data[0] = "
@ -1649,7 +1635,6 @@ int pqissl::readdata(void *data, int len)
#endif #endif
// Need to catch errors..... // Need to catch errors.....
//
if (tmppktlen <= 0) // probably needs a reset. if (tmppktlen <= 0) // probably needs a reset.
{ {
std::string out; std::string out;

View File

@ -119,12 +119,9 @@ virtual bool bandwidthLimited() { return true ; }
public: public:
/* Completion of the SSL connection, /// initiate incoming connection.
* this is public, so it can be called by
* the listener (should make friends??)
*/
int accept(SSL *ssl, int fd, const struct sockaddr_storage &foreign_addr); int accept(SSL *ssl, int fd, const struct sockaddr_storage &foreign_addr);
void getCryptoParams(RsPeerCryptoParams& params) ; void getCryptoParams(RsPeerCryptoParams& params) ;
bool actAsServer(); bool actAsServer();
@ -140,7 +137,10 @@ protected:
RsMutex mSslMtx; /**** MUTEX protects data and fn below ****/ RsMutex mSslMtx; /**** MUTEX protects data and fn below ****/
virtual int reset_locked(); virtual int reset_locked();
int accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &foreign_addr);
/// initiate incoming connection.
int accept_locked( SSL *ssl, int fd,
const sockaddr_storage& foreign_addr );
// A little bit of information to describe // A little bit of information to describe
// the SSL state, this is needed // the SSL state, this is needed

View File

@ -4,6 +4,7 @@
* 3P/PQI network interface for RetroShare. * 3P/PQI network interface for RetroShare.
* *
* Copyright 2004-2006 by Robert Fernie. * Copyright 2004-2006 by Robert Fernie.
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -106,10 +107,20 @@ int pqissllistenbase::status()
int pqissllistenbase::setuplisten() int pqissllistenbase::setuplisten()
{ {
int err; int err;
if (active) if (active) return -1;
return -1;
lsock = socket(PF_INET6, SOCK_STREAM, 0);
#ifdef IPV6_V6ONLY
int no = 0;
err = rs_setsockopt(lsock, IPPROTO_IPV6, IPV6_V6ONLY,
reinterpret_cast<uint8_t*>(&no), sizeof(no));
if (err) std::cerr << __PRETTY_FUNCTION__
<< ": Error setting IPv6 socket dual stack" << std::endl;
else std::cerr << __PRETTY_FUNCTION__
<< ": Success setting IPv6 socket dual stack" << std::endl;
#endif // IPV6_V6ONLY
lsock = socket(PF_INET, SOCK_STREAM, 0);
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ /********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS // ie UNIX #ifndef WINDOWS_SYS // ie UNIX
if (lsock < 0) if (lsock < 0)
@ -199,10 +210,14 @@ int pqissllistenbase::setuplisten()
#ifdef OPEN_UNIVERSAL_PORT #ifdef OPEN_UNIVERSAL_PORT
struct sockaddr_storage tmpaddr = laddr; struct sockaddr_storage tmpaddr = laddr;
if (!mPeerMgr->isHidden()) sockaddr_storage_zeroip(tmpaddr); if (!mPeerMgr->isHidden())
if (0 != (err = universal_bind(lsock, (struct sockaddr *) &tmpaddr, sizeof(tmpaddr)))) {
tmpaddr.ss_family = PF_INET6;
sockaddr_storage_zeroip(tmpaddr);
}
if (0 != (err = rs_bind(lsock, tmpaddr)))
#else #else
if (0 != (err = universal_bind(lsock, (struct sockaddr *) &laddr, sizeof(laddr)))) if (0 != (err = universal_bind(lsock, laddr)))
#endif #endif
{ {
std::string out = "pqissllistenbase::setuplisten() Cannot Bind to Local Address!\n"; std::string out = "pqissllistenbase::setuplisten() Cannot Bind to Local Address!\n";

View File

@ -250,20 +250,36 @@ int pqissludp::Initiate_Connection()
{ {
std::cerr << "CONVERTING ALL ADDRESSES TO IPV4: TODO make IPV6";
std::cerr << std::endl;
struct sockaddr_in srcaddr; struct sockaddr_in srcaddr;
struct sockaddr_in proxyaddr; struct sockaddr_in proxyaddr;
struct sockaddr_in remoteaddr; struct sockaddr_in remoteaddr;
if ((mConnectSrcAddr.ss_family != AF_INET) || bool nonIpV4 = false;
(mConnectProxyAddr.ss_family != AF_INET) || if(!sockaddr_storage_ipv6_to_ipv4(remote_addr))
(remote_addr.ss_family != AF_INET))
{ {
std::cerr << "Error One Address is not IPv4. aborting"; nonIpV4 = true;
std::cerr << std::endl; std::cerr << __PRETTY_FUNCTION__ << "Error: remote_addr is not "
abort(); << "valid IPv4!" << std::endl;
sockaddr_storage_dump(remote_addr);
}
if(!sockaddr_storage_ipv6_to_ipv4(mConnectSrcAddr))
{
nonIpV4 = true;
std::cerr << __PRETTY_FUNCTION__ << "Error: mConnectSrcAddr is "
<< "not valid IPv4!" << std::endl;
sockaddr_storage_dump(mConnectSrcAddr);
}
if(!sockaddr_storage_ipv6_to_ipv4(mConnectProxyAddr))
{
nonIpV4 = true;
std::cerr << __PRETTY_FUNCTION__ << "Error: mConnectProxyAddr "
<< "is not valid IPv4!" << std::endl;
sockaddr_storage_dump(mConnectProxyAddr);
}
if(!nonIpV4)
{
print_stacktrace();
return -EINVAL;
} }
struct sockaddr_in *rap = (struct sockaddr_in *) &remote_addr; struct sockaddr_in *rap = (struct sockaddr_in *) &remote_addr;

View File

@ -4,6 +4,7 @@
* RetroShare C++ Interface. * RetroShare C++ Interface.
* *
* Copyright 2004-2008 by Robert Fernie. * Copyright 2004-2008 by Robert Fernie.
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -900,68 +901,33 @@ bool p3Peers::setHiddenNode(const RsPeerId &id, const std::string &address, uin
return true; return true;
} }
bool p3Peers::setLocalAddress(const RsPeerId &id, const std::string &addr_str, uint16_t port) bool p3Peers::setLocalAddress(const RsPeerId &id,
const std::string &addr_str, uint16_t port)
{ {
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::setLocalAddress() " << id << std::endl; std::cerr << __PRETTY_FUNCTION__ << " " << id << " " << addr_str << " "
<< port << std::endl;
#endif #endif
if(port < 1024) sockaddr_storage addr;
{ if (sockaddr_storage_inet_pton(addr, addr_str))
std::cerr << "(EE) attempt to use a port that is reserved to the system: " << port << std::endl; if (sockaddr_storage_setport(addr, port))
return false ;
}
struct sockaddr_storage addr;
struct sockaddr_in *addrv4p = (struct sockaddr_in *) &addr;
addrv4p->sin_family = AF_INET;
addrv4p->sin_port = htons(port);
int ret = 1;
/********************************** WINDOWS/UNIX SPECIFIC PART *******************/
#ifndef WINDOWS_SYS
if (ret && (0 != inet_aton(addr_str.c_str(), &(addrv4p->sin_addr))))
#else
addrv4p->sin_addr.s_addr = inet_addr(addr_str.c_str());
if (ret)
#endif
/********************************** WINDOWS/UNIX SPECIFIC PART *******************/
{
return mPeerMgr->setLocalAddress(id, addr); return mPeerMgr->setLocalAddress(id, addr);
}
return false; return false;
} }
bool p3Peers::setExtAddress(const RsPeerId &id, const std::string &addr_str, uint16_t port) bool p3Peers::setExtAddress(const RsPeerId &id,
const std::string &addr_str, uint16_t port)
{ {
#ifdef P3PEERS_DEBUG #ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::setExtAddress() " << id << std::endl; std::cerr << __PRETTY_FUNCTION__ << " " << id << " " << addr_str << " "
<< port << std::endl;
#endif #endif
if(port < 1024)
{
std::cerr << "(EE) attempt to use a port that is reserved to the system: " << port << std::endl;
return false ;
}
sockaddr_storage addr;
// NOTE THIS IS IPV4 FOR NOW. if (sockaddr_storage_inet_pton(addr, addr_str))
struct sockaddr_storage addr; if (sockaddr_storage_setport(addr, port))
struct sockaddr_in *addrv4p = (struct sockaddr_in *) &addr;
addrv4p->sin_family = AF_INET;
addrv4p->sin_port = htons(port);
int ret = 1;
/********************************** WINDOWS/UNIX SPECIFIC PART *******************/
#ifndef WINDOWS_SYS
if (ret && (0 != inet_aton(addr_str.c_str(), &(addrv4p->sin_addr))))
#else
addrv4p->sin_addr.s_addr = inet_addr(addr_str.c_str());
if (ret)
#endif
/********************************** WINDOWS/UNIX SPECIFIC PART *******************/
{
return mPeerMgr->setExtAddress(id, addr); return mPeerMgr->setExtAddress(id, addr);
}
return false; return false;
} }

View File

@ -39,7 +39,9 @@ RsDisc *rsDisc = NULL;
* #define P3DISC_DEBUG 1 * #define P3DISC_DEBUG 1
****/ ****/
static bool populateContactInfo(const peerState &detail, RsDiscContactItem *pkt,bool include_ip_information) static bool populateContactInfo( const peerState &detail,
RsDiscContactItem *pkt,
bool include_ip_information )
{ {
pkt->clear(); pkt->clear();
@ -461,6 +463,7 @@ void p3discovery2::updatePeerAddressList(const RsDiscContactItem *item)
{ {
} }
else if(!mPeerMgr->isHiddenNode(rsPeers->getOwnId())) else if(!mPeerMgr->isHiddenNode(rsPeers->getOwnId()))
{
/* Cyril: we don't store IP addresses if we're a hidden node. /* Cyril: we don't store IP addresses if we're a hidden node.
* Normally they should not be sent to us, except for old peers. */ * Normally they should not be sent to us, except for old peers. */
/* G10h4ck: sending IP information also to hidden nodes has proven very /* G10h4ck: sending IP information also to hidden nodes has proven very
@ -471,13 +474,13 @@ void p3discovery2::updatePeerAddressList(const RsDiscContactItem *item)
* permission matrix. Disabling this instead will make life more * permission matrix. Disabling this instead will make life more
* difficult for average user, that moreover whould have no way to * difficult for average user, that moreover whould have no way to
* revert an hardcoded policy. */ * revert an hardcoded policy. */
{
pqiIpAddrSet addrsFromPeer; pqiIpAddrSet addrsFromPeer;
addrsFromPeer.mLocal.extractFromTlv(item->localAddrList); addrsFromPeer.mLocal.extractFromTlv(item->localAddrList);
addrsFromPeer.mExt.extractFromTlv(item->extAddrList); addrsFromPeer.mExt.extractFromTlv(item->extAddrList);
#ifdef P3DISC_DEBUG #ifdef P3DISC_DEBUG
std::cerr << "Setting address list to peer " << item->sslId << ", to be:" << std::endl ; std::cerr << "Setting address list to peer " << item->sslId
<< ", to be:" << std::endl ;
std::string addrstr; std::string addrstr;
addrsFromPeer.printAddrs(addrstr); addrsFromPeer.printAddrs(addrstr);

View File

@ -50,34 +50,37 @@ virtual bool resetAddress(struct sockaddr_in &local) { return false; }
/*******************************************************/ /*******************************************************/
#include "pqi/pqimonitor.h" #include "pqi/pqimonitor.h"
#include "util/rsnet.h"
#include "util/stacktrace.h"
#include <iostream> #include <iostream>
class rsUdpStack: public UdpStack, public pqiNetListener class rsUdpStack: public UdpStack, public pqiNetListener
{ {
public: public:
rsUdpStack(struct sockaddr_in &local) rsUdpStack(struct sockaddr_in &local) : UdpStack(local) {}
:UdpStack(local) { return; }
rsUdpStack(int testmode, struct sockaddr_in &local) rsUdpStack(int testmode, struct sockaddr_in &local) :
:UdpStack(testmode, local) { return; } UdpStack(testmode, local) {}
/* from pqiNetListener */ /// @see pqiNetListener
virtual bool resetListener(const struct sockaddr_storage &local) virtual bool resetListener(const sockaddr_storage& local)
{ {
//std::cerr << "rsUdpStack::resetListener(" << sockaddr_storage_tostring(local) << ")"; sockaddr_storage temp;
//std::cerr << std::endl; sockaddr_storage_copy(local, temp);
if (local.ss_family != AF_INET) if (!sockaddr_storage_ipv6_to_ipv4(temp))
{ {
std::cerr << "rsUdpStack::resetListener() NOT IPv4 ERROR"; std::cerr << __PRETTY_FUNCTION__ << " Got non IPv4 address ERROR"
std::cerr << std::endl; << std::endl;
abort(); sockaddr_storage_dump(local);
print_stacktrace();
return -EINVAL;
} }
struct sockaddr_in *addr = (struct sockaddr_in *) &local; sockaddr_in *addr = reinterpret_cast<sockaddr_in*>(&temp);
return resetAddress(*addr); return resetAddress(*addr);
} }
}; };
class rsFixedUdpStack: public UdpStack, public pqiNetListener class rsFixedUdpStack: public UdpStack, public pqiNetListener

View File

@ -88,14 +88,26 @@ std::string rs_inet_ntoa(struct in_addr in);
/***************************/ /***************************/
// sockaddr_storage fns. // sockaddr_storage fns.
// Standard bind, on OSX anyway will not accept a longer socklen for IPv4. int rs_bind(int fd, const sockaddr_storage& addr);
// so hidding details behind function.
int universal_bind(int fd, const struct sockaddr *addr, socklen_t socklen);
void sockaddr_storage_clear(struct sockaddr_storage &addr); void sockaddr_storage_clear(struct sockaddr_storage &addr);
// mods. // mods.
bool sockaddr_storage_zeroip(struct sockaddr_storage &addr); 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); bool sockaddr_storage_copyip(struct sockaddr_storage &dst, const struct sockaddr_storage &src);
uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr); uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr);
bool sockaddr_storage_setport(struct sockaddr_storage &addr, uint16_t port); 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_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_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_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_setport(struct sockaddr_storage &addr, const uint16_t port);
bool sockaddr_storage_ipv4_to_ipv6(sockaddr_storage &addr); bool sockaddr_storage_ipv4_to_ipv6(sockaddr_storage &addr);
bool sockaddr_storage_ipv6_to_ipv4(sockaddr_storage &addr);
// comparisons. // comparisons.
bool operator<(const struct sockaddr_storage &a, const struct sockaddr_storage &b); 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_isLoopbackNet(const struct sockaddr_storage &addr);
bool sockaddr_storage_isPrivateNet(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_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 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 */ #endif /* RS_UNIVERSAL_NETWORK_HEADER */

View File

@ -26,6 +26,24 @@
#include <sstream> #include <sstream>
#include <iomanip> #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/rsnet.h"
#include "util/rsstring.h" #include "util/rsstring.h"
@ -90,17 +108,14 @@ bool sockaddr_storage_ipv6_isExternalNet(const struct sockaddr_storage &addr);
/******************************** Socket Fns ***********************************/ /******************************** Socket Fns ***********************************/
// Standard bind, on OSX anyway will not accept a longer socklen for IPv4. // Standard bind, on OSX anyway will not accept a longer socklen for IPv4.
// so hidding details behind function. // 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 #ifdef SS_DEBUG
std::cerr << "universal_bind()"; std::cerr << __PRETTY_FUNCTION__ << std::endl;
std::cerr << std::endl;
#endif #endif
const struct sockaddr_storage *ss_addr = (struct sockaddr_storage *) addr; socklen_t len = 0;
socklen_t len = socklen; switch (addr.ss_family)
switch (ss_addr->ss_family)
{ {
case AF_INET: case AF_INET:
len = sizeof(struct sockaddr_in); len = sizeof(struct sockaddr_in);
@ -110,13 +125,7 @@ int universal_bind(int fd, const struct sockaddr *addr, socklen_t socklen)
break; break;
} }
if (len > socklen) return bind(fd, reinterpret_cast<const struct sockaddr *>(&addr), len);
{
std::cerr << "universal_bind() ERROR len > socklen" << std::endl;
len = socklen;
}
return bind(fd, addr, len);
} }
@ -252,6 +261,58 @@ bool sockaddr_storage_setipv6(struct sockaddr_storage &addr, const sockaddr_in6
return true; 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) 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_in & addr_ipv4 = (sockaddr_in &) addr;
sockaddr_in6 & addr_ipv6 = (sockaddr_in6 &) addr; sockaddr_in6 & addr_ipv6 = (sockaddr_in6 &) addr;
u_int32_t ip = addr_ipv4.sin_addr.s_addr; uint32_t ip = addr_ipv4.sin_addr.s_addr;
u_int16_t port = addr_ipv4.sin_port; uint16_t port = addr_ipv4.sin_port;
sockaddr_storage_clear(addr); sockaddr_storage_clear(addr);
addr_ipv6.sin6_family = AF_INET6; addr_ipv6.sin6_family = AF_INET6;
addr_ipv6.sin6_port = port; addr_ipv6.sin6_port = port;
addr_ipv6.sin6_addr.s6_addr32[3] = ip; addr_ipv6.sin6_addr.s6_addr16[5] = htons(0xffff);
addr_ipv6.sin6_addr.s6_addr16[5] = (u_int16_t) 0xffff; memmove( reinterpret_cast<void*>(&(addr_ipv6.sin6_addr.s6_addr16[6])),
reinterpret_cast<void*>(&ip), 4 );
return true; return true;
} }
return false; 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 **********************************/ /******************************** Comparisions **********************************/
bool operator<(const struct sockaddr_storage &a, const struct sockaddr_storage &b) bool operator<(const struct sockaddr_storage &a, const struct sockaddr_storage &b)
@ -398,12 +497,17 @@ std::string sockaddr_storage_tostring(const struct sockaddr_storage &addr)
switch(addr.ss_family) switch(addr.ss_family)
{ {
case AF_INET: case AF_INET:
case AF_INET6:
output += "="; output += "=";
output += sockaddr_storage_iptostring(addr); output += sockaddr_storage_iptostring(addr);
output += ":"; output += ":";
output += sockaddr_storage_porttostring(addr); output += sockaddr_storage_porttostring(addr);
break; break;
case AF_INET6:
output += "=[";
output += sockaddr_storage_iptostring(addr);
output += "]:";
output += sockaddr_storage_porttostring(addr);
break;
default: default:
break; break;
} }
@ -433,7 +537,7 @@ void sockaddr_storage_dump(const sockaddr_storage & addr, std::string * outputSt
{ {
const sockaddr_in6 * in6 = (const sockaddr_in6 *) & addr; const sockaddr_in6 * in6 = (const sockaddr_in6 *) & addr;
std::string addrStr = "INVALID_IPV6"; std::string addrStr = "INVALID_IPV6";
rs_inet_ntop(addr, addrStr); sockaddr_storage_inet_ntop(addr, addrStr);
output << "addr.ss_family = AF_INET6"; output << "addr.ss_family = AF_INET6";
output << " in6->sin6_addr = "; output << " in6->sin6_addr = ";
output << addrStr; 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); const uint8_t * buf = reinterpret_cast<const uint8_t *>(&addr);
for( uint32_t i = 0; i < sizeof(addr); ++i ) for( uint32_t i = 0; i < sizeof(addr); ++i )
output << std::setw(2) << std::setfill('0') << std::hex << +buf[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; break;
default: default:
output = "AF_INVALID"; output = "AF_INVALID";
std::cerr << __PRETTY_FUNCTION__ << " Got invalid address!"
<< std::endl;
sockaddr_storage_dump(addr);
print_stacktrace();
break; break;
} }
return output; return output;
@ -495,6 +604,9 @@ std::string sockaddr_storage_iptostring(const struct sockaddr_storage &addr)
break; break;
default: default:
output = "INVALID_IP"; output = "INVALID_IP";
std::cerr << __PRETTY_FUNCTION__ << " Got invalid IP:" << std::endl;
sockaddr_storage_dump(addr);
print_stacktrace();
break; break;
} }
return output; return output;
@ -619,9 +731,7 @@ bool sockaddr_storage_isLinkLocalNet(const struct sockaddr_storage &addr)
case AF_INET: case AF_INET:
return isLinkLocalNet(&(to_const_ipv4_ptr(addr)->sin_addr)); return isLinkLocalNet(&(to_const_ipv4_ptr(addr)->sin_addr));
case AF_INET6: case AF_INET6:
std::cerr << __PRETTY_FUNCTION__ << " for AF_INET6 not implemented" return sockaddr_storage_ipv6_isLinkLocalNet(addr);
<< std::endl;
break;
default: default:
#ifdef SS_DEBUG #ifdef SS_DEBUG
std::cerr << __PRETTY_FUNCTION__ <<" INVALID Family:" << std::endl; std::cerr << __PRETTY_FUNCTION__ <<" INVALID Family:" << std::endl;
@ -633,6 +743,16 @@ bool sockaddr_storage_isLinkLocalNet(const struct sockaddr_storage &addr)
return false; 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) 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 ***********************************/ /******************************** 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) bool sockaddr_storage_ipv4_zeroip(struct sockaddr_storage &addr)
{ {
#ifdef SS_DEBUG #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 sockaddr_storage_ipv6_iptostring(const struct sockaddr_storage & addr)
{ {
std::string addrStr; std::string addrStr;
rs_inet_ntop(addr, addrStr); sockaddr_storage_inet_ntop(addr, addrStr);
return 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 const sockaddr_in6& addr6 = reinterpret_cast<const sockaddr_in6&>(addr);
std::cerr << "sockaddr_storage_ipv6_isnull() TODO";
std::cerr << std::endl;
#endif
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 return !sockaddr_storage_ipv6_isnull(addr);
std::cerr << "sockaddr_storage_ipv6_isValidNet() TODO";
std::cerr << std::endl;
#endif
return false;
} }
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 #ifdef SS_DEBUG
std::cerr << "sockaddr_storage_ipv6_isLoopbackNet() TODO"; std::cerr << __PRETTY_FUNCTION__ << " " << sockaddr_storage_tostring(addr)
std::cerr << std::endl; << " " << isLoopBack << std::endl;
#endif #endif
return false; return isLoopBack;
} }
bool sockaddr_storage_ipv6_isPrivateNet(const struct sockaddr_storage &/*addr*/) bool sockaddr_storage_ipv6_isPrivateNet(const struct sockaddr_storage &/*addr*/)
{ {
#ifdef SS_DEBUG /* It is unlikely that we end up connecting to an IPv6 address behind NAT
std::cerr << "sockaddr_storage_ipv6_isPrivateNet() TODO"; * W.R.T. RS it is probably better to consider all IPv6 as internal/local
std::cerr << std::endl; * addresses as direct connection should be always possible. */
#endif
return false; return true;
} }
bool sockaddr_storage_ipv6_isExternalNet(const struct sockaddr_storage &/*addr*/) bool sockaddr_storage_ipv6_isExternalNet(const struct sockaddr_storage &/*addr*/)
{ {
#ifdef SS_DEBUG /* It is unlikely that we end up connecting to an IPv6 address behind NAT
std::cerr << "sockaddr_storage_ipv6_isExternalNet() TODO"; * W.R.T. RS it is probably better to consider all IPv6 as internal/local
std::cerr << std::endl; * addresses as direct connection should be always possible. */
#endif
return false; return false;
} }
#ifdef WINDOWS_SYS bool sockaddr_storage_inet_ntop (const sockaddr_storage &addr, std::string &dst)
#include <cstdlib>
#include <Winsock2.h>
#endif
bool rs_inet_ntop (const sockaddr_storage &addr, std::string &dst)
{ {
bool success = false; bool success = false;
char ipStr[255]; char ipStr[255];
@ -1098,3 +1259,15 @@ bool rs_inet_ntop (const sockaddr_storage &addr, std::string &dst)
dst = ipStr; dst = ipStr;
return success; 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

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