136c52a52SJonathan T. Looney /*-
236c52a52SJonathan T. Looney  * SPDX-License-Identifier: BSD-2-Clause
336c52a52SJonathan T. Looney  *
436c52a52SJonathan T. Looney  * Copyright (c) 2020 Netflix, Inc.
536c52a52SJonathan T. Looney  *
636c52a52SJonathan T. Looney  * Redistribution and use in source and binary forms, with or without
736c52a52SJonathan T. Looney  * modification, are permitted provided that the following conditions are
836c52a52SJonathan T. Looney  * met:
936c52a52SJonathan T. Looney  * 1. Redistributions of source code must retain the above copyright
1036c52a52SJonathan T. Looney  *    notice, this list of conditions and the following disclaimer.
1136c52a52SJonathan T. Looney  * 2. Redistributions in binary form must reproduce the above copyright
1236c52a52SJonathan T. Looney  *    notice, this list of conditions and the following disclaimer in
1336c52a52SJonathan T. Looney  *    the documentation and/or other materials provided with the
1436c52a52SJonathan T. Looney  *    distribution.
1536c52a52SJonathan T. Looney  *
1636c52a52SJonathan T. Looney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1736c52a52SJonathan T. Looney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1836c52a52SJonathan T. Looney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1936c52a52SJonathan T. Looney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2036c52a52SJonathan T. Looney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2136c52a52SJonathan T. Looney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2236c52a52SJonathan T. Looney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2336c52a52SJonathan T. Looney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2436c52a52SJonathan T. Looney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2536c52a52SJonathan T. Looney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2636c52a52SJonathan T. Looney  * SUCH DAMAGE.
2736c52a52SJonathan T. Looney  */
2836c52a52SJonathan T. Looney 
2936c52a52SJonathan T. Looney #include <sys/param.h>
3036c52a52SJonathan T. Looney #include <sys/socket.h>
3136c52a52SJonathan T. Looney #include <sys/stat.h>
3236c52a52SJonathan T. Looney #include <sys/sysctl.h>
3336c52a52SJonathan T. Looney 
3436c52a52SJonathan T. Looney #include <netinet/in.h>
3536c52a52SJonathan T. Looney 
3636c52a52SJonathan T. Looney #include <err.h>
3736c52a52SJonathan T. Looney #include <errno.h>
3836c52a52SJonathan T. Looney #include <fcntl.h>
3936c52a52SJonathan T. Looney #include <stdio.h>
4036c52a52SJonathan T. Looney #include <stdlib.h>
4136c52a52SJonathan T. Looney #include <unistd.h>
4236c52a52SJonathan T. Looney 
4336c52a52SJonathan T. Looney #include <atf-c.h>
4436c52a52SJonathan T. Looney 
4536c52a52SJonathan T. Looney #define	SYSCTLBAKFILE	"tmp.net.inet.ip.portrange.randomized"
4636c52a52SJonathan T. Looney 
4736c52a52SJonathan T. Looney /*
4836c52a52SJonathan T. Looney  * Check if port allocation is randomized. If so, update it. Save the old
4936c52a52SJonathan T. Looney  * value of the sysctl so it can be updated later.
5036c52a52SJonathan T. Looney  */
5136c52a52SJonathan T. Looney static void
disable_random_ports(void)5236c52a52SJonathan T. Looney disable_random_ports(void)
5336c52a52SJonathan T. Looney {
5436c52a52SJonathan T. Looney 	int error, fd, random_new, random_save;
5536c52a52SJonathan T. Looney 	size_t sysctlsz;
5636c52a52SJonathan T. Looney 
5736c52a52SJonathan T. Looney 	/*
5836c52a52SJonathan T. Looney 	 * Pre-emptively unlink our restoration file, so we will do no
5936c52a52SJonathan T. Looney 	 * restoration on error.
6036c52a52SJonathan T. Looney 	 */
6136c52a52SJonathan T. Looney 	unlink(SYSCTLBAKFILE);
6236c52a52SJonathan T. Looney 
6336c52a52SJonathan T. Looney 	/*
6436c52a52SJonathan T. Looney 	 * Disable the net.inet.ip.portrange.randomized sysctl. Save the
6536c52a52SJonathan T. Looney 	 * old value so we can restore it, if necessary.
6636c52a52SJonathan T. Looney 	 */
6736c52a52SJonathan T. Looney 	random_new = 0;
6836c52a52SJonathan T. Looney 	sysctlsz = sizeof(random_save);
6936c52a52SJonathan T. Looney 	error = sysctlbyname("net.inet.ip.portrange.randomized", &random_save,
7036c52a52SJonathan T. Looney 	    &sysctlsz, &random_new, sizeof(random_new));
7136c52a52SJonathan T. Looney 	if (error) {
7236c52a52SJonathan T. Looney 		warn("sysctlbyname(\"net.inet.ip.portrange.randomized\") "
7336c52a52SJonathan T. Looney 		    "failed");
7436c52a52SJonathan T. Looney 		atf_tc_skip("Unable to set sysctl");
7536c52a52SJonathan T. Looney 	}
7636c52a52SJonathan T. Looney 	if (sysctlsz != sizeof(random_save)) {
7736c52a52SJonathan T. Looney 		fprintf(stderr, "Error: unexpected sysctl value size "
7836c52a52SJonathan T. Looney 		    "(expected %zu, actual %zu)\n", sizeof(random_save),
7936c52a52SJonathan T. Looney 		    sysctlsz);
8036c52a52SJonathan T. Looney 		goto restore_sysctl;
8136c52a52SJonathan T. Looney 	}
8236c52a52SJonathan T. Looney 
8336c52a52SJonathan T. Looney 	/* Open the backup file, write the contents, and close it. */
8436c52a52SJonathan T. Looney 	fd = open(SYSCTLBAKFILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL,
8536c52a52SJonathan T. Looney 	    S_IRUSR|S_IWUSR);
8636c52a52SJonathan T. Looney 	if (fd < 0) {
8736c52a52SJonathan T. Looney 		warn("error opening sysctl backup file");
8836c52a52SJonathan T. Looney 		goto restore_sysctl;
8936c52a52SJonathan T. Looney 	}
9036c52a52SJonathan T. Looney 	error = write(fd, &random_save, sizeof(random_save));
9136c52a52SJonathan T. Looney 	if (error < 0) {
9236c52a52SJonathan T. Looney 		warn("error writing saved value to sysctl backup file");
9336c52a52SJonathan T. Looney 		goto cleanup_and_restore;
9436c52a52SJonathan T. Looney 	}
9536c52a52SJonathan T. Looney 	if (error != (int)sizeof(random_save)) {
9636c52a52SJonathan T. Looney 		fprintf(stderr,
9736c52a52SJonathan T. Looney 		    "Error writing saved value to sysctl backup file: "
9836c52a52SJonathan T. Looney 		    "(expected %zu, actual %d)\n", sizeof(random_save), error);
9936c52a52SJonathan T. Looney 		goto cleanup_and_restore;
10036c52a52SJonathan T. Looney 	}
10136c52a52SJonathan T. Looney 	error = close(fd);
10236c52a52SJonathan T. Looney 	if (error) {
10336c52a52SJonathan T. Looney 		warn("error closing sysctl backup file");
10436c52a52SJonathan T. Looney cleanup_and_restore:
10536c52a52SJonathan T. Looney 		(void)close(fd);
10636c52a52SJonathan T. Looney 		(void)unlink(SYSCTLBAKFILE);
10736c52a52SJonathan T. Looney restore_sysctl:
10836c52a52SJonathan T. Looney 		(void)sysctlbyname("net.inet.ip.portrange.randomized", NULL,
10936c52a52SJonathan T. Looney 		    NULL, &random_save, sysctlsz);
11036c52a52SJonathan T. Looney 		atf_tc_skip("Error setting sysctl");
11136c52a52SJonathan T. Looney 	}
11236c52a52SJonathan T. Looney }
11336c52a52SJonathan T. Looney 
11436c52a52SJonathan T. Looney /*
11536c52a52SJonathan T. Looney  * Restore the sysctl value from the backup file and delete the backup file.
11636c52a52SJonathan T. Looney  */
11736c52a52SJonathan T. Looney static void
restore_random_ports(void)11836c52a52SJonathan T. Looney restore_random_ports(void)
11936c52a52SJonathan T. Looney {
12036c52a52SJonathan T. Looney 	int error, fd, random_save;
12136c52a52SJonathan T. Looney 
12236c52a52SJonathan T. Looney 	/* Open the backup file, read the contents, close it, and delete it. */
12336c52a52SJonathan T. Looney 	fd = open(SYSCTLBAKFILE, O_RDONLY);
12436c52a52SJonathan T. Looney 	if (fd < 0) {
12536c52a52SJonathan T. Looney 		warn("error opening sysctl backup file");
12636c52a52SJonathan T. Looney 		return;
12736c52a52SJonathan T. Looney 	}
12836c52a52SJonathan T. Looney 	error = read(fd, &random_save, sizeof(random_save));
12936c52a52SJonathan T. Looney 	if (error < 0) {
13036c52a52SJonathan T. Looney 		warn("error reading saved value from sysctl backup file");
13136c52a52SJonathan T. Looney 		return;
13236c52a52SJonathan T. Looney 	}
13336c52a52SJonathan T. Looney 	if (error != (int)sizeof(random_save)) {
13436c52a52SJonathan T. Looney 		fprintf(stderr,
13536c52a52SJonathan T. Looney 		    "Error reading saved value from sysctl backup file: "
13636c52a52SJonathan T. Looney 		    "(expected %zu, actual %d)\n", sizeof(random_save), error);
13736c52a52SJonathan T. Looney 		return;
13836c52a52SJonathan T. Looney 	}
13936c52a52SJonathan T. Looney 	error = close(fd);
14036c52a52SJonathan T. Looney 	if (error)
14136c52a52SJonathan T. Looney 		warn("error closing sysctl backup file");
14236c52a52SJonathan T. Looney 	error = unlink(SYSCTLBAKFILE);
14336c52a52SJonathan T. Looney 	if (error)
14436c52a52SJonathan T. Looney 		warn("error removing sysctl backup file");
14536c52a52SJonathan T. Looney 
14636c52a52SJonathan T. Looney 	/* Restore the saved sysctl value. */
14736c52a52SJonathan T. Looney 	error = sysctlbyname("net.inet.ip.portrange.randomized", NULL, NULL,
14836c52a52SJonathan T. Looney 	    &random_save, sizeof(random_save));
14936c52a52SJonathan T. Looney 	if (error)
15036c52a52SJonathan T. Looney 		warn("sysctlbyname(\"net.inet.ip.portrange.randomized\") "
15136c52a52SJonathan T. Looney 		    "failed while restoring value");
15236c52a52SJonathan T. Looney }
15336c52a52SJonathan T. Looney 
15436c52a52SJonathan T. Looney /*
15536c52a52SJonathan T. Looney  * Given a domain and sockaddr, open a listening socket with automatic port
15636c52a52SJonathan T. Looney  * selection. Then, try to connect 64K times. Ensure the connected socket never
15736c52a52SJonathan T. Looney  * uses an overlapping port.
15836c52a52SJonathan T. Looney  */
15936c52a52SJonathan T. Looney static void
connect_loop(int domain,const struct sockaddr * addr)16036c52a52SJonathan T. Looney connect_loop(int domain, const struct sockaddr *addr)
16136c52a52SJonathan T. Looney {
16236c52a52SJonathan T. Looney 	union {
16336c52a52SJonathan T. Looney 		struct sockaddr saddr;
16436c52a52SJonathan T. Looney 		struct sockaddr_in saddr4;
16536c52a52SJonathan T. Looney 		struct sockaddr_in6 saddr6;
16636c52a52SJonathan T. Looney 	} su_clnt, su_srvr;
16736c52a52SJonathan T. Looney 	socklen_t salen;
16836c52a52SJonathan T. Looney 	int asock, csock, error, i, lsock;
16936c52a52SJonathan T. Looney 	const struct linger lopt = { 1, 0 };
17036c52a52SJonathan T. Looney 
17136c52a52SJonathan T. Looney 	/*
17236c52a52SJonathan T. Looney 	 * Disable the net.inet.ip.portrange.randomized sysctl. Assuming an
17336c52a52SJonathan T. Looney 	 * otherwise idle system, this makes the kernel try all possible
17436c52a52SJonathan T. Looney 	 * ports sequentially and makes it more likely it will try the
17536c52a52SJonathan T. Looney 	 * port on which we have a listening socket.
17636c52a52SJonathan T. Looney 	 */
17736c52a52SJonathan T. Looney 	disable_random_ports();
17836c52a52SJonathan T. Looney 
17936c52a52SJonathan T. Looney 	/* Setup the listen socket. */
18036c52a52SJonathan T. Looney 	lsock = socket(domain, SOCK_STREAM, 0);
18136c52a52SJonathan T. Looney 	ATF_REQUIRE_MSG(lsock >= 0, "socket() for listen socket failed: %s",
18236c52a52SJonathan T. Looney 	    strerror(errno));
18336c52a52SJonathan T. Looney 	error = bind(lsock, addr, addr->sa_len);
18436c52a52SJonathan T. Looney 	ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
18536c52a52SJonathan T. Looney 	error = listen(lsock, 1);
18636c52a52SJonathan T. Looney 	ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
18736c52a52SJonathan T. Looney 
18836c52a52SJonathan T. Looney 	/*
18936c52a52SJonathan T. Looney 	 * Get the address of the listen socket, which will be the destination
19036c52a52SJonathan T. Looney 	 * address for our connection attempts.
19136c52a52SJonathan T. Looney 	 */
19236c52a52SJonathan T. Looney 	salen = sizeof(su_srvr);
19336c52a52SJonathan T. Looney 	error = getsockname(lsock, &su_srvr.saddr, &salen);
19436c52a52SJonathan T. Looney 	ATF_REQUIRE_MSG(error == 0,
19536c52a52SJonathan T. Looney 	    "getsockname() for listen socket failed: %s",
19636c52a52SJonathan T. Looney 	    strerror(errno));
19736c52a52SJonathan T. Looney 	ATF_REQUIRE_MSG(salen == (domain == PF_INET ?
19836c52a52SJonathan T. Looney 	    sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)),
19936c52a52SJonathan T. Looney 	    "unexpected sockaddr size");
20036c52a52SJonathan T. Looney 	ATF_REQUIRE_MSG(su_srvr.saddr.sa_len == (domain == PF_INET ?
20136c52a52SJonathan T. Looney 	    sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)),
20236c52a52SJonathan T. Looney 	    "unexpected sa_len size");
20336c52a52SJonathan T. Looney 
20436c52a52SJonathan T. Looney 	/* Open 64K connections in a loop. */
20536c52a52SJonathan T. Looney 	for (i = 0; i < 65536; i++) {
20636c52a52SJonathan T. Looney 		csock = socket(domain, SOCK_STREAM, 0);
20736c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(csock >= 0,
20836c52a52SJonathan T. Looney 		    "socket() for client socket %d failed: %s",
20936c52a52SJonathan T. Looney 		    i, strerror(errno));
21036c52a52SJonathan T. Looney 
21136c52a52SJonathan T. Looney 		error = connect(csock, &su_srvr.saddr, su_srvr.saddr.sa_len);
21236c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(error == 0,
21336c52a52SJonathan T. Looney 		    "connect() for client socket %d failed: %s",
21436c52a52SJonathan T. Looney 		    i, strerror(errno));
21536c52a52SJonathan T. Looney 
21636c52a52SJonathan T. Looney 		error = setsockopt(csock, SOL_SOCKET, SO_LINGER, &lopt,
21736c52a52SJonathan T. Looney 		    sizeof(lopt));
21836c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(error == 0,
21936c52a52SJonathan T. Looney 		    "Setting linger for client socket %d failed: %s",
22036c52a52SJonathan T. Looney 		    i, strerror(errno));
22136c52a52SJonathan T. Looney 
22236c52a52SJonathan T. Looney 		/* Ascertain the client socket address. */
22336c52a52SJonathan T. Looney 		salen = sizeof(su_clnt);
22436c52a52SJonathan T. Looney 		error = getsockname(csock, &su_clnt.saddr, &salen);
22536c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(error == 0,
22636c52a52SJonathan T. Looney 		    "getsockname() for client socket %d failed: %s",
22736c52a52SJonathan T. Looney 		    i, strerror(errno));
22836c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(salen == (domain == PF_INET ?
22936c52a52SJonathan T. Looney 		    sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)),
23036c52a52SJonathan T. Looney 		    "unexpected sockaddr size for client socket %d", i);
23136c52a52SJonathan T. Looney 
23236c52a52SJonathan T. Looney 		/* Ensure the ports do not match. */
23336c52a52SJonathan T. Looney 		switch (domain) {
23436c52a52SJonathan T. Looney 		case PF_INET:
23536c52a52SJonathan T. Looney 			ATF_REQUIRE_MSG(su_clnt.saddr4.sin_port !=
23636c52a52SJonathan T. Looney 			    su_srvr.saddr4.sin_port,
23736c52a52SJonathan T. Looney 			    "client socket %d using the same port as server",
23836c52a52SJonathan T. Looney 			    i);
23936c52a52SJonathan T. Looney 			break;
24036c52a52SJonathan T. Looney 		case PF_INET6:
24136c52a52SJonathan T. Looney 			ATF_REQUIRE_MSG(su_clnt.saddr6.sin6_port !=
24236c52a52SJonathan T. Looney 			    su_srvr.saddr6.sin6_port,
24336c52a52SJonathan T. Looney 			    "client socket %d using the same port as server",
24436c52a52SJonathan T. Looney 			    i);
24536c52a52SJonathan T. Looney 			break;
24636c52a52SJonathan T. Looney 		}
24736c52a52SJonathan T. Looney 
24836c52a52SJonathan T. Looney 		/* Accept the socket and close both ends. */
24936c52a52SJonathan T. Looney 		asock = accept(lsock, NULL, NULL);
25036c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(asock >= 0,
25136c52a52SJonathan T. Looney 		    "accept() failed for client socket %d: %s",
25236c52a52SJonathan T. Looney 		    i, strerror(errno));
25336c52a52SJonathan T. Looney 
25436c52a52SJonathan T. Looney 		error = close(asock);
25536c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(error == 0,
25636c52a52SJonathan T. Looney 		    "close() failed for accepted socket %d: %s",
25736c52a52SJonathan T. Looney 		    i, strerror(errno));
25836c52a52SJonathan T. Looney 
25936c52a52SJonathan T. Looney 		error = close(csock);
26036c52a52SJonathan T. Looney 		ATF_REQUIRE_MSG(error == 0,
26136c52a52SJonathan T. Looney 		    "close() failed for client socket %d: %s",
26236c52a52SJonathan T. Looney 		    i, strerror(errno));
26336c52a52SJonathan T. Looney 	}
26436c52a52SJonathan T. Looney }
26536c52a52SJonathan T. Looney 
26636c52a52SJonathan T. Looney ATF_TC_WITH_CLEANUP(basic_ipv4);
ATF_TC_HEAD(basic_ipv4,tc)26736c52a52SJonathan T. Looney ATF_TC_HEAD(basic_ipv4, tc)
26836c52a52SJonathan T. Looney {
26936c52a52SJonathan T. Looney 
27036c52a52SJonathan T. Looney 	atf_tc_set_md_var(tc, "require.user", "root");
27136c52a52SJonathan T. Looney 	atf_tc_set_md_var(tc, "require.config", "allow_sysctl_side_effects");
27236c52a52SJonathan T. Looney 	atf_tc_set_md_var(tc, "descr",
27336c52a52SJonathan T. Looney 	    "Check automatic local port assignment during TCP connect calls");
27436c52a52SJonathan T. Looney }
27536c52a52SJonathan T. Looney 
ATF_TC_BODY(basic_ipv4,tc)27636c52a52SJonathan T. Looney ATF_TC_BODY(basic_ipv4, tc)
27736c52a52SJonathan T. Looney {
27836c52a52SJonathan T. Looney 	struct sockaddr_in saddr4;
27936c52a52SJonathan T. Looney 
28036c52a52SJonathan T. Looney 	memset(&saddr4, 0, sizeof(saddr4));
28136c52a52SJonathan T. Looney 	saddr4.sin_len = sizeof(saddr4);
28236c52a52SJonathan T. Looney 	saddr4.sin_family = AF_INET;
28336c52a52SJonathan T. Looney 	saddr4.sin_port = htons(0);
28436c52a52SJonathan T. Looney 	saddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
28536c52a52SJonathan T. Looney 
28636c52a52SJonathan T. Looney 	connect_loop(PF_INET, (const struct sockaddr *)&saddr4);
28736c52a52SJonathan T. Looney }
28836c52a52SJonathan T. Looney 
ATF_TC_CLEANUP(basic_ipv4,tc)28936c52a52SJonathan T. Looney ATF_TC_CLEANUP(basic_ipv4, tc)
29036c52a52SJonathan T. Looney {
29136c52a52SJonathan T. Looney 
29236c52a52SJonathan T. Looney 	restore_random_ports();
29336c52a52SJonathan T. Looney }
29436c52a52SJonathan T. Looney 
29536c52a52SJonathan T. Looney ATF_TC_WITH_CLEANUP(basic_ipv6);
ATF_TC_HEAD(basic_ipv6,tc)29636c52a52SJonathan T. Looney ATF_TC_HEAD(basic_ipv6, tc)
29736c52a52SJonathan T. Looney {
29836c52a52SJonathan T. Looney 
29936c52a52SJonathan T. Looney 	atf_tc_set_md_var(tc, "require.user", "root");
30036c52a52SJonathan T. Looney 	atf_tc_set_md_var(tc, "require.config", "allow_sysctl_side_effects");
30136c52a52SJonathan T. Looney 	atf_tc_set_md_var(tc, "descr",
30236c52a52SJonathan T. Looney 	    "Check automatic local port assignment during TCP connect calls");
30336c52a52SJonathan T. Looney }
30436c52a52SJonathan T. Looney 
ATF_TC_BODY(basic_ipv6,tc)30536c52a52SJonathan T. Looney ATF_TC_BODY(basic_ipv6, tc)
30636c52a52SJonathan T. Looney {
30736c52a52SJonathan T. Looney 	struct sockaddr_in6 saddr6;
30836c52a52SJonathan T. Looney 
30936c52a52SJonathan T. Looney 	memset(&saddr6, 0, sizeof(saddr6));
31036c52a52SJonathan T. Looney 	saddr6.sin6_len = sizeof(saddr6);
31136c52a52SJonathan T. Looney 	saddr6.sin6_family = AF_INET6;
31236c52a52SJonathan T. Looney 	saddr6.sin6_port = htons(0);
31336c52a52SJonathan T. Looney 	saddr6.sin6_addr = in6addr_loopback;
31436c52a52SJonathan T. Looney 
31536c52a52SJonathan T. Looney 	connect_loop(PF_INET6, (const struct sockaddr *)&saddr6);
31636c52a52SJonathan T. Looney }
31736c52a52SJonathan T. Looney 
ATF_TC_CLEANUP(basic_ipv6,tc)31836c52a52SJonathan T. Looney ATF_TC_CLEANUP(basic_ipv6, tc)
31936c52a52SJonathan T. Looney {
32036c52a52SJonathan T. Looney 
32136c52a52SJonathan T. Looney 	restore_random_ports();
32236c52a52SJonathan T. Looney }
32336c52a52SJonathan T. Looney 
ATF_TP_ADD_TCS(tp)32436c52a52SJonathan T. Looney ATF_TP_ADD_TCS(tp)
32536c52a52SJonathan T. Looney {
32636c52a52SJonathan T. Looney 	ATF_TP_ADD_TC(tp, basic_ipv4);
32736c52a52SJonathan T. Looney 	ATF_TP_ADD_TC(tp, basic_ipv6);
32836c52a52SJonathan T. Looney 
32936c52a52SJonathan T. Looney 	return (atf_no_error());
33036c52a52SJonathan T. Looney }
33136c52a52SJonathan T. Looney 
332