|
reSIProcate/rutil
9694
|
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
1.7.5.1