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