reSIProcate/rutil  9694
DnsUtil.cxx
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #if !defined(WIN32)
00006 #if defined(__SUNPRO_CC) || defined (__sun__)
00007 #define BSD_COMP /* !rk! needed to enable SIOCGIFCONF */
00008 #endif
00009 #include <sys/types.h>
00010 #include <sys/socket.h>
00011 #include <netinet/in.h>
00012 #include <arpa/inet.h>
00013 #include <sys/ioctl.h>
00014 #include <net/if.h>
00015 #include <errno.h>
00016 #include <netdb.h>
00017 #endif
00018 
00019 #include <stdio.h>
00020 #include <memory>
00021 
00022 #include "rutil/compat.hxx"
00023 #include "rutil/Socket.hxx"
00024 #include "rutil/DnsUtil.hxx"
00025 #include "rutil/Logger.hxx"
00026 #include "rutil/Inserter.hxx"
00027 #include "rutil/WinCompat.hxx"
00028 #include "rutil/WinLeakCheck.hxx"
00029 
00030 #define RESIPROCATE_SUBSYSTEM resip::Subsystem::DNS
00031 
00032 #ifndef MAXHOSTNAMELEN
00033 #define MAXHOSTNAMELEN 256
00034 #endif
00035 
00036 using namespace resip;
00037 using namespace std;
00038 
00039 
00040 list<Data> 
00041 DnsUtil::lookupARecords(const Data& host)
00042 {
00043    list<Data> names;
00044 
00045    if (DnsUtil::isIpV4Address(host))
00046    {
00047       names.push_back(host);
00048       return names;
00049    }
00050 
00051    struct hostent* result=0;
00052    int ret=0;
00053    int herrno=0;
00054 
00055 #if defined(__linux__)
00056    struct hostent hostbuf; 
00057    char buffer[8192];
00058    ret = gethostbyname_r( host.c_str(), &hostbuf, buffer, sizeof(buffer), &result, &herrno);
00059    assert (ret != ERANGE);
00060 #elif defined(__QNX__) || defined(__SUNPRO_CC)
00061    struct hostent hostbuf; 
00062    char buffer[8192];
00063    result = gethostbyname_r( host.c_str(), &hostbuf, buffer, sizeof(buffer), &herrno );
00064 #elif defined(__APPLE__)
00065    // gethostbyname in os/x is thread-safe...
00066    // http://developer.apple.com/technotes/tn2002/pdf/tn2053.pdf
00067    result = gethostbyname( host.c_str() );
00068    ret = (result == 0);
00069 #else
00070    assert(0);
00071    return names;
00072 #endif
00073    
00074    if (ret != 0 || result == 0)
00075    {
00076       Data msg;
00077       switch (herrno)
00078       {
00079          case HOST_NOT_FOUND:
00080             msg = "host not found: ";
00081             break;
00082          case NO_DATA:
00083             msg = "no data found for: ";
00084             break;
00085          case NO_RECOVERY:
00086             msg = "no recovery lookup up: ";
00087             break;
00088          case TRY_AGAIN:
00089             msg = "try again: ";
00090             break;
00091       }
00092       msg += host;
00093 
00094       DebugLog (<< "DNS lookup of " << host << " resulted in " << msg);
00095       throw Exception("no dns resolution:" + msg, __FILE__, __LINE__);
00096    }
00097    else
00098    {
00099       assert(result);
00100       assert(result->h_length == 4);
00101       char str[256];
00102       for (char** pptr = result->h_addr_list; *pptr != 0; pptr++)
00103       {
00104          inet_ntop(result->h_addrtype, (u_int32_t*)(*pptr), str, sizeof(str));
00105          names.push_back(str);
00106       }
00107 
00108       StackLog (<< "DNS lookup of " << host << ": canonical name: " << result->h_name 
00109                 << " "
00110                 << Inserter(names));
00111       
00112       return names;
00113    }
00114 }
00115 
00116 
00117 Data
00118 DnsUtil::getLocalHostName()
00119 {
00120    char buffer[MAXHOSTNAMELEN];
00121    initNetwork();
00122    buffer[0] = '\0';
00123    if (gethostname(buffer,sizeof(buffer)) == -1)
00124    {
00125       int err = getErrno();
00126       switch (err)
00127       {
00128 // !RjS! This makes no sense for non-windows. The
00129 //       current hack (see the #define in .hxx) needs
00130 //       to be reworked.
00131          case WSANOTINITIALISED:
00132             CritLog( << "could not find local hostname because network not initialized:" << strerror(err) );
00133             break;
00134          default:
00135             CritLog( << "could not find local hostname:" << strerror(err) );
00136             break;
00137       }
00138       throw Exception("could not find local hostname",__FILE__,__LINE__);
00139    }
00140 
00141    struct addrinfo* result=0;
00142    struct addrinfo hints;
00143    memset(&hints, 0, sizeof(hints));
00144    hints.ai_flags |= AI_CANONNAME;
00145    hints.ai_family |= AF_UNSPEC;
00146    int res = getaddrinfo(buffer, 0, &hints, &result);
00147    if (!res) 
00148    {
00149       // !jf! this should really use the Data class 
00150       if (strchr(result->ai_canonname, '.') != 0) 
00151       {
00152          strncpy(buffer, result->ai_canonname, sizeof(buffer));
00153       }
00154       else 
00155       {
00156          InfoLog( << "local hostname does not contain a domain part " << buffer);
00157       }
00158       freeaddrinfo(result);
00159    }
00160    else
00161    {
00162       InfoLog (<< "Couldn't determine local hostname. Error was: " << gai_strerror(res) << ". Returning empty string");
00163    }
00164    
00165    return Data(buffer);
00166 }
00167 
00168 
00169 Data
00170 DnsUtil::getLocalDomainName()
00171 {
00172    Data lhn(getLocalHostName());
00173    size_t dpos = lhn.find(".");
00174    if (dpos != Data::npos)
00175    {
00176       return lhn.substr(dpos+1);
00177    }
00178    else
00179    {
00180 #if defined( __APPLE__ ) || defined( WIN32 ) || defined(__SUNPRO_CC) || defined(__sun__)
00181       throw Exception("Could not find domainname in local hostname",__FILE__,__LINE__);
00182 #else
00183       DebugLog( << "No domain portion in hostname <" << lhn << ">, so using getdomainname");
00184       char buffer[MAXHOSTNAMELEN];
00185       if (int e = getdomainname(buffer,sizeof(buffer)) == -1)
00186       {
00187          if ( e != 0 )
00188          {
00189             int err = getErrno();
00190             CritLog(<< "Couldn't find domainname: " << strerror(err));
00191             throw Exception(strerror(err), __FILE__,__LINE__);
00192          }
00193       }
00194       DebugLog (<< "Found local domain name " << buffer);
00195      
00196       return Data(buffer);
00197 #endif
00198    }
00199 }
00200 
00201 Data
00202 DnsUtil::getLocalIpAddress(const Data& myInterface)
00203 {
00204    Data result;
00205    std::list<std::pair<Data,Data> > ifs = DnsUtil::getInterfaces(myInterface);
00206 
00207    if (ifs.empty())
00208    {
00209       WarningLog( << "No interfaces matching "  << myInterface << " were found" );
00210       throw Exception("No interfaces matching", __FILE__, __LINE__);
00211    }
00212    else
00213    {
00214       InfoLog (<< "Local IP address for " << myInterface << " is " << ifs.begin()->second);
00215       return ifs.begin()->second;
00216    }
00217 }
00218 
00219 Data
00220 DnsUtil::inet_ntop(const struct in_addr& addr)
00221 {
00222    char str[256];
00223    inet_ntop(AF_INET, &addr, str, sizeof(str));
00224    return Data(str);
00225 }
00226 
00227 #ifdef USE_IPV6
00228 Data
00229 DnsUtil::inet_ntop(const struct in6_addr& addr)
00230 {
00231    char str[256];
00232    inet_ntop(AF_INET6, &addr, str, sizeof(str));
00233    return Data(str);
00234 }
00235 #endif
00236 
00237 Data
00238 DnsUtil::inet_ntop(const struct sockaddr& addr)
00239 {
00240 #ifdef USE_IPV6
00241    if (addr.sa_family == AF_INET6)
00242    {
00243       const struct sockaddr_in6* addr6 = reinterpret_cast<const sockaddr_in6*>(&addr);
00244       return DnsUtil::inet_ntop(addr6->sin6_addr);
00245    }
00246    else
00247 #endif
00248    {
00249       const struct sockaddr_in* addr4 = reinterpret_cast<const sockaddr_in*>(&addr);
00250       return DnsUtil::inet_ntop(addr4->sin_addr);
00251    }
00252 }
00253 
00254 int
00255 DnsUtil::inet_pton(const Data& printableIp, struct in_addr& dst)
00256 {
00257    return DnsUtil::inet_pton(AF_INET, printableIp.c_str(), &dst);
00258 }
00259 
00260 #ifdef USE_IPV6
00261 int
00262 DnsUtil::inet_pton(const Data& printableIp, struct in6_addr& dst)
00263 {
00264    return DnsUtil::inet_pton(AF_INET6, printableIp.c_str(), &dst);
00265 }
00266 #endif
00267 
00268 
00269 bool
00270 DnsUtil::isIpV4Address(const Data& ipAddress)
00271 {
00272    // ok, this is fairly monstrous but it works. It is also more than 10 times 
00273    // faster than the commented-out code below, in the worst case scenario.
00274 
00275    const char* first = ipAddress.data();
00276    const char* end = first + ipAddress.size();
00277    int octets = 0;
00278    while(octets++ < 4)
00279    {
00280       const char* last=first;
00281 
00282       // .bwc. I have tried using std::bitset instead of the 0 <= *last <= 9
00283       // check, but it is slower.
00284       while(*last >= '0' && *last <= '9' && last - first <= 3 && last != end)
00285       {
00286          // Skip at most 3 decimals, without going past the end of the buffer.
00287          ++last;
00288       }
00289 
00290       // last should now point to either a '.', or the end of the buffer.
00291 
00292       switch(last-first) // number of decimals in this octet
00293       {
00294          case 2:
00295             if(*first == '0')
00296             {
00297                // Two-decimal octet can't begin with 0...
00298                // ?bwc? Maybe let this slide?
00299                return false;
00300             }
00301          case 1:
00302             // ... but a one-decimal octet can begin with a 0.
00303             break; // x. or xx.
00304          case 3:
00305             // xxx. (could be too large)
00306             // .bwc. I have tried implementing this with a reinterpret_cast 
00307             // and a UInt32 comparison (accounting for endianness), and memcmp, 
00308             // but both appear to be slower, even when using 
00309             // "255.255.255.255" (which maximizes the number of comparisons).
00310             if(*first != '1')
00311             {
00312                if(*first == '2')
00313                {
00314                   // Might have overflow if first digit is 2
00315                   if(*(first+1)>'5' || (*(first+1)=='5' && *(first+2)>'5'))
00316                   {
00317                      return false;
00318                   }
00319                }
00320                else
00321                {
00322                   // First digit greater than 2 means overflow, 0 not allowed.
00323                   return false;
00324                }
00325             }
00326             break;
00327          default:
00328             return false;
00329       }
00330 
00331       if(octets < 4)
00332       {
00333          if(*last == '.')
00334          {
00335             // Skip over the '.'
00336             ++last;
00337          }
00338          else
00339          {
00340             return false;
00341          }
00342       }
00343       first = last; // is now pointing at either the first digit in the next
00344                      // octet, or the end of the buffer.
00345    }
00346 
00347    return first==end;
00348 //   unsigned int p1,p2,p3,p4;
00349 //   int count=0;
00350 //   int result = sscanf( ipAddress.c_str(),
00351 //                        "%u.%u.%u.%u%n",
00352 //                        &p1, &p2, &p3, &p4, &count );
00353 //
00354 //   if ( (result == 4) && (p1 <= 255) && (p2 <= 255) && (p3 <= 255) && (p4 <= 255) && (count == int(ipAddress.size())) )
00355 //   {
00356 //      return true;
00357 //   }
00358 //   else
00359 //   {
00360 //      return false;
00361 //   }
00362 }
00363 
00364 // RFC 1884
00365 bool
00366 DnsUtil::isIpV6Address(const Data& ipAddress)
00367 {
00368    if (ipAddress.empty())
00369    {
00370       return false;
00371    }
00372 
00373    // first character must be a hex digit or colon
00374    if (!isxdigit(*ipAddress.data()) &&
00375        *ipAddress.data() != ':')
00376    {
00377       return false;
00378    }
00379 
00380    switch (ipAddress.size())
00381    {
00382       case 1:
00383          return false;
00384       case 2:
00385          return (*(ipAddress.data()+1) == ':' ||
00386                  *(ipAddress.data()+0) == ':');
00387       case 3:
00388          return (*(ipAddress.data()+2) == ':' ||
00389                  *(ipAddress.data()+1) == ':' ||
00390                  *(ipAddress.data()+0) == ':');
00391       case 4:
00392          return (*(ipAddress.data()+3) == ':' ||
00393                  *(ipAddress.data()+2) == ':' ||
00394                  *(ipAddress.data()+1) == ':' ||
00395                  *(ipAddress.data()+0) == ':');
00396       default:
00397 
00398          return (*(ipAddress.data()+4) == ':' ||
00399                  *(ipAddress.data()+3) == ':' ||
00400                  *(ipAddress.data()+2) == ':' ||
00401                  *(ipAddress.data()+1) == ':' ||
00402                  *(ipAddress.data()+0) == ':');
00403    }
00404 }
00405 
00406 Data
00407 DnsUtil::canonicalizeIpV6Address(const Data& ipV6Address)
00408 {
00409 #ifdef USE_IPV6
00410    struct in6_addr dst;
00411    int res = DnsUtil::inet_pton(ipV6Address, dst);
00412    if (res <= 0)
00413    {
00414       // .bwc. Until we supply an isIpV6Address that works, this is not an
00415       // error on anyone's part but our own. Don't log as a warning/error.
00416       InfoLog(<< ipV6Address << " is not a well formed IPV6 address");
00417       // .bwc. We should not assert in this function, because 
00418       // DnsUtil::isIpV6Address does not do a full validity check. If we have no
00419       // way of determining whether a V6 addr is valid before making this call,
00420       // this call _needs_ to be safe.
00421       // assert(0);
00422       return Data::Empty;
00423    }
00424    return DnsUtil::inet_ntop(dst);
00425 #else
00426    // assert(0);
00427 
00428    return ipV6Address;
00429 #endif
00430 }
00431 
00432 bool
00433 DnsUtil::isIpAddress(const Data& ipAddress)
00434 {
00435    return isIpV4Address(ipAddress) || isIpV6Address(ipAddress);
00436 }
00437 
00438 
00439 std::list<std::pair<Data,Data> >
00440 DnsUtil::getInterfaces(const Data& matching)
00441 {
00442    std::list<std::pair<Data,Data> > results;
00443 
00444 #if !defined(WIN32)
00445 
00446    struct ifconf ifc;
00447 
00448    int s = socket( AF_INET, SOCK_DGRAM, 0 );
00449    assert( s != INVALID_SOCKET );       // can run out of file descs
00450    const int len = 100 * sizeof(struct ifreq);
00451    int maxRet = 40;
00452 
00453    char buf[ len ];
00454    ifc.ifc_len = len;
00455    ifc.ifc_buf = buf;
00456 
00457    int e = ioctl(s,SIOCGIFCONF,&ifc);
00458    char *ptr = buf;
00459    int tl = ifc.ifc_len;
00460    int count=0;
00461   
00462    while ( (tl > 0) && ( count < maxRet) )
00463    {
00464       struct ifreq* ifr = (struct ifreq *)ptr;
00465 
00466       count++;
00467 
00468 #if defined(__NetBSD__) || defined(__APPLE__)
00469       int si = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
00470 #else
00471       int si = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_ifru);
00472 #endif
00473       
00474       tl -= si;
00475       ptr += si;
00476 
00477       char* name = ifr->ifr_name;
00478 
00479       struct ifreq ifr2;
00480       ifr2 = *ifr;
00481 
00482       e = ioctl(s,SIOCGIFADDR,&ifr2);
00483       if ( e == -1 )
00484       {
00485          // no valid address for this interface, skip it    
00486          DebugLog (<< "Ignoring interface  " << name << " as there is no valid address" );
00487          continue;
00488       }
00489       struct sockaddr a = ifr2.ifr_addr;
00490       Data ip = DnsUtil::inet_ntop(a);
00491       
00492       e = ioctl(s,SIOCGIFFLAGS,&ifr2);
00493       if ( e == -1 )
00494       {
00495          // no valid flags for this interface, skip it 
00496          DebugLog (<< "Ignoring interface  " << name << " as there is no valid flags" );
00497          continue;
00498       }
00499       short flags = ifr2.ifr_flags;
00500 
00501 #if 0
00502       // if this does not work on your OS, it is not used yet, 
00503       // comment it out and put a note of what OS it does not work for 
00504       struct ifmediareq media; 
00505       e = ioctl(s,SIOCGIFMEDIA,&media);
00506       int status = media.ifm_status;
00507       int active = media.ifm_active;
00508       DebugLog (<< "Media status=" << hex << status 
00509                 << " active=" << hex << active << dec );  
00510 #endif
00511 
00512 #if 0
00513       // if this does not work on your OS, it is not used yet, 
00514       // comment it out and put a note of what OS it does not work for 
00515       e = ioctl(s,SIOCGIFPHYS,&ifr2);
00516       int phys= ifr2.ifr_phys;
00517       DebugLog (<< "Phys=" << hex << phys << dec );  
00518 #endif
00519 
00520       DebugLog (<< "Considering: " << name << " -> " << ip
00521                 << " flags=0x" << hex << flags << dec );
00522    
00523       if (  (flags & IFF_UP) == 0 ) 
00524       {  
00525          DebugLog (<< "  ignore because: interface is not up");
00526          continue;
00527       }
00528 
00529       if (  (flags & IFF_LOOPBACK) != 0 ) 
00530       {
00531          DebugLog (<< "  ignore because: interface is loopback");
00532          continue;
00533       }
00534       
00535       if (  (flags & IFF_RUNNING) == 0 ) 
00536       {
00537          DebugLog (<< "  ignore because: interface is not running");
00538          continue;
00539       }
00540       
00541       if (  (name[0]<'A') || (name[0]>'z') ) // should never happen
00542       {  
00543          DebugLog (<< "  ignore because: name looks bogus");
00544          assert(0);
00545          continue;
00546       }
00547 
00548       if (matching == Data::Empty || matching == name)
00549       {
00550          DebugLog (<< "  using this");
00551          results.push_back(std::make_pair(Data(name), ip));
00552       }
00553    }
00554 
00555    close(s);
00556 #else 
00557 #if defined(WIN32)
00558    try
00559    {
00560       return WinCompat::getInterfaces(matching);
00561    }
00562    catch(WinCompat::Exception& e)
00563    {
00564       DebugLog (<< "  WinCompat::getInterfaces throws " << e.getMessage());
00565       return results;
00566    }
00567 #else
00568    assert(0);
00569 #endif
00570 #endif
00571 
00572    return results;
00573 }
00574 
00575 #ifdef __APPLE__
00576 const Data DnsUtil::UInt8ToStr[]={
00577   "0.",  "1.",  "2.",  "3.",  "4.",  "5.",  "6.",  "7.",
00578   "8.",  "9.", "10.", "11.", "12.", "13.", "14.", "15.",
00579  "16.", "17.", "18.", "19.", "20.", "21.", "22.", "23.",
00580  "24.", "25.", "26.", "27.", "28.", "29.", "30.", "31.",
00581  "32.", "33.", "34.", "35.", "36.", "37.", "38.", "39.",
00582  "40.", "41.", "42.", "43.", "44.", "45.", "46.", "47.",
00583  "48.", "49.", "50.", "51.", "52.", "53.", "54.", "55.",
00584  "56.", "57.", "58.", "59.", "60.", "61.", "62.", "63.",
00585  "64.", "65.", "66.", "67.", "68.", "69.", "70.", "71.",
00586  "72.", "73.", "74.", "75.", "76.", "77.", "78.", "79.",
00587  "80.", "81.", "82.", "83.", "84.", "85.", "86.", "87.",
00588  "88.", "89.", "90.", "91.", "92.", "93.", "94.", "95.",
00589  "96.", "97.", "98.", "99.","100.","101.","102.","103.",
00590 "104.","105.","106.","107.","108.","109.","110.","111.",
00591 "112.","113.","114.","115.","116.","117.","118.","119.",
00592 "120.","121.","122.","123.","124.","125.","126.","127.",
00593 "128.","129.","130.","131.","132.","133.","134.","135.",
00594 "136.","137.","138.","139.","140.","141.","142.","143.",
00595 "144.","145.","146.","147.","148.","149.","150.","151.",
00596 "152.","153.","154.","155.","156.","157.","158.","159.",
00597 "160.","161.","162.","163.","164.","165.","166.","167.",
00598 "168.","169.","170.","171.","172.","173.","174.","175.",
00599 "176.","177.","178.","179.","180.","181.","182.","183.",
00600 "184.","185.","186.","187.","188.","189.","190.","191.",
00601 "192.","193.","194.","195.","196.","197.","198.","199.",
00602 "200.","201.","202.","203.","204.","205.","206.","207.",
00603 "208.","209.","210.","211.","212.","213.","214.","215.",
00604 "216.","217.","218.","219.","220.","221.","222.","223.",
00605 "224.","225.","226.","227.","228.","229.","230.","231.",
00606 "232.","233.","234.","235.","236.","237.","238.","239.",
00607 "240.","241.","242.","243.","244.","245.","246.","247.",
00608 "248.","249.","250.","251.","252.","253.","254.","255."
00609 };
00610 #endif // __APPLE__
00611 
00612 #if !(defined(WIN32) || defined(__CYGWIN__))
00613 const char *DnsUtil::inet_ntop(int af, const void* src, char* dst,
00614                                size_t size)
00615 {
00616 
00617 #ifdef __APPLE__
00618    if(af==AF_INET)
00619    {
00620       // .bwc. inet_ntop4 seems to be implemented with sprintf on OS X.
00621       // This code is about 5-6 times faster. Linux has a well-optimized 
00622       // inet_ntop, however.
00623       const UInt8* bytes=(const UInt8*)src;
00624       Data dest(Data::Borrow, dst, sizeof("xxx.xxx.xxx.xxx."));
00625       dest.clear();
00626       dest.append(UInt8ToStr[bytes[0]].data(), UInt8ToStr[bytes[0]].size());
00627       dest.append(UInt8ToStr[bytes[1]].data(), UInt8ToStr[bytes[1]].size());
00628       dest.append(UInt8ToStr[bytes[2]].data(), UInt8ToStr[bytes[2]].size());
00629       dest.append(UInt8ToStr[bytes[3]].data(), UInt8ToStr[bytes[3]].size()-1);
00630       return dst;
00631    }
00632    else
00633 #endif // __APPLE__
00634    {
00635       return ::inet_ntop(af, src, dst, size);
00636    }
00637 }
00638 
00639 int DnsUtil::inet_pton(int af, const char* src, void* dst)
00640 {
00641    return ::inet_pton(af, src, dst);
00642 }
00643 #else
00644 #define __restrict
00645 
00646 #define  NS_INT16SZ   2
00647 #define  NS_INADDRSZ  4
00648 #define  NS_IN6ADDRSZ 16
00649 
00650 const char* inet_ntop4(const u_char *src, char *dst, size_t size);
00651 #ifdef USE_IPV6
00652 const char * inet_ntop6(const u_char *src, char *dst, size_t size);
00653 #endif
00654 //adapted from freebsd inet_ntop.c(1.12) and inet_pton.c(1.5) for windows(non-compliant snprinf workaround)
00655 /* const char *
00656  * inet_ntop4(src, dst, size)
00657  *      format an IPv4 address, more or less like inet_ntoa()
00658  * return:
00659  *      `dst' (as a const)
00660  * notes:
00661  *      (1) uses no statics
00662  *      (2) takes a u_char* not an in_addr as input
00663  * author:
00664  *      Paul Vixie, 1996.
00665  */
00666 const char *
00667 DnsUtil::inet_ntop(int af, const void * __restrict src, char * __restrict dst,
00668                    size_t size)
00669 {
00670    switch (af) 
00671    {
00672       case AF_INET:
00673          return (inet_ntop4((const u_char *)src, dst, size));
00674 #ifdef USE_IPV6
00675       case AF_INET6:
00676          return (inet_ntop6((const u_char *)src, dst, size));
00677 #endif
00678       default:
00679          errno = EAFNOSUPPORT;
00680          return (NULL);
00681    }
00682    /* NOTREACHED */
00683 }
00684 
00685 
00686 static const char fmt[] = "%u.%u.%u.%u";
00687 const char*
00688 inet_ntop4(const u_char *src, char *dst, size_t size)
00689 {
00690 #ifdef WIN32
00691    if ( _snprintf(dst, size, fmt, src[0], src[1], src[2], src[3]) < 0)
00692 #else
00693    if ( snprintf(dst, size, fmt, src[0], src[1], src[2], src[3]) < 0)
00694 #endif
00695    {
00696       errno = ENOSPC;
00697       dst[size-1] = 0;
00698       return NULL;
00699    }
00700    return (dst);
00701 }
00702 
00703 
00704 #ifdef USE_IPV6
00705 /* const char *
00706  * inet_ntop6(src, dst, size)
00707  *      convert IPv6 binary address into presentation (printable) format
00708  * author:
00709  *      Paul Vixie, 1996.
00710  */
00711 
00712 const char *
00713 inet_ntop6(const u_char *src, char *dst, size_t size)
00714 {
00715    /*
00716     * Note that int32_t and int16_t need only be "at least" large enough
00717     * to contain a value of the specified size.  On some systems, like
00718     * Crays, there is no such thing as an integer variable with 16 bits.
00719     * Keep this in mind if you think this function should have been coded
00720     * to use pointer overlays.  All the world's not a VAX.
00721     */
00722    char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
00723    struct { int base, len; } best, cur;
00724    u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
00725    int i;
00726 
00727    /*
00728     * Preprocess:
00729     *   Copy the input (bytewise) array into a wordwise array.
00730     *   Find the longest run of 0x00's in src[] for :: shorthanding.
00731     */
00732    memset(words, '\0', sizeof words);
00733    for (i = 0; i < NS_IN6ADDRSZ; i++)
00734       words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
00735    best.base = -1;
00736    cur.base = -1;
00737    for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
00738       if (words[i] == 0) {
00739          if (cur.base == -1)
00740             cur.base = i, cur.len = 1;
00741          else
00742             cur.len++;
00743       } else {
00744          if (cur.base != -1) {
00745             if (best.base == -1 || cur.len > best.len)
00746                best = cur;
00747             cur.base = -1;
00748          }
00749       }
00750    }
00751    if (cur.base != -1) {
00752       if (best.base == -1 || cur.len > best.len)
00753          best = cur;
00754    }
00755    if (best.base != -1 && best.len < 2)
00756       best.base = -1;
00757 
00758    /*
00759     * Format the result.
00760     */
00761    tp = tmp;
00762    for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
00763       /* Are we inside the best run of 0x00's? */
00764       if (best.base != -1 && i >= best.base &&
00765           i < (best.base + best.len)) {
00766          if (i == best.base)
00767             *tp++ = ':';
00768          continue;
00769       }
00770       /* Are we following an initial run of 0x00s or any real hex? */
00771       if (i != 0)
00772          *tp++ = ':';
00773       /* Is this address an encapsulated IPv4? */
00774       if (i == 6 && best.base == 0 &&
00775           (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
00776          if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
00777             return (NULL);
00778          tp += strlen(tp);
00779          break;
00780       }
00781       tp += sprintf(tp, "%x", words[i]);
00782    }
00783    /* Was it a trailing run of 0x00's? */
00784    if (best.base != -1 && (best.base + best.len) ==
00785        (NS_IN6ADDRSZ / NS_INT16SZ))
00786       *tp++ = ':';
00787    *tp++ = '\0';
00788 
00789    /*
00790     * Check for overflow, copy, and we're done.
00791     */
00792    if ((size_t)(tp - tmp) > size) {
00793       errno = ENOSPC;
00794       return (NULL);
00795    }
00796    strcpy(dst, tmp);
00797    return (dst);
00798 }
00799 
00800 static int      inet_pton6(const char *src, u_char *dst);
00801 #endif //USE_IPV6
00802 
00803 static int      inet_pton4(const char *src, u_char *dst);
00804 
00805 /* int
00806  * inet_pton(af, src, dst)
00807  *      convert from presentation format (which usually means ASCII printable)
00808  *      to network format (which is usually some kind of binary format).
00809  * return:
00810  *      1 if the address was valid for the specified address family
00811  *      0 if the address wasn't valid (`dst' is untouched in this case)
00812  *      -1 if some other error occurred (`dst' is untouched in this case, too)
00813  * author:
00814  *      Paul Vixie, 1996.
00815  */
00816 int
00817 DnsUtil::inet_pton(int af, const char* src, void* dst)
00818 {
00819    switch (af) {
00820       case AF_INET:
00821          return (inet_pton4(src, (u_char*) dst));
00822 #ifdef USE_IPV6
00823       case AF_INET6:
00824          return (inet_pton6(src, (u_char*) dst));
00825 #endif
00826       default:
00827          errno = EAFNOSUPPORT;
00828          return (-1);
00829    }
00830    /* NOTREACHED */
00831 }
00832 
00833 /* int
00834  * inet_pton4(src, dst)
00835  *      like inet_aton() but without all the hexadecimal and shorthand.
00836  * return:
00837  *      1 if `src' is a valid dotted quad, else 0.
00838  * notice:
00839  *      does not touch `dst' unless it's returning 1.
00840  * author:
00841  *      Paul Vixie, 1996.
00842  */
00843 static const char digits[] = "0123456789";
00844 static int
00845 inet_pton4(const char *src, u_char *dst)
00846 {
00847    int saw_digit, octets, ch;
00848    u_char tmp[NS_INADDRSZ], *tp;
00849 
00850    saw_digit = 0;
00851    octets = 0;
00852    *(tp = tmp) = 0;
00853    while ((ch = *src++) != '\0') {
00854       const char *pch;
00855 
00856       if ((pch = strchr(digits, ch)) != NULL) {
00857          u_int newVal = u_int(*tp * 10 + (pch - digits));
00858 
00859          if (newVal > 255)
00860             return (0);
00861          *tp = newVal;
00862          if (! saw_digit) {
00863             if (++octets > 4)
00864                return (0);
00865             saw_digit = 1;
00866          }
00867       } else if (ch == '.' && saw_digit) {
00868          if (octets == 4)
00869             return (0);
00870          *++tp = 0;
00871          saw_digit = 0;
00872       } else
00873          return (0);
00874    }
00875    if (octets < 4)
00876       return (0);
00877 
00878    memcpy(dst, tmp, NS_INADDRSZ);
00879    return (1);
00880 }
00881 
00882 #ifdef USE_IPV6
00883 
00884 /* int
00885  * inet_pton6(src, dst)
00886  *      convert presentation level address to network order binary form.
00887  * return:
00888  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
00889  * notice:
00890  *      (1) does not touch `dst' unless it's returning 1.
00891  *      (2) :: in a full address is silently ignored.
00892  * credit:
00893  *      inspired by Mark Andrews.
00894  * author:
00895  *      Paul Vixie, 1996.
00896  */
00897 static const char xdigits_l[] = "0123456789abcdef",
00898                   xdigits_u[] = "0123456789ABCDEF";
00899 static int
00900 inet_pton6(const char *src, u_char *dst)
00901 {
00902    u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
00903    const char *xdigits, *curtok;
00904    int ch, saw_xdigit;
00905    u_int val;
00906 
00907    memset((tp = tmp), '\0', NS_IN6ADDRSZ);
00908    endp = tp + NS_IN6ADDRSZ;
00909    colonp = NULL;
00910    /* Leading :: requires some special handling. */
00911    if (*src == ':')
00912       if (*++src != ':')
00913          return (0);
00914    curtok = src;
00915    saw_xdigit = 0;
00916    val = 0;
00917    while ((ch = *src++) != '\0') {
00918       const char *pch;
00919 
00920       if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
00921          pch = strchr((xdigits = xdigits_u), ch);
00922       if (pch != NULL) {
00923          val <<= 4;
00924          val |= (pch - xdigits);
00925          if (val > 0xffff)
00926             return (0);
00927          saw_xdigit = 1;
00928          continue;
00929       }
00930       if (ch == ':') {
00931          curtok = src;
00932          if (!saw_xdigit) {
00933             if (colonp)
00934                return (0);
00935             colonp = tp;
00936             continue;
00937          }
00938          if (tp + NS_INT16SZ > endp)
00939             return (0);
00940          *tp++ = (u_char) (val >> 8) & 0xff;
00941          *tp++ = (u_char) val & 0xff;
00942          saw_xdigit = 0;
00943          val = 0;
00944          continue;
00945       }
00946       if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
00947           inet_pton4(curtok, tp) > 0) {
00948          tp += NS_INADDRSZ;
00949          saw_xdigit = 0;
00950          break; /* '\0' was seen by inet_pton4(). */
00951       }
00952       return (0);
00953    }
00954    if (saw_xdigit) {
00955       if (tp + NS_INT16SZ > endp)
00956          return (0);
00957       *tp++ = (u_char) (val >> 8) & 0xff;
00958       *tp++ = (u_char) val & 0xff;
00959    }
00960    if (colonp != NULL) {
00961       /*
00962        * Since some memmove()'s erroneously fail to handle
00963        * overlapping regions, we'll do the shift by hand.
00964        */
00965       const int n = int(tp - colonp);
00966       int i;
00967 
00968       for (i = 1; i <= n; i++) {
00969          endp[- i] = colonp[n - i];
00970          colonp[n - i] = 0;
00971       }
00972       tp = endp;
00973    }
00974    if (tp != endp)
00975       return (0);
00976    memcpy(dst, tmp, NS_IN6ADDRSZ);
00977    return (1);
00978 }
00979 
00980 
00981 #endif
00982 #endif
00983 
00984 /* ====================================================================
00985  * The Vovida Software License, Version 1.0
00986  *
00987  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00988  *
00989  * Redistribution and use in source and binary forms, with or without
00990  * modification, are permitted provided that the following conditions
00991  * are met:
00992  *
00993  * 1. Redistributions of source code must retain the above copyright
00994  *    notice, this list of conditions and the following disclaimer.
00995  *
00996  * 2. Redistributions in binary form must reproduce the above copyright
00997  *    notice, this list of conditions and the following disclaimer in
00998  *    the documentation and/or other materials provided with the
00999  *    distribution.
01000  *
01001  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
01002  *    and "Vovida Open Communication Application Library (VOCAL)" must
01003  *    not be used to endorse or promote products derived from this
01004  *    software without prior written permission. For written
01005  *    permission, please contact vocal@vovida.org.
01006  *
01007  * 4. Products derived from this software may not be called "VOCAL", nor
01008  *    may "VOCAL" appear in their name, without prior written
01009  *    permission of Vovida Networks, Inc.
01010  *
01011  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
01012  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
01013  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
01014  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
01015  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
01016  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
01017  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
01018  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
01019  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
01020  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
01021  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
01022  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
01023  * DAMAGE.
01024  *
01025  * ====================================================================
01026  *
01027  * This software consists of voluntary contributions made by Vovida
01028  * Networks, Inc. and many individuals on behalf of Vovida Networks,
01029  * Inc.  For more information on Vovida Networks, Inc., please see
01030  * <http://www.vovida.org/>.
01031  *
01032  */
01033 
01034 /* Copyright (c) 1996 by Internet Software Consortium.
01035  *
01036  * Permission to use, copy, modify, and distribute this software for any
01037  * purpose with or without fee is hereby granted, provided that the above
01038  * copyright notice and this permission notice appear in all copies.
01039  *
01040  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
01041  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
01042  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
01043  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
01044  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
01045  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
01046  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
01047  * SOFTWARE.
01048  */
01049