1*679f6f2dSriastradh /* $NetBSD: getaddrinfo.c,v 1.5 2024/01/10 01:48:16 riastradh Exp $ */
288bc4b53Sriastradh
388bc4b53Sriastradh /*-
488bc4b53Sriastradh * Copyright (c) 2013 The NetBSD Foundation, Inc.
588bc4b53Sriastradh * All rights reserved.
688bc4b53Sriastradh *
788bc4b53Sriastradh * This code is derived from software contributed to The NetBSD Foundation
888bc4b53Sriastradh * by Taylor R. Campbell.
988bc4b53Sriastradh *
1088bc4b53Sriastradh * Redistribution and use in source and binary forms, with or without
1188bc4b53Sriastradh * modification, are permitted provided that the following conditions
1288bc4b53Sriastradh * are met:
1388bc4b53Sriastradh * 1. Redistributions of source code must retain the above copyright
1488bc4b53Sriastradh * notice, this list of conditions and the following disclaimer.
1588bc4b53Sriastradh * 2. Redistributions in binary form must reproduce the above copyright
1688bc4b53Sriastradh * notice, this list of conditions and the following disclaimer in the
1788bc4b53Sriastradh * documentation and/or other materials provided with the distribution.
1888bc4b53Sriastradh *
1988bc4b53Sriastradh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2088bc4b53Sriastradh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2188bc4b53Sriastradh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2288bc4b53Sriastradh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2388bc4b53Sriastradh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2488bc4b53Sriastradh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2588bc4b53Sriastradh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2688bc4b53Sriastradh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2788bc4b53Sriastradh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2888bc4b53Sriastradh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2988bc4b53Sriastradh * POSSIBILITY OF SUCH DAMAGE.
3088bc4b53Sriastradh */
3188bc4b53Sriastradh
3288bc4b53Sriastradh #include <sys/cdefs.h>
33*679f6f2dSriastradh __RCSID("$NetBSD: getaddrinfo.c,v 1.5 2024/01/10 01:48:16 riastradh Exp $");
34aa8e0936Sginsbach
35aa8e0936Sginsbach #include <sys/types.h>
36aa8e0936Sginsbach #include <sys/socket.h>
3788bc4b53Sriastradh
3888bc4b53Sriastradh #include <assert.h>
3988bc4b53Sriastradh #include <err.h>
4088bc4b53Sriastradh #include <errno.h>
4188bc4b53Sriastradh #include <limits.h>
4288bc4b53Sriastradh #include <netdb.h>
4388bc4b53Sriastradh #include <stdbool.h>
4488bc4b53Sriastradh #include <stdint.h>
4588bc4b53Sriastradh #include <stdlib.h>
46aa8e0936Sginsbach #include <stdio.h>
4788bc4b53Sriastradh #include <string.h>
4888bc4b53Sriastradh #include <unistd.h>
4988bc4b53Sriastradh #include <util.h>
5088bc4b53Sriastradh
5188bc4b53Sriastradh #include "tables.h"
5288bc4b53Sriastradh
5388bc4b53Sriastradh static void usage(void) __dead;
5488bc4b53Sriastradh static void printaddrinfo(struct addrinfo *);
5588bc4b53Sriastradh static bool parse_af(const char *, int *);
5688bc4b53Sriastradh static bool parse_protocol(const char *, int *);
5788bc4b53Sriastradh static bool parse_socktype(const char *, int *);
5888bc4b53Sriastradh static bool parse_numeric_tabular(const char *, int *, const char *const *,
5988bc4b53Sriastradh size_t);
6088bc4b53Sriastradh
6188bc4b53Sriastradh int
main(int argc,char ** argv)6288bc4b53Sriastradh main(int argc, char **argv)
6388bc4b53Sriastradh {
6488bc4b53Sriastradh static const struct addrinfo zero_addrinfo;
6588bc4b53Sriastradh struct addrinfo hints = zero_addrinfo;
6688bc4b53Sriastradh struct addrinfo *addrinfo;
6788bc4b53Sriastradh const char *hostname = NULL, *service = NULL;
6888bc4b53Sriastradh int ch;
6988bc4b53Sriastradh int error;
7088bc4b53Sriastradh
7188bc4b53Sriastradh setprogname(argv[0]);
7288bc4b53Sriastradh
7388bc4b53Sriastradh hints.ai_family = AF_UNSPEC;
7488bc4b53Sriastradh hints.ai_socktype = 0;
7588bc4b53Sriastradh hints.ai_protocol = 0;
7688bc4b53Sriastradh hints.ai_flags = 0;
7788bc4b53Sriastradh
7888bc4b53Sriastradh while ((ch = getopt(argc, argv, "cf:nNp:Ps:t:")) != -1) {
7988bc4b53Sriastradh switch (ch) {
8088bc4b53Sriastradh case 'c':
8188bc4b53Sriastradh hints.ai_flags |= AI_CANONNAME;
8288bc4b53Sriastradh break;
8388bc4b53Sriastradh case 'f':
8488bc4b53Sriastradh if (!parse_af(optarg, &hints.ai_family)) {
8588bc4b53Sriastradh warnx("invalid address family: %s", optarg);
8688bc4b53Sriastradh usage();
8788bc4b53Sriastradh }
8888bc4b53Sriastradh break;
8988bc4b53Sriastradh case 'n':
9088bc4b53Sriastradh hints.ai_flags |= AI_NUMERICHOST;
9188bc4b53Sriastradh break;
9288bc4b53Sriastradh case 'N':
9388bc4b53Sriastradh hints.ai_flags |= AI_NUMERICSERV;
9488bc4b53Sriastradh break;
9588bc4b53Sriastradh case 's':
9688bc4b53Sriastradh service = optarg;
9788bc4b53Sriastradh break;
9888bc4b53Sriastradh case 'p':
9988bc4b53Sriastradh if (!parse_protocol(optarg, &hints.ai_protocol)) {
10088bc4b53Sriastradh warnx("invalid protocol: %s", optarg);
10188bc4b53Sriastradh usage();
10288bc4b53Sriastradh }
10355791dffSginsbach break;
10488bc4b53Sriastradh case 'P':
10588bc4b53Sriastradh hints.ai_flags |= AI_PASSIVE;
10688bc4b53Sriastradh break;
10788bc4b53Sriastradh case 't':
10888bc4b53Sriastradh if (!parse_socktype(optarg, &hints.ai_socktype)) {
10988bc4b53Sriastradh warnx("invalid socket type: %s", optarg);
11088bc4b53Sriastradh usage();
11188bc4b53Sriastradh }
11288bc4b53Sriastradh break;
11388bc4b53Sriastradh case '?':
11488bc4b53Sriastradh default:
11588bc4b53Sriastradh usage();
11688bc4b53Sriastradh }
11788bc4b53Sriastradh }
11888bc4b53Sriastradh
11988bc4b53Sriastradh argc -= optind;
12088bc4b53Sriastradh argv += optind;
12188bc4b53Sriastradh
12288bc4b53Sriastradh if (!((argc == 1) || ((argc == 0) && (hints.ai_flags & AI_PASSIVE))))
12388bc4b53Sriastradh usage();
12488bc4b53Sriastradh if (argc == 1)
12588bc4b53Sriastradh hostname = argv[0];
12688bc4b53Sriastradh
127236104beSginsbach if (service != NULL) {
128236104beSginsbach char *p;
129236104beSginsbach
130236104beSginsbach if ((p = strchr(service, '/')) != NULL) {
131236104beSginsbach if (hints.ai_protocol != 0) {
132236104beSginsbach warnx("protocol already specified");
133236104beSginsbach usage();
134236104beSginsbach }
135236104beSginsbach *p = '\0';
136236104beSginsbach p++;
137236104beSginsbach
138236104beSginsbach if (!parse_protocol(p, &hints.ai_protocol)) {
139236104beSginsbach warnx("invalid protocol: %s", p);
140236104beSginsbach usage();
141236104beSginsbach }
142236104beSginsbach }
143236104beSginsbach }
144236104beSginsbach
14588bc4b53Sriastradh error = getaddrinfo(hostname, service, &hints, &addrinfo);
14688bc4b53Sriastradh if (error)
14788bc4b53Sriastradh errx(1, "%s", gai_strerror(error));
14888bc4b53Sriastradh
14988bc4b53Sriastradh if ((hints.ai_flags & AI_CANONNAME) && (addrinfo != NULL)) {
15088bc4b53Sriastradh if (printf("canonname %s\n", addrinfo->ai_canonname) < 0)
15188bc4b53Sriastradh err(1, "printf");
15288bc4b53Sriastradh }
15388bc4b53Sriastradh
15488bc4b53Sriastradh printaddrinfo(addrinfo);
15588bc4b53Sriastradh
15688bc4b53Sriastradh freeaddrinfo(addrinfo);
15788bc4b53Sriastradh
15888bc4b53Sriastradh return 0;
15988bc4b53Sriastradh }
16088bc4b53Sriastradh
16188bc4b53Sriastradh static void __dead
usage(void)16288bc4b53Sriastradh usage(void)
16388bc4b53Sriastradh {
16488bc4b53Sriastradh
16588bc4b53Sriastradh (void)fprintf(stderr, "Usage: %s", getprogname());
16688bc4b53Sriastradh (void)fprintf(stderr,
16788bc4b53Sriastradh " [-f <family>] [-p <protocol>] [-t <socktype>] [-s <service>]\n");
16888bc4b53Sriastradh (void)fprintf(stderr, " [-cnNP] [<hostname>]\n");
16988bc4b53Sriastradh exit(1);
17088bc4b53Sriastradh }
17188bc4b53Sriastradh
17288bc4b53Sriastradh static bool
parse_af(const char * string,int * afp)17388bc4b53Sriastradh parse_af(const char *string, int *afp)
17488bc4b53Sriastradh {
17588bc4b53Sriastradh
17688bc4b53Sriastradh return parse_numeric_tabular(string, afp, address_families,
17788bc4b53Sriastradh __arraycount(address_families));
17888bc4b53Sriastradh }
17988bc4b53Sriastradh
18088bc4b53Sriastradh static bool
parse_protocol(const char * string,int * protop)18188bc4b53Sriastradh parse_protocol(const char *string, int *protop)
18288bc4b53Sriastradh {
18388bc4b53Sriastradh struct protoent *protoent;
18488bc4b53Sriastradh char *end;
18588bc4b53Sriastradh long value;
18688bc4b53Sriastradh
18788bc4b53Sriastradh errno = 0;
18888bc4b53Sriastradh value = strtol(string, &end, 0);
18988bc4b53Sriastradh if ((string[0] == '\0') || (*end != '\0'))
19088bc4b53Sriastradh goto numeric_failed;
19188bc4b53Sriastradh if ((errno == ERANGE) && ((value == LONG_MAX) || (value == LONG_MIN)))
19288bc4b53Sriastradh goto numeric_failed;
19388bc4b53Sriastradh if ((value > INT_MAX) || (value < INT_MIN))
19488bc4b53Sriastradh goto numeric_failed;
19588bc4b53Sriastradh
19688bc4b53Sriastradh *protop = value;
19788bc4b53Sriastradh return true;
19888bc4b53Sriastradh
19988bc4b53Sriastradh numeric_failed:
20088bc4b53Sriastradh protoent = getprotobyname(string);
20188bc4b53Sriastradh if (protoent == NULL)
20288bc4b53Sriastradh goto protoent_failed;
20388bc4b53Sriastradh
20488bc4b53Sriastradh *protop = protoent->p_proto;
20588bc4b53Sriastradh return true;
20688bc4b53Sriastradh
20788bc4b53Sriastradh protoent_failed:
20888bc4b53Sriastradh return false;
20988bc4b53Sriastradh }
21088bc4b53Sriastradh
21188bc4b53Sriastradh static bool
parse_socktype(const char * string,int * typep)21288bc4b53Sriastradh parse_socktype(const char *string, int *typep)
21388bc4b53Sriastradh {
21488bc4b53Sriastradh
21588bc4b53Sriastradh return parse_numeric_tabular(string, typep, socket_types,
21688bc4b53Sriastradh __arraycount(socket_types));
21788bc4b53Sriastradh }
21888bc4b53Sriastradh
21988bc4b53Sriastradh static bool
parse_numeric_tabular(const char * string,int * valuep,const char * const * table,size_t n)22088bc4b53Sriastradh parse_numeric_tabular(const char *string, int *valuep,
22188bc4b53Sriastradh const char *const *table, size_t n)
22288bc4b53Sriastradh {
22388bc4b53Sriastradh char *end;
22488bc4b53Sriastradh long value;
22588bc4b53Sriastradh size_t i;
22688bc4b53Sriastradh
22788bc4b53Sriastradh assert((uintmax_t)n <= (uintmax_t)INT_MAX);
22888bc4b53Sriastradh
22988bc4b53Sriastradh errno = 0;
23088bc4b53Sriastradh value = strtol(string, &end, 0);
23188bc4b53Sriastradh if ((string[0] == '\0') || (*end != '\0'))
23288bc4b53Sriastradh goto numeric_failed;
23388bc4b53Sriastradh if ((errno == ERANGE) && ((value == LONG_MAX) || (value == LONG_MIN)))
23488bc4b53Sriastradh goto numeric_failed;
23588bc4b53Sriastradh if ((value > INT_MAX) || (value < INT_MIN))
23688bc4b53Sriastradh goto numeric_failed;
23788bc4b53Sriastradh
23888bc4b53Sriastradh *valuep = value;
23988bc4b53Sriastradh return true;
24088bc4b53Sriastradh
24188bc4b53Sriastradh numeric_failed:
24288bc4b53Sriastradh for (i = 0; i < n; i++)
24388bc4b53Sriastradh if ((table[i] != NULL) && (strcmp(string, table[i]) == 0))
24488bc4b53Sriastradh break;
24588bc4b53Sriastradh if (i == n)
24688bc4b53Sriastradh goto table_failed;
24788bc4b53Sriastradh *valuep = i;
24888bc4b53Sriastradh return true;
24988bc4b53Sriastradh
25088bc4b53Sriastradh table_failed:
25188bc4b53Sriastradh return false;
25288bc4b53Sriastradh }
25388bc4b53Sriastradh
25488bc4b53Sriastradh static void
printaddrinfo(struct addrinfo * addrinfo)25588bc4b53Sriastradh printaddrinfo(struct addrinfo *addrinfo)
25688bc4b53Sriastradh {
25788bc4b53Sriastradh struct addrinfo *ai;
25888bc4b53Sriastradh char buf[1024];
25988bc4b53Sriastradh int n;
26088bc4b53Sriastradh struct protoent *protoent;
26188bc4b53Sriastradh
26288bc4b53Sriastradh for (ai = addrinfo; ai != NULL; ai = ai->ai_next) {
26388bc4b53Sriastradh /* Print the socket type. */
26488bc4b53Sriastradh if ((ai->ai_socktype >= 0) &&
26588bc4b53Sriastradh ((size_t)ai->ai_socktype < __arraycount(socket_types)) &&
26688bc4b53Sriastradh (socket_types[ai->ai_socktype] != NULL))
26788bc4b53Sriastradh n = printf("%s", socket_types[ai->ai_socktype]);
26888bc4b53Sriastradh else
26988bc4b53Sriastradh n = printf("%d", ai->ai_socktype);
27088bc4b53Sriastradh if (n < 0)
27188bc4b53Sriastradh err(1, "printf");
27288bc4b53Sriastradh
27388bc4b53Sriastradh /* Print the address family. */
27488bc4b53Sriastradh if ((ai->ai_family >= 0) &&
27588bc4b53Sriastradh ((size_t)ai->ai_family < __arraycount(address_families)) &&
27688bc4b53Sriastradh (address_families[ai->ai_family] != NULL))
27788bc4b53Sriastradh n = printf(" %s", address_families[ai->ai_family]);
27888bc4b53Sriastradh else
27988bc4b53Sriastradh n = printf(" %d", ai->ai_family);
28088bc4b53Sriastradh if (n < 0)
28188bc4b53Sriastradh err(1, "printf");
28288bc4b53Sriastradh
28388bc4b53Sriastradh /* Print the protocol number. */
28488bc4b53Sriastradh protoent = getprotobynumber(ai->ai_protocol);
28588bc4b53Sriastradh if (protoent == NULL)
28688bc4b53Sriastradh n = printf(" %d", ai->ai_protocol);
28788bc4b53Sriastradh else
28888bc4b53Sriastradh n = printf(" %s", protoent->p_name);
28988bc4b53Sriastradh if (n < 0)
29088bc4b53Sriastradh err(1, "printf");
29188bc4b53Sriastradh
29288bc4b53Sriastradh /* Format the sockaddr. */
29388bc4b53Sriastradh switch (ai->ai_family) {
29488bc4b53Sriastradh case AF_INET:
29588bc4b53Sriastradh case AF_INET6:
29688bc4b53Sriastradh n = sockaddr_snprintf(buf, sizeof(buf), " %a %p",
29788bc4b53Sriastradh ai->ai_addr);
29888bc4b53Sriastradh break;
29988bc4b53Sriastradh default:
30088bc4b53Sriastradh n = sockaddr_snprintf(buf, sizeof(buf),
30188bc4b53Sriastradh "%a %p %I %F %R %S", ai->ai_addr);
30288bc4b53Sriastradh }
30388bc4b53Sriastradh
30488bc4b53Sriastradh /*
30588bc4b53Sriastradh * Check for sockaddr_snprintf failure.
30688bc4b53Sriastradh *
30788bc4b53Sriastradh * XXX sockaddr_snprintf's error reporting is botched
30888bc4b53Sriastradh * -- man page says it sets errno, but if getnameinfo
30988bc4b53Sriastradh * fails, errno is not where it reports the error...
31088bc4b53Sriastradh */
31188bc4b53Sriastradh if (n < 0) {
31288bc4b53Sriastradh warnx("sockaddr_snprintf failed");
31388bc4b53Sriastradh continue;
31488bc4b53Sriastradh }
31588bc4b53Sriastradh if (sizeof(buf) <= (size_t)n)
31688bc4b53Sriastradh warnx("truncated sockaddr_snprintf output");
31788bc4b53Sriastradh
31888bc4b53Sriastradh /* Print the formatted sockaddr. */
31988bc4b53Sriastradh if (printf("%s\n", buf) < 0)
32088bc4b53Sriastradh err(1, "printf");
32188bc4b53Sriastradh }
32288bc4b53Sriastradh }
323