00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "libts.h"
00025 #include "ts/TestBox.h"
00026 
00027 #if defined(darwin)
00028 extern "C"
00029 {
00030   struct hostent *gethostbyname_r(const char *name, struct hostent *result, char *buffer, int buflen, int *h_errnop);
00031   struct hostent *gethostbyaddr_r(const char *name, size_t size, int type,
00032                                   struct hostent *result, char *buffer, int buflen, int *h_errnop);
00033 }
00034 #endif
00035 
00036 IpAddr const IpAddr::INVALID;
00037 
00038 struct hostent *
00039 ink_gethostbyname_r(char *hostname, ink_gethostbyname_r_data * data)
00040 {
00041 #ifdef RENTRENT_GETHOSTBYNAME
00042   struct hostent *r = gethostbyname(hostname);
00043   if (r)
00044     data->ent = *r;
00045   data->herrno = errno;
00046 
00047 #else //RENTRENT_GETHOSTBYNAME
00048 #if GETHOSTBYNAME_R_GLIBC2
00049 
00050   struct hostent *addrp = NULL;
00051   int res = gethostbyname_r(hostname, &data->ent, data->buf,
00052                             INK_GETHOSTBYNAME_R_DATA_SIZE, &addrp,
00053                             &data->herrno);
00054   struct hostent *r = NULL;
00055   if (!res && addrp)
00056     r = addrp;
00057 
00058 #else
00059   struct hostent *r = gethostbyname_r(hostname, &data->ent, data->buf,
00060                                       INK_GETHOSTBYNAME_R_DATA_SIZE,
00061                                       &data->herrno);
00062 #endif
00063 #endif
00064   return r;
00065 }
00066 
00067 struct hostent *
00068 ink_gethostbyaddr_r(char *ip, int len, int type, ink_gethostbyaddr_r_data * data)
00069 {
00070 #if GETHOSTBYNAME_R_GLIBC2
00071   struct hostent *r = NULL;
00072   struct hostent *addrp = NULL;
00073   int res = gethostbyaddr_r((char *) ip, len, type, &data->ent, data->buf,
00074                             INK_GETHOSTBYNAME_R_DATA_SIZE, &addrp,
00075                             &data->herrno);
00076   if (!res && addrp)
00077     r = addrp;
00078 #else
00079 #ifdef RENTRENT_GETHOSTBYADDR
00080   struct hostent *r = gethostbyaddr((const void *) ip, len, type);
00081 
00082 #else
00083   struct hostent *r = gethostbyaddr_r((char *) ip, len, type, &data->ent,
00084                                       data->buf,
00085                                       INK_GETHOSTBYNAME_R_DATA_SIZE,
00086                                       &data->herrno);
00087 #endif
00088 #endif //LINUX
00089   return r;
00090 }
00091 
00092 uint32_t
00093 ink_inet_addr(const char *s)
00094 {
00095   uint32_t u[4];
00096   uint8_t *pc = (uint8_t *) s;
00097   int n = 0;
00098   uint32_t base = 10;
00099 
00100   while (n < 4) {
00101 
00102     u[n] = 0;
00103     base = 10;
00104 
00105     
00106 
00107     if (*pc == '0') {
00108       if (*++pc == 'x' || *pc == 'X')
00109         base = 16, pc++;
00110       else
00111         base = 8;
00112     }
00113     
00114 
00115     while (*pc) {
00116       if (ParseRules::is_digit(*pc)) {
00117         u[n] = u[n] * base + (*pc++ - '0');
00118         continue;
00119       }
00120       if (base == 16 && ParseRules::is_hex(*pc)) {
00121         u[n] = u[n] * 16 + ParseRules::ink_tolower(*pc++) - 'a' + 10;
00122         continue;
00123       }
00124       break;
00125     }
00126 
00127     n++;
00128     if (*pc == '.')
00129       pc++;
00130     else
00131       break;
00132   }
00133 
00134   if (*pc && !ParseRules::is_wslfcr(*pc))
00135     return htonl((uint32_t) - 1);
00136 
00137   switch (n) {
00138   case 1:
00139     return htonl(u[0]);
00140   case 2:
00141     if (u[0] > 0xff || u[1] > 0xffffff)
00142       return htonl((uint32_t) - 1);
00143     return htonl((u[0] << 24) | u[1]);
00144   case 3:
00145     if (u[0] > 0xff || u[1] > 0xff || u[2] > 0xffff)
00146       return htonl((uint32_t) - 1);
00147     return htonl((u[0] << 24) | (u[1] << 16) | u[2]);
00148   case 4:
00149     if (u[0] > 0xff || u[1] > 0xff || u[2] > 0xff || u[3] > 0xff)
00150       return htonl((uint32_t) - 1);
00151     return htonl((u[0] << 24) | (u[1] << 16) | (u[2] << 8) | u[3]);
00152   }
00153   return htonl((uint32_t) - 1);
00154 }
00155 
00156 const char *ats_ip_ntop(const struct sockaddr *addr, char *dst, size_t size)
00157 {
00158   char const* zret = 0;
00159 
00160   switch (addr->sa_family) {
00161   case AF_INET:
00162     zret = inet_ntop(AF_INET, &ats_ip4_addr_cast(addr), dst, size);
00163     break;
00164   case AF_INET6:
00165     zret = inet_ntop(AF_INET6, &ats_ip6_addr_cast(addr), dst, size);
00166     break;
00167   default:
00168     zret = dst;
00169     snprintf(dst, size, "*Not IP address [%u]*", addr->sa_family);
00170     break;
00171   }
00172   return zret;
00173 }
00174 
00175 char const*
00176 ats_ip_family_name(int family) {
00177   return AF_INET == family ? "IPv4"
00178     : AF_INET6 == family ? "IPv6"
00179     : "Unspec"
00180     ;
00181 }
00182 
00183 char const* ats_ip_nptop(
00184   sockaddr const* addr,
00185   char* dst, size_t size
00186 ) {
00187   char buff[INET6_ADDRSTRLEN];
00188   snprintf(dst, size, "%s:%u",
00189     ats_ip_ntop(addr, buff, sizeof(buff)),
00190     ats_ip_port_host_order(addr)
00191   );
00192   return dst;
00193 }
00194 
00195 int
00196 ats_ip_parse(ts::ConstBuffer src, ts::ConstBuffer* addr, ts::ConstBuffer* port) {
00197   
00198   ts::ConstBuffer localAddr, localPort;
00199   if (!addr) addr = &localAddr;
00200   if (!port) port = &localPort;
00201   addr->reset();
00202   port->reset();
00203 
00204   
00205   if (src) {
00206     while (src && isspace(*src)) ++src;
00207     
00208     if ('[' == *src) {
00209       
00210 
00211 
00212 
00213 
00214 
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00222 
00223       ++src; 
00224       *addr = src.splitOn(']');
00225       if (*addr && ':' == *src) { 
00226         ++src; 
00227         *port = src;
00228       } 
00229     } else {
00230       
00231       ts::ConstBuffer tmp = src.after(':');
00232       if (tmp && ! tmp.find(':')) { 
00233         src.clip(tmp.data() - 1); 
00234         *port = tmp;
00235       } 
00236       *addr = src;
00237     }
00238     
00239     if (*port) {
00240       char const* spot = port->data();
00241       while (isdigit(*spot)) ++spot;
00242       port->clip(spot);
00243     }
00244   }
00245   return *addr ? 0 : -1; 
00246 }
00247 
00248 int
00249 ats_ip_pton(const ts::ConstBuffer& src, sockaddr* ip)
00250 {
00251   int zret = -1;
00252   ts::ConstBuffer addr, port;
00253 
00254   ats_ip_invalidate(ip);
00255   if (0 == ats_ip_parse(src, &addr, &port)) {
00256     
00257     if (0 != addr[addr.size()-1]) {
00258       char* tmp = static_cast<char*>(alloca(addr.size()+1));
00259       memcpy(tmp, addr.data(), addr.size());
00260       tmp[addr.size()] = 0;
00261       addr.set(tmp, addr.size());
00262     }
00263     if (addr.find(':')) { 
00264       in6_addr addr6;
00265       if (inet_pton(AF_INET6, addr.data(), &addr6)) {
00266         zret = 0;
00267         ats_ip6_set(ip, addr6);
00268       }
00269     } else { 
00270       in_addr addr4;
00271       if (inet_aton(addr.data(), &addr4)) {
00272         zret = 0;
00273         ats_ip4_set(ip, addr4.s_addr);
00274       }
00275     }
00276     
00277     if (ats_is_ip(ip))
00278       ats_ip_port_cast(ip) = port ? htons(atoi(port.data())) : 0;
00279   }
00280 
00281   return zret;
00282 }
00283 
00284 uint32_t
00285 ats_ip_hash(sockaddr const* addr) {
00286   union md5sum {
00287     unsigned char c[16];
00288     uint32_t i;
00289   } zret;
00290   zret.i = 0;
00291 
00292   if (ats_is_ip4(addr)) {
00293     zret.i = ats_ip4_addr_cast(addr);
00294   } else if (ats_is_ip6(addr)) {
00295     ink_code_md5(const_cast<uint8_t*>(ats_ip_addr8_cast(addr)), TS_IP6_SIZE, zret.c);
00296   }
00297   return zret.i;
00298 }
00299 
00300 int
00301 ats_ip_to_hex(sockaddr const* src, char* dst, size_t len) {
00302   int zret = 0;
00303   ink_assert(len);
00304   char const* dst_limit = dst + len - 1; 
00305   if (ats_is_ip(src)) {
00306     uint8_t const* data = ats_ip_addr8_cast(src);
00307     for ( uint8_t const* src_limit = data + ats_ip_addr_size(src)
00308         ; data < src_limit && dst+1 < dst_limit
00309         ; ++data, zret += 2
00310     ) {
00311     uint8_t n1 = (*data >> 4) & 0xF; 
00312     uint8_t n0 = *data & 0xF; 
00313 
00314     *dst++ = n1 > 9 ? n1 + 'A' - 10 : n1 + '0';
00315     *dst++ = n0 > 9 ? n0 + 'A' - 10 : n0 + '0';
00316     }
00317   }
00318   *dst = 0; 
00319   return zret;
00320 }
00321 
00322 sockaddr* ats_ip_set(
00323   sockaddr* dst,
00324   IpAddr const& addr,
00325   uint16_t port
00326 ) {
00327   if (AF_INET == addr._family) ats_ip4_set(dst, addr._addr._ip4, port);
00328   else if (AF_INET6 == addr._family) ats_ip6_set(dst, addr._addr._ip6, port);
00329   else ats_ip_invalidate(dst);
00330   return dst;
00331 }
00332 
00333 int
00334 IpAddr::load(char const* text) {
00335   IpEndpoint ip;
00336   int zret = ats_ip_pton(text, &ip);
00337   *this = ip;
00338   return zret;
00339 }
00340 
00341 char*
00342 IpAddr::toString(char* dest, size_t len) const {
00343   IpEndpoint ip;
00344   ip.assign(*this);
00345   ats_ip_ntop(&ip, dest, len);
00346   return dest;
00347 }
00348 
00349 bool
00350 IpAddr::isMulticast() const {
00351   return (AF_INET == _family && 0xe == (_addr._byte[0] >> 4)) ||
00352     (AF_INET6 == _family && IN6_IS_ADDR_MULTICAST(&_addr._ip6))
00353     ;
00354 }
00355 
00356 bool
00357 operator == (IpAddr const& lhs, sockaddr const* rhs) {
00358   bool zret = false;
00359   if (lhs._family == rhs->sa_family) {
00360     if (AF_INET == lhs._family) {
00361       zret = lhs._addr._ip4 == ats_ip4_addr_cast(rhs);
00362     } else if (AF_INET6 == lhs._family) {
00363       zret = 0 == memcmp(&lhs._addr._ip6, &ats_ip6_addr_cast(rhs), sizeof(in6_addr));
00364     } else { 
00365       zret = true;
00366     }
00367   } 
00368   return zret;
00369 }
00370 
00371 int
00372 ats_ip_getbestaddrinfo(char const* host,
00373   IpEndpoint* ip4,
00374   IpEndpoint* ip6
00375 ) {
00376   int zret = -1;
00377   int port = 0; 
00378   addrinfo ai_hints;
00379   addrinfo* ai_result;
00380   ts::ConstBuffer addr_text, port_text;
00381   ts::ConstBuffer src(host, strlen(host)+1);
00382 
00383   if (ip4) ats_ip_invalidate(ip4);
00384   if (ip6) ats_ip_invalidate(ip6);
00385 
00386   if (0 == ats_ip_parse(src, &addr_text, &port_text)) {
00387     
00388     if (0 != addr_text[addr_text.size()-1]) {
00389       char* tmp = static_cast<char*>(alloca(addr_text.size()+1));
00390       memcpy(tmp, addr_text.data(), addr_text.size());
00391       tmp[addr_text.size()] = 0;
00392       addr_text.set(tmp, addr_text.size());
00393     }
00394     ink_zero(ai_hints);
00395     ai_hints.ai_family = AF_UNSPEC;
00396     ai_hints.ai_flags = AI_ADDRCONFIG;
00397     zret = getaddrinfo(addr_text.data(), 0, &ai_hints, &ai_result);
00398   
00399     if (0 == zret) {
00400       
00401       enum {
00402         NA, 
00403         LO, 
00404         LL, 
00405         PR, 
00406         MC, 
00407         GL  
00408       } spot_type = NA, ip4_type = NA, ip6_type = NA;
00409       sockaddr const* ip4_src = 0;
00410       sockaddr const* ip6_src = 0;
00411 
00412       for ( addrinfo* ai_spot = ai_result
00413           ; ai_spot
00414           ; ai_spot = ai_spot->ai_next
00415       ) {
00416         sockaddr const* ai_ip = ai_spot->ai_addr;
00417         if (!ats_is_ip(ai_ip)) spot_type = NA;
00418         else if (ats_is_ip_loopback(ai_ip)) spot_type = LO;
00419         else if (ats_is_ip_linklocal(ai_ip)) spot_type = LL;
00420         else if (ats_is_ip_private(ai_ip)) spot_type = PR;
00421         else if (ats_is_ip_multicast(ai_ip)) spot_type = MC;
00422         else spot_type = GL;
00423         
00424         if (spot_type == NA) continue; 
00425 
00426         if (ats_is_ip4(ai_ip)) {
00427           if (spot_type > ip4_type) {
00428             ip4_src = ai_ip;
00429             ip4_type = spot_type;
00430           }
00431         } else if (ats_is_ip6(ai_ip)) {
00432           if (spot_type > ip6_type) {
00433             ip6_src = ai_ip;
00434             ip6_type = spot_type;
00435           }
00436         }
00437       }
00438       if (ip4_type > NA) ats_ip_copy(ip4, ip4_src);
00439       if (ip6_type > NA) ats_ip_copy(ip6, ip6_src);
00440       freeaddrinfo(ai_result); 
00441 
00442     }
00443   }
00444 
00445   
00446   
00447   
00448   if (port_text.size()) port = htons(atoi(port_text.data()));
00449   if (ats_is_ip(ip4)) ats_ip_port_cast(ip4) = port;
00450   if (ats_is_ip(ip6)) ats_ip_port_cast(ip6) = port;
00451 
00452   if (!ats_is_ip(ip4) && !ats_is_ip(ip6)) zret = -1;
00453 
00454   return zret;
00455 }
00456 
00457 int
00458 ats_ip_check_characters(ts::ConstBuffer text) {
00459   bool found_colon = false;
00460   bool found_hex = false;
00461   for ( char const *p = text.data(), *limit = p + text.size()
00462       ; p < limit
00463       ; ++p
00464   )
00465     if (':' == *p) found_colon = true;
00466     else if ('.' == *p || isdigit(*p)) ;
00467     else if (isxdigit(*p)) found_hex = true;
00468     else return AF_UNSPEC;
00469 
00470   return found_hex && !found_colon ? AF_UNSPEC
00471     : found_colon ? AF_INET6
00472     : AF_INET
00473     ;
00474 }
00475 
00476 
00477 struct ip_parse_spec { const char * hostspec; const char * host; const char * port; };
00478 
00479 REGRESSION_TEST(Ink_Inet) (RegressionTest * t, int , int * pstatus) {
00480   TestBox box(t, pstatus);
00481   IpEndpoint  ep;
00482   IpAddr      addr;
00483 
00484   box = REGRESSION_TEST_PASSED;
00485 
00486   
00487   {
00488     struct ip_parse_spec names[] = {
00489       { "::", "::", NULL },
00490       { "[::1]:99", "::1", "99" },
00491       { "127.0.0.1:8080", "127.0.0.1", "8080" },
00492       { "foo.example.com", "foo.example.com", NULL },
00493       { "foo.example.com:99", "foo.example.com", "99" },
00494     };
00495 
00496     for (unsigned i = 0; i < countof(names); ++i) {
00497       ts::ConstBuffer addr, port;
00498 
00499       box.check(ats_ip_parse(ts::ConstBuffer(names[i].hostspec, strlen(names[i].hostspec)), &addr, &port) == 0,
00500           "ats_ip_parse(%s)", names[i].hostspec);
00501       box.check(strncmp(addr.data(), names[i].host, addr.size()) ==  0,
00502           "ats_ip_parse(%s) gave addr '%.*s'", names[i].hostspec, (int)addr.size(), addr.data());
00503       if (names[i].port) {
00504         box.check(strncmp(port.data(), names[i].port, port.size()) ==  0,
00505           "ats_ip_parse(%s) gave port '%.*s'", names[i].hostspec, (int)port.size(), port.data());
00506       } else {
00507         box.check(port.size() == 0,
00508           "ats_ip_parse(%s) gave port '%.*s'", names[i].hostspec, (int)port.size(), port.data());
00509       }
00510 
00511     }
00512   }
00513 
00514   
00515   {
00516     box.check(ats_ip_pton("76.14.64.156", &ep.sa) == 0, "ats_ip_pton()");
00517     box.check(addr.load("76.14.64.156") == 0, "IpAddr::load()");
00518     box.check(addr.family() == ep.family(), "mismatched address family");
00519 
00520     switch (addr.family()) {
00521     case AF_INET:
00522       box.check(ep.sin.sin_addr.s_addr == addr._addr._ip4, "IPv4 address mismatch");
00523       break;
00524     case AF_INET6:
00525       box.check(memcmp(&ep.sin6.sin6_addr, &addr._addr._ip6, sizeof(in6_addr)) == 0, "IPv6 address mismatch");
00526       break;
00527     default:
00528       ;
00529     }
00530   }
00531 
00532 
00533 }