]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/libntp/ntp_rfc2553.c
Upgrade NTP to 4.2.8p4.
[FreeBSD/releng/10.2.git] / contrib / ntp / libntp / ntp_rfc2553.c
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 *
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 *
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 *
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                 REQUIRE(ai_src->ai_addrlen <= sizeof(sockaddr_u));
207                 memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
208                 ai_cpy->ai_addr = &psau->sa;
209                 ++psau;
210                 if (NULL != ai_cpy->ai_canonname) {
211                         ai_cpy->ai_canonname = pcanon;
212                         str_octets = 1 + strlen(ai_src->ai_canonname);
213                         memcpy(pcanon, ai_src->ai_canonname, str_octets);
214                         pcanon += str_octets;
215                 }
216                 if (NULL != ai_cpy->ai_next) {
217                         if (just_one)
218                                 ai_cpy->ai_next = NULL;
219                         else
220                                 ai_cpy->ai_next = ai_cpy + 1;
221                 }
222                 ++ai_cpy;
223         }
224         ENSURE(pcanon == ((char *)dst + octets));
225
226         return dst;
227 }
228
229
230 #ifndef ISC_PLATFORM_HAVEIPV6
231
232 static char *ai_errlist[] = {
233         "Success",
234         "Address family for hostname not supported",    /* EAI_ADDRFAMILY */
235         "Temporary failure in name resolution",         /* EAI_AGAIN      */
236         "Invalid value for ai_flags",                   /* EAI_BADFLAGS   */
237         "Non-recoverable failure in name resolution",   /* EAI_FAIL       */
238         "ai_family not supported",                      /* EAI_FAMILY     */
239         "Memory allocation failure",                    /* EAI_MEMORY     */
240         "No address associated with hostname",          /* EAI_NODATA     */
241         "hostname nor servname provided, or not known", /* EAI_NONAME     */
242         "servname not supported for ai_socktype",       /* EAI_SERVICE    */
243         "ai_socktype not supported",                    /* EAI_SOCKTYPE   */
244         "System error returned in errno",               /* EAI_SYSTEM     */
245         "Invalid value for hints",                      /* EAI_BADHINTS   */
246         "Resolved protocol is unknown",                 /* EAI_PROTOCOL   */
247         "Unknown error",                                /* EAI_MAX        */
248 };
249
250 /*
251  * Local declaration
252  */
253 int
254 DNSlookup_name(
255         const char *name,
256         int ai_family,
257         struct hostent **Addresses
258 );
259
260 #ifndef SYS_WINNT
261 /*
262  * Encapsulate gethostbyname to control the error code
263  */
264 int
265 DNSlookup_name(
266         const char *name,
267         int ai_family,
268         struct hostent **Addresses
269 )
270 {
271         *Addresses = gethostbyname(name);
272         return (h_errno);
273 }
274 #endif
275
276 static  int do_nodename (const char *nodename, struct addrinfo *ai,
277     const struct addrinfo *hints);
278
279 int
280 getaddrinfo (const char *nodename, const char *servname,
281         const struct addrinfo *hints, struct addrinfo **res)
282 {
283         int rval;
284         struct servent *sp;
285         struct addrinfo *ai = NULL;
286         int port;
287         const char *proto = NULL;
288         int family, socktype, flags, protocol;
289
290
291         /*
292          * If no name is provide just return an error
293          */
294         if (nodename == NULL && servname == NULL)
295                 return (EAI_NONAME);
296         
297         ai = calloc(sizeof(struct addrinfo), 1);
298         if (ai == NULL)
299                 return (EAI_MEMORY);
300
301         /*
302          * Copy default values from hints, if available
303          */
304         if (hints != NULL) {
305                 ai->ai_flags = hints->ai_flags;
306                 ai->ai_family = hints->ai_family;
307                 ai->ai_socktype = hints->ai_socktype;
308                 ai->ai_protocol = hints->ai_protocol;
309
310                 family = hints->ai_family;
311                 socktype = hints->ai_socktype;
312                 protocol = hints->ai_protocol;
313                 flags = hints->ai_flags;
314
315                 switch (family) {
316                 case AF_UNSPEC:
317                         switch (hints->ai_socktype) {
318                         case SOCK_STREAM:
319                                 proto = "tcp";
320                                 break;
321                         case SOCK_DGRAM:
322                                 proto = "udp";
323                                 break;
324                         }
325                         break;
326                 case AF_INET:
327                 case AF_INET6:
328                         switch (hints->ai_socktype) {
329                         case 0:
330                                 break;
331                         case SOCK_STREAM:
332                                 proto = "tcp";
333                                 break;
334                         case SOCK_DGRAM:
335                                 proto = "udp";
336                                 break;
337                         case SOCK_RAW:
338                                 break;
339                         default:
340                                 return (EAI_SOCKTYPE);
341                         }
342                         break;
343 #ifdef  AF_LOCAL
344                 case AF_LOCAL:
345                         switch (hints->ai_socktype) {
346                         case 0:
347                                 break;
348                         case SOCK_STREAM:
349                                 break;
350                         case SOCK_DGRAM:
351                                 break;
352                         default:
353                                 return (EAI_SOCKTYPE);
354                         }
355                         break;
356 #endif
357                 default:
358                         return (EAI_FAMILY);
359                 }
360         } else {
361                 protocol = 0;
362                 family = 0;
363                 socktype = 0;
364                 flags = 0;
365         }
366
367         rval = do_nodename(nodename, ai, hints);
368         if (rval != 0) {
369                 freeaddrinfo(ai);
370                 return (rval);
371         }
372
373         /*
374          * First, look up the service name (port) if it was
375          * requested.  If the socket type wasn't specified, then
376          * try and figure it out.
377          */
378         if (servname != NULL) {
379                 char *e;
380
381                 port = strtol(servname, &e, 10);
382                 if (*e == '\0') {
383                         if (socktype == 0)
384                                 return (EAI_SOCKTYPE);
385                         if (port < 0 || port > 65535)
386                                 return (EAI_SERVICE);
387                         port = htons((unsigned short) port);
388                 } else {
389                         sp = getservbyname(servname, proto);
390                         if (sp == NULL)
391                                 return (EAI_SERVICE);
392                         port = sp->s_port;
393                         if (socktype == 0) {
394                                 if (strcmp(sp->s_proto, "tcp") == 0)
395                                         socktype = SOCK_STREAM;
396                                 else if (strcmp(sp->s_proto, "udp") == 0)
397                                         socktype = SOCK_DGRAM;
398                         }
399                 }
400         } else
401                 port = 0;
402
403         /*
404          *
405          * Set up the port number
406          */
407         if (ai->ai_family == AF_INET)
408                 ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
409         else if (ai->ai_family == AF_INET6)
410                 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
411         *res = ai;
412         return (0);
413 }
414
415 void
416 freeaddrinfo(struct addrinfo *ai)
417 {
418         if (ai->ai_canonname != NULL)
419         {
420                 free(ai->ai_canonname);
421                 ai->ai_canonname = NULL;
422         }
423         if (ai->ai_addr != NULL)
424         {
425                 free(ai->ai_addr);
426                 ai->ai_addr = NULL;
427         }
428         free(ai);
429         ai = NULL;
430 }
431
432 int
433 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
434         size_t hostlen, char *serv, size_t servlen, int flags)
435 {
436         struct hostent *hp;
437
438         if (sa->sa_family != AF_INET)
439                 return (EAI_FAMILY);
440         hp = gethostbyaddr(
441             (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
442             4, AF_INET);
443         if (hp == NULL) {
444                 if (h_errno == TRY_AGAIN)
445                         return (EAI_AGAIN);
446                 else
447                         return (EAI_FAIL);
448         }
449         if (host != NULL && hostlen > 0)
450                 strlcpy(host, hp->h_name, hostlen);
451         return (0);
452 }
453
454 char *
455 gai_strerror(int ecode)
456 {
457         if (ecode < 0 || ecode > EAI_MAX)
458                 ecode = EAI_MAX;
459         return ai_errlist[ecode];
460 }
461
462 static int
463 do_nodename(
464         const char *nodename,
465         struct addrinfo *ai,
466         const struct addrinfo *hints)
467 {
468         struct hostent *hp = NULL;
469         struct sockaddr_in *sockin;
470         struct sockaddr_in6 *sockin6;
471         int errval;
472
473         ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
474         if (ai->ai_addr == NULL)
475                 return (EAI_MEMORY);
476
477         /*
478          * For an empty node name just use the wildcard.
479          * NOTE: We need to assume that the address family is
480          * set elsewhere so that we can set the appropriate wildcard
481          */
482         if (nodename == NULL) {
483                 ai->ai_addrlen = sizeof(struct sockaddr_storage);
484                 if (ai->ai_family == AF_INET)
485                 {
486                         sockin = (struct sockaddr_in *)ai->ai_addr;
487                         sockin->sin_family = (short) ai->ai_family;
488                         sockin->sin_addr.s_addr = htonl(INADDR_ANY);
489                 }
490                 else
491                 {
492                         sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
493                         sockin6->sin6_family = (short) ai->ai_family;
494                         /*
495                          * we have already zeroed out the address
496                          * so we don't actually need to do this
497                          * This assignment is causing problems so
498                          * we don't do what this would do.
499                          sockin6->sin6_addr = in6addr_any;
500                          */
501                 }
502 #ifdef ISC_PLATFORM_HAVESALEN
503                 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
504 #endif
505
506                 return (0);
507         }
508
509         /*
510          * See if we have an IPv6 address
511          */
512         if(strchr(nodename, ':') != NULL) {
513                 if (inet_pton(AF_INET6, nodename,
514                     &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
515                         ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
516                         ai->ai_family = AF_INET6;
517                         ai->ai_addrlen = sizeof(struct sockaddr_in6);
518                         return (0);
519                 }
520         }
521
522         /*
523          * See if we have an IPv4 address
524          */
525         if (inet_pton(AF_INET, nodename,
526             &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
527                 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
528                 ai->ai_family = AF_INET;
529                 ai->ai_addrlen = sizeof(struct sockaddr_in);
530                 return (0);
531         }
532
533         /*
534          * If the numeric host flag is set, don't attempt resolution
535          */
536         if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
537                 return (EAI_NONAME);
538
539         /*
540          * Look for a name
541          */
542
543         errval = DNSlookup_name(nodename, AF_INET, &hp);
544
545         if (hp == NULL) {
546                 if (errval == TRY_AGAIN || errval == EAI_AGAIN)
547                         return (EAI_AGAIN);
548                 else if (errval == EAI_NONAME) {
549                         if (inet_pton(AF_INET, nodename,
550                             &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
551                                 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
552                                 ai->ai_family = AF_INET;
553                                 ai->ai_addrlen = sizeof(struct sockaddr_in);
554                                 return (0);
555                         }
556                         return (errval);
557                 }
558                 else
559                 {
560                         return (errval);
561                 }
562         }
563         ai->ai_family = hp->h_addrtype;
564         ai->ai_addrlen = sizeof(struct sockaddr);
565         sockin = (struct sockaddr_in *)ai->ai_addr;
566         memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
567         ai->ai_addr->sa_family = hp->h_addrtype;
568 #ifdef ISC_PLATFORM_HAVESALEN
569         ai->ai_addr->sa_len = sizeof(struct sockaddr);
570 #endif
571         if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
572                 ai->ai_canonname = estrdup(hp->h_name);
573         return (0);
574 }
575
576 #endif /* !ISC_PLATFORM_HAVEIPV6 */