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