|
reSIProcate/rutil
9694
|
Provides a collection of utility functions for manipulating DNS names and IP addresses and discovering details about the local interfaces. More...
#include <DnsUtil.hxx>
Classes | |
| class | Exception |
Static Public Member Functions | |
| static Data | getLocalHostName () |
| static Data | getLocalDomainName () |
| static Data | getLocalIpAddress (const Data &defaultInterface=Data::Empty) |
| Gets the IP address of "the" local interface. | |
| static std::list< std::pair < Data, Data > > | getInterfaces (const Data &matchingInterface=Data::Empty) |
| static Data | inet_ntop (const struct in_addr &addr) |
| Converts from the network format to presentation format. | |
| static Data | inet_ntop (const struct sockaddr &addr) |
| Converts from the network format to presentation format. | |
| static int | inet_pton (const Data &printableIp, struct in_addr &dst) |
| Convert from the presentation format of the IPv4 address to struct in_addr. | |
| static bool | isIpAddress (const Data &ipAddress) |
| static bool | isIpV4Address (const Data &ipAddress) |
| static bool | isIpV6Address (const Data &ipAddress) |
| static const char * | inet_ntop (int af, const void *src, char *dst, size_t size) |
| Converts from the network format to presentation format. | |
| static int | inet_pton (int af, const char *src, void *dst) |
| Converts from the presentation format to network format. | |
| static Data | canonicalizeIpV6Address (const Data &ipV6Address) |
| Converts the printable form of an IPv6 address into consistent format so that string comparisons will do what you expect. | |
| static std::list< Data > | lookupARecords (const Data &host) |
| Used to synchronously query A records - only for test code usage. | |
Provides a collection of utility functions for manipulating DNS names and IP addresses and discovering details about the local interfaces.
Definition at line 28 of file DnsUtil.hxx.
Converts the printable form of an IPv6 address into consistent format so that string comparisons will do what you expect.
For instance, XXXX:0:0:0:YYYY:192.168.2.233 will be converted to XXXX::::YYYY:192.168.2.233. Currently, this is realized by (inet_ntop(inet_pton(input)).
Definition at line 407 of file DnsUtil.cxx.
References resip::Data::Empty, inet_ntop(), inet_pton(), and InfoLog.
Referenced by main().
{
#ifdef USE_IPV6
struct in6_addr dst;
int res = DnsUtil::inet_pton(ipV6Address, dst);
if (res <= 0)
{
// .bwc. Until we supply an isIpV6Address that works, this is not an
// error on anyone's part but our own. Don't log as a warning/error.
InfoLog(<< ipV6Address << " is not a well formed IPV6 address");
// .bwc. We should not assert in this function, because
// DnsUtil::isIpV6Address does not do a full validity check. If we have no
// way of determining whether a V6 addr is valid before making this call,
// this call _needs_ to be safe.
// assert(0);
return Data::Empty;
}
return DnsUtil::inet_ntop(dst);
#else
// assert(0);
return ipV6Address;
#endif
}

| std::list< std::pair< Data, Data > > DnsUtil::getInterfaces | ( | const Data & | matchingInterface = Data::Empty | ) | [static] |
Definition at line 440 of file DnsUtil.cxx.
References DebugLog, resip::Data::Empty, inet_ntop(), and INVALID_SOCKET.
Referenced by getLocalIpAddress(), and main().
{
std::list<std::pair<Data,Data> > results;
#if !defined(WIN32)
struct ifconf ifc;
int s = socket( AF_INET, SOCK_DGRAM, 0 );
assert( s != INVALID_SOCKET ); // can run out of file descs
const int len = 100 * sizeof(struct ifreq);
int maxRet = 40;
char buf[ len ];
ifc.ifc_len = len;
ifc.ifc_buf = buf;
int e = ioctl(s,SIOCGIFCONF,&ifc);
char *ptr = buf;
int tl = ifc.ifc_len;
int count=0;
while ( (tl > 0) && ( count < maxRet) )
{
struct ifreq* ifr = (struct ifreq *)ptr;
count++;
#if defined(__NetBSD__) || defined(__APPLE__)
int si = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
#else
int si = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_ifru);
#endif
tl -= si;
ptr += si;
char* name = ifr->ifr_name;
struct ifreq ifr2;
ifr2 = *ifr;
e = ioctl(s,SIOCGIFADDR,&ifr2);
if ( e == -1 )
{
// no valid address for this interface, skip it
DebugLog (<< "Ignoring interface " << name << " as there is no valid address" );
continue;
}
struct sockaddr a = ifr2.ifr_addr;
Data ip = DnsUtil::inet_ntop(a);
e = ioctl(s,SIOCGIFFLAGS,&ifr2);
if ( e == -1 )
{
// no valid flags for this interface, skip it
DebugLog (<< "Ignoring interface " << name << " as there is no valid flags" );
continue;
}
short flags = ifr2.ifr_flags;
#if 0
// if this does not work on your OS, it is not used yet,
// comment it out and put a note of what OS it does not work for
struct ifmediareq media;
e = ioctl(s,SIOCGIFMEDIA,&media);
int status = media.ifm_status;
int active = media.ifm_active;
DebugLog (<< "Media status=" << hex << status
<< " active=" << hex << active << dec );
#endif
#if 0
// if this does not work on your OS, it is not used yet,
// comment it out and put a note of what OS it does not work for
e = ioctl(s,SIOCGIFPHYS,&ifr2);
int phys= ifr2.ifr_phys;
DebugLog (<< "Phys=" << hex << phys << dec );
#endif
DebugLog (<< "Considering: " << name << " -> " << ip
<< " flags=0x" << hex << flags << dec );
if ( (flags & IFF_UP) == 0 )
{
DebugLog (<< " ignore because: interface is not up");
continue;
}
if ( (flags & IFF_LOOPBACK) != 0 )
{
DebugLog (<< " ignore because: interface is loopback");
continue;
}
if ( (flags & IFF_RUNNING) == 0 )
{
DebugLog (<< " ignore because: interface is not running");
continue;
}
if ( (name[0]<'A') || (name[0]>'z') ) // should never happen
{
DebugLog (<< " ignore because: name looks bogus");
assert(0);
continue;
}
if (matching == Data::Empty || matching == name)
{
DebugLog (<< " using this");
results.push_back(std::make_pair(Data(name), ip));
}
}
close(s);
#else
#if defined(WIN32)
try
{
return WinCompat::getInterfaces(matching);
}
catch(WinCompat::Exception& e)
{
DebugLog (<< " WinCompat::getInterfaces throws " << e.getMessage());
return results;
}
#else
assert(0);
#endif
#endif
return results;
}

