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 DEBUG_INSIST(ai_cpy->ai_canonname == ai_src->ai_canonname); 207 INSIST(ai_src->ai_addrlen <= sizeof(sockaddr_u)); 208 memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen); 209 ai_cpy->ai_addr = &psau->sa; 210 ++psau; 211 if (NULL != ai_src->ai_canonname) { 212 ai_cpy->ai_canonname = pcanon; 213 str_octets = 1 + strlen(ai_src->ai_canonname); 214 memcpy(pcanon, ai_src->ai_canonname, str_octets); 215 pcanon += str_octets; 216 } 217 if (NULL != ai_cpy->ai_next) { 218 if (just_one) 219 ai_cpy->ai_next = NULL; 220 else 221 ai_cpy->ai_next = ai_cpy + 1; 222 } 223 ++ai_cpy; 224 } 225 ENSURE(pcanon == ((char *)dst + octets)); 226 227 return dst; 228 } 229 230 231 #ifndef ISC_PLATFORM_HAVEIPV6 232 233 static char *ai_errlist[] = { 234 "Success", 235 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 236 "Temporary failure in name resolution", /* EAI_AGAIN */ 237 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 238 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 239 "ai_family not supported", /* EAI_FAMILY */ 240 "Memory allocation failure", /* EAI_MEMORY */ 241 "No address associated with hostname", /* EAI_NODATA */ 242 "hostname nor servname provided, or not known", /* EAI_NONAME */ 243 "servname not supported for ai_socktype", /* EAI_SERVICE */ 244 "ai_socktype not supported", /* EAI_SOCKTYPE */ 245 "System error returned in errno", /* EAI_SYSTEM */ 246 "Invalid value for hints", /* EAI_BADHINTS */ 247 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 248 "Unknown error", /* EAI_MAX */ 249 }; 250 251 /* 252 * Local declaration 253 */ 254 int 255 DNSlookup_name( 256 const char *name, 257 int ai_family, 258 struct hostent **Addresses 259 ); 260 261 #ifndef SYS_WINNT 262 /* 263 * Encapsulate gethostbyname to control the error code 264 */ 265 int 266 DNSlookup_name( 267 const char *name, 268 int ai_family, 269 struct hostent **Addresses 270 ) 271 { 272 *Addresses = gethostbyname(name); 273 return (h_errno); 274 } 275 #endif 276 277 static int do_nodename (const char *nodename, struct addrinfo *ai, 278 const struct addrinfo *hints); 279 280 int 281 getaddrinfo (const char *nodename, const char *servname, 282 const struct addrinfo *hints, struct addrinfo **res) 283 { 284 int rval; 285 struct servent *sp; 286 struct addrinfo *ai = NULL; 287 int port; 288 const char *proto = NULL; 289 int family, socktype, flags, protocol; 290 291 292 /* 293 * If no name is provide just return an error 294 */ 295 if (nodename == NULL && servname == NULL) 296 return (EAI_NONAME); 297 298 ai = calloc(sizeof(struct addrinfo), 1); 299 if (ai == NULL) 300 return (EAI_MEMORY); 301 302 /* 303 * Copy default values from hints, if available 304 */ 305 if (hints != NULL) { 306 ai->ai_flags = hints->ai_flags; 307 ai->ai_family = hints->ai_family; 308 ai->ai_socktype = hints->ai_socktype; 309 ai->ai_protocol = hints->ai_protocol; 310 311 family = hints->ai_family; 312 socktype = hints->ai_socktype; 313 protocol = hints->ai_protocol; 314 flags = hints->ai_flags; 315 316 switch (family) { 317 case AF_UNSPEC: 318 switch (hints->ai_socktype) { 319 case SOCK_STREAM: 320 proto = "tcp"; 321 break; 322 case SOCK_DGRAM: 323 proto = "udp"; 324 break; 325 } 326 break; 327 case AF_INET: 328 case AF_INET6: 329 switch (hints->ai_socktype) { 330 case 0: 331 break; 332 case SOCK_STREAM: 333 proto = "tcp"; 334 break; 335 case SOCK_DGRAM: 336 proto = "udp"; 337 break; 338 case SOCK_RAW: 339 break; 340 default: 341 return (EAI_SOCKTYPE); 342 } 343 break; 344 #ifdef AF_LOCAL 345 case AF_LOCAL: 346 switch (hints->ai_socktype) { 347 case 0: 348 break; 349 case SOCK_STREAM: 350 break; 351 case SOCK_DGRAM: 352 break; 353 default: 354 return (EAI_SOCKTYPE); 355 } 356 break; 357 #endif 358 default: 359 return (EAI_FAMILY); 360 } 361 } else { 362 protocol = 0; 363 family = 0; 364 socktype = 0; 365 flags = 0; 366 } 367 368 rval = do_nodename(nodename, ai, hints); 369 if (rval != 0) { 370 freeaddrinfo(ai); 371 return (rval); 372 } 373 374 /* 375 * First, look up the service name (port) if it was 376 * requested. If the socket type wasn't specified, then 377 * try and figure it out. 378 */ 379 if (servname != NULL) { 380 char *e; 381 382 port = strtol(servname, &e, 10); 383 if (*e == '\0') { 384 if (socktype == 0) 385 return (EAI_SOCKTYPE); 386 if (port < 0 || port > 65535) 387 return (EAI_SERVICE); 388 port = htons((unsigned short) port); 389 } else { 390 sp = getservbyname(servname, proto); 391 if (sp == NULL) 392 return (EAI_SERVICE); 393 port = sp->s_port; 394 if (socktype == 0) { 395 if (strcmp(sp->s_proto, "tcp") == 0) 396 socktype = SOCK_STREAM; 397 else if (strcmp(sp->s_proto, "udp") == 0) 398 socktype = SOCK_DGRAM; 399 } 400 } 401 } else 402 port = 0; 403 404 /* 405 * 406 * Set up the port number 407 */ 408 if (ai->ai_family == AF_INET) 409 ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port; 410 else if (ai->ai_family == AF_INET6) 411 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port; 412 *res = ai; 413 return (0); 414 } 415 416 void 417 freeaddrinfo(struct addrinfo *ai) 418 { 419 if (ai->ai_canonname != NULL) 420 { 421 free(ai->ai_canonname); 422 ai->ai_canonname = NULL; 423 } 424 if (ai->ai_addr != NULL) 425 { 426 free(ai->ai_addr); 427 ai->ai_addr = NULL; 428 } 429 free(ai); 430 ai = NULL; 431 } 432 433 int 434 getnameinfo (const struct sockaddr *sa, u_int salen, char *host, 435 size_t hostlen, char *serv, size_t servlen, int flags) 436 { 437 struct hostent *hp; 438 439 if (sa->sa_family != AF_INET) 440 return (EAI_FAMILY); 441 hp = gethostbyaddr( 442 (const char *)&((const struct sockaddr_in *)sa)->sin_addr, 443 4, AF_INET); 444 if (hp == NULL) { 445 if (h_errno == TRY_AGAIN) 446 return (EAI_AGAIN); 447 else 448 return (EAI_FAIL); 449 } 450 if (host != NULL && hostlen > 0) 451 strlcpy(host, hp->h_name, hostlen); 452 return (0); 453 } 454 455 char * 456 gai_strerror(int ecode) 457 { 458 if (ecode < 0 || ecode > EAI_MAX) 459 ecode = EAI_MAX; 460 return ai_errlist[ecode]; 461 } 462 463 static int 464 do_nodename( 465 const char *nodename, 466 struct addrinfo *ai, 467 const struct addrinfo *hints) 468 { 469 struct hostent *hp = NULL; 470 struct sockaddr_in *sockin; 471 struct sockaddr_in6 *sockin6; 472 int errval; 473 474 ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1); 475 if (ai->ai_addr == NULL) 476 return (EAI_MEMORY); 477 478 /* 479 * For an empty node name just use the wildcard. 480 * NOTE: We need to assume that the address family is 481 * set elsewhere so that we can set the appropriate wildcard 482 */ 483 if (nodename == NULL) { 484 if (ai->ai_family == AF_INET) 485 { 486 ai->ai_addrlen = sizeof(struct sockaddr_in); 487 sockin = (struct sockaddr_in *)ai->ai_addr; 488 sockin->sin_family = (short) ai->ai_family; 489 sockin->sin_addr.s_addr = htonl(INADDR_ANY); 490 } 491 else 492 { 493 ai->ai_addrlen = sizeof(struct sockaddr_in6); 494 sockin6 = (struct sockaddr_in6 *)ai->ai_addr; 495 sockin6->sin6_family = (short) ai->ai_family; 496 /* 497 * we have already zeroed out the address 498 * so we don't actually need to do this 499 * This assignment is causing problems so 500 * we don't do what this would do. 501 sockin6->sin6_addr = in6addr_any; 502 */ 503 } 504 #ifdef ISC_PLATFORM_HAVESALEN 505 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr); 506 #endif 507 508 return (0); 509 } 510 511 /* 512 * See if we have an IPv6 address 513 */ 514 if(strchr(nodename, ':') != NULL) { 515 if (inet_pton(AF_INET6, nodename, 516 &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) { 517 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6; 518 ai->ai_family = AF_INET6; 519 ai->ai_addrlen = sizeof(struct sockaddr_in6); 520 return (0); 521 } 522 } 523 524 /* 525 * See if we have an IPv4 address 526 */ 527 if (inet_pton(AF_INET, nodename, 528 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) { 529 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET; 530 ai->ai_family = AF_INET; 531 ai->ai_addrlen = sizeof(struct sockaddr_in); 532 return (0); 533 } 534 535 /* 536 * If the numeric host flag is set, don't attempt resolution 537 */ 538 if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST)) 539 return (EAI_NONAME); 540 541 /* 542 * Look for a name 543 */ 544 545 errval = DNSlookup_name(nodename, AF_INET, &hp); 546 547 if (hp == NULL) { 548 if (errval == TRY_AGAIN || errval == EAI_AGAIN) 549 return (EAI_AGAIN); 550 else if (errval == EAI_NONAME) { 551 if (inet_pton(AF_INET, nodename, 552 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) { 553 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET; 554 ai->ai_family = AF_INET; 555 ai->ai_addrlen = sizeof(struct sockaddr_in); 556 return (0); 557 } 558 return (errval); 559 } 560 else 561 { 562 return (errval); 563 } 564 } 565 ai->ai_family = hp->h_addrtype; 566 ai->ai_addrlen = sizeof(struct sockaddr); 567 sockin = (struct sockaddr_in *)ai->ai_addr; 568 memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length); 569 ai->ai_addr->sa_family = hp->h_addrtype; 570 #ifdef ISC_PLATFORM_HAVESALEN 571 ai->ai_addr->sa_len = sizeof(struct sockaddr); 572 #endif 573 if (hints != NULL && (hints->ai_flags & AI_CANONNAME)) 574 ai->ai_canonname = estrdup(hp->h_name); 575 return (0); 576 } 577 578 #endif /* !ISC_PLATFORM_HAVEIPV6 */ 579