sendip-2.5/0040775000076400007640000000000007711504771011325 5ustar mikemikesendip-2.5/CHANGES0100644000076400007640000001267107711152636012321 0ustar mikemikeChanges between sendip-0.0.1 and sendip-0.0.2 * Now compiles under libc5 as well as glibc Changes between sendip-0.0.2 and sendip-0.0.3 * New man page, taken from one supplied by rmartini Changes between sendip-0.0.3 and sendip-1.0 * Makefile no longer requires GNU make or etags * included spec file from Delvin Upton * now ship source and binary RPMs as well as source tar.gz * now compiles on FreeBSD (and hopefully Net and Open) as well as linux * minor bug fixes * added option for random header fields (idea roughly by ganesh@earth.li) * switched to 2digit versions Changes between sendip-1.0 and sendip-1.1 * Fix bug the caused incorrect tcp checksums (smitchell@realogy.com) * Add RIP-1 and RIP-2 support from Richard Polton Changes between sendip-1.1 and sendip-1.2 * Add IPv6 support from Antti Tuominen * Add (some) TCP options form Alexander Talos * Bugfixes Changes between sendip-1.2 and sendip-1.3 * Compile fix for *BSD * Various other bugfixes * Removed bogus libpcap dependancy * Now included in debian unstable, hopefully * Ready to be included in FreeBSD ports collection, hopefully * Added -h option Changes between sendip-1.3 and sendip-1.4 * Added contrib directory and wake on lan script, curtesy of Beat Bolli * RIP default option from Richard Polton Changes between sendip-1.4 and sendip-2.0-pre2 * RIP bugfix from Richard Polton * Massive code tidy up * -tr no longer affects -tfe and -tfc * TCP header length defaults to correct even if options are supplied * Setting IP checksum prints a warning as it might not work * Can now specify the version field of the IP header * -if now documented correctly * man page autobuilds from help, help is more likely to be right * TCP over IPV6 still sends the wrong checksum, but now it warns you first * Enable setting of IPV6 priority * ICMP and ICMPv6 merged as they are almost identical * RIP no longer only accepts 25 entries * BGP support from David Ball Changes between sendip-2.0-pre2 and sendip-2.0 * include string.h to avoid memcpy(), strlen() and strcpy() warnings in ipv4.c, ipv6.c, rip.c and udp.c (Antti Tuominen ) * ipv6 checksum fixes (Antti Tuominen) * BGP fixes (David Ball ) * Compiles on AIX (thanks to Parag Kukde ) * -d now supports hex, octal or binary data * man page (built automagically from hacked help2man) * finds modules correctly after a make install Changes between sendip-2.0 and sendip-2.1 * Now FHS aware (Juan Antonio Martinez ) * NTP support added (requested by John Deatherage ) * Merged ipv6_csum and icmp6csum * Use (s)random() instead of (s)rand() (Bryan Croft ) * Added -fPIC to CFLAGS to make it compile on hppa * Now compiles on Solaris (thanks to Dax Kelson ) - tidied up the build for platform specific LDFLAGS - turned off profiling - renamed our copy of getopt to gnugetopt - created types.h with bool, u_int*_t (solaris only), and endianness stuff * sendip: - searches for libraries in . as well as installed path - man page fix (pointed out by Ambar Paul ) * tcp.so: - now supports -tonum to specify arbitrary TCP options * ipv4.so: - supports (some) IP options requested by Fabrice MARIE - only checks a single layer of enclosing headers for IPV4 * bgp.so: - non-enclosure in TCP is non-fatal - doesn't segfault on platforms where static variables and .so files don't mix * rip.so: - only checks a single layer of enclosing headers for UDP * icmp.so: - only checks a single layer of enclosing headers for IPV4/IPV6 - now compiles on platforms which care about alignment Changes between sendip-2.1 and sendip-2.2 * spec file fixes (Calum Selkirk ) * FreeBSD compile fixes * Linux-PPC compile fixes * More SunOS compile fixes * Use ?= not = in Makefile to allow FreeBSD ports to work without a hack (Joseph Scott ) * Added support for RIPng over UDP/IPv6. Completely untested, I haven't even read the spec... Requested by armite * CheckSum code tidied up * tcp.so: - now supports sending TCP over IPv6 - tcp length correctly calculated (pointed out by Yuchung Cheng ) * udp.so: - now supports sending UDP over IPv6 - only checks a single layer of enclosing headers for IP * ipv6.so: - now correctly sets src and dst fields (Pekka Savola ) * ipv4.so: - ip_len now in host byte order on FreeBSD to avoid sendto: Invalid argument * rip.so: - off-by-one error causing segfaults and other badness fixed - hton* added where needed Changes between sendip-2.2 and sendip-2.3 * Now compiles on archs requiring alignment * ripng.so: - now conforms more closely to the spec (help from armite Changes between sendip-2.3 and sendip-2.4 * Random packet data payloads (Anand (Andy) Rao ) * ipv4.so: - fix bug with iossr and iolsr adding wrong ip options - ip_len really is now in host byte order on FreeBSD, so the sendto: Invalid argument thing really is fixed now. I hope. (brdraney@nersc.gov) Changes between sendip-2.4 and sendip-2.5 * Fix minor memory leaks in several places (found using valgrind) * Fix compile bug on Solaris (found by Dave Gibelli ) * tcp.so - Fix -tonum bug found by Yaniv Kaul sendip-2.5/LICENSE0100600000076400007640000003663507377506173012340 0ustar mikemikeGNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: * a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. * b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. * c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: * a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, * b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, * c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contrribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. sendip-2.5/Makefile0100664000076400007640000000364207552055640012766 0ustar mikemike#configureable stuff PREFIX ?= /usr/local BINDIR ?= $(PREFIX)/bin MANDIR ?= $(PREFIX)/share/man/man1 LIBDIR ?= $(PREFIX)/lib/sendip #For most systems, this works INSTALL ?= install #For Solaris, you may need #INSTALL=/usr/ucb/install CFLAGS= -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings \ -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align \ -DSENDIP_LIBS=\"$(LIBDIR)\" #-Wcast-align causes problems on solaris, but not serious ones LDFLAGS= -g -rdynamic -lm #LDFLAGS_SOLARIS= -g -lsocket -lnsl -lm LDFLAGS_SOLARIS= -g -lsocket -lnsl -lm -ldl LDFLAGS_LINUX= -g -rdynamic -ldl -lm LIBCFLAGS= -shared CC= gcc PROGS= sendip BASEPROTOS= ipv4.so ipv6.so IPPROTOS= icmp.so tcp.so udp.so UDPPROTOS= rip.so ripng.so ntp.so TCPPROTOS= bgp.so PROTOS= $(BASEPROTOS) $(IPPROTOS) $(UDPPROTOS) $(TCPPROTOS) GLOBALOBJS= csum.o compact.o all: $(GLOBALOBJS) sendip $(PROTOS) sendip.1 sendip.spec #there has to be a nice way to do this sendip: sendip.o gnugetopt.o gnugetopt1.o compact.o sh -c "if [ `uname` = Linux ] ; then \ $(CC) -o $@ $(LDFLAGS_LINUX) $(CFLAGS) $+ ; \ elif [ `uname` = SunOS ] ; then \ $(CC) -o $@ $(LDFLAGS_SOLARIS) $(CFLAGS) $+ ;\ else \ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $+ ; \ fi" sendip.1: ./help2man $(PROGS) $(PROTOS) VERSION ./help2man -n "Send arbitrary IP packets" -N >sendip.1 sendip.spec: sendip.spec.in VERSION echo -n '%define ver ' >sendip.spec cat VERSION >>sendip.spec cat sendip.spec.in >>sendip.spec %.so: %.c $(GLOBALOBJS) $(CC) -o $@ $(CFLAGS) $(LIBCFLAGS) $+ .PHONY: clean install clean: rm -f *.o *~ *.so $(PROTOS) $(PROGS) core gmon.out veryclean: make clean rm -f sendip.spec sendip.1 install: all [ -d $(LIBDIR) ] || mkdir -p $(LIBDIR) [ -d $(BINDIR) ] || mkdir -p $(BINDIR) [ -d $(MANDIR) ] || mkdir -p $(MANDIR) $(INSTALL) -m 755 $(PROGS) $(BINDIR) $(INSTALL) -m 644 sendip.1 $(MANDIR) $(INSTALL) -m 755 $(PROTOS) $(LIBDIR) sendip-2.5/README0100644000076400007640000001137607707506300012203 0ustar mikemikeSendIP Author: Mike Ricketts Web: http://www.earth.li/projectpurple/progs/sendip.html Part of Project Purple. (http://www.earth.li/projectpurple/) 1. Introduction SendIP is a tool to send completely arbitrary packets out over the network. In conjunction with PackPrint (see http://www.earth.li/projectpurple/progs/packprint.html), this makes an extremely powerful debugging tool for networks. 1.1 Home page All the latest news, documentation and versions of SendIP will be made available from http://www.earth.li/projectpurple/ or directly from the the author. Please, if you find SendIP useful, consider visiting making a donation at http://heaven.on.earth.li/donate. The more donations I get the more time I can afford to spend improving SendIP! 2. Protocols Here is a list of protocols that SendIP currently understands: * IPv4 (but see below section 7) * TCP * BGP * ICMP * UDP * RIP * NTP * IPv6 (except on solaris) * ICMPv6 * TCP * UDP * RIPng * NTP? Other protocols will be added in future versions, as and when I have time to add them. Of course, it is still possible to send packets using other protocols, but you have to construct the packet data and headers entirely by hand. 3. Usage instructions SendIP can take a huge number of commandline parameters. For this reason, future versions may have some sort of user interface... Please read the man page or sendip -h for details. They are not documented here because they change often between versions and I can't be bothered to keep this up to date. 4. Installation make ; make install should work. You MUST use GNU make. On Solaris you need to use gcc-3.x or above, and GNU binutils. On other platforms, you probably need gcc-2.x or above. If you have install problems on Solaris, try: make install INSTALL=/usr/ucb/install If you can't persuade it to compile or install, mail me with details of what goes wrong, and what system you are trying to install it on. By this I mean at least: - output of make -k veryclean all install - OS, including version - version of make, gcc, etc - version of sendip - anything else you think might be relevant You can change where it installs by changing BINDIR and/or PREFIX at the top of the Makefile. A .spec file is included to build RPMS, and source and binary RPMS are also available from the web page. Debian packages are also available, and sendip is included in the FreeBSD ports collection. 5. Problems, Bugs, and Comments If you have any comments, suggestions, or bug reports, please email me. Please, when sending bug reports include all the relevant information so I have a hope of reproducing or fixing the bug. I need at least: - output of make -k veryclean all install (if you installed from source) - OS, including version and platform - glibc version if you are on linux - sendip version - exact command line that fails - exact error messages, if any - exactly what you expected to happen that didn't, or what didn't happen that you expected - anything else that might be relevant Make sure you have read section 7 of this README first. The email address I currently use is mike@earth.li I am interested in any feedback in order to improve SendIP. 6. License SendIP is distributed under the GNU Public License a copy of which is included in this archive as LICENSE. 7. Note on IPv4 options Many operating systems rewrite some or all of the IP header when sending packets. Exactly which headers get rewritten depends on the OS. There is no portable way to bypass this that I am aware of. so some IP options do not work on some operating systems. Listed below are the ones I know about. This list is not by any means complete and what is here may not be accurate, and I would welcome more information. Linux, *BSD: - IP source address is rewritten if it is zero. - IP checksum is always rewritten to the correct value. - IP packet ID is rewritten (to a randomish value) if it is zero. - Total packet length is always rewritten to the number of bytes sent. - All other headers work as expected. Solaris: - IP source address is rewritten if it is zero. - IP header length works provided that the length given is not greater than the number of bytes in the packet. If it is, sendip will segfault. - IP don't fragment flag always set, other IP flags always cleared. - IP checksum is always rewritten to the correct value. - IP packet ID is rewritten (to a randomish value) if it is zero. - Total packet length is always rewritten to the number of bytes sent. - All other headers work as expected. sendip-2.5/TODO0100664000076400007640000000124307650770453012016 0ustar mikemikeMAIN: Try using PF_PACKET (so ip works with wrong checksums) ipv4.c: __FreeBSD hack needed on solaris too? ipv4.h: __FreeBSD hack needed for fragment offset rip.c: handling of -re is sick ripng.c: handling of -re is sick, check conformance to spec ALL - DNS - RSVP (satish chandodi ) - OSPF and OSPF6 (armite ) - ARP (suggested by Christian Schmid ) - IPX (if I can find the spec) - bugfixes - ncurses and/or X interface - allow comments in packet data files - script to automatically frag packets (John Deatherage ) - XML data files? (Antti Tuominen ) sendip-2.5/VERSION0100664000076400007640000000000407651056262012364 0ustar mikemike2.5 sendip-2.5/bgp.c0100664000076400007640000003413007570212051012225 0ustar mikemike/*---------------------------------------------------------------------------- * bgp.c - bgp module for SendIP * * Copyright (C) David Ball for Project Purple, August 2001 *---------------------------------------------------------------------------- */ #include #include #include #include #include #include "sendip_module.h" /* * Roughly stolen from arpa/nameser.h */ #define GETSHORT(ptr) (ntohs( \ ((u_int16_t)((u_int8_t *)(ptr))[0] << 8) | \ ((u_int16_t)((u_int8_t *)(ptr))[1]) \ )) #define GETLONG(ptr) (ntohl( \ ((u_int32_t)((u_int8_t *)(ptr))[0] << 24) | \ ((u_int32_t)((u_int8_t *)(ptr))[1] << 16) | \ ((u_int32_t)((u_int8_t *)(ptr))[2] << 8) | \ ((u_int32_t)((u_int8_t *)(ptr))[3]) \ )) #define PUTSHORT(ptr, s) { \ u_int16_t v = htons((u_int16_t)(s)); \ *((u_int8_t *)(ptr)) = v >> 8; \ *(((u_int8_t *)(ptr)) + 1) = v; \ } #define PUTLONG(ptr, l) { \ u_int32_t v = htonl((u_int32_t)(l)); \ *((u_int8_t *)(ptr)) = v >> 24; \ *(((u_int8_t *)(ptr)) + 1) = v >> 16; \ *(((u_int8_t *)(ptr)) + 2) = v >> 8; \ *(((u_int8_t *)(ptr)) + 3) = v; \ } /* * Defines for which parts have been modified */ const u_int32_t BGP_MOD_LENGTH = 0x00000001; const u_int32_t BGP_MOD_OPT_LEN = 0x00000002; const u_int32_t BGP_MOD_WDR_LEN = 0x00000004; const u_int32_t BGP_MOD_ATTR_LEN = 0x00000008; /* * Parts of BGP messages */ typedef enum { BGP_HEADER, BGP_OPEN, BGP_OPEN_OPT, BGP_UPDATE_WDR_LEN, BGP_UPDATE_WDR, BGP_UPDATE_ATTR_LEN, BGP_UPDATE_ATTR, BGP_UPDATE_NLRI, BGP_NOTFN } bgp_msg_part; /* * Options */ sendip_option bgp_opts[] = { { "m", TRUE, "BGP Marker field (format is ::...)", "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF" }, { "l", TRUE, "Packet length", "Correct" }, { "t", TRUE, "Message Type (1 OPEN, 2 UPDATE, 3 NOTIFICATION, 4 " "KEEPALIVE", "4 (KEEPALIVE)" }, { "o", TRUE, "Open message. Format is ::" "::", "4:1:90:127.0.0.1:Correct (Any parameter can be omitted to get " "the default)" }, { "oo", TRUE, "Optional OPEN parameter. Format is ::" " - value is in hex bytes separated by :s", "Length may be omitted to get correct value" }, { "ul", TRUE, "Withdrawn routes length", "Correct" }, { "uw", TRUE, "Withdrawn route. Format is x.x.x.x/n:", "Bytes field may be omitted to use the correct number" }, { "us", TRUE, "Attributes length", "Correct" }, { "ua", TRUE, "Attribute. Format is ::" ":", "The length fields may be omitted to use the correct value" }, { "un", TRUE, "NLRI Prefix. Format is as for -buw", "As for -buw" }, { "n", TRUE, "Notification. Format is ::", "Data may be omitted for no data" }, }; /* * Option char */ const char bgp_opt_char = 'b'; /* * Gaping buffer overrun - make sure this is long enough :) */ const u_int32_t BGP_BUFLEN = 1400; /*static*/ bgp_msg_part bgp_prev_part; /*static*/ u_int8_t *bgp_len_ptr = NULL; /*static*/ u_int8_t *bgp_opt_len_ptr = NULL; /*static*/ u_int8_t *bgp_wdr_len_ptr = NULL; /*static*/ u_int8_t *bgp_attr_len_ptr = NULL; sendip_data *initialize (void) { sendip_data *data = NULL; u_int8_t *ptr; data = malloc(sizeof(sendip_data)); if (data != NULL) { memset(data, 0, sizeof(sendip_data)); data->data = malloc(BGP_BUFLEN); if (data->data == NULL) { free(data); data = NULL; } } if (data != NULL) { memset(data->data, 0, BGP_BUFLEN); ptr = data->data; memset(data->data, 0xFF, 16); ptr += 16; bgp_len_ptr = ptr; PUTSHORT(ptr, 19); ptr += 2; *ptr++ = 4; data->alloc_len = ptr - (u_int8_t *)data->data; bgp_prev_part = BGP_HEADER; } return (data); } static u_int32_t bgp_parse_bytes (u_int8_t *buf, char *arg, char **new_arg, u_int32_t limit, int base, char stopc) { u_int8_t *ptr = buf; char *arg_ptr = arg; while (*arg_ptr != '\0' && *arg_ptr != stopc && limit > 0) { *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, base); if (*arg_ptr != '\0' && *arg_ptr != stopc) { arg_ptr++; } limit--; } if (new_arg != NULL) { *new_arg = arg_ptr; } return (ptr - buf); } static u_int32_t bgp_parse_nlri (u_int8_t *buf, char *arg) { u_int8_t *ptr = buf; char *arg_ptr = arg; char *new_arg_ptr; u_int8_t bytes; ptr++; (void)bgp_parse_bytes(ptr, arg_ptr, &arg_ptr, 4, 10, '\0'); *buf = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); if (*arg_ptr != '\0') { arg_ptr++; } bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); if (arg_ptr != new_arg_ptr) { ptr += bytes; } else if (*buf > 0) { ptr += ((*buf - 1) >> 3) + 1; } return (ptr - buf); } bool do_opt (char *optstring, char *optarg, sendip_data *pack) { u_int8_t *ptr = (u_int8_t *)pack->data + pack->alloc_len; u_int8_t *rem_ptr = NULL; char *arg_ptr = NULL; char *new_arg_ptr = NULL; bool rc = TRUE; bool len_mod = FALSE; u_int8_t bytes; switch (optstring[1]) { case 'm': rem_ptr = (u_int8_t *)pack->data; (void)bgp_parse_bytes(rem_ptr, optarg, NULL, 16, 16, '\0'); break; case 'l': rem_ptr = (u_int8_t *)pack->data + 16; PUTSHORT(rem_ptr, (u_int16_t)strtoul(optarg, NULL, 10)); pack->modified |= BGP_MOD_LENGTH; break; case 't': rem_ptr = (u_int8_t *)pack->data + 18; *rem_ptr = (u_int8_t)strtoul(optarg, NULL, 0); break; case 'o': switch (optstring[2]) { case '\0': if (bgp_prev_part != BGP_HEADER) { usage_error("Open message must come immediately " "after header\n"); rc = FALSE; } else { arg_ptr = optarg; *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); if (arg_ptr == new_arg_ptr) { *ptr = 4; } ptr++; arg_ptr = new_arg_ptr; if (*arg_ptr != '\0') { arg_ptr++; } PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10)); if (arg_ptr == new_arg_ptr) { PUTSHORT(ptr, 1); } ptr += 2; arg_ptr = new_arg_ptr; if (*arg_ptr != '\0') { arg_ptr++; } PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10)); if (arg_ptr == new_arg_ptr) { PUTSHORT(ptr, 90); } ptr += 2; arg_ptr = new_arg_ptr; if (*arg_ptr != '\0') { arg_ptr++; } (void)bgp_parse_bytes(ptr, arg_ptr, &new_arg_ptr, 4, 10, ':'); if (arg_ptr == new_arg_ptr) { PUTLONG(ptr, 0x7F000001); } ptr += 4; arg_ptr = new_arg_ptr; if (*arg_ptr != '\0') { arg_ptr++; } *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); if (arg_ptr == new_arg_ptr) { *ptr = 0; } else { pack->modified |= BGP_MOD_OPT_LEN; } bgp_opt_len_ptr = ptr; ptr++; bgp_prev_part = BGP_OPEN; } break; case 'o': if (bgp_prev_part != BGP_OPEN && bgp_prev_part != BGP_OPEN_OPT) { usage_error("Open options must occur after open " "message\n"); rc = FALSE; } else { rem_ptr = ptr; arg_ptr = optarg; *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); if (*arg_ptr != '\0') { arg_ptr++; } *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); if (arg_ptr == new_arg_ptr) { *ptr = 0; } else { len_mod = TRUE; } ptr++; arg_ptr = new_arg_ptr; if (*arg_ptr != '\0') { arg_ptr++; } ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0'); if (!len_mod) { *(rem_ptr + 1) = ptr - rem_ptr; } if (!(pack->modified & BGP_MOD_OPT_LEN)) { *bgp_opt_len_ptr += ptr - rem_ptr; } bgp_prev_part = BGP_OPEN_OPT; } break; default: fprintf(stderr, "Unrecognised BGP OPEN option: %s\n", optstring); rc = FALSE; } break; case 'u': switch(optstring[2]) { case 'l': if (bgp_prev_part != BGP_HEADER) { usage_error("Update message must come immediately " "after header\n"); rc = FALSE; } else { bgp_wdr_len_ptr = ptr; PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10)); ptr += 2; pack->modified |= BGP_MOD_WDR_LEN; bgp_prev_part = BGP_UPDATE_WDR_LEN; } break; case 'w': if (bgp_prev_part == BGP_HEADER) { bgp_wdr_len_ptr = ptr; PUTSHORT(ptr, 0); ptr += 2; bgp_prev_part = BGP_UPDATE_WDR_LEN; } if (bgp_prev_part != BGP_UPDATE_WDR && bgp_prev_part != BGP_UPDATE_WDR_LEN) { usage_error("Unfeasible routes must occur immediately " "after header or -bul\n"); rc = FALSE; } else { rem_ptr = ptr; ptr += bgp_parse_nlri(ptr, optarg); if (!(pack->modified & BGP_MOD_WDR_LEN)) { PUTSHORT(bgp_wdr_len_ptr, GETSHORT(bgp_wdr_len_ptr) + ptr - rem_ptr); } bgp_prev_part = BGP_UPDATE_WDR; } break; case 's': if (bgp_prev_part == BGP_HEADER) { bgp_wdr_len_ptr = ptr; PUTSHORT(ptr, 0); ptr += 2; bgp_prev_part = BGP_UPDATE_WDR_LEN; } if (bgp_prev_part != BGP_UPDATE_WDR_LEN && bgp_prev_part != BGP_UPDATE_WDR) { usage_error("Path Attributes must come after " "unfeasible routes (if any), " "or after header\n"); rc = FALSE; } else { bgp_attr_len_ptr = ptr; PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10)); ptr += 2; pack->modified |= BGP_MOD_ATTR_LEN; bgp_prev_part = BGP_UPDATE_ATTR_LEN; } break; case 'a': if (bgp_prev_part == BGP_HEADER) { bgp_wdr_len_ptr = ptr; PUTSHORT(ptr, 0); ptr += 2; bgp_prev_part = BGP_UPDATE_WDR_LEN; } if (bgp_prev_part == BGP_UPDATE_WDR_LEN || bgp_prev_part == BGP_UPDATE_WDR) { bgp_attr_len_ptr = ptr; PUTSHORT(ptr, 0); ptr += 2; bgp_prev_part = BGP_UPDATE_ATTR_LEN; } if (bgp_prev_part != BGP_UPDATE_ATTR_LEN && bgp_prev_part != BGP_UPDATE_ATTR) { usage_error("Path Attributes must come after " "unfeasible routes (if any), " "or after header\n"); rc = FALSE; } else { rem_ptr = ptr; arg_ptr = optarg; *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 16); if (*arg_ptr != '\0') { arg_ptr++; } *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); if (*arg_ptr != '\0') { arg_ptr++; } bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); if (arg_ptr != new_arg_ptr) { if (bytes <= 1) { bytes = 1; } else { bytes = 2; } } else { if (*rem_ptr & 0x10) { bytes = 2; } else { bytes = 1; } } arg_ptr = new_arg_ptr; if (*arg_ptr != '\0') { arg_ptr++; } if (bytes == 1) { *ptr++ = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); } else { PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10)); ptr += 2; } if (arg_ptr != new_arg_ptr) { len_mod = TRUE; } arg_ptr = new_arg_ptr; if (*arg_ptr != '\0') { arg_ptr++; } if (bytes == 1) { ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0'); } else { ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16, '\0'); } if (!len_mod) { if (bytes == 1) { *(rem_ptr + 2) = ptr - rem_ptr - 3; } else { PUTSHORT(rem_ptr + 2, ptr - rem_ptr - 4); } } if (!(pack->modified & BGP_MOD_ATTR_LEN)) { PUTSHORT(bgp_attr_len_ptr, GETSHORT(bgp_attr_len_ptr) + ptr - rem_ptr); } bgp_prev_part = BGP_UPDATE_ATTR; } break; case 'n': if (bgp_prev_part == BGP_HEADER) { bgp_wdr_len_ptr = ptr; PUTSHORT(ptr, 0); ptr += 2; bgp_prev_part = BGP_UPDATE_WDR_LEN; } if (bgp_prev_part == BGP_UPDATE_WDR_LEN || bgp_prev_part == BGP_UPDATE_WDR) { bgp_attr_len_ptr = ptr; PUTSHORT(ptr, 0); ptr += 2; bgp_prev_part = BGP_UPDATE_ATTR_LEN; } if (bgp_prev_part != BGP_UPDATE_ATTR_LEN && bgp_prev_part != BGP_UPDATE_ATTR && bgp_prev_part != BGP_UPDATE_NLRI) { usage_error("NLRI must come after Unfeasible routes and " "attributes, if any, or after header\n"); rc = FALSE; } else { rem_ptr = ptr; ptr += bgp_parse_nlri(ptr, optarg); bgp_prev_part = BGP_UPDATE_NLRI; } break; default: fprintf(stderr, "Unrecognised BGP UPDATE option: %s\n", optstring); rc = FALSE; } break; case 'n': if (bgp_prev_part != BGP_HEADER) { usage_error("Notification must come immediately after header\n"); rc = FALSE; } else { arg_ptr = optarg; *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); if (*arg_ptr != '\0') { arg_ptr++; } *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); if (*arg_ptr != '\0') { arg_ptr++; } ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16, '\0'); bgp_prev_part = BGP_NOTFN; } break; default: fprintf(stderr, "Unrecognised BGP option: %s", optstring); rc = FALSE; } if (rc) { pack->alloc_len = ptr - (u_int8_t *)pack->data; if (!(pack->modified & BGP_MOD_LENGTH)) { PUTSHORT(bgp_len_ptr, pack->alloc_len); } } return (rc); } bool finalize (char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { if (hdrs[strlen(hdrs) - 1] != 't') { usage_error("WARNING: BGP should be carried over TCP\n"); } return TRUE; } int num_opts (void) { return (sizeof(bgp_opts)/sizeof(sendip_option)); } sendip_option *get_opts (void) { return (bgp_opts); } char get_optchar (void) { return (bgp_opt_char); } sendip-2.5/compact.c0100664000076400007640000000301307403242004013073 0ustar mikemike/* compact.c - function to convert hex/octal/decimal/raw string to raw * ChangeLog since initial release in sendip 2.1. */ #include #include int compact_string(char *data_out) { char *data_in = data_out; int i=0; if(*data_in=='0') { data_in++; if(*data_in=='x' || *data_in=='X') { /* Hex */ char c='\0'; data_in++; while(*data_in) { if(*data_in>='0' && *data_in<='9') { c+=*data_in-'0'; } else if(*data_in>='A' && *data_in<='F') { c+=*data_in-'A'+10; } else if(*data_in>='a' && *data_in<='f') { c+=*data_in-'a'+10; } else { fprintf(stderr,"Character %c invalid in hex data stream\n", *data_in); return 0; } if( i&1) { *(data_out++)=c; // odd nibble - output it c='\0'; } else { c<<=4; // even nibble - shift to top of byte } data_in++; i++; } *data_out=c; // make sure last nibble is added i++; i>>=1; // i was a nibble count... return i; } else { /* Octal */ char c='\0'; while(*data_in) { if(*data_in>='0' && *data_in<='7') { c+=*data_in-'0'; } else { fprintf(stderr,"Character %c invalid in octal data stream\n", *data_in); return 0; } if( (i&3) == 3 ) { *(data_out++)=c; // output every 4th char c='\0'; } else { // otherwise just shift it up c<<=2; } data_in++; i++; } *data_out=c; // add partial last byte i+=3; i>>=2; return i; } } else { /* String */ return strlen(data_in); } } sendip-2.5/contrib/0040775000076400007640000000000007650202076012760 5ustar mikemikesendip-2.5/contrib/gmon.out0100664000076400007640000001271707600152234014451 0ustar mikemikegmon> dsecondss@D@ȱ@|@@`@̵0(tX@th~@DȮ@~@T@$@4@`ЩڦҨ`Ҩsendip-2.5/contrib/wake.sh0100755000076400007640000000221007377506173014247 0ustar mikemike#! /bin/sh # Usage: wake [] # # can be a host name or a dotted-quad IP address. # If the is not given, it is taken from ethers(5). # For this to work, if you give a host name as first argument, ethers # has to contain host names (as opposed to IP addresses). # # Unless you have it already, you can build your ethers file like this: # # nmap -sP -PI 192.168.1.0/24 # prepare ARP cache with a ping-sweep # arp -a | awk '$5 == "[ether]" { printf("%s\t%s\n", $4, $1); }' \ # | sort >>/etc/ethers # # The 'magic packet' consists of 6 times 0xFF followed by 16 times # the hardware address of the NIC. This sequence can be encapsulated # in any kind of packet; I chose UDP to the discard port (9). if [ $# = 1 ]; then ETHER=`awk "/$1/"' { gsub(":", "", $1); print $1; exit; }' /etc/ethers` if [ -z $ETHER ]; then echo "$0: host $1 is not in /etc/ethers" >&2 exit 1 fi ETHER=`echo $ETHER | sed 's/://g'` else ETHER=$2 fi ETHER="${ETHER}${ETHER}${ETHER}${ETHER}" # 4 x MAC ETHER="FFFFFFFFFFFF${ETHER}${ETHER}${ETHER}${ETHER}" # Preamble + 16 x MAC sendip $1 -p ipv4 -p udp.so -ud 9 -d 0x"$ETHER" sendip-2.5/csum.c0100644000076400007640000000155307423364017012434 0ustar mikemike/* csum.c * Computes the standard internet checksum of a set of data (from RFC1071) * ChangeLog since sendip 2.0: * 02/12/2001: Moved ipv6_csum into icmp.c as that is where it is used * 22/01/2002: Include types.h to make sure u_int*_t defined on Solaris */ #define __USE_BSD /* GLIBC */ #define _BSD_SOURCE /* LIBC5 */ #include #include #include #include #include #include "types.h" u_int16_t csum (u_int16_t *packet, int packlen); /* Checksum a block of data */ u_int16_t csum (u_int16_t *packet, int packlen) { register unsigned long sum = 0; while (packlen > 1) { sum+= *(packet++); packlen-=2; } if (packlen > 0) sum += *(unsigned char *)packet; /* TODO: this depends on byte order */ while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); return (u_int16_t) ~sum; } sendip-2.5/dummy.c0100664000076400007640000001346407573203526012631 0ustar mikemike/* dummy.c - example sendip module * Author: Mike Ricketts * ChangeLog since 2.0 release: * 02/12/2001: added num_opts, get_opts and get_optchar functions * 02/12/2001: added more helpful comments */ /* To write a new sendip module: * * mail mike@earth.li to check that nobody else is already working on the * same thing. * * copy dummy.c and dummy.h * * replace dummy with the name of your module throughout * * In .h: * - fill in the struct foo_header with all the header fields in your * module's packet. If the packet is a variable length, only put the * common bits here and use additional structs for other bits, if needed. * Be very careful about introducing byteorder dependencies. See ntp.h * for a simple case of how to do it. In general, things smaller than * 16 bits are problematic, use the __BYTE_ORDER macro and test against * __LITTLE_ENDIAN, __BIG_ENDIAN. Always have a #else catchall with a * #error in, just in case. * Every field should be a u_int*_t or an int*_t to avoid things being * differnt lengths from you expect. Use these rather than equivalent * ones as these will exist everywhere that sendip compiles. * - create a list of #defines FOO_MOD_*, one for each header field that * may be modified. The first should have value 1, the rest should be * 1<.c: * - remove this essay (you can still read it in dummy.c!) * - change the top comment in the obvious way * - find an option character not used elsewhere and replace opt_char with * that. You can see what is used by doing * grep '^const char opt_char' *.c * in the sendip source directory. * - in the do_opt function, fill in code for all the options you defined in * the header file. Typically, the code will look a lot like: * case 'option': * header->thing = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); * pack->modified |= FOO_MOD_THING; * break; * If some of your options change the length of the packet, you might want * to take a look in ipv4.c or tcp.c - specifically where they add IPV4 or * TCP options. * Make sure you use htons and htonl everywhere you need to to avoid * byteorder problems. * -opt contains the option string, including the starting opt_char * -arg contains any argument given * -pack contains our headers * - in the finalize function, fill in anything that needs to be computed * after all the optoins are processed. This function MUST NOT change * the length or location of the headers in memory, else bad things will * happen. Typical things that go in here are filling in the length * field of the header if it hasn't been overriden, computing checksums, * etc. You may also which to check that your packet is enclosed in a * sensible carrier. tcp.c does all of the things. * -hdrs is build by taking the opt_char for each packet in turn from the * outside in, up to but not including this packet * -headers is an array of all the enclosing headers in the same order * -data contains the data inside this set of headers. This may include * headers of underlying protocols, that will already have been * finalized. DO NOT MODIFY IT. * -pack contains our headers. * - You might, possibly, find the following functions useful. They are * automatically available to all modules: * -int compact_string(char *string); * For strings starting 0x or 0X, converts each pair of bytes thereafter * to a single byte of that hex value. For other strings starting 0, * converts sets of 3 bytes to a single byte of that octal value. For * all other strings, does nothing. Returns the length of the final * string. This is recomended when parsing arbitrary data (like the -d * option of sendip, -tonum for arbitrary TCP options) * -u_int16_t csum(u_int16_t *data, int len) * returns the standard internet checksum of the packet * - If something doesn't work as expected, or you can't figure out how to * do sometihng, mail mike@earth.li and ask. * * In the Makefile add .so to the PROTOS line * * Test it * * Mail it to mike@earth.li, either as a patch or just send the .c and .h * files you created */ #include #include #include "sendip_module.h" #include "dummy.h" /* Character that identifies our options */ const char opt_char='dummy'; sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); dummy_header *dummy = malloc(sizeof(dummy_header)); memset(dummy,0,sizeof(dummy_header)); ret->alloc_len = sizeof(dummy_header); ret->data = dummy; ret->modified=0; return ret; } bool do_opt(char *opt, char *arg, sendip_data *pack) { dummy_header *dummy = (dummy_header *)pack->data; switch(opt[1]) { //... } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { //... return TRUE; } int num_opts() { return sizeof(dummy_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return dummy_opts; } char get_optchar() { return opt_char; } sendip-2.5/dummy.h0100664000076400007640000000055307402504502012616 0ustar mikemike/* dummy.h * see dummy.c for more information */ #ifndef _SENDIP_dummy_H #define _SENDIP_dummy_H #error "Don't include this, dumbass" /* dummy HEADER */ typedef struct { //... } dummy_header; /* Defines for which parts have been modified */ #define dummy_MOD_* 1<<* /* Options */ sendip_option dummy_opts[] = { //... }; #endif /* _SENDIP_dummy_H */ sendip-2.5/gnugetopt.c0100664000076400007640000007100307423371032013473 0ustar mikemike/* Getopt.c ripped straight out of glibc with some very minor modifications Use this getopt not a system dependant one, as sendip is rather sensitive to precise getopt behaviour. */ /* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ /* #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif */ #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if defined HAVE_LIBINTL_H || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "gnugetopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *gnuoptarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `gnuoptind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int gnuoptind = 1; /* Formerly, initialization of getopt depended on gnuoptind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ /* MODIFIED THIS LINE so that sendip can force skipping options */ char *nextchar = NULL; /* Callers store zero here to inhibit the error message for unrecognized options. */ int gnuopterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int gnuoptopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `gnuoptind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ static char * my_index (const char *str, int chr) { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void __attribute__ ((unused)) store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } # ifdef text_set_element text_set_element (__libc_subinit, store_args_and_env); # endif /* text_set_element */ # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,gnuoptind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = gnuoptind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (gnuoptind - last_nonopt); last_nonopt = gnuoptind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = gnuoptind; nextchar = NULL; /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else ordering = PERMUTE; #ifdef _LIBC if ( argc == original_argc && argv == original_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `gnuoptind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `gnuoptind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `gnuopterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `gnuoptarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `gnuoptarg', otherwise `gnuoptarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only) { int print_errors = gnuopterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; gnuoptarg = NULL; if (gnuoptind == 0 || !__getopt_initialized) { if (gnuoptind == 0) gnuoptind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[gnuoptind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #ifdef _LIBC # define NONOPTION_P (argv[gnuoptind][0] != '-' || argv[gnuoptind][1] == '\0' \ || (gnuoptind < nonoption_flags_len \ && __getopt_nonoption_flags[gnuoptind] == '1')) #else # define NONOPTION_P (argv[gnuoptind][0] != '-' || argv[gnuoptind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if GNUOPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > gnuoptind) last_nonopt = gnuoptind; if (first_nonopt > gnuoptind) first_nonopt = gnuoptind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != gnuoptind) exchange ((char **) argv); else if (last_nonopt != gnuoptind) first_nonopt = gnuoptind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (gnuoptind < argc && NONOPTION_P) gnuoptind++; last_nonopt = gnuoptind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (gnuoptind != argc && !strcmp (argv[gnuoptind], "--")) { gnuoptind++; if (first_nonopt != last_nonopt && last_nonopt != gnuoptind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = gnuoptind; last_nonopt = argc; gnuoptind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (gnuoptind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) gnuoptind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; gnuoptarg = argv[gnuoptind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[gnuoptind] + 1 + (longopts != NULL && argv[gnuoptind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[gnuoptind][1] == '-' || (long_only && (argv[gnuoptind][2] || !my_index (optstring, argv[gnuoptind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[gnuoptind]); nextchar += strlen (nextchar); gnuoptind++; gnuoptopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; gnuoptind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) gnuoptarg = nameend + 1; else { if (print_errors) { if (argv[gnuoptind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[gnuoptind - 1][0], pfound->name); } nextchar += strlen (nextchar); gnuoptopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (gnuoptind < argc) gnuoptarg = argv[gnuoptind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[gnuoptind - 1]); nextchar += strlen (nextchar); gnuoptopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[gnuoptind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { if (argv[gnuoptind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[gnuoptind][0], nextchar); } nextchar = (char *) ""; gnuoptind++; gnuoptopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `gnuoptind' when we start to process its last character. */ if (*nextchar == '\0') ++gnuoptind; if (temp == NULL || c == ':') { if (print_errors) { fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } gnuoptopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { gnuoptarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ gnuoptind++; } else if (gnuoptind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } gnuoptopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `gnuoptind' once; increment it again when taking next ARGV-elt as argument. */ gnuoptarg = argv[gnuoptind++]; /* gnuoptarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = gnuoptarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[gnuoptind]); nextchar += strlen (nextchar); gnuoptind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) gnuoptarg = nameend + 1; else { if (print_errors) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (gnuoptind < argc) gnuoptarg = argv[gnuoptind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[gnuoptind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { gnuoptarg = nextchar; gnuoptind++; } else gnuoptarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { gnuoptarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ gnuoptind++; } else if (gnuoptind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } gnuoptopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `gnuoptind' once; increment it again when taking next ARGV-elt as argument. */ gnuoptarg = argv[gnuoptind++]; nextchar = NULL; } } return c; } } int gnugetopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ sendip-2.5/gnugetopt.h0100644000076400007640000001207407423351334013504 0ustar mikemike/* Declarations for getopt. Copyright (C) 1989,90,91,92,93,94,96,97,98,99 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __GNU_GETOPT_H #define __GNU_GETOPT_H /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *gnuoptarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `gnuoptind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int gnuoptind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int gnuopterr; /* Set to an option character which was unrecognized. */ extern int gnuoptopt; /* modification to getopt - allows us to skip options */ extern char *nextchar; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `gnuoptarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if defined __STDC__ && __STDC__ const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `gnuoptopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `gnuoptarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ extern int gnugetopt (int __argc, char *const *__argv, const char *__shortopts); extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); #endif /* getopt.h */ sendip-2.5/gnugetopt1.c0100644000076400007640000001077007423352042013556 0ustar mikemike/* ripped straight from glibc, with minor modifications. Included to make sure we get getopt_long_only on all systems */ /* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "gnugetopt.h" #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ /* #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif */ #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_gnuoptind = 0; while (1) { int this_option_gnuoptind = gnuoptind ? gnuoptind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (gnuoptarg) printf (" with arg %s", gnuoptarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_gnuoptind != 0 && digit_gnuoptind != this_option_gnuoptind) printf ("digits occur in two different argv-elements.\n"); digit_gnuoptind = this_option_gnuoptind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", gnuoptarg); break; case 'd': printf ("option d with value `%s'\n", gnuoptarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (gnuoptind < argc) { printf ("non-option ARGV-elements: "); while (gnuoptind < argc) printf ("%s ", argv[gnuoptind++]); printf ("\n"); } exit (0); } #endif /* TEST */ sendip-2.5/help2man0100755000076400007640000002740607377506174012774 0ustar mikemike#!/usr/bin/perl -w # MODIFICATION OF GNU's help2man # CHANGES: # executeable hardcoded to be ./sendip with lots of options... # uses -h instead of --help # version hardcoded rather than --version # puts options in OPTIONS rather than in DESCRIPTION my $version=`cat VERSION`; chop $version; # Generate a short man page from --help and --version output. # Copyright 1997, 1998, 1999, 2000 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Written by Brendan O'Dea # Available from ftp://ftp.gnu.org/gnu/help2man/ use 5.004; use strict; use Getopt::Long; use Text::Tabs qw(expand); use POSIX qw(strftime setlocale LC_TIME); my $this_program = 'help2man'; my $this_version = '1.23-sendip'; my $version_info = < EOT my $help_info = <. EOT my $section = 1; my ($opt_name, @opt_include, $opt_output, $opt_no_info); # Parse options. Getopt::Long::config('bundling'); GetOptions ( 'n|name=s' => \$opt_name, 's|section=s' => \$section, 'i|include=s' => sub { push @opt_include, [ pop, 1 ] }, 'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] }, 'o|output=s' => \$opt_output, 'N|no-info' => \$opt_no_info, help => sub { print $help_info; exit }, version => sub { print $version_info; exit }, ) or die $help_info; die $help_info unless @ARGV == 0; my %include = (); my %append = (); my @include = (); # retain order given in include file # Provide replacement `quote-regex' operator for pre-5.005. BEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 } # Process include file (if given). Format is: # # [section name] # verbatim text # # or # # /pattern/ # verbatim text # for (@opt_include) { my ($inc, $required) = @$_; next unless -f $inc or $required; die "$this_program: can't open `$inc' ($!)\n" unless open INC, $inc; my $key; my $hash = \%include; while () { # [section] if (/^\[([^]]+)\]/) { $key = uc $1; $key =~ s/^\s+//; $key =~ s/\s+$//; $hash = \%include; push @include, $key unless $include{$key}; next; } # /pattern/ if (m!^/(.*)/([ims]*)!) { my $pat = $2 ? "(?$2)$1" : $1; # Check pattern. eval { $key = qr($pat) }; if ($@) { $@ =~ s/ at .*? line \d.*//; die "$inc:$.:$@"; } $hash = \%append; next; } # Silently ignore anything before the first # section--allows for comments and revision info. next unless $key; $hash->{$key} ||= ''; $hash->{$key} .= $_; } close INC; die "$this_program: no valid information found in `$inc'\n" unless $key; } # Compress trailing blank lines. for my $hash (\(%include, %append)) { for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ } } # Turn off localisation of executable's ouput. @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; # Turn off localisation of date (for strftime). setlocale LC_TIME, 'C'; # Grab help and version info from executable. #MAR - DON'T GRAB VERSION, hardcode ./sendip -p * -h my $mods = `echo ./*.so`; $mods =~ s/\.\//-p \.\//g; my $command = "./sendip 2>/dev/null -h $mods"; my $help_text = join '', map { s/ +$//; expand $_ } `$command` or die "$this_program: can't get `-$_' info from ./sendip\n"; my $date = strftime "%B %Y", localtime; (my $program = "./sendip") =~ s!.*/!!; my $package = $program; if ($opt_output) { unlink $opt_output or die "$this_program: can't unlink $opt_output ($!)\n" if -e $opt_output; open STDOUT, ">$opt_output" or die "$this_program: can't create $opt_output ($!)\n"; } #MAR DON'T PROCESS VERSION # The first line of the --version information is assumed to # of the following formats: # # # # {GNU,Free} # ({GNU,Free} ) # - {GNU,Free} # # and seperated from any copyright/author details by a blank line. #($_, $version_text) = split /\n+/, $version_text, 2; #if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or # /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/) #{ # $program = $1; # $package = $2; # $version = $3; #} #elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/) #{ # $program = $2; # $package = $1 ? "$1$2" : $2; # $version = $3; #} #else #{ # $version = $_; #} # #$program =~ s!.*/!!; # No info for `info' itself. $opt_no_info = 1 if $program eq 'info'; # --name overrides --include contents. $include{NAME} = "$program \\- $opt_name\n" if $opt_name; # Default (useless) NAME paragraph. $include{NAME} ||= "$program \\- manual page for $program $version\n"; # Man pages traditionally have the page title in caps. my $PROGRAM = uc $program; # Extract usage clause(s) [if any] for SYNOPSIS. if ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m) { my @syn = $2 . $3; if ($_ = $4) { s/^\n//; for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ } } my $synopsis = ''; for (@syn) { $synopsis .= ".br\n" if $synopsis; s!^\S*/!!; s/^(\S+) *//; $synopsis .= ".B $1\n"; s/\s+$//; s/(([][]|\.\.+)+)/\\fR$1\\fI/g; s/^/\\fI/ unless s/^\\fR//; $_ .= '\fR'; s/(\\fI)( *)/$2$1/g; s/\\fI\\fR//g; s/^\\fR//; s/\\fI$//; s/^\./\\&./; $synopsis .= "$_\n"; } $include{SYNOPSIS} ||= $synopsis; } # Process text, initial section is OPTIONS. my $sect = 'OPTIONS'; $_ = "$help_text"; # Normalise paragraph breaks. s/^\n+//; s/\n*$/\n/; s/\n\n+/\n\n/g; # Temporarily exchange leading dots, apostrophes and backslashes for # tokens. s/^\./\x80/mg; s/^'/\x81/mg; s/\\/\x82/g; # Start a new paragraph (if required) for these. s/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g; sub convert_option; while (length) { # Convert some standard paragraph names. if (s/^(Options|Examples): *\n//) { $sect = uc $1; next; } # Copyright section if (/^Copyright +[(\xa9]/) { $sect = 'COPYRIGHT'; $include{$sect} ||= ''; $include{$sect} .= ".PP\n" if $include{$sect}; my $copy; ($copy, $_) = split /\n\n/, $_, 2; for ($copy) { # Add back newline s/\n*$/\n/; # Convert iso9959-1 copyright symbol or (c) to nroff # character. s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg; # Insert line breaks before additional copyright messages # and the disclaimer. s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g; # Join hyphenated lines. s/([A-Za-z])-\n */$1/g; } $include{$sect} .= $copy; $_ ||= ''; next; } # Catch bug report text. if (/^(Report +bugs|Email +bug +reports +to) /) { $sect = 'REPORTING BUGS'; } # Author section. elsif (/^Written +by/) { $sect = 'AUTHOR'; } # Examples, indicated by an indented leading $, % or > are # rendered in a constant width font. if (/^( +)([\$\%>] )\S/) { my $indent = $1; my $prefix = $2; my $break = '.IP'; $include{$sect} ||= ''; while (s/^$indent\Q$prefix\E(\S.*)\n*//) { $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n"; $break = '.br'; } next; } my $matched = ''; $include{$sect} ||= ''; # Sub-sections have a trailing colon and the second line indented. if (s/^(\S.*:) *\n / /) { $matched .= $& if %append; $include{$sect} .= qq(.SS "$1"\n); } my $indent = 0; my $content = ''; # Option with description. if (s/^( {1,10}([+-]\S.*?))(?:( +)|\n( {20,}))(\S.*)\n//) { $matched .= $& if %append; $indent = length ($4 || "$1$3"); $content = ".TP\n\x83$2\n\x83$5\n"; unless ($4) { # Indent may be different on second line. $indent = length $& if /^ {20,}/; } } # Option without description. elsif (s/^ {1,10}([+-]\S.*)\n//) { $matched .= $& if %append; $content = ".HP\n\x83$1\n"; $indent = 80; # not continued } # Indented paragraph with tag. elsif (s/^( +(\S.*?) +)(\S.*)\n//) { $matched .= $& if %append; $indent = length $1; $content = ".TP\n\x83$2\n\x83$3\n"; } # Indented paragraph. elsif (s/^( +)(\S.*)\n//) { $matched .= $& if %append; $indent = length $1; $content = ".IP\n\x83$2\n"; } # Left justified paragraph. else { s/(.*)\n//; $matched .= $& if %append; $content = ".PP\n" if $include{$sect}; $content .= "$1\n"; } # Append continuations. while (s/^ {$indent}(\S.*)\n//) { $matched .= $& if %append; $content .= "\x83$1\n" } # Move to next paragraph. s/^\n+//; for ($content) { # Leading dot and apostrophe protection. s/\x83\./\x80/g; s/\x83'/\x81/g; s/\x83//g; # Convert options. s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge; } # Check if matched paragraph contains /pat/. if (%append) { for my $pat (keys %append) { if ($matched =~ $pat) { $content .= ".PP\n" unless $append{$pat} =~ /^\./; $content .= $append{$pat}; } } } $include{$sect} .= $content; } # Refer to the real documentation. unless ($opt_no_info) { $sect = 'SEE ALSO'; $include{$sect} ||= ''; $include{$sect} .= ".PP\n" if $include{$sect}; $include{$sect} .= < * ChangeLog since 2.0 release: * 02/12/2001: Moved ipv6_csum into here as this is where it is used. * 02/12/2001: Merged icmp6csum with ipv6_csum * 02/12/2001: Only check one layer of headers for enclosing ipv[46] header * 22/01/2002: Include string.h * 22/02/2002: Fix alignment problem in icmp*csum * ChangeLog since 2.1 release: * 16/04/2002: Move ipv6_pseudo_header into ipv6.h so tcp.c and udp.c can get it * ChangeLog since 2.4 release: * 21/04/2003: Fix errors detected by valgrind */ #include #include #include #include #include "sendip_module.h" #include "icmp.h" #include "ipv4.h" #include "ipv6.h" /* Character that identifies our options */ const char opt_char='c'; static void icmpcsum(sendip_data *icmp_hdr, sendip_data *data) { icmp_header *icp = (icmp_header *)icmp_hdr->data; u_int16_t *buf = malloc(icmp_hdr->alloc_len+data->alloc_len); u_int8_t *tempbuf = (u_int8_t *)buf; icp->check = 0; if(tempbuf == NULL) { fprintf(stderr,"Out of memory: ICMP checksum not computed\n"); return; } memcpy(tempbuf,icmp_hdr->data,icmp_hdr->alloc_len); memcpy(tempbuf+icmp_hdr->alloc_len,data->data,data->alloc_len); icp->check = csum(buf,icmp_hdr->alloc_len+data->alloc_len); free(buf); } static void icmp6csum(struct in6_addr *src, struct in6_addr *dst, sendip_data *hdr, sendip_data *data) { icmp_header *icp = (icmp_header *)hdr->data; struct ipv6_pseudo_hdr phdr; /* Make sure tempbuf is word aligned */ u_int16_t *buf = malloc(sizeof(phdr)+hdr->alloc_len+data->alloc_len); u_int8_t *tempbuf = (u_int8_t *)buf; icp->check = 0; if(tempbuf == NULL) { fprintf(stderr,"Out of memory: ICMP checksum not computed\n"); return; } memcpy(tempbuf+sizeof(phdr), hdr->data, hdr->alloc_len); memcpy(tempbuf+sizeof(phdr)+hdr->alloc_len, data->data, data->alloc_len); /* do an ipv6 checksum */ memset(&phdr, 0, sizeof(phdr)); memcpy(&phdr.source, src, sizeof(struct in6_addr)); memcpy(&phdr.destination, dst, sizeof(struct in6_addr)); phdr.ulp_length = htonl(hdr->alloc_len+data->alloc_len); phdr.nexthdr = IPPROTO_ICMPV6; memcpy(tempbuf, &phdr, sizeof(phdr)); icp->check = csum(buf,sizeof(phdr)+hdr->alloc_len+data->alloc_len); free(buf); } sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); icmp_header *icmp = malloc(sizeof(icmp_header)); memset(icmp,0,sizeof(icmp_header)); ret->alloc_len = sizeof(icmp_header); ret->data = (void *)icmp; ret->modified=0; return ret; } bool do_opt(char *opt, char *arg, sendip_data *pack) { icmp_header *icp = (icmp_header *)pack->data; switch(opt[1]) { case 't': icp->type = (u_int8_t)strtoul(arg, (char **)NULL, 0); pack->modified |= ICMP_MOD_TYPE; break; case 'd': icp->code = (u_int8_t)strtoul(arg, (char **)NULL, 0); pack->modified |= ICMP_MOD_CODE; break; case 'c': icp->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= ICMP_MOD_CHECK; break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { icmp_header *icp = (icmp_header *)pack->data; int i=strlen(hdrs)-1; /* Find enclosing IP header and do the checksum */ if(hdrs[i]=='i') { // ipv4 if(!(headers[i]->modified&IP_MOD_PROTOCOL)) { ((ip_header *)(headers[i]->data))->protocol=IPPROTO_ICMP; headers[i]->modified |= IP_MOD_PROTOCOL; } } else if(hdrs[i]=='6') { // ipv6 if(!(headers[i]->modified&IPV6_MOD_NXT)) { ((ipv6_header *)(headers[i]->data))->ip6_nxt=IPPROTO_ICMPV6; headers[i]->modified |= IPV6_MOD_NXT; } } if(!(pack->modified&ICMP_MOD_TYPE)) { if(hdrs[i]=='6') { icp->type=ICMP6_ECHO_REQUEST; } else { icp->type=ICMP_ECHO; } } if(!(pack->modified&ICMP_MOD_CHECK)) { if (hdrs[i] == '6') { // ipv6 struct in6_addr *src, *dst; src = (struct in6_addr *)&(((ipv6_header *)(headers[i]->data))->ip6_src); dst = (struct in6_addr *)&(((ipv6_header *)(headers[i]->data))->ip6_dst); icmp6csum(src, dst, pack, data); } else { // ipv4 or anything else icmpcsum(pack,data); } } return TRUE; } int num_opts() { return sizeof(icmp_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return icmp_opts; } char get_optchar() { return opt_char; } sendip-2.5/icmp.h0100664000076400007640000000123707441241671012423 0ustar mikemike/* icmp.h */ #ifndef _SENDIP_ICMP_H #define _SENDIP_ICMP_H #define ICMP6_ECHO_REQUEST 128 #define ICMP_ECHO 8 /* ICMP HEADER * Copied from glibc 2.2, reproduced here without code specific stuff */ typedef struct { u_int8_t type; u_int8_t code; u_int16_t check; } icmp_header; /* Defines for which parts have been modified */ #define ICMP_MOD_TYPE 1 #define ICMP_MOD_CODE 1<<1 #define ICMP_MOD_CHECK 1<<2 /* Options */ sendip_option icmp_opts[] = { {"t",1,"ICMP message type","ICMP_ECHO (8), or ICMP6_ECHO_REQUEST (128) if embedded in an IPv6 packet"}, {"d",1,"ICMP code","0"}, {"c",1,"ICMP checksum","Correct"} }; #endif /* _SENDIP_ICMP_H */ sendip-2.5/ipv4.c0100664000076400007640000002537607650770312012363 0ustar mikemike/* ipv4.c - IPV4 code for sendip * Author: Mike Ricketts * ChangeLog from 2.0 release: * 26/11/2001 IP options * 23/01/2002 Spelling fix (Dax Kelson ) * 26/08/2002 Put tot_len field in host byte order on FreeBSD * ChangeLog since 2.2 release: * 24/11/2002 make it compile on archs that care about alignment * ChangeLog since 2.3 release: * 23/12/2002 fix bug with -iossr and -iolsr * 20/01/2003 fix FreeBSD sendto(): invalid argument error. Again. */ #include #include #include #include #include #include #include #include "sendip_module.h" #include "ipv4.h" /* Character that identifies our options */ const char opt_char='i'; static void ipcsum(sendip_data *ip_hdr) { ip_header *ip = (ip_header *)ip_hdr->data; ip->check=0; ip->check=csum((u_int16_t *)ip_hdr->data, ip_hdr->alloc_len); } /* This builds a source route format option from an argument */ static u_int8_t buildroute(char *data) { char *data_out = data; char *data_in = data; char *next; u_int8_t p='0'; int i; /* First, the first 2 bytes give us the pointer */ for(i=0;i<2;i++) { p<<=4; if('0'<=*data_in && *data_in<='9') { p+=*data_in-'0'; } else if('A'<=*data_in && *data_in<='F') { p+=*data_in-'A'+0x0A; } else if('a'<=*data_in && *data_in<='f') { p+=*data_in-'a'+0x0a; } else { fprintf(stderr,"First 2 chars of record route options must be hex pointer\n"); return 0; } data_in++; } *(data_out++)=p; /* Now loop through IP addresses... */ if(*data_in != ':') { fprintf(stderr,"Third char of a record route option must be a :\n"); return 0; } data_in++; next=data_in; while(next) { u_int32_t ip; next=strchr(data_in,':'); if(next) { *(next++)=0; } ip=inet_addr(data_in); memcpy(data_out,&ip,4); data_out+=4; data_in = next; } return (data_out-data); } /* This bears an incredible resemblance to the TCP addoption function... */ static void addoption(u_int8_t copy, u_int8_t class, u_int8_t num, u_int8_t len, u_int8_t *data, sendip_data *pack) { /* opt is copy flag (1bit) + class (2 bit) + number (5 bit) */ u_int8_t opt = ((copy&1)<<7) | ((class&3)<<5) | (num&31); pack->data = realloc(pack->data, pack->alloc_len + len); *((u_int8_t *)pack->data+pack->alloc_len) = opt; if(len > 1) *((u_int8_t *)pack->data+pack->alloc_len+1) = len; if(len > 2) memcpy((u_int8_t *)pack->data+pack->alloc_len+2,data,len-2); pack->alloc_len += len; } sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); ip_header *ip = malloc(sizeof(ip_header)); memset(ip,0,sizeof(ip_header)); ret->alloc_len = sizeof(ip_header); ret->data = (void *)ip; ret->modified=0; return ret; } bool set_addr(char *hostname, sendip_data *pack) { ip_header *ip = (ip_header *)pack->data; struct hostent *host = gethostbyname2(hostname,AF_INET); if(!(pack->modified & IP_MOD_SADDR)) { ip->saddr = inet_addr("127.0.0.1"); } if(!(pack->modified & IP_MOD_DADDR)) { if(host==NULL) return FALSE; if(host->h_length != sizeof(ip->daddr)) { fprintf(stderr,"IPV4 destination address is the wrong size!!!"); return FALSE; } memcpy(&(ip->daddr),host->h_addr,host->h_length); } return TRUE; } bool do_opt(char *opt, char *arg, sendip_data *pack) { ip_header *iph = (ip_header *)pack->data; switch(opt[1]) { case 's': iph->saddr = inet_addr(arg); pack->modified |= IP_MOD_SADDR; break; case 'd': iph->daddr = inet_addr(arg); pack->modified |= IP_MOD_DADDR; break; case 'h': iph->header_len = (unsigned int)strtoul(arg, (char **)NULL, 0) & 0xF; pack->modified |= IP_MOD_HEADERLEN; break; case 'v': iph->version = (unsigned int)strtoul(arg, (char **)NULL, 0) & 0xF; pack->modified |= IP_MOD_VERSION; break; case 'y': iph->tos = (u_int8_t)strtoul(arg, (char **)NULL, 0); pack->modified |= IP_MOD_TOS; break; case 'l': iph->tot_len = (u_int16_t)strtoul(arg, (char **)NULL, 0); #ifndef __FreeBSD__ #ifndef __FreeBSD iph->tot_len = htons(iph->tot_len); #endif #endif pack->modified |= IP_MOD_TOTLEN; break; case 'i': iph->id = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= IP_MOD_ID; break; case 'f': if(opt[2]) { /* Note: *arg&1 is what we want because: if arg=="0", *arg&1==0 if arg=="1", *arg&1==1 otherwise, it doesn't really matter... */ switch(opt[2]) { case 'r': iph->res=*arg&1; pack->modified |= IP_MOD_RES; break; case 'd': iph->df=*arg&1; pack->modified |= IP_MOD_DF; break; case 'm': iph->mf=*arg&1; pack->modified |= IP_MOD_MF; break; } } else { IP_SET_FRAGOFF(iph,(u_int16_t)strtoul(arg, (char **)NULL, 0) & (u_int16_t)0x1FFF); pack->modified |= IP_MOD_FRAGOFF; break; } break; case 't': iph->ttl = (u_int8_t)strtoul(arg, (char **)NULL, 0); pack->modified |= IP_MOD_TTL; break; case 'p': iph->protocol = (u_int8_t)strtoul(arg, (char **)NULL, 0); pack->modified |= IP_MOD_PROTOCOL; break; case 'c': iph->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= IP_MOD_CHECK; break; case 'o': /* IP options */ if(!strcmp(opt+2, "num")) { /* Other options (auto legnth) */ u_int8_t cp, cls, num, len; u_int8_t *data = malloc(strlen(arg)+2); if(!data) { fprintf(stderr,"Out of memory!\n"); return FALSE; } sprintf(data,"0x%s",arg); len = compact_string(data); cp=(*data&0x80)>>7; cls=(*data&0x60)>>5; num=(*data&0x1F); addoption(cp,cls,num,len+1,data+1,pack); free(data); } else if(!strcmp(opt+2, "eol")) { /* End of list */ addoption(0,0,0,1,NULL,pack); } else if(!strcmp(opt+2, "nop")) { /* NOP */ addoption(0,0,1,1,NULL,pack); } else if(!strcmp(opt+2, "rr")) { /* Record route * Format is the same as for loose source route */ char *data = strdup(arg); u_int8_t len; if(!data) { fprintf(stderr,"Out of memory!\n"); return FALSE; } len = buildroute(data); if(len==0) { free(data); return FALSE; } else { addoption(0,0,7,len+2,data,pack); free(data); } } else if(!strcmp(opt+2, "ts")) { /* Time stamp (RFC791) * Format is: * type (68, 8bit) * length (automatic, 8bit) * pointer (8bit) * overflow (4bit), flag (4bit) * if(flag) ip1 (32bit) * timestamp1 (32bit) * if(flag) ip2 (32bit) * timestamp2 (32bit) * ... */ char *data = strdup(arg); char *data_in = data; char *data_out = data; char *next; u_int8_t p=0; int i; if(data==NULL) { fprintf(stderr,"Out of memory\n"); return FALSE; } /* First, get the pointer */ for(i=0;i<2;i++) { p<<=4; if('0'<=*data_in && *data_in<='9') { p+=*data_in-'0'; } else if('A'<=*data_in && *data_in<='F') { p+=*data_in-'A'+0x0A; } else if('a'<=*data_in && *data_in<='f') { p+=*data_in-'a'+0x0a; } else { fprintf(stderr, "First 2 chars of IP timestamp must be hex pointer\n"); free(data); return FALSE; } data_in++; } *(data_out++)=p; /* Skip a : */ if(*(data_in++) != ':') { fprintf(stderr,"Third char of IP timestamp must be :\n"); free(data); return FALSE; } /* Get the overflow and skip a : */ next = strchr(data_in,':'); if(!next) { fprintf(stderr,"IP timestamp option incorrect\n"); free(data); return FALSE; } *(next++)=0; i = atoi(data_in); if(i > 15) { fprintf(stderr,"IP timestamp overflow too big (max 15)\n"); free(data); return FALSE; } *data_out=(u_int8_t)(i<<4); data_in=next; /* Now get the flag and skip a : */ next = strchr(data_in,':'); if(!next) { fprintf(stderr,"IP timestamp option incorrect\n"); free(data); return FALSE; } *(next++)=0; i = atoi(data_in); if(i > 15) { fprintf(stderr,"IP timestamp flag too big (max 3)\n"); free(data); return FALSE; } else if(i!=0 && i!=1 && i!=3) { fprintf(stderr, "Warning: IP timestamp flag value %d not understood\n",i); } (*data_out)+=(u_int8_t)i; data_in=next; data_out++; /* Fill in (ip?) timestamp pairs */ while(next) { u_int32_t ts; if(i) { /* if we need IPs */ u_int32_t ip; next=strchr(data_in,':'); if(!next) { fprintf(stderr,"IP address in IP timestamp option must be followed by a timesamp\n"); free(data); return FALSE; } *(next++)=0; ip=inet_addr(data_in); memcpy(data_out,&ip,4); data_out+=4; data_in = next; } next=strchr(next,':'); if(next) *(next++)=0; ts = htonl(atoi(data_in)); memcpy(data_out,&ts,4); data_out+=4; data_in = next; } addoption(0,2,4,data_out-data+2,data,pack); free(data); /* End of timestamp parsing */ } else if(!strcmp(opt+2, "lsr")) { /* Loose Source Route * Format is: * type (131, 8bit) * length (automatic, 8bit) * pointer (>=4, 8bit) * ip address0 (32bit) * ip address1 (32bit) * ... */ char *data = strdup(arg); u_int8_t len; if(!data) { fprintf(stderr,"Out of memory!\n"); return FALSE; } len = buildroute(data); if(len==0) { free(data); return FALSE; } else { addoption(1,0,3,len+2,data,pack); free(data); } } else if(!strcmp(opt+2, "sid")) { /* Stream ID (RFC791) */ u_int16_t sid = htons(atoi(arg)); addoption(1,0,8,4,(u_int8_t *)&sid,pack); } else if(!strcmp(opt+2, "ssr")) { /* Strict Source Route * Format is identical to loose source route */ char *data = strdup(arg); u_int8_t len; if(!data) { fprintf(stderr,"Out of memory!\n"); return FALSE; } len = buildroute(data); if(len==0) { free(data); return FALSE; } else { addoption(1,0,9,len+2,data,pack); free(data); } } else { fprintf(stderr, "unsupported IP option %s val %s\n", opt, arg); return FALSE; } break; default: usage_error("unknown IP option\n"); return FALSE; break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { ip_header *iph = (ip_header *)pack->data; if(!(pack->modified & IP_MOD_VERSION)) { iph->version=4; } if(!(pack->modified & IP_MOD_HEADERLEN)) { iph->header_len=(pack->alloc_len+3)/4; } if(!(pack->modified & IP_MOD_TOTLEN)) { iph->tot_len=pack->alloc_len + data->alloc_len; #ifndef __FreeBSD__ #ifndef __FreeBSD iph->tot_len = htons(iph->tot_len); #endif #endif } if(!(pack->modified & IP_MOD_ID)) { iph->id = rand(); } if(!(pack->modified & IP_MOD_TTL)) { iph->ttl = 255; } if(!(pack->modified & IP_MOD_CHECK)) { ipcsum(pack); } return TRUE; } int num_opts() { return sizeof(ip_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return ip_opts; } char get_optchar() { return opt_char; } sendip-2.5/ipv4.h0100664000076400007640000000543707430611506012357 0ustar mikemike/* ip.h */ #ifndef _SENDIP_IP_H #define _SENDIP_IP_H /* IP HEADER * Taken from glibc 2.2, and modified */ typedef struct { #if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int header_len:4; unsigned int version:4; #elif __BYTE_ORDER == __BIG_ENDIAN unsigned int version:4; unsigned int header_len:4; #else # error "Please fix " #endif u_int8_t tos; u_int16_t tot_len; u_int16_t id; #if __BYTE_ORDER == __LITTLE_ENDIAN u_int16_t frag_off1:5; u_int16_t mf:1; u_int16_t df:1; u_int16_t res:1; u_int16_t frag_off2:8; #define IP_SET_FRAGOFF(ip,v) {(ip)->frag_off1=((v)&0x1F00)>>8;(ip)->frag_off2=(v)&0x00FF;} #elif __BYTE_ORDER == __BIG_ENDIAN u_int16_t res:1; u_int16_t df:1; u_int16_t mf:1; u_int16_t frag_off:13; #define IP_SET_FRAGOFF(ip,v) (ip)->frag_off=(v) #else # error "Please fix " #endif u_int8_t ttl; u_int8_t protocol; u_int16_t check; u_int32_t saddr; u_int32_t daddr; } ip_header; /* Defines for which parts have been modified */ #define IP_MOD_HEADERLEN (1) #define IP_MOD_VERSION (1<<1) #define IP_MOD_TOS (1<<2) #define IP_MOD_TOTLEN (1<<3) #define IP_MOD_ID (1<<4) #define IP_MOD_RES (1<<5) #define IP_MOD_DF (1<<6) #define IP_MOD_MF (1<<7) #define IP_MOD_FRAGOFF (1<<8) #define IP_MOD_TTL (1<<9) #define IP_MOD_PROTOCOL (1<<10) #define IP_MOD_CHECK (1<<11) #define IP_MOD_SADDR (1<<12) #define IP_MOD_DADDR (1<<13) /* Options */ sendip_option ip_opts[] = { {"s",1,"Source IP address (see README)","127.0.0.1"}, {"d",1,"Desitnation IP address","Correct"}, {"h",1,"IP header length (see README)","Correct"}, {"v",1,"IP version (you almost definately don't want to change this)","4"}, {"y",1,"IP type of service","0"}, {"l",1,"Total IP packet length (see README)","Correct"}, {"i",1,"IP packet ID (see README)","Random"}, {"fr",1,"IP reservced flag (see README)","0 (options are 0,1,r)"}, {"fd",1,"IP don't fragment flag (see README)","0 (options are 0,1,r)"}, {"fm",1,"IP more fragments flag (see README)","0 (options are 0,1,r)"}, {"f",1,"IP fragment offset","0"}, {"t",1,"IP time to live","255"}, {"p",1,"IP protcol","0, or set by underlying protocol"}, {"c",1,"IP checksum (see README)","Correct"}, {"onum",1,"IP option as string of hex bytes (length is always correct)","(no options)"}, {"oeol",0,"IP option: end of list",NULL}, {"onop",0,"IP option: no-op",NULL}, {"orr",1,"IP option: record route. Format: pointer:addr1:addr2:...",NULL}, {"ots",1,"IP option: timestamp. Format: pointer:overflow:flag:(ip1:)ts1:(ip2:)ts2:...",NULL}, {"olsr",1,"IP option: loose source route. Format: pointer:addr1:addr2:...",NULL}, {"osid",1,"IP option: stream identifier",NULL}, {"ossr",1,"IP option: strict source route. Format: pointer:addr1:addr2:...",NULL} }; #endif /* _SENDIP_IP_H */ sendip-2.5/ipv6.c0100664000076400007640000000654007524770233012357 0ustar mikemike/* ipv6.c - sendip IPv6 code * Taken from code by Antti Tuominen * ChangeLog since 2.0 release: * 09/08/2002 Setting src/dst now works (Pekka Savola ) */ #include #include #include #include #include #include #include #include "sendip_module.h" #include "ipv6.h" /* Character that identifies our options */ const char opt_char='6'; sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); ipv6_header *ipv6 = malloc(sizeof(ipv6_header)); memset(ipv6,0,sizeof(ipv6_header)); ret->alloc_len = sizeof(ipv6_header); ret->data = (void *)ipv6; ret->modified=0; return ret; } bool set_addr(char *hostname, sendip_data *pack) { ipv6_header *ipv6 = (ipv6_header *)pack->data; struct hostent *host = gethostbyname2(hostname,AF_INET6); if(!(pack->modified & IPV6_MOD_SRC)) { ipv6->ip6_src = in6addr_loopback; } if(!(pack->modified & IPV6_MOD_DST)) { if(host==NULL) return FALSE; if(host->h_length != sizeof(ipv6->ip6_dst)) { fprintf(stderr,"IPV6 destination address is the wrong size!!!"); return FALSE; } memcpy(&(ipv6->ip6_dst),host->h_addr,host->h_length); } return TRUE; } bool do_opt(char *opt, char *arg, sendip_data *pack) { ipv6_header *hdr = (ipv6_header *)pack->data; struct in6_addr addr; switch(opt[1]) { case 'f': /* TODO : This looks byte-order dependant */ hdr->ip6_flow |= htonl((u_int32_t)strtoul(arg, (char **)NULL, 0) & 0xFFF00000); pack->modified |= IPV6_MOD_FLOW; break; case 'v': hdr->ip6_vfc &= 0x0F; hdr->ip6_vfc |= (u_int8_t)(strtoul(arg, (char **)NULL, 0) &0x0F) << 4; pack->modified |= IPV6_MOD_VERSION; break; case 'p': hdr->ip6_vfc &= 0xF0; hdr->ip6_vfc |= (u_int8_t)strtoul(arg, (char **)NULL, 0) & 0x0F; pack->modified |= IPV6_MOD_PRIORITY; break; case 't': /* TODO : This looks byte-order dependant */ hdr->ip6_flow |= htonl(((u_int32_t)strtoul(arg, (char **)NULL, 0) << 20) & 0x0F000000); pack->modified |= IPV6_MOD_FLOW; break; case 'l': hdr->ip6_plen = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= IPV6_MOD_PLEN; break; case 'h': hdr->ip6_hlim = (u_int8_t)strtoul(arg, (char **)NULL, 0); pack->modified |= IPV6_MOD_HLIM; break; case 'n': hdr->ip6_nxt = (u_int8_t)strtoul(arg, (char **)NULL, 0); pack->modified |= IPV6_MOD_NXT; break; case 's': if (inet_pton(AF_INET6, arg, &addr)) { memcpy(&hdr->ip6_src, &addr, sizeof(struct in6_addr)); } pack->modified |= IPV6_MOD_SRC; break; case 'd': if (inet_pton(AF_INET6, arg, &addr)) { memcpy(&hdr->ip6_dst, &addr, sizeof(struct in6_addr)); } pack->modified |= IPV6_MOD_DST; break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { ipv6_header *ipv6 = (ipv6_header *)pack->data; if(!(pack->modified&IPV6_MOD_VERSION)) { ipv6->ip6_vfc &= 0x0F; ipv6->ip6_vfc |= (6 << 4); } if(!(pack->modified&IPV6_MOD_PLEN)) { ipv6->ip6_plen = htons(data->alloc_len); } if(!(pack->modified&IPV6_MOD_NXT)) { ipv6->ip6_nxt = (u_int8_t)IPPROTO_NONE; } if(!(pack->modified&IPV6_MOD_HLIM)) { ipv6->ip6_hlim = 32; } return TRUE; } int num_opts() { return sizeof(ipv6_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return ipv6_opts; } char get_optchar() { return opt_char; } sendip-2.5/ipv6.h0100664000076400007640000000336507457067526012377 0ustar mikemike/* ipv6.h */ #ifndef _SENDIP_IPV6_H #define _SENDIP_IPV6_H /* Pseudo header used for checksumming ICMP, TCP, UDP etc */ struct ipv6_pseudo_hdr { struct in6_addr source; struct in6_addr destination; u_int32_t ulp_length; u_int32_t zero: 24, nexthdr: 8; }; /* Header taken from glibc 2.2 */ typedef struct { union { struct ip6_hdrctl { uint32_t ip6_un1_flow; /* 24 bits of flow-ID */ uint16_t ip6_un1_plen; /* payload length */ uint8_t ip6_un1_nxt; /* next header */ uint8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; uint8_t ip6_un2_vfc; /* 4 bits version, 4 bits priority */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ } ipv6_header; #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim /* Defines for which parts have been modified */ #define IPV6_MOD_FLOW 1 #define IPV6_MOD_VERSION 1<<1 #define IPV6_MOD_PRIORITY 1<<2 #define IPV6_MOD_PLEN 1<<3 #define IPV6_MOD_HLIM 1<<4 #define IPV6_MOD_NXT 1<<5 #define IPV6_MOD_SRC 1<<6 #define IPV6_MOD_DST 1<<7 /* Options */ sendip_option ipv6_opts[] = { {"f",1,"IPv6 flow ID","32"}, {"t",1,"IPv6 traffic class","0"}, {"l",1,"IPv6 payload length","Correct"}, {"n",1,"IPv6 next header","IPPROTO_NONE"}, {"h",1,"IPv6 hop limit","32"}, {"v",1,"IP version (you probably don't want to change this"}, {"p",1,"IPv6 priority","0"}, {"s",1,"IPv6 source address","::1"}, {"d",1,"IPv6 destination address","Correct"} }; #endif /* _SENDIP_IPV6_H */ sendip-2.5/ntp.c0100664000076400007640000001204207416053405012261 0ustar mikemike/* ntp.c - Network Timxe Protocol module for sendip * Author: Mike Ricketts * ChangeLog since 2.1 release: */ #include #include #include #include #include #include #include #include "sendip_module.h" #include "ntp.h" /* Character that identifies our options */ const char opt_char='n'; u_int32_t make_fixed_point(double n, bool issigned, int totbits, int intbits) { u_int32_t intpart; u_int32_t fracpart; u_int32_t result; bool signbit; double intpartd, fracpartd; int fracbits; if(issigned) totbits--; fracbits=totbits-intbits; if(issigned && n<0) { signbit=TRUE; } else { signbit=FALSE; } /* else, signbit is unused */ n=fabs(n); /* fracpartd=floor(ldexp(modf(n,&intpartd),ldexp(2.0,fracbits))); */ fracpartd=floor(ldexp(modf(n,&intpartd),32)); intpart=(u_int32_t)intpartd; fracpart=(u_int32_t)fracpartd; if(issigned&&signbit) { result=1<>=intbits; } result|=fracpart; } return htonl(result); } bool make_ts(ntp_ts *dest, char *src) { char *intpart, *fracpart; intpart=src; fracpart=strchr(intpart,'.'); if(*intpart) { dest->intpart=(u_int32_t)strtoul(intpart,&fracpart,0); } else { dest->intpart=0; } fracpart++; // skip the . if(fracpart && *fracpart) { double d; d = strtod(fracpart-1,(char **)NULL); dest->fracpart=make_fixed_point(d,FALSE,32,0); } return TRUE; } sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); ntp_header *ntp = malloc(sizeof(ntp_header)); memset(ntp,0,sizeof(ntp_header)); ret->alloc_len = sizeof(ntp_header); ret->data = (void *)ntp; ret->modified=0; return ret; } bool do_opt(char *opt, char *arg, sendip_data *pack) { ntp_header *ntp = (ntp_header *)pack->data; switch(opt[1]) { case 'l': /* Leap Indicator (2 bits) */ ntp->leap=(u_int8_t)strtoul(arg,(char **)NULL,0)&3; pack->modified|=NTP_MOD_LEAP; break; case 's': /* Status (6 bits, values 0-4 defined */ ntp->status=(u_int8_t)strtoul(arg,(char **)NULL,0)&0x3F; pack->modified|=NTP_MOD_STATUS; break; case 't': /* Type (8 bits, values 0-4 defined */ ntp->type=(u_int8_t)strtoul(arg,(char **)NULL,0)&0xFF; pack->modified|=NTP_MOD_TYPE; break; case 'p': /* precision (16 bits, range +32 to -32) */ ntp->precision=htons((int8_t)strtol(arg,(char **)NULL,0)); pack->modified|=NTP_MOD_PRECISION; break; case 'e': /* esitmated error (32 bits, fixed point between bits 15/16) */ ntp->error=make_fixed_point(strtod(arg,(char **)NULL),FALSE,32,16); pack->modified|=NTP_MOD_ERROR; break; case 'd': /* estimated drift rate (32 bits, signed fixed point left of high order bit) */ ntp->drift=make_fixed_point(strtod(arg,(char **)NULL),TRUE,32,0); pack->modified|=NTP_MOD_DRIFT; break; case 'r': /* reference clock id (32 bits or a 4 byte string). Can be: If type==1: "WWVB", "GOES", "WWV\0" If type==2: IP address Else: must be zero */ if('0'<=*arg&&*arg<='9') { /* either a number or an IP */ if((ntp->reference.ipaddr=inet_addr(arg))==-1) { /* Not a valid IP, or really want 255.255.255.255 */ if(strcmp(arg,"255.255.255.255")) { ntp->reference.ipaddr=htonl(strtol(arg,(char **)NULL,0)); } } } else { /* Hopefully a 4 byte or less string */ ntp->reference.ipaddr = 0; if(strlen(arg)<=4) { memcpy(ntp->reference.id,arg,strlen(arg)); } else { usage_error("NTP reference clock ID must be IP addr, 32 bit integer, or 4 byte string\n"); return FALSE; } } pack->modified|=NTP_MOD_REF; break; case 'f': /* reference timestamp (64 bits) */ if(make_ts(&(ntp->reference_ts),arg)) { pack->modified|=NTP_MOD_REFERENCE; } else { usage_error("Couldn't parse NTP reference timestamp\n"); return FALSE; } break; case 'o': /* originate timestamp (64 bits) */ if(make_ts(&(ntp->originate_ts),arg)) { pack->modified|=NTP_MOD_ORIGINATE; } else { usage_error("Couldn't parse NTP originate timestamp\n"); return FALSE; } break; case 'a': /* receive timestamp (64 bits) */ if(make_ts(&(ntp->receive_ts),arg)) { pack->modified|=NTP_MOD_RECEIVE; } else { usage_error("Couldn't parse NTP receive timestamp\n"); return FALSE; } break; case 'x': /* transmit timestamp (64 bits) */ if(make_ts(&(ntp->transmit_ts),arg)) { pack->modified|=NTP_MOD_TRANSMIT; } else { usage_error("Couldn't parse NTP transmit timestamp\n"); return FALSE; } break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { if(hdrs[strlen(hdrs)-1] != 'u') { usage_error("Warning: NTP should be contained in a UDP packet\n"); } return TRUE; } int num_opts() { return sizeof(ntp_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return ntp_opts; } char get_optchar() { return opt_char; } sendip-2.5/ntp.h0100664000076400007640000000266407402517315012277 0ustar mikemike/* ntp.h */ #ifndef _SENDIP_NTP_H #define _SENDIP_NTP_H typedef struct { u_int32_t intpart; u_int32_t fracpart; } ntp_ts; /* NTP HEADER */ typedef struct { /* TODO BYTEORDER!!! */ u_int8_t leap:2; u_int8_t status:6; u_int8_t type; /* END TODO */ u_int16_t precision; u_int32_t error; u_int32_t drift; union { u_int32_t ipaddr; char id[4]; } reference; ntp_ts reference_ts; ntp_ts originate_ts; ntp_ts receive_ts; ntp_ts transmit_ts; } ntp_header; /* Defines for which parts have been modified */ #define NTP_MOD_LEAP (1) #define NTP_MOD_STATUS (1<<1) #define NTP_MOD_TYPE (1<<2) #define NTP_MOD_PRECISION (1<<3) #define NTP_MOD_ERROR (1<<4) #define NTP_MOD_DRIFT (1<<5) #define NTP_MOD_REF (1<<6) #define NTP_MOD_REFERENCE (1<<7) #define NTP_MOD_ORIGINATE (1<<8) #define NTP_MOD_RECEIVE (1<<9) #define NTP_MOD_TRANSMIT (1<<10) /* Options */ sendip_option ntp_opts[] = { {"l",1,"NTP Leap Indicator","00 (no warning)"}, {"s",1,"NTP status","0 (clock operating OK)"}, {"t",1,"NTP type","0 (unspecified)"}, {"p",1,"NTP precision","0"}, {"e",1,"NTP estimated error","0.0"}, {"d",1,"NTP estimated drift rate","0.0"}, {"r",1,"NTP reference clock ID (string or IP or number)","0"}, {"f",1,"NTP reference timestamp","0.0"}, {"o",1,"NTP originate timestamp","0.0"}, {"a",1,"NTP arrival (receive) timestamp","0.0"}, {"x",1,"NTP xmit (transmit) timestamp","0.0"} }; #endif /* _SENDIP_NTP_H */ sendip-2.5/rip.c0100664000076400007640000000726707570212051012262 0ustar mikemike/* rip.c - RIP-1 and -2 code for sendip * Taken from code by Richard Polton * ChangeLog since 2.0 release: * 02/12/2001 Only check 1 layer for enclosing UDP header * 21/08/2002 Off-by-one fix in -re handling that caused bad things to happen * 21/08/2002 htons() and htonl() added where needed * ChangeLog since 2.2 release: * 24/11/2002 make it compile on archs that care about alignment */ #include #include #include #include #include #include #include "sendip_module.h" #include "rip.h" /* Character that identifies our options */ const char opt_char='r'; sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); rip_header *rip = malloc(sizeof(rip_header)); memset(rip,0,sizeof(rip_header)); ret->alloc_len = sizeof(rip_header); ret->data = (void *)rip; ret->modified=0; return ret; } bool do_opt(char *opt, char *arg, sendip_data *pack) { rip_header *rippack = (rip_header *)pack->data; rip_options *ripopt; char *p, *q; switch(opt[1]) { case 'v': /* version */ rippack->version = (u_int8_t)strtoul(arg, (char **)0, 0); pack->modified |= RIP_MOD_VERSION; break; case 'c': /* command */ rippack->command = (u_int8_t)strtoul(arg, (char **)0, 0); pack->modified |= RIP_MOD_COMMAND; break; case 'a': /* authenticate */ if(RIP_NUM_ENTRIES(pack) != 0) { usage_error("Warning: a real RIP-2 packet only has authentication on the first entry.\n"); } pack->modified |= RIP_IS_AUTH; pack->data = realloc(pack->data,pack->alloc_len+strlen(arg)); strcpy((char *)pack->data+pack->alloc_len,arg); pack->alloc_len += strlen(arg); break; case 'e': /* rip entry */ if(RIP_NUM_ENTRIES(pack)==25) { usage_error("Warning: a real RIP packet contains no more than 25 entries.\n"); } RIP_ADD_ENTRY(pack); ripopt = RIP_OPTION(pack); p=q=arg; /* TODO: if arg is malformed, this could segfault */ while(*(q++)!=':') /* do nothing */; *(--q)='\0'; rippack->addressFamily= htons((p==q)?2:(u_int16_t)strtoul(p, (char **)0, 0)); pack->modified |= RIP_MOD_ADDRFAM; p=++q; while(*(q++)!=':') /* do nothing */; *(--q)='\0'; rippack->routeTagOrAuthenticationType=htons((p==q)?0:(u_int16_t)strtoul(p, (char **)0,0)); pack->modified |= RIP_MOD_ROUTETAG; p=++q; while(*(q++)!=':') /* do nothing */; *(--q)='\0'; ripopt->address=(p==q)?inet_addr("0.0.0.0"):inet_addr(p); p=++q; while(*(q++)!=':') /* do nothing */; *(--q)='\0'; ripopt->subnetMask=(p==q)?inet_addr("255.255.255.0"):inet_addr(p); p=++q; while(*(q++)!=':') /* do nothing */; *(--q)='\0'; ripopt->nextHop=(p==q)?inet_addr("0.0.0.0"):inet_addr(p); p=++q; while(*(q++)!='\0') /* do nothing */; *(--q)='\0'; ripopt->metric=htonl((p==q)?16:(u_int32_t)strtoul(p,(char **)0, 0)); break; case 'd': /* default request */ if(RIP_NUM_ENTRIES(pack) != 0) { usage_error("Warning: a real RIP-1 or -2 packet does not have any entries in a default request.\n"); } rippack->command = (u_int8_t)1; rippack->addressFamily = (u_int16_t)0; rippack->routeTagOrAuthenticationType = (u_int16_t)0; RIP_ADD_ENTRY(pack); ripopt=RIP_OPTION(pack); ripopt->address=inet_addr("0.0.0.0"); ripopt->subnetMask=inet_addr("0.0.0.0"); ripopt->nextHop=inet_addr("0.0.0.0"); ripopt->metric=htons((u_int16_t)16); break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { if(hdrs[strlen(hdrs)-1] != 'u') { usage_error("Warning: RIP should be contained in a UDP packet\n"); } return TRUE; } int num_opts() { return sizeof(rip_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return rip_opts; } char get_optchar() { return opt_char; } sendip-2.5/rip.h0100664000076400007640000000307207570212052012256 0ustar mikemike/* rip.h */ #ifndef _SENDIP_RIP_H #define _SENDIP_RIP_H /* RIP PACKET STRUCTURES */ typedef struct { u_int8_t command; u_int8_t version; u_int16_t res; u_int16_t addressFamily; u_int16_t routeTagOrAuthenticationType; } rip_header; typedef struct { u_int32_t address; u_int32_t subnetMask; u_int32_t nextHop; u_int32_t metric; } rip_options; /* Defines for which parts have been modified */ #define RIP_MOD_COMMAND 1 #define RIP_MOD_VERSION 1<<1 #define RIP_MOD_ADDRFAM 1<<2 #define RIP_MOD_ROUTETAG 1<<3 #define RIP_IS_AUTH 1<<4 /* Options */ sendip_option rip_opts[] = { {"v",1,"RIP version","2"}, {"c",1, "RIP command (1=request, 2=response, 3=traceon (obsolete), 4=traceoff (obsolete), 5=poll (undocumented), 6=poll entry (undocumented)","1"}, {"e",1,"Add a RIP entry. Format is: Address family:route tag:address:subnet mask:next hop:metric","2:0:0.0.0.0:255.255.255.0:0.0.0.0:16, any option my be left out to use the default"}, {"a",1,"RIP authenticat packet, argument is the password; do not use any other RIP options on this RIP header",NULL}, {"d",0,"RIP default request - get router's entire routing table; do not use any other RIP options on this RIP header",NULL} }; /* Helpful macros */ #define RIP_NUM_ENTRIES(d) (((d)->alloc_len-sizeof(rip_header))/sizeof(rip_options)) #define RIP_ADD_ENTRY(d) { (d)->data = realloc((d)->data,(d)->alloc_len+sizeof(rip_options)); (d)->alloc_len+=sizeof(rip_options); } #define RIP_OPTION(d) ((rip_options *)((u_int32_t *)((d)->data)+((d)->alloc_len>>2)-(sizeof(rip_options)>>2))) #endif /* _SENDIP_RIP_H */ sendip-2.5/ripng.c0100664000076400007640000000724207570212051012600 0ustar mikemike/* ripng.c - RIPng (version 1) code for sendip * Created by hacking rip code * ChangeLog since 2.2 release: * 15/10/2002 Read the spec * 24/11/2002 Made it compile on archs needing alignment */ #include #include #include #include #include #include #include #include "sendip_module.h" #include "ripng.h" /* Character that identifies our options */ const char opt_char='R'; static struct in6_addr inet6_addr(char *hostname) { struct hostent *host = gethostbyname2(hostname,AF_INET6); struct in6_addr ret; if(host==NULL) { fprintf(stderr,"RIPNG: Couldn't get address for %s defaulting to loopback",hostname); return in6addr_loopback; } if(host->h_length != sizeof(struct in6_addr)) { fprintf(stderr,"RIPNG: IPV6 address is the wrong size: defaulting to loopback"); return in6addr_loopback; } memcpy(&ret,host->h_addr,sizeof(ret)); return ret; } sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); ripng_header *rip = malloc(sizeof(ripng_header)); memset(rip,0,sizeof(ripng_header)); ret->alloc_len = sizeof(ripng_header); ret->data = (void *)rip; ret->modified=0; return ret; } bool do_opt(char *opt, char *arg, sendip_data *pack) { ripng_header *rippack = (ripng_header *)pack->data; ripng_entry *ripopt; char *p, *q; switch(opt[1]) { case 'v': /* version */ rippack->version = (u_int8_t)strtoul(arg, (char **)0, 0); pack->modified |= RIPNG_MOD_VERSION; break; case 'c': /* command */ rippack->command = (u_int8_t)strtoul(arg, (char **)0, 0); pack->modified |= RIPNG_MOD_COMMAND; break; case 'r': /* reserved */ rippack->res = htons((u_int16_t)strtoul(arg, (char **)0, 0)); pack->modified |= RIPNG_MOD_RESERVED; break; /* case 'a': / * authenticate * / if(RIPNG_NUM_ENTRIES(pack) != 0) { usage_error("Warning: a real RIP-2 packet only has authentication on the first entry.\n"); } pack->modified |= RIP_IS_AUTH; pack->data = realloc(pack->data,pack->alloc_len+strlen(arg)); strcpy(pack->data+pack->alloc_len,arg); pack->alloc_len += strlen(arg); break; */ case 'e': /* rip entry */ RIPNG_ADD_ENTRY(pack); ripopt = RIPNG_ENTRY(pack); p=q=arg; /* TODO: if arg is malformed, this could segfault */ while(*(q++)!='/') /* do nothing */; *(--q)='\0'; ripopt->prefix = (p==q)?in6addr_any:inet6_addr(p); p=++q; while(*(q++)!='/') /* do nothing */; *(--q)='\0'; ripopt->tag=htons( (p==q)?0:(u_int16_t)strtoul(p, (char **)0,0)); p=++q; while(*(q++)!='/') /* do nothing */; *(--q)='\0'; ripopt->len=(p==q)?(u_int8_t)128:(u_int8_t)strtoul(p, (char **)0,0); p=++q; while(*(q++)!='\0') /* do nothing */; *(--q)='\0'; ripopt->metric=(p==q)?(u_int8_t)16:(u_int8_t)strtoul(p,(char **)0, 0); break; case 'd': /* default request */ if(RIPNG_NUM_ENTRIES(pack) != 0) { usage_error("Warning: a real RIPng packet does not have any other entries in a default request.\n"); } rippack->command = (u_int8_t)1; rippack->version = (u_int8_t)1; rippack->res = (u_int16_t)0; pack->modified|=RIPNG_MOD_COMMAND|RIPNG_MOD_VERSION|RIPNG_MOD_RESERVED; RIPNG_ADD_ENTRY(pack); ripopt=RIPNG_ENTRY(pack); ripopt->prefix=in6addr_any; ripopt->tag=(u_int16_t)0; ripopt->len=(u_int8_t)0; ripopt->metric=htons((u_int16_t)16); break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { if(hdrs[strlen(hdrs)-1] != 'u') { usage_error("Warning: RIPng should be contained in a UDP packet\n"); } return TRUE; } int num_opts() { return sizeof(rip_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return rip_opts; } char get_optchar() { return opt_char; } sendip-2.5/ripng.h0100664000076400007640000000253607570212052012607 0ustar mikemike/* ripng.h */ #ifndef _SENDIP_RIPNG_H #define _SENDIP_RIPNG_H /* RIP PACKET STRUCTURES */ typedef struct { u_int8_t command; u_int8_t version; u_int16_t res; } ripng_header; typedef struct { struct in6_addr prefix; u_int16_t tag; u_int8_t len; u_int8_t metric; } ripng_entry; /* Defines for which parts have been modified */ #define RIPNG_MOD_COMMAND 1 #define RIPNG_MOD_VERSION 1<<1 #define RIPNG_MOD_RESERVED 1<<2 //#define RIP_MOD_ADDRFAM 1<<2 //#define RIP_MOD_ROUTETAG 1<<3 //#define RIP_IS_AUTH 1<<4 /* Options */ sendip_option rip_opts[] = { {"v",1,"RIPng version","1"}, {"c",1,"RIPng command (1=request, 2=response)","1"}, {"r",1,"RIPng reserved field (should be 0)","0"}, {"e",1,"Add a RIPng entry. Format is: Address/route tag/address/len/metric","::/0/128/1, any option my be left out to use the default"}, {"d",0,"RIPng default request - get router's entire routing table; do not use any other RIPng options on this RIPng header",NULL} }; /* Helpful macros */ #define RIPNG_NUM_ENTRIES(d) (((d)->alloc_len-sizeof(ripng_header))/sizeof(ripng_entry)) #define RIPNG_ADD_ENTRY(d) { (d)->data = realloc((d)->data,(d)->alloc_len+sizeof(ripng_entry)); (d)->alloc_len+=sizeof(ripng_entry); } #define RIPNG_ENTRY(d) ((ripng_entry *)((u_int32_t *)((d)->data)+((d)->alloc_len>>2)-(sizeof(ripng_entry)>>2))) #endif /* _SENDIP_RIPNG_H */ sendip-2.5/sendip.c0100664000076400007640000004162207711152706012752 0ustar mikemike/* sendip.c - main program code for sendip * Copyright 2001 Mike Ricketts * Distributed under the GPL. See LICENSE. * Bug reports, patches, comments etc to mike@earth.li * ChangeLog since 2.0 release: * 27/11/2001 compact_string() moved to compact.c * 27/11/2001 change search path for libs to include .so * 23/01/2002 make random fields more random (Bryan Croft ) * 10/08/2002 detect attempt to use multiple -d and -f options * ChangeLog since 2.2 release: * 24/11/2002 compile on archs requiring alignment * ChangeLog since 2.3 release: * 21/04/2003 random data (Anand (Andy) Rao ) * ChangeLog since 2.4 release: * 21/04/2003 fix errors detected by valgrind * 28/07/2003 fix compile error on solaris */ #define _SENDIP_MAIN /* socket stuff */ #include #include #include #include /* everything else */ #include #include #include #include #include #include #include #include #include /* isprint */ #include "sendip_module.h" #ifdef __sun__ /* for EVILNESS workaround */ #include "ipv4.h" #endif /* __sun__ */ /* Use our own getopt to ensure consistant behaviour on all platforms */ #include "gnugetopt.h" typedef struct _s_m { struct _s_m *next; struct _s_m *prev; char *name; char optchar; sendip_data * (*initialize)(void); bool (*do_opt)(const char *optstring, const char *optarg, sendip_data *pack); bool (*set_addr)(char *hostname, sendip_data *pack); bool (*finalize)(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack); sendip_data *pack; void *handle; sendip_option *opts; int num_opts; } sendip_module; /* sockaddr_storage struct is not defined everywhere, so here is our own nasty version */ typedef struct { u_int16_t ss_family; u_int32_t ss_align; char ss_padding[122]; } _sockaddr_storage; static int num_opts=0; static sendip_module *first; static sendip_module *last; static char *progname; static int sendpacket(sendip_data *data, char *hostname, int af_type, bool verbose) { _sockaddr_storage *to = malloc(sizeof(_sockaddr_storage)); int tolen; /* socket stuff */ int s; /* socket for sending */ /* hostname stuff */ struct hostent *host = NULL; /* result of gethostbyname2 */ /* casts for specific protocols */ struct sockaddr_in *to4 = (struct sockaddr_in *)to; /* IPv4 */ struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)to; /* IPv6 */ int sent; /* number of bytes sent */ if(to==NULL) { perror("OUT OF MEMORY!\n"); return -3; } memset(to, 0, sizeof(_sockaddr_storage)); if ((host = gethostbyname2(hostname, af_type)) == NULL) { perror("Couldn't get destination host: gethostbyname2()"); free(to); return -1; } switch (af_type) { case AF_INET: to4->sin_family = host->h_addrtype; memcpy(&to4->sin_addr, host->h_addr, host->h_length); tolen = sizeof(struct sockaddr_in); break; case AF_INET6: to6->sin6_family = host->h_addrtype; memcpy(&to6->sin6_addr, host->h_addr, host->h_length); tolen = sizeof(struct sockaddr_in6); break; default: return -2; break; } if(verbose) { int i, j; printf("Final packet data:\n"); for(i=0; ialloc_len; ) { for(j=0; j<4 && i+jalloc_len; j++) printf("%02X ", ((unsigned char *)(data->data))[i+j]); printf(" "); for(j=0; j<4 && i+jalloc_len; j++) { int c=(int) ((unsigned char *)(data->data))[i+j]; printf("%c", isprint(c)?((char *)(data->data))[i+j]:'.'); } printf("\n"); i+=j; } } if ((s = socket(af_type, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("Couldn't open RAW socket"); free(to); return -1; } /* Need this for OpenBSD, shouldn't cause problems elsewhere */ /* TODO: should make it a command line option */ if(af_type == AF_INET) { const int on=1; if (setsockopt(s, IPPROTO_IP,IP_HDRINCL,(const void *)&on,sizeof(on)) <0) { perror ("Couldn't setsockopt IP_HDRINCL"); free(to); close(s); return -2; } } /* On Solaris, it seems that the only way to send IP options or packets with a faked IP header length is to: setsockopt(IP_OPTIONS) with the IP option data and size decrease the total length of the packet accordingly I'm sure this *shouldn't* work. But it does. */ #ifdef __sun__ if((*((char *)(data->data))&0x0F) != 5) { ip_header *iphdr = (ip_header *)data->data; int optlen = iphdr->header_len*4-20; if(verbose) printf("Solaris workaround enabled for %d IP option bytes\n", optlen); iphdr->tot_len = htons(ntohs(iphdr->tot_len)-optlen); if(setsockopt(s,IPPROTO_IP,IP_OPTIONS, (void *)(((char *)(data->data))+20),optlen)) { perror("Couldn't setsockopt IP_OPTIONS"); free(to); close(s); return -2; } } #endif /* __sun__ */ /* Send the packet */ sent = sendto(s, (char *)data->data, data->alloc_len, 0, (void *)to, tolen); if (sent == data->alloc_len) { if(verbose) printf("Sent %d bytes to %s\n",sent,hostname); } else { if (sent < 0) perror("sendto"); else { if(verbose) fprintf(stderr, "Only sent %d of %d bytes to %s\n", sent, data->alloc_len, hostname); } } free(to); close(s); return sent; } static void unload_modules(bool freeit, int verbosity) { sendip_module *mod, *p; p = NULL; for(mod=first;mod!=NULL;mod=mod->next) { if(verbosity) printf("Freeing module %s\n",mod->name); if(p) free(p); p = mod; free(mod->name); if(freeit) free(mod->pack->data); free(mod->pack); (void)dlclose(mod->handle); /* Do not free options - TODO should we? */ } if(p) free(p); } static bool load_module(char *modname) { sendip_module *newmod = malloc(sizeof(sendip_module)); sendip_module *cur; int (*n_opts)(void); sendip_option * (*get_opts)(void); char (*get_optchar)(void); for(cur=first;cur!=NULL;cur=cur->next) { if(!strcmp(modname,cur->name)) { memcpy(newmod,cur,sizeof(sendip_module)); newmod->num_opts=0; goto out; } } newmod->name=malloc(strlen(modname)+strlen(SENDIP_LIBS)+strlen(".so")+2); strcpy(newmod->name,modname); if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { char *error0=strdup(dlerror()); sprintf(newmod->name,"./%s.so",modname); if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { char *error1=strdup(dlerror()); sprintf(newmod->name,"%s/%s.so",SENDIP_LIBS,modname); if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { char *error2=strdup(dlerror()); sprintf(newmod->name,"%s/%s",SENDIP_LIBS,modname); if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { char *error3=strdup(dlerror()); fprintf(stderr,"Couldn't open module %s, tried:\n",modname); fprintf(stderr," %s\n %s\n %s\n %s\n", error0, error1, error2, error3); free(newmod); free(error3); return FALSE; } free(error2); } free(error1); } free(error0); } strcpy(newmod->name,modname); if(NULL==(newmod->initialize=dlsym(newmod->handle,"initialize"))) { fprintf(stderr,"%s doesn't have an initialize function: %s\n",modname, dlerror()); dlclose(newmod->handle); free(newmod); return FALSE; } if(NULL==(newmod->do_opt=dlsym(newmod->handle,"do_opt"))) { fprintf(stderr,"%s doesn't contain a do_opt function: %s\n",modname, dlerror()); dlclose(newmod->handle); free(newmod); return FALSE; } newmod->set_addr=dlsym(newmod->handle,"set_addr"); // don't care if fails if(NULL==(newmod->finalize=dlsym(newmod->handle,"finalize"))) { fprintf(stderr,"%s\n",dlerror()); dlclose(newmod->handle); free(newmod); return FALSE; } if(NULL==(n_opts=dlsym(newmod->handle,"num_opts"))) { fprintf(stderr,"%s\n",dlerror()); dlclose(newmod->handle); free(newmod); return FALSE; } if(NULL==(get_opts=dlsym(newmod->handle,"get_opts"))) { fprintf(stderr,"%s\n",dlerror()); dlclose(newmod->handle); free(newmod); return FALSE; } if(NULL==(get_optchar=dlsym(newmod->handle,"get_optchar"))) { fprintf(stderr,"%s\n",dlerror()); dlclose(newmod->handle); free(newmod); return FALSE; } newmod->num_opts = n_opts(); newmod->optchar=get_optchar(); /* TODO: check uniqueness */ newmod->opts = get_opts(); num_opts+=newmod->num_opts; out: newmod->pack=NULL; newmod->prev=last; newmod->next=NULL; last = newmod; if(last->prev) last->prev->next = last; if(!first) first=last; return TRUE; } static void print_usage(void) { sendip_module *mod; int i; printf("Usage: %s [-v] [-d data] [-h] [-f datafile] [-p module] [module options] hostname\n",progname); printf(" -d data\tadd this data as a string to the end of the packet\n"); printf("\t\tData can be:\n"); printf("\t\trN to generate N random(ish) data bytes;\n"); printf("\t\t0x or 0X followed by hex digits;\n"); printf("\t\t0 followed by octal digits;\n"); printf("\t\tany other stream of bytes\n"); printf(" -f datafile\tread packet data from file\n"); printf(" -h\t\tprint this message\n"); printf(" -p module\tload the specified module (see below)\n"); printf(" -v\t\tbe verbose\n"); printf("\n\nModules are loaded in the order the -p option appears. The headers from\n"); printf("each module are put immediately inside the headers from the previos model in\n"); printf("the final packet. For example, to embed bgp inside tcp inside ipv4, do\n"); printf("sendip -p ipv4 -p tcp -p bgp ....\n"); printf("\n\nModules available at compile time:\n"); printf("\tipv4 ipv6 icmp tcp udp bgp rip ntp\n\n"); for(mod=first;mod!=NULL;mod=mod->next) { printf("\n\nArguments for module %s:\n",mod->name); for(i=0;inum_opts;i++) { printf(" -%c%s %c\t%s\n",mod->optchar, mod->opts[i].optname,mod->opts[i].arg?'x':' ', mod->opts[i].description); if(mod->opts[i].def) printf(" \t\t Default: %s\n", mod->opts[i].def); } } } int main(int argc, char *const argv[]) { int i; struct option *opts=NULL; int longindex=0; char rbuff[31]; bool usage=FALSE, verbosity=FALSE; char *data=NULL; int datafile=-1; int datalen=0; bool randomflag=FALSE; sendip_module *mod; int optc; int num_modules=0; sendip_data packet; num_opts = 0; first=last=NULL; progname=argv[0]; /* magic random seed that gives 4 really random octets */ srandom(time(NULL) ^ (getpid()+(42<<15))); /* First, get all the builtin options, and load the modules */ gnuopterr=0; gnuoptind=0; while(gnuoptind when n is number of bytes */ datalen = atoi(data+1); if(datalen < 1) { fprintf(stderr,"Random data with length %d invalid\nNo data will be included\n",datalen); data=NULL; datalen=0; } data=(char *)malloc(datalen); for(i=0;inext) { int j; char *s; // nasty kludge because option.name is const for(j=0;jnum_opts;j++) { /* +2 on next line is one for the char, one for the trailing null */ opts[i].name = s = malloc(strlen(mod->opts[j].optname)+2); sprintf(s,"%c%s",mod->optchar,mod->opts[j].optname); opts[i].has_arg = mod->opts[j].arg; opts[i].flag = NULL; opts[i].val = mod->optchar; i++; } } if(verbosity) printf("Added %d options\n",num_opts); /* Initialize all */ for(mod=first;mod!=NULL;mod=mod->next) { if(verbosity) printf("Initializing module %s\n",mod->name); mod->pack=mod->initialize(); } /* Do the get opt */ gnuopterr=1; gnuoptind=0; while(EOF != (optc=getopt_long_only(argc,argv,"p:vd:hf:",opts,&longindex))) { switch(optc) { case 'p': case 'v': case 'd': case 'f': case 'h': /* Processed above */ break; case ':': usage=TRUE; fprintf(stderr,"Option %s requires an argument\n", opts[longindex].name); break; case '?': usage=TRUE; fprintf(stderr,"Option starting %c not recognized\n",gnuoptopt); break; default: for(mod=first;mod!=NULL;mod=mod->next) { if(mod->optchar==optc) { /* Random option arguments */ if(gnuoptarg != NULL && !strcmp(gnuoptarg,"r")) { /* need a 32 bit number, but random() is signed and nonnegative so only 31bits - we simply repeat one */ unsigned long r = (unsigned long)random()<<1; r+=(r&0x00000040)>>6; sprintf(rbuff,"%lu",r); gnuoptarg = rbuff; } if(!mod->do_opt(opts[longindex].name,gnuoptarg,mod->pack)) { usage=TRUE; } } } } } /* gnuoptind is the first thing that is not an option - should have exactly one hostname... */ if(argc != gnuoptind+1) { usage=TRUE; if(argc-gnuoptind < 1) fprintf(stderr,"No hostname specified\n"); else fprintf(stderr,"More than one hostname specified\n"); } else { if(first && first->set_addr) { first->set_addr(argv[gnuoptind],first->pack); } } /* free opts now we have finished with it */ for(i=0;i<(1+num_opts);i++) { if(opts[i].name != NULL) free((void *)opts[i].name); } free(opts); /* don't need them any more */ if(usage) { print_usage(); unload_modules(TRUE,verbosity); if(datafile != -1) { munmap(data,datalen); close(datafile); datafile=-1; } if(randomflag) free(data); return 0; } /* EVIL EVIL EVIL! */ /* Stick all the bits together. This means that finalize better not change the size or location of any packet's data... */ packet.data = NULL; packet.alloc_len = 0; packet.modified = 0; for(mod=first;mod!=NULL;mod=mod->next) { packet.alloc_len+=mod->pack->alloc_len; } if(data != NULL) packet.alloc_len+=datalen; packet.data = malloc(packet.alloc_len); for(i=0, mod=first;mod!=NULL;mod=mod->next) { memcpy((char *)packet.data+i,mod->pack->data,mod->pack->alloc_len); free(mod->pack->data); mod->pack->data = (char *)packet.data+i; i+=mod->pack->alloc_len; } /* Add any data */ if(data != NULL) memcpy((char *)packet.data+i,data,datalen); if(datafile != -1) { munmap(data,datalen); close(datafile); datafile=-1; } if(randomflag) free(data); /* Finalize from inside out */ { char hdrs[num_modules]; sendip_data *headers[num_modules]; sendip_data d; d.alloc_len = datalen; d.data = (char *)packet.data+packet.alloc_len-datalen; for(i=0,mod=first;mod!=NULL;mod=mod->next,i++) { hdrs[i]=mod->optchar; headers[i]=mod->pack; } for(i=num_modules-1,mod=last;mod!=NULL;mod=mod->prev,i--) { if(verbosity) printf("Finalizing module %s\n",mod->name); /* Remove this header from enclosing list */ hdrs[i]='\0'; headers[i] = NULL; mod->finalize(hdrs, headers, &d, mod->pack); /* Get everything ready for the next call */ d.data=(char *)d.data-mod->pack->alloc_len; d.alloc_len+=mod->pack->alloc_len; } } /* And send the packet */ { int af_type; if(first==NULL) { if(data == NULL) { fprintf(stderr,"Nothing specified to send!\n"); print_usage(); free(packet.data); unload_modules(FALSE,verbosity); return 1; } else { af_type = AF_INET; } } else if(first->optchar=='i') af_type = AF_INET; else if(first->optchar=='6') af_type = AF_INET6; else { fprintf(stderr,"Either IPv4 or IPv6 must be the outermost packet\n"); unload_modules(FALSE,verbosity); free(packet.data); return 1; } i = sendpacket(&packet,argv[gnuoptind],af_type,verbosity); free(packet.data); } unload_modules(FALSE,verbosity); return 0; } sendip-2.5/sendip.spec.in0100644000076400007640000000531607573204741014070 0ustar mikemike%define name sendip Summary: A command line tool to allow sending arbitrary IP packets Name: %name Version: %ver Release: 1 Copyright: GPL Group: Applications/Internet Source: http://www.earth.li/projectpurple/files/sendip-%ver.tar.gz URL: http://www.earth.li/projectpurple/progs/sendip.html Vendor: Project Purple Packager: Mike Ricketts BuildRoot: /var/tmp/sendip-root %description A command line tool to send arbitrary IP packets. It has a large number of command line options to specify the content of every header of a NTP, BGP, RIP, RIPng, TCP, UDP, ICMP, or raw IPv4 or IPv6 packet. It also allows any data to be added to the packet. %changelog * Tue Dec 3 2002 Mike Ricketts - Update to version 2.3 - RIPng fixes - Compile on archs requiring alignment * Sat Oct 12 2002 Mike Ricketts - Update to version 2.2 - See CHANGES for a more complete list (there's even more than last time) * Sun Feb 24 2002 Calum Selkirk - changed /usr/share/man to %{_mandir} and added perl to edit Makefile to refect this - wrapped %discription to tw=78 - rm buildroot before install - other minor tweeks * Sat Feb 23 2002 Mike Ricketts - Update to version 2.1 - See CHANGES for a more complete list (there's a *lot*) * Fri Nov 23 2001 Juan Antonio Martinez - Made it FHS aware * Tue Jul 10 2001 Mike Ricketts - Update to version 2.0 - See CHANGES for a more complete list * Mon Dec 25 2000 Mike Ricketts - Updated to version 1.4 - RIP default - bugfixes - contrib * Wed Nov 29 2000 Mike Ricketts - Updated to version 1.3 - IPv6, TCP options and other enhancements - Bugfixes - See CHANGES for more details * Sun Oct 22 2000 Mike Ricketts - Updated to version 1.1 - RIP support (Richard Polton) - Bugfixes * Sat Jun 08 2000 Mike Ricketts - Updated to version 1.0 * Mon Apr 10 2000 Mike Ricketts - Minor specfile changes, merged with main sendip release * Thu Apr 06 2000 Devlin Upton - First RPM release. %prep %setup %build mkdir -p $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/share/man/man1 mkdir -p $RPM_BUILD_ROOT/usr/lib make PREFIX=/usr MANDIR=%{_mandir}/man1 %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/{bin,lib} mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 make PREFIX=$RPM_BUILD_ROOT/usr MANDIR=$RPM_BUILD_ROOT%{_mandir}/man1 install %clean rm -fr $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc VERSION README CHANGES LICENSE TODO %doc /usr/share/man/man1/sendip.1* %attr(755,root,root) /usr/bin/sendip %attr(755,root,root) /usr/lib/sendip/*.so %dir /usr/lib/sendip sendip-2.5/sendip_module.h0100664000076400007640000000157407570212052014320 0ustar mikemike#ifndef _SENDIP_MODULE_H #define _SENDIP_MODULE_H #include // for fprintf #include "types.h" /* Options */ typedef struct { const char *optname; const bool arg; const char *description; const char *def; } sendip_option; /* Data */ typedef struct { void *data; int alloc_len; unsigned int modified; } sendip_data; /* Prototypes */ #ifndef _SENDIP_MAIN sendip_data *initialize(void); bool do_opt(char *optstring, char *optarg, sendip_data *pack); bool set_addr(char *hostname, sendip_data *pack); bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack); int num_opts(void); sendip_option *get_opts(void); char get_optchar(void); #endif /* _SENDIP_MAIN */ #define usage_error(x) fprintf(stderr,x) extern u_int16_t csum(u_int16_t *packet, int packlen); extern int compact_string(char *data_out); #endif /* _SENDIP_MODULE_H */ sendip-2.5/tcp.c0100664000076400007640000002343007671436157012265 0ustar mikemike/* tcp.c - tcp support for sendip * Author: Mike Ricketts * TCP options taken from code by Alexander Talos * ChangeLog since 2.0 release: * 27/11/2001: Added -tonum option * 02/12/2001: Only check 1 layer for enclosing IPV4 header * ChangeLog since 2.1 release: * 16/04/2002: Tidy up checksum code (like in icmp.c) * 16/04/2002: Add support for TCP over IPV6 (code from armite ) * 26/08/2002: Fix bug where tcp length was wrong with tcp options * ChangeLog since 2.2 release: * 24/11/2002: made it compile on archs that care about alignment * ChangeLog since 2.4 release: * 21/04/2003: fix errors found by valgrind * 10/06/2003: fix -tonum (pointed out by Yaniv Kaul ) */ #include #include #include #include #include "sendip_module.h" #include "tcp.h" #include "ipv4.h" #include "ipv6.h" /* Character that identifies our options */ const char opt_char='t'; static void tcpcsum(sendip_data *ip_hdr, sendip_data *tcp_hdr, sendip_data *data) { tcp_header *tcp = (tcp_header *)tcp_hdr->data; ip_header *ip = (ip_header *)ip_hdr->data; u_int16_t *buf = malloc(12+tcp_hdr->alloc_len+data->alloc_len); u_int8_t *tempbuf = (u_int8_t *)buf; tcp->check=0; if(tempbuf == NULL) { fprintf(stderr,"Out of memory: TCP checksum not computed\n"); return; } /* Set up the pseudo header */ memcpy(tempbuf,&(ip->saddr),sizeof(u_int32_t)); memcpy(&(tempbuf[4]),&(ip->daddr),sizeof(u_int32_t)); tempbuf[8]=0; tempbuf[9]=(u_int16_t)ip->protocol; tempbuf[10]=(u_int16_t)((tcp_hdr->alloc_len+data->alloc_len)&0xFF00)>>8; tempbuf[11]=(u_int16_t)((tcp_hdr->alloc_len+data->alloc_len)&0x00FF); /* Copy the TCP header and data */ memcpy(tempbuf+12,tcp_hdr->data,tcp_hdr->alloc_len); memcpy(tempbuf+12+tcp_hdr->alloc_len,data->data,data->alloc_len); /* CheckSum it */ tcp->check = csum(buf,12+tcp_hdr->alloc_len+data->alloc_len); free(buf); } static void tcp6csum(sendip_data *ipv6_hdr, sendip_data *tcp_hdr, sendip_data *data) { tcp_header *tcp = (tcp_header *)tcp_hdr->data; ipv6_header *ipv6 = (ipv6_header *)ipv6_hdr->data; struct ipv6_pseudo_hdr phdr; u_int16_t *buf = malloc(sizeof(phdr)+tcp_hdr->alloc_len+data->alloc_len); u_int8_t *tempbuf = (u_int8_t *)buf; tcp->check=0; if(tempbuf == NULL) { fprintf(stderr,"Out of memory: TCP checksum not computed\n"); return; } /* Set up the pseudo header */ memset(&phdr,0,sizeof(phdr)); memcpy(&phdr.source,&ipv6->ip6_src,sizeof(struct in6_addr)); memcpy(&phdr.destination,&ipv6->ip6_dst,sizeof(struct in6_addr)); phdr.ulp_length=IPPROTO_TCP; memcpy(tempbuf,&phdr,sizeof(phdr)); /* Copy the TCP header and data */ memcpy(tempbuf+sizeof(phdr),tcp_hdr->data,tcp_hdr->alloc_len); memcpy(tempbuf+sizeof(phdr)+tcp_hdr->alloc_len,data->data,data->alloc_len); /* CheckSum it */ tcp->check = csum(buf,sizeof(phdr)+tcp_hdr->alloc_len+data->alloc_len); free(buf); } static void addoption(u_int8_t opt, u_int8_t len, u_int8_t *data, sendip_data *pack) { pack->data = realloc(pack->data, pack->alloc_len + len); *((u_int8_t *)pack->data+pack->alloc_len) = opt; if(len > 1) *((u_int8_t *)pack->data+pack->alloc_len+1)=len; if(len > 2) memcpy((u_int8_t *)pack->data+pack->alloc_len+2,data,len-2); pack->alloc_len += len; } sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); tcp_header *tcp = malloc(sizeof(tcp_header)); memset(tcp,0,sizeof(tcp_header)); ret->alloc_len = sizeof(tcp_header); ret->data = (void *)tcp; ret->modified=0; return ret; } bool do_opt(char *opt, char *arg, sendip_data *pack) { tcp_header *tcp = (tcp_header *)pack->data; // opt[0]==t switch(opt[1]) { case 's': tcp->source = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= TCP_MOD_SOURCE; break; case 'd': tcp->dest = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= TCP_MOD_DEST; break; case 'n': tcp->seq = htonl((u_int32_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= TCP_MOD_SEQ; break; case 'a': tcp->ack_seq = htonl((u_int32_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= TCP_MOD_ACKSEQ; if(!(pack->modified&TCP_MOD_ACK)) { tcp->ack = 1; pack->modified |= TCP_MOD_ACK; } break; case 't': tcp->off = (u_int16_t)strtoul(arg, (char **)NULL, 0) &0xF; pack->modified |= TCP_MOD_OFF; break; case 'r': tcp->res = (u_int16_t)(strtoul(arg, (char **)NULL, 0) & 0x000F); pack->modified |= TCP_MOD_RES; break; case 'f': switch(opt[2]) { case 'e': tcp->ecn=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_ECN; break; case 'c': tcp->cwr=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_CWR; break; case 'u': tcp->urg=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_URG; break; case 'a': tcp->ack=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_ACK; break; case 'p': tcp->psh=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_PSH; break; case 'r': tcp->rst=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_RST; break; case 's': tcp->syn=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_SYN; break; case 'f': tcp->fin=(u_int16_t)*arg&1; pack->modified |= TCP_MOD_FIN; break; default: usage_error("TCP flag not known\n"); return FALSE; } break; case 'w': tcp->window = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= TCP_MOD_WINDOW; break; case 'c': tcp->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= TCP_MOD_CHECK; break; case 'u': tcp->urg_ptr = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= TCP_MOD_URGPTR; if(!(pack->modified&TCP_MOD_URG)) { tcp->urg = 1; pack->modified |= TCP_MOD_URG; } break; case 'o': /* TCP OPTIONS */ if(!strcmp(opt+2, "num")) { /* Other options (auto length) */ u_int8_t *data = malloc(strlen(arg)+2); int len; if(!data) { fprintf(stderr,"Out of memory!\n"); return FALSE; } sprintf(data,"0x%s",arg); len = compact_string(data); if(len==1) addoption(*data,1,NULL,pack); else addoption(*data,len+1,data+1,pack); free(data); } else if (!strcmp(opt+2, "eol")) { /* End of options list RFC 793 kind 0, no length */ addoption(0,1,NULL,pack); } else if (!strcmp(opt+2, "nop")) { /* No op RFC 793 kind 1, no length */ addoption(1,1,NULL,pack); } else if (!strcmp(opt+2, "mss")) { /* Maximum segment size RFC 793 kind 2 */ u_int16_t mss=htons(atoi(arg)); addoption(2,4,(u_int8_t *)&mss,pack); } else if (!strcmp(opt+2, "wscale")) { /* Window scale rfc1323 */ u_int8_t wscale=atoi(arg); addoption(3,3,&wscale,pack); } else if (!strcmp(opt+2, "sackok")) { /* Selective Acknowledge permitted rfc1323 */ addoption(4,2,NULL,pack); } else if (!strcmp(opt+2, "sack")) { /* Selective Acknowledge rfc1323 */ unsigned char *next; u_int32_t le, re; u_int8_t *comb, *c; int count=0; /* count the options */ next=arg; while(next) { next=strchr(next,','); count++; if(next) next++; } comb = malloc(count*8); c = comb; next=arg; while(*next) { /* get left edge */ next=strchr(arg, ':'); if (!next) { fprintf(stderr, "Value in tcp sack option incorrect. Usage: \n"); fprintf(stderr, " -tosack left:right[,left:right...]\n"); return FALSE; } *next++=0; le=atoi(arg); arg=next; /* get right edge */ next=strchr(arg, ','); if (!next) next=arg-1; /* Finito - next points to \0 */ else *next++=0; re=atoi(arg); arg=next; le=htonl(le); re=htonl(re); memcpy(c, &le, 4); memcpy(c+4, &re, 4); c+=8; } addoption(5,count*8+2,comb,pack); free(comb); } else if (!strcmp(opt+2, "ts")) { /* Timestamp rfc1323 */ u_int32_t tsval=0, tsecr=0; u_int8_t comb[8]; if (2!=sscanf(arg, "%d:%d", &tsval, &tsecr)) { fprintf(stderr, "Invalid value for tcp timestamp option.\n"); fprintf(stderr, "Usage: -tots tsval:tsecr\n"); return FALSE; } tsval=htonl(tsval); memcpy(comb, &tsval, 4); tsecr=htonl(tsecr); memcpy(comb+4, &tsecr, 4); addoption(8,10,comb,pack); } else { /* Unrecognized -to* */ fprintf(stderr, "unsupported TCP Option %s val %s\n", opt, arg); return FALSE; } break; default: usage_error("unknown TCP option\n"); return FALSE; break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { tcp_header *tcp = (tcp_header *)pack->data; /* Set relevant fields */ if(!(pack->modified&TCP_MOD_SEQ)) { tcp->seq = (u_int32_t)rand(); } if(!(pack->modified&TCP_MOD_OFF)) { tcp->off = (u_int16_t)((pack->alloc_len+3)/4) & 0x0F; } if(!(pack->modified&TCP_MOD_SYN)) { tcp->syn=1; } if(!(pack->modified&TCP_MOD_WINDOW)) { tcp->window=htons((u_int16_t)65535); } /* Find enclosing IP header and do the checksum */ if(hdrs[strlen(hdrs)-1]=='i') { int i = strlen(hdrs)-1; if(!(headers[i]->modified&IP_MOD_PROTOCOL)) { ((ip_header *)(headers[i]->data))->protocol=IPPROTO_TCP; headers[i]->modified |= IP_MOD_PROTOCOL; } if(!(pack->modified&TCP_MOD_CHECK)) { tcpcsum(headers[i],pack,data); } } else if(hdrs[strlen(hdrs)-1]=='6') { int i = strlen(hdrs)-1; if(!(headers[i]->modified&IPV6_MOD_NXT)) { ((ipv6_header *)(headers[i]->data))->ip6_nxt=IPPROTO_TCP; headers[i]->modified |= IPV6_MOD_NXT; } if(!(pack->modified&TCP_MOD_CHECK)) { tcp6csum(headers[i],pack,data); } } else { if(!(pack->modified&TCP_MOD_CHECK)) { usage_error("TCP checksum not defined when TCP is not embedded in IP\n"); return FALSE; } } return TRUE; } int num_opts() { return sizeof(tcp_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return tcp_opts; } char get_optchar() { return opt_char; } sendip-2.5/tcp.h0100664000076400007640000000544307525532272012267 0ustar mikemike/* tcp.h */ #ifndef _SENDIP_TCP_H #define _SENDIP_TCP_H #ifndef NULL #define NULL (0L) #endif /* TCP HEADER * Ripped straight out of glibc-2.2.2, modified for RFC22481 * Reproduced here to prevent nasty #defines on non-linux boxes */ typedef struct { u_int16_t source; u_int16_t dest; u_int32_t seq; u_int32_t ack_seq; #if __BYTE_ORDER == __LITTLE_ENDIAN u_int16_t res:4; u_int16_t off:4; u_int16_t fin:1; u_int16_t syn:1; u_int16_t rst:1; u_int16_t psh:1; u_int16_t ack:1; u_int16_t urg:1; u_int16_t cwr:1; u_int16_t ecn:1; #elif __BYTE_ORDER == __BIG_ENDIAN u_int16_t off:4; u_int16_t res:4; u_int16_t ecn:1; u_int16_t cwr:1; u_int16_t urg:1; u_int16_t ack:1; u_int16_t psh:1; u_int16_t rst:1; u_int16_t syn:1; u_int16_t fin:1; #else # error "Adjust your defines" #endif u_int16_t window; u_int16_t check; u_int16_t urg_ptr; } tcp_header; /* Defines for which parts have been modified */ #define TCP_MOD_SOURCE 1 #define TCP_MOD_DEST 1<<1 #define TCP_MOD_SEQ 1<<2 #define TCP_MOD_ACKSEQ 1<<3 #define TCP_MOD_RES 1<<4 #define TCP_MOD_OFF 1<<5 #define TCP_MOD_FIN 1<<6 #define TCP_MOD_SYN 1<<7 #define TCP_MOD_RST 1<<8 #define TCP_MOD_PSH 1<<9 #define TCP_MOD_ACK 1<<10 #define TCP_MOD_URG 1<<11 #define TCP_MOD_ECN 1<<12 #define TCP_MOD_CWR 1<<13 #define TCP_MOD_WINDOW 1<<14 #define TCP_MOD_CHECK 1<<15 #define TCP_MOD_URGPTR 1<<16 /* Options */ sendip_option tcp_opts[] = { {"s",1,"TCP source port","0"}, {"d",1,"TCP destination port","0"}, {"n",1,"TCP sequence number","Random"}, {"a",1,"TCP ack number","0"}, {"t",1,"TCP data offset","Correct"}, {"r",1,"TCP header reserved field EXCLUDING ECN and CWR bits","0"}, {"fe",1,"TCP ECN bit (rfc2481)","0 (options are 0,1,r)"}, {"fc",1,"TCP CWR bit (rfc2481)","0 (options are 0,1,r)"}, {"fu",1,"TCP URG bit","0, or 1 if -tu specified (options are 0,1,r)"}, {"fa",1,"TCP ACK bit","0, or 1 if -ta specified (options are 0,1,r)"}, {"fp",1,"TCP PSH bit","0 (options are 0,1,r)"}, {"fr",1,"TCP RST bit","0 (options are 0,1,r)"}, {"fs",1,"TCP SYN bit","1 (options are 0,1,r)"}, {"ff",1,"TCP FIN bit","0 (options are 0,1,r)"}, {"w",1,"TCP window size","65535"}, {"c",1,"TCP checksum","Correct"}, {"u",1,"TCP urgent pointer","0"}, {"onum",1,"TCP option as string of hex bytes (length is always correct)","(no options)"}, {"oeol",0,"TCP option: end of list", NULL }, {"onop",0,"TCP option: no op", NULL }, {"omss",1,"TCP option: maximum segment size", NULL }, {"owscale",1,"TCP option: window scale (rfc1323)", NULL }, {"osackok",0,"TCP option: allow selective ack (rfc2018)", NULL }, {"osack",1,"TCP option: selective ack (rfc2018), format is l_edge1:r_edge1,l_edge2:r_edge2...", NULL }, {"ots",1,"TCP option: timestamp (rfc1323), format is tsval:tsecr", NULL } }; #endif /* _SENDIP_TCP_H */ sendip-2.5/types.h0100644000076400007640000000434307552056120012632 0ustar mikemike/* types.h - tpyes needed in sendip and not defined everywhere * Author: Mike Ricketts * ChangeLog since 2.1 release: * 03/02/2002 Added more defines/protos for non-IPv6 systems. * 26/03/2002 FreeBSD style BYTE_ORDER fixes */ #ifndef _SENDIP_TYPES_H #define _SENDIP_TYPES_H /* Make sure we have bool */ typedef int bool; #ifndef FALSE #define TRUE (0==0) #define FALSE (!TRUE) #endif /* Solaris doesn't define these */ #ifdef __sun__ typedef uint16_t u_int16_t; typedef uint32_t u_int32_t; typedef uint8_t u_int8_t; /* disable ipv6 on solaris */ #define gethostbyname2(x,y) gethostbyname(x) #endif /* __sun__ */ /* for things that *really* don't know about ipv6, ... */ #ifndef AF_INET6 #define AF_INET6 10 #define IPPROTO_ICMPV6 58 #define IPPROTO_NONE 59 #define IPPROTO_DSTOPTS 60 #endif /* !AF_INET6 */ #ifndef s6_addr struct in6_addr { union { u_int8_t u6_addr8[16]; u_int16_t u6_addr16[8]; u_int32_t u6_addr32[4]; } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_add16 in6_u.u6_addr16 #define s6_add32 in6_u.u6_addr32 }; extern const struct in6_addr in6addr_any; /* :: */ extern const struct in6_addr in6addr_loopback; /* ::1 */ struct sockaddr_in6 { u_int16_t sin6_family; u_int16_t sin6_port; u_int32_t sin6_flowinfo; struct in6_addr sin6_addr; u_int32_t sin6_scope_id; }; extern int inet_pton (int af, const char *cp, void *buf); #endif /* !s6_addr */ /* Convert _BIG_ENDIAN/_LITTLE_ENDIAN to __BYTE_ORDER */ #ifndef __LITTLE_ENDIAN #define __LITTLE_ENDIAN 1234 #endif #ifndef __BIG_ENDIAN #define __BIG_ENDIAN 4321 #endif #ifndef __BYTE_ORDER /* Not linux-style, maybe FreeBSD-style */ #ifdef BYTE_ORDER #undef __LITTLE_ENDIAN #undef __BIG_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN #define __BIG_ENDIAN BIG_ENDIAN #define __BYTE_ORDER BYTE_ORDER #else /* Not FreeBSD-style, try solaris style */ #ifdef _BIG_ENDIAN #define __BYTE_ORDER __BIG_ENDIAN #else /* not _BIG_ENDIAN */ #ifdef _LITTLE_ENDIAN #define __BYTE_ORDER __LITTLE_ENDIAN #else /* not _LITTLE_ENDIAN */ /* Not solaris style. Give up. */ #error Could not guess your byte order #endif /* not _LITTLE_ENDIAN */ #endif /* not _BIG_ENDIAN */ #endif /* not BYTE_ORDER */ #endif /* not __BYTE_ORDER */ #endif /* _SENDIP_TYPES_H */ sendip-2.5/udp.c0100664000076400007640000001107107651056165012260 0ustar mikemike/* udp.c - UDP code for sendip * Author: Mike Ricketts * ChangeLog since 2.0 release: * ChangeLog since 2.1 release: * 16/04/2002: Only check one layer of enclosing headers for ip * 16/04/2002: Add support for UDP over IPV6 * ChangeLog since 2.4 release: * 21/04/2003: Fix errors found by valgrind */ #include #include #include #include #include "sendip_module.h" #include "udp.h" #include "ipv4.h" #include "ipv6.h" /* Character that identifies our options */ const char opt_char='u'; static void udpcsum(sendip_data *ip_hdr, sendip_data *udp_hdr, sendip_data *data) { udp_header *udp = (udp_header *)udp_hdr->data; ip_header *ip = (ip_header *)ip_hdr->data; u_int16_t *buf = malloc(12+udp_hdr->alloc_len+data->alloc_len); u_int8_t *tempbuf = (u_int8_t *)buf; udp->check=0; if(tempbuf == NULL) { fprintf(stderr,"Out of memory: UDP checksum not computed\n"); return; } /* Set up the pseudo header */ memcpy(tempbuf,&(ip->saddr),sizeof(u_int32_t)); memcpy(&(tempbuf[4]),&(ip->daddr),sizeof(u_int32_t)); tempbuf[8]=0; tempbuf[9]=(u_int16_t)ip->protocol; tempbuf[10]=(u_int16_t)((udp_hdr->alloc_len+data->alloc_len)&0xFF00)>>8; tempbuf[11]=(u_int16_t)((udp_hdr->alloc_len+data->alloc_len)&0x00FF); /* Copy the UDP header and data */ memcpy(tempbuf+12,udp_hdr->data,udp_hdr->alloc_len); memcpy(tempbuf+12+udp_hdr->alloc_len,data->data,data->alloc_len); /* CheckSum it */ udp->check = csum(buf,12+udp_hdr->alloc_len+data->alloc_len); free(buf); } static void udp6csum(sendip_data *ipv6_hdr, sendip_data *udp_hdr, sendip_data *data) { udp_header *udp = (udp_header *)udp_hdr->data; ipv6_header *ipv6 = (ipv6_header *)ipv6_hdr->data; struct ipv6_pseudo_hdr phdr; u_int16_t *buf = malloc(sizeof(phdr)+udp_hdr->alloc_len+data->alloc_len); u_int8_t *tempbuf = (u_int8_t *)buf; udp->check=0; if(tempbuf == NULL) { fprintf(stderr,"Out of memory: UDP checksum not computed\n"); return; } /* Set up the pseudo header */ memset(&phdr,0,sizeof(phdr)); memcpy(&phdr.source,&ipv6->ip6_src,sizeof(struct in6_addr)); memcpy(&phdr.destination,&ipv6->ip6_dst,sizeof(struct in6_addr)); phdr.ulp_length=IPPROTO_UDP; memcpy(tempbuf,&phdr,sizeof(phdr)); /* Copy the UDP header and data */ memcpy(tempbuf+sizeof(phdr),udp_hdr->data,udp_hdr->alloc_len); memcpy(tempbuf+sizeof(phdr)+udp_hdr->alloc_len,data->data,data->alloc_len); /* CheckSum it */ udp->check = csum(buf,sizeof(phdr)+udp_hdr->alloc_len+data->alloc_len); free(buf); } sendip_data *initialize(void) { sendip_data *ret = malloc(sizeof(sendip_data)); udp_header *udp = malloc(sizeof(udp_header)); memset(udp,0,sizeof(udp_header)); ret->alloc_len = sizeof(udp_header); ret->data = (void *)udp; ret->modified=0; return ret; } bool do_opt(char *opt, char *arg, sendip_data *pack) { udp_header *udp = (udp_header *)pack->data; switch(opt[1]) { case 's': udp->source = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= UDP_MOD_SOURCE; break; case 'd': udp->dest = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= UDP_MOD_DEST; break; case 'l': udp->len = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= UDP_MOD_LEN; break; case 'c': udp->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); pack->modified |= UDP_MOD_CHECK; break; } return TRUE; } bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, sendip_data *pack) { udp_header *udp = (udp_header *)pack->data; /* Set relevant fields */ if(!(pack->modified&UDP_MOD_LEN)) { udp->len=htons(pack->alloc_len+data->alloc_len); } /* Find enclosing IP header and do the checksum */ if(hdrs[strlen(hdrs)-1]=='i') { int i = strlen(hdrs)-1; if(!(headers[i]->modified&IP_MOD_PROTOCOL)) { ((ip_header *)(headers[i]->data))->protocol=IPPROTO_UDP; headers[i]->modified |= IP_MOD_PROTOCOL; } if(!(pack->modified&UDP_MOD_CHECK)) { udpcsum(headers[i],pack,data); } } else if(hdrs[strlen(hdrs)-1]=='6') { int i = strlen(hdrs)-1; if(!(headers[i]->modified&IPV6_MOD_NXT)) { ((ipv6_header *)(headers[i]->data))->ip6_nxt=IPPROTO_UDP; headers[i]->modified |= IPV6_MOD_NXT; } if(!(pack->modified&UDP_MOD_CHECK)) { udp6csum(headers[i],pack,data); } } else { if(!(pack->modified&UDP_MOD_CHECK)) { usage_error("UDP checksum not defined when UDP is not embedded in IP\n"); return FALSE; } } return TRUE; } int num_opts() { return sizeof(udp_opts)/sizeof(sendip_option); } sendip_option *get_opts() { return udp_opts; } char get_optchar() { return opt_char; } sendip-2.5/udp.h0100664000076400007640000000110507402504503012246 0ustar mikemike/* udp.h */ #ifndef _SENDIP_UDP_H #define _SENDIP_UDP_H /* UDP HEADER */ typedef struct { u_int16_t source; u_int16_t dest; u_int16_t len; u_int16_t check; } udp_header; /* Defines for which parts have been modified */ #define UDP_MOD_SOURCE 1 #define UDP_MOD_DEST 1<<1 #define UDP_MOD_LEN 1<<2 #define UDP_MOD_CHECK 1<<3 /* Options */ sendip_option udp_opts[] = { {"s",1,"UDP source port","0"}, {"d",1,"UDP destination port","0"}, {"l",1,"UDP packet legnth","Correct"}, {"c",1,"UDP checksum","Correct"} }; #endif /* _SENDIP_UDP_H */