| Data DnsUtil::getLocalDomainName | ( | ) | [static] |
Definition at line 170 of file DnsUtil.cxx.
References CritLog, DebugLog, resip::Data::find(), resip::getErrno(), MAXHOSTNAMELEN, resip::Data::npos, strerror(), and resip::Data::substr().
{
Data lhn(getLocalHostName());
size_t dpos = lhn.find(".");
if (dpos != Data::npos)
{
return lhn.substr(dpos+1);
}
else
{
#if defined( __APPLE__ ) || defined( WIN32 ) || defined(__SUNPRO_CC) || defined(__sun__)
throw Exception("Could not find domainname in local hostname",__FILE__,__LINE__);
#else
DebugLog( << "No domain portion in hostname <" << lhn << ">, so using getdomainname");
char buffer[MAXHOSTNAMELEN];
if (int e = getdomainname(buffer,sizeof(buffer)) == -1)
{
if ( e != 0 )
{
int err = getErrno();
CritLog(<< "Couldn't find domainname: " << strerror(err));
throw Exception(strerror(err), __FILE__,__LINE__);
}
}
DebugLog (<< "Found local domain name " << buffer);
return Data(buffer);
#endif
}
}

| Data DnsUtil::getLocalHostName | ( | ) | [static] |
Definition at line 118 of file DnsUtil.cxx.
References CritLog, resip::getErrno(), InfoLog, resip::initNetwork(), MAXHOSTNAMELEN, strerror(), and WSANOTINITIALISED.
{
char buffer[MAXHOSTNAMELEN];
initNetwork();
buffer[0] = '\0';
if (gethostname(buffer,sizeof(buffer)) == -1)
{
int err = getErrno();
switch (err)
{
// !RjS! This makes no sense for non-windows. The
// current hack (see the #define in .hxx) needs
// to be reworked.
case WSANOTINITIALISED:
CritLog( << "could not find local hostname because network not initialized:" << strerror(err) );
break;
default:
CritLog( << "could not find local hostname:" << strerror(err) );
break;
}
throw Exception("could not find local hostname",__FILE__,__LINE__);
}
struct addrinfo* result=0;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags |= AI_CANONNAME;
hints.ai_family |= AF_UNSPEC;
int res = getaddrinfo(buffer, 0, &hints, &result);
if (!res)
{
// !jf! this should really use the Data class
if (strchr(result->ai_canonname, '.') != 0)
{
strncpy(buffer, result->ai_canonname, sizeof(buffer));
}
else
{
InfoLog( << "local hostname does not contain a domain part " << buffer);
}
freeaddrinfo(result);
}
else
{
InfoLog (<< "Couldn't determine local hostname. Error was: " << gai_strerror(res) << ". Returning empty string");
}
return Data(buffer);
}

