1*33de042dSApple OSS Distributions /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2*33de042dSApple OSS Distributions
3*33de042dSApple OSS Distributions #include <darwintest.h>
4*33de042dSApple OSS Distributions #include <poll.h>
5*33de042dSApple OSS Distributions #include <sys/socket.h>
6*33de042dSApple OSS Distributions #include <unistd.h>
7*33de042dSApple OSS Distributions #include <netinet/in.h>
8*33de042dSApple OSS Distributions #include <arpa/inet.h>
9*33de042dSApple OSS Distributions #include <errno.h>
10*33de042dSApple OSS Distributions
11*33de042dSApple OSS Distributions static int
sockv6_open(void)12*33de042dSApple OSS Distributions sockv6_open(void)
13*33de042dSApple OSS Distributions {
14*33de042dSApple OSS Distributions int s;
15*33de042dSApple OSS Distributions
16*33de042dSApple OSS Distributions s = socket(AF_INET6, SOCK_DGRAM, 0);
17*33de042dSApple OSS Distributions T_QUIET;
18*33de042dSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(s, "socket(AF_INET6, SOCK_DGRAM, 0)");
19*33de042dSApple OSS Distributions return s;
20*33de042dSApple OSS Distributions }
21*33de042dSApple OSS Distributions
22*33de042dSApple OSS Distributions static int
sockv6_bind(int s,in_port_t port)23*33de042dSApple OSS Distributions sockv6_bind(int s, in_port_t port)
24*33de042dSApple OSS Distributions {
25*33de042dSApple OSS Distributions struct sockaddr_in6 sin6;
26*33de042dSApple OSS Distributions
27*33de042dSApple OSS Distributions bzero(&sin6, sizeof(sin6));
28*33de042dSApple OSS Distributions sin6.sin6_len = sizeof(sin6);
29*33de042dSApple OSS Distributions sin6.sin6_family = AF_INET6;
30*33de042dSApple OSS Distributions sin6.sin6_port = port;
31*33de042dSApple OSS Distributions return bind(s, (const struct sockaddr *)&sin6, sizeof(sin6));
32*33de042dSApple OSS Distributions }
33*33de042dSApple OSS Distributions
34*33de042dSApple OSS Distributions static void
sockv6_set_v6only(int s)35*33de042dSApple OSS Distributions sockv6_set_v6only(int s)
36*33de042dSApple OSS Distributions {
37*33de042dSApple OSS Distributions int on = 1;
38*33de042dSApple OSS Distributions int ret;
39*33de042dSApple OSS Distributions
40*33de042dSApple OSS Distributions ret = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
41*33de042dSApple OSS Distributions T_QUIET;
42*33de042dSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "setsockopt(%d, IPV6_ONLY)", s);
43*33de042dSApple OSS Distributions }
44*33de042dSApple OSS Distributions
45*33de042dSApple OSS Distributions static bool
alloc_and_bind_ports(in_port_t port_start,in_port_t port_end,int bind_attempts)46*33de042dSApple OSS Distributions alloc_and_bind_ports(in_port_t port_start, in_port_t port_end,
47*33de042dSApple OSS Distributions int bind_attempts)
48*33de042dSApple OSS Distributions {
49*33de042dSApple OSS Distributions int bound_count = 0;
50*33de042dSApple OSS Distributions bool success = true;
51*33de042dSApple OSS Distributions
52*33de042dSApple OSS Distributions for (in_port_t i = port_start; success && i <= port_end; i++) {
53*33de042dSApple OSS Distributions int s6 = -1;
54*33de042dSApple OSS Distributions int s6_other = -1;
55*33de042dSApple OSS Distributions int ret;
56*33de042dSApple OSS Distributions
57*33de042dSApple OSS Distributions s6 = sockv6_open();
58*33de042dSApple OSS Distributions sockv6_set_v6only(s6);
59*33de042dSApple OSS Distributions if (sockv6_bind(s6, i) != 0) {
60*33de042dSApple OSS Distributions /* find the next available port */
61*33de042dSApple OSS Distributions goto loop_done;
62*33de042dSApple OSS Distributions }
63*33de042dSApple OSS Distributions s6_other = sockv6_open();
64*33de042dSApple OSS Distributions ret = sockv6_bind(s6_other, i);
65*33de042dSApple OSS Distributions T_WITH_ERRNO;
66*33de042dSApple OSS Distributions T_QUIET;
67*33de042dSApple OSS Distributions T_ASSERT_TRUE(ret != 0, "socket %d bind %d", s6_other, i);
68*33de042dSApple OSS Distributions /*
69*33de042dSApple OSS Distributions * After bind fails, try binding to a different port.
70*33de042dSApple OSS Distributions * For non-root user, this will panic without the fix for
71*33de042dSApple OSS Distributions * <rdar://problem/35243417>.
72*33de042dSApple OSS Distributions */
73*33de042dSApple OSS Distributions if (sockv6_bind(s6_other, i + 1) == 0) {
74*33de042dSApple OSS Distributions bound_count++;
75*33de042dSApple OSS Distributions if (bound_count >= bind_attempts) {
76*33de042dSApple OSS Distributions break;
77*33de042dSApple OSS Distributions }
78*33de042dSApple OSS Distributions }
79*33de042dSApple OSS Distributions loop_done:
80*33de042dSApple OSS Distributions if (s6 >= 0) {
81*33de042dSApple OSS Distributions close(s6);
82*33de042dSApple OSS Distributions }
83*33de042dSApple OSS Distributions if (s6_other >= 0) {
84*33de042dSApple OSS Distributions close(s6_other);
85*33de042dSApple OSS Distributions }
86*33de042dSApple OSS Distributions }
87*33de042dSApple OSS Distributions T_ASSERT_TRUE(bound_count == bind_attempts,
88*33de042dSApple OSS Distributions "number of successful binds %d (out of %d)",
89*33de042dSApple OSS Distributions bound_count, bind_attempts);
90*33de042dSApple OSS Distributions return success;
91*33de042dSApple OSS Distributions }
92*33de042dSApple OSS Distributions
93*33de042dSApple OSS Distributions
94*33de042dSApple OSS Distributions T_DECL(socket_bind_35243417,
95*33de042dSApple OSS Distributions "bind IPv6 only UDP socket, then bind IPv6 socket.",
96*33de042dSApple OSS Distributions T_META_ASROOT(false),
97*33de042dSApple OSS Distributions T_META_CHECK_LEAKS(false),
98*33de042dSApple OSS Distributions T_META_TAG_VM_PREFERRED)
99*33de042dSApple OSS Distributions {
100*33de042dSApple OSS Distributions alloc_and_bind_ports(1, 65534, 10);
101*33de042dSApple OSS Distributions }
102*33de042dSApple OSS Distributions
103*33de042dSApple OSS Distributions T_DECL(socket_bind_35243417_root,
104*33de042dSApple OSS Distributions "bind IPv6 only UDP socket, then bind IPv6 socket.",
105*33de042dSApple OSS Distributions T_META_ASROOT(true),
106*33de042dSApple OSS Distributions T_META_TAG_VM_PREFERRED)
107*33de042dSApple OSS Distributions {
108*33de042dSApple OSS Distributions alloc_and_bind_ports(1, 65534, 10);
109*33de042dSApple OSS Distributions }
110