ntp_rfc2553.c revision 1.1 1 1.1 kardel /* $NetBSD: ntp_rfc2553.c,v 1.1 2009/12/13 16:55:04 kardel Exp $ */
2 1.1 kardel
3 1.1 kardel /*
4 1.1 kardel * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 1.1 kardel * All rights reserved.
6 1.1 kardel *
7 1.1 kardel * Redistribution and use in source and binary forms, with or without
8 1.1 kardel * modification, are permitted provided that the following conditions
9 1.1 kardel * are met:
10 1.1 kardel * 1. Redistributions of source code must retain the above copyright
11 1.1 kardel * notice, this list of conditions and the following disclaimer.
12 1.1 kardel * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 kardel * notice, this list of conditions and the following disclaimer in the
14 1.1 kardel * documentation and/or other materials provided with the distribution.
15 1.1 kardel * 3. Neither the name of the project nor the names of its contributors
16 1.1 kardel * may be used to endorse or promote products derived from this software
17 1.1 kardel * without specific prior written permission.
18 1.1 kardel *
19 1.1 kardel * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 1.1 kardel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 kardel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 kardel * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 1.1 kardel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 kardel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 kardel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 kardel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 kardel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 kardel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 kardel * SUCH DAMAGE.
30 1.1 kardel */
31 1.1 kardel
32 1.1 kardel /*
33 1.1 kardel * Copyright (c) 1982, 1986, 1990, 1993
34 1.1 kardel * The Regents of the University of California. All rights reserved.
35 1.1 kardel *
36 1.1 kardel * Redistribution and use in source and binary forms, with or without
37 1.1 kardel * modification, are permitted provided that the following conditions
38 1.1 kardel * are met:
39 1.1 kardel * 1. Redistributions of source code must retain the above copyright
40 1.1 kardel * notice, this list of conditions and the following disclaimer.
41 1.1 kardel * 2. Redistributions in binary form must reproduce the above copyright
42 1.1 kardel * notice, this list of conditions and the following disclaimer in the
43 1.1 kardel * documentation and/or other materials provided with the distribution.
44 1.1 kardel * 3. All advertising materials mentioning features or use of this software
45 1.1 kardel * must display the following acknowledgement:
46 1.1 kardel * This product includes software developed by the University of
47 1.1 kardel * California, Berkeley and its contributors.
48 1.1 kardel * 4. Neither the name of the University nor the names of its contributors
49 1.1 kardel * may be used to endorse or promote products derived from this software
50 1.1 kardel * without specific prior written permission.
51 1.1 kardel *
52 1.1 kardel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 1.1 kardel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 1.1 kardel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 1.1 kardel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 1.1 kardel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 1.1 kardel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 1.1 kardel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 1.1 kardel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 1.1 kardel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 1.1 kardel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 1.1 kardel * SUCH DAMAGE.
63 1.1 kardel *
64 1.1 kardel */
65 1.1 kardel
66 1.1 kardel /*
67 1.1 kardel * Compatability shims with the rfc2553 API to simplify ntp.
68 1.1 kardel */
69 1.1 kardel
70 1.1 kardel #include <config.h>
71 1.1 kardel
72 1.1 kardel #include <sys/types.h>
73 1.1 kardel #include <ctype.h>
74 1.1 kardel #ifdef HAVE_SYS_SOCKET_H
75 1.1 kardel #include <sys/socket.h>
76 1.1 kardel #endif
77 1.1 kardel #include <isc/net.h>
78 1.1 kardel #ifdef HAVE_NETINET_IN_H
79 1.1 kardel #include <netinet/in.h>
80 1.1 kardel #endif
81 1.1 kardel #include "ntp_rfc2553.h"
82 1.1 kardel
83 1.1 kardel #include "ntpd.h"
84 1.1 kardel #include "ntp_malloc.h"
85 1.1 kardel #include "ntp_stdlib.h"
86 1.1 kardel #include "ntp_string.h"
87 1.1 kardel
88 1.1 kardel #ifndef ISC_PLATFORM_HAVEIPV6
89 1.1 kardel
90 1.1 kardel static char *ai_errlist[] = {
91 1.1 kardel "Success",
92 1.1 kardel "Address family for hostname not supported", /* EAI_ADDRFAMILY */
93 1.1 kardel "Temporary failure in name resolution", /* EAI_AGAIN */
94 1.1 kardel "Invalid value for ai_flags", /* EAI_BADFLAGS */
95 1.1 kardel "Non-recoverable failure in name resolution", /* EAI_FAIL */
96 1.1 kardel "ai_family not supported", /* EAI_FAMILY */
97 1.1 kardel "Memory allocation failure", /* EAI_MEMORY */
98 1.1 kardel "No address associated with hostname", /* EAI_NODATA */
99 1.1 kardel "hostname nor servname provided, or not known", /* EAI_NONAME */
100 1.1 kardel "servname not supported for ai_socktype", /* EAI_SERVICE */
101 1.1 kardel "ai_socktype not supported", /* EAI_SOCKTYPE */
102 1.1 kardel "System error returned in errno", /* EAI_SYSTEM */
103 1.1 kardel "Invalid value for hints", /* EAI_BADHINTS */
104 1.1 kardel "Resolved protocol is unknown", /* EAI_PROTOCOL */
105 1.1 kardel "Unknown error", /* EAI_MAX */
106 1.1 kardel };
107 1.1 kardel
108 1.1 kardel /*
109 1.1 kardel * Local declaration
110 1.1 kardel */
111 1.1 kardel int
112 1.1 kardel DNSlookup_name(
113 1.1 kardel const char *name,
114 1.1 kardel int ai_family,
115 1.1 kardel struct hostent **Addresses
116 1.1 kardel );
117 1.1 kardel
118 1.1 kardel #ifndef SYS_WINNT
119 1.1 kardel /*
120 1.1 kardel * Encapsulate gethostbyname to control the error code
121 1.1 kardel */
122 1.1 kardel int
123 1.1 kardel DNSlookup_name(
124 1.1 kardel const char *name,
125 1.1 kardel int ai_family,
126 1.1 kardel struct hostent **Addresses
127 1.1 kardel )
128 1.1 kardel {
129 1.1 kardel *Addresses = gethostbyname(name);
130 1.1 kardel return (h_errno);
131 1.1 kardel }
132 1.1 kardel #endif
133 1.1 kardel
134 1.1 kardel static int do_nodename (const char *nodename, struct addrinfo *ai,
135 1.1 kardel const struct addrinfo *hints);
136 1.1 kardel
137 1.1 kardel int
138 1.1 kardel getaddrinfo (const char *nodename, const char *servname,
139 1.1 kardel const struct addrinfo *hints, struct addrinfo **res)
140 1.1 kardel {
141 1.1 kardel int rval;
142 1.1 kardel struct servent *sp;
143 1.1 kardel struct addrinfo *ai = NULL;
144 1.1 kardel int port;
145 1.1 kardel const char *proto = NULL;
146 1.1 kardel int family, socktype, flags, protocol;
147 1.1 kardel
148 1.1 kardel
149 1.1 kardel /*
150 1.1 kardel * If no name is provide just return an error
151 1.1 kardel */
152 1.1 kardel if (nodename == NULL && servname == NULL)
153 1.1 kardel return (EAI_NONAME);
154 1.1 kardel
155 1.1 kardel ai = calloc(sizeof(struct addrinfo), 1);
156 1.1 kardel if (ai == NULL)
157 1.1 kardel return (EAI_MEMORY);
158 1.1 kardel
159 1.1 kardel /*
160 1.1 kardel * Copy default values from hints, if available
161 1.1 kardel */
162 1.1 kardel if (hints != NULL) {
163 1.1 kardel ai->ai_flags = hints->ai_flags;
164 1.1 kardel ai->ai_family = hints->ai_family;
165 1.1 kardel ai->ai_socktype = hints->ai_socktype;
166 1.1 kardel ai->ai_protocol = hints->ai_protocol;
167 1.1 kardel
168 1.1 kardel family = hints->ai_family;
169 1.1 kardel socktype = hints->ai_socktype;
170 1.1 kardel protocol = hints->ai_protocol;
171 1.1 kardel flags = hints->ai_flags;
172 1.1 kardel
173 1.1 kardel switch (family) {
174 1.1 kardel case AF_UNSPEC:
175 1.1 kardel switch (hints->ai_socktype) {
176 1.1 kardel case SOCK_STREAM:
177 1.1 kardel proto = "tcp";
178 1.1 kardel break;
179 1.1 kardel case SOCK_DGRAM:
180 1.1 kardel proto = "udp";
181 1.1 kardel break;
182 1.1 kardel }
183 1.1 kardel break;
184 1.1 kardel case AF_INET:
185 1.1 kardel case AF_INET6:
186 1.1 kardel switch (hints->ai_socktype) {
187 1.1 kardel case 0:
188 1.1 kardel break;
189 1.1 kardel case SOCK_STREAM:
190 1.1 kardel proto = "tcp";
191 1.1 kardel break;
192 1.1 kardel case SOCK_DGRAM:
193 1.1 kardel proto = "udp";
194 1.1 kardel break;
195 1.1 kardel case SOCK_RAW:
196 1.1 kardel break;
197 1.1 kardel default:
198 1.1 kardel return (EAI_SOCKTYPE);
199 1.1 kardel }
200 1.1 kardel break;
201 1.1 kardel #ifdef AF_LOCAL
202 1.1 kardel case AF_LOCAL:
203 1.1 kardel switch (hints->ai_socktype) {
204 1.1 kardel case 0:
205 1.1 kardel break;
206 1.1 kardel case SOCK_STREAM:
207 1.1 kardel break;
208 1.1 kardel case SOCK_DGRAM:
209 1.1 kardel break;
210 1.1 kardel default:
211 1.1 kardel return (EAI_SOCKTYPE);
212 1.1 kardel }
213 1.1 kardel break;
214 1.1 kardel #endif
215 1.1 kardel default:
216 1.1 kardel return (EAI_FAMILY);
217 1.1 kardel }
218 1.1 kardel } else {
219 1.1 kardel protocol = 0;
220 1.1 kardel family = 0;
221 1.1 kardel socktype = 0;
222 1.1 kardel flags = 0;
223 1.1 kardel }
224 1.1 kardel
225 1.1 kardel rval = do_nodename(nodename, ai, hints);
226 1.1 kardel if (rval != 0) {
227 1.1 kardel freeaddrinfo(ai);
228 1.1 kardel return (rval);
229 1.1 kardel }
230 1.1 kardel
231 1.1 kardel /*
232 1.1 kardel * First, look up the service name (port) if it was
233 1.1 kardel * requested. If the socket type wasn't specified, then
234 1.1 kardel * try and figure it out.
235 1.1 kardel */
236 1.1 kardel if (servname != NULL) {
237 1.1 kardel char *e;
238 1.1 kardel
239 1.1 kardel port = strtol(servname, &e, 10);
240 1.1 kardel if (*e == '\0') {
241 1.1 kardel if (socktype == 0)
242 1.1 kardel return (EAI_SOCKTYPE);
243 1.1 kardel if (port < 0 || port > 65535)
244 1.1 kardel return (EAI_SERVICE);
245 1.1 kardel port = htons((unsigned short) port);
246 1.1 kardel } else {
247 1.1 kardel sp = getservbyname(servname, proto);
248 1.1 kardel if (sp == NULL)
249 1.1 kardel return (EAI_SERVICE);
250 1.1 kardel port = sp->s_port;
251 1.1 kardel if (socktype == 0) {
252 1.1 kardel if (strcmp(sp->s_proto, "tcp") == 0)
253 1.1 kardel socktype = SOCK_STREAM;
254 1.1 kardel else if (strcmp(sp->s_proto, "udp") == 0)
255 1.1 kardel socktype = SOCK_DGRAM;
256 1.1 kardel }
257 1.1 kardel }
258 1.1 kardel } else
259 1.1 kardel port = 0;
260 1.1 kardel
261 1.1 kardel /*
262 1.1 kardel *
263 1.1 kardel * Set up the port number
264 1.1 kardel */
265 1.1 kardel if (ai->ai_family == AF_INET)
266 1.1 kardel ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
267 1.1 kardel else if (ai->ai_family == AF_INET6)
268 1.1 kardel ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
269 1.1 kardel *res = ai;
270 1.1 kardel return (0);
271 1.1 kardel }
272 1.1 kardel
273 1.1 kardel void
274 1.1 kardel freeaddrinfo(struct addrinfo *ai)
275 1.1 kardel {
276 1.1 kardel if (ai->ai_canonname != NULL)
277 1.1 kardel {
278 1.1 kardel free(ai->ai_canonname);
279 1.1 kardel ai->ai_canonname = NULL;
280 1.1 kardel }
281 1.1 kardel if (ai->ai_addr != NULL)
282 1.1 kardel {
283 1.1 kardel free(ai->ai_addr);
284 1.1 kardel ai->ai_addr = NULL;
285 1.1 kardel }
286 1.1 kardel free(ai);
287 1.1 kardel ai = NULL;
288 1.1 kardel }
289 1.1 kardel
290 1.1 kardel int
291 1.1 kardel getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
292 1.1 kardel size_t hostlen, char *serv, size_t servlen, int flags)
293 1.1 kardel {
294 1.1 kardel struct hostent *hp;
295 1.1 kardel int namelen;
296 1.1 kardel
297 1.1 kardel if (sa->sa_family != AF_INET)
298 1.1 kardel return (EAI_FAMILY);
299 1.1 kardel hp = gethostbyaddr(
300 1.1 kardel (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
301 1.1 kardel 4, AF_INET);
302 1.1 kardel if (hp == NULL) {
303 1.1 kardel if (h_errno == TRY_AGAIN)
304 1.1 kardel return (EAI_AGAIN);
305 1.1 kardel else
306 1.1 kardel return (EAI_FAIL);
307 1.1 kardel }
308 1.1 kardel if (host != NULL && hostlen > 0) {
309 1.1 kardel /*
310 1.1 kardel * Don't exceed buffer
311 1.1 kardel */
312 1.1 kardel namelen = min(strlen(hp->h_name), hostlen - 1);
313 1.1 kardel if (namelen > 0) {
314 1.1 kardel strncpy(host, hp->h_name, namelen);
315 1.1 kardel host[namelen] = '\0';
316 1.1 kardel }
317 1.1 kardel }
318 1.1 kardel return (0);
319 1.1 kardel }
320 1.1 kardel
321 1.1 kardel char *
322 1.1 kardel gai_strerror(int ecode)
323 1.1 kardel {
324 1.1 kardel if (ecode < 0 || ecode > EAI_MAX)
325 1.1 kardel ecode = EAI_MAX;
326 1.1 kardel return ai_errlist[ecode];
327 1.1 kardel }
328 1.1 kardel
329 1.1 kardel static int
330 1.1 kardel do_nodename(
331 1.1 kardel const char *nodename,
332 1.1 kardel struct addrinfo *ai,
333 1.1 kardel const struct addrinfo *hints)
334 1.1 kardel {
335 1.1 kardel struct hostent *hp = NULL;
336 1.1 kardel struct sockaddr_in *sockin;
337 1.1 kardel struct sockaddr_in6 *sockin6;
338 1.1 kardel int errval;
339 1.1 kardel
340 1.1 kardel ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
341 1.1 kardel if (ai->ai_addr == NULL)
342 1.1 kardel return (EAI_MEMORY);
343 1.1 kardel
344 1.1 kardel /*
345 1.1 kardel * For an empty node name just use the wildcard.
346 1.1 kardel * NOTE: We need to assume that the address family is
347 1.1 kardel * set elsewhere so that we can set the appropriate wildcard
348 1.1 kardel */
349 1.1 kardel if (nodename == NULL) {
350 1.1 kardel ai->ai_addrlen = sizeof(struct sockaddr_storage);
351 1.1 kardel if (ai->ai_family == AF_INET)
352 1.1 kardel {
353 1.1 kardel sockin = (struct sockaddr_in *)ai->ai_addr;
354 1.1 kardel sockin->sin_family = (short) ai->ai_family;
355 1.1 kardel sockin->sin_addr.s_addr = htonl(INADDR_ANY);
356 1.1 kardel }
357 1.1 kardel else
358 1.1 kardel {
359 1.1 kardel sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
360 1.1 kardel sockin6->sin6_family = (short) ai->ai_family;
361 1.1 kardel /*
362 1.1 kardel * we have already zeroed out the address
363 1.1 kardel * so we don't actually need to do this
364 1.1 kardel * This assignment is causing problems so
365 1.1 kardel * we don't do what this would do.
366 1.1 kardel sockin6->sin6_addr = in6addr_any;
367 1.1 kardel */
368 1.1 kardel }
369 1.1 kardel #ifdef ISC_PLATFORM_HAVESALEN
370 1.1 kardel ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
371 1.1 kardel #endif
372 1.1 kardel
373 1.1 kardel return (0);
374 1.1 kardel }
375 1.1 kardel
376 1.1 kardel /*
377 1.1 kardel * See if we have an IPv6 address
378 1.1 kardel */
379 1.1 kardel if(strchr(nodename, ':') != NULL) {
380 1.1 kardel if (inet_pton(AF_INET6, nodename,
381 1.1 kardel &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
382 1.1 kardel ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
383 1.1 kardel ai->ai_family = AF_INET6;
384 1.1 kardel ai->ai_addrlen = sizeof(struct sockaddr_in6);
385 1.1 kardel return (0);
386 1.1 kardel }
387 1.1 kardel }
388 1.1 kardel
389 1.1 kardel /*
390 1.1 kardel * See if we have an IPv4 address
391 1.1 kardel */
392 1.1 kardel if (inet_pton(AF_INET, nodename,
393 1.1 kardel &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
394 1.1 kardel ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
395 1.1 kardel ai->ai_family = AF_INET;
396 1.1 kardel ai->ai_addrlen = sizeof(struct sockaddr_in);
397 1.1 kardel return (0);
398 1.1 kardel }
399 1.1 kardel
400 1.1 kardel /*
401 1.1 kardel * If the numeric host flag is set, don't attempt resolution
402 1.1 kardel */
403 1.1 kardel if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
404 1.1 kardel return (EAI_NONAME);
405 1.1 kardel
406 1.1 kardel /*
407 1.1 kardel * Look for a name
408 1.1 kardel */
409 1.1 kardel
410 1.1 kardel errval = DNSlookup_name(nodename, AF_INET, &hp);
411 1.1 kardel
412 1.1 kardel if (hp == NULL) {
413 1.1 kardel if (errval == TRY_AGAIN || errval == EAI_AGAIN)
414 1.1 kardel return (EAI_AGAIN);
415 1.1 kardel else if (errval == EAI_NONAME) {
416 1.1 kardel if (inet_pton(AF_INET, nodename,
417 1.1 kardel &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
418 1.1 kardel ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
419 1.1 kardel ai->ai_family = AF_INET;
420 1.1 kardel ai->ai_addrlen = sizeof(struct sockaddr_in);
421 1.1 kardel return (0);
422 1.1 kardel }
423 1.1 kardel return (errval);
424 1.1 kardel }
425 1.1 kardel else
426 1.1 kardel {
427 1.1 kardel return (errval);
428 1.1 kardel }
429 1.1 kardel }
430 1.1 kardel ai->ai_family = hp->h_addrtype;
431 1.1 kardel ai->ai_addrlen = sizeof(struct sockaddr);
432 1.1 kardel sockin = (struct sockaddr_in *)ai->ai_addr;
433 1.1 kardel memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
434 1.1 kardel ai->ai_addr->sa_family = hp->h_addrtype;
435 1.1 kardel #ifdef ISC_PLATFORM_HAVESALEN
436 1.1 kardel ai->ai_addr->sa_len = sizeof(struct sockaddr);
437 1.1 kardel #endif
438 1.1 kardel if (hints != NULL && hints->ai_flags & AI_CANONNAME)
439 1.1 kardel ai->ai_canonname = estrdup(hp->h_name);
440 1.1 kardel return (0);
441 1.1 kardel }
442 1.1 kardel
443 1.1 kardel #endif /* !ISC_PLATFORM_HAVEIPV6 */
444