mcgrab.cc revision 225736
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: stable/9/tools/tools/mcgrab/mcgrab.cc 204310 2010-02-25 14:36:50Z ru $"); 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 56using namespace std; 57 58// 59// usage - just the program's usage line 60// 61// 62void 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// 74void 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// 91void grab(char *interface, struct in_addr *group, int number) { 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 printf("Press Control-C to exit.\n"); 142 sleep(INT_MAX); 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 164 if (argc != 7) 165 usage(); 166 167 while ((ch = getopt(argc, argv, "g:i:n:h")) != -1) { 168 switch (ch) { 169 case 'g': 170 group = new (struct in_addr ); 171 if (inet_pton(AF_INET, optarg, group) < 1) 172 usage(argv[0] + string(" Error: invalid multicast group") + 173 optarg); 174 break; 175 case 'i': 176 interface = optarg; 177 break; 178 case 'n': 179 number = atoi(optarg); 180 break; 181 case 'h': 182 usage(string("Help\n")); 183 break; 184 } 185 } 186 187 grab(interface, group, number); 188 189} 190