getaddrinfo.c revision 1.6 1 /* $NetBSD: getaddrinfo.c,v 1.6 2025/02/06 19:35:28 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: getaddrinfo.c,v 1.6 2025/02/06 19:35:28 christos Exp $");
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37
38 #include <assert.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <limits.h>
42 #include <netdb.h>
43 #include <stdbool.h>
44 #include <stdint.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <util.h>
50
51 #include "tables.h"
52 #include "support.h"
53
54 static void usage(void) __dead;
55 static void printaddrinfo(struct addrinfo *);
56
57 int
58 main(int argc, char **argv)
59 {
60 static const struct addrinfo zero_addrinfo;
61 struct addrinfo hints = zero_addrinfo;
62 struct addrinfo *addrinfo;
63 const char *hostname = NULL;
64 char *service = NULL;
65 int ch;
66 int error;
67
68 setprogname(argv[0]);
69
70 hints.ai_family = AF_UNSPEC;
71 hints.ai_socktype = 0;
72 hints.ai_protocol = 0;
73 hints.ai_flags = 0;
74
75 while ((ch = getopt(argc, argv, "cf:nNp:Ps:t:")) != -1) {
76 switch (ch) {
77 case 'c':
78 hints.ai_flags |= AI_CANONNAME;
79 break;
80 case 'f':
81 if (!parse_af(optarg, &hints.ai_family)) {
82 warnx("invalid address family: %s", optarg);
83 usage();
84 }
85 break;
86 case 'n':
87 hints.ai_flags |= AI_NUMERICHOST;
88 break;
89 case 'N':
90 hints.ai_flags |= AI_NUMERICSERV;
91 break;
92 case 's':
93 service = optarg;
94 break;
95 case 'p':
96 if (!parse_protocol(optarg, &hints.ai_protocol)) {
97 warnx("invalid protocol: %s", optarg);
98 usage();
99 }
100 break;
101 case 'P':
102 hints.ai_flags |= AI_PASSIVE;
103 break;
104 case 't':
105 if (!parse_socktype(optarg, &hints.ai_socktype)) {
106 warnx("invalid socket type: %s", optarg);
107 usage();
108 }
109 break;
110 case '?':
111 default:
112 usage();
113 }
114 }
115
116 argc -= optind;
117 argv += optind;
118
119 if (!((argc == 1) || ((argc == 0) && (hints.ai_flags & AI_PASSIVE))))
120 usage();
121 if (argc == 1)
122 hostname = argv[0];
123
124 if (service != NULL) {
125 char *p;
126
127 if ((p = strchr(service, '/')) != NULL) {
128 if (hints.ai_protocol != 0) {
129 warnx("protocol already specified");
130 usage();
131 }
132 *p = '\0';
133 p++;
134
135 if (!parse_protocol(p, &hints.ai_protocol)) {
136 warnx("invalid protocol: %s", p);
137 usage();
138 }
139 }
140 }
141
142 error = getaddrinfo(hostname, service, &hints, &addrinfo);
143 if (error)
144 errx(1, "%s", gai_strerror(error));
145
146 if ((hints.ai_flags & AI_CANONNAME) && (addrinfo != NULL)) {
147 if (printf("canonname %s\n", addrinfo->ai_canonname) < 0)
148 err(1, "printf");
149 }
150
151 printaddrinfo(addrinfo);
152
153 freeaddrinfo(addrinfo);
154
155 return 0;
156 }
157
158 static void __dead
159 usage(void)
160 {
161
162 (void)fprintf(stderr, "Usage: %s", getprogname());
163 (void)fprintf(stderr,
164 " [-f <family>] [-p <protocol>] [-t <socktype>] [-s <service>]\n");
165 (void)fprintf(stderr, " [-cnNP] [<hostname>]\n");
166 exit(1);
167 }
168
169 static void
170 printaddrinfo(struct addrinfo *addrinfo)
171 {
172 struct addrinfo *ai;
173 char buf[1024];
174 int n;
175 struct protoent *protoent;
176
177 for (ai = addrinfo; ai != NULL; ai = ai->ai_next) {
178 /* Print the socket type. */
179 if ((ai->ai_socktype >= 0) &&
180 ((size_t)ai->ai_socktype < __arraycount(socket_types)) &&
181 (socket_types[ai->ai_socktype] != NULL))
182 n = printf("%s", socket_types[ai->ai_socktype]);
183 else
184 n = printf("%d", ai->ai_socktype);
185 if (n < 0)
186 err(1, "printf");
187
188 /* Print the address family. */
189 if ((ai->ai_family >= 0) &&
190 ((size_t)ai->ai_family < __arraycount(address_families)) &&
191 (address_families[ai->ai_family] != NULL))
192 n = printf(" %s", address_families[ai->ai_family]);
193 else
194 n = printf(" %d", ai->ai_family);
195 if (n < 0)
196 err(1, "printf");
197
198 /* Print the protocol number. */
199 protoent = getprotobynumber(ai->ai_protocol);
200 if (protoent == NULL)
201 n = printf(" %d", ai->ai_protocol);
202 else
203 n = printf(" %s", protoent->p_name);
204 if (n < 0)
205 err(1, "printf");
206
207 /* Format the sockaddr. */
208 switch (ai->ai_family) {
209 case AF_INET:
210 case AF_INET6:
211 n = sockaddr_snprintf(buf, sizeof(buf), " %a %p",
212 ai->ai_addr);
213 break;
214 default:
215 n = sockaddr_snprintf(buf, sizeof(buf),
216 "%a %p %I %F %R %S", ai->ai_addr);
217 }
218
219 /*
220 * Check for sockaddr_snprintf failure.
221 *
222 * XXX sockaddr_snprintf's error reporting is botched
223 * -- man page says it sets errno, but if getnameinfo
224 * fails, errno is not where it reports the error...
225 */
226 if (n < 0) {
227 warnx("sockaddr_snprintf failed");
228 continue;
229 }
230 if (sizeof(buf) <= (size_t)n)
231 warnx("truncated sockaddr_snprintf output");
232
233 /* Print the formatted sockaddr. */
234 if (printf("%s\n", buf) < 0)
235 err(1, "printf");
236 }
237 }
238