Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / libntp / ntp_rfc2553.c
blobcee0b7e2206861fc7cf9f9400e8350a5c96eb409
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
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.
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.
33 * Copyright (c) 1982, 1986, 1990, 1993
34 * The Regents of the University of California. All rights reserved.
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.
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.
67 * Compatability shims with the rfc2553 API to simplify ntp.
70 #include <config.h>
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"
83 #include "ntpd.h"
84 #include "ntp_malloc.h"
85 #include "ntp_stdlib.h"
86 #include "ntp_string.h"
88 #ifndef ISC_PLATFORM_HAVEIPV6
90 static 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 */
109 * Local declaration
112 DNSlookup_name(
113 const char *name,
114 int ai_family,
115 struct hostent **Addresses
118 #ifndef SYS_WINNT
120 * Encapsulate gethostbyname to control the error code
123 DNSlookup_name(
124 const char *name,
125 int ai_family,
126 struct hostent **Addresses
129 *Addresses = gethostbyname(name);
130 return (h_errno);
132 #endif
134 static int do_nodename (const char *nodename, struct addrinfo *ai,
135 const struct addrinfo *hints);
138 getaddrinfo (const char *nodename, const char *servname,
139 const struct addrinfo *hints, struct addrinfo **res)
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;
150 * If no name is provide just return an error
152 if (nodename == NULL && servname == NULL)
153 return (EAI_NONAME);
155 ai = calloc(sizeof(struct addrinfo), 1);
156 if (ai == NULL)
157 return (EAI_MEMORY);
160 * Copy default values from hints, if available
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;
168 family = hints->ai_family;
169 socktype = hints->ai_socktype;
170 protocol = hints->ai_protocol;
171 flags = hints->ai_flags;
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;
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);
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);
213 break;
214 #endif
215 default:
216 return (EAI_FAMILY);
218 } else {
219 protocol = 0;
220 family = 0;
221 socktype = 0;
222 flags = 0;
225 rval = do_nodename(nodename, ai, hints);
226 if (rval != 0) {
227 freeaddrinfo(ai);
228 return (rval);
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.
236 if (servname != NULL) {
237 char *e;
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;
258 } else
259 port = 0;
263 * Set up the port number
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);
273 void
274 freeaddrinfo(struct addrinfo *ai)
276 if (ai->ai_canonname != NULL)
278 free(ai->ai_canonname);
279 ai->ai_canonname = NULL;
281 if (ai->ai_addr != NULL)
283 free(ai->ai_addr);
284 ai->ai_addr = NULL;
286 free(ai);
287 ai = NULL;
291 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
292 size_t hostlen, char *serv, size_t servlen, int flags)
294 struct hostent *hp;
295 int namelen;
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);
308 if (host != NULL && hostlen > 0) {
310 * Don't exceed buffer
312 namelen = min(strlen(hp->h_name), hostlen - 1);
313 if (namelen > 0) {
314 strncpy(host, hp->h_name, namelen);
315 host[namelen] = '\0';
318 return (0);
321 char *
322 gai_strerror(int ecode)
324 if (ecode < 0 || ecode > EAI_MAX)
325 ecode = EAI_MAX;
326 return ai_errlist[ecode];
329 static int
330 do_nodename(
331 const char *nodename,
332 struct addrinfo *ai,
333 const struct addrinfo *hints)
335 struct hostent *hp = NULL;
336 struct sockaddr_in *sockin;
337 struct sockaddr_in6 *sockin6;
338 int errval;
340 ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
341 if (ai->ai_addr == NULL)
342 return (EAI_MEMORY);
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
349 if (nodename == NULL) {
350 ai->ai_addrlen = sizeof(struct sockaddr_storage);
351 if (ai->ai_family == AF_INET)
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);
357 else
359 sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
360 sockin6->sin6_family = (short) ai->ai_family;
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;
369 #ifdef ISC_PLATFORM_HAVESALEN
370 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
371 #endif
373 return (0);
377 * See if we have an IPv6 address
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);
390 * See if we have an IPv4 address
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);
401 * If the numeric host flag is set, don't attempt resolution
403 if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
404 return (EAI_NONAME);
407 * Look for a name
410 errval = DNSlookup_name(nodename, AF_INET, &hp);
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);
423 return (errval);
425 else
427 return (errval);
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);
443 #endif /* !ISC_PLATFORM_HAVEIPV6 */