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 }