1 /*
2 * Check decoding of MCAST_JOIN_GROUP/MCAST_LEAVE_GROUP.
3 *
4 * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2017-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include <net/if.h>
13 #include <netinet/in.h>
14
15 #if defined MCAST_JOIN_GROUP && defined MCAST_LEAVE_GROUP
16
17 # include <limits.h>
18 # include <stdio.h>
19 # include <unistd.h>
20 # include <sys/socket.h>
21 # include <arpa/inet.h>
22
23 # define multi4addr "224.0.0.3"
24 # define multi6addr "ff01::c"
25
26 static const char *errstr;
27
28 static int
29 set_opt(const int fd, const int level, const int opt,
30 const void *const val, const socklen_t len)
31 {
32 int rc = setsockopt(fd, level, opt, val, len);
33 errstr = sprintrc(rc);
34 return rc;
35 }
36
37 int
38 main(void)
39 {
40 TAIL_ALLOC_OBJECT_CONST_PTR(struct group_req, greq4);
41 TAIL_ALLOC_OBJECT_CONST_PTR(struct group_req, greq6);
42
43 greq6->gr_interface = greq4->gr_interface = ifindex_lo();
44 if (!greq4->gr_interface)
45 perror_msg_and_skip("lo");
46
47 greq4->gr_group.ss_family = AF_INET;
48 inet_pton(AF_INET, multi4addr, &greq4->gr_group.ss_family + 2);
49
50 greq6->gr_group.ss_family = AF_INET6;
51 inet_pton(AF_INET6, multi6addr, &greq6->gr_group.ss_family + 4);
52
53 (void) close(0);
54 if (socket(AF_INET, SOCK_DGRAM, 0))
55 perror_msg_and_skip("socket");
56
57 struct {
58 const int level;
59 const char *const str_level;
60 const int name;
61 const char *const str_name;
62 const struct group_req *const val;
63 const char *const addr;
64 } opts[] = {
65 {
66 ARG_STR(SOL_IP), ARG_STR(MCAST_JOIN_GROUP), greq4,
67 "gr_group={sa_family=AF_INET, sin_port=htons(65535)"
68 ", sin_addr=inet_addr(\"" multi4addr "\")}"
69 },
70 {
71 ARG_STR(SOL_IP), ARG_STR(MCAST_LEAVE_GROUP), greq4,
72 "gr_group={sa_family=AF_INET, sin_port=htons(65535)"
73 ", sin_addr=inet_addr(\"" multi4addr "\")}"
74 },
75 {
76 ARG_STR(SOL_IPV6), ARG_STR(MCAST_JOIN_GROUP), greq6,
77 "gr_group={sa_family=AF_INET6, sin6_port=htons(65535)"
78 ", sin6_flowinfo=htonl(4294967295)"
79 ", inet_pton(AF_INET6, \"" multi6addr "\", &sin6_addr)"
80 ", sin6_scope_id=4294967295}"
81 },
82 {
83 ARG_STR(SOL_IPV6), ARG_STR(MCAST_LEAVE_GROUP), greq6,
84 "gr_group={sa_family=AF_INET6, sin6_port=htons(65535)"
85 ", sin6_flowinfo=htonl(4294967295)"
86 ", inet_pton(AF_INET6, \"" multi6addr "\", &sin6_addr)"
87 ", sin6_scope_id=4294967295}"
88 }
89 };
90
91 for (unsigned int i = 0; i < ARRAY_SIZE(opts); ++i) {
92 /* optlen < 0, EINVAL */
93 set_opt(0, opts[i].level, opts[i].name, opts[i].val, -1U);
94 printf("setsockopt(0, %s, %s, %p, -1) = %s\n",
95 opts[i].str_level, opts[i].str_name,
96 opts[i].val, errstr);
97
98 /* optlen < sizeof(struct group_req), EINVAL */
99 set_opt(0, opts[i].level, opts[i].name, opts[i].val,
100 sizeof(*opts[i].val) - 1);
101 printf("setsockopt(0, %s, %s, %p, %u) = %s\n",
102 opts[i].str_level, opts[i].str_name,
103 opts[i].val, (unsigned int) sizeof(*opts[i].val) - 1,
104 errstr);
105
106 /* optval EFAULT */
107 set_opt(0, opts[i].level, opts[i].name,
108 (const char *) opts[i].val + 1, sizeof(*opts[i].val));
109 printf("setsockopt(0, %s, %s, %p, %u) = %s\n",
110 opts[i].str_level, opts[i].str_name,
111 (const char *) opts[i].val + 1,
112 (unsigned int) sizeof(*opts[i].val), errstr);
113
114 /* classic */
115 set_opt(0, opts[i].level, opts[i].name,
116 opts[i].val, sizeof(*opts[i].val));
117 printf("setsockopt(0, %s, %s"
118 ", {gr_interface=%s, %s}, %u) = %s\n",
119 opts[i].str_level, opts[i].str_name,
120 IFINDEX_LO_STR, opts[i].addr,
121 (unsigned int) sizeof(*opts[i].val), errstr);
122
123 /* optlen > sizeof(struct group_req), shortened */
124 set_opt(0, opts[i].level, opts[i].name, opts[i].val, INT_MAX);
125 printf("setsockopt(0, %s, %s"
126 ", {gr_interface=%s, %s}, %u) = %s\n",
127 opts[i].str_level, opts[i].str_name,
128 IFINDEX_LO_STR, opts[i].addr,
129 INT_MAX, errstr);
130 }
131
132 puts("+++ exited with 0 +++");
133 return 0;
134 }
135
136 #else
137
138 SKIP_MAIN_UNDEFINED("MCAST_JOIN_GROUP && MCAST_LEAVE_GROUP")
139
140 #endif