xref: /freebsd/tests/sys/netinet/ip6_v4mapped_test.c (revision 6dced2c6358e467ac1dccd99f6f648d4f71957a8)
1ae5c3dfdSMark Johnston /*-
2ae5c3dfdSMark Johnston  * SPDX-License-Identifier: BSD-2-Clause
3ae5c3dfdSMark Johnston  *
4ae5c3dfdSMark Johnston  * Copyright (c) 2022 Michael J. Karels.
5ae5c3dfdSMark Johnston  * Copyright (c) 2020 Netflix, Inc.
6ae5c3dfdSMark Johnston  *
7ae5c3dfdSMark Johnston  * Redistribution and use in source and binary forms, with or without
8ae5c3dfdSMark Johnston  * modification, are permitted provided that the following conditions are
9ae5c3dfdSMark Johnston  * met:
10ae5c3dfdSMark Johnston  * 1. Redistributions of source code must retain the above copyright
11ae5c3dfdSMark Johnston  *    notice, this list of conditions and the following disclaimer.
12ae5c3dfdSMark Johnston  * 2. Redistributions in binary form must reproduce the above copyright
13ae5c3dfdSMark Johnston  *    notice, this list of conditions and the following disclaimer in
14ae5c3dfdSMark Johnston  *    the documentation and/or other materials provided with the
15ae5c3dfdSMark Johnston  *    distribution.
16ae5c3dfdSMark Johnston  *
17ae5c3dfdSMark Johnston  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18ae5c3dfdSMark Johnston  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19ae5c3dfdSMark Johnston  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ae5c3dfdSMark Johnston  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21ae5c3dfdSMark Johnston  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22ae5c3dfdSMark Johnston  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23ae5c3dfdSMark Johnston  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24ae5c3dfdSMark Johnston  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25ae5c3dfdSMark Johnston  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26ae5c3dfdSMark Johnston  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27ae5c3dfdSMark Johnston  * SUCH DAMAGE.
28ae5c3dfdSMark Johnston  */
29ae5c3dfdSMark Johnston 
30ae5c3dfdSMark Johnston /*
31ae5c3dfdSMark Johnston  * This test is derived from tcp_connect_port_test.c.
32ae5c3dfdSMark Johnston  */
33ae5c3dfdSMark Johnston 
34ae5c3dfdSMark Johnston #include <sys/param.h>
35ae5c3dfdSMark Johnston #include <sys/socket.h>
36ae5c3dfdSMark Johnston #include <sys/stat.h>
37ae5c3dfdSMark Johnston #include <sys/sysctl.h>
38ae5c3dfdSMark Johnston 
39ae5c3dfdSMark Johnston #include <netinet/in.h>
40ae5c3dfdSMark Johnston 
41ae5c3dfdSMark Johnston #include <err.h>
42ae5c3dfdSMark Johnston #include <errno.h>
43ae5c3dfdSMark Johnston #include <fcntl.h>
44ae5c3dfdSMark Johnston #include <netdb.h>
45ae5c3dfdSMark Johnston #include <stdio.h>
46ae5c3dfdSMark Johnston #include <stdlib.h>
47ae5c3dfdSMark Johnston #include <unistd.h>
48ae5c3dfdSMark Johnston 
49ae5c3dfdSMark Johnston #include <atf-c.h>
50ae5c3dfdSMark Johnston 
51ae5c3dfdSMark Johnston #define	SYSCTLBAKFILE	"tmp.net.inet.ip.portrange.values"
52ae5c3dfdSMark Johnston 
53ae5c3dfdSMark Johnston #define	PORT_FIRST	10000		/* normal default */
54ae5c3dfdSMark Johnston #define	PORT_LAST	10003
55ae5c3dfdSMark Johnston #define	LOOPS		10		/* 5 should be enough */
56ae5c3dfdSMark Johnston 
57ae5c3dfdSMark Johnston struct portrange {
58ae5c3dfdSMark Johnston 	int	first;
59ae5c3dfdSMark Johnston 	int	last;
60ae5c3dfdSMark Johnston };
61ae5c3dfdSMark Johnston 
62ae5c3dfdSMark Johnston /*
63ae5c3dfdSMark Johnston  * Set first and last ports in the ipport range.  Save the old values
64ae5c3dfdSMark Johnston  * of the sysctls so they can be restored later.
65ae5c3dfdSMark Johnston  */
66ae5c3dfdSMark Johnston static void
set_portrange(void)67ae5c3dfdSMark Johnston set_portrange(void)
68ae5c3dfdSMark Johnston {
69ae5c3dfdSMark Johnston 	int error, fd, first_new, last_new;
70ae5c3dfdSMark Johnston 	struct portrange save_ports;
71ae5c3dfdSMark Johnston 	size_t sysctlsz;
72ae5c3dfdSMark Johnston 
73ae5c3dfdSMark Johnston 	/*
74ae5c3dfdSMark Johnston 	 * Pre-emptively unlink our restoration file, so we will do no
75ae5c3dfdSMark Johnston 	 * restoration on error.
76ae5c3dfdSMark Johnston 	 */
77ae5c3dfdSMark Johnston 	unlink(SYSCTLBAKFILE);
78ae5c3dfdSMark Johnston 
79ae5c3dfdSMark Johnston 	/*
80ae5c3dfdSMark Johnston 	 * Set the net.inet.ip.portrange.{first,last} sysctls. Save the
81ae5c3dfdSMark Johnston 	 * old values so we can restore them.
82ae5c3dfdSMark Johnston 	 */
83ae5c3dfdSMark Johnston 	first_new = PORT_FIRST;
84ae5c3dfdSMark Johnston 	sysctlsz = sizeof(save_ports.first);
85ae5c3dfdSMark Johnston 	error = sysctlbyname("net.inet.ip.portrange.first", &save_ports.first,
86ae5c3dfdSMark Johnston 	    &sysctlsz, &first_new, sizeof(first_new));
87ae5c3dfdSMark Johnston 	if (error) {
88ae5c3dfdSMark Johnston 		warn("sysctlbyname(\"net.inet.ip.portrange.first\") "
89ae5c3dfdSMark Johnston 		    "failed");
90ae5c3dfdSMark Johnston 		atf_tc_skip("Unable to set sysctl");
91ae5c3dfdSMark Johnston 	}
92ae5c3dfdSMark Johnston 	if (sysctlsz != sizeof(save_ports.first)) {
93ae5c3dfdSMark Johnston 		fprintf(stderr, "Error: unexpected sysctl value size "
94ae5c3dfdSMark Johnston 		    "(expected %zu, actual %zu)\n", sizeof(save_ports.first),
95ae5c3dfdSMark Johnston 		    sysctlsz);
96ae5c3dfdSMark Johnston 		goto restore_sysctl;
97ae5c3dfdSMark Johnston 	}
98ae5c3dfdSMark Johnston 
99ae5c3dfdSMark Johnston 	last_new = PORT_LAST;
100ae5c3dfdSMark Johnston 	sysctlsz = sizeof(save_ports.last);
101ae5c3dfdSMark Johnston 	error = sysctlbyname("net.inet.ip.portrange.last", &save_ports.last,
102ae5c3dfdSMark Johnston 	    &sysctlsz, &last_new, sizeof(last_new));
103ae5c3dfdSMark Johnston 	if (error) {
104ae5c3dfdSMark Johnston 		warn("sysctlbyname(\"net.inet.ip.portrange.last\") "
105ae5c3dfdSMark Johnston 		    "failed");
106ae5c3dfdSMark Johnston 		atf_tc_skip("Unable to set sysctl");
107ae5c3dfdSMark Johnston 	}
108ae5c3dfdSMark Johnston 	if (sysctlsz != sizeof(save_ports.last)) {
109ae5c3dfdSMark Johnston 		fprintf(stderr, "Error: unexpected sysctl value size "
110ae5c3dfdSMark Johnston 		    "(expected %zu, actual %zu)\n", sizeof(save_ports.last),
111ae5c3dfdSMark Johnston 		    sysctlsz);
112ae5c3dfdSMark Johnston 		goto restore_sysctl;
113ae5c3dfdSMark Johnston 	}
114ae5c3dfdSMark Johnston 
115ae5c3dfdSMark Johnston 	/* Open the backup file, write the contents, and close it. */
116ae5c3dfdSMark Johnston 	fd = open(SYSCTLBAKFILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL,
117ae5c3dfdSMark Johnston 	    S_IRUSR|S_IWUSR);
118ae5c3dfdSMark Johnston 	if (fd < 0) {
119ae5c3dfdSMark Johnston 		warn("error opening sysctl backup file");
120ae5c3dfdSMark Johnston 		goto restore_sysctl;
121ae5c3dfdSMark Johnston 	}
122ae5c3dfdSMark Johnston 	error = write(fd, &save_ports, sizeof(save_ports));
123ae5c3dfdSMark Johnston 	if (error < 0) {
124ae5c3dfdSMark Johnston 		warn("error writing saved value to sysctl backup file");
125ae5c3dfdSMark Johnston 		goto cleanup_and_restore;
126ae5c3dfdSMark Johnston 	}
127ae5c3dfdSMark Johnston 	if (error != (int)sizeof(save_ports)) {
128ae5c3dfdSMark Johnston 		fprintf(stderr,
129ae5c3dfdSMark Johnston 		    "Error writing saved value to sysctl backup file: "
130ae5c3dfdSMark Johnston 		    "(expected %zu, actual %d)\n", sizeof(save_ports), error);
131ae5c3dfdSMark Johnston 		goto cleanup_and_restore;
132ae5c3dfdSMark Johnston 	}
133ae5c3dfdSMark Johnston 	error = close(fd);
134ae5c3dfdSMark Johnston 	if (error) {
135ae5c3dfdSMark Johnston 		warn("error closing sysctl backup file");
136ae5c3dfdSMark Johnston cleanup_and_restore:
137ae5c3dfdSMark Johnston 		(void)close(fd);
138ae5c3dfdSMark Johnston 		(void)unlink(SYSCTLBAKFILE);
139ae5c3dfdSMark Johnston restore_sysctl:
140ae5c3dfdSMark Johnston 		sysctlsz = sizeof(save_ports.first);
141ae5c3dfdSMark Johnston 		(void)sysctlbyname("net.inet.ip.portrange.first", NULL,
142ae5c3dfdSMark Johnston 		    NULL, &save_ports.first, sysctlsz);
143ae5c3dfdSMark Johnston 		sysctlsz = sizeof(save_ports.last);
144ae5c3dfdSMark Johnston 		(void)sysctlbyname("net.inet.ip.portrange.last", NULL,
145ae5c3dfdSMark Johnston 		    NULL, &save_ports.last, sysctlsz);
146ae5c3dfdSMark Johnston 		atf_tc_skip("Error setting sysctl");
147ae5c3dfdSMark Johnston 	}
148ae5c3dfdSMark Johnston }
149ae5c3dfdSMark Johnston 
150ae5c3dfdSMark Johnston /*
151ae5c3dfdSMark Johnston  * Restore the sysctl values from the backup file and delete the backup file.
152ae5c3dfdSMark Johnston  */
153ae5c3dfdSMark Johnston static void
restore_portrange(void)154ae5c3dfdSMark Johnston restore_portrange(void)
155ae5c3dfdSMark Johnston {
156ae5c3dfdSMark Johnston 	int error, fd;
157ae5c3dfdSMark Johnston 	struct portrange save_ports;
158ae5c3dfdSMark Johnston 
159ae5c3dfdSMark Johnston 	/* Open the backup file, read the contents, close it, and delete it. */
160ae5c3dfdSMark Johnston 	fd = open(SYSCTLBAKFILE, O_RDONLY);
161ae5c3dfdSMark Johnston 	if (fd < 0) {
162ae5c3dfdSMark Johnston 		warn("error opening sysctl backup file");
163ae5c3dfdSMark Johnston 		return;
164ae5c3dfdSMark Johnston 	}
165ae5c3dfdSMark Johnston 	error = read(fd, &save_ports, sizeof(save_ports));
166ae5c3dfdSMark Johnston 	if (error < 0) {
167ae5c3dfdSMark Johnston 		warn("error reading saved values from sysctl backup file");
168ae5c3dfdSMark Johnston 		return;
169ae5c3dfdSMark Johnston 	}
170ae5c3dfdSMark Johnston 	if (error != (int)sizeof(save_ports)) {
171ae5c3dfdSMark Johnston 		fprintf(stderr,
172ae5c3dfdSMark Johnston 		    "Error reading saved values from sysctl backup file: "
173ae5c3dfdSMark Johnston 		    "(expected %zu, actual %d)\n", sizeof(save_ports), error);
174ae5c3dfdSMark Johnston 		return;
175ae5c3dfdSMark Johnston 	}
176ae5c3dfdSMark Johnston 	error = close(fd);
177ae5c3dfdSMark Johnston 	if (error)
178ae5c3dfdSMark Johnston 		warn("error closing sysctl backup file");
179ae5c3dfdSMark Johnston 	error = unlink(SYSCTLBAKFILE);
180ae5c3dfdSMark Johnston 	if (error)
181ae5c3dfdSMark Johnston 		warn("error removing sysctl backup file");
182ae5c3dfdSMark Johnston 
183ae5c3dfdSMark Johnston 	/* Restore the saved sysctl values. */
184ae5c3dfdSMark Johnston 	error = sysctlbyname("net.inet.ip.portrange.first", NULL, NULL,
185ae5c3dfdSMark Johnston 	    &save_ports.first, sizeof(save_ports.first));
186ae5c3dfdSMark Johnston 	if (error)
187ae5c3dfdSMark Johnston 		warn("sysctlbyname(\"net.inet.ip.portrange.first\") "
188ae5c3dfdSMark Johnston 		    "failed while restoring value");
189ae5c3dfdSMark Johnston 	error = sysctlbyname("net.inet.ip.portrange.last", NULL, NULL,
190ae5c3dfdSMark Johnston 	    &save_ports.last, sizeof(save_ports.last));
191ae5c3dfdSMark Johnston 	if (error)
192ae5c3dfdSMark Johnston 		warn("sysctlbyname(\"net.inet.ip.portrange.last\") "
193ae5c3dfdSMark Johnston 		    "failed while restoring value");
194ae5c3dfdSMark Johnston }
195ae5c3dfdSMark Johnston 
196ae5c3dfdSMark Johnston ATF_TC_WITH_CLEANUP(tcp_v4mapped_bind);
ATF_TC_HEAD(tcp_v4mapped_bind,tc)197ae5c3dfdSMark Johnston ATF_TC_HEAD(tcp_v4mapped_bind, tc)
198ae5c3dfdSMark Johnston {
199ae5c3dfdSMark Johnston 	/* root is only required for sysctls (setup and cleanup). */
200ae5c3dfdSMark Johnston 	atf_tc_set_md_var(tc, "require.user", "root");
201ae5c3dfdSMark Johnston 	atf_tc_set_md_var(tc, "require.config", "allow_sysctl_side_effects");
202ae5c3dfdSMark Johnston 	atf_tc_set_md_var(tc, "descr",
203ae5c3dfdSMark Johnston 	    "Check local port assignment with bind and mapped V4 addresses");
204ae5c3dfdSMark Johnston }
205ae5c3dfdSMark Johnston /*
206ae5c3dfdSMark Johnston  * Create a listening IPv4 socket, then connect to it repeatedly using a
207ae5c3dfdSMark Johnston  * bound IPv6 socket using a v4 mapped address.  With a small port range,
208ae5c3dfdSMark Johnston  * this should fail on a bind() call with EADDRNOTAVAIL.  However, in
209ae5c3dfdSMark Johnston  * previous systems, the bind() would succeed, binding a duplicate port,
210ae5c3dfdSMark Johnston  * and then the connect would fail with EADDRINUSE.  Make sure we get
211ae5c3dfdSMark Johnston  * the right error.
212ae5c3dfdSMark Johnston  */
ATF_TC_BODY(tcp_v4mapped_bind,tc)213ae5c3dfdSMark Johnston ATF_TC_BODY(tcp_v4mapped_bind, tc)
214ae5c3dfdSMark Johnston {
215ae5c3dfdSMark Johnston 	union {
216ae5c3dfdSMark Johnston 		struct sockaddr saddr;
217ae5c3dfdSMark Johnston 		struct sockaddr_in saddr4;
218ae5c3dfdSMark Johnston 		struct sockaddr_in6 saddr6;
219ae5c3dfdSMark Johnston 	} su_clnt, su_srvr, su_mapped;
220ae5c3dfdSMark Johnston 	struct addrinfo ai_hint, *aip;
221ae5c3dfdSMark Johnston 	socklen_t salen;
222ae5c3dfdSMark Johnston 	int csock, error, i, lsock, off = 0;
223ae5c3dfdSMark Johnston 	bool got_bind_error = false;
224ae5c3dfdSMark Johnston 
225ae5c3dfdSMark Johnston 	/*
226ae5c3dfdSMark Johnston 	 * Set the net.inet.ip.portrange.{first,last} sysctls to use a small
227ae5c3dfdSMark Johnston 	 * range, allowing us to generate port exhaustion quickly.
228ae5c3dfdSMark Johnston 	 */
229ae5c3dfdSMark Johnston 	set_portrange();
230ae5c3dfdSMark Johnston 
231ae5c3dfdSMark Johnston 	/* Setup the listen socket. */
232ae5c3dfdSMark Johnston 	lsock = socket(PF_INET, SOCK_STREAM, 0);
233ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(lsock >= 0, "socket() for listen socket failed: %s",
234ae5c3dfdSMark Johnston 	    strerror(errno));
235ae5c3dfdSMark Johnston 
236ae5c3dfdSMark Johnston 	memset(&su_srvr.saddr4, 0, sizeof(su_srvr.saddr4));
237ae5c3dfdSMark Johnston 	su_srvr.saddr4.sin_family = AF_INET;
238ae5c3dfdSMark Johnston 	error = bind(lsock, &su_srvr.saddr, sizeof(su_srvr.saddr4));
239ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
240ae5c3dfdSMark Johnston 	error = listen(lsock, LOOPS + 1);
241ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
242ae5c3dfdSMark Johnston 
243ae5c3dfdSMark Johnston 	/* Get the address of the listen socket. */
244ae5c3dfdSMark Johnston 	salen = sizeof(su_srvr);
245ae5c3dfdSMark Johnston 	error = getsockname(lsock, &su_srvr.saddr, &salen);
246ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0,
247ae5c3dfdSMark Johnston 	    "getsockname() for listen socket failed: %s",
248ae5c3dfdSMark Johnston 	    strerror(errno));
249ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(salen == sizeof(struct sockaddr_in),
250ae5c3dfdSMark Johnston 	    "unexpected sockaddr size");
251ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(su_srvr.saddr.sa_len == sizeof(struct sockaddr_in),
252ae5c3dfdSMark Johnston 	    "unexpected sa_len size");
253ae5c3dfdSMark Johnston 
254ae5c3dfdSMark Johnston 	/* Set up destination address for client sockets. */
255ae5c3dfdSMark Johnston 	memset(&ai_hint, 0, sizeof(ai_hint));
256ae5c3dfdSMark Johnston 	ai_hint.ai_family = AF_INET6;
257ae5c3dfdSMark Johnston 	ai_hint.ai_flags = AI_NUMERICHOST | AI_V4MAPPED;
258ae5c3dfdSMark Johnston 	error = getaddrinfo("127.0.0.1", NULL, &ai_hint, &aip);
259ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0, "getaddrinfo: %s", gai_strerror(error));
260ae5c3dfdSMark Johnston 	memcpy(&su_mapped.saddr6, aip->ai_addr, sizeof(su_mapped.saddr6));
261ae5c3dfdSMark Johnston 	su_mapped.saddr6.sin6_port = su_srvr.saddr4.sin_port;
262ae5c3dfdSMark Johnston 	freeaddrinfo(aip);
263ae5c3dfdSMark Johnston 
264ae5c3dfdSMark Johnston 	/* Set up address to bind for client sockets (unspecified). */
265ae5c3dfdSMark Johnston 	memset(&su_clnt.saddr6, 0, sizeof(su_clnt.saddr6));
266ae5c3dfdSMark Johnston 	su_clnt.saddr6.sin6_family = AF_INET6;
267ae5c3dfdSMark Johnston 
268ae5c3dfdSMark Johnston 	/* Open connections in a loop. */
269ae5c3dfdSMark Johnston 	for (i = 0; i < LOOPS; i++) {
270ae5c3dfdSMark Johnston 		csock = socket(PF_INET6, SOCK_STREAM, 0);
271ae5c3dfdSMark Johnston 		ATF_REQUIRE_MSG(csock >= 0,
272ae5c3dfdSMark Johnston 		    "socket() for client socket %d failed: %s",
273ae5c3dfdSMark Johnston 		    i, strerror(errno));
274ae5c3dfdSMark Johnston 		error = setsockopt(csock, IPPROTO_IPV6, IPV6_V6ONLY, &off,
275ae5c3dfdSMark Johnston 		    sizeof(off));
276ae5c3dfdSMark Johnston 		ATF_REQUIRE_MSG(error == 0,
277ae5c3dfdSMark Johnston 		    "setsockopt(IPV6_ONLY = 0) failed: %s", strerror(errno));
278ae5c3dfdSMark Johnston 
279ae5c3dfdSMark Johnston 		/*
280ae5c3dfdSMark Johnston 		 * A bind would not be necessary for operation, but
281ae5c3dfdSMark Johnston 		 * provokes the error.
282ae5c3dfdSMark Johnston 		 */
283ae5c3dfdSMark Johnston 		error = bind(csock, &su_clnt.saddr, sizeof(su_clnt.saddr6));
284ae5c3dfdSMark Johnston 		if (error != 0) {
285ae5c3dfdSMark Johnston 			if (errno == EADDRNOTAVAIL) {	/* Success, expected */
286ae5c3dfdSMark Johnston 				got_bind_error = true;
287ae5c3dfdSMark Johnston 				break;
288ae5c3dfdSMark Johnston 			}
289ae5c3dfdSMark Johnston 			ATF_REQUIRE_MSG(error == 0,
290ae5c3dfdSMark Johnston 			    "client bind %d failed: %s", i, strerror(errno));
291ae5c3dfdSMark Johnston 		}
292ae5c3dfdSMark Johnston 
293ae5c3dfdSMark Johnston 		error = connect(csock, &su_mapped.saddr, su_mapped.saddr.sa_len);
294ae5c3dfdSMark Johnston 		if (error != 0 && errno == EADDRINUSE) {
295ae5c3dfdSMark Johnston 			/* This is the specific error we were looking for. */
296*6ad69299SMark Johnston 			atf_tc_fail("client connect %d failed, "
297ae5c3dfdSMark Johnston 			    " client had duplicate port: %s",
298ae5c3dfdSMark Johnston 			    i, strerror(errno));
299ae5c3dfdSMark Johnston 		}
300ae5c3dfdSMark Johnston 		ATF_REQUIRE_MSG(error == 0,
301ae5c3dfdSMark Johnston 		    "connect() for client socket %d failed: %s",
302ae5c3dfdSMark Johnston 		    i, strerror(errno));
303ae5c3dfdSMark Johnston 
304ae5c3dfdSMark Johnston 		/*
305ae5c3dfdSMark Johnston 		 * We don't accept the new socket from the server socket
306ae5c3dfdSMark Johnston 		 * or close the client socket, as we want the ports to
307ae5c3dfdSMark Johnston 		 * remain busy.  The range is small enough that this is
308ae5c3dfdSMark Johnston 		 * not a problem.
309ae5c3dfdSMark Johnston 		 */
310ae5c3dfdSMark Johnston 	}
311ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(i >= 1, "No successful connections");
312ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(got_bind_error == true, "No expected bind error");
313*6ad69299SMark Johnston 
314*6ad69299SMark Johnston 	ATF_REQUIRE(close(lsock) == 0);
315ae5c3dfdSMark Johnston }
ATF_TC_CLEANUP(tcp_v4mapped_bind,tc)316ae5c3dfdSMark Johnston ATF_TC_CLEANUP(tcp_v4mapped_bind, tc)
317ae5c3dfdSMark Johnston {
318ae5c3dfdSMark Johnston 	restore_portrange();
319ae5c3dfdSMark Johnston }
320ae5c3dfdSMark Johnston 
321ae5c3dfdSMark Johnston ATF_TC(udp_v4mapped_sendto);
ATF_TC_HEAD(udp_v4mapped_sendto,tc)322ae5c3dfdSMark Johnston ATF_TC_HEAD(udp_v4mapped_sendto, tc)
323ae5c3dfdSMark Johnston {
324ae5c3dfdSMark Johnston 	atf_tc_set_md_var(tc, "descr",
325ae5c3dfdSMark Johnston 	    "Validate sendto() with a v4-mapped address and a v6-only socket");
326ae5c3dfdSMark Johnston }
ATF_TC_BODY(udp_v4mapped_sendto,tc)327ae5c3dfdSMark Johnston ATF_TC_BODY(udp_v4mapped_sendto, tc)
328ae5c3dfdSMark Johnston {
329ae5c3dfdSMark Johnston 	struct addrinfo ai_hint, *aip;
330ae5c3dfdSMark Johnston 	struct sockaddr_in sin;
331ae5c3dfdSMark Johnston 	struct sockaddr_in6 sin6;
332ae5c3dfdSMark Johnston 	ssize_t n;
333ae5c3dfdSMark Johnston 	socklen_t salen;
334ae5c3dfdSMark Johnston 	int error, ls, s, zero;
335ae5c3dfdSMark Johnston 	short port;
336ae5c3dfdSMark Johnston 	char ch;
337ae5c3dfdSMark Johnston 
338ae5c3dfdSMark Johnston 	ls = socket(PF_INET, SOCK_DGRAM, 0);
339ae5c3dfdSMark Johnston 	ATF_REQUIRE(ls >= 0);
340ae5c3dfdSMark Johnston 
341ae5c3dfdSMark Johnston 	memset(&ai_hint, 0, sizeof(ai_hint));
342ae5c3dfdSMark Johnston 	ai_hint.ai_family = AF_INET;
343ae5c3dfdSMark Johnston 	ai_hint.ai_flags = AI_NUMERICHOST;
344ae5c3dfdSMark Johnston 	error = getaddrinfo("127.0.0.1", NULL, &ai_hint, &aip);
345ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0, "getaddrinfo: %s", gai_strerror(error));
346ae5c3dfdSMark Johnston 	memcpy(&sin, aip->ai_addr, sizeof(sin));
347ae5c3dfdSMark Johnston 
348ae5c3dfdSMark Johnston 	error = bind(ls, (struct sockaddr *)&sin, sizeof(sin));
349ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0, "bind: %s", strerror(errno));
350ae5c3dfdSMark Johnston 	salen = sizeof(sin);
351ae5c3dfdSMark Johnston 	error = getsockname(ls, (struct sockaddr *)&sin, &salen);
352ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0,
353ae5c3dfdSMark Johnston 	    "getsockname() for listen socket failed: %s", strerror(errno));
354ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(salen == sizeof(struct sockaddr_in),
355ae5c3dfdSMark Johnston 	    "unexpected sockaddr size");
356ae5c3dfdSMark Johnston 	port = sin.sin_port;
357ae5c3dfdSMark Johnston 
358ae5c3dfdSMark Johnston 	s = socket(PF_INET6, SOCK_DGRAM, 0);
359ae5c3dfdSMark Johnston 	ATF_REQUIRE(s >= 0);
360ae5c3dfdSMark Johnston 
361ae5c3dfdSMark Johnston 	memset(&ai_hint, 0, sizeof(ai_hint));
362ae5c3dfdSMark Johnston 	ai_hint.ai_family = AF_INET6;
363ae5c3dfdSMark Johnston 	ai_hint.ai_flags = AI_NUMERICHOST | AI_V4MAPPED;
364ae5c3dfdSMark Johnston 	error = getaddrinfo("127.0.0.1", NULL, &ai_hint, &aip);
365ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0, "getaddrinfo: %s", gai_strerror(error));
366ae5c3dfdSMark Johnston 	memcpy(&sin6, aip->ai_addr, sizeof(sin6));
367ae5c3dfdSMark Johnston 	sin6.sin6_port = port;
368*6ad69299SMark Johnston 	freeaddrinfo(aip);
369ae5c3dfdSMark Johnston 
370ae5c3dfdSMark Johnston 	ch = 0x42;
371ae5c3dfdSMark Johnston 	n = sendto(s, &ch, 1, 0, (struct sockaddr *)&sin6, sizeof(sin6));
372ae5c3dfdSMark Johnston 	ATF_REQUIRE_ERRNO(EINVAL, n == -1);
373ae5c3dfdSMark Johnston 
374ae5c3dfdSMark Johnston 	zero = 0;
375ae5c3dfdSMark Johnston 	error = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
376ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(error == 0,
377ae5c3dfdSMark Johnston 	    "setsockopt(IPV6_V6ONLY) failed: %s", strerror(errno));
378ae5c3dfdSMark Johnston 
379ae5c3dfdSMark Johnston 	ch = 0x42;
380ae5c3dfdSMark Johnston 	n = sendto(s, &ch, 1, 0, (struct sockaddr *)&sin6, sizeof(sin6));
381ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(n == 1, "sendto() failed: %s", strerror(errno));
382ae5c3dfdSMark Johnston 
383ae5c3dfdSMark Johnston 	ch = 0;
384ae5c3dfdSMark Johnston 	n = recv(ls, &ch, 1, 0);
385ae5c3dfdSMark Johnston 	ATF_REQUIRE_MSG(n == 1, "recv() failed: %s", strerror(errno));
386ae5c3dfdSMark Johnston 	ATF_REQUIRE(ch == 0x42);
387*6ad69299SMark Johnston 
388*6ad69299SMark Johnston 	ATF_REQUIRE(close(s) == 0);
389*6ad69299SMark Johnston 	ATF_REQUIRE(close(ls) == 0);
390ae5c3dfdSMark Johnston }
391ae5c3dfdSMark Johnston 
ATF_TP_ADD_TCS(tp)392ae5c3dfdSMark Johnston ATF_TP_ADD_TCS(tp)
393ae5c3dfdSMark Johnston {
394ae5c3dfdSMark Johnston 	ATF_TP_ADD_TC(tp, tcp_v4mapped_bind);
395ae5c3dfdSMark Johnston 	ATF_TP_ADD_TC(tp, udp_v4mapped_sendto);
396ae5c3dfdSMark Johnston 
397ae5c3dfdSMark Johnston 	return (atf_no_error());
398ae5c3dfdSMark Johnston }
399