diff --git a/libretroshare/src/dht/p3bitdht_peers.cc b/libretroshare/src/dht/p3bitdht_peers.cc index 0543b91b2..cf2d2af97 100644 --- a/libretroshare/src/dht/p3bitdht_peers.cc +++ b/libretroshare/src/dht/p3bitdht_peers.cc @@ -4,6 +4,7 @@ * BitDht interface for RetroShare. * * Copyright 2009-2010 by Robert Fernie. + * Copyright (C) 2015-2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -184,18 +185,24 @@ bool p3BitDht::dropPeer(const RsPeerId& pid) ********************************* 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); - struct sockaddr_in addrv4; - if (addr.ss_family != AF_INET) + sockaddr_in addrv4; + 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 << std::endl; - abort(); + std::cerr << __PRETTY_FUNCTION__ << " Error: got non IPv4 address!" + << std::endl; + 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. addrv4.sin_family = ap->sin_family; @@ -216,39 +223,30 @@ 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_clear(&addrv4); + sockaddr_in addrv4; + sockaddr_clear(&addrv4); - if (addr.ss_family != AF_INET) - { - if(addr.ss_family != AF_UNSPEC) - { - std::cerr << "p3BitDht::addKnownPeer() Warning! Non IPv4 Address - Cannot handle IPV6 Yet. addr.ss_family=" << addr.ss_family; - std::cerr << std::endl; - } - - if (flags & NETASSIST_KNOWN_PEER_ONLINE) - { - std::cerr << "p3BitDht::addKnownPeer() Non IPv4 Address & ONLINE. Abort()ing."; - std::cerr << std::endl; - abort(); - } - } - else + sockaddr_storage tmpaddr; + sockaddr_storage_copy(addr, tmpaddr); + if( !sockaddr_storage_isnull(addr) && + !sockaddr_storage_ipv6_to_ipv4(tmpaddr) ) { - - // convert. - struct sockaddr_in *ap = (struct sockaddr_in *) &addr; - - addrv4.sin_family = ap->sin_family; - addrv4.sin_addr = ap->sin_addr; - addrv4.sin_port = ap->sin_port; + std::cerr << __PRETTY_FUNCTION__ << " Error: got non IPv4 address!" + << std::endl; + sockaddr_storage_dump(addr); + print_stacktrace(); + return -EINVAL; } - - + // convert. + struct sockaddr_in *ap = (struct sockaddr_in *) &tmpaddr; + addrv4.sin_family = ap->sin_family; + addrv4.sin_addr = ap->sin_addr; + addrv4.sin_port = ap->sin_port; + int p3type = 0; int bdflags = 0; bdId id; @@ -295,7 +293,7 @@ int p3BitDht::addKnownPeer(const RsPeerId &pid, const struct sockaddr_storage &a if (!isOwnId) { - RsStackMutex stack(dhtMtx); /********* LOCKED *********/ + RS_STACK_MUTEX(dhtMtx); DhtPeerDetails *dpd = addInternalPeer_locked(pid, p3type); diff --git a/libretroshare/src/pqi/p3netmgr.cc b/libretroshare/src/pqi/p3netmgr.cc index 7dad79bb2..54b6415cd 100644 --- a/libretroshare/src/pqi/p3netmgr.cc +++ b/libretroshare/src/pqi/p3netmgr.cc @@ -1038,12 +1038,15 @@ bool p3NetMgrIMPL::checkNetAddress() } /* 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) { sockaddr_storage& addr(*it); if( sockaddr_storage_isValidNet(addr) && - !sockaddr_storage_isLoopbackNet(addr) ) + !sockaddr_storage_isLoopbackNet(addr) && + !sockaddr_storage_ipv6_isLinkLocalNet(addr) ) { prefAddr = addr; validAddr = true; diff --git a/libretroshare/src/pqi/p3peermgr.cc b/libretroshare/src/pqi/p3peermgr.cc index 9862838aa..f275170d6 100644 --- a/libretroshare/src/pqi/p3peermgr.cc +++ b/libretroshare/src/pqi/p3peermgr.cc @@ -4,6 +4,7 @@ * 3P/PQI network interface for RetroShare. * * Copyright 2007-2011 by Robert Fernie. + * Copyright (C) 2015-2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,6 +24,9 @@ * */ +#include // for std::vector +#include // for std::random_shuffle + #include "rsserver/p3face.h" #include "util/rsnet.h" #include "pqi/authgpg.h" @@ -32,6 +36,7 @@ #include "pqi/p3linkmgr.h" #include "pqi/p3netmgr.h" #include "pqi/p3historymgr.h" +#include "pqi/pqinetwork.h" // for getLocalAddresses //#include "pqi/p3dhtmgr.h" // Only need it for constants. //#include "tcponudp/tou.h" @@ -1227,38 +1232,85 @@ void p3PeerMgrIMPL::printPeerLists(std::ostream &out) * 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 - std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress("; - std::cerr << sockaddr_storage_tostring(localAddr); - std::cerr << ", "; - std::cerr << sockaddr_storage_tostring(extAddr); - std::cerr << ")" << std::endl; + std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress(" + << sockaddr_storage_tostring(localAddr) << ", " + << sockaddr_storage_tostring(extAddr) << ")" << std::endl; #endif - if((rsBanList != NULL) && !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; - return false ; - } + 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; + return false; + } - { - RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + { + RS_STACK_MUTEX(mPeerMtx); - //update ip address list - pqiIpAddress ipAddressTimed; - ipAddressTimed.mAddr = localAddr; - ipAddressTimed.mSeenTime = time(NULL); - ipAddressTimed.mSrc = 0 ; - mOwnState.ipAddrs.updateLocalAddrs(ipAddressTimed); + //update ip address list + pqiIpAddress ipAddressTimed; + ipAddressTimed.mAddr = localAddr; + ipAddressTimed.mSeenTime = time(NULL); + ipAddressTimed.mSrc = 0; + mOwnState.ipAddrs.updateLocalAddrs(ipAddressTimed); - mOwnState.localaddr = localAddr; - } + 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 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; + } - { - RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + { + RS_STACK_MUTEX(mPeerMtx); //update ip address list pqiIpAddress ipAddressTimed; diff --git a/libretroshare/src/pqi/pqinetwork.cc b/libretroshare/src/pqi/pqinetwork.cc index 058e1cd07..8f843cfeb 100644 --- a/libretroshare/src/pqi/pqinetwork.cc +++ b/libretroshare/src/pqi/pqinetwork.cc @@ -41,6 +41,7 @@ #include "util/rsdebug.h" #include "util/rsstring.h" #include "util/rsnet.h" +#include "util/stacktrace.h" static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"}; #define pqinetzone &pqinetzoneInfo @@ -335,15 +336,17 @@ bool getLocalAddresses(std::vector& addrs) struct ifaddrs *ifsaddrs, *ifa; if(getifaddrs(&ifsaddrs) != 0) { - std::cerr << "FATAL ERROR: getLocalAddresses failed!" << std::endl; - return false ; + std::cerr << __PRETTY_FUNCTION__ << " FATAL ERROR: " << errno << " " + << strerror(errno) << std::endl; + print_stacktrace(); + return false; } for ( ifa = ifsaddrs; ifa; ifa = ifa->ifa_next ) if ( ifa->ifa_addr && (ifa->ifa_flags & IFF_UP) ) { sockaddr_storage tmp; sockaddr_storage_clear(tmp); - if (sockaddr_storage_copyip(tmp, * reinterpret_cast(ifa->ifa_addr))) + if (sockaddr_storage_copyip(tmp, *reinterpret_cast(ifa->ifa_addr))) addrs.push_back(tmp); } freeifaddrs(ifsaddrs); diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 74bf6f8d2..d549e9542 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -60,14 +60,15 @@ static struct RsLog::logInfo pqisslzoneInfo = {RsLog::Default, "pqisslzone"}; #define PQISSL_PASSIVE 0x00 #define PQISSL_ACTIVE 0x01 -#define PQISSL_DEBUG 1 -#define PQISSL_LOG_DEBUG 1 - const int PQISSL_LOCAL_FLAG = 0x01; const int PQISSL_REMOTE_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 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) { RS_STACK_MUTEX(mSslMtx); + remote_addr = raddr; return ConnectAttempt(); } @@ -171,12 +173,11 @@ int pqissl::close() // put back on the listening queue. int pqissl::reset() { - RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ - + RS_STACK_MUTEX(mSslMtx); return reset_locked(); } -int pqissl::reset_locked() +int pqissl::reset_locked() { std::string outLog; bool neededReset = false; @@ -355,7 +356,7 @@ int pqissl::status() out += " active: \n"; // print out connection. - out += "Connected TO : " + PeerId() + "\n"; + out += "Connected TO : " + PeerId().toStdString() + "\n"; // print out cipher. 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); @@ -551,7 +552,7 @@ int pqissl::Delay_Connection() #ifdef PQISSL_LOG_DEBUG { 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); } #endif @@ -564,7 +565,7 @@ int pqissl::Delay_Connection() #ifdef PQISSL_LOG_DEBUG { 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); } #endif @@ -710,10 +711,12 @@ int pqissl::Initiate_Connection() * will support IPv6 only and not IPv4 */ #ifdef IPV6_V6ONLY int no = 0; - err = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&no, sizeof(no)); + err = rs_setsockopt( osock, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&no), sizeof(no) ); #ifdef PQISSL_DEBUG 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__ << " Setting IPv6 socket dual stack" << std::endl; #endif // PQISSL_DEBUG @@ -1089,7 +1092,7 @@ int pqissl::Initiate_SSL_Connection() return 1; } -int pqissl::SSL_Connection_Complete() +int pqissl::SSL_Connection_Complete() { #ifdef PQISSL_LOG_DEBUG rslog(RSL_DEBUG_BASIC, pqisslzone, @@ -1231,27 +1234,21 @@ int pqissl::Extract_Failed_SSL_Certificate() -int pqissl::Authorise_SSL_Connection() +int pqissl::Authorise_SSL_Connection() { -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::Authorise_SSL_Connection()"); +#ifdef PQISSL_DEBUG + std::cerr << __PRETTY_FUNCTION__ << std::endl; #endif - if (time(NULL) > ssl_connect_timeout) - { - rslog(RSL_WARNING, pqisslzone, - "pqissl::Authorise_SSL_Connection() Connection Timed Out!"); - /* as sockfd is valid, this should close it all up */ - rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()"); - reset_locked(); + if (time(NULL) > ssl_connect_timeout) + { + std::cerr << __PRETTY_FUNCTION__ << " Connection timed out reset!" + << std::endl; + reset_locked(); } int err; - if (0 >= (err = SSL_Connection_Complete())) - { - return err; - } + if (0 >= (err = SSL_Connection_Complete())) return err; #ifdef PQISSL_LOG_DEBUG 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 */ -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 - std::cerr << "pqissl::accept()"; - std::cerr << std::endl; + std::cerr << __PRETTY_FUNCTION__ << std::endl; #endif - RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ - + RS_STACK_MUTEX(mSslMtx); 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 ) { - uint32_t check_result; - uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST; - if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL) - checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST; +#ifdef PQISSL_DEBUG + std::cerr << __PRETTY_FUNCTION__ << std::endl; +#endif - if(rsBanList!=NULL && !rsBanList->isAddressAccepted(foreign_addr,checking_flags,&check_result)) - { - std::cerr << "(SS) refusing incoming SSL connection from blacklisted foreign address " << sockaddr_storage_iptostring(foreign_addr) - << ". Reason: " << check_result << "." << std::endl; - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(foreign_addr), "", "", check_result); + uint32_t check_result; + uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST; + + if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL) + checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST; + + if( rsBanList && !rsBanList->isAddressAccepted( foreign_addr, + checking_flags, + &check_result ) ) + { + std::cerr << __PRETTY_FUNCTION__ + << " (SS) refusing incoming SSL connection from blacklisted " + << "foreign address " + << sockaddr_storage_iptostring(foreign_addr) + << ". Reason: " << check_result << "." << std::endl; + + RsServer::notify()->AddFeedItem( + RS_FEED_ITEM_SEC_IP_BLACKLISTED, + PeerId().toStdString(), + sockaddr_storage_iptostring(foreign_addr), "", "", + check_result); reset_locked(); - return -1; - } + return -1; + } + 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. // shut this baby down. @@ -1376,70 +1391,51 @@ int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &forei switch(waiting) { - case WAITING_SOCK_CONNECT: - -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::accept() STATE = Waiting Sock Connect - close the socket"); +#ifdef PQISSL_DEBUG + std::cerr << __PRETTY_FUNCTION__ << " STATE = Waiting Sock Connect " + << "- close the socket" << std::endl; #endif - break; - case WAITING_SSL_CONNECTION: - -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::accept() STATE = Waiting SSL Connection - close sockfd + ssl_conn"); +#ifdef PQISSL_DEBUG + std::cerr << __PRETTY_FUNCTION__ << " STATE = Waiting SSL " + << "Connection - close sockfd + ssl_conn" << std::endl; #endif - break; - case WAITING_SSL_AUTHORISE: - -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::accept() STATE = Waiting SSL Authorise - close sockfd + ssl_conn"); +#ifdef PQISSL_DEBUG + std::cerr << __PRETTY_FUNCTION__ << " STATE = Waiting SSL Authorise" + << " - close sockfd + ssl_conn" << std::endl; #endif - break; - case WAITING_FAIL_INTERFACE: - -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::accept() STATE = Failed, ignore?"); +#ifdef PQISSL_DEBUG + std::cerr << __PRETTY_FUNCTION__ << " STATE = Failed, ignore?" + << std::endl; #endif - break; - - default: - rslog(RSL_ALERT, pqisslzone, - "pqissl::accept() STATE = Unknown - ignore?"); - - rslog(RSL_ALERT, pqisslzone, "pqissl::accept() -> calling reset()"); + std::cerr << __PRETTY_FUNCTION__ << " STATE = Unknown - resetting!" + << std::endl; reset_locked(); break; } - - //waiting = WAITING_FAIL_INTERFACE; - //return -1; } /* shutdown existing - in all cases use the new one */ if ((ssl_connection) && (ssl_connection != ssl)) { - rslog(RSL_ALERT, pqisslzone, - "pqissl::accept() closing Previous/Existing ssl_connection"); + std::cerr << __PRETTY_FUNCTION__ + << " closing Previous/Existing ssl_connection" << std::endl; SSL_shutdown(ssl_connection); SSL_free (ssl_connection); } if ((sockfd > -1) && (sockfd != fd)) { - rslog(RSL_ALERT, pqisslzone, - "pqissl::accept() closing Previous/Existing sockfd"); + std::cerr << __PRETTY_FUNCTION__ << " closing Previous/Existing sockfd" + << std::endl; 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, * 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 */ - - struct sockaddr_storage localaddr; - mLinkMgr->getLocalAddress(localaddr); + std::cerr << __PRETTY_FUNCTION__ << " SUCCESSFUL connection to: " + << PeerId().toStdString() << " remoteaddr: " + << sockaddr_storage_iptostring(remote_addr) << std::endl; +#ifdef PQISSL_DEBUG { - 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; - std::string out; - rs_sprintf(out, "SSL Cipher:%s\n", SSL_get_cipher(ssl)); - rs_sprintf_append(out, "SSL Cipher Bits:%d - %d\n", SSL_get_cipher_bits(ssl, &alg), alg); - rs_sprintf_append(out, "SSL Cipher Version:%s\n", SSL_get_cipher_version(ssl)); - rslog(RSL_DEBUG_BASIC, pqisslzone, out); + int alg; + std::cerr << __PRETTY_FUNCTION__ << "SSL Cipher: " + << SSL_get_cipher(ssl) << std::endl << "SSL Cipher Bits: " + << SSL_get_cipher_bits(ssl, &alg) << " - " << alg + << std::endl; } #endif // make non-blocking / or check..... - if ((err = net_internal_fcntl_nonblock(sockfd)) < 0) + int err; + 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; - waiting = WAITING_FAIL_INTERFACE; - // failed completely. - rslog(RSL_ALERT, pqisslzone, "pqissl::accept() -> calling reset()"); + waiting = WAITING_FAIL_INTERFACE; // failed completely. + reset_locked(); return -1; } - else - { -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, "pqissl::accept() Socket Made Non-Blocking!"); +#ifdef PQISSL_DEBUG + else std::cerr << __PRETTY_FUNCTION__ << " Socket made non-nlocking!" + << std::endl; #endif - } // we want to continue listening - incase this socket is crap, and they try again. //stoplistening(); @@ -1508,15 +1489,16 @@ int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &forei waiting = WAITING_NOT; #ifdef PQISSL_DEBUG - std::cerr << "pqissl::accept_locked() connection complete - notifying parent"; - std::cerr << std::endl; + std::cerr << __PRETTY_FUNCTION__ << "connection complete - notifying parent" + << std::endl; #endif // Notify the pqiperson.... (Both Connect/Receive) if (parent()) { - struct sockaddr_storage addr = remote_addr; - parent() -> notifyEvent(this, NET_CONNECT_SUCCESS, addr); + // Is the copy necessary? + sockaddr_storage addr; sockaddr_storage_copy(remote_addr, addr); + parent()->notifyEvent(this, NET_CONNECT_SUCCESS, addr); } return 1; } @@ -1610,31 +1592,35 @@ int pqissl::senddata(void *data, int len) return tmppktlen; } -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 - 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 + // 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 // when they are larger than 16384 bytes. Such packets have to be read in // multiple slices. do { - int tmppktlen ; + int tmppktlen; #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 - ERR_clear_error() ; - - tmppktlen = SSL_read(ssl_connection, (void*)( &(((uint8_t*)data)[total_len])), len-total_len) ; + ERR_clear_error(); + + tmppktlen = SSL_read(ssl_connection, + (void*)( &(((uint8_t*)data)[total_len])), + len-total_len); + #ifdef PQISSL_DEBUG std::cerr << "have read " << tmppktlen << " bytes" << std::endl ; std::cerr << "data[0] = " @@ -1649,7 +1635,6 @@ int pqissl::readdata(void *data, int len) #endif // Need to catch errors..... - // if (tmppktlen <= 0) // probably needs a reset. { std::string out; diff --git a/libretroshare/src/pqi/pqissl.h b/libretroshare/src/pqi/pqissl.h index 5748f5a9c..e14e3928d 100644 --- a/libretroshare/src/pqi/pqissl.h +++ b/libretroshare/src/pqi/pqissl.h @@ -119,12 +119,9 @@ virtual bool bandwidthLimited() { return true ; } public: -/* Completion of the SSL connection, - * this is public, so it can be called by - * the listener (should make friends??) - */ +/// initiate incoming connection. +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) ; bool actAsServer(); @@ -140,7 +137,10 @@ protected: RsMutex mSslMtx; /**** MUTEX protects data and fn below ****/ 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 // the SSL state, this is needed diff --git a/libretroshare/src/pqi/pqissllistener.cc b/libretroshare/src/pqi/pqissllistener.cc index 975791eec..15c754888 100644 --- a/libretroshare/src/pqi/pqissllistener.cc +++ b/libretroshare/src/pqi/pqissllistener.cc @@ -4,6 +4,7 @@ * 3P/PQI network interface for RetroShare. * * Copyright 2004-2006 by Robert Fernie. + * Copyright (C) 2015-2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -103,17 +104,27 @@ int pqissllistenbase::status() return 1; } -int pqissllistenbase::setuplisten() +int pqissllistenbase::setuplisten() { - int err; - if (active) - return -1; + int err; + if (active) 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(&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 ******************/ #ifndef WINDOWS_SYS // ie UNIX - if (lsock < 0) - { + if (lsock < 0) + { pqioutput(PQL_ALERT, pqissllistenzone, "pqissllistenbase::setuplisten() Cannot Open Socket!"); @@ -199,10 +210,14 @@ int pqissllistenbase::setuplisten() #ifdef OPEN_UNIVERSAL_PORT struct sockaddr_storage tmpaddr = laddr; - if (!mPeerMgr->isHidden()) sockaddr_storage_zeroip(tmpaddr); - if (0 != (err = universal_bind(lsock, (struct sockaddr *) &tmpaddr, sizeof(tmpaddr)))) + if (!mPeerMgr->isHidden()) + { + tmpaddr.ss_family = PF_INET6; + sockaddr_storage_zeroip(tmpaddr); + } + if (0 != (err = rs_bind(lsock, tmpaddr))) #else - if (0 != (err = universal_bind(lsock, (struct sockaddr *) &laddr, sizeof(laddr)))) + if (0 != (err = universal_bind(lsock, laddr))) #endif { std::string out = "pqissllistenbase::setuplisten() Cannot Bind to Local Address!\n"; diff --git a/libretroshare/src/pqi/pqissludp.cc b/libretroshare/src/pqi/pqissludp.cc index f14fb82e5..8d7e45fd1 100644 --- a/libretroshare/src/pqi/pqissludp.cc +++ b/libretroshare/src/pqi/pqissludp.cc @@ -250,22 +250,38 @@ 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 proxyaddr; struct sockaddr_in remoteaddr; - - if ((mConnectSrcAddr.ss_family != AF_INET) || - (mConnectProxyAddr.ss_family != AF_INET) || - (remote_addr.ss_family != AF_INET)) + + bool nonIpV4 = false; + if(!sockaddr_storage_ipv6_to_ipv4(remote_addr)) { - std::cerr << "Error One Address is not IPv4. aborting"; - std::cerr << std::endl; - abort(); + nonIpV4 = true; + std::cerr << __PRETTY_FUNCTION__ << "Error: remote_addr is not " + << "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 *pap = (struct sockaddr_in *) &mConnectProxyAddr; struct sockaddr_in *sap = (struct sockaddr_in *) &mConnectSrcAddr; diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index 9292e1562..245a074df 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -4,6 +4,7 @@ * RetroShare C++ Interface. * * Copyright 2004-2008 by Robert Fernie. + * Copyright (C) 2015-2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * 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; } -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 - std::cerr << "p3Peers::setLocalAddress() " << id << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " " << id << " " << addr_str << " " + << port << std::endl; #endif - if(port < 1024) - { - std::cerr << "(EE) attempt to use a port that is reserved to the system: " << port << std::endl; - 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); - } + sockaddr_storage addr; + if (sockaddr_storage_inet_pton(addr, addr_str)) + if (sockaddr_storage_setport(addr, port)) + return mPeerMgr->setLocalAddress(id, addr); 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 - std::cerr << "p3Peers::setExtAddress() " << id << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " " << id << " " << addr_str << " " + << port << std::endl; #endif - if(port < 1024) - { - std::cerr << "(EE) attempt to use a port that is reserved to the system: " << port << std::endl; - return false ; - } - - // NOTE THIS IS IPV4 FOR NOW. - 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->setExtAddress(id, addr); - } + sockaddr_storage addr; + if (sockaddr_storage_inet_pton(addr, addr_str)) + if (sockaddr_storage_setport(addr, port)) + return mPeerMgr->setExtAddress(id, addr); return false; } diff --git a/libretroshare/src/services/p3discovery2.cc b/libretroshare/src/services/p3discovery2.cc index a1ee778a4..3eacf2548 100644 --- a/libretroshare/src/services/p3discovery2.cc +++ b/libretroshare/src/services/p3discovery2.cc @@ -39,7 +39,9 @@ RsDisc *rsDisc = NULL; * #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(); @@ -342,7 +344,7 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) std::cerr << std::endl; #endif peerState detail; - if (mPeerMgr->getOwnNetStatus(detail)) + if (mPeerMgr->getOwnNetStatus(detail)) { RsDiscContactItem *pkt = new RsDiscContactItem(); /* Cyril: we dont send our own IP to an hidden node. It will not use it @@ -461,6 +463,7 @@ void p3discovery2::updatePeerAddressList(const RsDiscContactItem *item) { } else if(!mPeerMgr->isHiddenNode(rsPeers->getOwnId())) + { /* 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. */ /* 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 * difficult for average user, that moreover whould have no way to * revert an hardcoded policy. */ - { - pqiIpAddrSet addrsFromPeer; + pqiIpAddrSet addrsFromPeer; addrsFromPeer.mLocal.extractFromTlv(item->localAddrList); addrsFromPeer.mExt.extractFromTlv(item->extAddrList); #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; addrsFromPeer.printAddrs(addrstr); diff --git a/libretroshare/src/tcponudp/rsudpstack.h b/libretroshare/src/tcponudp/rsudpstack.h index e2dec61b0..ac1408a05 100644 --- a/libretroshare/src/tcponudp/rsudpstack.h +++ b/libretroshare/src/tcponudp/rsudpstack.h @@ -50,34 +50,37 @@ virtual bool resetAddress(struct sockaddr_in &local) { return false; } /*******************************************************/ #include "pqi/pqimonitor.h" +#include "util/rsnet.h" +#include "util/stacktrace.h" + #include class rsUdpStack: public UdpStack, public pqiNetListener { - public: - rsUdpStack(struct sockaddr_in &local) - :UdpStack(local) { return; } +public: + rsUdpStack(struct sockaddr_in &local) : UdpStack(local) {} - rsUdpStack(int testmode, struct sockaddr_in &local) - :UdpStack(testmode, local) { return; } + rsUdpStack(int testmode, struct sockaddr_in &local) : + UdpStack(testmode, local) {} - /* from pqiNetListener */ -virtual bool resetListener(const struct sockaddr_storage &local) + /// @see pqiNetListener + virtual bool resetListener(const sockaddr_storage& local) { - //std::cerr << "rsUdpStack::resetListener(" << sockaddr_storage_tostring(local) << ")"; - //std::cerr << std::endl; + sockaddr_storage temp; + 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 << std::endl; - abort(); + std::cerr << __PRETTY_FUNCTION__ << " Got non IPv4 address ERROR" + << std::endl; + sockaddr_storage_dump(local); + print_stacktrace(); + return -EINVAL; } - struct sockaddr_in *addr = (struct sockaddr_in *) &local; + sockaddr_in *addr = reinterpret_cast(&temp); return resetAddress(*addr); } - }; class rsFixedUdpStack: public UdpStack, public pqiNetListener diff --git a/libretroshare/src/util/rsnet.h b/libretroshare/src/util/rsnet.h index 903ee0a65..1d028e991 100644 --- a/libretroshare/src/util/rsnet.h +++ b/libretroshare/src/util/rsnet.h @@ -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 */ diff --git a/libretroshare/src/util/rsnet_ss.cc b/libretroshare/src/util/rsnet_ss.cc index ad4db25ac..da9ab2dfb 100644 --- a/libretroshare/src/util/rsnet_ss.cc +++ b/libretroshare/src/util/rsnet_ss.cc @@ -26,6 +26,24 @@ #include #include +#include + +#ifdef WINDOWS_SYS +# include +/** 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 +# include +# include +# 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(&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(&(addr_ipv6.sin6_addr.s6_addr16[6])), + reinterpret_cast(&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(&ip), + reinterpret_cast(&(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(&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(src)); + sockaddr_in& ind(reinterpret_cast(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(src)); + sockaddr_in6& ind6(reinterpret_cast(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(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(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 -#include -#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(optval), optlen ); +#else + return setsockopt( sockfd, level, optname, + reinterpret_cast(optval), optlen ); +#endif // WINDOWS_SYS +} diff --git a/libretroshare/src/util/rsthreads.cc b/libretroshare/src/util/rsthreads.cc index 39eca594a..65fcad4b7 100644 --- a/libretroshare/src/util/rsthreads.cc +++ b/libretroshare/src/util/rsthreads.cc @@ -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 ;