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