| Data DnsUtil::getLocalIpAddress | ( | const Data & | defaultInterface = Data::Empty | ) | [static] |
Gets the IP address of "the" local interface.
Note that this will not work on systems with more than one ethernet interface.
Definition at line 202 of file DnsUtil.cxx.
References resip::Data::begin(), getInterfaces(), InfoLog, and WarningLog.
{
Data result;
std::list<std::pair<Data,Data> > ifs = DnsUtil::getInterfaces(myInterface);
if (ifs.empty())
{
WarningLog( << "No interfaces matching " << myInterface << " were found" );
throw Exception("No interfaces matching", __FILE__, __LINE__);
}
else
{
InfoLog (<< "Local IP address for " << myInterface << " is " << ifs.begin()->second);
return ifs.begin()->second;
}
}

| Data DnsUtil::inet_ntop | ( | const struct in_addr & | addr | ) | [static] |
Converts from the network format to presentation format.
That is, it converts from struct in_addr to character representation of the IPv4 address.
Definition at line 220 of file DnsUtil.cxx.
Referenced by canonicalizeIpV6Address(), resip::DnsHostRecord::dump(), resip::DnsAAAARecord::dump(), resip::RRList::encodeRecordItem(), getInterfaces(), inet_ntop(), resip::AresDns::internalInit(), resip::DnsHostRecord::isSameValue(), and resip::DnsAAAARecord::isSameValue().
| Data DnsUtil::inet_ntop | ( | const struct sockaddr & | addr | ) | [static] |
Converts from the network format to presentation format.
Converts from struct sockaddr to character representation of the IPv4 address.
Definition at line 238 of file DnsUtil.cxx.
References inet_ntop().
{
#ifdef USE_IPV6
if (addr.sa_family == AF_INET6)
{
const struct sockaddr_in6* addr6 = reinterpret_cast<const sockaddr_in6*>(&addr);
return DnsUtil::inet_ntop(addr6->sin6_addr);
}
else
#endif
{
const struct sockaddr_in* addr4 = reinterpret_cast<const sockaddr_in*>(&addr);
return DnsUtil::inet_ntop(addr4->sin_addr);
}
}

