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 54using namespace std; 55 56// 57// usage - just the program's usage line 58// 59// 60void 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// 72void 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// 89void 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// 154int 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