diff options
Diffstat (limited to 'src/igmp_querier.c')
-rw-r--r-- | src/igmp_querier.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/igmp_querier.c b/src/igmp_querier.c new file mode 100644 index 0000000..d18af5b --- /dev/null +++ b/src/igmp_querier.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2018 + * Broadcom Corporation + * All Rights Reserved. + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. Neither the name of the Broadcom nor the names of + * contributors may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USEn, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author Robert J. McMahon, Broadcom LTD + * Date April 2016 + * + * IGMP 2 querier that can be controlled remotely + * + * Author Robert J. McMahon (rmcmahon) + * Last modified: 06/25/2010 + * + * $Copyright Open Broadcom Corporation$ + * + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <stdlib.h> +#include <time.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <strings.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <arpa/inet.h> +#include "headers.h" + +#define IGMP_HEADER_SIZE 8 + +void sigint(); +void siguser(); +void sigalrm(); +static int querier_sent_count = 0; +static int sendcount = 0; +static short daemonmode = 0; +static char mcast_queryaddr[20] = "224.0.0.1"; +static int send_igmp_allhosts_querier (char *); + + +int main (int argc, char **argv) { + char *tvalue = NULL; + char *cvalue = NULL; + int c; + int queryinterval; + int pid; + + opterr = 0; + while ((c = getopt (argc, argv, "c:dg:t:")) != -1) { + switch (c) { + case 'c': + cvalue = optarg; + break; + case 'g' : + strcpy(mcast_queryaddr, optarg); + break; + case 't': + tvalue = optarg; + break; + case 'd': + daemonmode = 1; + break; + case '?': + if (optopt == 't') + fprintf (stderr, "Option -%c requires an integer argument.\n", optopt); + else if (optopt == 'c') + fprintf (stderr, "Option -%c requires an integer argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr, + "Unknown option character `\\x%x'.\n", + optopt); + default: + fprintf(stderr,"Usage -c <count>, -d daemon, -g <group>, -t <period in seconds>\n"); + exit(-1); + } + } + if (tvalue != NULL) { + queryinterval = atoi(tvalue); + } else { + queryinterval = 0; + } + if (cvalue != NULL) { + sendcount = atoi(cvalue); + if (tvalue == NULL) + queryinterval = 0; + } else { + sendcount = 1; + } + signal(SIGINT, sigint); + signal(SIGUSR1, siguser); + signal(SIGALRM, sigalrm); + pid = (int) getpid(); + if (daemonmode) { + if (tvalue != NULL) { + sendcount = 1; + printf("IGMP All Hosts Querier (pid=%d) started as a daemon with interval of %d seconds to %s\n", pid, queryinterval, mcast_queryaddr); + } else { + sendcount = 0; + printf("IGMP All Hosts Querier (pid=%d) to %s started as a daemon only\n", pid, mcast_queryaddr); + } + } else { + printf("IGMP All Hosts Querier (pid=%d) sending %d reports with interval of %d seconds\n", pid, sendcount, queryinterval); + } + fflush(stdout); + while (daemonmode || sendcount) { + if (sendcount-- > 0) { + send_igmp_allhosts_querier(mcast_queryaddr); + } + if (queryinterval) { + alarm(queryinterval); + pause(); + } + if (daemonmode && sendcount <= 0) + pause(); + } +} + +void sigint (void) { + exit(0); +} + +void siguser (void) { + if (!send_igmp_allhosts_querier(mcast_queryaddr)) { + exit (-1); + } +} + +void sigalrm (void) { + if (daemonmode) + sendcount++; +} + +static int send_igmp_allhosts_querier (char *mcast_queryaddr) { + int sid=0; + int rc; + char buf[IGMP_HEADER_SIZE]; + unsigned int ttl=1; + char type = 17; + char maxresptime = 1; + // unsigned int groupaddr = 0; + char checksum_upper = 0xee; + char checksum_lower = 0xfe; + struct sockaddr_in msock; + const time_t timer = time(NULL); + + bzero (&buf, sizeof(buf)); + /* + * Note: with byte writes shouldn't need to worry about network/host + * byte ordering, though should double check on non intel system + */ + buf[0] = type; + buf[1] = maxresptime; + buf[2] = checksum_upper; + buf[3] = checksum_lower; + + bzero (&msock, sizeof(msock)); + msock.sin_family = AF_INET; + + inet_pton(AF_INET, mcast_queryaddr, &msock.sin_addr); + setuid(geteuid()); + sid = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); + if (sid != -1) { + rc = setsockopt(sid, IPPROTO_IP, IP_TTL, (char *) &ttl, sizeof(ttl)); + if (rc != -1) { + rc = sendto(sid, &buf, IGMP_HEADER_SIZE, 0, (const struct sockaddr *) &msock, sizeof(msock)); + if (rc == -1) { + fprintf(stderr, "IGMP Query sendto error = %s\n", strerror(errno)); + } + } else { + fprintf(stderr, "IGMP Query setsockopt error = %s\n", strerror(errno)); + } + } else { + fprintf(stderr, "IGMP Query, socket error = %s\n", strerror(errno)); + } + if (sid > 0) { + close(sid); + rc=1; + } else { + rc = 0; + } + setuid(getuid()); + if (rc) { + printf("Sent IGMP all hosts querier to %s (count = %d) at %s",mcast_queryaddr, ++querier_sent_count, ctime(&timer)); + fflush(stdout); + } + return rc; +} |