| const char * DnsUtil::inet_ntop | ( | int | af, |
| const void * | src, | ||
| char * | dst, | ||
| size_t | size | ||
| ) | [static] |
Converts from the network format to presentation format.
| af | the address family (AF_INET, AF_INET6) |
| src | the address of the networking representation to be converted (often of type struct in_addr *) |
| dst | the address where presentation format will be stored |
the size of the dst
Definition at line 613 of file DnsUtil.cxx.
References resip::Data::append(), resip::Data::Borrow, and resip::Data::clear().
{
#ifdef __APPLE__
if(af==AF_INET)
{
// .bwc. inet_ntop4 seems to be implemented with sprintf on OS X.
// This code is about 5-6 times faster. Linux has a well-optimized
// inet_ntop, however.
const UInt8* bytes=(const UInt8*)src;
Data dest(Data::Borrow, dst, sizeof("xxx.xxx.xxx.xxx."));
dest.clear();
dest.append(UInt8ToStr[bytes[0]].data(), UInt8ToStr[bytes[0]].size());
dest.append(UInt8ToStr[bytes[1]].data(), UInt8ToStr[bytes[1]].size());
dest.append(UInt8ToStr[bytes[2]].data(), UInt8ToStr[bytes[2]].size());
dest.append(UInt8ToStr[bytes[3]].data(), UInt8ToStr[bytes[3]].size()-1);
return dst;
}
else
#endif // __APPLE__
{
return ::inet_ntop(af, src, dst, size);
}
}

| int DnsUtil::inet_pton | ( | const Data & | printableIp, |
| struct in_addr & | dst | ||
| ) | [static] |
Convert from the presentation format of the IPv4 address to struct in_addr.
Definition at line 255 of file DnsUtil.cxx.
References resip::Data::c_str().
Referenced by canonicalizeIpV6Address().
{
return DnsUtil::inet_pton(AF_INET, printableIp.c_str(), &dst);
}

| int DnsUtil::inet_pton | ( | int | af, |
| const char * | src, | ||
| void * | dst | ||
| ) | [static] |
Converts from the presentation format to network format.
| af | the address family (AF_INET, AF_INET6) |
| src | the address of the presentation representation to be converted |
| dst | the address where presentation format will be stored (struct in_addr *, or struct in_addr6 *) |
Definition at line 639 of file DnsUtil.cxx.
{
return ::inet_pton(af, src, dst);
}
| bool DnsUtil::isIpAddress | ( | const Data & | ipAddress | ) | [static] |
Definition at line 433 of file DnsUtil.cxx.
{
return isIpV4Address(ipAddress) || isIpV6Address(ipAddress);
}
| bool DnsUtil::isIpV4Address | ( | const Data & | ipAddress | ) | [static] |
Definition at line 270 of file DnsUtil.cxx.
References resip::Data::data(), and resip::Data::size().
Referenced by lookupARecords().
{
// ok, this is fairly monstrous but it works. It is also more than 10 times
// faster than the commented-out code below, in the worst case scenario.
const char* first = ipAddress.data();
const char* end = first + ipAddress.size();
int octets = 0;
while(octets++ < 4)
{
const char* last=first;
// .bwc. I have tried using std::bitset instead of the 0 <= *last <= 9
// check, but it is slower.
while(*last >= '0' && *last <= '9' && last - first <= 3 && last != end)
{
// Skip at most 3 decimals, without going past the end of the buffer.
++last;
}
// last should now point to either a '.', or the end of the buffer.
switch(last-first) // number of decimals in this octet
{
case 2:
if(*first == '0')
{
// Two-decimal octet can't begin with 0...
// ?bwc? Maybe let this slide?
return false;
}
case 1:
// ... but a one-decimal octet can begin with a 0.
break; // x. or xx.
case 3:
// xxx. (could be too large)
// .bwc. I have tried implementing this with a reinterpret_cast
// and a UInt32 comparison (accounting for endianness), and memcmp,
// but both appear to be slower, even when using
// "255.255.255.255" (which maximizes the number of comparisons).
if(*first != '1')
{
if(*first == '2')
{
// Might have overflow if first digit is 2
if(*(first+1)>'5' || (*(first+1)=='5' && *(first+2)>'5'))
{
return false;
}
}
else
{
// First digit greater than 2 means overflow, 0 not allowed.
return false;
}
}
break;
default:
return false;
}
if(octets < 4)
{
if(*last == '.')
{
// Skip over the '.'
++last;
}
else
{
return false;
}
}
first = last; // is now pointing at either the first digit in the next
// octet, or the end of the buffer.
}
return first==end;
// unsigned int p1,p2,p3,p4;
// int count=0;
// int result = sscanf( ipAddress.c_str(),
// "%u.%u.%u.%u%n",
// &p1, &p2, &p3, &p4, &count );
//
// if ( (result == 4) && (p1 <= 255) && (p2 <= 255) && (p3 <= 255) && (p4 <= 255) && (count == int(ipAddress.size())) )
// {
// return true;
// }
// else
// {
// return false;
// }
}

