xref: /netbsd-src/external/bsd/ntp/dist/libntp/ntp_rfc2553.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: ntp_rfc2553.c,v 1.1.1.1 2009/12/13 16:55:04 kardel Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1982, 1986, 1990, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by the University of
47  *	California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  */
65 
66 /*
67  * Compatability shims with the rfc2553 API to simplify ntp.
68  */
69 
70 #include <config.h>
71 
72 #include <sys/types.h>
73 #include <ctype.h>
74 #ifdef HAVE_SYS_SOCKET_H
75 #include <sys/socket.h>
76 #endif
77 #include <isc/net.h>
78 #ifdef HAVE_NETINET_IN_H
79 #include <netinet/in.h>
80 #endif
81 #include "ntp_rfc2553.h"
82 
83 #include "ntpd.h"
84 #include "ntp_malloc.h"
85 #include "ntp_stdlib.h"
86 #include "ntp_string.h"
87 
88 #ifndef ISC_PLATFORM_HAVEIPV6
89 
90 static char *ai_errlist[] = {
91 	"Success",
92 	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
93 	"Temporary failure in name resolution",		/* EAI_AGAIN      */
94 	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
95 	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
96 	"ai_family not supported",			/* EAI_FAMILY     */
97 	"Memory allocation failure", 			/* EAI_MEMORY     */
98 	"No address associated with hostname", 		/* EAI_NODATA     */
99 	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
100 	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
101 	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
102 	"System error returned in errno", 		/* EAI_SYSTEM     */
103 	"Invalid value for hints",			/* EAI_BADHINTS	  */
104 	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
105 	"Unknown error", 				/* EAI_MAX        */
106 };
107 
108 /*
109  * Local declaration
110  */
111 int
112 DNSlookup_name(
113 	const char *name,
114 	int ai_family,
115 	struct hostent **Addresses
116 );
117 
118 #ifndef SYS_WINNT
119 /*
120  * Encapsulate gethostbyname to control the error code
121  */
122 int
123 DNSlookup_name(
124 	const char *name,
125 	int ai_family,
126 	struct hostent **Addresses
127 )
128 {
129 	*Addresses = gethostbyname(name);
130 	return (h_errno);
131 }
132 #endif
133 
134 static	int do_nodename (const char *nodename, struct addrinfo *ai,
135     const struct addrinfo *hints);
136 
137 int
138 getaddrinfo (const char *nodename, const char *servname,
139 	const struct addrinfo *hints, struct addrinfo **res)
140 {
141 	int rval;
142 	struct servent *sp;
143 	struct addrinfo *ai = NULL;
144 	int port;
145 	const char *proto = NULL;
146 	int family, socktype, flags, protocol;
147 
148 
149 	/*
150 	 * If no name is provide just return an error
151 	 */
152 	if (nodename == NULL && servname == NULL)
153 		return (EAI_NONAME);
154 
155 	ai = calloc(sizeof(struct addrinfo), 1);
156 	if (ai == NULL)
157 		return (EAI_MEMORY);
158 
159 	/*
160 	 * Copy default values from hints, if available
161 	 */
162 	if (hints != NULL) {
163 		ai->ai_flags = hints->ai_flags;
164 		ai->ai_family = hints->ai_family;
165 		ai->ai_socktype = hints->ai_socktype;
166 		ai->ai_protocol = hints->ai_protocol;
167 
168 		family = hints->ai_family;
169 		socktype = hints->ai_socktype;
170 		protocol = hints->ai_protocol;
171 		flags = hints->ai_flags;
172 
173 		switch (family) {
174 		case AF_UNSPEC:
175 			switch (hints->ai_socktype) {
176 			case SOCK_STREAM:
177 				proto = "tcp";
178 				break;
179 			case SOCK_DGRAM:
180 				proto = "udp";
181 				break;
182 			}
183 			break;
184 		case AF_INET:
185 		case AF_INET6:
186 			switch (hints->ai_socktype) {
187 			case 0:
188 				break;
189 			case SOCK_STREAM:
190 				proto = "tcp";
191 				break;
192 			case SOCK_DGRAM:
193 				proto = "udp";
194 				break;
195 			case SOCK_RAW:
196 				break;
197 			default:
198 				return (EAI_SOCKTYPE);
199 			}
200 			break;
201 #ifdef	AF_LOCAL
202 		case AF_LOCAL:
203 			switch (hints->ai_socktype) {
204 			case 0:
205 				break;
206 			case SOCK_STREAM:
207 				break;
208 			case SOCK_DGRAM:
209 				break;
210 			default:
211 				return (EAI_SOCKTYPE);
212 			}
213 			break;
214 #endif
215 		default:
216 			return (EAI_FAMILY);
217 		}
218 	} else {
219 		protocol = 0;
220 		family = 0;
221 		socktype = 0;
222 		flags = 0;
223 	}
224 
225 	rval = do_nodename(nodename, ai, hints);
226 	if (rval != 0) {
227 		freeaddrinfo(ai);
228 		return (rval);
229 	}
230 
231 	/*
232 	 * First, look up the service name (port) if it was
233 	 * requested.  If the socket type wasn't specified, then
234 	 * try and figure it out.
235 	 */
236 	if (servname != NULL) {
237 		char *e;
238 
239 		port = strtol(servname, &e, 10);
240 		if (*e == '\0') {
241 			if (socktype == 0)
242 				return (EAI_SOCKTYPE);
243 			if (port < 0 || port > 65535)
244 				return (EAI_SERVICE);
245 			port = htons((unsigned short) port);
246 		} else {
247 			sp = getservbyname(servname, proto);
248 			if (sp == NULL)
249 				return (EAI_SERVICE);
250 			port = sp->s_port;
251 			if (socktype == 0) {
252 				if (strcmp(sp->s_proto, "tcp") == 0)
253 					socktype = SOCK_STREAM;
254 				else if (strcmp(sp->s_proto, "udp") == 0)
255 					socktype = SOCK_DGRAM;
256 			}
257 		}
258 	} else
259 		port = 0;
260 
261 	/*
262 	 *
263 	 * Set up the port number
264 	 */
265 	if (ai->ai_family == AF_INET)
266 		((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
267 	else if (ai->ai_family == AF_INET6)
268 		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
269 	*res = ai;
270 	return (0);
271 }
272 
273 void
274 freeaddrinfo(struct addrinfo *ai)
275 {
276 	if (ai->ai_canonname != NULL)
277 	{
278 		free(ai->ai_canonname);
279 		ai->ai_canonname = NULL;
280 	}
281 	if (ai->ai_addr != NULL)
282 	{
283 		free(ai->ai_addr);
284 		ai->ai_addr = NULL;
285 	}
286 	free(ai);
287 	ai = NULL;
288 }
289 
290 int
291 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
292 	size_t hostlen, char *serv, size_t servlen, int flags)
293 {
294 	struct hostent *hp;
295 	int namelen;
296 
297 	if (sa->sa_family != AF_INET)
298 		return (EAI_FAMILY);
299 	hp = gethostbyaddr(
300 	    (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
301 	    4, AF_INET);
302 	if (hp == NULL) {
303 		if (h_errno == TRY_AGAIN)
304 			return (EAI_AGAIN);
305 		else
306 			return (EAI_FAIL);
307 	}
308 	if (host != NULL && hostlen > 0) {
309 		/*
310 		 * Don't exceed buffer
311 		 */
312 		namelen = min(strlen(hp->h_name), hostlen - 1);
313 		if (namelen > 0) {
314 			strncpy(host, hp->h_name, namelen);
315 			host[namelen] = '\0';
316 		}
317 	}
318 	return (0);
319 }
320 
321 char *
322 gai_strerror(int ecode)
323 {
324 	if (ecode < 0 || ecode > EAI_MAX)
325 		ecode = EAI_MAX;
326 	return ai_errlist[ecode];
327 }
328 
329 static int
330 do_nodename(
331 	const char *nodename,
332 	struct addrinfo *ai,
333 	const struct addrinfo *hints)
334 {
335 	struct hostent *hp = NULL;
336 	struct sockaddr_in *sockin;
337 	struct sockaddr_in6 *sockin6;
338 	int errval;
339 
340 	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
341 	if (ai->ai_addr == NULL)
342 		return (EAI_MEMORY);
343 
344 	/*
345 	 * For an empty node name just use the wildcard.
346 	 * NOTE: We need to assume that the address family is
347 	 * set elsewhere so that we can set the appropriate wildcard
348 	 */
349 	if (nodename == NULL) {
350 		ai->ai_addrlen = sizeof(struct sockaddr_storage);
351 		if (ai->ai_family == AF_INET)
352 		{
353 			sockin = (struct sockaddr_in *)ai->ai_addr;
354 			sockin->sin_family = (short) ai->ai_family;
355 			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
356 		}
357 		else
358 		{
359 			sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
360 			sockin6->sin6_family = (short) ai->ai_family;
361 			/*
362 			 * we have already zeroed out the address
363 			 * so we don't actually need to do this
364 			 * This assignment is causing problems so
365 			 * we don't do what this would do.
366 			 sockin6->sin6_addr = in6addr_any;
367 			 */
368 		}
369 #ifdef ISC_PLATFORM_HAVESALEN
370 		ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
371 #endif
372 
373 		return (0);
374 	}
375 
376 	/*
377 	 * See if we have an IPv6 address
378 	 */
379 	if(strchr(nodename, ':') != NULL) {
380 		if (inet_pton(AF_INET6, nodename,
381 		    &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
382 			((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
383 			ai->ai_family = AF_INET6;
384 			ai->ai_addrlen = sizeof(struct sockaddr_in6);
385 			return (0);
386 		}
387 	}
388 
389 	/*
390 	 * See if we have an IPv4 address
391 	 */
392 	if (inet_pton(AF_INET, nodename,
393 	    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
394 		((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
395 		ai->ai_family = AF_INET;
396 		ai->ai_addrlen = sizeof(struct sockaddr_in);
397 		return (0);
398 	}
399 
400 	/*
401 	 * If the numeric host flag is set, don't attempt resolution
402 	 */
403 	if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
404 		return (EAI_NONAME);
405 
406 	/*
407 	 * Look for a name
408 	 */
409 
410 	errval = DNSlookup_name(nodename, AF_INET, &hp);
411 
412 	if (hp == NULL) {
413 		if (errval == TRY_AGAIN || errval == EAI_AGAIN)
414 			return (EAI_AGAIN);
415 		else if (errval == EAI_NONAME) {
416 			if (inet_pton(AF_INET, nodename,
417 			    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
418 				((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
419 				ai->ai_family = AF_INET;
420 				ai->ai_addrlen = sizeof(struct sockaddr_in);
421 				return (0);
422 			}
423 			return (errval);
424 		}
425 		else
426 		{
427 			return (errval);
428 		}
429 	}
430 	ai->ai_family = hp->h_addrtype;
431 	ai->ai_addrlen = sizeof(struct sockaddr);
432 	sockin = (struct sockaddr_in *)ai->ai_addr;
433 	memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
434 	ai->ai_addr->sa_family = hp->h_addrtype;
435 #ifdef ISC_PLATFORM_HAVESALEN
436 	ai->ai_addr->sa_len = sizeof(struct sockaddr);
437 #endif
438 	if (hints != NULL && hints->ai_flags & AI_CANONNAME)
439 		ai->ai_canonname = estrdup(hp->h_name);
440 	return (0);
441 }
442 
443 #endif /* !ISC_PLATFORM_HAVEIPV6 */
444