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 // C++ STL and other related includes 34 #include <stdlib.h> 35 #include <limits.h> 36 #include <iostream> 37 #include <string.h> 38 #include <string> 39 40 // Operating System and other C based includes 41 #include <unistd.h> 42 #include <errno.h> 43 #include <sys/types.h> 44 #include <sys/time.h> 45 #include <sys/socket.h> 46 #include <sys/ioctl.h> 47 #include <netinet/in.h> 48 #include <net/if.h> 49 #include <arpa/inet.h> 50 51 // Private include files 52 #include "mctest.h" 53 54 using namespace std; 55 56 // 57 // usage - just the program's usage line 58 // 59 // 60 void usage() 61 { 62 cout << "mcgrab -i interface -g multicast group -n number of groups\n"; 63 exit(-1); 64 } 65 66 // 67 // usage - print out the usage with a possible message and exit 68 // 69 // \param message optional string 70 // 71 // 72 void usage(string message) 73 { 74 75 cerr << message << endl; 76 usage(); 77 } 78 79 80 // 81 // grab a set of addresses 82 // 83 // @param interface ///< text name of the interface (em0 etc.) 84 // @param group ///< multicast group 85 // @param number ///< number of addresses to grab 86 // 87 // @return 0 for 0K, -1 for error, sets errno 88 // 89 void grab(char *interface, struct in_addr *group, int number, int block) { 90 91 92 int sock; 93 struct ip_mreq mreq; 94 struct ifreq ifreq; 95 struct in_addr lgroup; 96 97 if (group == NULL) { 98 group = &lgroup; 99 if (inet_pton(AF_INET, DEFAULT_GROUP, group) < 1) 100 return; 101 } 102 103 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 104 perror("failed to open datagram socket"); 105 return; 106 } 107 108 for (int i = 0; i < number; i++) { 109 bzero((struct ip_mreq *)&mreq, sizeof(mreq)); 110 bzero((struct ifreq *)&ifreq, sizeof(ifreq)); 111 112 strncpy(ifreq.ifr_name, interface, IFNAMSIZ); 113 if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0) { 114 perror("no such interface"); 115 return; 116 } 117 118 memcpy(&mreq.imr_interface, 119 &((struct sockaddr_in*) &ifreq.ifr_addr)->sin_addr, 120 sizeof(struct in_addr)); 121 122 mreq.imr_multiaddr.s_addr = group->s_addr; 123 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, 124 sizeof(mreq)) < 0) { 125 126 perror("failed to add membership"); 127 return; 128 } 129 130 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, 131 &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, 132 sizeof(struct in_addr)) < 0) { 133 perror("failed to bind interface"); 134 return; 135 } 136 137 group->s_addr = htonl(ntohl(group->s_addr) + 1); 138 } 139 if (block > 0) { 140 printf("Press Control-C to exit.\n"); 141 sleep(INT_MAX); 142 } 143 144 } 145 146 147 // 148 // main - the main program 149 // 150 // \param -g multicast group address which we will hold 151 // \param -i interface on which we're holding the address 152 // 153 // 154 int main(int argc, char**argv) 155 { 156 157 char ch; ///< character from getopt() 158 extern char* optarg; ///< option argument 159 160 char* interface = 0; ///< Name of the interface 161 struct in_addr *group = NULL; ///< the multicast group address 162 int number = 0; ///< Number of addresses to grab 163 int block = 1; ///< Do we block or just return? 164 165 if ((argc < 7) || (argc > 8)) 166 usage(); 167 168 while ((ch = getopt(argc, argv, "g:i:n:bh")) != -1) { 169 switch (ch) { 170 case 'g': 171 group = new (struct in_addr ); 172 if (inet_pton(AF_INET, optarg, group) < 1) 173 usage(argv[0] + string(" Error: invalid multicast group") + 174 optarg); 175 break; 176 case 'i': 177 interface = optarg; 178 break; 179 case 'n': 180 number = atoi(optarg); 181 break; 182 case 'b': 183 block = 0; 184 break; 185 case 'h': 186 usage(string("Help\n")); 187 break; 188 } 189 } 190 191 grab(interface, group, number, block); 192 193 } 194