rebased patch 0007-Substitute-getpreferredinterface-flawed-logic-with-s.patch to new IPv6 branch

git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.6-IPv6-2@8239 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2015-05-14 12:58:54 +00:00
parent 82822fa283
commit bfa14152d7
5 changed files with 31 additions and 484 deletions

View file

@ -925,7 +925,9 @@ bool p3NetMgrIMPL::checkNetAddress()
} }
else else
{ {
validAddr = getPreferredInterface(mLocalAddr, prefAddr); std::list<struct sockaddr_storage> addrs;
validAddr = getLocalAddresses(addrs);
if (validAddr) prefAddr = addrs.front();
} }

View file

@ -38,7 +38,8 @@
#include "util/rsdebug.h" #include "util/rsdebug.h"
#include "util/rsstring.h" #include "util/rsstring.h"
#include <iomanip> #include "util/rsnet.h"
static const int pqinetzone = 96184; static const int pqinetzone = 96184;
/***** /*****
@ -144,78 +145,6 @@ std::string socket_errorType(int err)
return std::string("UNKNOWN ERROR CODE - ASK RS-DEVS TO ADD IT!"); return std::string("UNKNOWN ERROR CODE - ASK RS-DEVS TO ADD IT!");
} }
#include <net/if.h>
#include <sys/ioctl.h>
bool getLocalInterfaces_ipv4(struct in_addr &/*routeAddr*/, std::list<struct in_addr> &addrs)
{
int sock = 0;
struct ifreq ifreq;
struct if_nameindex *iflist = if_nameindex();
struct if_nameindex *ifptr = iflist;
//need a socket for ioctl()
if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
pqioutput(PQL_ALERT, pqinetzone,
"Cannot Determine Local Addresses!");
return false;
}
if (!ifptr)
{
pqioutput(PQL_ALERT, pqinetzone,
"getLocalInterfaces(): ERROR if_nameindex == NULL");
return false;
}
// loop through the interfaces.
for(; ifptr->if_index != 0; ++ifptr)
{
//copy in the interface name to look up address of
strncpy(ifreq.ifr_name, ifptr->if_name, IF_NAMESIZE);
if(ioctl(sock, SIOCGIFADDR, &ifreq) != 0)
{
std::string out;
rs_sprintf(out, "Cannot Determine Address for Iface: %s", ifptr -> if_name);
pqioutput(PQL_DEBUG_BASIC, pqinetzone, out);
}
else
{
struct sockaddr_in *aptr =
(struct sockaddr_in *) &ifreq.ifr_addr;
std::string astr =rs_inet_ntoa(aptr -> sin_addr);
std::string out;
rs_sprintf(out, "Iface: %s\n Address: %s", ifptr -> if_name, astr.c_str());
pqioutput(PQL_DEBUG_BASIC, pqinetzone, out);
// Now check wether the interface is up and running. If not, we don't use it!!
//
if(ioctl(sock,SIOCGIFFLAGS,&ifreq) != 0)
{
std::cerr << "Could not get flags from interface " << ifptr -> if_name << std::endl ;
continue ;
}
#ifdef NET_DEBUG
std::cout << out.str() ;
std::cout << "flags = " << ifreq.ifr_flags << std::endl ;
#endif
if((ifreq.ifr_flags & IFF_UP) == 0) continue ;
if((ifreq.ifr_flags & IFF_RUNNING) == 0) continue ;
addrs.push_back(aptr->sin_addr);
}
}
// free socket -> or else run out of fds.
close(sock);
if_freenameindex(iflist);
return (addrs.size() > 0);
}
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ /********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#else #else
@ -434,396 +363,32 @@ in_addr_t inet_network(const char *inet_name)
#endif #endif
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ /********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#include <iostream>
#include <sys/types.h>
#include <ifaddrs.h>
#include <net/if.h>
// This returns in Net Byte Order. bool getLocalAddresses(std::list<struct sockaddr_storage> & addrs)
// NB: Linux man page claims it is in Host Byte order, but
// this is blatantly wrong!..... (for Debian anyway)
// Making this consistent with the Actual behavior (rather than documented).
in_addr_t pqi_inet_netof(struct in_addr addr)
{ {
// decide if A class address. struct ifaddrs *ifsaddrs, *ifa;
unsigned long haddr = ntohl(addr.s_addr); if(getifaddrs(&ifsaddrs) != 0) exit(1);
unsigned long abit = haddr & 0xff000000UL;
unsigned long bbit = haddr & 0xffff0000UL;
unsigned long cbit = haddr & 0xffffff00UL;
#ifdef NET_DEBUG addrs.clear();
std::cerr << "inet_netof(" << rs_inet_ntoa(addr) << ") "; for ( ifa = ifsaddrs; ifa; ifa = ifa->ifa_next )
#endif if ( (ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_LOOPBACK) )
if (!((haddr >> 31) | 0x0UL)) // MSB = 0
{
#ifdef NET_DEBUG
std::cerr << " Type A " << std::endl;
std::cerr << "\tShifted(31): " << (haddr >> 31);
std::cerr << " Xord(0x0UL): " <<
!((haddr >> 31) | 0x0UL) << std::endl;
#endif
return htonl(abit);
}
else if (!((haddr >> 30) ^ 0x2UL)) // 2MSBs = 10
{
#ifdef NET_DEBUG
std::cerr << " Type B " << std::endl;
std::cerr << "\tShifted(30): " << (haddr >> 30);
std::cerr << " Xord(0x2UL): " <<
!((haddr >> 30) | 0x2UL) << std::endl;
#endif
return htonl(bbit);
}
else if (!((haddr >> 29) ^ 0x6UL)) // 3MSBs = 110
{
#ifdef NET_DEBUG
std::cerr << " Type C " << std::endl;
std::cerr << "\tShifted(29): " << (haddr >> 29);
std::cerr << " Xord(0x6UL): " <<
!((haddr >> 29) | 0x6UL) << std::endl;
#endif
return htonl(cbit);
}
else if (!((haddr >> 28) ^ 0xeUL)) // 4MSBs = 1110
{
#ifdef NET_DEBUG
std::cerr << " Type Multicast " << std::endl;
std::cerr << "\tShifted(28): " << (haddr >> 28);
std::cerr << " Xord(0xeUL): " <<
!((haddr >> 29) | 0xeUL) << std::endl;
#endif
return addr.s_addr; // return full address.
}
else if (!((haddr >> 27) ^ 0x1eUL)) // 5MSBs = 11110
{
#ifdef NET_DEBUG
std::cerr << " Type Reserved " << std::endl;
std::cerr << "\tShifted(27): " << (haddr >> 27);
std::cerr << " Xord(0x1eUL): " <<
!((haddr >> 27) | 0x1eUL) << std::endl;
#endif
return addr.s_addr; // return full address.
}
return htonl(abit);
}
int sockaddr_cmp(struct sockaddr_in &addr1, struct sockaddr_in &addr2 )
{
if (addr1.sin_family != addr2.sin_family)
return addr1.sin_family - addr2.sin_family;
if (addr1.sin_addr.s_addr != addr2.sin_addr.s_addr)
return (addr1.sin_addr.s_addr - addr2.sin_addr.s_addr);
if (addr1.sin_port != addr2.sin_port)
return (addr1.sin_port - addr2.sin_port);
return 0;
}
int inaddr_cmp(struct sockaddr_in addr1, struct sockaddr_in addr2 )
{
#ifdef NET_DEBUG
std::string out;
rs_sprintf(out, "inaddr_cmp(%s-%lu,%s-%lu)", rs_inet_ntoa(addr1.sin_addr).c_str(), addr1.sin_addr.s_addr, rs_inet_ntoa(addr2.sin_addr).c_str(), addr2.sin_addr.s_addr);
pqioutput(PQL_DEBUG_BASIC, pqinetzone, out);
#endif
if (addr1.sin_addr.s_addr == addr2.sin_addr.s_addr)
{
return 0;
}
if (addr1.sin_addr.s_addr < addr2.sin_addr.s_addr)
return -1;
return 1;
}
int inaddr_cmp(struct sockaddr_in addr1, unsigned long addr2)
{
#ifdef NET_DEBUG
struct in_addr inaddr_tmp;
inaddr_tmp.s_addr = addr2;
std::string out;
rs_sprintf(out, "inaddr_cmp2(%s vs %s /or/ %10x vs %10x)", rs_inet_ntoa(addr1.sin_addr).c_str(), rs_inet_ntoa(inaddr_tmp).c_str(), addr1.sin_addr.s_addr, addr2);
pqioutput(PQL_DEBUG_BASIC, pqinetzone, out);
#endif
if (addr1.sin_addr.s_addr == addr2)
{
return 0;
}
if (addr1.sin_addr.s_addr < addr2)
return -1;
return 1;
}
bool getPreferredInterface_ipv4(in_addr &routeAddr, struct in_addr &prefAddr) // returns best addr.
{
std::list<struct in_addr> addrs;
std::list<struct in_addr>::iterator it;
struct in_addr addr_zero, addr_loop, addr_priv, addr_ext;
#ifdef NET_DEBUG
struct in_addr addr;
#endif
bool found_zero = false;
bool found_loopback = false;
bool found_priv = false;
bool found_ext = false;
if (!getLocalInterfaces_ipv4(routeAddr, addrs))
{
return false;
}
memset(&addr_zero, 0, sizeof(addr_zero));
memset(&addr_loop, 0, sizeof(addr_loop));
memset(&addr_priv, 0, sizeof(addr_priv));
memset(&addr_ext, 0, sizeof(addr_ext));
#ifdef NET_DEBUG
memset(&addr, 0, sizeof(addr));
#endif
// find the first of each of these.
// if ext - take first.
// if no ext -> first priv
// if no priv -> first loopback.
#ifdef NET_DEBUG
std::cerr << "getPreferredInterface() " << addrs.size() << " interfaces." << std::endl;
#endif
for(it = addrs.begin(); it != addrs.end(); ++it)
{
struct in_addr addr = *it;
#ifdef NET_DEBUG
std::cerr << "Examining addr: " << rs_inet_ntoa(addr);
std::cerr << " => " << (uint32_t) addr.s_addr << std::endl ;
#endif
// for windows silliness (returning 0.0.0.0 as valid addr!).
if (addr.s_addr == 0)
{ {
if (!found_zero) sockaddr_storage * tmp = new sockaddr_storage;
{ if (sockaddr_storage_copyip(* tmp, * (const struct sockaddr_storage *) ifa->ifa_addr))
#ifdef NET_DEBUG addrs.push_back(*tmp);
std::cerr << "\tFound Zero Address" << std::endl ; else delete tmp;
#endif
found_zero = true;
addr_zero = addr;
}
} }
else if (isLoopbackNet(&addr))
{
if (!found_loopback)
{
#ifdef NET_DEBUG
std::cerr << "\tFound Loopback Address" << std::endl ;
#endif
found_loopback = true; freeifaddrs(ifsaddrs);
addr_loop = addr;
}
}
else if (isPrivateNet(&addr))
{
if (!found_priv)
{
#ifdef NET_DEBUG
std::cerr << "\tFound Private Address" << std::endl ;
#endif
found_priv = true; return (!addrs.empty());
addr_priv = addr;
}
}
else
{
if (!found_ext)
{
#ifdef NET_DEBUG
std::cerr << "\tFound Other Address (Ext?) " << std::endl ;
#endif
found_ext = true;
addr_ext = addr;
}
}
}
if(found_ext) // external address is best.
{
prefAddr = addr_ext;
return true;
}
if (found_priv)
{
prefAddr = addr_priv;
return true;
}
// next bit can happen under windows,
// a general address is still
// preferable to a loopback device.
if (found_zero)
{
prefAddr = addr_zero;
return true;
}
if (found_loopback)
{
prefAddr = addr_loop;
return true;
}
// shound be 255.255.255.255 (error).
prefAddr.s_addr = 0xffffffff;
return false;
} }
bool getPreferredInterface(const struct sockaddr_storage & existAddr, struct sockaddr_storage & prefAddr)
{
struct in_addr existing_addr;
struct in_addr pref_addr;
{
struct sockaddr_in *eaddr = (sockaddr_in *) &existAddr;
if (eaddr->sin_family != AF_INET)
{
std::cerr << "getPreferredInterface() ERROR only valid for IPv4 for now";
return false; // TODO:IPV6
}
existing_addr = eaddr->sin_addr;
}
if (getPreferredInterface_ipv4(existing_addr, pref_addr))
{
/* store into prefAddr */
sockaddr_storage_clear(prefAddr);
struct sockaddr_in *addr = (sockaddr_in *) &prefAddr;
addr->sin_family = AF_INET;
addr->sin_addr = pref_addr;
addr->sin_port = htons(0);
return true;
}
return false;
}
bool getLocalInterfaces(struct sockaddr_storage &existAddr, std::list<struct sockaddr_storage> &addrs)
{
struct in_addr existing_addr;
std::list<struct in_addr> local_addrs;
{
struct sockaddr_in *eaddr = (sockaddr_in *) &existAddr;
if (eaddr->sin_family != AF_INET)
{
std::cerr << "getLocalInterfaces() ERROR only valid for IPv4 for now";
return false; // TODO:IPV6
}
existing_addr = eaddr->sin_addr;
}
if (getLocalInterfaces_ipv4(existing_addr, local_addrs))
{
std::list<struct in_addr>::iterator it;
for(it = local_addrs.begin(); it != local_addrs.end(); ++it)
{
/* store into prefAddr */
sockaddr_storage localAddr;
sockaddr_storage_clear(localAddr);
struct sockaddr_in *addr = (sockaddr_in *) &localAddr;
addr->sin_family = AF_INET;
addr->sin_addr = *it;
addr->sin_port = htons(0);
addrs.push_back(localAddr);
}
return true;
}
return false;
}
/* This just might be portable!!! will see!!!
* Unfortunately this is usable on winXP+, determined by: (_WIN32_WINNT >= 0x0501)
* but not older platforms.... which must use gethostbyname.
*
* include it for now.....
*/
bool LookupDNSAddr(std::string name, struct sockaddr_in &addr)
{
#if 1
char service[100];
struct addrinfo hints_st;
struct addrinfo *hints = &hints_st;
struct addrinfo *res;
hints -> ai_flags = 0; // (cygwin don;t like these) AI_ADDRCONFIG | AI_NUMERICSERV;
hints -> ai_family = AF_INET;
hints -> ai_socktype = 0;
hints -> ai_protocol = 0;
hints -> ai_addrlen = 0;
hints -> ai_addr = NULL;
hints -> ai_canonname = NULL;
hints -> ai_next = NULL;
/* get the port number */
sprintf(service, "%d", ntohs(addr.sin_port));
/* set it to IPV4 */
#ifdef NET_DEBUG
std::cerr << "LookupDNSAddr() name: " << name << " service: " << service << std::endl;
#endif
int err = 0;
if (0 != (err = getaddrinfo(name.c_str(), service, hints, &res)))
{
#ifdef NET_DEBUG
std::cerr << "LookupDNSAddr() getaddrinfo failed!" << std::endl;
std::cerr << "Error: " << gai_strerror(err) << std::endl;
#endif
return false;
}
if ((res) && (res->ai_family == AF_INET))
{
addr = *((struct sockaddr_in *) res->ai_addr);
freeaddrinfo(res);
#ifdef NET_DEBUG
std::cerr << "LookupDNSAddr() getaddrinfo found address" << std::endl;
std::cerr << "addr: " << rs_inet_ntoa(addr.sin_addr) << std::endl;
std::cerr << "port: " << ntohs(addr.sin_port) << std::endl;
#endif
return true;
}
#ifdef NET_DEBUG
std::cerr << "getaddrinfo failed - no address" << std::endl;
#endif
#endif
#ifdef NET_DEBUG
//std::cerr << "getaddrinfo disabled" << std::endl;
#endif
return false;
}
/************************************************************* /*************************************************************
* Socket Library Wrapper Functions * Socket Library Wrapper Functions
* to get over the crapness of the windows. * to get over the crapness of the windows.

View file

@ -93,21 +93,11 @@ extern int errno; /* Define extern errno, to duplicate unix behaviour */
#include <list> #include <list>
// Same def - different functions... // Same def - different functions...
void showSocketError(std::string &out); void showSocketError(std::string &out);
std::string socket_errorType(int err); std::string socket_errorType(int err);
int sockaddr_cmp(struct sockaddr_in &addr1, struct sockaddr_in &addr2 ); bool getLocalAddresses(std::list<struct sockaddr_storage> & addrs);
int inaddr_cmp(struct sockaddr_in addr1, struct sockaddr_in addr2 );
int inaddr_cmp(struct sockaddr_in addr1, unsigned long);
bool getPreferredInterface(const struct sockaddr_storage &existAddr, struct sockaddr_storage &prefAddr); // returns best addr.
bool getLocalInterfaces(struct sockaddr_storage &existAddr, std::list<struct sockaddr_storage> &addrs); // returns all possible addrs.
in_addr_t pqi_inet_netof(struct in_addr addr); // our implementation.
bool LookupDNSAddr(std::string name, struct sockaddr_in &addr);
/* universal socket interface */ /* universal socket interface */

