1 /* 2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * Copyright (c) 1982, 1986, 1990, 1993 32 * The Regents of the University of California. All rights reserved. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions 36 * are met: 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 2. Redistributions in binary form must reproduce the above copyright 40 * notice, this list of conditions and the following disclaimer in the 41 * documentation and/or other materials provided with the distribution. 42 * 3. All advertising materials mentioning features or use of this software 43 * must display the following acknowledgement: 44 * This product includes software developed by the University of 45 * California, Berkeley and its contributors. 46 * 4. Neither the name of the University nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 */ 63 64 /* 65 * Compatability shims with the rfc2553 API to simplify ntp. 66 */ 67 68 #include <config.h> 69 70 #include <sys/types.h> 71 #include <ctype.h> 72 #ifdef HAVE_SYS_SOCKET_H 73 #include <sys/socket.h> 74 #endif 75 #include <isc/net.h> 76 #ifdef HAVE_NETINET_IN_H 77 #include <netinet/in.h> 78 #endif 79 #include "ntp_rfc2553.h" 80 81 #include "ntpd.h" 82 #include "ntp_malloc.h" 83 #include "ntp_string.h" 84 #include "ntp_debug.h" 85 86 87 /* 88 * copy_addrinfo() - copy a single addrinfo to malloc()'d block. 89 * copy_addrinfo_list() - copy an addrinfo list to malloc()'d block. 90 * 91 * Copies an addrinfo list and its associated data to a contiguous block 92 * of storage from emalloc(). Callback routines invoked via 93 * getaddrinfo_sometime() have access to the resulting addrinfo list 94 * only until they return. This routine provides an easy way to make a 95 * persistent copy. Although the list provided to gai_sometime_callback 96 * routines is similarly contiguous, to keep this code usable in any 97 * context where we might want to duplicate an addrinfo list, it does 98 * not require the input list be contiguous. 99 * 100 * The returned list head pointer is passed to free() to release the 101 * entire list. 102 * 103 * In keeping with the rest of the NTP distribution, sockaddr_u is used 104 * in preference to struct sockaddr_storage, which is a member of the 105 * former union and so compatible. 106 * 107 * The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6 108 * not being defined, copy_addrinfo_*() are exceptions. 109 */ 110 struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int 111 #ifdef EREALLOC_CALLSITE 112 , 113 const char *, int 114 #endif 115 ); 116 117 118 struct addrinfo * 119 copy_addrinfo_impl( 120 const struct addrinfo * src 121 #ifdef EREALLOC_CALLSITE 122 , 123 const char * caller_file, 124 int caller_line 125 #endif 126 ) 127 { 128 return copy_addrinfo_common(src, TRUE 129 #ifdef EREALLOC_CALLSITE 130 , 131 caller_file, caller_line 132 #endif 133 ); 134 } 135 136 137 struct addrinfo * 138 copy_addrinfo_list_impl( 139 const struct addrinfo * src 140 #ifdef EREALLOC_CALLSITE 141 , 142 const char * caller_file, 143 int caller_line 144 #endif 145 ) 146 { 147 return copy_addrinfo_common(src, FALSE 148 #ifdef EREALLOC_CALLSITE 149 , 150 caller_file, caller_line 151 #endif 152 ); 153 } 154 155 156 struct addrinfo * 157 copy_addrinfo_common( 158 const struct addrinfo * src, 159 int just_one 160 #ifdef EREALLOC_CALLSITE 161 , 162 const char * caller_file, 163 int caller_line 164 #endif 165 ) 166 { 167 const struct addrinfo * ai_src; 168 const struct addrinfo * ai_nxt; 169 struct addrinfo * ai_cpy; 170 struct addrinfo * dst; 171 sockaddr_u * psau; 172 char * pcanon; 173 u_int elements; 174 size_t octets; 175 size_t canons_octets; 176 size_t str_octets; 177 178 elements = 0; 179 canons_octets = 0; 180 181 for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) { 182 if (just_one) 183 ai_nxt = NULL; 184 else 185 ai_nxt = ai_src->ai_next; 186 ++elements; 187 if (NULL != ai_src->ai_canonname) 188 canons_octets += 1 + strlen(ai_src->ai_canonname); 189 } 190 191 octets = elements * (sizeof(*ai_cpy) + sizeof(*psau)); 192 octets += canons_octets; 193 194 dst = erealloczsite(NULL, octets, 0, TRUE, caller_file, 195 caller_line); 196 ai_cpy = dst; 197 psau = (void *)(ai_cpy + elements); 198 pcanon = (void *)(psau + elements); 199 200 for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) { 201 if (just_one) 202 ai_nxt = NULL; 203 else 204 ai_nxt = ai_src->ai_next; 205 *ai_cpy = *ai_src; 206 REQUIRE(ai_src->ai_addrlen <= sizeof(sockaddr_u)); 207 memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen); 208 ai_cpy->ai_addr = &psau->sa; 209 ++psau; 210 if (NULL != ai_cpy->ai_canonname) { 211 ai_cpy->ai_canonname = pcanon; 212 str_octets = 1 + strlen(ai_src->ai_canonname); 213 memcpy(pcanon, ai_src->ai_canonname, str_octets); 214 pcanon += str_octets; 215 } 216 if (NULL != ai_cpy->ai_next) { 217 if (just_one) 218 ai_cpy->ai_next = NULL; 219 else 220 ai_cpy->ai_next = ai_cpy + 1; 221 } 222 ++ai_cpy; 223 } 224 ENSURE(pcanon == ((char *)dst + octets)); 225 226 return dst; 227 } 228 229 230 #ifndef ISC_PLATFORM_HAVEIPV6 231 232 static char *ai_errlist[] = { 233 "Success", 234 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 235 "Temporary failure in name resolution", /* EAI_AGAIN */ 236 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 237 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 238 "ai_family not supported", /* EAI_FAMILY */ 239 "Memory allocation failure", /* EAI_MEMORY */ 240 "No address associated with hostname", /* EAI_NODATA */ 241 "hostname nor servname provided, or not known", /* EAI_NONAME */ 242 "servname not supported for ai_socktype", /* EAI_SERVICE */ 243 "ai_socktype not supported", /* EAI_SOCKTYPE */ 244 "System error returned in errno", /* EAI_SYSTEM */ 245 "Invalid value for hints", /* EAI_BADHINTS */ 246 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 247 "Unknown error", /* EAI_MAX */ 248 }; 249 250 /* 251 * Local declaration 252 */ 253 int 254 DNSlookup_name( 255 const char *name, 256 int ai_family, 257 struct hostent **Addresses 258 ); 259 260 #ifndef SYS_WINNT 261 /* 262 * Encapsulate gethostbyname to control the error code 263 */ 264 int 265 DNSlookup_name( 266 const char *name, 267 int ai_family, 268 struct hostent **Addresses 269 ) 270 { 271 *Addresses = gethostbyname(name); 272 return (h_errno); 273 } 274 #endif 275 276 static int do_nodename (const char *nodename, struct addrinfo *ai, 277 const struct addrinfo *hints); 278 279 int 280 getaddrinfo (const char *nodename, const char *servname, 281 const struct addrinfo *hints, struct addrinfo **res) 282 { 283 int rval; 284 struct servent *sp; 285 struct addrinfo *ai = NULL; 286 int port; 287 const char *proto = NULL; 288 int family, socktype, flags, protocol; 289 290 291 /* 292 * If no name is provide just return an error 293 */ 294 if (nodename == NULL && servname == NULL) 295 return (EAI_NONAME); 296 297 ai = calloc(sizeof(struct addrinfo), 1); 298 if (ai == NULL) 299 return (EAI_MEMORY); 300 301 /* 302 * Copy default values from hints, if available 303 */ 304 if (hints != NULL) { 305 ai->ai_flags = hints->ai_flags; 306 ai->ai_family = hints->ai_family; 307 ai->ai_socktype = hints->ai_socktype; 308 ai->ai_protocol = hints->ai_protocol; 309 310 family = hints->ai_family; 311 socktype = hints->ai_socktype; 312 protocol = hints->ai_protocol; 313 flags = hints->ai_flags; 314 315 switch (family) { 316 case AF_UNSPEC: 317 switch (hints->ai_socktype) { 318 case SOCK_STREAM: 319 proto = "tcp"; 320 break; 321 case SOCK_DGRAM: 322 proto = "udp"; 323 break; 324 } 325 break; 326 case AF_INET: 327 case AF_INET6: 328 switch (hints->ai_socktype) { 329 case 0: 330 break; 331 case SOCK_STREAM: 332 proto = "tcp"; 333 break; 334 case SOCK_DGRAM: 335 proto = "udp"; 336 break; 337 case SOCK_RAW: 338 break; 339 default: 340 return (EAI_SOCKTYPE); 341 } 342 break; 343 #ifdef AF_LOCAL 344 case AF_LOCAL: 345 switch (hints->ai_socktype) { 346 case 0: 347 break; 348 case SOCK_STREAM: 349 break; 350 case SOCK_DGRAM: 351 break; 352 default: 353 return (EAI_SOCKTYPE); 354 } 355 break; 356 #endif 357 default: 358 return (EAI_FAMILY); 359 } 360 } else { 361 protocol = 0; 362 family = 0; 363 socktype = 0; 364 flags = 0; 365 } 366 367 rval = do_nodename(nodename, ai, hints); 368 if (rval != 0) { 369 freeaddrinfo(ai); 370 return (rval); 371 } 372 373 /* 374 * First, look up the service name (port) if it was 375 * requested. If the socket type wasn't specified, then 376 * try and figure it out. 377 */ 378 if (servname != NULL) { 379 char *e; 380 381 port = strtol(servname, &e, 10); 382 if (*e == '\0') { 383 if (socktype == 0) 384 return (EAI_SOCKTYPE); 385 if (port < 0 || port > 65535) 386 return (EAI_SERVICE); 387 port = htons((unsigned short) port); 388 } else { 389 sp = getservbyname(servname, proto); 390 if (sp == NULL) 391 return (EAI_SERVICE); 392 port = sp->s_port; 393 if (socktype == 0) { 394 if (strcmp(sp->s_proto, "tcp") == 0) 395 socktype = SOCK_STREAM; 396 else if (strcmp(sp->s_proto, "udp") == 0) 397 socktype = SOCK_DGRAM; 398 } 399 } 400 } else 401 port = 0; 402 403 /* 404 * 405 * Set up the port number 406 */ 407 if (ai->ai_family == AF_INET) 408 ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port; 409 else if (ai->ai_family == AF_INET6) 410 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port; 411 *res = ai; 412 return (0); 413 } 414 415 void 416 freeaddrinfo(struct addrinfo *ai) 417 { 418 if (ai->ai_canonname != NULL) 419 { 420 free(ai->ai_canonname); 421 ai->ai_canonname = NULL; 422 } 423 if (ai->ai_addr != NULL) 424 { 425 free(ai->ai_addr); 426 ai->ai_addr = NULL; 427 } 428 free(ai); 429 ai = NULL; 430 } 431 432 int 433 getnameinfo (const struct sockaddr *sa, u_int salen, char *host, 434 size_t hostlen, char *serv, size_t servlen, int flags) 435 { 436 struct hostent *hp; 437 438 if (sa->sa_family != AF_INET) 439 return (EAI_FAMILY); 440 hp = gethostbyaddr( 441 (const char *)&((const struct sockaddr_in *)sa)->sin_addr, 442 4, AF_INET); 443 if (hp == NULL) { 444 if (h_errno == TRY_AGAIN) 445 return (EAI_AGAIN); 446 else 447 return (EAI_FAIL); 448 } 449 if (host != NULL && hostlen > 0) 450 strlcpy(host, hp->h_name, hostlen); 451 return (0); 452 } 453 454 char * 455 gai_strerror(int ecode) 456 { 457 if (ecode < 0 || ecode > EAI_MAX) 458 ecode = EAI_MAX; 459 return ai_errlist[ecode]; 460 } 461 462 static int 463 do_nodename( 464 const char *nodename, 465 struct addrinfo *ai, 466 const struct addrinfo *hints) 467 { 468 struct hostent *hp = NULL; 469 struct sockaddr_in *sockin; 470 struct sockaddr_in6 *sockin6; 471 int errval; 472 473 ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1); 474 if (ai->ai_addr == NULL) 475 return (EAI_MEMORY); 476 477 /* 478 * For an empty node name just use the wildcard. 479 * NOTE: We need to assume that the address family is 480 * set elsewhere so that we can set the appropriate wildcard 481 */ 482 if (nodename == NULL) { 483 ai->ai_addrlen = sizeof(struct sockaddr_storage); 484 if (ai->ai_family == AF_INET) 485 { 486 sockin = (struct sockaddr_in *)ai->ai_addr; 487 sockin->sin_family = (short) ai->ai_family; 488 sockin->sin_addr.s_addr = htonl(INADDR_ANY); 489 } 490 else 491 { 492 sockin6 = (struct sockaddr_in6 *)ai->ai_addr; 493 sockin6->sin6_family = (short) ai->ai_family; 494 /* 495 * we have already zeroed out the address 496 * so we don't actually need to do this 497 * This assignment is causing problems so 498 * we don't do what this would do. 499 sockin6->sin6_addr = in6addr_any; 500 */ 501 } 502 #ifdef ISC_PLATFORM_HAVESALEN 503 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr); 504 #endif 505 506 return (0); 507 } 508 509 /* 510 * See if we have an IPv6 address 511 */ 512 if(strchr(nodename, ':') != NULL) { 513 if (inet_pton(AF_INET6, nodename, 514 &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) { 515 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6; 516 ai->ai_family = AF_INET6; 517 ai->ai_addrlen = sizeof(struct sockaddr_in6); 518 return (0); 519 } 520 } 521 522 /* 523 * See if we have an IPv4 address 524 */ 525 if (inet_pton(AF_INET, nodename, 526 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) { 527 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET; 528 ai->ai_family = AF_INET; 529 ai->ai_addrlen = sizeof(struct sockaddr_in); 530 return (0); 531 } 532 533 /* 534 * If the numeric host flag is set, don't attempt resolution 535 */ 536 if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST)) 537 return (EAI_NONAME); 538 539 /* 540 * Look for a name 541 */ 542 543 errval = DNSlookup_name(nodename, AF_INET, &hp); 544 545 if (hp == NULL) { 546 if (errval == TRY_AGAIN || errval == EAI_AGAIN) 547 return (EAI_AGAIN); 548 else if (errval == EAI_NONAME) { 549 if (inet_pton(AF_INET, nodename, 550 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) { 551 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET; 552 ai->ai_family = AF_INET; 553 ai->ai_addrlen = sizeof(struct sockaddr_in); 554 return (0); 555 } 556 return (errval); 557 } 558 else 559 { 560 return (errval); 561 } 562 } 563 ai->ai_family = hp->h_addrtype; 564 ai->ai_addrlen = sizeof(struct sockaddr); 565 sockin = (struct sockaddr_in *)ai->ai_addr; 566 memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length); 567 ai->ai_addr->sa_family = hp->h_addrtype; 568 #ifdef ISC_PLATFORM_HAVESALEN 569 ai->ai_addr->sa_len = sizeof(struct sockaddr); 570 #endif 571 if (hints != NULL && (hints->ai_flags & AI_CANONNAME)) 572 ai->ai_canonname = estrdup(hp->h_name); 573 return (0); 574 } 575 576 #endif /* !ISC_PLATFORM_HAVEIPV6 */ 577