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_stdlib.h" 84#include "ntp_string.h" 85 86#ifndef ISC_PLATFORM_HAVEIPV6 87 88static char *ai_errlist[] = { 89 "Success", 90 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 91 "Temporary failure in name resolution", /* EAI_AGAIN */ 92 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 93 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 94 "ai_family not supported", /* EAI_FAMILY */ 95 "Memory allocation failure", /* EAI_MEMORY */ 96 "No address associated with hostname", /* EAI_NODATA */ 97 "hostname nor servname provided, or not known", /* EAI_NONAME */ 98 "servname not supported for ai_socktype", /* EAI_SERVICE */ 99 "ai_socktype not supported", /* EAI_SOCKTYPE */ 100 "System error returned in errno", /* EAI_SYSTEM */ 101 "Invalid value for hints", /* EAI_BADHINTS */ 102 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 103 "Unknown error", /* EAI_MAX */ 104}; 105 106/* 107 * Local declaration 108 */ 109int 110DNSlookup_name( 111 const char *name, 112 int ai_family, 113 struct hostent **Addresses 114); 115 116#ifndef SYS_WINNT 117/* 118 * Encapsulate gethostbyname to control the error code 119 */ 120int 121DNSlookup_name( 122 const char *name, 123 int ai_family, 124 struct hostent **Addresses 125) 126{ 127 *Addresses = gethostbyname(name); 128 return (h_errno); 129} 130#endif 131 132static int do_nodename (const char *nodename, struct addrinfo *ai, 133 const struct addrinfo *hints); 134 135int 136getaddrinfo (const char *nodename, const char *servname, 137 const struct addrinfo *hints, struct addrinfo **res) 138{ 139 int rval; 140 struct servent *sp; 141 struct addrinfo *ai = NULL; 142 int port; 143 const char *proto = NULL; 144 int family, socktype, flags, protocol; 145 146 147 /* 148 * If no name is provide just return an error 149 */ 150 if (nodename == NULL && servname == NULL) 151 return (EAI_NONAME); 152 153 ai = calloc(sizeof(struct addrinfo), 1); 154 if (ai == NULL) 155 return (EAI_MEMORY); 156 157 /* 158 * Copy default values from hints, if available 159 */ 160 if (hints != NULL) { 161 ai->ai_flags = hints->ai_flags; 162 ai->ai_family = hints->ai_family; 163 ai->ai_socktype = hints->ai_socktype; 164 ai->ai_protocol = hints->ai_protocol; 165 166 family = hints->ai_family; 167 socktype = hints->ai_socktype; 168 protocol = hints->ai_protocol; 169 flags = hints->ai_flags; 170 171 switch (family) { 172 case AF_UNSPEC: 173 switch (hints->ai_socktype) { 174 case SOCK_STREAM: 175 proto = "tcp"; 176 break; 177 case SOCK_DGRAM: 178 proto = "udp"; 179 break; 180 } 181 break; 182 case AF_INET: 183 case AF_INET6: 184 switch (hints->ai_socktype) { 185 case 0: 186 break; 187 case SOCK_STREAM: 188 proto = "tcp"; 189 break; 190 case SOCK_DGRAM: 191 proto = "udp"; 192 break; 193 case SOCK_RAW: 194 break; 195 default: 196 return (EAI_SOCKTYPE); 197 } 198 break; 199#ifdef AF_LOCAL 200 case AF_LOCAL: 201 switch (hints->ai_socktype) { 202 case 0: 203 break; 204 case SOCK_STREAM: 205 break; 206 case SOCK_DGRAM: 207 break; 208 default: 209 return (EAI_SOCKTYPE); 210 } 211 break; 212#endif 213 default: 214 return (EAI_FAMILY); 215 } 216 } else { 217 protocol = 0; 218 family = 0; 219 socktype = 0; 220 flags = 0; 221 } 222 223 rval = do_nodename(nodename, ai, hints); 224 if (rval != 0) { 225 freeaddrinfo(ai); 226 return (rval); 227 } 228 229 /* 230 * First, look up the service name (port) if it was 231 * requested. If the socket type wasn't specified, then 232 * try and figure it out. 233 */ 234 if (servname != NULL) { 235 char *e; 236 237 port = strtol(servname, &e, 10); 238 if (*e == '\0') { 239 if (socktype == 0) 240 return (EAI_SOCKTYPE); 241 if (port < 0 || port > 65535) 242 return (EAI_SERVICE); 243 port = htons((unsigned short) port); 244 } else { 245 sp = getservbyname(servname, proto); 246 if (sp == NULL) 247 return (EAI_SERVICE); 248 port = sp->s_port; 249 if (socktype == 0) { 250 if (strcmp(sp->s_proto, "tcp") == 0) 251 socktype = SOCK_STREAM; 252 else if (strcmp(sp->s_proto, "udp") == 0) 253 socktype = SOCK_DGRAM; 254 } 255 } 256 } else 257 port = 0; 258 259 /* 260 * 261 * Set up the port number 262 */ 263 if (ai->ai_family == AF_INET) 264 ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port; 265 else if (ai->ai_family == AF_INET6) 266 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port; 267 *res = ai; 268 return (0); 269} 270 271void 272freeaddrinfo(struct addrinfo *ai) 273{ 274 if (ai->ai_canonname != NULL) 275 { 276 free(ai->ai_canonname); 277 ai->ai_canonname = NULL; 278 } 279 if (ai->ai_addr != NULL) 280 { 281 free(ai->ai_addr); 282 ai->ai_addr = NULL; 283 } 284 free(ai); 285 ai = NULL; 286} 287 288int 289getnameinfo (const struct sockaddr *sa, u_int salen, char *host, 290 size_t hostlen, char *serv, size_t servlen, int flags) 291{ 292 struct hostent *hp; 293 int namelen; 294 295 if (sa->sa_family != AF_INET) 296 return (EAI_FAMILY); 297 hp = gethostbyaddr( 298 (const char *)&((const struct sockaddr_in *)sa)->sin_addr, 299 4, AF_INET); 300 if (hp == NULL) { 301 if (h_errno == TRY_AGAIN) 302 return (EAI_AGAIN); 303 else 304 return (EAI_FAIL); 305 } 306 if (host != NULL && hostlen > 0) { 307 /* 308 * Don't exceed buffer 309 */ 310 namelen = min(strlen(hp->h_name), hostlen - 1); 311 if (namelen > 0) { 312 strncpy(host, hp->h_name, namelen); 313 host[namelen] = '\0'; 314 } 315 } 316 return (0); 317} 318 319char * 320gai_strerror(int ecode) 321{ 322 if (ecode < 0 || ecode > EAI_MAX) 323 ecode = EAI_MAX; 324 return ai_errlist[ecode]; 325} 326 327static int 328do_nodename( 329 const char *nodename, 330 struct addrinfo *ai, 331 const struct addrinfo *hints) 332{ 333 struct hostent *hp = NULL; 334 struct sockaddr_in *sockin; 335 struct sockaddr_in6 *sockin6; 336 int errval; 337 338 ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1); 339 if (ai->ai_addr == NULL) 340 return (EAI_MEMORY); 341 342 /* 343 * For an empty node name just use the wildcard. 344 * NOTE: We need to assume that the address family is 345 * set elsewhere so that we can set the appropriate wildcard 346 */ 347 if (nodename == NULL) { 348 ai->ai_addrlen = sizeof(struct sockaddr_storage); 349 if (ai->ai_family == AF_INET) 350 { 351 sockin = (struct sockaddr_in *)ai->ai_addr; 352 sockin->sin_family = (short) ai->ai_family; 353 sockin->sin_addr.s_addr = htonl(INADDR_ANY); 354 } 355 else 356 { 357 sockin6 = (struct sockaddr_in6 *)ai->ai_addr; 358 sockin6->sin6_family = (short) ai->ai_family; 359 /* 360 * we have already zeroed out the address 361 * so we don't actually need to do this 362 * This assignment is causing problems so 363 * we don't do what this would do. 364 sockin6->sin6_addr = in6addr_any; 365 */ 366 } 367#ifdef ISC_PLATFORM_HAVESALEN 368 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr); 369#endif 370 371 return (0); 372 } 373 374 /* 375 * See if we have an IPv6 address 376 */ 377 if(strchr(nodename, ':') != NULL) { 378 if (inet_pton(AF_INET6, nodename, 379 &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) { 380 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6; 381 ai->ai_family = AF_INET6; 382 ai->ai_addrlen = sizeof(struct sockaddr_in6); 383 return (0); 384 } 385 } 386 387 /* 388 * See if we have an IPv4 address 389 */ 390 if (inet_pton(AF_INET, nodename, 391 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) { 392 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET; 393 ai->ai_family = AF_INET; 394 ai->ai_addrlen = sizeof(struct sockaddr_in); 395 return (0); 396 } 397 398 /* 399 * If the numeric host flag is set, don't attempt resolution 400 */ 401 if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST)) 402 return (EAI_NONAME); 403 404 /* 405 * Look for a name 406 */ 407 408 errval = DNSlookup_name(nodename, AF_INET, &hp); 409 410 if (hp == NULL) { 411 if (errval == TRY_AGAIN || errval == EAI_AGAIN) 412 return (EAI_AGAIN); 413 else if (errval == EAI_NONAME) { 414 if (inet_pton(AF_INET, nodename, 415 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) { 416 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET; 417 ai->ai_family = AF_INET; 418 ai->ai_addrlen = sizeof(struct sockaddr_in); 419 return (0); 420 } 421 return (errval); 422 } 423 else 424 { 425 return (errval); 426 } 427 } 428 ai->ai_family = hp->h_addrtype; 429 ai->ai_addrlen = sizeof(struct sockaddr); 430 sockin = (struct sockaddr_in *)ai->ai_addr; 431 memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length); 432 ai->ai_addr->sa_family = hp->h_addrtype; 433#ifdef ISC_PLATFORM_HAVESALEN 434 ai->ai_addr->sa_len = sizeof(struct sockaddr); 435#endif 436 if (hints != NULL && hints->ai_flags & AI_CANONNAME) 437 ai->ai_canonname = estrdup(hp->h_name); 438 return (0); 439} 440 441#endif /* !ISC_PLATFORM_HAVEIPV6 */ 442