1180394Sgnn// 2180394Sgnn// Copyright (c) 2008, Neville-Neil Consulting 3180394Sgnn// All rights reserved. 4180394Sgnn// 5180394Sgnn// Redistribution and use in source and binary forms, with or without 6180394Sgnn// modification, are permitted provided that the following conditions 7180394Sgnn// are met: 8180394Sgnn// 1. Redistributions of source code must retain the above copyright 9180394Sgnn// notice, this list of conditions and the following disclaimer. 10180394Sgnn// 2. Redistributions in binary form must reproduce the above copyright 11180394Sgnn// notice, this list of conditions and the following disclaimer in the 12180394Sgnn// documentation and/or other materials provided with the distribution. 13180394Sgnn// 14180394Sgnn// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15180394Sgnn// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16180394Sgnn// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17180394Sgnn// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18180394Sgnn// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19180394Sgnn// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20180394Sgnn// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21180394Sgnn// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22180394Sgnn// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23180394Sgnn// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24180394Sgnn// SUCH DAMAGE. 25180394Sgnn// 26180394Sgnn// This test simply grabs N multicast addresses starting 27180394Sgnn// from a base address. The purpose is to make sure that switching a device 28180394Sgnn// from using a multicast filtering table or function to promiscuous 29180394Sgnn// multicast listening mode does not cause deleterious side effects. 30180394Sgnn// 31180394Sgnn 32180394Sgnn#include <sys/cdefs.h> 33180394Sgnn__FBSDID("$FreeBSD$"); 34180394Sgnn 35180394Sgnn// C++ STL and other related includes 36180394Sgnn#include <stdlib.h> 37180394Sgnn#include <limits.h> 38180394Sgnn#include <iostream> 39180394Sgnn#include <string.h> 40180394Sgnn#include <string> 41180394Sgnn 42180394Sgnn// Operating System and other C based includes 43180394Sgnn#include <unistd.h> 44180394Sgnn#include <errno.h> 45180394Sgnn#include <sys/types.h> 46180394Sgnn#include <sys/time.h> 47180394Sgnn#include <sys/socket.h> 48180394Sgnn#include <sys/ioctl.h> 49180394Sgnn#include <netinet/in.h> 50180394Sgnn#include <net/if.h> 51180394Sgnn#include <arpa/inet.h> 52180394Sgnn 53180394Sgnn// Private include files 54180394Sgnn#include "mctest.h" 55180394Sgnn 56180394Sgnnusing namespace std; 57180394Sgnn 58180394Sgnn// 59180394Sgnn// usage - just the program's usage line 60180394Sgnn// 61180394Sgnn// 62180394Sgnnvoid usage() 63180394Sgnn{ 64180394Sgnn cout << "mcgrab -i interface -g multicast group -n number of groups\n"; 65180394Sgnn exit(-1); 66180394Sgnn} 67180394Sgnn 68180394Sgnn// 69180394Sgnn// usage - print out the usage with a possible message and exit 70180394Sgnn// 71180394Sgnn// \param message optional string 72180394Sgnn// 73180394Sgnn// 74180394Sgnnvoid usage(string message) 75180394Sgnn{ 76180394Sgnn 77180394Sgnn cerr << message << endl; 78180394Sgnn usage(); 79180394Sgnn} 80180394Sgnn 81180394Sgnn 82180394Sgnn// 83180394Sgnn// grab a set of addresses 84180394Sgnn// 85180394Sgnn// @param interface ///< text name of the interface (em0 etc.) 86180394Sgnn// @param group ///< multicast group 87180394Sgnn// @param number ///< number of addresses to grab 88180394Sgnn// 89180394Sgnn// @return 0 for 0K, -1 for error, sets errno 90180394Sgnn// 91260791Sgnnvoid grab(char *interface, struct in_addr *group, int number, int block) { 92180394Sgnn 93180394Sgnn 94180394Sgnn int sock; 95180394Sgnn struct ip_mreq mreq; 96180394Sgnn struct ifreq ifreq; 97180394Sgnn struct in_addr lgroup; 98180394Sgnn 99180394Sgnn if (group == NULL) { 100180394Sgnn group = &lgroup; 101180394Sgnn if (inet_pton(AF_INET, DEFAULT_GROUP, group) < 1) 102180394Sgnn return; 103180394Sgnn } 104180394Sgnn 105180394Sgnn if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 106180394Sgnn perror("failed to open datagram socket"); 107180394Sgnn return; 108180394Sgnn } 109180394Sgnn 110180394Sgnn for (int i = 0; i < number; i++) { 111180394Sgnn bzero((struct ip_mreq *)&mreq, sizeof(mreq)); 112180394Sgnn bzero((struct ifreq *)&ifreq, sizeof(ifreq)); 113180394Sgnn 114180394Sgnn strncpy(ifreq.ifr_name, interface, IFNAMSIZ); 115180394Sgnn if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0) { 116180394Sgnn perror("no such interface"); 117180394Sgnn return; 118180394Sgnn } 119180394Sgnn 120180394Sgnn memcpy(&mreq.imr_interface, 121180394Sgnn &((struct sockaddr_in*) &ifreq.ifr_addr)->sin_addr, 122180394Sgnn sizeof(struct in_addr)); 123180394Sgnn 124180394Sgnn mreq.imr_multiaddr.s_addr = group->s_addr; 125180394Sgnn if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, 126180394Sgnn sizeof(mreq)) < 0) { 127180394Sgnn 128180394Sgnn perror("failed to add membership"); 129180394Sgnn return; 130180394Sgnn } 131180394Sgnn 132180394Sgnn if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, 133180394Sgnn &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, 134180394Sgnn sizeof(struct in_addr)) < 0) { 135180394Sgnn perror("failed to bind interface"); 136180394Sgnn return; 137180394Sgnn } 138180394Sgnn 139180394Sgnn group->s_addr = htonl(ntohl(group->s_addr) + 1); 140180394Sgnn } 141260791Sgnn if (block > 0) { 142260791Sgnn printf("Press Control-C to exit.\n"); 143260791Sgnn sleep(INT_MAX); 144260791Sgnn } 145180394Sgnn 146180394Sgnn} 147180394Sgnn 148180394Sgnn 149180394Sgnn// 150180394Sgnn// main - the main program 151180394Sgnn// 152180394Sgnn// \param -g multicast group address which we will hold 153180394Sgnn// \param -i interface on which we're holding the address 154180394Sgnn// 155180394Sgnn// 156180394Sgnnint main(int argc, char**argv) 157180394Sgnn{ 158180394Sgnn 159180394Sgnn char ch; ///< character from getopt() 160180394Sgnn extern char* optarg; ///< option argument 161180394Sgnn 162180394Sgnn char* interface = 0; ///< Name of the interface 163180394Sgnn struct in_addr *group = NULL; ///< the multicast group address 164180394Sgnn int number = 0; ///< Number of addresses to grab 165260791Sgnn int block = 1; ///< Do we block or just return? 166180394Sgnn 167260791Sgnn if ((argc < 7) || (argc > 8)) 168180394Sgnn usage(); 169180394Sgnn 170260791Sgnn while ((ch = getopt(argc, argv, "g:i:n:bh")) != -1) { 171180394Sgnn switch (ch) { 172180394Sgnn case 'g': 173180394Sgnn group = new (struct in_addr ); 174180394Sgnn if (inet_pton(AF_INET, optarg, group) < 1) 175180394Sgnn usage(argv[0] + string(" Error: invalid multicast group") + 176180394Sgnn optarg); 177180394Sgnn break; 178180394Sgnn case 'i': 179180394Sgnn interface = optarg; 180180394Sgnn break; 181180394Sgnn case 'n': 182180394Sgnn number = atoi(optarg); 183180394Sgnn break; 184260791Sgnn case 'b': 185260791Sgnn block = 0; 186260791Sgnn break; 187180394Sgnn case 'h': 188180394Sgnn usage(string("Help\n")); 189180394Sgnn break; 190180394Sgnn } 191180394Sgnn } 192180394Sgnn 193260791Sgnn grab(interface, group, number, block); 194180394Sgnn 195180394Sgnn} 196