]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/libntp/ntp_rfc2553.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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 #include <sys/socket.h>
73 #include <isc/net.h>
74 #ifdef HAVE_NETINET_IN_H
75 #include <netinet/in.h>
76 #endif
77 #include "ntp_rfc2553.h"
78
79 #include "ntpd.h"
80 #include "ntp_malloc.h"
81 #include "ntp_stdlib.h"
82 #include "ntp_string.h"
83
84 #ifndef ISC_PLATFORM_HAVEIPV6
85
86 static char *ai_errlist[] = {
87         "Success",
88         "Address family for hostname not supported",    /* EAI_ADDRFAMILY */
89         "Temporary failure in name resolution",         /* EAI_AGAIN      */
90         "Invalid value for ai_flags",                   /* EAI_BADFLAGS   */
91         "Non-recoverable failure in name resolution",   /* EAI_FAIL       */
92         "ai_family not supported",                      /* EAI_FAMILY     */
93         "Memory allocation failure",                    /* EAI_MEMORY     */
94         "No address associated with hostname",          /* EAI_NODATA     */
95         "hostname nor servname provided, or not known", /* EAI_NONAME     */
96         "servname not supported for ai_socktype",       /* EAI_SERVICE    */
97         "ai_socktype not supported",                    /* EAI_SOCKTYPE   */
98         "System error returned in errno",               /* EAI_SYSTEM     */
99         "Invalid value for hints",                      /* EAI_BADHINTS   */
100         "Resolved protocol is unknown",                 /* EAI_PROTOCOL   */
101         "Unknown error",                                /* EAI_MAX        */
102 };
103
104 /*
105  * Local declaration
106  */
107 int
108 DNSlookup_name(
109         const char *name,
110         int ai_family,
111         struct hostent **Addresses
112 );
113
114 #ifndef SYS_WINNT
115 /*
116  * Encapsulate gethostbyname to control the error code
117  */
118 int
119 DNSlookup_name(
120         const char *name,
121         int ai_family,
122         struct hostent **Addresses
123 )
124 {
125         *Addresses = gethostbyname(name);
126         return (h_errno);
127 }
128 #endif
129
130 static  int do_nodename P((const char *nodename, struct addrinfo *ai,
131     const struct addrinfo *hints));
132
133 int
134 getaddrinfo (const char *nodename, const char *servname,
135         const struct addrinfo *hints, struct addrinfo **res)
136 {
137         int rval;
138         struct servent *sp;
139         struct addrinfo *ai = NULL;
140         int port;
141         const char *proto = NULL;
142         int family, socktype, flags, protocol;
143
144
145         /*
146          * If no name is provide just return an error
147          */
148         if (nodename == NULL && servname == NULL)
149                 return (EAI_NONAME);
150         
151         ai = calloc(sizeof(struct addrinfo), 1);
152         if (ai == NULL)
153                 return (EAI_MEMORY);
154
155         /*
156          * Copy default values from hints, if available
157          */
158         if (hints != NULL) {
159                 ai->ai_flags = hints->ai_flags;
160                 ai->ai_family = hints->ai_family;
161                 ai->ai_socktype = hints->ai_socktype;
162                 ai->ai_protocol = hints->ai_protocol;
163
164                 family = hints->ai_family;
165                 socktype = hints->ai_socktype;
166                 protocol = hints->ai_protocol;
167                 flags = hints->ai_flags;
168
169                 switch (family) {
170                 case AF_UNSPEC:
171                         switch (hints->ai_socktype) {
172                         case SOCK_STREAM:
173                                 proto = "tcp";
174                                 break;
175                         case SOCK_DGRAM:
176                                 proto = "udp";
177                                 break;
178                         }
179                         break;
180                 case AF_INET:
181                 case AF_INET6:
182                         switch (hints->ai_socktype) {
183                         case 0:
184                                 break;
185                         case SOCK_STREAM:
186                                 proto = "tcp";
187                                 break;
188                         case SOCK_DGRAM:
189                                 proto = "udp";
190                                 break;
191                         case SOCK_RAW:
192                                 break;
193                         default:
194                                 return (EAI_SOCKTYPE);
195                         }
196                         break;
197 #ifdef  AF_LOCAL
198                 case AF_LOCAL:
199                         switch (hints->ai_socktype) {
200                         case 0:
201                                 break;
202                         case SOCK_STREAM:
203                                 break;
204                         case SOCK_DGRAM:
205                                 break;
206                         default:
207                                 return (EAI_SOCKTYPE);
208                         }
209                         break;
210 #endif
211                 default:
212                         return (EAI_FAMILY);
213                 }
214         } else {
215                 protocol = 0;
216                 family = 0;
217                 socktype = 0;
218                 flags = 0;
219         }
220
221         rval = do_nodename(nodename, ai, hints);
222         if (rval != 0) {
223                 freeaddrinfo(ai);
224                 return (rval);
225         }
226
227         /*
228          * First, look up the service name (port) if it was
229          * requested.  If the socket type wasn't specified, then
230          * try and figure it out.
231          */
232         if (servname != NULL) {
233                 char *e;
234
235                 port = strtol(servname, &e, 10);
236                 if (*e == '\0') {
237                         if (socktype == 0)
238                                 return (EAI_SOCKTYPE);
239                         if (port < 0 || port > 65535)
240                                 return (EAI_SERVICE);
241                         port = htons((unsigned short) port);
242                 } else {
243                         sp = getservbyname(servname, proto);
244                         if (sp == NULL)
245                                 return (EAI_SERVICE);
246                         port = sp->s_port;
247                         if (socktype == 0) {
248                                 if (strcmp(sp->s_proto, "tcp") == 0)
249                                         socktype = SOCK_STREAM;
250                                 else if (strcmp(sp->s_proto, "udp") == 0)
251                                         socktype = SOCK_DGRAM;
252                         }
253                 }
254         } else
255                 port = 0;
256
257         /*
258          *
259          * Set up the port number
260          */
261         if (ai->ai_family == AF_INET)
262                 ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
263         else if (ai->ai_family == AF_INET6)
264                 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
265         *res = ai;
266         return (0);
267 }
268
269 void
270 freeaddrinfo(struct addrinfo *ai)
271 {
272         if (ai->ai_canonname != NULL)
273         {
274                 free(ai->ai_canonname);
275                 ai->ai_canonname = NULL;
276         }
277         if (ai->ai_addr != NULL)
278         {
279                 free(ai->ai_addr);
280                 ai->ai_addr = NULL;
281         }
282         free(ai);
283         ai = NULL;
284 }
285
286 int
287 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
288         size_t hostlen, char *serv, size_t servlen, int flags)
289 {
290         struct hostent *hp;
291         int namelen;
292
293         if (sa->sa_family != AF_INET)
294                 return (EAI_FAMILY);
295         hp = gethostbyaddr(
296             (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
297             4, AF_INET);
298         if (hp == NULL) {
299                 if (h_errno == TRY_AGAIN)
300                         return (EAI_AGAIN);
301                 else
302                         return (EAI_FAIL);
303         }
304         if (host != NULL && hostlen > 0) {
305                 /*
306                  * Don't exceed buffer
307                  */
308                 namelen = min(strlen(hp->h_name), hostlen - 1);
309                 if (namelen > 0) {
310                         strncpy(host, hp->h_name, namelen);
311                         host[namelen] = '\0';
312                 }
313         }
314         return (0);
315 }
316
317 char *
318 gai_strerror(int ecode)
319 {
320         if (ecode < 0 || ecode > EAI_MAX)
321                 ecode = EAI_MAX;
322         return ai_errlist[ecode];
323 }
324
325 static int
326 do_nodename(
327         const char *nodename,
328         struct addrinfo *ai,
329         const struct addrinfo *hints)
330 {
331         struct hostent *hp = NULL;
332         struct sockaddr_in *sockin;
333         struct sockaddr_in6 *sockin6;
334         int errval;
335
336         ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
337         if (ai->ai_addr == NULL)
338                 return (EAI_MEMORY);
339
340         /*
341          * For an empty node name just use the wildcard.
342          * NOTE: We need to assume that the address family is
343          * set elsewhere so that we can set the appropriate wildcard
344          */
345         if (nodename == NULL) {
346                 ai->ai_addrlen = sizeof(struct sockaddr_storage);
347                 if (ai->ai_family == AF_INET)
348                 {
349                         sockin = (struct sockaddr_in *)ai->ai_addr;
350                         sockin->sin_family = (short) ai->ai_family;
351                         sockin->sin_addr.s_addr = htonl(INADDR_ANY);
352                 }
353                 else
354                 {
355                         sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
356                         sockin6->sin6_family = (short) ai->ai_family;
357                         /*
358                          * we have already zeroed out the address
359                          * so we don't actually need to do this
360                          * This assignment is causing problems so
361                          * we don't do what this would do.
362                          sockin6->sin6_addr = in6addr_any;
363                          */
364                 }
365 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
366                 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
367 #endif
368
369                 return (0);
370         }
371
372         /*
373          * See if we have an IPv6 address
374          */
375         if(strchr(nodename, ':') != NULL) {
376                 if (inet_pton(AF_INET6, nodename,
377                     &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
378                         ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
379                         ai->ai_family = AF_INET6;
380                         ai->ai_addrlen = sizeof(struct sockaddr_in6);
381                         return (0);
382                 }
383         }
384
385         /*
386          * See if we have an IPv4 address
387          */
388         if (inet_pton(AF_INET, nodename,
389             &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
390                 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
391                 ai->ai_family = AF_INET;
392                 ai->ai_addrlen = sizeof(struct sockaddr_in);
393                 return (0);
394         }
395
396         /*
397          * If the numeric host flag is set, don't attempt resolution
398          */
399         if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
400                 return (EAI_NONAME);
401
402         /*
403          * Look for a name
404          */
405
406         errval = DNSlookup_name(nodename, AF_INET, &hp);
407
408         if (hp == NULL) {
409                 if (errval == TRY_AGAIN || errval == EAI_AGAIN)
410                         return (EAI_AGAIN);
411                 else if (errval == EAI_NONAME) {
412                         if (inet_pton(AF_INET, nodename,
413                             &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
414                                 ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
415                                 ai->ai_family = AF_INET;
416                                 ai->ai_addrlen = sizeof(struct sockaddr_in);
417                                 return (0);
418                         }
419                         return (errval);
420                 }
421                 else
422                 {
423                         return (errval);
424                 }
425         }
426         ai->ai_family = hp->h_addrtype;
427         ai->ai_addrlen = sizeof(struct sockaddr);
428         sockin = (struct sockaddr_in *)ai->ai_addr;
429         memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
430         ai->ai_addr->sa_family = hp->h_addrtype;
431 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
432         ai->ai_addr->sa_len = sizeof(struct sockaddr);
433 #endif
434         if (hints != NULL && hints->ai_flags & AI_CANONNAME) {
435                 ai->ai_canonname = malloc(strlen(hp->h_name) + 1);
436                 if (ai->ai_canonname == NULL)
437                         return (EAI_MEMORY);
438                 strcpy(ai->ai_canonname, hp->h_name);
439         }
440         return (0);
441 }
442
443 #endif /* !ISC_PLATFORM_HAVEIPV6 */