From 43ef132e2b35d7b9c4ed19cd06a1a8d9f752b79b Mon Sep 17 00:00:00 2001 From: Glenn Date: Mon, 14 Sep 2009 22:56:24 +0200 Subject: [PATCH] feat: add real igmp features --- src/igmpgen.c | 252 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 233 insertions(+), 19 deletions(-) diff --git a/src/igmpgen.c b/src/igmpgen.c index c9ac936..b220fd0 100644 --- a/src/igmpgen.c +++ b/src/igmpgen.c @@ -5,6 +5,8 @@ #include #include +#define IGMP_V3_MEMBERSHIP_REPORT 0x22 + /* Structure to represent IGMP extra information */ struct igmp_extra { u_int8_t igmp_version; @@ -21,80 +23,149 @@ struct igmp_extra { { 2, "query", 0x11, 1, "224.0.0.1", 0 }, { 2, "report", 0x16, 1, "224.0.0.2", 1 }, { 2, "leave", 0x17, 1, "224.0.0.2", 0 }, + { 3, "report", 0x22, 1, "224.0.0.22", 0 }, + /* Note: end of list (please keep) */ { 0, 0, 0, 0 }, }; void usage(char *name) { - fprintf(stderr, "usage: %s -i ethdevice -g group -t packet.version\n", name); + struct igmp_extra *pkt_ptr; + fprintf(stderr, "usage: %s -i ethdevice -g group -t packet.version [-s ip:port] [-d ip:port]\n", name); + + pkt_ptr = g_igmp_pkts; + fprintf(stderr,"\nAvailable packet types:\n"); + while(pkt_ptr->igmp_version || pkt_ptr->igmp_tag){ + fprintf(stderr," - %s.%d\n", pkt_ptr->igmp_tag, pkt_ptr->igmp_version); + pkt_ptr++; + } } int main(int argc, char **argv) { u_int32_t ip_src = 0; + u_int32_t ip_dst = 0; + u_int32_t igmp_group = 0; + char *igmp_group_str = NULL; char *ip_src_str = NULL; + char *ip_dst_str = NULL; + + /* ports */ + u_short src_prt = 3141; + u_short dst_prt = 5926; + + /* igmp stuff */ + u_char igmp_type = 0; + u_char igmp_code = 0; + u_int8_t igmp_version = 0; + int igmp_override; + struct igmp_extra *pkt_ptr; + + int ip_src_test = 1; + int ip_dst_test = 1; + int igmp_group_test =1; + /* libnet stuff */ char neterr[LIBNET_ERRBUF_SIZE]; + libnet_ptag_t ptag; libnet_t *netcontext = NULL; /* misc */ - int c; - char *device = NULL; - u_int8_t igmp_version = 0; - char *cp = NULL; - int found = 0; - struct igmp_extra *pkt_ptr; - u_char igmp_type = 0; - u_char igmp_code = 0; + char *device = "eth0"; + int c; + char *cp = NULL; + int found=0; printf("IGMP packet generator\n\n"); printf("Parsing command line...\n"); - while((c = getopt(argc, argv, "i:t:g:")) != EOF) + while((c = getopt(argc, argv, "i:t:g:d:s:")) != EOF) { switch (c) { case 'i': - printf(" Net interface = [%s]\n", optarg); + printf(" Net interface = [%s]\n",optarg); device = optarg; break; + case 't': if (!(cp = strrchr(optarg, '.'))) { usage(argv[0]); exit(1); } *cp++ = 0; + igmp_version = (u_short)atoi(cp); + pkt_ptr = g_igmp_pkts; - while (pkt_ptr->igmp_version || pkt_ptr->igmp_tag) { + while(pkt_ptr->igmp_version || pkt_ptr->igmp_tag){ if ((strcasecmp(pkt_ptr->igmp_tag, optarg) == 0) - && (igmp_version == pkt_ptr->igmp_version)) { + && (igmp_version == pkt_ptr->igmp_version)){ found = 1; igmp_type = pkt_ptr->igmp_type; igmp_code = pkt_ptr->igmp_code; + ip_dst_str = pkt_ptr->igmp_dst; + igmp_override = pkt_ptr->group_override_dst; + break; } - pkt_ptr++; + pkt_ptr++; } - if (!found) { + if (found){ + printf(" Packet = [%s] version [%d]\n", pkt_ptr->igmp_tag, igmp_version); + } else { usage(argv[0]); exit(1); } break; + case 'g': // Group argument handling logic printf(" Group = [%s]\n", optarg); - igmp_group_str = optarg; + igmp_group_str = optarg; break; + case 'n': + // delay between packets in sec break; + + /* + * We expect the input to be of the form `ip.ip.ip.ip.port`. We + * point cp to the last dot of the IP address/port string and + * then seperate them with a NULL byte. The optarg now points to + * just the IP address, and cp points to the port. + */ + case 'd': + if ((cp = strrchr(optarg, ':'))) + { + *cp++ = 0; + dst_prt = (u_short)atoi(cp); + } else { + dst_prt = 0; + } + ip_dst_str = strdup(optarg); + printf(" Destination = ip [%s] port [%d]\n", ip_dst_str, dst_prt); + break; + + case 's': + if ((cp = strrchr(optarg, ':'))) + { + *cp++ = 0; + src_prt = (u_short)atoi(cp); + } else { + src_prt = 0; + } + ip_src_str = strdup(optarg); + printf(" Source = ip [%s] port [%d]\n", ip_src_str, src_prt); + break; + default: usage(argv[0]); exit(1); } } - if (!device) + if (!igmp_group_str || !device) { usage(argv[0]); exit(EXIT_FAILURE); @@ -120,7 +191,6 @@ int main(int argc, char **argv) /* Packet construction: IGMP */ printf(" Building IGMP content...\n"); - libnet_ptag_t ptag; ptag = libnet_build_igmp( igmp_type, // IGMP type igmp_code, // IGMP code @@ -146,6 +216,150 @@ int main(int argc, char **argv) printf("Packet sent successfully.\n"); } + printf("Packet construction...\n"); + + /* + * Packet construction : IGMP + */ + printf(" Building IGMP content...\n"); + + // Override dest with group info when needed + if (igmp_override) { + ip_dst_str = igmp_group_str; + } + + switch ( igmp_type ) { + case 0x11: // IGMP_MEMBERSHIP_QUERY + if (igmp_version == 2){ + // group specific + } else if (igmp_version == 1) { + // general + igmp_group = 0; + igmp_group_str = "0.0.0.0"; + igmp_group_test = 0; + } + // DST = 224.0.0.1 + //igmp_group = 0; + //igmp_group_test = 0; + break; + case 0x12: // + default: + break; + } + + if (ip_src_test + && !(ip_src = libnet_name2addr4(netcontext, ip_src_str, LIBNET_RESOLVE))) + { + fprintf(stderr,"Bad source IP address: %s\n", ip_src_str); + fprintf(stderr,"%s\n", libnet_geterror(netcontext)); + exit(1); + } + + if (ip_dst_test + && !(ip_dst = libnet_name2addr4(netcontext, ip_dst_str, LIBNET_RESOLVE))) + { + fprintf(stderr,"Bad destination IP address: %s\n", ip_dst_str); + fprintf(stderr,"%s\n", libnet_geterror(netcontext)); + exit(1); + } + + if (igmp_group_test && !(igmp_group = libnet_name2addr4(netcontext, igmp_group_str, LIBNET_RESOLVE))) + { + fprintf(stderr,"Bad group IP address: %s\n", optarg); + fprintf(stderr,"%s\n", libnet_geterror(netcontext)); + exit(1); + } + + printf(" IP SRC IP = %s\n", ip_src_str); + printf(" IP DEST IP = %s\n", ip_dst_str); + printf(" IGMP TYPE = 0x%02x\n", igmp_type); + printf(" IGMP CODE = 0x%02x\n", igmp_code); + printf(" IGMP GROUP = %s\n", igmp_group_str); + printf(" GROUP TEST = %d\n", igmp_group_test); + + /* + int test = 1; + if ( *(char *) test == 1) { + // little endian + printf("little endian\n"); + } else { + // big endian + printf("big endian\n"); + } + */ + + ptag = libnet_build_igmp( + igmp_type, // IGMP type + igmp_code, // IGMP code or TTL + 0, // checksum + htonl(igmp_group), // ip addr + NULL, // Ptr to packet data (or null) + 0, // Packet payload length + netcontext, // Ptr to libnet context + 0); // Build a new packet header + if (ptag < 0) + { + fprintf(stderr, "Error while building IGMP header data (err %d)\n", ptag); + fprintf(stderr,"%s\n", libnet_geterror(netcontext)); + exit(1); + } + + + u_int8_t ipopt[2]; + ipopt[0] = IPOPT_RA; + ipopt[1] = 4; + ptag = libnet_build_ipv4_options( + ipopt, // options + 2, // options_s (length of option string) + netcontext, // libnet context + 0 // ptag + ); + if (ptag < 0) + { + fprintf(stderr, "Error while building IPv4 options data (err %d)\n", ptag); + } + + ptag = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_IGMP_H, // pkg size + data + 0, // IP tos + getpid(), // IP ID + IP_DF, // frag flags and offset + 1, // TTL + IPPROTO_IGMP, // transport protocol + 0, // checksum + ip_src, // source IP + ip_dst, // destination IP + NULL, // payload (none) + 0, // payload length + netcontext, // libnet context + 0 // build a new header + ); + if (ptag < 0) + { + fprintf(stderr, "Error while building IPv4 header data (err %d)\n", ptag); + fprintf(stderr,"%s\n", libnet_geterror(netcontext)); + exit(1); + } + + printf(" done\n"); //IGMP content + + c = libnet_write(netcontext); + if (c < 0) + { + fprintf(stderr,"%s\n", libnet_geterror(netcontext)); + } + else + { + printf("construction and injection completed, wrote all %d bytes\n", c); + } + + /* + * Free packet memory. + */ + libnet_diag_dump_pblock(netcontext); libnet_destroy(netcontext); - return 0; + exit(0); + + return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS); } + +// vim: ts=4 sts=4 sw=4 et