View file

@ -81,7 +81,7 @@ std::string rs_inet_ntoa(struct in_addr in);
// 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 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);

View file

@ -29,8 +29,6 @@
#include "util/rsstring.h" #include "util/rsstring.h"
#include "pqi/pqinetwork.h" #include "pqi/pqinetwork.h"
#include "util/stacktrace.h"
/***************************** Internal Helper Fns ******************************/ /***************************** Internal Helper Fns ******************************/
/******************************** Casting **************************************/ /******************************** Casting **************************************/
@ -158,8 +156,7 @@ bool sockaddr_storage_zeroip(struct sockaddr_storage &addr)
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)
{ {
#ifdef SS_DEBUG #ifdef SS_DEBUG
std::cerr << "sockaddr_storage_copyip()"; std::cerr << "sockaddr_storage_copyip()" << std::endl;
std::cerr << std::endl;
#endif #endif
switch(src.ss_family) switch(src.ss_family)
@ -171,8 +168,9 @@ bool sockaddr_storage_copyip(struct sockaddr_storage &dst, const struct sockaddr
return sockaddr_storage_ipv6_copyip(dst, src); return sockaddr_storage_ipv6_copyip(dst, src);
break; break;
default: default:
std::cerr << "sockaddr_storage_copyip() invalid addr.ss_family"; #ifdef SS_DEBUG
std::cerr << std::endl; std::cerr << "sockaddr_storage_copyip() Unknown ss_family: " << src.ss_family << std::endl;
#endif
break; break;
} }
return false; return false;
@ -194,8 +192,7 @@ uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr)
return sockaddr_storage_ipv6_port(addr); return sockaddr_storage_ipv6_port(addr);
break; break;
default: default:
std::cerr << "sockaddr_storage_port() invalid addr.ss_family"; std::cerr << "sockaddr_storage_port() invalid addr.ss_family" << std::endl;
std::cerr << std::endl;
sockaddr_storage_dump(addr); sockaddr_storage_dump(addr);
break; break;
} }
@ -205,8 +202,7 @@ 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)
{ {
#ifdef SS_DEBUG #ifdef SS_DEBUG
std::cerr << "sockaddr_storage_setport()"; std::cerr << "sockaddr_storage_setport()" << std::endl;
std::cerr << std::endl;
#endif #endif
switch(addr.ss_family) switch(addr.ss_family)
@ -218,8 +214,7 @@ bool sockaddr_storage_setport(struct sockaddr_storage &addr, uint16_t port)
return sockaddr_storage_ipv6_setport(addr, port); return sockaddr_storage_ipv6_setport(addr, port);
break; break;
default: default:
std::cerr << "sockaddr_storage_setport() invalid addr.ss_family"; std::cerr << "sockaddr_storage_setport() invalid addr.ss_family" << std::endl;
std::cerr << std::endl;
break; break;
} }
return false; return false;
@ -244,8 +239,7 @@ bool sockaddr_storage_setipv4(struct sockaddr_storage &addr, const sockaddr_in *
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)
{ {
std::cerr << "sockaddr_storage_setipv6()"; std::cerr << "sockaddr_storage_setipv6()" << std::endl;
std::cerr << std::endl;
sockaddr_storage_clear(addr); sockaddr_storage_clear(addr);
struct sockaddr_in6 *ipv6_ptr = to_ipv6_ptr(addr); struct sockaddr_in6 *ipv6_ptr = to_ipv6_ptr(addr);
@ -703,8 +697,7 @@ bool sockaddr_storage_ipv6_zeroip(struct sockaddr_storage &addr)
bool sockaddr_storage_ipv6_copyip(struct sockaddr_storage &dst, const struct sockaddr_storage &src) bool sockaddr_storage_ipv6_copyip(struct sockaddr_storage &dst, const struct sockaddr_storage &src)
{ {
#ifdef SS_DEBUG #ifdef SS_DEBUG
std::cerr << "sockaddr_storage_ipv6_copyip()"; std::cerr << "sockaddr_storage_ipv6_copyip()" << std::endl;
std::cerr << std::endl;
#endif #endif
struct sockaddr_in6 *dst_ptr = to_ipv6_ptr(dst); struct sockaddr_in6 *dst_ptr = to_ipv6_ptr(dst);
@ -923,9 +916,6 @@ void sockaddr_storage_dump(const sockaddr_storage & addr)
std::cerr << output.str() << std::endl; std::cerr << output.str() << std::endl;
} }
/********************************* Net Checks ***********************************/ /********************************* Net Checks ***********************************/
bool sockaddr_storage_ipv4_isnull(const struct sockaddr_storage &addr) bool sockaddr_storage_ipv4_isnull(const struct sockaddr_storage &addr)
{ {