| bool DnsUtil::isIpV6Address | ( | const Data & | ipAddress | ) | [static] |
Definition at line 366 of file DnsUtil.cxx.
References resip::Data::data(), resip::Data::empty(), and resip::Data::size().
Referenced by main().
{
if (ipAddress.empty())
{
return false;
}
// first character must be a hex digit or colon
if (!isxdigit(*ipAddress.data()) &&
*ipAddress.data() != ':')
{
return false;
}
switch (ipAddress.size())
{
case 1:
return false;
case 2:
return (*(ipAddress.data()+1) == ':' ||
*(ipAddress.data()+0) == ':');
case 3:
return (*(ipAddress.data()+2) == ':' ||
*(ipAddress.data()+1) == ':' ||
*(ipAddress.data()+0) == ':');
case 4:
return (*(ipAddress.data()+3) == ':' ||
*(ipAddress.data()+2) == ':' ||
*(ipAddress.data()+1) == ':' ||
*(ipAddress.data()+0) == ':');
default:
return (*(ipAddress.data()+4) == ':' ||
*(ipAddress.data()+3) == ':' ||
*(ipAddress.data()+2) == ':' ||
*(ipAddress.data()+1) == ':' ||
*(ipAddress.data()+0) == ':');
}
}

Used to synchronously query A records - only for test code usage.
Definition at line 41 of file DnsUtil.cxx.
References resip::Data::c_str(), DebugLog, resip::Inserter(), isIpV4Address(), and StackLog.
{
list<Data> names;
if (DnsUtil::isIpV4Address(host))
{
names.push_back(host);
return names;
}
struct hostent* result=0;
int ret=0;
int herrno=0;
#if defined(__linux__)
struct hostent hostbuf;
char buffer[8192];
ret = gethostbyname_r( host.c_str(), &hostbuf, buffer, sizeof(buffer), &result, &herrno);
assert (ret != ERANGE);
#elif defined(__QNX__) || defined(__SUNPRO_CC)
struct hostent hostbuf;
char buffer[8192];
result = gethostbyname_r( host.c_str(), &hostbuf, buffer, sizeof(buffer), &herrno );
#elif defined(__APPLE__)
// gethostbyname in os/x is thread-safe...
// http://developer.apple.com/technotes/tn2002/pdf/tn2053.pdf
result = gethostbyname( host.c_str() );
ret = (result == 0);
#else
assert(0);
return names;
#endif
if (ret != 0 || result == 0)
{
Data msg;
switch (herrno)
{
case HOST_NOT_FOUND:
msg = "host not found: ";
break;
case NO_DATA:
msg = "no data found for: ";
break;
case NO_RECOVERY:
msg = "no recovery lookup up: ";
break;
case TRY_AGAIN:
msg = "try again: ";
break;
}
msg += host;
DebugLog (<< "DNS lookup of " << host << " resulted in " << msg);
throw Exception("no dns resolution:" + msg, __FILE__, __LINE__);
}
else
{
assert(result);
assert(result->h_length == 4);
char str[256];
for (char** pptr = result->h_addr_list; *pptr != 0; pptr++)
{
inet_ntop(result->h_addrtype, (u_int32_t*)(*pptr), str, sizeof(str));
names.push_back(str);
}
StackLog (<< "DNS lookup of " << host << ": canonical name: " << result->h_name
<< " "
<< Inserter(names));
return names;
}
}

1.7.5.1