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_string.h"
84 #include "ntp_debug.h"
85
86
87 /*
88 * copy_addrinfo() - copy a single addrinfo to malloc()'d block.
89 * copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
90 *
91 * Copies an addrinfo list and its associated data to a contiguous block
92 * of storage from emalloc(). Callback routines invoked via
93 * getaddrinfo_sometime() have access to the resulting addrinfo list
94 * only until they return. This routine provides an easy way to make a
95 * persistent copy. Although the list provided to gai_sometime_callback
96 * routines is similarly contiguous, to keep this code usable in any
97 * context where we might want to duplicate an addrinfo list, it does
98 * not require the input list be contiguous.
99 *
100 * The returned list head pointer is passed to free() to release the
101 * entire list.
102 *
103 * In keeping with the rest of the NTP distribution, sockaddr_u is used
104 * in preference to struct sockaddr_storage, which is a member of the
105 * former union and so compatible.
106 *
107 * The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6
108 * not being defined, copy_addrinfo_*() are exceptions.
109 */
110 struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
111 #ifdef EREALLOC_CALLSITE
112 ,
113 const char *, int
114 #endif
115 );
116
117
118 struct addrinfo *
copy_addrinfo_impl(const struct addrinfo * src,const char * caller_file,int caller_line)119 copy_addrinfo_impl(
120 const struct addrinfo * src
121 #ifdef EREALLOC_CALLSITE
122 ,
123 const char * caller_file,
124 int caller_line
125 #endif
126 )
127 {
128 return copy_addrinfo_common(src, TRUE
129 #ifdef EREALLOC_CALLSITE
130 ,
131 caller_file, caller_line
132 #endif
133 );
134 }
135
136
137 struct addrinfo *
copy_addrinfo_list_impl(const struct addrinfo * src,const char * caller_file,int caller_line)138 copy_addrinfo_list_impl(
139 const struct addrinfo * src
140 #ifdef EREALLOC_CALLSITE
141 ,
142 const char * caller_file,
143 int caller_line
144 #endif
145 )
146 {
147 return copy_addrinfo_common(src, FALSE
148 #ifdef EREALLOC_CALLSITE
149 ,
150 caller_file, caller_line
151 #endif
152 );
153 }
154
155
156 struct addrinfo *
copy_addrinfo_common(const struct addrinfo * src,int just_one,const char * caller_file,int caller_line)157 copy_addrinfo_common(
158 const struct addrinfo * src,
159 int just_one
160 #ifdef EREALLOC_CALLSITE
161 ,
162 const char * caller_file,
163 int caller_line
164 #endif
165 )
166 {
167 const struct addrinfo * ai_src;
168 const struct addrinfo * ai_nxt;
169 struct addrinfo * ai_cpy;
170 struct addrinfo * dst;
171 sockaddr_u * psau;
172 char * pcanon;
173 u_int elements;
174 size_t octets;
175 size_t canons_octets;
176 size_t str_octets;
177
178 elements = 0;
179 canons_octets = 0;
180
181 for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
182 if (just_one)
183 ai_nxt = NULL;
184 else
185 ai_nxt = ai_src->ai_next;
186 ++elements;
187 if (NULL != ai_src->ai_canonname)
188 canons_octets += 1 + strlen(ai_src->ai_canonname);
189 }
190
191 octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
192 octets += canons_octets;
193
194 dst = erealloczsite(NULL, octets, 0, TRUE, caller_file,
195 caller_line);
196 ai_cpy = dst;
197 psau = (void *)(ai_cpy + elements);
198 pcanon = (void *)(psau + elements);
199
200 for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
201 if (just_one)
202 ai_nxt = NULL;
203 else
204 ai_nxt = ai_src->ai_next;
205 *ai_cpy = *ai_src;
206 DEBUG_INSIST(ai_cpy->ai_canonname == ai_src->ai_canonname);
207 INSIST(ai_src->ai_addrlen <= sizeof(sockaddr_u));
208 memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
209 ai_cpy->ai_addr = &psau->sa;
210 ++psau;
211 if (NULL != ai_src->ai_canonname) {
212 ai_cpy->ai_canonname = pcanon;
213 str_octets = 1 + strlen(ai_src->ai_canonname);
214 memcpy(pcanon, ai_src->ai_canonname, str_octets);
215 pcanon += str_octets;
216 }
217 if (NULL != ai_cpy->ai_next) {
218 if (just_one)
219 ai_cpy->ai_next = NULL;
220 else
221 ai_cpy->ai_next = ai_cpy + 1;
222 }
223 ++ai_cpy;
224 }
225 ENSURE(pcanon == ((char *)dst + octets));
226
227 return dst;
228 }
229
230
231 #ifndef ISC_PLATFORM_HAVEIPV6
232
233 static char *ai_errlist[] = {
234 "Success",
235 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
236 "Temporary failure in name resolution", /* EAI_AGAIN */
237 "Invalid value for ai_flags", /* EAI_BADFLAGS */
238 "Non-recoverable failure in name resolution", /* EAI_FAIL */
239 "ai_family not supported", /* EAI_FAMILY */
240 "Memory allocation failure", /* EAI_MEMORY */
241 "No address associated with hostname", /* EAI_NODATA */
242 "hostname nor servname provided, or not known", /* EAI_NONAME */
243 "servname not supported for ai_socktype", /* EAI_SERVICE */
244 "ai_socktype not supported", /* EAI_SOCKTYPE */
245 "System error returned in errno", /* EAI_SYSTEM */
246 "Invalid value for hints", /* EAI_BADHINTS */
247 "Resolved protocol is unknown", /* EAI_PROTOCOL */
248 "Unknown error", /* EAI_MAX */
249 };
250
251 /*
252 * Local declaration
253 */
254 int
255 DNSlookup_name(
256 const char *name,
257 int ai_family,
258 struct hostent **Addresses
259 );
260
261 #ifndef SYS_WINNT
262 /*
263 * Encapsulate gethostbyname to control the error code
264 */
265 int
DNSlookup_name(const char * name,int ai_family,struct hostent ** Addresses)266 DNSlookup_name(
267 const char *name,
268 int ai_family,
269 struct hostent **Addresses
270 )
271 {
272 *Addresses = gethostbyname(name);
273 return (h_errno);
274 }
275 #endif
276
277 static int do_nodename (const char *nodename, struct addrinfo *ai,
278 const struct addrinfo *hints);
279
280 int
getaddrinfo(const char * nodename,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)281 getaddrinfo (const char *nodename, const char *servname,
282 const struct addrinfo *hints, struct addrinfo **res)
283 {
284 int rval;
285 struct servent *sp;
286 struct addrinfo *ai = NULL;
287 int port;
288 const char *proto = NULL;
289 int family, socktype, flags, protocol;
290
291
292 /*
293 * If no name is provide just return an error
294 */
295 if (nodename == NULL && servname == NULL)
296 return (EAI_NONAME);
297
298 ai = calloc(sizeof(struct addrinfo), 1);
299 if (ai == NULL)
300 return (EAI_MEMORY);
301
302 /*
303 * Copy default values from hints, if available
304 */
305 if (hints != NULL) {
306 ai->ai_flags = hints->ai_flags;
307 ai->ai_family = hints->ai_family;
308 ai->ai_socktype = hints->ai_socktype;
309 ai->ai_protocol = hints->ai_protocol;
310
311 family = hints->ai_family;
312 socktype = hints->ai_socktype;
313 protocol = hints->ai_protocol;
314 flags = hints->ai_flags;
315
316 switch (family) {
317 case AF_UNSPEC:
318 switch (hints->ai_socktype) {
319 case SOCK_STREAM:
320 proto = "tcp";
321 break;
322 case SOCK_DGRAM:
323 proto = "udp";
324 break;
325 }
326 break;
327 case AF_INET:
328 case AF_INET6:
329 switch (hints->ai_socktype) {
330 case 0:
331 break;
332 case SOCK_STREAM:
333 proto = "tcp";
334 break;
335 case SOCK_DGRAM:
336 proto = "udp";
337 break;
338 case SOCK_RAW:
339 break;
340 default:
341 return (EAI_SOCKTYPE);
342 }
343 break;
344 #ifdef AF_LOCAL
345 case AF_LOCAL:
346 switch (hints->ai_socktype) {
347 case 0:
348 break;
349 case SOCK_STREAM:
350 break;
351 case SOCK_DGRAM:
352 break;
353 default:
354 return (EAI_SOCKTYPE);
355 }
356 break;
357 #endif
358 default:
359 return (EAI_FAMILY);
360 }
361 } else {
362 protocol = 0;
363 family = 0;
364 socktype = 0;
365 flags = 0;
366 }
367
368 rval = do_nodename(nodename, ai, hints);
369 if (rval != 0) {
370 freeaddrinfo(ai);
371 return (rval);
372 }
373
374 /*
375 * First, look up the service name (port) if it was
376 * requested. If the socket type wasn't specified, then
377 * try and figure it out.
378 */
379 if (servname != NULL) {
380 char *e;
381
382 port = strtol(servname, &e, 10);
383 if (*e == '\0') {
384 if (socktype == 0)
385 return (EAI_SOCKTYPE);
386 if (port < 0 || port > 65535)
387 return (EAI_SERVICE);
388 port = htons((unsigned short) port);
389 } else {
390 sp = getservbyname(servname, proto);
391 if (sp == NULL)
392 return (EAI_SERVICE);
393 port = sp->s_port;
394 if (socktype == 0) {
395 if (strcmp(sp->s_proto, "tcp") == 0)
396 socktype = SOCK_STREAM;
397 else if (strcmp(sp->s_proto, "udp") == 0)
398 socktype = SOCK_DGRAM;
399 }
400 }
401 } else
402 port = 0;
403
404 /*
405 *
406 * Set up the port number
407 */
408 if (ai->ai_family == AF_INET)
409 ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
410 else if (ai->ai_family == AF_INET6)
411 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
412 *res = ai;
413 return (0);
414 }
415
416 void
freeaddrinfo(struct addrinfo * ai)417 freeaddrinfo(struct addrinfo *ai)
418 {
419 if (ai->ai_canonname != NULL)
420 {
421 free(ai->ai_canonname);
422 ai->ai_canonname = NULL;
423 }
424 if (ai->ai_addr != NULL)
425 {
426 free(ai->ai_addr);
427 ai->ai_addr = NULL;
428 }
429 free(ai);
430 ai = NULL;
431 }
432
433 int
getnameinfo(const struct sockaddr * sa,u_int salen,char * host,size_t hostlen,char * serv,size_t servlen,int flags)434 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
435 size_t hostlen, char *serv, size_t servlen, int flags)
436 {
437 struct hostent *hp;
438
439 if (sa->sa_family != AF_INET)
440 return (EAI_FAMILY);
441 hp = gethostbyaddr(
442 (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
443 4, AF_INET);
444 if (hp == NULL) {
445 if (h_errno == TRY_AGAIN)
446 return (EAI_AGAIN);
447 else
448 return (EAI_FAIL);
449 }
450 if (host != NULL && hostlen > 0)
451 strlcpy(host, hp->h_name, hostlen);
452 return (0);
453 }
454
455 char *
gai_strerror(int ecode)456 gai_strerror(int ecode)
457 {
458 if (ecode < 0 || ecode > EAI_MAX)
459 ecode = EAI_MAX;
460 return ai_errlist[ecode];
461 }
462
463 static int
do_nodename(const char * nodename,struct addrinfo * ai,const struct addrinfo * hints)464 do_nodename(
465 const char *nodename,
466 struct addrinfo *ai,
467 const struct addrinfo *hints)
468 {
469 struct hostent *hp = NULL;
470 struct sockaddr_in *sockin;
471 struct sockaddr_in6 *sockin6;
472 int errval;
473
474 ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
475 if (ai->ai_addr == NULL)
476 return (EAI_MEMORY);
477
478 /*
479 * For an empty node name just use the wildcard.
480 * NOTE: We need to assume that the address family is
481 * set elsewhere so that we can set the appropriate wildcard
482 */
483 if (nodename == NULL) {
484 if (ai->ai_family == AF_INET)
485 {
486 ai->ai_addrlen = sizeof(struct sockaddr_in);
487 sockin = (struct sockaddr_in *)ai->ai_addr;
488 sockin->sin_family = (short) ai->ai_family;
489 sockin->sin_addr.s_addr = htonl(INADDR_ANY);
490 }
491 else
492 {
493 ai->ai_addrlen = sizeof(struct sockaddr_in6);
494 sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
495 sockin6->sin6_family = (short) ai->ai_family;
496 /*
497 * we have already zeroed out the address
498 * so we don't actually need to do this
499 * This assignment is causing problems so
500 * we don't do what this would do.
501 sockin6->sin6_addr = in6addr_any;
502 */
503 }
504 #ifdef ISC_PLATFORM_HAVESALEN
505 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
506 #endif
507
508 return (0);
509 }
510
511 /*
512 * See if we have an IPv6 address
513 */
514 if(strchr(nodename, ':') != NULL) {
515 if (inet_pton(AF_INET6, nodename,
516 &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
517 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
518 ai->ai_family = AF_INET6;
519 ai->ai_addrlen = sizeof(struct sockaddr_in6);
520 return (0);
521 }
522 }
523
524 /*
525 * See if we have an IPv4 address
526 */
527 if (inet_pton(AF_INET, nodename,
528 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
529 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
530 ai->ai_family = AF_INET;
531 ai->ai_addrlen = sizeof(struct sockaddr_in);
532 return (0);
533 }
534
535 /*
536 * If the numeric host flag is set, don't attempt resolution
537 */
538 if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
539 return (EAI_NONAME);
540
541 /*
542 * Look for a name
543 */
544
545 errval = DNSlookup_name(nodename, AF_INET, &hp);
546
547 if (hp == NULL) {
548 if (errval == TRY_AGAIN || errval == EAI_AGAIN)
549 return (EAI_AGAIN);
550 else if (errval == EAI_NONAME) {
551 if (inet_pton(AF_INET, nodename,
552 &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
553 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
554 ai->ai_family = AF_INET;
555 ai->ai_addrlen = sizeof(struct sockaddr_in);
556 return (0);
557 }
558 return (errval);
559 }
560 else
561 {
562 return (errval);
563 }
564 }
565 ai->ai_family = hp->h_addrtype;
566 ai->ai_addrlen = sizeof(struct sockaddr);
567 sockin = (struct sockaddr_in *)ai->ai_addr;
568 memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
569 ai->ai_addr->sa_family = hp->h_addrtype;
570 #ifdef ISC_PLATFORM_HAVESALEN
571 ai->ai_addr->sa_len = sizeof(struct sockaddr);
572 #endif
573 if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
574 ai->ai_canonname = estrdup(hp->h_name);
575 return (0);
576 }
577
578 #endif /* !ISC_PLATFORM_HAVEIPV6 */
579