xref: /dflybsd-src/usr.bin/getaddrinfo/getaddrinfo.c (revision 68e29d3e80a281a9306ee43f1803fc3c406f9d04)
1*5fb3968eSAaron LI /*	$NetBSD: getaddrinfo.c,v 1.4 2014/04/22 02:23:03 ginsbach Exp $	*/
2*5fb3968eSAaron LI 
3*5fb3968eSAaron LI /*-
4*5fb3968eSAaron LI  * Copyright (c) 2013 The NetBSD Foundation, Inc.
5*5fb3968eSAaron LI  * All rights reserved.
6*5fb3968eSAaron LI  *
7*5fb3968eSAaron LI  * This code is derived from software contributed to The NetBSD Foundation
8*5fb3968eSAaron LI  * by Taylor R. Campbell.
9*5fb3968eSAaron LI  *
10*5fb3968eSAaron LI  * Redistribution and use in source and binary forms, with or without
11*5fb3968eSAaron LI  * modification, are permitted provided that the following conditions
12*5fb3968eSAaron LI  * are met:
13*5fb3968eSAaron LI  * 1. Redistributions of source code must retain the above copyright
14*5fb3968eSAaron LI  *    notice, this list of conditions and the following disclaimer.
15*5fb3968eSAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
16*5fb3968eSAaron LI  *    notice, this list of conditions and the following disclaimer in the
17*5fb3968eSAaron LI  *    documentation and/or other materials provided with the distribution.
18*5fb3968eSAaron LI  *
19*5fb3968eSAaron LI  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*5fb3968eSAaron LI  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*5fb3968eSAaron LI  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*5fb3968eSAaron LI  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*5fb3968eSAaron LI  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*5fb3968eSAaron LI  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*5fb3968eSAaron LI  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*5fb3968eSAaron LI  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*5fb3968eSAaron LI  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*5fb3968eSAaron LI  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*5fb3968eSAaron LI  * POSSIBILITY OF SUCH DAMAGE.
30*5fb3968eSAaron LI  */
31*5fb3968eSAaron LI 
32*5fb3968eSAaron LI #include <sys/param.h>
33*5fb3968eSAaron LI #include <sys/socket.h>
34*5fb3968eSAaron LI 
35*5fb3968eSAaron LI #include <assert.h>
36*5fb3968eSAaron LI #include <err.h>
37*5fb3968eSAaron LI #include <errno.h>
38*5fb3968eSAaron LI #include <limits.h>
39*5fb3968eSAaron LI #include <netdb.h>
40*5fb3968eSAaron LI #include <stdbool.h>
41*5fb3968eSAaron LI #include <stdint.h>
42*5fb3968eSAaron LI #include <stdlib.h>
43*5fb3968eSAaron LI #include <stdio.h>
44*5fb3968eSAaron LI #include <string.h>
45*5fb3968eSAaron LI #include <unistd.h>
46*5fb3968eSAaron LI #include <util.h>
47*5fb3968eSAaron LI 
48*5fb3968eSAaron LI #include "tables.h"
49*5fb3968eSAaron LI 
50*5fb3968eSAaron LI static void	usage(void) __dead2;
51*5fb3968eSAaron LI static void	printaddrinfo(struct addrinfo *);
52*5fb3968eSAaron LI static bool	parse_af(const char *, int *);
53*5fb3968eSAaron LI static bool	parse_protocol(const char *, int *);
54*5fb3968eSAaron LI static bool	parse_socktype(const char *, int *);
55*5fb3968eSAaron LI static bool	parse_numeric_tabular(const char *, int *, const char *const *,
56*5fb3968eSAaron LI 		    size_t);
57*5fb3968eSAaron LI 
58*5fb3968eSAaron LI int
main(int argc,char ** argv)59*5fb3968eSAaron LI main(int argc, char **argv)
60*5fb3968eSAaron LI {
61*5fb3968eSAaron LI 	static const struct addrinfo zero_addrinfo;
62*5fb3968eSAaron LI 	struct addrinfo hints = zero_addrinfo;
63*5fb3968eSAaron LI 	struct addrinfo *addrinfo;
64*5fb3968eSAaron LI 	const char *hostname = NULL, *service = NULL;
65*5fb3968eSAaron LI 	int ch;
66*5fb3968eSAaron LI 	int error;
67*5fb3968eSAaron LI 
68*5fb3968eSAaron LI 	setprogname(argv[0]);
69*5fb3968eSAaron LI 
70*5fb3968eSAaron LI 	hints.ai_family = AF_UNSPEC;
71*5fb3968eSAaron LI 	hints.ai_socktype = 0;
72*5fb3968eSAaron LI 	hints.ai_protocol = 0;
73*5fb3968eSAaron LI 	hints.ai_flags = 0;
74*5fb3968eSAaron LI 
75*5fb3968eSAaron LI 	while ((ch = getopt(argc, argv, "cf:nNp:Ps:t:")) != -1) {
76*5fb3968eSAaron LI 		switch (ch) {
77*5fb3968eSAaron LI 		case 'c':
78*5fb3968eSAaron LI 			hints.ai_flags |= AI_CANONNAME;
79*5fb3968eSAaron LI 			break;
80*5fb3968eSAaron LI 
81*5fb3968eSAaron LI 		case 'f':
82*5fb3968eSAaron LI 			if (!parse_af(optarg, &hints.ai_family)) {
83*5fb3968eSAaron LI 				warnx("invalid address family: %s", optarg);
84*5fb3968eSAaron LI 				usage();
85*5fb3968eSAaron LI 			}
86*5fb3968eSAaron LI 			break;
87*5fb3968eSAaron LI 
88*5fb3968eSAaron LI 		case 'n':
89*5fb3968eSAaron LI 			hints.ai_flags |= AI_NUMERICHOST;
90*5fb3968eSAaron LI 			break;
91*5fb3968eSAaron LI 
92*5fb3968eSAaron LI 		case 'N':
93*5fb3968eSAaron LI 			hints.ai_flags |= AI_NUMERICSERV;
94*5fb3968eSAaron LI 			break;
95*5fb3968eSAaron LI 
96*5fb3968eSAaron LI 		case 's':
97*5fb3968eSAaron LI 			service = optarg;
98*5fb3968eSAaron LI 			break;
99*5fb3968eSAaron LI 
100*5fb3968eSAaron LI 		case 'p':
101*5fb3968eSAaron LI 			if (!parse_protocol(optarg, &hints.ai_protocol)) {
102*5fb3968eSAaron LI 				warnx("invalid protocol: %s", optarg);
103*5fb3968eSAaron LI 				usage();
104*5fb3968eSAaron LI 			}
105*5fb3968eSAaron LI 			break;
106*5fb3968eSAaron LI 
107*5fb3968eSAaron LI 		case 'P':
108*5fb3968eSAaron LI 			hints.ai_flags |= AI_PASSIVE;
109*5fb3968eSAaron LI 			break;
110*5fb3968eSAaron LI 
111*5fb3968eSAaron LI 		case 't':
112*5fb3968eSAaron LI 			if (!parse_socktype(optarg, &hints.ai_socktype)) {
113*5fb3968eSAaron LI 				warnx("invalid socket type: %s", optarg);
114*5fb3968eSAaron LI 				usage();
115*5fb3968eSAaron LI 			}
116*5fb3968eSAaron LI 			break;
117*5fb3968eSAaron LI 
118*5fb3968eSAaron LI 		case '?':
119*5fb3968eSAaron LI 		default:
120*5fb3968eSAaron LI 			usage();
121*5fb3968eSAaron LI 		}
122*5fb3968eSAaron LI 	}
123*5fb3968eSAaron LI 
124*5fb3968eSAaron LI 	argc -= optind;
125*5fb3968eSAaron LI 	argv += optind;
126*5fb3968eSAaron LI 
127*5fb3968eSAaron LI 	if (!((argc == 1) || ((argc == 0) && (hints.ai_flags & AI_PASSIVE))))
128*5fb3968eSAaron LI 		usage();
129*5fb3968eSAaron LI 	if (argc == 1)
130*5fb3968eSAaron LI 		hostname = argv[0];
131*5fb3968eSAaron LI 
132*5fb3968eSAaron LI 	if (service != NULL) {
133*5fb3968eSAaron LI 		char *p;
134*5fb3968eSAaron LI 
135*5fb3968eSAaron LI 		if ((p = strchr(service, '/')) != NULL) {
136*5fb3968eSAaron LI 			if (hints.ai_protocol != 0) {
137*5fb3968eSAaron LI 				warnx("protocol already specified");
138*5fb3968eSAaron LI 				usage();
139*5fb3968eSAaron LI 			}
140*5fb3968eSAaron LI 			*p = '\0';
141*5fb3968eSAaron LI 			p++;
142*5fb3968eSAaron LI 
143*5fb3968eSAaron LI 			if (!parse_protocol(p, &hints.ai_protocol)) {
144*5fb3968eSAaron LI 				warnx("invalid protocol: %s", p);
145*5fb3968eSAaron LI 				usage();
146*5fb3968eSAaron LI 			}
147*5fb3968eSAaron LI 		}
148*5fb3968eSAaron LI 	}
149*5fb3968eSAaron LI 
150*5fb3968eSAaron LI 	error = getaddrinfo(hostname, service, &hints, &addrinfo);
151*5fb3968eSAaron LI 	if (error)
152*5fb3968eSAaron LI 		errx(1, "%s", gai_strerror(error));
153*5fb3968eSAaron LI 
154*5fb3968eSAaron LI 	if ((hints.ai_flags & AI_CANONNAME) && (addrinfo != NULL)) {
155*5fb3968eSAaron LI 		if (printf("canonname %s\n", addrinfo->ai_canonname) < 0)
156*5fb3968eSAaron LI 			err(1, "printf");
157*5fb3968eSAaron LI 	}
158*5fb3968eSAaron LI 
159*5fb3968eSAaron LI 	printaddrinfo(addrinfo);
160*5fb3968eSAaron LI 
161*5fb3968eSAaron LI 	freeaddrinfo(addrinfo);
162*5fb3968eSAaron LI 
163*5fb3968eSAaron LI 	return 0;
164*5fb3968eSAaron LI }
165*5fb3968eSAaron LI 
166*5fb3968eSAaron LI static void __dead2
usage(void)167*5fb3968eSAaron LI usage(void)
168*5fb3968eSAaron LI {
169*5fb3968eSAaron LI 
170*5fb3968eSAaron LI 	(void)fprintf(stderr, "Usage: %s", getprogname());
171*5fb3968eSAaron LI 	(void)fprintf(stderr,
172*5fb3968eSAaron LI 	    " [-f <family>] [-p <protocol>] [-t <socktype>] [-s <service>]\n");
173*5fb3968eSAaron LI 	(void)fprintf(stderr, "   [-cnNP] [<hostname>]\n");
174*5fb3968eSAaron LI 	exit(1);
175*5fb3968eSAaron LI }
176*5fb3968eSAaron LI 
177*5fb3968eSAaron LI static bool
parse_af(const char * string,int * afp)178*5fb3968eSAaron LI parse_af(const char *string, int *afp)
179*5fb3968eSAaron LI {
180*5fb3968eSAaron LI 
181*5fb3968eSAaron LI 	return parse_numeric_tabular(string, afp, address_families,
182*5fb3968eSAaron LI 	    nitems(address_families));
183*5fb3968eSAaron LI }
184*5fb3968eSAaron LI 
185*5fb3968eSAaron LI static bool
parse_protocol(const char * string,int * protop)186*5fb3968eSAaron LI parse_protocol(const char *string, int *protop)
187*5fb3968eSAaron LI {
188*5fb3968eSAaron LI 	struct protoent *protoent;
189*5fb3968eSAaron LI 	char *end;
190*5fb3968eSAaron LI 	long value;
191*5fb3968eSAaron LI 
192*5fb3968eSAaron LI 	errno = 0;
193*5fb3968eSAaron LI 	value = strtol(string, &end, 0);
194*5fb3968eSAaron LI 	if ((string[0] == '\0') || (*end != '\0'))
195*5fb3968eSAaron LI 		goto numeric_failed;
196*5fb3968eSAaron LI 	if ((errno == ERANGE) && ((value == LONG_MAX) || (value == LONG_MIN)))
197*5fb3968eSAaron LI 		goto numeric_failed;
198*5fb3968eSAaron LI 	if ((value > INT_MAX) || (value < INT_MIN))
199*5fb3968eSAaron LI 		goto numeric_failed;
200*5fb3968eSAaron LI 
201*5fb3968eSAaron LI 	*protop = value;
202*5fb3968eSAaron LI 	return true;
203*5fb3968eSAaron LI 
204*5fb3968eSAaron LI numeric_failed:
205*5fb3968eSAaron LI 	protoent = getprotobyname(string);
206*5fb3968eSAaron LI 	if (protoent == NULL)
207*5fb3968eSAaron LI 		goto protoent_failed;
208*5fb3968eSAaron LI 
209*5fb3968eSAaron LI 	*protop = protoent->p_proto;
210*5fb3968eSAaron LI 	return true;
211*5fb3968eSAaron LI 
212*5fb3968eSAaron LI protoent_failed:
213*5fb3968eSAaron LI 	return false;
214*5fb3968eSAaron LI }
215*5fb3968eSAaron LI 
216*5fb3968eSAaron LI static bool
parse_socktype(const char * string,int * typep)217*5fb3968eSAaron LI parse_socktype(const char *string, int *typep)
218*5fb3968eSAaron LI {
219*5fb3968eSAaron LI 
220*5fb3968eSAaron LI 	return parse_numeric_tabular(string, typep, socket_types,
221*5fb3968eSAaron LI 	    nitems(socket_types));
222*5fb3968eSAaron LI }
223*5fb3968eSAaron LI 
224*5fb3968eSAaron LI static bool
parse_numeric_tabular(const char * string,int * valuep,const char * const * table,size_t n)225*5fb3968eSAaron LI parse_numeric_tabular(const char *string, int *valuep,
226*5fb3968eSAaron LI     const char *const *table, size_t n)
227*5fb3968eSAaron LI {
228*5fb3968eSAaron LI 	char *end;
229*5fb3968eSAaron LI 	long value;
230*5fb3968eSAaron LI 	size_t i;
231*5fb3968eSAaron LI 
232*5fb3968eSAaron LI 	assert((uintmax_t)n <= (uintmax_t)INT_MAX);
233*5fb3968eSAaron LI 
234*5fb3968eSAaron LI 	errno = 0;
235*5fb3968eSAaron LI 	value = strtol(string, &end, 0);
236*5fb3968eSAaron LI 	if ((string[0] == '\0') || (*end != '\0'))
237*5fb3968eSAaron LI 		goto numeric_failed;
238*5fb3968eSAaron LI 	if ((errno == ERANGE) && ((value == LONG_MAX) || (value == LONG_MIN)))
239*5fb3968eSAaron LI 		goto numeric_failed;
240*5fb3968eSAaron LI 	if ((value > INT_MAX) || (value < INT_MIN))
241*5fb3968eSAaron LI 		goto numeric_failed;
242*5fb3968eSAaron LI 
243*5fb3968eSAaron LI 	*valuep = value;
244*5fb3968eSAaron LI 	return true;
245*5fb3968eSAaron LI 
246*5fb3968eSAaron LI numeric_failed:
247*5fb3968eSAaron LI 	for (i = 0; i < n; i++)
248*5fb3968eSAaron LI 		if ((table[i] != NULL) && (strcmp(string, table[i]) == 0))
249*5fb3968eSAaron LI 			break;
250*5fb3968eSAaron LI 	if (i == n)
251*5fb3968eSAaron LI 		goto table_failed;
252*5fb3968eSAaron LI 	*valuep = i;
253*5fb3968eSAaron LI 	return true;
254*5fb3968eSAaron LI 
255*5fb3968eSAaron LI table_failed:
256*5fb3968eSAaron LI 	return false;
257*5fb3968eSAaron LI }
258*5fb3968eSAaron LI 
259*5fb3968eSAaron LI static void
printaddrinfo(struct addrinfo * addrinfo)260*5fb3968eSAaron LI printaddrinfo(struct addrinfo *addrinfo)
261*5fb3968eSAaron LI {
262*5fb3968eSAaron LI 	struct addrinfo *ai;
263*5fb3968eSAaron LI 	char buf[1024];
264*5fb3968eSAaron LI 	int n;
265*5fb3968eSAaron LI 	struct protoent *protoent;
266*5fb3968eSAaron LI 
267*5fb3968eSAaron LI 	for (ai = addrinfo; ai != NULL; ai = ai->ai_next) {
268*5fb3968eSAaron LI 		/* Print the socket type.  */
269*5fb3968eSAaron LI 		if ((ai->ai_socktype >= 0) &&
270*5fb3968eSAaron LI 		    ((size_t)ai->ai_socktype < nitems(socket_types)) &&
271*5fb3968eSAaron LI 		    (socket_types[ai->ai_socktype] != NULL))
272*5fb3968eSAaron LI 			n = printf("%s", socket_types[ai->ai_socktype]);
273*5fb3968eSAaron LI 		else
274*5fb3968eSAaron LI 			n = printf("%d", ai->ai_socktype);
275*5fb3968eSAaron LI 		if (n < 0)
276*5fb3968eSAaron LI 			err(1, "printf");
277*5fb3968eSAaron LI 
278*5fb3968eSAaron LI 		/* Print the address family.  */
279*5fb3968eSAaron LI 		if ((ai->ai_family >= 0) &&
280*5fb3968eSAaron LI 		    ((size_t)ai->ai_family < nitems(address_families)) &&
281*5fb3968eSAaron LI 		    (address_families[ai->ai_family] != NULL))
282*5fb3968eSAaron LI 			n = printf(" %s", address_families[ai->ai_family]);
283*5fb3968eSAaron LI 		else
284*5fb3968eSAaron LI 			n = printf(" %d", ai->ai_family);
285*5fb3968eSAaron LI 		if (n < 0)
286*5fb3968eSAaron LI 			err(1, "printf");
287*5fb3968eSAaron LI 
288*5fb3968eSAaron LI 		/* Print the protocol number.  */
289*5fb3968eSAaron LI 		protoent = getprotobynumber(ai->ai_protocol);
290*5fb3968eSAaron LI 		if (protoent == NULL)
291*5fb3968eSAaron LI 			n = printf(" %d", ai->ai_protocol);
292*5fb3968eSAaron LI 		else
293*5fb3968eSAaron LI 			n = printf(" %s", protoent->p_name);
294*5fb3968eSAaron LI 		if (n < 0)
295*5fb3968eSAaron LI 			err(1, "printf");
296*5fb3968eSAaron LI 
297*5fb3968eSAaron LI 		/* Format the sockaddr.  */
298*5fb3968eSAaron LI 		switch (ai->ai_family) {
299*5fb3968eSAaron LI 		case AF_INET:
300*5fb3968eSAaron LI 		case AF_INET6:
301*5fb3968eSAaron LI 			n = sockaddr_snprintf(buf, sizeof(buf), " %a %p",
302*5fb3968eSAaron LI 			    ai->ai_addr);
303*5fb3968eSAaron LI 			break;
304*5fb3968eSAaron LI 
305*5fb3968eSAaron LI 		default:
306*5fb3968eSAaron LI 			n = sockaddr_snprintf(buf, sizeof(buf),
307*5fb3968eSAaron LI 			    "%a %p %I %F %R %S", ai->ai_addr);
308*5fb3968eSAaron LI 		}
309*5fb3968eSAaron LI 
310*5fb3968eSAaron LI 		/*
311*5fb3968eSAaron LI 		 * Check for sockaddr_snprintf failure.
312*5fb3968eSAaron LI 		 *
313*5fb3968eSAaron LI 		 * XXX sockaddr_snprintf's error reporting is botched
314*5fb3968eSAaron LI 		 * -- man page says it sets errno, but if getnameinfo
315*5fb3968eSAaron LI 		 * fails, errno is not where it reports the error...
316*5fb3968eSAaron LI 		 */
317*5fb3968eSAaron LI 		if (n < 0) {
318*5fb3968eSAaron LI 			warnx("sockaddr_snprintf failed");
319*5fb3968eSAaron LI 			continue;
320*5fb3968eSAaron LI 		}
321*5fb3968eSAaron LI 		if (sizeof(buf) <= (size_t)n)
322*5fb3968eSAaron LI 			warnx("truncated sockaddr_snprintf output");
323*5fb3968eSAaron LI 
324*5fb3968eSAaron LI 		/* Print the formatted sockaddr.  */
325*5fb3968eSAaron LI 		if (printf("%s\n", buf) < 0)
326*5fb3968eSAaron LI 			err(1, "printf");
327*5fb3968eSAaron LI 	}
328*5fb3968eSAaron LI }
329