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