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