]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/libntp/ntp_rfc2553.c
This commit was generated by cvs2svn to compensate for changes in r161653,
[FreeBSD/FreeBSD.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 #ifdef HAVE_CONFIG_H
69 #include <config.h>
70 #endif
71
72 #include <sys/types.h>
73 #include <ctype.h>
74 #include <sys/socket.h>
75 #include "ntp_rfc2553.h"
76 #ifdef HAVE_NETINET_IN_H
77 #include <netinet/in.h>
78 #endif
79 #include <netdb.h>
80
81 #include "ntpd.h"
82 #include "ntp_malloc.h"
83 #include "ntp_stdlib.h"
84 #include "ntp_string.h"
85
86 #ifndef HAVE_IPV6
87
88 #if defined(SYS_WINNT)
89 /* XXX This is the preferred way, but for some reason the SunOS compiler
90  * does not like it.
91  */
92 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
93 #else
94 const struct in6_addr in6addr_any;
95 #endif
96
97 static char *ai_errlist[] = {
98         "Success",
99         "Address family for hostname not supported",    /* EAI_ADDRFAMILY */
100         "Temporary failure in name resolution",         /* EAI_AGAIN      */
101         "Invalid value for ai_flags",                   /* EAI_BADFLAGS   */
102         "Non-recoverable failure in name resolution",   /* EAI_FAIL       */
103         "ai_family not supported",                      /* EAI_FAMILY     */
104         "Memory allocation failure",                    /* EAI_MEMORY     */
105         "No address associated with hostname",          /* EAI_NODATA     */
106         "hostname nor servname provided, or not known", /* EAI_NONAME     */
107         "servname not supported for ai_socktype",       /* EAI_SERVICE    */
108         "ai_socktype not supported",                    /* EAI_SOCKTYPE   */
109         "System error returned in errno",               /* EAI_SYSTEM     */
110         "Invalid value for hints",                      /* EAI_BADHINTS   */
111         "Resolved protocol is unknown",                 /* EAI_PROTOCOL   */
112         "Unknown error",                                /* EAI_MAX        */
113 };
114
115 static  int ipv4_aton P((const char *, struct sockaddr_storage *));
116 static  int do_nodename P((const char *nodename, struct addrinfo *ai,
117     const struct addrinfo *hints));
118
119 int
120 getaddrinfo (const char *nodename, const char *servname,
121         const struct addrinfo *hints, struct addrinfo **res)
122 {
123         int rval;
124         struct addrinfo *ai;
125         struct sockaddr_in *sockin;
126
127         ai = calloc(sizeof(struct addrinfo), 1);
128         if (ai == NULL)
129                 return (EAI_MEMORY);
130
131         if (nodename != NULL) {
132                 rval = do_nodename(nodename, ai, hints);
133                 if (rval != 0) {
134                         freeaddrinfo(ai);
135                         return (rval);
136                 }
137         }
138         if (nodename == NULL && hints != NULL) {
139                 ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
140                 if (ai->ai_addr == NULL) {
141                         freeaddrinfo(ai);
142                         return (EAI_MEMORY);
143                 }
144                 ai->ai_family = AF_INET;
145                 ai->ai_addrlen = sizeof(struct sockaddr_storage);
146                 sockin = (struct sockaddr_in *)ai->ai_addr;
147                 sockin->sin_family = AF_INET;
148                 sockin->sin_addr.s_addr = htonl(INADDR_ANY);
149 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
150                 ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
151 #endif
152         }
153         if (servname != NULL) {
154                 ai->ai_family = AF_INET;
155                 ai->ai_socktype = SOCK_DGRAM;
156                 if (strcmp(servname, "ntp") != 0) {
157                         freeaddrinfo(ai);
158                         return (EAI_SERVICE);
159                 }
160                 sockin = (struct sockaddr_in *)ai->ai_addr;
161                 sockin->sin_port = htons(NTP_PORT);
162         }
163         *res = ai;
164         return (0);
165 }
166
167 void
168 freeaddrinfo(struct addrinfo *ai)
169 {
170         if (ai->ai_canonname != NULL)
171                 free(ai->ai_canonname);
172         if (ai->ai_addr != NULL)
173                 free(ai->ai_addr);
174         free(ai);
175 }
176
177 int
178 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
179         size_t hostlen, char *serv, size_t servlen, int flags)
180 {
181         struct hostent *hp;
182
183         if (sa->sa_family != AF_INET)
184                 return (EAI_FAMILY);
185         hp = gethostbyaddr(
186             (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
187             4, AF_INET);
188         if (hp == NULL) {
189                 if (h_errno == TRY_AGAIN)
190                         return (EAI_AGAIN);
191                 else
192                         return (EAI_FAIL);
193         }
194         if (host != NULL) {
195                 strncpy(host, hp->h_name, hostlen);
196                 host[hostlen] = '\0';
197         }
198         return (0);
199 }
200
201 char *
202 gai_strerror(int ecode)
203 {
204         if (ecode < 0 || ecode > EAI_MAX)
205                 ecode = EAI_MAX;
206         return ai_errlist[ecode];
207 }
208
209 static int
210 do_nodename(
211         const char *nodename,
212         struct addrinfo *ai,
213         const struct addrinfo *hints)
214 {
215         struct hostent *hp;
216         struct sockaddr_in *sockin;
217
218         ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
219         if (ai->ai_addr == NULL)
220                 return (EAI_MEMORY);
221
222         if (hints != NULL && hints->ai_flags & AI_NUMERICHOST) {
223                 if (ipv4_aton(nodename,
224                     (struct sockaddr_storage *)ai->ai_addr) == 1) {
225                         ai->ai_family = AF_INET;
226                         ai->ai_addrlen = sizeof(struct sockaddr_in);
227                         return (0);
228                 }
229                 return (EAI_NONAME);
230         }
231         hp = gethostbyname(nodename);
232         if (hp == NULL) {
233                 if (h_errno == TRY_AGAIN)
234                         return (EAI_AGAIN);
235                 else {
236                         if (ipv4_aton(nodename,
237                             (struct sockaddr_storage *)ai->ai_addr) == 1) {
238                                 ai->ai_family = AF_INET;
239                                 ai->ai_addrlen = sizeof(struct sockaddr_in);
240                                 return (0);
241                         }
242                         return (EAI_FAIL);
243                 }
244         }
245         ai->ai_family = hp->h_addrtype;
246         ai->ai_addrlen = sizeof(struct sockaddr);
247         sockin = (struct sockaddr_in *)ai->ai_addr;
248         memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
249         ai->ai_addr->sa_family = hp->h_addrtype;
250 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
251         ai->ai_addr->sa_len = sizeof(struct sockaddr);
252 #endif
253         if (hints != NULL && hints->ai_flags & AI_CANONNAME) {
254                 ai->ai_canonname = malloc(strlen(hp->h_name) + 1);
255                 if (ai->ai_canonname == NULL)
256                         return (EAI_MEMORY);
257                 strcpy(ai->ai_canonname, hp->h_name);
258         }
259         return (0);
260 }
261
262 /*
263  * ipv4_aton - return a net number (this is crude, but careful)
264  */
265 static int
266 ipv4_aton(
267         const char *num,
268         struct sockaddr_storage *saddr
269         )
270 {
271         const char *cp;
272         char *bp;
273         int i;
274         int temp;
275         char buf[80];           /* will core dump on really stupid stuff */
276         u_int32 netnum;
277         struct sockaddr_in *addr;
278
279         cp = num;
280         netnum = 0;
281         for (i = 0; i < 4; i++) {
282                 bp = buf;
283                 while (isdigit((int)*cp))
284                         *bp++ = *cp++;
285                 if (bp == buf)
286                         break;
287
288                 if (i < 3) {
289                         if (*cp++ != '.')
290                                 break;
291                 } else if (*cp != '\0')
292                         break;
293
294                 *bp = '\0';
295                 temp = atoi(buf);
296                 if (temp > 255)
297                         break;
298                 netnum <<= 8;
299                 netnum += temp;
300 #ifdef DEBUG
301                 if (debug > 3)
302                         printf("ipv4_aton %s step %d buf %s temp %d netnum %lu\n",
303                            num, i, buf, temp, (u_long)netnum);
304 #endif
305         }
306
307         if (i < 4) {
308 #ifdef DEBUG
309                 if (debug > 3)
310                         printf(
311                                 "ipv4_aton: \"%s\" invalid host number, line ignored\n",
312                                 num);
313 #endif
314                 return (0);
315         }
316
317         /*
318          * make up socket address.      Clear it out for neatness.
319          */
320         memset((void *)saddr, 0, sizeof(struct sockaddr_storage));
321         addr = (struct sockaddr_in *)saddr;
322         addr->sin_family = AF_INET;
323         addr->sin_port = htons(NTP_PORT);
324         addr->sin_addr.s_addr = htonl(netnum);
325 #ifdef DEBUG
326         if (debug > 1)
327                 printf("ipv4_aton given %s, got %s.\n", num, ntoa(saddr));
328 #endif
329         return (1);
330 }
331 #endif /* !HAVE_IPV6 */