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