1 /*
2  * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2015-2018 The strace developers.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "tests.h"
30 #include <netinet/in.h>
31 
32 #if defined IP_ADD_MEMBERSHIP && defined IPV6_ADD_MEMBERSHIP \
33  && defined IPV6_JOIN_ANYCAST
34 
35 # include <limits.h>
36 # include <stdio.h>
37 # include <unistd.h>
38 # include <sys/socket.h>
39 # include <arpa/inet.h>
40 # include <net/if.h>
41 
42 #define	multi4addr	"224.0.0.3"
43 #define	multi6addr	"ff01::c"
44 #define	interface	"127.0.0.1"
45 
46 int
main(void)47 main(void)
48 {
49 	TAIL_ALLOC_OBJECT_CONST_PTR(struct ip_mreq, m4);
50 	TAIL_ALLOC_OBJECT_CONST_PTR(struct ipv6_mreq, m6);
51 	unsigned int i;
52 	int rc;
53 
54 	inet_pton(AF_INET, multi4addr, &m4->imr_multiaddr);
55 	inet_pton(AF_INET, interface, &m4->imr_interface);
56 	inet_pton(AF_INET6, multi6addr, &m6->ipv6mr_multiaddr);
57 
58 	m6->ipv6mr_interface = ifindex_lo();
59 	if (!m6->ipv6mr_interface)
60 		perror_msg_and_skip("lo");
61 
62 	(void) close(0);
63 	if (socket(AF_INET, SOCK_DGRAM, 0))
64 		perror_msg_and_skip("socket");
65 
66 	struct {
67 		const int level;
68 		const char *const str_level;
69 		const int name;
70 		const char *str_name;
71 		const void *const val;
72 		unsigned int size;
73 		const char *const addr;
74 	} opts[] = {
75 		{
76 			ARG_STR(SOL_IP), ARG_STR(IP_ADD_MEMBERSHIP),
77 			m4, sizeof(*m4),
78 			"{imr_multiaddr=inet_addr(\"" multi4addr
79 			"\"), imr_interface=inet_addr(\"" interface "\")}"
80 		},
81 		{
82 			ARG_STR(SOL_IP), ARG_STR(IP_DROP_MEMBERSHIP),
83 			m4, sizeof(*m4),
84 			"{imr_multiaddr=inet_addr(\"" multi4addr
85 			"\"), imr_interface=inet_addr(\"" interface "\")}"
86 		},
87 		{
88 			ARG_STR(SOL_IPV6), ARG_STR(IPV6_ADD_MEMBERSHIP),
89 			m6, sizeof(*m6),
90 			"{inet_pton(AF_INET6, \"" multi6addr
91 			"\", &ipv6mr_multiaddr)"
92 			", ipv6mr_interface=" IFINDEX_LO_STR "}"
93 		},
94 		{
95 			ARG_STR(SOL_IPV6), ARG_STR(IPV6_DROP_MEMBERSHIP),
96 			m6, sizeof(*m6),
97 			"{inet_pton(AF_INET6, \"" multi6addr
98 			"\", &ipv6mr_multiaddr)"
99 			", ipv6mr_interface=" IFINDEX_LO_STR "}"
100 		},
101 		{
102 			ARG_STR(SOL_IPV6), ARG_STR(IPV6_JOIN_ANYCAST),
103 			m6, sizeof(*m6),
104 			"{inet_pton(AF_INET6, \"" multi6addr
105 			"\", &ipv6mr_multiaddr)"
106 			", ipv6mr_interface=" IFINDEX_LO_STR "}"
107 		},
108 		{
109 			ARG_STR(SOL_IPV6), ARG_STR(IPV6_LEAVE_ANYCAST),
110 			m6, sizeof(*m6),
111 			"{inet_pton(AF_INET6, \"" multi6addr
112 			"\", &ipv6mr_multiaddr)"
113 			", ipv6mr_interface=" IFINDEX_LO_STR "}"
114 		}
115 	};
116 
117 	for (i = 0; i < ARRAY_SIZE(opts); ++i) {
118 		/* optlen < 0, EINVAL */
119 		rc = setsockopt(0, opts[i].level, opts[i].name,
120 				opts[i].val, -1);
121 		printf("setsockopt(0, %s, %s, %p, -1) = %s\n",
122 		       opts[i].str_level, opts[i].str_name,
123 		       opts[i].val, sprintrc(rc));
124 
125 		/* optlen < sizeof(struct), EINVAL */
126 		rc = setsockopt(0, opts[i].level, opts[i].name,
127 				opts[i].val, opts[i].size - 1);
128 		printf("setsockopt(0, %s, %s, %p, %u) = %s\n",
129 		       opts[i].str_level, opts[i].str_name,
130 		       opts[i].val, opts[i].size - 1, sprintrc(rc));
131 
132 		/* optval EFAULT */
133 		rc = setsockopt(0, opts[i].level, opts[i].name,
134 				opts[i].val + 1, opts[i].size);
135 		printf("setsockopt(0, %s, %s, %p, %u) = %s\n",
136 		       opts[i].str_level, opts[i].str_name,
137 		       opts[i].val + 1, opts[i].size, sprintrc(rc));
138 
139 		/* classic */
140 		rc = setsockopt(0, opts[i].level, opts[i].name,
141 				opts[i].val, opts[i].size);
142 		printf("setsockopt(0, %s, %s, %s, %u) = %s\n",
143 		       opts[i].str_level, opts[i].str_name,
144 		       opts[i].addr, opts[i].size, sprintrc(rc));
145 
146 		/* optlen > sizeof(struct), shortened */
147 		rc = setsockopt(0, opts[i].level, opts[i].name,
148 				opts[i].val, INT_MAX);
149 		printf("setsockopt(0, %s, %s, %s, %u) = %s\n",
150 		       opts[i].str_level, opts[i].str_name,
151 		       opts[i].addr, INT_MAX, sprintrc(rc));
152 	}
153 
154 	puts("+++ exited with 0 +++");
155 	return 0;
156 }
157 
158 #else
159 
160 SKIP_MAIN_UNDEFINED("IP_ADD_MEMBERSHIP && IPV6_ADD_MEMBERSHIP"
161 		    " && IPV6_JOIN_ANYCAST")
162 
163 #endif
164