1#include <arpa/inet.h>
2#include <sys/types.h>
3#include <sys/socket.h>
4#include <netinet/in.h>
5#include <errno.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <netdb.h>
10#include <unistd.h>
11
12static char *prog;
13static int errors;
14
15static int join_group(int, char *, struct ip_mreq *);
16static int leave_group(int, char *, struct ip_mreq *);
17static void usage(void);
18
19int main(int argc, char *argv[])
20{
21	int s;
22	struct ip_mreq imr;
23
24	char *group_list = NULL, *interface = NULL;
25	unsigned i1, i2, i3, i4;
26	struct hostent *hp, *gethostbyname();
27	int c;
28	int lflg = 0, jflg = 0, sflg = 0;
29
30	prog = argv[0];
31	if (argc == 1)
32		usage();
33
34	while ((c = getopt(argc, argv, "jlg:s:i:")) != EOF)
35		switch (c) {
36		case 'j':
37			if (lflg)
38				usage();
39			else
40				jflg++;
41			break;
42		case 'l':
43			if (jflg)
44				usage();
45			else
46				lflg++;
47			break;
48		case 'g':
49			group_list = optarg;
50			break;
51		case 's':
52			sflg = atoi(optarg);
53			break;
54		case 'i':
55			interface = optarg;
56			break;
57		case '?':
58			usage();
59		}
60
61	if (optind != argc)
62		usage();
63
64	if (access(group_list, R_OK) != 0) {
65		printf("Unabled to read group file %s\n", group_list);
66		exit(1);
67	}
68
69	s = socket(AF_INET, SOCK_DGRAM, 0);
70	if (s == -1) {
71		perror("can not open socket");
72		exit(1);
73	}
74
75	hp = gethostbyname(interface);
76	if (hp != NULL) {
77		memcpy(&imr.imr_interface.s_addr, hp->h_addr, hp->h_length);
78	} else if (sscanf(interface, "%u.%u.%u.%u", &i1, &i2, &i3, &i4) != 4) {
79		fprintf(stderr, "bad group address\n");
80		exit(1);
81	} else {
82		imr.imr_interface.s_addr =
83		    htonl((i1 << 24) | (i2 << 16) | (i3 << 8) | i4);
84	}
85	/* verify socket options */
86	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
87		       &imr.imr_interface.s_addr,
88		       sizeof(imr.imr_interface.s_addr)) != 0) {
89		fprintf(stderr,
90			"Error: unable to set socket option IP_MULTICAST_IF\n");
91		errors++;
92	} else
93		printf("Socket set for Multicasting on: %s\n", interface);
94
95	if ((!jflg && !lflg) || jflg)
96		join_group(s, group_list, &imr);
97
98	sleep(sflg);
99
100	if ((!jflg && !lflg) || lflg)
101		leave_group(s, group_list, &imr);
102
103	close(s);
104	if (errors)
105		exit(1);
106	return 0;
107}
108
109static int join_group(int s, char *glist, struct ip_mreq *imr)
110{
111	char buf[40];
112	unsigned g1, g2, g3, g4;
113	FILE *fd;
114	char group[40], itf[40];
115
116	fd = fopen(glist, "r");
117	if (fd == NULL)
118		printf("Error: unable to open %s\n", glist);
119
120	while (fgets(buf, sizeof(buf), fd) != NULL) {
121		if (sscanf(buf, "%u.%u.%u.%u", &g1, &g2, &g3, &g4) != 4) {
122			fprintf(stderr, "bad group address\n");
123			exit(1);
124		}
125
126		imr->imr_multiaddr.s_addr =
127		    htonl((g1 << 24) | (g2 << 16) | (g3 << 8) | g4);
128
129		if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
130			       imr, sizeof(struct ip_mreq)) == -1) {
131			fprintf(stderr, "errno is %d\n", errno);
132			perror("can't join group");
133			errors++;
134		} else {
135			strcpy(group, inet_ntoa(imr->imr_multiaddr));
136			strcpy(itf, inet_ntoa(imr->imr_interface));
137			printf("IPM group: %s added to interface: %s\n", group,
138			       itf);
139		}
140	}
141	return 0;
142}
143
144static int leave_group(int s, char *glist, struct ip_mreq *imr)
145{
146	char buf[40];
147	unsigned g1, g2, g3, g4;
148	FILE *fd;
149	char group[40], itf[40];
150
151	fd = fopen(glist, "r");
152	if (fd == NULL)
153		printf("Error: unable to open %s\n", glist);
154
155	while (fgets(buf, sizeof(buf), fd) != NULL) {
156		if (sscanf(buf, "%u.%u.%u.%u", &g1, &g2, &g3, &g4) != 4) {
157			fprintf(stderr, "leave_group: bad group address\n");
158			exit(1);
159		}
160
161		imr->imr_multiaddr.s_addr =
162		    htonl((g1 << 24) | (g2 << 16) | (g3 << 8) | g4);
163
164		if (setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,
165			       imr, sizeof(struct ip_mreq)) == -1) {
166			perror("can't leave group");
167			errors++;
168		} else {
169			strcpy(group, inet_ntoa(imr->imr_multiaddr));
170			strcpy(itf, inet_ntoa(imr->imr_interface));
171			printf("IPM group: %s dropped from interface: %s\n",
172			       group, itf);
173		}
174	}
175	return 0;
176}
177
178static void usage(void)
179{
180	fprintf(stderr,
181		"usage: %s [ -j -l ] -g group_list [-s time_to_sleep] -i interface_name (or i.i.i.i)\n",
182		prog);
183	exit(1);
184}
185