]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/ntp/libntp/ntp_rfc2553.c
o Fix invalid TCP checksums with pf(4). [EN-16:02.pf]
[FreeBSD/releng/9.3.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                 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
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
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
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
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 *
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
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 */