1e2c3f7afd092b0a20c3417954cc4fc6f7e6cc6c7robbiew#include <arpa/inet.h>
2865695bbc89088b9526ea9045410e5afb70a985cplars#include <sys/types.h>
3865695bbc89088b9526ea9045410e5afb70a985cplars#include <sys/socket.h>
4865695bbc89088b9526ea9045410e5afb70a985cplars#include <netinet/in.h>
5865695bbc89088b9526ea9045410e5afb70a985cplars#include <errno.h>
6865695bbc89088b9526ea9045410e5afb70a985cplars#include <stdio.h>
7e2c3f7afd092b0a20c3417954cc4fc6f7e6cc6c7robbiew#include <stdlib.h>
8e2c3f7afd092b0a20c3417954cc4fc6f7e6cc6c7robbiew#include <string.h>
9865695bbc89088b9526ea9045410e5afb70a985cplars#include <netdb.h>
10865695bbc89088b9526ea9045410e5afb70a985cplars#include <unistd.h>
11865695bbc89088b9526ea9045410e5afb70a985cplars
12cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic char *prog;
13cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic int errors;
14865695bbc89088b9526ea9045410e5afb70a985cplars
15cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic int join_group(int, char *, struct ip_mreq *);
16cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic int leave_group(int, char *, struct ip_mreq *);
17cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic void usage(void);
18e2c3f7afd092b0a20c3417954cc4fc6f7e6cc6c7robbiew
19cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangint main(int argc, char *argv[])
202c28215423293e443469a07ae7011135d058b671Garrett Cooper{
21354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int s;
22354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip_mreq imr;
23865695bbc89088b9526ea9045410e5afb70a985cplars
24354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *group_list = NULL, *interface = NULL;
25354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned i1, i2, i3, i4;
26354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct hostent *hp, *gethostbyname();
27cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	int c;
28354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int lflg = 0, jflg = 0, sflg = 0;
29354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
30354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	prog = argv[0];
31354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (argc == 1)
32354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		usage();
33354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
34354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while ((c = getopt(argc, argv, "jlg:s:i:")) != EOF)
35354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		switch (c) {
36354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'j':
37354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (lflg)
38354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				usage();
39354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			else
40354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				jflg++;
41354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
42354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'l':
43354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (jflg)
44354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				usage();
45354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			else
46354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				lflg++;
47354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
48354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'g':
49354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			group_list = optarg;
50354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
51354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 's':
52354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			sflg = atoi(optarg);
53354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
54354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'i':
55354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			interface = optarg;
56354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
57354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case '?':
58354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			usage();
59354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
60354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
61354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (optind != argc)
62354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		usage();
63354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
64354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (access(group_list, R_OK) != 0) {
65354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf("Unabled to read group file %s\n", group_list);
66354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(1);
67354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
68354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
69cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	s = socket(AF_INET, SOCK_DGRAM, 0);
70cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	if (s == -1) {
71354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		perror("can not open socket");
72354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(1);
73354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
74354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
75cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	hp = gethostbyname(interface);
76cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	if (hp != NULL) {
77354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		memcpy(&imr.imr_interface.s_addr, hp->h_addr, hp->h_length);
78cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	} else if (sscanf(interface, "%u.%u.%u.%u", &i1, &i2, &i3, &i4) != 4) {
79354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "bad group address\n");
80354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(1);
81cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	} else {
82354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		imr.imr_interface.s_addr =
83354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    htonl((i1 << 24) | (i2 << 16) | (i3 << 8) | i4);
84cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	}
85354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* verify socket options */
86354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
87354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       &imr.imr_interface.s_addr,
88354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       sizeof(imr.imr_interface.s_addr)) != 0) {
89354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr,
90354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			"Error: unable to set socket option IP_MULTICAST_IF\n");
91354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		errors++;
92354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else
93354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf("Socket set for Multicasting on: %s\n", interface);
94865695bbc89088b9526ea9045410e5afb70a985cplars
95354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if ((!jflg && !lflg) || jflg)
96354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		join_group(s, group_list, &imr);
97865695bbc89088b9526ea9045410e5afb70a985cplars
98354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sleep(sflg);
99865695bbc89088b9526ea9045410e5afb70a985cplars
100354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if ((!jflg && !lflg) || lflg)
101354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		leave_group(s, group_list, &imr);
102865695bbc89088b9526ea9045410e5afb70a985cplars
103354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	close(s);
104354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (errors)
105354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(1);
106cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	return 0;
107865695bbc89088b9526ea9045410e5afb70a985cplars}
108865695bbc89088b9526ea9045410e5afb70a985cplars
109cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic int join_group(int s, char *glist, struct ip_mreq *imr)
110865695bbc89088b9526ea9045410e5afb70a985cplars{
111354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char buf[40];
112354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned g1, g2, g3, g4;
113354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	FILE *fd;
114354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char group[40], itf[40];
115354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
116cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	fd = fopen(glist, "r");
117cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	if (fd == NULL)
118354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf("Error: unable to open %s\n", glist);
119354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
120354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while (fgets(buf, sizeof(buf), fd) != NULL) {
121354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (sscanf(buf, "%u.%u.%u.%u", &g1, &g2, &g3, &g4) != 4) {
122354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fprintf(stderr, "bad group address\n");
123354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			exit(1);
124354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
125354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
126354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		imr->imr_multiaddr.s_addr =
127354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    htonl((g1 << 24) | (g2 << 16) | (g3 << 8) | g4);
128354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
129354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
130354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       imr, sizeof(struct ip_mreq)) == -1) {
131cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang			fprintf(stderr, "errno is %d\n", errno);
132354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			perror("can't join group");
133354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			errors++;
134354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		} else {
135354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			strcpy(group, inet_ntoa(imr->imr_multiaddr));
136354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			strcpy(itf, inet_ntoa(imr->imr_interface));
137354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			printf("IPM group: %s added to interface: %s\n", group,
138354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       itf);
139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
140354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
141cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	return 0;
142865695bbc89088b9526ea9045410e5afb70a985cplars}
143865695bbc89088b9526ea9045410e5afb70a985cplars
144cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic int leave_group(int s, char *glist, struct ip_mreq *imr)
145865695bbc89088b9526ea9045410e5afb70a985cplars{
146354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char buf[40];
147354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned g1, g2, g3, g4;
148354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	FILE *fd;
149354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char group[40], itf[40];
150354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
151cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	fd = fopen(glist, "r");
152cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	if (fd == NULL)
153354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf("Error: unable to open %s\n", glist);
154354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
155354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while (fgets(buf, sizeof(buf), fd) != NULL) {
156354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (sscanf(buf, "%u.%u.%u.%u", &g1, &g2, &g3, &g4) != 4) {
157354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fprintf(stderr, "leave_group: bad group address\n");
158354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			exit(1);
159354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
160354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
161354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		imr->imr_multiaddr.s_addr =
162354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    htonl((g1 << 24) | (g2 << 16) | (g3 << 8) | g4);
163354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
164354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,
165354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       imr, sizeof(struct ip_mreq)) == -1) {
166354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			perror("can't leave group");
167354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			errors++;
168354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		} else {
169354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			strcpy(group, inet_ntoa(imr->imr_multiaddr));
170354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			strcpy(itf, inet_ntoa(imr->imr_interface));
171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			printf("IPM group: %s dropped from interface: %s\n",
172354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       group, itf);
173354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
174354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
175cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggang	return 0;
176865695bbc89088b9526ea9045410e5afb70a985cplars}
177865695bbc89088b9526ea9045410e5afb70a985cplars
178cb49919064fe0f527437fe0587dfc820290e4c35Zeng Linggangstatic void usage(void)
179865695bbc89088b9526ea9045410e5afb70a985cplars{
180354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	fprintf(stderr,
181354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"usage: %s [ -j -l ] -g group_list [-s time_to_sleep] -i interface_name (or i.i.i.i)\n",
182354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		prog);
183354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	exit(1);
184ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
185