1 // 2 // Copyright (c) 2008, Neville-Neil Consulting 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 // 14 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 // SUCH DAMAGE. 25 // 26 // This test simply grabs N multicast addresses starting 27 // from a base address. The purpose is to make sure that switching a device 28 // from using a multicast filtering table or function to promiscuous 29 // multicast listening mode does not cause deleterious side effects. 30 // 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 // C++ STL and other related includes 36 #include <stdlib.h> 37 #include <limits.h> 38 #include <iostream> 39 #include <string.h> 40 #include <string> 41 42 // Operating System and other C based includes 43 #include <unistd.h> 44 #include <errno.h> 45 #include <sys/types.h> 46 #include <sys/time.h> 47 #include <sys/socket.h> 48 #include <sys/ioctl.h> 49 #include <netinet/in.h> 50 #include <net/if.h> 51 #include <arpa/inet.h> 52 53 // Private include files 54 #include "mctest.h" 55 56 using namespace std; 57 58 // 59 // usage - just the program's usage line 60 // 61 // 62 void usage() 63 { 64 cout << "mcgrab -i interface -g multicast group -n number of groups\n"; 65 exit(-1); 66 } 67 68 // 69 // usage - print out the usage with a possible message and exit 70 // 71 // \param message optional string 72 // 73 // 74 void usage(string message) 75 { 76 77 cerr << message << endl; 78 usage(); 79 } 80 81 82 // 83 // grab a set of addresses 84 // 85 // @param interface ///< text name of the interface (em0 etc.) 86 // @param group ///< multicast group 87 // @param number ///< number of addresses to grab 88 // 89 // @return 0 for 0K, -1 for error, sets errno 90 // 91 void grab(char *interface, struct in_addr *group, int number, int block) { 92 93 94 int sock; 95 struct ip_mreq mreq; 96 struct ifreq ifreq; 97 struct in_addr lgroup; 98 99 if (group == NULL) { 100 group = &lgroup; 101 if (inet_pton(AF_INET, DEFAULT_GROUP, group) < 1) 102 return; 103 } 104 105 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 106 perror("failed to open datagram socket"); 107 return; 108 } 109 110 for (int i = 0; i < number; i++) { 111 bzero((struct ip_mreq *)&mreq, sizeof(mreq)); 112 bzero((struct ifreq *)&ifreq, sizeof(ifreq)); 113 114 strncpy(ifreq.ifr_name, interface, IFNAMSIZ); 115 if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0) { 116 perror("no such interface"); 117 return; 118 } 119 120 memcpy(&mreq.imr_interface, 121 &((struct sockaddr_in*) &ifreq.ifr_addr)->sin_addr, 122 sizeof(struct in_addr)); 123 124 mreq.imr_multiaddr.s_addr = group->s_addr; 125 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, 126 sizeof(mreq)) < 0) { 127 128 perror("failed to add membership"); 129 return; 130 } 131 132 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, 133 &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, 134 sizeof(struct in_addr)) < 0) { 135 perror("failed to bind interface"); 136 return; 137 } 138 139 group->s_addr = htonl(ntohl(group->s_addr) + 1); 140 } 141 if (block > 0) { 142 printf("Press Control-C to exit.\n"); 143 sleep(INT_MAX); 144 } 145 146 } 147 148 149 // 150 // main - the main program 151 // 152 // \param -g multicast group address which we will hold 153 // \param -i interface on which we're holding the address 154 // 155 // 156 int main(int argc, char**argv) 157 { 158 159 char ch; ///< character from getopt() 160 extern char* optarg; ///< option argument 161 162 char* interface = 0; ///< Name of the interface 163 struct in_addr *group = NULL; ///< the multicast group address 164 int number = 0; ///< Number of addresses to grab 165 int block = 1; ///< Do we block or just return? 166 167 if ((argc < 7) || (argc > 8)) 168 usage(); 169 170 while ((ch = getopt(argc, argv, "g:i:n:bh")) != -1) { 171 switch (ch) { 172 case 'g': 173 group = new (struct in_addr ); 174 if (inet_pton(AF_INET, optarg, group) < 1) 175 usage(argv[0] + string(" Error: invalid multicast group") + 176 optarg); 177 break; 178 case 'i': 179 interface = optarg; 180 break; 181 case 'n': 182 number = atoi(optarg); 183 break; 184 case 'b': 185 block = 0; 186 break; 187 case 'h': 188 usage(string("Help\n")); 189 break; 190 } 191 } 192 193 grab(interface, group, number, block); 194 195 } 196