xref: /freebsd/contrib/ntp/libntp/ntp_rfc2553.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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 */
332