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