xref: /freebsd/lib/libc/tests/net/getaddrinfo/getaddrinfo.c (revision c10fd9ac00b1097ab622d055dcc3d1484012bccc)
153134577SGleb Smirnoff /*-
253134577SGleb Smirnoff  * SPDX-License-Identifier: BSD-2-Clause
353134577SGleb Smirnoff  *
453134577SGleb Smirnoff  * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
553134577SGleb Smirnoff  *
653134577SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
753134577SGleb Smirnoff  * modification, are permitted provided that the following conditions
853134577SGleb Smirnoff  * are met:
953134577SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
1053134577SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
1153134577SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
1253134577SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
1353134577SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
1453134577SGleb Smirnoff  *
1553134577SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1653134577SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1753134577SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1853134577SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1953134577SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2053134577SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2153134577SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2253134577SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2353134577SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2453134577SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2553134577SGleb Smirnoff  * SUCH DAMAGE.
2653134577SGleb Smirnoff  */
2753134577SGleb Smirnoff 
2853134577SGleb Smirnoff #include <dlfcn.h>
2953134577SGleb Smirnoff #include <errno.h>
3053134577SGleb Smirnoff #include <netdb.h>
3153134577SGleb Smirnoff #include <stdlib.h>
3253134577SGleb Smirnoff #include <string.h>
3353134577SGleb Smirnoff #include <resolv.h>
3453134577SGleb Smirnoff 
3553134577SGleb Smirnoff #include <atf-c.h>
3653134577SGleb Smirnoff 
3753134577SGleb Smirnoff static const char goodname[] = "www.freebsd.org";
3853134577SGleb Smirnoff static const char goodname_dot[] = "www.freebsd.org.";
3953134577SGleb Smirnoff static const char badname[] = "does-not-exist.freebsd.org";
4053134577SGleb Smirnoff static const char badname_dot[] = "does-not-exist.freebsd.org.";
4153134577SGleb Smirnoff static const char ipv6onlyname[] = "beefy15.nyi.freebsd.org";
4253134577SGleb Smirnoff static const char ipv6onlyname_dot[] = "beefy15.nyi.freebsd.org.";
4353134577SGleb Smirnoff static const char ipv4onlyname[] = "ipv4only.arpa";
4453134577SGleb Smirnoff static const char ipv4onlyname_dot[] = "ipv4only.arpa.";
4553134577SGleb Smirnoff /*
4653134577SGleb Smirnoff  * We need an IP address that doesn't exist, but not reported with ICMP
4753134577SGleb Smirnoff  * unreachable by the nearest router.  Let's try TEST-NET-3.
4853134577SGleb Smirnoff  */
4953134577SGleb Smirnoff static char badresolvconf[] =	"nameserver 203.0.113.1";
5053134577SGleb Smirnoff static char badresolvconf2[] =	"nameserver 203.0.113.1\n"
5153134577SGleb Smirnoff 				"nameserver 203.0.113.2";
5253134577SGleb Smirnoff static char *resconf = NULL;
5353134577SGleb Smirnoff FILE *
fopen(const char * restrict path,const char * restrict mode)5453134577SGleb Smirnoff fopen(const char * restrict path, const char * restrict mode)
5553134577SGleb Smirnoff {
5653134577SGleb Smirnoff 	static FILE *(*orig)(const char *, const char *);
5753134577SGleb Smirnoff 
5853134577SGleb Smirnoff 	if (orig == NULL && (orig = dlsym(RTLD_NEXT, "fopen")) == NULL)
5953134577SGleb Smirnoff 		atf_libc_error(ENOENT, "dlsym(fopen): %s", dlerror());
6053134577SGleb Smirnoff 	if (resconf != NULL && strcmp(path, _PATH_RESCONF) == 0)
6153134577SGleb Smirnoff 		return (fmemopen(resconf, strlen(resconf), mode));
6253134577SGleb Smirnoff 	else
6353134577SGleb Smirnoff 		return (orig(path, mode));
6453134577SGleb Smirnoff }
6553134577SGleb Smirnoff 
6653134577SGleb Smirnoff static int send_error = 0;
6753134577SGleb Smirnoff ssize_t
send(int s,const void * msg,size_t len,int flags)6853134577SGleb Smirnoff send(int s, const void *msg, size_t len, int flags)
6953134577SGleb Smirnoff {
7053134577SGleb Smirnoff 	static ssize_t (*orig)(int, const void *, size_t, int);
7153134577SGleb Smirnoff 
7253134577SGleb Smirnoff 	if (orig == NULL && (orig = dlsym(RTLD_NEXT, "send")) == NULL)
7353134577SGleb Smirnoff 		atf_libc_error(ENOENT, "dlsym(send): %s", dlerror());
7453134577SGleb Smirnoff 	if (send_error != 0) {
7553134577SGleb Smirnoff 		errno = send_error;
7653134577SGleb Smirnoff 		return (-1);
7753134577SGleb Smirnoff 	} else {
7853134577SGleb Smirnoff 		return (orig(s, msg, len, flags));
7953134577SGleb Smirnoff 	}
8053134577SGleb Smirnoff }
8153134577SGleb Smirnoff 
82*c10fd9acSOlivier Cochard ATF_TC(basic);
ATF_TC_HEAD(basic,tc)83*c10fd9acSOlivier Cochard ATF_TC_HEAD(basic, tc)
84*c10fd9acSOlivier Cochard {
85*c10fd9acSOlivier Cochard 	atf_tc_set_md_var(tc, "require.config", "allow_network_access");
86*c10fd9acSOlivier Cochard }
87*c10fd9acSOlivier Cochard 
ATF_TC_BODY(basic,tc)8853134577SGleb Smirnoff ATF_TC_BODY(basic, tc)
8953134577SGleb Smirnoff {
9053134577SGleb Smirnoff 	static const struct addrinfo hints = {
9153134577SGleb Smirnoff 		.ai_family = AF_UNSPEC,
9253134577SGleb Smirnoff 		.ai_flags = AI_CANONNAME,
9353134577SGleb Smirnoff 	};
9453134577SGleb Smirnoff 	struct addrinfo *res;
9553134577SGleb Smirnoff 	int rv;
9653134577SGleb Smirnoff 
9753134577SGleb Smirnoff 	rv = getaddrinfo(goodname, NULL, &hints, &res);
9853134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == 0,
9953134577SGleb Smirnoff 	    "Expected 0, got %d (%s)", rv, gai_strerror(rv));
10053134577SGleb Smirnoff 	freeaddrinfo(res);
10153134577SGleb Smirnoff 
10253134577SGleb Smirnoff 	rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
10353134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == 0,
10453134577SGleb Smirnoff 	    "Expected 0, got %d (%s)", rv, gai_strerror(rv));
10553134577SGleb Smirnoff 	freeaddrinfo(res);
10653134577SGleb Smirnoff 
10753134577SGleb Smirnoff 	rv = getaddrinfo(badname, NULL, &hints, &res);
10853134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_NONAME,
10953134577SGleb Smirnoff 	    "Expected %d (EAI_NONAME), got %d (%s)",
11053134577SGleb Smirnoff 	    EAI_NONAME, rv, gai_strerror(rv));
11153134577SGleb Smirnoff 
11253134577SGleb Smirnoff 	rv = getaddrinfo(badname_dot, NULL, &hints, &res);
11353134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_NONAME,
11453134577SGleb Smirnoff 	    "Expected %d (EAI_NONAME), got %d (%s)",
11553134577SGleb Smirnoff 	    EAI_NONAME, rv, gai_strerror(rv));
11653134577SGleb Smirnoff }
11753134577SGleb Smirnoff 
11853134577SGleb Smirnoff ATF_TC_WITHOUT_HEAD(timeout);
ATF_TC_BODY(timeout,tc)11953134577SGleb Smirnoff ATF_TC_BODY(timeout, tc)
12053134577SGleb Smirnoff {
12153134577SGleb Smirnoff 	static const struct addrinfo hints = {
12253134577SGleb Smirnoff 		.ai_family = AF_UNSPEC,
12353134577SGleb Smirnoff 		.ai_flags = AI_CANONNAME,
12453134577SGleb Smirnoff 	};
12553134577SGleb Smirnoff 	struct addrinfo *res;
12653134577SGleb Smirnoff 	int rv;
12753134577SGleb Smirnoff 
12853134577SGleb Smirnoff 	resconf = badresolvconf;
12953134577SGleb Smirnoff 	rv = getaddrinfo(goodname, NULL, &hints, &res);
130d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
131d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
132d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
13353134577SGleb Smirnoff 
13453134577SGleb Smirnoff 	rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
135d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
136d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
137d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
13853134577SGleb Smirnoff }
13953134577SGleb Smirnoff 
14053134577SGleb Smirnoff ATF_TC_WITHOUT_HEAD(timeout_specific);
ATF_TC_BODY(timeout_specific,tc)14153134577SGleb Smirnoff ATF_TC_BODY(timeout_specific, tc)
14253134577SGleb Smirnoff {
14353134577SGleb Smirnoff 	static const struct addrinfo hints = {
14453134577SGleb Smirnoff 		.ai_family = AF_INET,
14553134577SGleb Smirnoff 		.ai_socktype = SOCK_STREAM,
14653134577SGleb Smirnoff 		.ai_flags = AI_CANONNAME,
14753134577SGleb Smirnoff 	};
14853134577SGleb Smirnoff 	struct addrinfo *res;
14953134577SGleb Smirnoff 	int rv;
15053134577SGleb Smirnoff 
15153134577SGleb Smirnoff 	resconf = badresolvconf;
15253134577SGleb Smirnoff 	rv = getaddrinfo(goodname, "666", &hints, &res);
153d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
154d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
155d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
15653134577SGleb Smirnoff 
15753134577SGleb Smirnoff 	rv = getaddrinfo(goodname_dot, "666", &hints, &res);
158d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
159d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
160d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
16153134577SGleb Smirnoff }
16253134577SGleb Smirnoff 
16353134577SGleb Smirnoff ATF_TC_WITHOUT_HEAD(timeout2);
ATF_TC_BODY(timeout2,tc)16453134577SGleb Smirnoff ATF_TC_BODY(timeout2, tc)
16553134577SGleb Smirnoff {
16653134577SGleb Smirnoff 	static const struct addrinfo hints = {
16753134577SGleb Smirnoff 		.ai_family = AF_UNSPEC,
16853134577SGleb Smirnoff 		.ai_flags = AI_CANONNAME,
16953134577SGleb Smirnoff 	};
17053134577SGleb Smirnoff 	struct addrinfo *res;
17153134577SGleb Smirnoff 	int rv;
17253134577SGleb Smirnoff 
17353134577SGleb Smirnoff 	resconf = badresolvconf2;
17453134577SGleb Smirnoff 	rv = getaddrinfo(goodname, NULL, &hints, &res);
175d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
176d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
177d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
17853134577SGleb Smirnoff 
17953134577SGleb Smirnoff 	rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
180d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
181d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
182d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
18353134577SGleb Smirnoff }
18453134577SGleb Smirnoff 
18553134577SGleb Smirnoff /*
18653134577SGleb Smirnoff  * Emulate interface/network down.
18753134577SGleb Smirnoff  */
18853134577SGleb Smirnoff ATF_TC_WITHOUT_HEAD(netdown);
ATF_TC_BODY(netdown,tc)18953134577SGleb Smirnoff ATF_TC_BODY(netdown, tc)
19053134577SGleb Smirnoff {
19153134577SGleb Smirnoff 	static const struct addrinfo hints = {
19253134577SGleb Smirnoff 		.ai_family = AF_UNSPEC,
19353134577SGleb Smirnoff 		.ai_flags = AI_CANONNAME,
19453134577SGleb Smirnoff 	};
19553134577SGleb Smirnoff 	struct addrinfo *res;
19653134577SGleb Smirnoff 	int rv;
19753134577SGleb Smirnoff 
19853134577SGleb Smirnoff 	send_error = ENETDOWN;
19953134577SGleb Smirnoff 	rv = getaddrinfo(goodname, NULL, &hints, &res);
200d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
201d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
202d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
20353134577SGleb Smirnoff 
20453134577SGleb Smirnoff 	rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
205d803854bSGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_AGAIN,
206d803854bSGleb Smirnoff 	    "Expected %d (EAI_AGAIN), got %d (%s)",
207d803854bSGleb Smirnoff 	    EAI_AGAIN, rv, gai_strerror(rv));
20853134577SGleb Smirnoff }
20953134577SGleb Smirnoff 
21053134577SGleb Smirnoff /*
21153134577SGleb Smirnoff  * See https://reviews.freebsd.org/D37139.
21253134577SGleb Smirnoff  */
213*c10fd9acSOlivier Cochard ATF_TC(nofamily);
ATF_TC_HEAD(nofamily,tc)214*c10fd9acSOlivier Cochard ATF_TC_HEAD(nofamily, tc)
215*c10fd9acSOlivier Cochard {
216*c10fd9acSOlivier Cochard 	atf_tc_set_md_var(tc, "require.config", "allow_network_access");
217*c10fd9acSOlivier Cochard }
ATF_TC_BODY(nofamily,tc)21853134577SGleb Smirnoff ATF_TC_BODY(nofamily, tc)
21953134577SGleb Smirnoff {
22053134577SGleb Smirnoff 	static const struct addrinfo hints4 = {
22153134577SGleb Smirnoff 		.ai_family = AF_INET,
22253134577SGleb Smirnoff 		.ai_flags = AI_CANONNAME,
22353134577SGleb Smirnoff 	}, hints6 = {
22453134577SGleb Smirnoff 		.ai_family = AF_INET6,
22553134577SGleb Smirnoff 		.ai_flags = AI_CANONNAME,
22653134577SGleb Smirnoff 	};
22753134577SGleb Smirnoff 	struct addrinfo *res;
22853134577SGleb Smirnoff 	int rv;
22953134577SGleb Smirnoff 
23053134577SGleb Smirnoff 	rv = getaddrinfo(ipv6onlyname, NULL, &hints4, &res);
23153134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
23253134577SGleb Smirnoff 	    "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
23353134577SGleb Smirnoff 	    EAI_ADDRFAMILY, rv, gai_strerror(rv));
23453134577SGleb Smirnoff 
23553134577SGleb Smirnoff 	rv = getaddrinfo(ipv6onlyname_dot, NULL, &hints4, &res);
23653134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
23753134577SGleb Smirnoff 	    "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
23853134577SGleb Smirnoff 	    EAI_ADDRFAMILY, rv, gai_strerror(rv));
23953134577SGleb Smirnoff 
24053134577SGleb Smirnoff 	rv = getaddrinfo(ipv4onlyname, NULL, &hints6, &res);
24153134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
24253134577SGleb Smirnoff 	    "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
24353134577SGleb Smirnoff 	    EAI_ADDRFAMILY, rv, gai_strerror(rv));
24453134577SGleb Smirnoff 
24553134577SGleb Smirnoff 	rv = getaddrinfo(ipv4onlyname_dot, NULL, &hints6, &res);
24653134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
24753134577SGleb Smirnoff 	    "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
24853134577SGleb Smirnoff 	    EAI_ADDRFAMILY, rv, gai_strerror(rv));
24953134577SGleb Smirnoff 
25053134577SGleb Smirnoff 	rv = getaddrinfo(badname, NULL, &hints4, &res);
25153134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_NONAME,
25253134577SGleb Smirnoff 	    "Expected %d (EAI_NONAME), got %d (%s)",
25353134577SGleb Smirnoff 	    EAI_NONAME, rv, gai_strerror(rv));
25453134577SGleb Smirnoff 
25553134577SGleb Smirnoff 	rv = getaddrinfo(badname_dot, NULL, &hints6, &res);
25653134577SGleb Smirnoff 	ATF_REQUIRE_MSG(rv == EAI_NONAME,
25753134577SGleb Smirnoff 	    "Expected %d (EAI_NONAME), got %d (%s)",
25853134577SGleb Smirnoff 	    EAI_NONAME, rv, gai_strerror(rv));
25953134577SGleb Smirnoff }
26053134577SGleb Smirnoff 
ATF_TP_ADD_TCS(tp)26153134577SGleb Smirnoff ATF_TP_ADD_TCS(tp)
26253134577SGleb Smirnoff {
26353134577SGleb Smirnoff 	ATF_TP_ADD_TC(tp, basic);
26453134577SGleb Smirnoff 	ATF_TP_ADD_TC(tp, timeout);
26553134577SGleb Smirnoff 	ATF_TP_ADD_TC(tp, timeout_specific);
26653134577SGleb Smirnoff 	ATF_TP_ADD_TC(tp, timeout2);
26753134577SGleb Smirnoff 	ATF_TP_ADD_TC(tp, netdown);
26853134577SGleb Smirnoff 	ATF_TP_ADD_TC(tp, nofamily);
26953134577SGleb Smirnoff 
27053134577SGleb Smirnoff 	return (atf_no_error());
27153134577SGleb Smirnoff }
272