summaryrefslogtreecommitdiffstats
path: root/src/igmp_querier.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/igmp_querier.c')
-rw-r--r--src/igmp_querier.c213
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;
+}