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