commit 04f524d203b78d4767873e14c062beb54c3c38e1 Author: Glenn Date: Fri Sep 25 21:18:43 2009 +0200 igmpv3gen: Initial import. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..0a82915 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,9 @@ +IGMPPROG=igmpgen +CFLAGS=-Werror -Wall `libnet-config --defines` +LDFLAGS=`libnet-config --libs` + +all: + gcc $(CFLAGS) $(IGMPPROG).c -o $(IGMPPROG) $(LDFLAGS) + +clean: + rm -f $(IGMPPROG) diff --git a/src/igmpgen.c b/src/igmpgen.c new file mode 100644 index 0000000..27eb7ee --- /dev/null +++ b/src/igmpgen.c @@ -0,0 +1,336 @@ +#include +#include + +#define IGMP_V3_MEMBERSHIP_REPORT 0x22 + +struct igmp_extra { + u_int8_t igmp_version; + char * igmp_tag; + u_int8_t igmp_type; /* IGMP type */ + u_int8_t igmp_code; /* routing code */ + char * igmp_dst; + int group_override_dst; +} g_igmp_pkts[] = { + // name, type (or version+type), code + { 1, "query", 0x11, 0, "224.0.0.1", 0 }, + { 1, "report", 0x12, 0, "224.0.0.1", 1 }, + { 1, "dvmrp", 0x13, 0, "224.0.0.1", 0 }, + + { 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 }, + + { 0, 0, 0, 0 }, +}; + +void usage(char *); + +int main(int argc, char **argv) +{ + /* ip addresses */ + 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; + + + 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; + char *device = "eth0"; + + /* misc */ + 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:d:s:")) != EOF) + { + switch (c) + { + case 'i': + 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){ + if ((strcasecmp(pkt_ptr->igmp_tag, optarg) == 0) + && (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++; + } + if (found){ + printf(" Packet = [%s] version [%d]\n", pkt_ptr->igmp_tag, igmp_version); + } else { + usage(argv[0]); + exit(1); + } + + break; + case 'g': + printf(" Group = [%s]\n", 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; + } + } + if (!igmp_group_str || !device) + { + usage(argv[0]); + exit(EXIT_FAILURE); + } + printf("done\n"); + + /* + * Memory initialization + */ + printf("Initializing libnet context..."); + netcontext = libnet_init(LIBNET_RAW4, device, neterr); + if (!netcontext){ + fprintf(stderr,neterr); + exit(1); + } + libnet_clear_packet(netcontext); + if (!ip_src_str) + { + ip_src = libnet_get_ipaddr4(netcontext); + ip_src_str = libnet_addr2name4(ip_src, LIBNET_DONT_RESOLVE); + } + + printf("done\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); + exit(0); + + return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS); +} + + +void usage(char *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++; + } +} + + +// vim: ts=4 sts=4 sw=4 et