├── .gitignore ├── .travis.yml ├── CHANGES ├── LICENSE ├── Makefile ├── README ├── TODO ├── VERSION ├── bgp.c ├── compact.c ├── contrib ├── contrib │ ├── gmon.out │ └── wake.sh ├── gmon.out └── wake.sh ├── csum.c ├── dummy.c ├── dummy.h ├── gnugetopt.c ├── gnugetopt.h ├── gnugetopt1.c ├── help2man ├── icmp.c ├── icmp.h ├── ipv4.c ├── ipv4.h ├── ipv6.c ├── ipv6.h ├── ntp.c ├── ntp.h ├── rip.c ├── rip.h ├── ripng.c ├── ripng.h ├── sendip.c ├── sendip.spec.in ├── sendip_module.h ├── tcp.c ├── tcp.h ├── types.h ├── udp.c └── udp.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.o 3 | sendip 4 | sendip.1 5 | sendip.spec 6 | *~ 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | script: make veryclean all 3 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | Changes between sendip-0.0.1 and sendip-0.0.2 2 | * Now compiles under libc5 as well as glibc 3 | 4 | Changes between sendip-0.0.2 and sendip-0.0.3 5 | * New man page, taken from one supplied by rmartini 6 | 7 | Changes between sendip-0.0.3 and sendip-1.0 8 | * Makefile no longer requires GNU make or etags 9 | * included spec file from Delvin Upton 10 | * now ship source and binary RPMs as well as source tar.gz 11 | * now compiles on FreeBSD (and hopefully Net and Open) as well as linux 12 | * minor bug fixes 13 | * added option for random header fields (idea roughly by ganesh@earth.li) 14 | * switched to 2digit versions 15 | 16 | Changes between sendip-1.0 and sendip-1.1 17 | * Fix bug the caused incorrect tcp checksums (smitchell@realogy.com) 18 | * Add RIP-1 and RIP-2 support from Richard Polton 19 | 20 | Changes between sendip-1.1 and sendip-1.2 21 | * Add IPv6 support from Antti Tuominen 22 | * Add (some) TCP options form Alexander Talos 23 | * Bugfixes 24 | 25 | Changes between sendip-1.2 and sendip-1.3 26 | * Compile fix for *BSD 27 | * Various other bugfixes 28 | * Removed bogus libpcap dependancy 29 | * Now included in debian unstable, hopefully 30 | * Ready to be included in FreeBSD ports collection, hopefully 31 | * Added -h option 32 | 33 | Changes between sendip-1.3 and sendip-1.4 34 | * Added contrib directory and wake on lan script, curtesy of 35 | Beat Bolli 36 | * RIP default option from Richard Polton 37 | 38 | Changes between sendip-1.4 and sendip-2.0-pre2 39 | * RIP bugfix from Richard Polton 40 | * Massive code tidy up 41 | * -tr no longer affects -tfe and -tfc 42 | * TCP header length defaults to correct even if options are supplied 43 | * Setting IP checksum prints a warning as it might not work 44 | * Can now specify the version field of the IP header 45 | * -if now documented correctly 46 | * man page autobuilds from help, help is more likely to be right 47 | * TCP over IPV6 still sends the wrong checksum, but now it warns you first 48 | * Enable setting of IPV6 priority 49 | * ICMP and ICMPv6 merged as they are almost identical 50 | * RIP no longer only accepts 25 entries 51 | * BGP support from David Ball 52 | 53 | Changes between sendip-2.0-pre2 and sendip-2.0 54 | * include string.h to avoid memcpy(), strlen() and strcpy() warnings in 55 | ipv4.c, ipv6.c, rip.c and udp.c (Antti Tuominen ) 56 | * ipv6 checksum fixes (Antti Tuominen) 57 | * BGP fixes (David Ball ) 58 | * Compiles on AIX (thanks to Parag Kukde ) 59 | * -d now supports hex, octal or binary data 60 | * man page (built automagically from hacked help2man) 61 | * finds modules correctly after a make install 62 | 63 | Changes between sendip-2.0 and sendip-2.1 64 | * Now FHS aware (Juan Antonio Martinez ) 65 | * NTP support added (requested by John Deatherage ) 66 | * Merged ipv6_csum and icmp6csum 67 | * Use (s)random() instead of (s)rand() (Bryan Croft ) 68 | * Added -fPIC to CFLAGS to make it compile on hppa 69 | * Now compiles on Solaris (thanks to Dax Kelson ) 70 | - tidied up the build for platform specific LDFLAGS 71 | - turned off profiling 72 | - renamed our copy of getopt to gnugetopt 73 | - created types.h with bool, u_int*_t (solaris only), and endianness stuff 74 | * sendip: 75 | - searches for libraries in . as well as installed path 76 | - man page fix (pointed out by Ambar Paul ) 77 | * tcp.so: 78 | - now supports -tonum to specify arbitrary TCP options 79 | * ipv4.so: 80 | - supports (some) IP options requested by Fabrice MARIE 81 | - only checks a single layer of enclosing headers for IPV4 82 | * bgp.so: 83 | - non-enclosure in TCP is non-fatal 84 | - doesn't segfault on platforms where static variables and .so files don't mix 85 | * rip.so: 86 | - only checks a single layer of enclosing headers for UDP 87 | * icmp.so: 88 | - only checks a single layer of enclosing headers for IPV4/IPV6 89 | - now compiles on platforms which care about alignment 90 | 91 | Changes between sendip-2.1 and sendip-2.2 92 | * spec file fixes (Calum Selkirk ) 93 | * FreeBSD compile fixes 94 | * Linux-PPC compile fixes 95 | * More SunOS compile fixes 96 | * Use ?= not = in Makefile to allow FreeBSD ports to work without a hack 97 | (Joseph Scott ) 98 | * Added support for RIPng over UDP/IPv6. Completely untested, I haven't even 99 | read the spec... Requested by armite 100 | * CheckSum code tidied up 101 | * tcp.so: 102 | - now supports sending TCP over IPv6 103 | - tcp length correctly calculated (pointed out by 104 | Yuchung Cheng ) 105 | * udp.so: 106 | - now supports sending UDP over IPv6 107 | - only checks a single layer of enclosing headers for IP 108 | * ipv6.so: 109 | - now correctly sets src and dst fields (Pekka Savola ) 110 | * ipv4.so: 111 | - ip_len now in host byte order on FreeBSD to avoid sendto: Invalid argument 112 | * rip.so: 113 | - off-by-one error causing segfaults and other badness fixed 114 | - hton* added where needed 115 | 116 | Changes between sendip-2.2 and sendip-2.3 117 | * Now compiles on archs requiring alignment 118 | * ripng.so: 119 | - now conforms more closely to the spec (help from armite 120 | 121 | Changes between sendip-2.3 and sendip-2.4 122 | * Random packet data payloads (Anand (Andy) Rao ) 123 | * ipv4.so: 124 | - fix bug with iossr and iolsr adding wrong ip options 125 | - ip_len really is now in host byte order on FreeBSD, so the sendto: Invalid 126 | argument thing really is fixed now. I hope. (brdraney@nersc.gov) 127 | 128 | Changes between sendip-2.4 and sendip-2.5 129 | * Fix minor memory leaks in several places (found using valgrind) 130 | * Fix compile bug on Solaris (found by Dave Gibelli ) 131 | * tcp.so 132 | - Fix -tonum bug found by Yaniv Kaul 133 | 134 | Changes between sendip-2.5 and sendip-2.6 135 | * Fix BSD byte order bug found by Jaya Krishna 136 | * Fix ipv6 options bug found by Jaya Krishna 137 | * Add -s option to set sockets options: 138 | - SO_BROADCAST requested by Andre Luerssen" ) 139 | - IP_HDRINCL alread required 140 | - IPV6_* options required (pointed out by Jaya Krishna) 141 | * tcp.so 142 | - Fix -tonum segfault (zamez) 143 | * rip.so 144 | - Fix multiple -re options (pointed out by several people) 145 | - Fix -ra (thanks to sharmily.anantaraman@conexant.com) 146 | * udp.c 147 | - Fix udpv6 checksum bug (thanks to sarkarbiplab@gmail.com) 148 | 149 | Changes between sendip-2.6 and sendip-2.7 150 | * Move code to GitHub 151 | * ipv4.so and tcp.so 152 | - Fix signedness compile errors (Jerzy Tarasiuk ) 153 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 2, June 1991 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 6 | 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | Preamble 11 | 12 | The licenses for most software are designed to take away your freedom 13 | to share and change it. By contrast, the GNU General Public License is 14 | intended to guarantee your freedom to share and change free 15 | software--to make sure the software is free for all its users. This 16 | General Public License applies to most of the Free Software 17 | Foundation's software and to any other program whose authors commit to 18 | using it. (Some other Free Software Foundation software is covered by 19 | the GNU Library General Public License instead.) You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | this service if you wish), that you receive source code or can get it 26 | if you want it, that you can change the software or use pieces of it 27 | in new free programs; and that you know you can do these things. 28 | 29 | To protect your rights, we need to make restrictions that forbid 30 | anyone to deny you these rights or to ask you to surrender the rights. 31 | These restrictions translate to certain responsibilities for you if 32 | you distribute copies of the software, or if you modify it. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must give the recipients all the rights that 36 | you have. You must make sure that they, too, receive or can get the 37 | source code. And you must show them these terms so they know their 38 | rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and 41 | (2) offer you this license which gives you legal permission to copy, 42 | distribute and/or modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain 45 | that everyone understands that there is no warranty for this free 46 | software. If the software is modified by someone else and passed on, 47 | we want its recipients to know that what they have is not the 48 | original, so that any problems introduced by others will not reflect 49 | on the original authors' reputations. 50 | 51 | Finally, any free program is threatened constantly by software 52 | patents. We wish to avoid the danger that redistributors of a free 53 | program will individually obtain patent licenses, in effect making the 54 | program proprietary. To prevent this, we have made it clear that any 55 | patent must be licensed for everyone's free use or not licensed at 56 | all. 57 | 58 | The precise terms and conditions for copying, distribution and 59 | modification follow. 60 | 61 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 62 | 63 | 0. This License applies to any program or other work which contains a 64 | notice placed by the copyright holder saying it may be distributed 65 | under the terms of this General Public License. The "Program", below, 66 | refers to any such program or work, and a "work based on the Program" 67 | means either the Program or any derivative work under copyright law: 68 | that is to say, a work containing the Program or a portion of it, 69 | either verbatim or with modifications and/or translated into another 70 | language. (Hereinafter, translation is included without limitation in 71 | the term "modification".) Each licensee is addressed as "you". 72 | 73 | Activities other than copying, distribution and modification are not 74 | covered by this License; they are outside its scope. The act of 75 | running the Program is not restricted, and the output from the Program 76 | is covered only if its contents constitute a work based on the Program 77 | (independent of having been made by running the Program). Whether that 78 | is true depends on what the Program does. 79 | 80 | 1. You may copy and distribute verbatim copies of the Program's source 81 | code as you receive it, in any medium, provided that you conspicuously 82 | and appropriately publish on each copy an appropriate copyright notice 83 | and disclaimer of warranty; keep intact all the notices that refer to 84 | this License and to the absence of any warranty; and give any other 85 | recipients of the Program a copy of this License along with the 86 | Program. 87 | 88 | You may charge a fee for the physical act of transferring a copy, and 89 | you may at your option offer warranty protection in exchange for a 90 | fee. 91 | 92 | 2. You may modify your copy or copies of the Program or any portion of 93 | it, thus forming a work based on the Program, and copy and distribute 94 | such modifications or work under the terms of Section 1 above, 95 | provided that you also meet all of these conditions: 96 | 97 | * a) You must cause the modified files to carry prominent notices 98 | stating that you changed the files and the date of any change. 99 | * b) You must cause any work that you distribute or publish, that in 100 | whole or in part contains or is derived from the Program or any 101 | part thereof, to be licensed as a whole at no charge to all third 102 | parties under the terms of this License. 103 | * c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but does 111 | not normally print such an announcement, your work based on the 112 | Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote 123 | it. 124 | 125 | Thus, it is not the intent of this section to claim rights or contest 126 | your rights to work written entirely by you; rather, the intent is to 127 | exercise the right to control the distribution of derivative or 128 | collective works based on the Program. 129 | 130 | In addition, mere aggregation of another work not based on the Program 131 | with the Program (or with a work based on the Program) on a volume of 132 | a storage or distribution medium does not bring the other work under 133 | the scope of this License. 134 | 135 | 3. You may copy and distribute the Program (or a work based on it, 136 | under Section 2) in object code or executable form under the terms of 137 | Sections 1 and 2 above provided that you also do one of the following: 138 | * a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software 141 | interchange; or, 142 | * b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | * c) Accompany it with the information you received as to the offer 149 | to distribute corresponding source code. (This alternative is 150 | allowed only for noncommercial distribution and only if you 151 | received the program in object code or executable form with such 152 | an offer, in accord with Subsection b above.) 153 | 154 | The source code for a work means the preferred form of the work for 155 | making modifications to it. For an executable work, complete source 156 | code means all the source code for all modules it contains, plus any 157 | associated interface definition files, plus the scripts used to 158 | control compilation and installation of the executable. However, as a 159 | special exception, the source code distributed need not include 160 | anything that is normally distributed (in either source or binary 161 | form) with the major components (compiler, kernel, and so on) of the 162 | operating system on which the executable runs, unless that component 163 | itself accompanies the executable. 164 | 165 | If distribution of executable or object code is made by offering 166 | access to copy from a designated place, then offering equivalent 167 | access to copy the source code from the same place counts as 168 | distribution of the source code, even though third parties are not 169 | compelled to copy the source along with the object code. 170 | 171 | 4. You may not copy, modify, sublicense, or distribute the Program 172 | except as expressly provided under this License. Any attempt otherwise 173 | to copy, modify, sublicense or distribute the Program is void, and 174 | will automatically terminate your rights under this License. However, 175 | parties who have received copies, or rights, from you under this 176 | License will not have their licenses terminated so long as such 177 | parties remain in full compliance. 178 | 179 | 5. You are not required to accept this License, since you have not 180 | signed it. However, nothing else grants you permission to modify or 181 | distribute the Program or its derivative works. These actions are 182 | prohibited by law if you do not accept this License. Therefore, by 183 | modifying or distributing the Program (or any work based on the 184 | Program), you indicate your acceptance of this License to do so, and 185 | all its terms and conditions for copying, distributing or modifying 186 | the Program or works based on it. 187 | 188 | 6. Each time you redistribute the Program (or any work based on the 189 | Program), the recipient automatically receives a license from the 190 | original licensor to copy, distribute or modify the Program subject to 191 | these terms and conditions. You may not impose any further 192 | restrictions on the recipients' exercise of the rights granted herein. 193 | You are not responsible for enforcing compliance by third parties to 194 | this License. 195 | 196 | 7. If, as a consequence of a court judgment or allegation of patent 197 | infringement or for any other reason (not limited to patent issues), 198 | conditions are imposed on you (whether by court order, agreement or 199 | otherwise) that contradict the conditions of this License, they do not 200 | excuse you from the conditions of this License. If you cannot 201 | distribute so as to satisfy simultaneously your obligations under this 202 | License and any other pertinent obligations, then as a consequence you 203 | may not distribute the Program at all. For example, if a patent 204 | license would not permit royalty-free redistribution of the Program by 205 | all those who receive copies directly or indirectly through you, then 206 | the only way you could satisfy both it and this License would be to 207 | refrain entirely from distribution of the Program. 208 | 209 | If any portion of this section is held invalid or unenforceable under 210 | any particular circumstance, the balance of the section is intended to 211 | apply and the section as a whole is intended to apply in other 212 | circumstances. 213 | 214 | It is not the purpose of this section to induce you to infringe any 215 | patents or other property right claims or to contest validity of any 216 | such claims; this section has the sole purpose of protecting the 217 | integrity of the free software distribution system, which is 218 | implemented by public license practices. Many people have made 219 | generous contrribute and/or modify the software. 220 | 221 | Also, for each author's protection and ours, we want to make certain 222 | that everyone understands that there is no warranty for this free 223 | software. If the software is modified by someone else and passed on, 224 | we want its recipients to know that what they have is not the 225 | original, so that any problems introduced by others will not reflect 226 | on the original authors' reputations. 227 | 228 | Finally, any free program is threatened constantly by software 229 | patents. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #configureable stuff 2 | PREFIX ?= /usr/local 3 | BINDIR ?= $(PREFIX)/bin 4 | MANDIR ?= $(PREFIX)/share/man/man1 5 | LIBDIR ?= $(PREFIX)/lib/sendip 6 | #For most systems, this works 7 | INSTALL ?= install 8 | #For Solaris, you may need 9 | #INSTALL=/usr/ucb/install 10 | 11 | CFLAGS= -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings \ 12 | -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align \ 13 | -DSENDIP_LIBS=\"$(LIBDIR)\" 14 | #-Wcast-align causes problems on solaris, but not serious ones 15 | LDFLAGS= -g -rdynamic -lm 16 | #LDFLAGS_SOLARIS= -g -lsocket -lnsl -lm 17 | LDFLAGS_SOLARIS= -g 18 | LIBS_SOLARIS= -lsocket -lnsl -lm -ldl 19 | LDFLAGS_LINUX= -g -rdynamic 20 | LIBS_LINUX= -ldl -lm 21 | LIBCFLAGS= -shared 22 | CC= gcc 23 | 24 | PROGS= sendip 25 | BASEPROTOS= ipv4.so ipv6.so 26 | IPPROTOS= icmp.so tcp.so udp.so 27 | UDPPROTOS= rip.so ripng.so ntp.so 28 | TCPPROTOS= bgp.so 29 | PROTOS= $(BASEPROTOS) $(IPPROTOS) $(UDPPROTOS) $(TCPPROTOS) 30 | GLOBALOBJS= csum.o compact.o 31 | 32 | all: $(GLOBALOBJS) sendip $(PROTOS) sendip.1 sendip.spec 33 | 34 | #there has to be a nice way to do this 35 | sendip: sendip.o gnugetopt.o gnugetopt1.o compact.o 36 | sh -c "if [ `uname` = Linux ] ; then \ 37 | echo $(CC) -o $@ $(LDFLAGS_LINUX) $(CFLAGS) $+ ; \ 38 | $(CC) -o $@ $(LDFLAGS_LINUX) $(CFLAGS) $+ $(LIBS_LINUX) ; \ 39 | elif [ `uname` = SunOS ] ; then \ 40 | echo $(CC) -o $@ $(LDFLAGS_SOLARIS) $(CFLAGS) $+ ;\ 41 | $(CC) -o $@ $(LDFLAGS_SOLARIS) $(CFLAGS) $+ $(LIBS_SOLARIS) ;\ 42 | else \ 43 | echo $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $+ ; \ 44 | $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $+ ; \ 45 | fi" 46 | 47 | sendip.1: ./help2man $(PROGS) $(PROTOS) VERSION 48 | ./help2man -n "Send arbitrary IP packets" -N >sendip.1 49 | 50 | sendip.spec: sendip.spec.in VERSION 51 | echo -n '%define ver ' >sendip.spec 52 | cat VERSION >>sendip.spec 53 | cat sendip.spec.in >>sendip.spec 54 | 55 | %.so: %.c $(GLOBALOBJS) 56 | $(CC) -o $@ $(CFLAGS) $(LIBCFLAGS) $+ 57 | 58 | .PHONY: clean install 59 | 60 | clean: 61 | rm -f *.o *~ *.so $(PROTOS) $(PROGS) core gmon.out 62 | 63 | veryclean: 64 | make clean 65 | rm -f sendip.spec sendip.1 66 | 67 | install: all 68 | [ -d $(LIBDIR) ] || mkdir -p $(LIBDIR) 69 | [ -d $(BINDIR) ] || mkdir -p $(BINDIR) 70 | [ -d $(MANDIR) ] || mkdir -p $(MANDIR) 71 | $(INSTALL) -m 755 $(PROGS) $(BINDIR) 72 | $(INSTALL) -m 644 sendip.1 $(MANDIR) 73 | $(INSTALL) -m 755 $(PROTOS) $(LIBDIR) 74 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | SendIP 2 | Author: Mike Ricketts 3 | Web: http://www.earth.li/projectpurple/progs/sendip.html 4 | Part of Project Purple. (http://www.earth.li/projectpurple/) 5 | 6 | 1. Introduction 7 | 8 | SendIP is a tool to send completely arbitrary packets out over the network. 9 | In conjunction with PackPrint (see 10 | http://www.earth.li/projectpurple/progs/packprint.html), this makes an 11 | extremely powerful debugging tool for networks. 12 | 13 | 1.1 Home page 14 | 15 | All the latest news, documentation and versions of SendIP will be made 16 | available from http://www.earth.li/projectpurple/ or directly from the 17 | the author. 18 | 19 | Please, if you find SendIP useful, consider visiting making a donation 20 | at http://heaven.on.earth.li/donate. The more donations I get the more 21 | time I can afford to spend improving SendIP! 22 | 23 | 2. Protocols 24 | 25 | Here is a list of protocols that SendIP currently understands: 26 | * IPv4 (but see below section 7) 27 | * TCP 28 | * BGP 29 | * ICMP 30 | * UDP 31 | * RIP 32 | * NTP 33 | * IPv6 (except on solaris) 34 | * ICMPv6 35 | * TCP 36 | * UDP 37 | * RIPng 38 | * NTP? 39 | 40 | Other protocols will be added in future versions, as and when I have time 41 | to add them. 42 | 43 | Of course, it is still possible to send packets using other protocols, but 44 | you have to construct the packet data and headers entirely by hand. 45 | 46 | 3. Usage instructions 47 | 48 | SendIP can take a huge number of commandline parameters. For this reason, 49 | future versions may have some sort of user interface... 50 | 51 | Please read the man page or sendip -h for details. They are not documented 52 | here because they change often between versions and I can't be bothered to 53 | keep this up to date. 54 | 55 | 4. Installation 56 | 57 | make ; make install should work. 58 | You MUST use GNU make. 59 | On Solaris you need to use gcc-3.x or above, and GNU binutils. 60 | On other platforms, you probably need gcc-2.x or above. 61 | 62 | If you have install problems on Solaris, try: 63 | make install INSTALL=/usr/ucb/install 64 | 65 | If you can't persuade it to compile or install, mail me with details of 66 | what goes wrong, and what system you are trying to install it on. 67 | By this I mean at least: 68 | - output of make -k veryclean all install 69 | - OS, including version 70 | - version of make, gcc, etc 71 | - version of sendip 72 | - anything else you think might be relevant 73 | 74 | You can change where it installs by changing BINDIR and/or PREFIX at the 75 | top of the Makefile. 76 | 77 | A .spec file is included to build RPMS, and source and binary RPMS are 78 | also available from the web page. Debian packages are also available, and 79 | sendip is included in the FreeBSD ports collection. 80 | 81 | 5. Problems, Bugs, and Comments 82 | 83 | If you have any comments, suggestions, or bug reports, please email me. 84 | 85 | Please, when sending bug reports include all the relevant information so 86 | I have a hope of reproducing or fixing the bug. I need at least: 87 | - output of make -k veryclean all install (if you installed from source) 88 | - OS, including version and platform 89 | - glibc version if you are on linux 90 | - sendip version 91 | - exact command line that fails 92 | - exact error messages, if any 93 | - exactly what you expected to happen that didn't, or what didn't happen 94 | that you expected 95 | - anything else that might be relevant 96 | Make sure you have read section 7 of this README first. 97 | 98 | The email address I currently use is mike@earth.li 99 | 100 | I am interested in any feedback in order to improve SendIP. 101 | 102 | 6. License 103 | 104 | SendIP is distributed under the GNU Public License a copy of which is 105 | included in this archive as LICENSE. 106 | 107 | 7. Note on IPv4 options 108 | 109 | Many operating systems rewrite some or all of the IP header when sending 110 | packets. Exactly which headers get rewritten depends on the OS. There is 111 | no portable way to bypass this that I am aware of. so some IP options do not 112 | work on some operating systems. Listed below are the ones I know about. 113 | This list is not by any means complete and what is here may not be accurate, 114 | and I would welcome more information. 115 | 116 | Linux, *BSD: 117 | - IP source address is rewritten if it is zero. 118 | - IP checksum is always rewritten to the correct value. 119 | - IP packet ID is rewritten (to a randomish value) if it is zero. 120 | - Total packet length is always rewritten to the number of bytes sent. 121 | - All other headers work as expected. 122 | 123 | Solaris: 124 | - IP source address is rewritten if it is zero. 125 | - IP header length works provided that the length given is not greater 126 | than the number of bytes in the packet. If it is, sendip will segfault. 127 | - IP don't fragment flag always set, other IP flags always cleared. 128 | - IP checksum is always rewritten to the correct value. 129 | - IP packet ID is rewritten (to a randomish value) if it is zero. 130 | - Total packet length is always rewritten to the number of bytes sent. 131 | - All other headers work as expected. 132 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | MAIN: Try using PF_PACKET (so ip works with wrong checksums) 2 | 3 | ipv4.c: __FreeBSD hack needed on solaris too? 4 | ipv4.h: __FreeBSD hack needed for fragment offset 5 | rip.c: handling of -re is sick 6 | ripng.c: handling of -re is sick, check conformance to spec 7 | sendip.c: add missing ipv6 sockopts 8 | 9 | ALL 10 | - DNS 11 | - RSVP (satish chandodi ) 12 | - OSPF and OSPF6 (armite ) 13 | - ARP (suggested by Christian Schmid ) 14 | - IPX (if I can find the spec) 15 | - bugfixes 16 | - ncurses and/or X interface 17 | - allow comments in packet data files 18 | - script to automatically frag packets (John Deatherage ) 19 | - XML data files? (Antti Tuominen ) 20 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 2.7 2 | -------------------------------------------------------------------------------- /bgp.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | * bgp.c - bgp module for SendIP 3 | * 4 | * Copyright (C) David Ball for Project Purple, August 2001 5 | *---------------------------------------------------------------------------- 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "sendip_module.h" 14 | 15 | 16 | /* 17 | * Roughly stolen from arpa/nameser.h 18 | */ 19 | #define GETSHORT(ptr) (ntohs( \ 20 | ((u_int16_t)((u_int8_t *)(ptr))[0] << 8) | \ 21 | ((u_int16_t)((u_int8_t *)(ptr))[1]) \ 22 | )) 23 | 24 | #define GETLONG(ptr) (ntohl( \ 25 | ((u_int32_t)((u_int8_t *)(ptr))[0] << 24) | \ 26 | ((u_int32_t)((u_int8_t *)(ptr))[1] << 16) | \ 27 | ((u_int32_t)((u_int8_t *)(ptr))[2] << 8) | \ 28 | ((u_int32_t)((u_int8_t *)(ptr))[3]) \ 29 | )) 30 | 31 | #define PUTSHORT(ptr, s) { \ 32 | u_int16_t v = htons((u_int16_t)(s)); \ 33 | *((u_int8_t *)(ptr)) = v >> 8; \ 34 | *(((u_int8_t *)(ptr)) + 1) = v; \ 35 | } 36 | 37 | #define PUTLONG(ptr, l) { \ 38 | u_int32_t v = htonl((u_int32_t)(l)); \ 39 | *((u_int8_t *)(ptr)) = v >> 24; \ 40 | *(((u_int8_t *)(ptr)) + 1) = v >> 16; \ 41 | *(((u_int8_t *)(ptr)) + 2) = v >> 8; \ 42 | *(((u_int8_t *)(ptr)) + 3) = v; \ 43 | } 44 | 45 | 46 | /* 47 | * Defines for which parts have been modified 48 | */ 49 | const u_int32_t BGP_MOD_LENGTH = 0x00000001; 50 | const u_int32_t BGP_MOD_OPT_LEN = 0x00000002; 51 | const u_int32_t BGP_MOD_WDR_LEN = 0x00000004; 52 | const u_int32_t BGP_MOD_ATTR_LEN = 0x00000008; 53 | 54 | 55 | /* 56 | * Parts of BGP messages 57 | */ 58 | typedef enum { 59 | BGP_HEADER, 60 | BGP_OPEN, 61 | BGP_OPEN_OPT, 62 | BGP_UPDATE_WDR_LEN, 63 | BGP_UPDATE_WDR, 64 | BGP_UPDATE_ATTR_LEN, 65 | BGP_UPDATE_ATTR, 66 | BGP_UPDATE_NLRI, 67 | BGP_NOTFN 68 | } bgp_msg_part; 69 | 70 | 71 | /* 72 | * Options 73 | */ 74 | sendip_option bgp_opts[] = { 75 | { "m", TRUE, "BGP Marker field (format is ::...)", 76 | "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF" }, 77 | { "l", TRUE, "Packet length", "Correct" }, 78 | { "t", TRUE, "Message Type (1 OPEN, 2 UPDATE, 3 NOTIFICATION, 4 " 79 | "KEEPALIVE", 80 | "4 (KEEPALIVE)" }, 81 | { "o", TRUE, "Open message. Format is ::" 82 | "::", 83 | "4:1:90:127.0.0.1:Correct (Any parameter can be omitted to get " 84 | "the default)" }, 85 | { "oo", TRUE, "Optional OPEN parameter. Format is ::" 86 | " - value is in hex bytes separated by :s", 87 | "Length may be omitted to get correct value" }, 88 | { "ul", TRUE, "Withdrawn routes length", "Correct" }, 89 | { "uw", TRUE, "Withdrawn route. Format is x.x.x.x/n:", 91 | "Bytes field may be omitted to use the correct number" }, 92 | { "us", TRUE, "Attributes length", "Correct" }, 93 | { "ua", TRUE, "Attribute. Format is ::" 94 | ":", 95 | "The length fields may be omitted to use the correct value" }, 96 | { "un", TRUE, "NLRI Prefix. Format is as for -buw", "As for -buw" }, 97 | { "n", TRUE, "Notification. Format is ::", 98 | "Data may be omitted for no data" }, 99 | }; 100 | 101 | /* 102 | * Option char 103 | */ 104 | const char bgp_opt_char = 'b'; 105 | 106 | 107 | /* 108 | * Gaping buffer overrun - make sure this is long enough :) 109 | */ 110 | const u_int32_t BGP_BUFLEN = 1400; 111 | 112 | /*static*/ bgp_msg_part bgp_prev_part; 113 | /*static*/ u_int8_t *bgp_len_ptr = NULL; 114 | /*static*/ u_int8_t *bgp_opt_len_ptr = NULL; 115 | /*static*/ u_int8_t *bgp_wdr_len_ptr = NULL; 116 | /*static*/ u_int8_t *bgp_attr_len_ptr = NULL; 117 | 118 | 119 | sendip_data *initialize (void) 120 | { 121 | sendip_data *data = NULL; 122 | u_int8_t *ptr; 123 | 124 | data = malloc(sizeof(sendip_data)); 125 | 126 | if (data != NULL) { 127 | memset(data, 0, sizeof(sendip_data)); 128 | data->data = malloc(BGP_BUFLEN); 129 | if (data->data == NULL) { 130 | free(data); 131 | data = NULL; 132 | } 133 | } 134 | 135 | if (data != NULL) { 136 | memset(data->data, 0, BGP_BUFLEN); 137 | ptr = data->data; 138 | 139 | memset(data->data, 0xFF, 16); 140 | ptr += 16; 141 | bgp_len_ptr = ptr; 142 | PUTSHORT(ptr, 19); 143 | ptr += 2; 144 | *ptr++ = 4; 145 | 146 | data->alloc_len = ptr - (u_int8_t *)data->data; 147 | bgp_prev_part = BGP_HEADER; 148 | } 149 | return (data); 150 | } 151 | 152 | 153 | static u_int32_t bgp_parse_bytes (u_int8_t *buf, 154 | char *arg, 155 | char **new_arg, 156 | u_int32_t limit, 157 | int base, 158 | char stopc) 159 | { 160 | u_int8_t *ptr = buf; 161 | char *arg_ptr = arg; 162 | 163 | while (*arg_ptr != '\0' && *arg_ptr != stopc && limit > 0) { 164 | *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, base); 165 | if (*arg_ptr != '\0' && *arg_ptr != stopc) { 166 | arg_ptr++; 167 | } 168 | limit--; 169 | } 170 | 171 | if (new_arg != NULL) { 172 | *new_arg = arg_ptr; 173 | } 174 | 175 | return (ptr - buf); 176 | } 177 | 178 | 179 | static u_int32_t bgp_parse_nlri (u_int8_t *buf, 180 | char *arg) 181 | { 182 | u_int8_t *ptr = buf; 183 | char *arg_ptr = arg; 184 | char *new_arg_ptr; 185 | u_int8_t bytes; 186 | 187 | ptr++; 188 | (void)bgp_parse_bytes(ptr, arg_ptr, &arg_ptr, 4, 10, '\0'); 189 | *buf = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); 190 | if (*arg_ptr != '\0') { 191 | arg_ptr++; 192 | } 193 | bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); 194 | if (arg_ptr != new_arg_ptr) { 195 | ptr += bytes; 196 | } else if (*buf > 0) { 197 | ptr += ((*buf - 1) >> 3) + 1; 198 | } 199 | 200 | return (ptr - buf); 201 | } 202 | 203 | 204 | bool do_opt (char *optstring, 205 | char *optarg, 206 | sendip_data *pack) 207 | { 208 | u_int8_t *ptr = (u_int8_t *)pack->data + pack->alloc_len; 209 | u_int8_t *rem_ptr = NULL; 210 | char *arg_ptr = NULL; 211 | char *new_arg_ptr = NULL; 212 | bool rc = TRUE; 213 | bool len_mod = FALSE; 214 | u_int8_t bytes; 215 | 216 | switch (optstring[1]) { 217 | case 'm': 218 | rem_ptr = (u_int8_t *)pack->data; 219 | (void)bgp_parse_bytes(rem_ptr, optarg, NULL, 16, 16, '\0'); 220 | break; 221 | case 'l': 222 | rem_ptr = (u_int8_t *)pack->data + 16; 223 | PUTSHORT(rem_ptr, (u_int16_t)strtoul(optarg, NULL, 10)); 224 | pack->modified |= BGP_MOD_LENGTH; 225 | break; 226 | case 't': 227 | rem_ptr = (u_int8_t *)pack->data + 18; 228 | *rem_ptr = (u_int8_t)strtoul(optarg, NULL, 0); 229 | break; 230 | case 'o': 231 | switch (optstring[2]) { 232 | case '\0': 233 | if (bgp_prev_part != BGP_HEADER) { 234 | usage_error("Open message must come immediately " 235 | "after header\n"); 236 | rc = FALSE; 237 | } else { 238 | arg_ptr = optarg; 239 | *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); 240 | if (arg_ptr == new_arg_ptr) { 241 | *ptr = 4; 242 | } 243 | ptr++; 244 | 245 | arg_ptr = new_arg_ptr; 246 | if (*arg_ptr != '\0') { 247 | arg_ptr++; 248 | } 249 | PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10)); 250 | if (arg_ptr == new_arg_ptr) { 251 | PUTSHORT(ptr, 1); 252 | } 253 | ptr += 2; 254 | 255 | arg_ptr = new_arg_ptr; 256 | if (*arg_ptr != '\0') { 257 | arg_ptr++; 258 | } 259 | PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10)); 260 | if (arg_ptr == new_arg_ptr) { 261 | PUTSHORT(ptr, 90); 262 | } 263 | ptr += 2; 264 | 265 | arg_ptr = new_arg_ptr; 266 | if (*arg_ptr != '\0') { 267 | arg_ptr++; 268 | } 269 | (void)bgp_parse_bytes(ptr, arg_ptr, &new_arg_ptr, 4, 10, ':'); 270 | if (arg_ptr == new_arg_ptr) { 271 | PUTLONG(ptr, 0x7F000001); 272 | } 273 | ptr += 4; 274 | 275 | arg_ptr = new_arg_ptr; 276 | if (*arg_ptr != '\0') { 277 | arg_ptr++; 278 | } 279 | *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); 280 | if (arg_ptr == new_arg_ptr) { 281 | *ptr = 0; 282 | } else { 283 | pack->modified |= BGP_MOD_OPT_LEN; 284 | } 285 | bgp_opt_len_ptr = ptr; 286 | ptr++; 287 | 288 | bgp_prev_part = BGP_OPEN; 289 | } 290 | break; 291 | 292 | case 'o': 293 | if (bgp_prev_part != BGP_OPEN && 294 | bgp_prev_part != BGP_OPEN_OPT) { 295 | usage_error("Open options must occur after open " 296 | "message\n"); 297 | rc = FALSE; 298 | } else { 299 | rem_ptr = ptr; 300 | arg_ptr = optarg; 301 | *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); 302 | if (*arg_ptr != '\0') { 303 | arg_ptr++; 304 | } 305 | 306 | *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); 307 | if (arg_ptr == new_arg_ptr) { 308 | *ptr = 0; 309 | } else { 310 | len_mod = TRUE; 311 | } 312 | ptr++; 313 | arg_ptr = new_arg_ptr; 314 | if (*arg_ptr != '\0') { 315 | arg_ptr++; 316 | } 317 | 318 | ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0'); 319 | 320 | if (!len_mod) { 321 | *(rem_ptr + 1) = ptr - rem_ptr; 322 | } 323 | if (!(pack->modified & BGP_MOD_OPT_LEN)) { 324 | *bgp_opt_len_ptr += ptr - rem_ptr; 325 | } 326 | bgp_prev_part = BGP_OPEN_OPT; 327 | } 328 | break; 329 | 330 | default: 331 | fprintf(stderr, "Unrecognised BGP OPEN option: %s\n", 332 | optstring); 333 | rc = FALSE; 334 | } 335 | break; 336 | 337 | case 'u': 338 | switch(optstring[2]) { 339 | case 'l': 340 | if (bgp_prev_part != BGP_HEADER) { 341 | usage_error("Update message must come immediately " 342 | "after header\n"); 343 | rc = FALSE; 344 | } else { 345 | bgp_wdr_len_ptr = ptr; 346 | PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10)); 347 | ptr += 2; 348 | pack->modified |= BGP_MOD_WDR_LEN; 349 | bgp_prev_part = BGP_UPDATE_WDR_LEN; 350 | } 351 | break; 352 | 353 | case 'w': 354 | if (bgp_prev_part == BGP_HEADER) { 355 | bgp_wdr_len_ptr = ptr; 356 | PUTSHORT(ptr, 0); 357 | ptr += 2; 358 | bgp_prev_part = BGP_UPDATE_WDR_LEN; 359 | } 360 | 361 | if (bgp_prev_part != BGP_UPDATE_WDR && 362 | bgp_prev_part != BGP_UPDATE_WDR_LEN) { 363 | usage_error("Unfeasible routes must occur immediately " 364 | "after header or -bul\n"); 365 | rc = FALSE; 366 | } else { 367 | rem_ptr = ptr; 368 | ptr += bgp_parse_nlri(ptr, optarg); 369 | 370 | if (!(pack->modified & BGP_MOD_WDR_LEN)) { 371 | PUTSHORT(bgp_wdr_len_ptr, 372 | GETSHORT(bgp_wdr_len_ptr) + ptr - rem_ptr); 373 | } 374 | bgp_prev_part = BGP_UPDATE_WDR; 375 | } 376 | break; 377 | 378 | case 's': 379 | if (bgp_prev_part == BGP_HEADER) { 380 | bgp_wdr_len_ptr = ptr; 381 | PUTSHORT(ptr, 0); 382 | ptr += 2; 383 | bgp_prev_part = BGP_UPDATE_WDR_LEN; 384 | } 385 | 386 | if (bgp_prev_part != BGP_UPDATE_WDR_LEN && 387 | bgp_prev_part != BGP_UPDATE_WDR) { 388 | usage_error("Path Attributes must come after " 389 | "unfeasible routes (if any), " 390 | "or after header\n"); 391 | rc = FALSE; 392 | } else { 393 | bgp_attr_len_ptr = ptr; 394 | PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10)); 395 | ptr += 2; 396 | pack->modified |= BGP_MOD_ATTR_LEN; 397 | bgp_prev_part = BGP_UPDATE_ATTR_LEN; 398 | } 399 | break; 400 | 401 | case 'a': 402 | if (bgp_prev_part == BGP_HEADER) { 403 | bgp_wdr_len_ptr = ptr; 404 | PUTSHORT(ptr, 0); 405 | ptr += 2; 406 | bgp_prev_part = BGP_UPDATE_WDR_LEN; 407 | } 408 | 409 | if (bgp_prev_part == BGP_UPDATE_WDR_LEN || 410 | bgp_prev_part == BGP_UPDATE_WDR) { 411 | bgp_attr_len_ptr = ptr; 412 | PUTSHORT(ptr, 0); 413 | ptr += 2; 414 | bgp_prev_part = BGP_UPDATE_ATTR_LEN; 415 | } 416 | 417 | if (bgp_prev_part != BGP_UPDATE_ATTR_LEN && 418 | bgp_prev_part != BGP_UPDATE_ATTR) { 419 | usage_error("Path Attributes must come after " 420 | "unfeasible routes (if any), " 421 | "or after header\n"); 422 | rc = FALSE; 423 | } else { 424 | rem_ptr = ptr; 425 | arg_ptr = optarg; 426 | 427 | *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 16); 428 | if (*arg_ptr != '\0') { 429 | arg_ptr++; 430 | } 431 | 432 | *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); 433 | if (*arg_ptr != '\0') { 434 | arg_ptr++; 435 | } 436 | 437 | bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); 438 | if (arg_ptr != new_arg_ptr) { 439 | if (bytes <= 1) { 440 | bytes = 1; 441 | } else { 442 | bytes = 2; 443 | } 444 | } else { 445 | if (*rem_ptr & 0x10) { 446 | bytes = 2; 447 | } else { 448 | bytes = 1; 449 | } 450 | } 451 | arg_ptr = new_arg_ptr; 452 | if (*arg_ptr != '\0') { 453 | arg_ptr++; 454 | } 455 | 456 | if (bytes == 1) { 457 | *ptr++ = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10); 458 | } else { 459 | PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10)); 460 | ptr += 2; 461 | } 462 | if (arg_ptr != new_arg_ptr) { 463 | len_mod = TRUE; 464 | } 465 | arg_ptr = new_arg_ptr; 466 | if (*arg_ptr != '\0') { 467 | arg_ptr++; 468 | } 469 | 470 | if (bytes == 1) { 471 | ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0'); 472 | } else { 473 | ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16, 474 | '\0'); 475 | } 476 | 477 | if (!len_mod) { 478 | if (bytes == 1) { 479 | *(rem_ptr + 2) = ptr - rem_ptr - 3; 480 | } else { 481 | PUTSHORT(rem_ptr + 2, ptr - rem_ptr - 4); 482 | } 483 | } 484 | 485 | if (!(pack->modified & BGP_MOD_ATTR_LEN)) { 486 | PUTSHORT(bgp_attr_len_ptr, 487 | GETSHORT(bgp_attr_len_ptr) + ptr - rem_ptr); 488 | } 489 | bgp_prev_part = BGP_UPDATE_ATTR; 490 | } 491 | break; 492 | 493 | case 'n': 494 | if (bgp_prev_part == BGP_HEADER) { 495 | bgp_wdr_len_ptr = ptr; 496 | PUTSHORT(ptr, 0); 497 | ptr += 2; 498 | bgp_prev_part = BGP_UPDATE_WDR_LEN; 499 | } 500 | 501 | if (bgp_prev_part == BGP_UPDATE_WDR_LEN || 502 | bgp_prev_part == BGP_UPDATE_WDR) { 503 | bgp_attr_len_ptr = ptr; 504 | PUTSHORT(ptr, 0); 505 | ptr += 2; 506 | bgp_prev_part = BGP_UPDATE_ATTR_LEN; 507 | } 508 | 509 | if (bgp_prev_part != BGP_UPDATE_ATTR_LEN && 510 | bgp_prev_part != BGP_UPDATE_ATTR && 511 | bgp_prev_part != BGP_UPDATE_NLRI) { 512 | usage_error("NLRI must come after Unfeasible routes and " 513 | "attributes, if any, or after header\n"); 514 | rc = FALSE; 515 | } else { 516 | rem_ptr = ptr; 517 | ptr += bgp_parse_nlri(ptr, optarg); 518 | 519 | bgp_prev_part = BGP_UPDATE_NLRI; 520 | } 521 | break; 522 | 523 | default: 524 | fprintf(stderr, "Unrecognised BGP UPDATE option: %s\n", optstring); 525 | rc = FALSE; 526 | } 527 | break; 528 | 529 | case 'n': 530 | if (bgp_prev_part != BGP_HEADER) { 531 | usage_error("Notification must come immediately after header\n"); 532 | rc = FALSE; 533 | } else { 534 | arg_ptr = optarg; 535 | *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); 536 | if (*arg_ptr != '\0') { 537 | arg_ptr++; 538 | } 539 | 540 | *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10); 541 | if (*arg_ptr != '\0') { 542 | arg_ptr++; 543 | } 544 | 545 | ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16, '\0'); 546 | 547 | bgp_prev_part = BGP_NOTFN; 548 | } 549 | break; 550 | 551 | default: 552 | fprintf(stderr, "Unrecognised BGP option: %s", optstring); 553 | rc = FALSE; 554 | } 555 | 556 | if (rc) { 557 | pack->alloc_len = ptr - (u_int8_t *)pack->data; 558 | if (!(pack->modified & BGP_MOD_LENGTH)) { 559 | PUTSHORT(bgp_len_ptr, pack->alloc_len); 560 | } 561 | } 562 | 563 | return (rc); 564 | } 565 | 566 | 567 | bool finalize (char *hdrs, 568 | sendip_data *headers[], 569 | sendip_data *data, 570 | sendip_data *pack) 571 | { 572 | if (hdrs[strlen(hdrs) - 1] != 't') { 573 | usage_error("WARNING: BGP should be carried over TCP\n"); 574 | } 575 | return TRUE; 576 | } 577 | 578 | 579 | int num_opts (void) 580 | { 581 | return (sizeof(bgp_opts)/sizeof(sendip_option)); 582 | } 583 | 584 | 585 | sendip_option *get_opts (void) 586 | { 587 | return (bgp_opts); 588 | } 589 | 590 | 591 | char get_optchar (void) 592 | { 593 | return (bgp_opt_char); 594 | } 595 | -------------------------------------------------------------------------------- /compact.c: -------------------------------------------------------------------------------- 1 | /* compact.c - function to convert hex/octal/decimal/raw string to raw 2 | * ChangeLog since initial release in sendip 2.1. 3 | */ 4 | #include 5 | #include 6 | 7 | int compact_string(char *data_out) { 8 | char *data_in = data_out; 9 | int i=0; 10 | if(*data_in=='0') { 11 | data_in++; 12 | if(*data_in=='x' || *data_in=='X') { 13 | /* Hex */ 14 | char c='\0'; 15 | data_in++; 16 | while(*data_in) { 17 | if(*data_in>='0' && *data_in<='9') { 18 | c+=*data_in-'0'; 19 | } else if(*data_in>='A' && *data_in<='F') { 20 | c+=*data_in-'A'+10; 21 | } else if(*data_in>='a' && *data_in<='f') { 22 | c+=*data_in-'a'+10; 23 | } else { 24 | fprintf(stderr,"Character %c invalid in hex data stream\n", 25 | *data_in); 26 | return 0; 27 | } 28 | if( i&1) { 29 | *(data_out++)=c; // odd nibble - output it 30 | c='\0'; 31 | } else { 32 | c<<=4; // even nibble - shift to top of byte 33 | } 34 | data_in++; i++; 35 | } 36 | *data_out=c; // make sure last nibble is added 37 | i++; i>>=1; // i was a nibble count... 38 | return i; 39 | } else { 40 | /* Octal */ 41 | char c='\0'; 42 | while(*data_in) { 43 | if(*data_in>='0' && *data_in<='7') { 44 | c+=*data_in-'0'; 45 | } else { 46 | fprintf(stderr,"Character %c invalid in octal data stream\n", 47 | *data_in); 48 | return 0; 49 | } 50 | if( (i&3) == 3 ) { 51 | *(data_out++)=c; // output every 4th char 52 | c='\0'; 53 | } else { // otherwise just shift it up 54 | c<<=2; 55 | } 56 | data_in++; i++; 57 | } 58 | *data_out=c; // add partial last byte 59 | i+=3; i>>=2; 60 | return i; 61 | } 62 | } else { 63 | /* String */ 64 | return strlen(data_in); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contrib/contrib/gmon.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickettm/SendIP/aad12a001157489ab9053c8665e09aec24a2ff6d/contrib/contrib/gmon.out -------------------------------------------------------------------------------- /contrib/contrib/wake.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # Usage: wake [] 4 | # 5 | # can be a host name or a dotted-quad IP address. 6 | # If the is not given, it is taken from ethers(5). 7 | # For this to work, if you give a host name as first argument, ethers 8 | # has to contain host names (as opposed to IP addresses). 9 | # 10 | # Unless you have it already, you can build your ethers file like this: 11 | # 12 | # nmap -sP -PI 192.168.1.0/24 # prepare ARP cache with a ping-sweep 13 | # arp -a | awk '$5 == "[ether]" { printf("%s\t%s\n", $4, $1); }' \ 14 | # | sort >>/etc/ethers 15 | # 16 | # The 'magic packet' consists of 6 times 0xFF followed by 16 times 17 | # the hardware address of the NIC. This sequence can be encapsulated 18 | # in any kind of packet; I chose UDP to the discard port (9). 19 | 20 | if [ $# = 1 ]; then 21 | ETHER=`awk "/$1/"' { gsub(":", "", $1); print $1; exit; }' /etc/ethers` 22 | if [ -z $ETHER ]; then 23 | echo "$0: host $1 is not in /etc/ethers" >&2 24 | exit 1 25 | fi 26 | ETHER=`echo $ETHER | sed 's/://g'` 27 | else 28 | ETHER=$2 29 | fi 30 | 31 | ETHER="${ETHER}${ETHER}${ETHER}${ETHER}" # 4 x MAC 32 | ETHER="FFFFFFFFFFFF${ETHER}${ETHER}${ETHER}${ETHER}" # Preamble + 16 x MAC 33 | 34 | sendip $1 -p ipv4 -p udp.so -ud 9 -d 0x"$ETHER" 35 | -------------------------------------------------------------------------------- /contrib/gmon.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickettm/SendIP/aad12a001157489ab9053c8665e09aec24a2ff6d/contrib/gmon.out -------------------------------------------------------------------------------- /contrib/wake.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # Usage: wake [] 4 | # 5 | # can be a host name or a dotted-quad IP address. 6 | # If the is not given, it is taken from ethers(5). 7 | # For this to work, if you give a host name as first argument, ethers 8 | # has to contain host names (as opposed to IP addresses). 9 | # 10 | # Unless you have it already, you can build your ethers file like this: 11 | # 12 | # nmap -sP -PI 192.168.1.0/24 # prepare ARP cache with a ping-sweep 13 | # arp -a | awk '$5 == "[ether]" { printf("%s\t%s\n", $4, $1); }' \ 14 | # | sort >>/etc/ethers 15 | # 16 | # The 'magic packet' consists of 6 times 0xFF followed by 16 times 17 | # the hardware address of the NIC. This sequence can be encapsulated 18 | # in any kind of packet; I chose UDP to the discard port (9). 19 | 20 | if [ $# = 1 ]; then 21 | ETHER=`awk "/$1/"' { gsub(":", "", $1); print $1; exit; }' /etc/ethers` 22 | if [ -z $ETHER ]; then 23 | echo "$0: host $1 is not in /etc/ethers" >&2 24 | exit 1 25 | fi 26 | ETHER=`echo $ETHER | sed 's/://g'` 27 | else 28 | ETHER=$2 29 | fi 30 | 31 | ETHER="${ETHER}${ETHER}${ETHER}${ETHER}" # 4 x MAC 32 | ETHER="FFFFFFFFFFFF${ETHER}${ETHER}${ETHER}${ETHER}" # Preamble + 16 x MAC 33 | 34 | sendip $1 -p ipv4 -p udp.so -ud 9 -d 0x"$ETHER" 35 | -------------------------------------------------------------------------------- /csum.c: -------------------------------------------------------------------------------- 1 | /* csum.c 2 | * Computes the standard internet checksum of a set of data (from RFC1071) 3 | * ChangeLog since sendip 2.0: 4 | * 02/12/2001: Moved ipv6_csum into icmp.c as that is where it is used 5 | * 22/01/2002: Include types.h to make sure u_int*_t defined on Solaris 6 | */ 7 | 8 | #define __USE_BSD /* GLIBC */ 9 | #define _BSD_SOURCE /* LIBC5 */ 10 | #define _DEFAULT_SOURCE /* GLIBC 2.20+ */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "types.h" 17 | 18 | u_int16_t csum (u_int16_t *packet, int packlen); 19 | 20 | /* Checksum a block of data */ 21 | u_int16_t csum (u_int16_t *packet, int packlen) { 22 | register unsigned long sum = 0; 23 | 24 | while (packlen > 1) { 25 | sum+= *(packet++); 26 | packlen-=2; 27 | } 28 | 29 | if (packlen > 0) 30 | sum += *(unsigned char *)packet; 31 | 32 | /* TODO: this depends on byte order */ 33 | 34 | while (sum >> 16) 35 | sum = (sum & 0xffff) + (sum >> 16); 36 | 37 | return (u_int16_t) ~sum; 38 | } 39 | -------------------------------------------------------------------------------- /dummy.c: -------------------------------------------------------------------------------- 1 | /* dummy.c - example sendip module 2 | * Author: Mike Ricketts 3 | * ChangeLog since 2.0 release: 4 | * 02/12/2001: added num_opts, get_opts and get_optchar functions 5 | * 02/12/2001: added more helpful comments 6 | */ 7 | 8 | /* To write a new sendip module: 9 | * * mail mike@earth.li to check that nobody else is already working on the 10 | * same thing. 11 | * * copy dummy.c and dummy.h 12 | * * replace dummy with the name of your module throughout 13 | * * In .h: 14 | * - fill in the struct foo_header with all the header fields in your 15 | * module's packet. If the packet is a variable length, only put the 16 | * common bits here and use additional structs for other bits, if needed. 17 | * Be very careful about introducing byteorder dependencies. See ntp.h 18 | * for a simple case of how to do it. In general, things smaller than 19 | * 16 bits are problematic, use the __BYTE_ORDER macro and test against 20 | * __LITTLE_ENDIAN, __BIG_ENDIAN. Always have a #else catchall with a 21 | * #error in, just in case. 22 | * Every field should be a u_int*_t or an int*_t to avoid things being 23 | * differnt lengths from you expect. Use these rather than equivalent 24 | * ones as these will exist everywhere that sendip compiles. 25 | * - create a list of #defines FOO_MOD_*, one for each header field that 26 | * may be modified. The first should have value 1, the rest should be 27 | * 1<.c: 38 | * - remove this essay (you can still read it in dummy.c!) 39 | * - change the top comment in the obvious way 40 | * - find an option character not used elsewhere and replace opt_char with 41 | * that. You can see what is used by doing 42 | * grep '^const char opt_char' *.c 43 | * in the sendip source directory. 44 | * - in the do_opt function, fill in code for all the options you defined in 45 | * the header file. Typically, the code will look a lot like: 46 | * case 'option': 47 | * header->thing = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 48 | * pack->modified |= FOO_MOD_THING; 49 | * break; 50 | * If some of your options change the length of the packet, you might want 51 | * to take a look in ipv4.c or tcp.c - specifically where they add IPV4 or 52 | * TCP options. 53 | * Make sure you use htons and htonl everywhere you need to to avoid 54 | * byteorder problems. 55 | * -opt contains the option string, including the starting opt_char 56 | * -arg contains any argument given 57 | * -pack contains our headers 58 | * - in the finalize function, fill in anything that needs to be computed 59 | * after all the optoins are processed. This function MUST NOT change 60 | * the length or location of the headers in memory, else bad things will 61 | * happen. Typical things that go in here are filling in the length 62 | * field of the header if it hasn't been overriden, computing checksums, 63 | * etc. You may also which to check that your packet is enclosed in a 64 | * sensible carrier. tcp.c does all of the things. 65 | * -hdrs is build by taking the opt_char for each packet in turn from the 66 | * outside in, up to but not including this packet 67 | * -headers is an array of all the enclosing headers in the same order 68 | * -data contains the data inside this set of headers. This may include 69 | * headers of underlying protocols, that will already have been 70 | * finalized. DO NOT MODIFY IT. 71 | * -pack contains our headers. 72 | * - You might, possibly, find the following functions useful. They are 73 | * automatically available to all modules: 74 | * -int compact_string(char *string); 75 | * For strings starting 0x or 0X, converts each pair of bytes thereafter 76 | * to a single byte of that hex value. For other strings starting 0, 77 | * converts sets of 3 bytes to a single byte of that octal value. For 78 | * all other strings, does nothing. Returns the length of the final 79 | * string. This is recomended when parsing arbitrary data (like the -d 80 | * option of sendip, -tonum for arbitrary TCP options) 81 | * -u_int16_t csum(u_int16_t *data, int len) 82 | * returns the standard internet checksum of the packet 83 | * - If something doesn't work as expected, or you can't figure out how to 84 | * do sometihng, mail mike@earth.li and ask. 85 | * * In the Makefile add .so to the PROTOS line 86 | * * Test it 87 | * * Mail it to mike@earth.li, either as a patch or just send the .c and .h 88 | * files you created 89 | */ 90 | 91 | #include 92 | #include 93 | #include "sendip_module.h" 94 | #include "dummy.h" 95 | 96 | /* Character that identifies our options 97 | */ 98 | const char opt_char='dummy'; 99 | 100 | sendip_data *initialize(void) { 101 | sendip_data *ret = malloc(sizeof(sendip_data)); 102 | dummy_header *dummy = malloc(sizeof(dummy_header)); 103 | memset(dummy,0,sizeof(dummy_header)); 104 | ret->alloc_len = sizeof(dummy_header); 105 | ret->data = dummy; 106 | ret->modified=0; 107 | return ret; 108 | } 109 | 110 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 111 | dummy_header *dummy = (dummy_header *)pack->data; 112 | switch(opt[1]) { 113 | //... 114 | } 115 | return TRUE; 116 | 117 | } 118 | 119 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 120 | sendip_data *pack) { 121 | //... 122 | return TRUE; 123 | } 124 | 125 | int num_opts() { 126 | return sizeof(dummy_opts)/sizeof(sendip_option); 127 | } 128 | sendip_option *get_opts() { 129 | return dummy_opts; 130 | } 131 | char get_optchar() { 132 | return opt_char; 133 | } 134 | -------------------------------------------------------------------------------- /dummy.h: -------------------------------------------------------------------------------- 1 | /* dummy.h 2 | * see dummy.c for more information 3 | */ 4 | #ifndef _SENDIP_dummy_H 5 | #define _SENDIP_dummy_H 6 | 7 | #error "Don't include this, dumbass" 8 | 9 | /* dummy HEADER 10 | */ 11 | typedef struct { 12 | //... 13 | } dummy_header; 14 | 15 | /* Defines for which parts have been modified 16 | */ 17 | #define dummy_MOD_* 1<<* 18 | 19 | /* Options 20 | */ 21 | sendip_option dummy_opts[] = { 22 | //... 23 | }; 24 | 25 | #endif /* _SENDIP_dummy_H */ 26 | -------------------------------------------------------------------------------- /gnugetopt.c: -------------------------------------------------------------------------------- 1 | /* Getopt.c ripped straight out of glibc with some very minor modifications 2 | Use this getopt not a system dependant one, as sendip is rather sensitive 3 | to precise getopt behaviour. 4 | */ 5 | 6 | /* Getopt for GNU. 7 | NOTE: getopt is now part of the C library, so if you don't know what 8 | "Keep this file name-space clean" means, talk to drepper@gnu.org 9 | before changing it! 10 | 11 | Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 12 | Free Software Foundation, Inc. 13 | 14 | The GNU C Library is free software; you can redistribute it and/or 15 | modify it under the terms of the GNU Library General Public License as 16 | published by the Free Software Foundation; either version 2 of the 17 | License, or (at your option) any later version. 18 | 19 | The GNU C Library is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | Library General Public License for more details. 23 | 24 | You should have received a copy of the GNU Library General Public 25 | License along with the GNU C Library; see the file COPYING.LIB. If not, 26 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 27 | Boston, MA 02111-1307, USA. */ 28 | 29 | /* This tells Alpha OSF/1 not to define a getopt prototype in . 30 | Ditto for AIX 3.2 and . */ 31 | #ifndef _NO_PROTO 32 | # define _NO_PROTO 33 | #endif 34 | 35 | #ifdef HAVE_CONFIG_H 36 | # include 37 | #endif 38 | 39 | #if !defined __STDC__ || !__STDC__ 40 | /* This is a separate conditional since some stdc systems 41 | reject `defined (const)'. */ 42 | # ifndef const 43 | # define const 44 | # endif 45 | #endif 46 | 47 | #include 48 | 49 | /* Comment out all this code if we are using the GNU C Library, and are not 50 | actually compiling the library itself. This code is part of the GNU C 51 | Library, but also included in many other GNU distributions. Compiling 52 | and linking in this code is a waste when using the GNU C library 53 | (especially if it is a shared library). Rather than having every GNU 54 | program understand `configure --with-gnu-libc' and omit the object files, 55 | it is simpler to just do this in the source for each such file. */ 56 | /* 57 | #define GETOPT_INTERFACE_VERSION 2 58 | #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 59 | # include 60 | # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION 61 | # define ELIDE_CODE 62 | # endif 63 | #endif 64 | */ 65 | #ifndef ELIDE_CODE 66 | 67 | 68 | /* This needs to come after some library #include 69 | to get __GNU_LIBRARY__ defined. */ 70 | #ifdef __GNU_LIBRARY__ 71 | /* Don't include stdlib.h for non-GNU C libraries because some of them 72 | contain conflicting prototypes for getopt. */ 73 | # include 74 | # include 75 | #endif /* GNU C library. */ 76 | 77 | #ifdef VMS 78 | # include 79 | # if HAVE_STRING_H - 0 80 | # include 81 | # endif 82 | #endif 83 | 84 | #ifndef _ 85 | /* This is for other GNU distributions with internationalized messages. */ 86 | # if defined HAVE_LIBINTL_H || defined _LIBC 87 | # include 88 | # ifndef _ 89 | # define _(msgid) gettext (msgid) 90 | # endif 91 | # else 92 | # define _(msgid) (msgid) 93 | # endif 94 | #endif 95 | 96 | /* This version of `getopt' appears to the caller like standard Unix `getopt' 97 | but it behaves differently for the user, since it allows the user 98 | to intersperse the options with the other arguments. 99 | 100 | As `getopt' works, it permutes the elements of ARGV so that, 101 | when it is done, all the options precede everything else. Thus 102 | all application programs are extended to handle flexible argument order. 103 | 104 | Setting the environment variable POSIXLY_CORRECT disables permutation. 105 | Then the behavior is completely standard. 106 | 107 | GNU application programs can use a third alternative mode in which 108 | they can distinguish the relative order of options and other arguments. */ 109 | 110 | #include "gnugetopt.h" 111 | 112 | /* For communication from `getopt' to the caller. 113 | When `getopt' finds an option that takes an argument, 114 | the argument value is returned here. 115 | Also, when `ordering' is RETURN_IN_ORDER, 116 | each non-option ARGV-element is returned here. */ 117 | 118 | char *gnuoptarg; 119 | 120 | /* Index in ARGV of the next element to be scanned. 121 | This is used for communication to and from the caller 122 | and for communication between successive calls to `getopt'. 123 | 124 | On entry to `getopt', zero means this is the first call; initialize. 125 | 126 | When `getopt' returns -1, this is the index of the first of the 127 | non-option elements that the caller should itself scan. 128 | 129 | Otherwise, `gnuoptind' communicates from one call to the next 130 | how much of ARGV has been scanned so far. */ 131 | 132 | /* 1003.2 says this must be 1 before any call. */ 133 | int gnuoptind = 1; 134 | 135 | /* Formerly, initialization of getopt depended on gnuoptind==0, which 136 | causes problems with re-calling getopt as programs generally don't 137 | know that. */ 138 | 139 | int __getopt_initialized; 140 | 141 | /* The next char to be scanned in the option-element 142 | in which the last option character we returned was found. 143 | This allows us to pick up the scan where we left off. 144 | 145 | If this is zero, or a null string, it means resume the scan 146 | by advancing to the next ARGV-element. */ 147 | 148 | /* MODIFIED THIS LINE so that sendip can force skipping options */ 149 | char *nextchar = NULL; 150 | 151 | /* Callers store zero here to inhibit the error message 152 | for unrecognized options. */ 153 | 154 | int gnuopterr = 1; 155 | 156 | /* Set to an option character which was unrecognized. 157 | This must be initialized on some systems to avoid linking in the 158 | system's own getopt implementation. */ 159 | 160 | int gnuoptopt = '?'; 161 | 162 | /* Describe how to deal with options that follow non-option ARGV-elements. 163 | 164 | If the caller did not specify anything, 165 | the default is REQUIRE_ORDER if the environment variable 166 | POSIXLY_CORRECT is defined, PERMUTE otherwise. 167 | 168 | REQUIRE_ORDER means don't recognize them as options; 169 | stop option processing when the first non-option is seen. 170 | This is what Unix does. 171 | This mode of operation is selected by either setting the environment 172 | variable POSIXLY_CORRECT, or using `+' as the first character 173 | of the list of option characters. 174 | 175 | PERMUTE is the default. We permute the contents of ARGV as we scan, 176 | so that eventually all the non-options are at the end. This allows options 177 | to be given in any order, even with programs that were not written to 178 | expect this. 179 | 180 | RETURN_IN_ORDER is an option available to programs that were written 181 | to expect options and other ARGV-elements in any order and that care about 182 | the ordering of the two. We describe each non-option ARGV-element 183 | as if it were the argument of an option with character code 1. 184 | Using `-' as the first character of the list of option characters 185 | selects this mode of operation. 186 | 187 | The special argument `--' forces an end of option-scanning regardless 188 | of the value of `ordering'. In the case of RETURN_IN_ORDER, only 189 | `--' can cause `getopt' to return -1 with `gnuoptind' != ARGC. */ 190 | 191 | static enum 192 | { 193 | REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER 194 | } ordering; 195 | 196 | #ifdef __GNU_LIBRARY__ 197 | /* We want to avoid inclusion of string.h with non-GNU libraries 198 | because there are many ways it can cause trouble. 199 | On some systems, it contains special magic macros that don't work 200 | in GCC. */ 201 | # include 202 | # define my_index strchr 203 | #else 204 | 205 | # if HAVE_STRING_H 206 | # include 207 | # else 208 | # include 209 | # endif 210 | 211 | /* Avoid depending on library functions or files 212 | whose names are inconsistent. */ 213 | 214 | static char * 215 | my_index (const char *str, int chr) 216 | { 217 | while (*str) 218 | { 219 | if (*str == chr) 220 | return (char *) str; 221 | str++; 222 | } 223 | return 0; 224 | } 225 | 226 | /* If using GCC, we can safely declare strlen this way. 227 | If not using GCC, it is ok not to declare it. */ 228 | #ifdef __GNUC__ 229 | /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. 230 | That was relevant to code that was here before. */ 231 | # if (!defined __STDC__ || !__STDC__) && !defined strlen 232 | /* gcc with -traditional declares the built-in strlen to return int, 233 | and has done so at least since version 2.4.5. -- rms. */ 234 | extern int strlen (const char *); 235 | # endif /* not __STDC__ */ 236 | #endif /* __GNUC__ */ 237 | 238 | #endif /* not __GNU_LIBRARY__ */ 239 | 240 | /* Handle permutation of arguments. */ 241 | 242 | /* Describe the part of ARGV that contains non-options that have 243 | been skipped. `first_nonopt' is the index in ARGV of the first of them; 244 | `last_nonopt' is the index after the last of them. */ 245 | 246 | static int first_nonopt; 247 | static int last_nonopt; 248 | 249 | #ifdef _LIBC 250 | /* Bash 2.0 gives us an environment variable containing flags 251 | indicating ARGV elements that should not be considered arguments. */ 252 | 253 | /* Defined in getopt_init.c */ 254 | extern char *__getopt_nonoption_flags; 255 | 256 | static int nonoption_flags_max_len; 257 | static int nonoption_flags_len; 258 | 259 | static int original_argc; 260 | static char *const *original_argv; 261 | 262 | /* Make sure the environment variable bash 2.0 puts in the environment 263 | is valid for the getopt call we must make sure that the ARGV passed 264 | to getopt is that one passed to the process. */ 265 | static void 266 | __attribute__ ((unused)) 267 | store_args_and_env (int argc, char *const *argv) 268 | { 269 | /* XXX This is no good solution. We should rather copy the args so 270 | that we can compare them later. But we must not use malloc(3). */ 271 | original_argc = argc; 272 | original_argv = argv; 273 | } 274 | # ifdef text_set_element 275 | text_set_element (__libc_subinit, store_args_and_env); 276 | # endif /* text_set_element */ 277 | 278 | # define SWAP_FLAGS(ch1, ch2) \ 279 | if (nonoption_flags_len > 0) \ 280 | { \ 281 | char __tmp = __getopt_nonoption_flags[ch1]; \ 282 | __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ 283 | __getopt_nonoption_flags[ch2] = __tmp; \ 284 | } 285 | #else /* !_LIBC */ 286 | # define SWAP_FLAGS(ch1, ch2) 287 | #endif /* _LIBC */ 288 | 289 | /* Exchange two adjacent subsequences of ARGV. 290 | One subsequence is elements [first_nonopt,last_nonopt) 291 | which contains all the non-options that have been skipped so far. 292 | The other is elements [last_nonopt,gnuoptind), which contains all 293 | the options processed since those non-options were skipped. 294 | 295 | `first_nonopt' and `last_nonopt' are relocated so that they describe 296 | the new indices of the non-options in ARGV after they are moved. */ 297 | 298 | #if defined __STDC__ && __STDC__ 299 | static void exchange (char **); 300 | #endif 301 | 302 | static void 303 | exchange (argv) 304 | char **argv; 305 | { 306 | int bottom = first_nonopt; 307 | int middle = last_nonopt; 308 | int top = gnuoptind; 309 | char *tem; 310 | 311 | /* Exchange the shorter segment with the far end of the longer segment. 312 | That puts the shorter segment into the right place. 313 | It leaves the longer segment in the right place overall, 314 | but it consists of two parts that need to be swapped next. */ 315 | 316 | #ifdef _LIBC 317 | /* First make sure the handling of the `__getopt_nonoption_flags' 318 | string can work normally. Our top argument must be in the range 319 | of the string. */ 320 | if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) 321 | { 322 | /* We must extend the array. The user plays games with us and 323 | presents new arguments. */ 324 | char *new_str = malloc (top + 1); 325 | if (new_str == NULL) 326 | nonoption_flags_len = nonoption_flags_max_len = 0; 327 | else 328 | { 329 | memset (__mempcpy (new_str, __getopt_nonoption_flags, 330 | nonoption_flags_max_len), 331 | '\0', top + 1 - nonoption_flags_max_len); 332 | nonoption_flags_max_len = top + 1; 333 | __getopt_nonoption_flags = new_str; 334 | } 335 | } 336 | #endif 337 | 338 | while (top > middle && middle > bottom) 339 | { 340 | if (top - middle > middle - bottom) 341 | { 342 | /* Bottom segment is the short one. */ 343 | int len = middle - bottom; 344 | register int i; 345 | 346 | /* Swap it with the top part of the top segment. */ 347 | for (i = 0; i < len; i++) 348 | { 349 | tem = argv[bottom + i]; 350 | argv[bottom + i] = argv[top - (middle - bottom) + i]; 351 | argv[top - (middle - bottom) + i] = tem; 352 | SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); 353 | } 354 | /* Exclude the moved bottom segment from further swapping. */ 355 | top -= len; 356 | } 357 | else 358 | { 359 | /* Top segment is the short one. */ 360 | int len = top - middle; 361 | register int i; 362 | 363 | /* Swap it with the bottom part of the bottom segment. */ 364 | for (i = 0; i < len; i++) 365 | { 366 | tem = argv[bottom + i]; 367 | argv[bottom + i] = argv[middle + i]; 368 | argv[middle + i] = tem; 369 | SWAP_FLAGS (bottom + i, middle + i); 370 | } 371 | /* Exclude the moved top segment from further swapping. */ 372 | bottom += len; 373 | } 374 | } 375 | 376 | /* Update records for the slots the non-options now occupy. */ 377 | 378 | first_nonopt += (gnuoptind - last_nonopt); 379 | last_nonopt = gnuoptind; 380 | } 381 | 382 | /* Initialize the internal data when the first call is made. */ 383 | 384 | #if defined __STDC__ && __STDC__ 385 | static const char *_getopt_initialize (int, char *const *, const char *); 386 | #endif 387 | static const char * 388 | _getopt_initialize (argc, argv, optstring) 389 | int argc; 390 | char *const *argv; 391 | const char *optstring; 392 | { 393 | /* Start processing options with ARGV-element 1 (since ARGV-element 0 394 | is the program name); the sequence of previously skipped 395 | non-option ARGV-elements is empty. */ 396 | 397 | first_nonopt = last_nonopt = gnuoptind; 398 | 399 | nextchar = NULL; 400 | 401 | /* Determine how to handle the ordering of options and nonoptions. */ 402 | 403 | if (optstring[0] == '-') 404 | { 405 | ordering = RETURN_IN_ORDER; 406 | ++optstring; 407 | } 408 | else if (optstring[0] == '+') 409 | { 410 | ordering = REQUIRE_ORDER; 411 | ++optstring; 412 | } 413 | else 414 | ordering = PERMUTE; 415 | 416 | #ifdef _LIBC 417 | if ( argc == original_argc && argv == original_argv) 418 | { 419 | if (nonoption_flags_max_len == 0) 420 | { 421 | if (__getopt_nonoption_flags == NULL 422 | || __getopt_nonoption_flags[0] == '\0') 423 | nonoption_flags_max_len = -1; 424 | else 425 | { 426 | const char *orig_str = __getopt_nonoption_flags; 427 | int len = nonoption_flags_max_len = strlen (orig_str); 428 | if (nonoption_flags_max_len < argc) 429 | nonoption_flags_max_len = argc; 430 | __getopt_nonoption_flags = 431 | (char *) malloc (nonoption_flags_max_len); 432 | if (__getopt_nonoption_flags == NULL) 433 | nonoption_flags_max_len = -1; 434 | else 435 | memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), 436 | '\0', nonoption_flags_max_len - len); 437 | } 438 | } 439 | nonoption_flags_len = nonoption_flags_max_len; 440 | } 441 | else 442 | nonoption_flags_len = 0; 443 | #endif 444 | 445 | return optstring; 446 | } 447 | 448 | /* Scan elements of ARGV (whose length is ARGC) for option characters 449 | given in OPTSTRING. 450 | 451 | If an element of ARGV starts with '-', and is not exactly "-" or "--", 452 | then it is an option element. The characters of this element 453 | (aside from the initial '-') are option characters. If `getopt' 454 | is called repeatedly, it returns successively each of the option characters 455 | from each of the option elements. 456 | 457 | If `getopt' finds another option character, it returns that character, 458 | updating `gnuoptind' and `nextchar' so that the next call to `getopt' can 459 | resume the scan with the following option character or ARGV-element. 460 | 461 | If there are no more option characters, `getopt' returns -1. 462 | Then `gnuoptind' is the index in ARGV of the first ARGV-element 463 | that is not an option. (The ARGV-elements have been permuted 464 | so that those that are not options now come last.) 465 | 466 | OPTSTRING is a string containing the legitimate option characters. 467 | If an option character is seen that is not listed in OPTSTRING, 468 | return '?' after printing an error message. If you set `gnuopterr' to 469 | zero, the error message is suppressed but we still return '?'. 470 | 471 | If a char in OPTSTRING is followed by a colon, that means it wants an arg, 472 | so the following text in the same ARGV-element, or the text of the following 473 | ARGV-element, is returned in `gnuoptarg'. Two colons mean an option that 474 | wants an optional arg; if there is text in the current ARGV-element, 475 | it is returned in `gnuoptarg', otherwise `gnuoptarg' is set to zero. 476 | 477 | If OPTSTRING starts with `-' or `+', it requests different methods of 478 | handling the non-option ARGV-elements. 479 | See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. 480 | 481 | Long-named options begin with `--' instead of `-'. 482 | Their names may be abbreviated as long as the abbreviation is unique 483 | or is an exact match for some defined option. If they have an 484 | argument, it follows the option name in the same ARGV-element, separated 485 | from the option name by a `=', or else the in next ARGV-element. 486 | When `getopt' finds a long-named option, it returns 0 if that option's 487 | `flag' field is nonzero, the value of the option's `val' field 488 | if the `flag' field is zero. 489 | 490 | The elements of ARGV aren't really const, because we permute them. 491 | But we pretend they're const in the prototype to be compatible 492 | with other systems. 493 | 494 | LONGOPTS is a vector of `struct option' terminated by an 495 | element containing a name which is zero. 496 | 497 | LONGIND returns the index in LONGOPT of the long-named option found. 498 | It is only valid when a long-named option has been found by the most 499 | recent call. 500 | 501 | If LONG_ONLY is nonzero, '-' as well as '--' can introduce 502 | long-named options. */ 503 | 504 | int _getopt_internal (int argc, char *const *argv, const char *optstring, 505 | const struct option *longopts, int *longind, 506 | int long_only) 507 | { 508 | int print_errors = gnuopterr; 509 | if (optstring[0] == ':') 510 | print_errors = 0; 511 | 512 | if (argc < 1) 513 | return -1; 514 | 515 | gnuoptarg = NULL; 516 | 517 | if (gnuoptind == 0 || !__getopt_initialized) 518 | { 519 | if (gnuoptind == 0) 520 | gnuoptind = 1; /* Don't scan ARGV[0], the program name. */ 521 | optstring = _getopt_initialize (argc, argv, optstring); 522 | __getopt_initialized = 1; 523 | } 524 | 525 | /* Test whether ARGV[gnuoptind] points to a non-option argument. 526 | Either it does not have option syntax, or there is an environment flag 527 | from the shell indicating it is not an option. The later information 528 | is only used when the used in the GNU libc. */ 529 | #ifdef _LIBC 530 | # define NONOPTION_P (argv[gnuoptind][0] != '-' || argv[gnuoptind][1] == '\0' \ 531 | || (gnuoptind < nonoption_flags_len \ 532 | && __getopt_nonoption_flags[gnuoptind] == '1')) 533 | #else 534 | # define NONOPTION_P (argv[gnuoptind][0] != '-' || argv[gnuoptind][1] == '\0') 535 | #endif 536 | 537 | if (nextchar == NULL || *nextchar == '\0') 538 | { 539 | /* Advance to the next ARGV-element. */ 540 | 541 | /* Give FIRST_NONOPT & LAST_NONOPT rational values if GNUOPTIND has been 542 | moved back by the user (who may also have changed the arguments). */ 543 | if (last_nonopt > gnuoptind) 544 | last_nonopt = gnuoptind; 545 | if (first_nonopt > gnuoptind) 546 | first_nonopt = gnuoptind; 547 | 548 | if (ordering == PERMUTE) 549 | { 550 | /* If we have just processed some options following some non-options, 551 | exchange them so that the options come first. */ 552 | 553 | if (first_nonopt != last_nonopt && last_nonopt != gnuoptind) 554 | exchange ((char **) argv); 555 | else if (last_nonopt != gnuoptind) 556 | first_nonopt = gnuoptind; 557 | 558 | /* Skip any additional non-options 559 | and extend the range of non-options previously skipped. */ 560 | 561 | while (gnuoptind < argc && NONOPTION_P) 562 | gnuoptind++; 563 | last_nonopt = gnuoptind; 564 | } 565 | 566 | /* The special ARGV-element `--' means premature end of options. 567 | Skip it like a null option, 568 | then exchange with previous non-options as if it were an option, 569 | then skip everything else like a non-option. */ 570 | 571 | if (gnuoptind != argc && !strcmp (argv[gnuoptind], "--")) 572 | { 573 | gnuoptind++; 574 | 575 | if (first_nonopt != last_nonopt && last_nonopt != gnuoptind) 576 | exchange ((char **) argv); 577 | else if (first_nonopt == last_nonopt) 578 | first_nonopt = gnuoptind; 579 | last_nonopt = argc; 580 | 581 | gnuoptind = argc; 582 | } 583 | 584 | /* If we have done all the ARGV-elements, stop the scan 585 | and back over any non-options that we skipped and permuted. */ 586 | 587 | if (gnuoptind == argc) 588 | { 589 | /* Set the next-arg-index to point at the non-options 590 | that we previously skipped, so the caller will digest them. */ 591 | if (first_nonopt != last_nonopt) 592 | gnuoptind = first_nonopt; 593 | return -1; 594 | } 595 | 596 | /* If we have come to a non-option and did not permute it, 597 | either stop the scan or describe it to the caller and pass it by. */ 598 | 599 | if (NONOPTION_P) 600 | { 601 | if (ordering == REQUIRE_ORDER) 602 | return -1; 603 | gnuoptarg = argv[gnuoptind++]; 604 | return 1; 605 | } 606 | 607 | /* We have found another option-ARGV-element. 608 | Skip the initial punctuation. */ 609 | 610 | nextchar = (argv[gnuoptind] + 1 611 | + (longopts != NULL && argv[gnuoptind][1] == '-')); 612 | } 613 | 614 | /* Decode the current option-ARGV-element. */ 615 | 616 | /* Check whether the ARGV-element is a long option. 617 | 618 | If long_only and the ARGV-element has the form "-f", where f is 619 | a valid short option, don't consider it an abbreviated form of 620 | a long option that starts with f. Otherwise there would be no 621 | way to give the -f short option. 622 | 623 | On the other hand, if there's a long option "fubar" and 624 | the ARGV-element is "-fu", do consider that an abbreviation of 625 | the long option, just like "--fu", and not "-f" with arg "u". 626 | 627 | This distinction seems to be the most useful approach. */ 628 | 629 | if (longopts != NULL 630 | && (argv[gnuoptind][1] == '-' 631 | || (long_only && (argv[gnuoptind][2] || !my_index (optstring, argv[gnuoptind][1]))))) 632 | { 633 | char *nameend; 634 | const struct option *p; 635 | const struct option *pfound = NULL; 636 | int exact = 0; 637 | int ambig = 0; 638 | int indfound = -1; 639 | int option_index; 640 | 641 | for (nameend = nextchar; *nameend && *nameend != '='; nameend++) 642 | /* Do nothing. */ ; 643 | 644 | /* Test all long options for either exact match 645 | or abbreviated matches. */ 646 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 647 | if (!strncmp (p->name, nextchar, nameend - nextchar)) 648 | { 649 | if ((unsigned int) (nameend - nextchar) 650 | == (unsigned int) strlen (p->name)) 651 | { 652 | /* Exact match found. */ 653 | pfound = p; 654 | indfound = option_index; 655 | exact = 1; 656 | break; 657 | } 658 | else if (pfound == NULL) 659 | { 660 | /* First nonexact match found. */ 661 | pfound = p; 662 | indfound = option_index; 663 | } 664 | else if (long_only 665 | || pfound->has_arg != p->has_arg 666 | || pfound->flag != p->flag 667 | || pfound->val != p->val) 668 | /* Second or later nonexact match found. */ 669 | ambig = 1; 670 | } 671 | 672 | if (ambig && !exact) 673 | { 674 | if (print_errors) 675 | fprintf (stderr, _("%s: option `%s' is ambiguous\n"), 676 | argv[0], argv[gnuoptind]); 677 | nextchar += strlen (nextchar); 678 | gnuoptind++; 679 | gnuoptopt = 0; 680 | return '?'; 681 | } 682 | 683 | if (pfound != NULL) 684 | { 685 | option_index = indfound; 686 | gnuoptind++; 687 | if (*nameend) 688 | { 689 | /* Don't test has_arg with >, because some C compilers don't 690 | allow it to be used on enums. */ 691 | if (pfound->has_arg) 692 | gnuoptarg = nameend + 1; 693 | else 694 | { 695 | if (print_errors) 696 | { 697 | if (argv[gnuoptind - 1][1] == '-') 698 | /* --option */ 699 | fprintf (stderr, 700 | _("%s: option `--%s' doesn't allow an argument\n"), 701 | argv[0], pfound->name); 702 | else 703 | /* +option or -option */ 704 | fprintf (stderr, 705 | _("%s: option `%c%s' doesn't allow an argument\n"), 706 | argv[0], argv[gnuoptind - 1][0], pfound->name); 707 | } 708 | 709 | nextchar += strlen (nextchar); 710 | 711 | gnuoptopt = pfound->val; 712 | return '?'; 713 | } 714 | } 715 | else if (pfound->has_arg == 1) 716 | { 717 | if (gnuoptind < argc) 718 | gnuoptarg = argv[gnuoptind++]; 719 | else 720 | { 721 | if (print_errors) 722 | fprintf (stderr, 723 | _("%s: option `%s' requires an argument\n"), 724 | argv[0], argv[gnuoptind - 1]); 725 | nextchar += strlen (nextchar); 726 | gnuoptopt = pfound->val; 727 | return optstring[0] == ':' ? ':' : '?'; 728 | } 729 | } 730 | nextchar += strlen (nextchar); 731 | if (longind != NULL) 732 | *longind = option_index; 733 | if (pfound->flag) 734 | { 735 | *(pfound->flag) = pfound->val; 736 | return 0; 737 | } 738 | return pfound->val; 739 | } 740 | 741 | /* Can't find it as a long option. If this is not getopt_long_only, 742 | or the option starts with '--' or is not a valid short 743 | option, then it's an error. 744 | Otherwise interpret it as a short option. */ 745 | if (!long_only || argv[gnuoptind][1] == '-' 746 | || my_index (optstring, *nextchar) == NULL) 747 | { 748 | if (print_errors) 749 | { 750 | if (argv[gnuoptind][1] == '-') 751 | /* --option */ 752 | fprintf (stderr, _("%s: unrecognized option `--%s'\n"), 753 | argv[0], nextchar); 754 | else 755 | /* +option or -option */ 756 | fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), 757 | argv[0], argv[gnuoptind][0], nextchar); 758 | } 759 | nextchar = (char *) ""; 760 | gnuoptind++; 761 | gnuoptopt = 0; 762 | return '?'; 763 | } 764 | } 765 | 766 | /* Look at and handle the next short option-character. */ 767 | 768 | { 769 | char c = *nextchar++; 770 | char *temp = my_index (optstring, c); 771 | 772 | /* Increment `gnuoptind' when we start to process its last character. */ 773 | if (*nextchar == '\0') 774 | ++gnuoptind; 775 | 776 | if (temp == NULL || c == ':') 777 | { 778 | if (print_errors) 779 | { 780 | fprintf (stderr, _("%s: invalid option -- %c\n"), 781 | argv[0], c); 782 | } 783 | gnuoptopt = c; 784 | return '?'; 785 | } 786 | /* Convenience. Treat POSIX -W foo same as long option --foo */ 787 | if (temp[0] == 'W' && temp[1] == ';') 788 | { 789 | char *nameend; 790 | const struct option *p; 791 | const struct option *pfound = NULL; 792 | int exact = 0; 793 | int ambig = 0; 794 | int indfound = 0; 795 | int option_index; 796 | 797 | /* This is an option that requires an argument. */ 798 | if (*nextchar != '\0') 799 | { 800 | gnuoptarg = nextchar; 801 | /* If we end this ARGV-element by taking the rest as an arg, 802 | we must advance to the next element now. */ 803 | gnuoptind++; 804 | } 805 | else if (gnuoptind == argc) 806 | { 807 | if (print_errors) 808 | { 809 | /* 1003.2 specifies the format of this message. */ 810 | fprintf (stderr, _("%s: option requires an argument -- %c\n"), 811 | argv[0], c); 812 | } 813 | gnuoptopt = c; 814 | if (optstring[0] == ':') 815 | c = ':'; 816 | else 817 | c = '?'; 818 | return c; 819 | } 820 | else 821 | /* We already incremented `gnuoptind' once; 822 | increment it again when taking next ARGV-elt as argument. */ 823 | gnuoptarg = argv[gnuoptind++]; 824 | 825 | /* gnuoptarg is now the argument, see if it's in the 826 | table of longopts. */ 827 | 828 | for (nextchar = nameend = gnuoptarg; *nameend && *nameend != '='; nameend++) 829 | /* Do nothing. */ ; 830 | 831 | /* Test all long options for either exact match 832 | or abbreviated matches. */ 833 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 834 | if (!strncmp (p->name, nextchar, nameend - nextchar)) 835 | { 836 | if ((unsigned int) (nameend - nextchar) == strlen (p->name)) 837 | { 838 | /* Exact match found. */ 839 | pfound = p; 840 | indfound = option_index; 841 | exact = 1; 842 | break; 843 | } 844 | else if (pfound == NULL) 845 | { 846 | /* First nonexact match found. */ 847 | pfound = p; 848 | indfound = option_index; 849 | } 850 | else 851 | /* Second or later nonexact match found. */ 852 | ambig = 1; 853 | } 854 | if (ambig && !exact) 855 | { 856 | if (print_errors) 857 | fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), 858 | argv[0], argv[gnuoptind]); 859 | nextchar += strlen (nextchar); 860 | gnuoptind++; 861 | return '?'; 862 | } 863 | if (pfound != NULL) 864 | { 865 | option_index = indfound; 866 | if (*nameend) 867 | { 868 | /* Don't test has_arg with >, because some C compilers don't 869 | allow it to be used on enums. */ 870 | if (pfound->has_arg) 871 | gnuoptarg = nameend + 1; 872 | else 873 | { 874 | if (print_errors) 875 | fprintf (stderr, _("\ 876 | %s: option `-W %s' doesn't allow an argument\n"), 877 | argv[0], pfound->name); 878 | 879 | nextchar += strlen (nextchar); 880 | return '?'; 881 | } 882 | } 883 | else if (pfound->has_arg == 1) 884 | { 885 | if (gnuoptind < argc) 886 | gnuoptarg = argv[gnuoptind++]; 887 | else 888 | { 889 | if (print_errors) 890 | fprintf (stderr, 891 | _("%s: option `%s' requires an argument\n"), 892 | argv[0], argv[gnuoptind - 1]); 893 | nextchar += strlen (nextchar); 894 | return optstring[0] == ':' ? ':' : '?'; 895 | } 896 | } 897 | nextchar += strlen (nextchar); 898 | if (longind != NULL) 899 | *longind = option_index; 900 | if (pfound->flag) 901 | { 902 | *(pfound->flag) = pfound->val; 903 | return 0; 904 | } 905 | return pfound->val; 906 | } 907 | nextchar = NULL; 908 | return 'W'; /* Let the application handle it. */ 909 | } 910 | if (temp[1] == ':') 911 | { 912 | if (temp[2] == ':') 913 | { 914 | /* This is an option that accepts an argument optionally. */ 915 | if (*nextchar != '\0') 916 | { 917 | gnuoptarg = nextchar; 918 | gnuoptind++; 919 | } 920 | else 921 | gnuoptarg = NULL; 922 | nextchar = NULL; 923 | } 924 | else 925 | { 926 | /* This is an option that requires an argument. */ 927 | if (*nextchar != '\0') 928 | { 929 | gnuoptarg = nextchar; 930 | /* If we end this ARGV-element by taking the rest as an arg, 931 | we must advance to the next element now. */ 932 | gnuoptind++; 933 | } 934 | else if (gnuoptind == argc) 935 | { 936 | if (print_errors) 937 | { 938 | /* 1003.2 specifies the format of this message. */ 939 | fprintf (stderr, 940 | _("%s: option requires an argument -- %c\n"), 941 | argv[0], c); 942 | } 943 | gnuoptopt = c; 944 | if (optstring[0] == ':') 945 | c = ':'; 946 | else 947 | c = '?'; 948 | } 949 | else 950 | /* We already incremented `gnuoptind' once; 951 | increment it again when taking next ARGV-elt as argument. */ 952 | gnuoptarg = argv[gnuoptind++]; 953 | nextchar = NULL; 954 | } 955 | } 956 | return c; 957 | } 958 | } 959 | 960 | int 961 | gnugetopt (int argc, char *const *argv, const char *optstring) 962 | { 963 | return _getopt_internal (argc, argv, optstring, 964 | (const struct option *) 0, 965 | (int *) 0, 966 | 0); 967 | } 968 | 969 | #endif /* Not ELIDE_CODE. */ 970 | -------------------------------------------------------------------------------- /gnugetopt.h: -------------------------------------------------------------------------------- 1 | /* Declarations for getopt. 2 | Copyright (C) 1989,90,91,92,93,94,96,97,98,99 Free Software Foundation, Inc. 3 | This file is part of the GNU C Library. 4 | 5 | The GNU C Library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Library General Public License as 7 | published by the Free Software Foundation; either version 2 of the 8 | License, or (at your option) any later version. 9 | 10 | The GNU C Library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Library General Public License for more details. 14 | 15 | You should have received a copy of the GNU Library General Public 16 | License along with the GNU C Library; see the file COPYING.LIB. If not, 17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 | Boston, MA 02111-1307, USA. */ 19 | 20 | #ifndef __GNU_GETOPT_H 21 | #define __GNU_GETOPT_H 22 | 23 | /* For communication from `getopt' to the caller. 24 | When `getopt' finds an option that takes an argument, 25 | the argument value is returned here. 26 | Also, when `ordering' is RETURN_IN_ORDER, 27 | each non-option ARGV-element is returned here. */ 28 | 29 | extern char *gnuoptarg; 30 | 31 | /* Index in ARGV of the next element to be scanned. 32 | This is used for communication to and from the caller 33 | and for communication between successive calls to `getopt'. 34 | 35 | On entry to `getopt', zero means this is the first call; initialize. 36 | 37 | When `getopt' returns -1, this is the index of the first of the 38 | non-option elements that the caller should itself scan. 39 | 40 | Otherwise, `gnuoptind' communicates from one call to the next 41 | how much of ARGV has been scanned so far. */ 42 | 43 | extern int gnuoptind; 44 | 45 | /* Callers store zero here to inhibit the error message `getopt' prints 46 | for unrecognized options. */ 47 | 48 | extern int gnuopterr; 49 | 50 | /* Set to an option character which was unrecognized. */ 51 | 52 | extern int gnuoptopt; 53 | 54 | /* modification to getopt - allows us to skip options */ 55 | extern char *nextchar; 56 | 57 | 58 | /* Describe the long-named options requested by the application. 59 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 60 | of `struct option' terminated by an element containing a name which is 61 | zero. 62 | 63 | The field `has_arg' is: 64 | no_argument (or 0) if the option does not take an argument, 65 | required_argument (or 1) if the option requires an argument, 66 | optional_argument (or 2) if the option takes an optional argument. 67 | 68 | If the field `flag' is not NULL, it points to a variable that is set 69 | to the value given in the field `val' when the option is found, but 70 | left unchanged if the option is not found. 71 | 72 | To have a long-named option do something other than set an `int' to 73 | a compiled-in constant, such as set a value from `gnuoptarg', set the 74 | option's `flag' field to zero and its `val' field to a nonzero 75 | value (the equivalent single-letter option character, if there is 76 | one). For long options that have a zero `flag' field, `getopt' 77 | returns the contents of the `val' field. */ 78 | 79 | struct option 80 | { 81 | # if defined __STDC__ && __STDC__ 82 | const char *name; 83 | # else 84 | char *name; 85 | # endif 86 | /* has_arg can't be an enum because some compilers complain about 87 | type mismatches in all the code that assumes it is an int. */ 88 | int has_arg; 89 | int *flag; 90 | int val; 91 | }; 92 | 93 | /* Names for the values of the `has_arg' field of `struct option'. */ 94 | 95 | # define no_argument 0 96 | # define required_argument 1 97 | # define optional_argument 2 98 | 99 | 100 | /* Get definitions and prototypes for functions to process the 101 | arguments in ARGV (ARGC of them, minus the program name) for 102 | options given in OPTS. 103 | 104 | Return the option character from OPTS just read. Return -1 when 105 | there are no more options. For unrecognized options, or options 106 | missing arguments, `gnuoptopt' is set to the option letter, and '?' is 107 | returned. 108 | 109 | The OPTS string is a list of characters which are recognized option 110 | letters, optionally followed by colons, specifying that that letter 111 | takes an argument, to be placed in `gnuoptarg'. 112 | 113 | If a letter in OPTS is followed by two colons, its argument is 114 | optional. This behavior is specific to the GNU `getopt'. 115 | 116 | The argument `--' causes premature termination of argument 117 | scanning, explicitly telling `getopt' that there are no more 118 | options. 119 | 120 | If OPTS begins with `--', then non-option arguments are treated as 121 | arguments to the option '\0'. This behavior is specific to the GNU 122 | `getopt'. */ 123 | 124 | extern int gnugetopt (int __argc, char *const *__argv, const char *__shortopts); 125 | extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, 126 | const struct option *__longopts, int *__longind); 127 | extern int getopt_long_only (int __argc, char *const *__argv, 128 | const char *__shortopts, 129 | const struct option *__longopts, int *__longind); 130 | 131 | /* Internal only. Users should not call this directly. */ 132 | extern int _getopt_internal (int __argc, char *const *__argv, 133 | const char *__shortopts, 134 | const struct option *__longopts, int *__longind, 135 | int __long_only); 136 | 137 | #endif /* getopt.h */ 138 | -------------------------------------------------------------------------------- /gnugetopt1.c: -------------------------------------------------------------------------------- 1 | /* ripped straight from glibc, with minor modifications. Included to make sure 2 | we get getopt_long_only on all systems 3 | */ 4 | 5 | /* getopt_long and getopt_long_only entry points for GNU getopt. 6 | Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 7 | Free Software Foundation, Inc. 8 | This file is part of the GNU C Library. 9 | 10 | The GNU C Library is free software; you can redistribute it and/or 11 | modify it under the terms of the GNU Library General Public License as 12 | published by the Free Software Foundation; either version 2 of the 13 | License, or (at your option) any later version. 14 | 15 | The GNU C Library is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | Library General Public License for more details. 19 | 20 | You should have received a copy of the GNU Library General Public 21 | License along with the GNU C Library; see the file COPYING.LIB. If not, 22 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 23 | Boston, MA 02111-1307, USA. */ 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include 27 | #endif 28 | 29 | #include "gnugetopt.h" 30 | 31 | #if !defined __STDC__ || !__STDC__ 32 | /* This is a separate conditional since some stdc systems 33 | reject `defined (const)'. */ 34 | #ifndef const 35 | #define const 36 | #endif 37 | #endif 38 | 39 | #include 40 | 41 | /* Comment out all this code if we are using the GNU C Library, and are not 42 | actually compiling the library itself. This code is part of the GNU C 43 | Library, but also included in many other GNU distributions. Compiling 44 | and linking in this code is a waste when using the GNU C library 45 | (especially if it is a shared library). Rather than having every GNU 46 | program understand `configure --with-gnu-libc' and omit the object files, 47 | it is simpler to just do this in the source for each such file. */ 48 | /* 49 | #define GETOPT_INTERFACE_VERSION 2 50 | #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 51 | #include 52 | #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION 53 | #define ELIDE_CODE 54 | #endif 55 | #endif 56 | */ 57 | #ifndef ELIDE_CODE 58 | 59 | 60 | /* This needs to come after some library #include 61 | to get __GNU_LIBRARY__ defined. */ 62 | #ifdef __GNU_LIBRARY__ 63 | #include 64 | #endif 65 | 66 | #ifndef NULL 67 | #define NULL 0 68 | #endif 69 | 70 | int getopt_long (int argc, char *const *argv, const char *options, 71 | const struct option *long_options, int *opt_index) 72 | { 73 | return _getopt_internal (argc, argv, options, long_options, opt_index, 0); 74 | } 75 | 76 | /* Like getopt_long, but '-' as well as '--' can indicate a long option. 77 | If an option that starts with '-' (not '--') doesn't match a long option, 78 | but does match a short option, it is parsed as a short option 79 | instead. */ 80 | 81 | int 82 | getopt_long_only (int argc, char *const *argv, const char *options, 83 | const struct option *long_options, int *opt_index) 84 | { 85 | return _getopt_internal (argc, argv, options, long_options, opt_index, 1); 86 | } 87 | 88 | 89 | #endif /* Not ELIDE_CODE. */ 90 | 91 | #ifdef TEST 92 | 93 | #include 94 | 95 | int 96 | main (argc, argv) 97 | int argc; 98 | char **argv; 99 | { 100 | int c; 101 | int digit_gnuoptind = 0; 102 | 103 | while (1) 104 | { 105 | int this_option_gnuoptind = gnuoptind ? gnuoptind : 1; 106 | int option_index = 0; 107 | static struct option long_options[] = 108 | { 109 | {"add", 1, 0, 0}, 110 | {"append", 0, 0, 0}, 111 | {"delete", 1, 0, 0}, 112 | {"verbose", 0, 0, 0}, 113 | {"create", 0, 0, 0}, 114 | {"file", 1, 0, 0}, 115 | {0, 0, 0, 0} 116 | }; 117 | 118 | c = getopt_long (argc, argv, "abc:d:0123456789", 119 | long_options, &option_index); 120 | if (c == -1) 121 | break; 122 | 123 | switch (c) 124 | { 125 | case 0: 126 | printf ("option %s", long_options[option_index].name); 127 | if (gnuoptarg) 128 | printf (" with arg %s", gnuoptarg); 129 | printf ("\n"); 130 | break; 131 | 132 | case '0': 133 | case '1': 134 | case '2': 135 | case '3': 136 | case '4': 137 | case '5': 138 | case '6': 139 | case '7': 140 | case '8': 141 | case '9': 142 | if (digit_gnuoptind != 0 && digit_gnuoptind != this_option_gnuoptind) 143 | printf ("digits occur in two different argv-elements.\n"); 144 | digit_gnuoptind = this_option_gnuoptind; 145 | printf ("option %c\n", c); 146 | break; 147 | 148 | case 'a': 149 | printf ("option a\n"); 150 | break; 151 | 152 | case 'b': 153 | printf ("option b\n"); 154 | break; 155 | 156 | case 'c': 157 | printf ("option c with value `%s'\n", gnuoptarg); 158 | break; 159 | 160 | case 'd': 161 | printf ("option d with value `%s'\n", gnuoptarg); 162 | break; 163 | 164 | case '?': 165 | break; 166 | 167 | default: 168 | printf ("?? getopt returned character code 0%o ??\n", c); 169 | } 170 | } 171 | 172 | if (gnuoptind < argc) 173 | { 174 | printf ("non-option ARGV-elements: "); 175 | while (gnuoptind < argc) 176 | printf ("%s ", argv[gnuoptind++]); 177 | printf ("\n"); 178 | } 179 | 180 | exit (0); 181 | } 182 | 183 | #endif /* TEST */ 184 | -------------------------------------------------------------------------------- /help2man: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickettm/SendIP/aad12a001157489ab9053c8665e09aec24a2ff6d/help2man -------------------------------------------------------------------------------- /icmp.c: -------------------------------------------------------------------------------- 1 | /* icmp.c - ICMP support for sendip 2 | * Author: Mike Ricketts 3 | * ChangeLog since 2.0 release: 4 | * 02/12/2001: Moved ipv6_csum into here as this is where it is used. 5 | * 02/12/2001: Merged icmp6csum with ipv6_csum 6 | * 02/12/2001: Only check one layer of headers for enclosing ipv[46] header 7 | * 22/01/2002: Include string.h 8 | * 22/02/2002: Fix alignment problem in icmp*csum 9 | * ChangeLog since 2.1 release: 10 | * 16/04/2002: Move ipv6_pseudo_header into ipv6.h so tcp.c and udp.c can get it 11 | * ChangeLog since 2.4 release: 12 | * 21/04/2003: Fix errors detected by valgrind 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "sendip_module.h" 20 | #include "icmp.h" 21 | #include "ipv4.h" 22 | #include "ipv6.h" 23 | 24 | /* Character that identifies our options 25 | */ 26 | const char opt_char='c'; 27 | 28 | static void icmpcsum(sendip_data *icmp_hdr, sendip_data *data) { 29 | icmp_header *icp = (icmp_header *)icmp_hdr->data; 30 | u_int16_t *buf = malloc(icmp_hdr->alloc_len+data->alloc_len); 31 | u_int8_t *tempbuf = (u_int8_t *)buf; 32 | icp->check = 0; 33 | if(tempbuf == NULL) { 34 | fprintf(stderr,"Out of memory: ICMP checksum not computed\n"); 35 | return; 36 | } 37 | memcpy(tempbuf,icmp_hdr->data,icmp_hdr->alloc_len); 38 | memcpy(tempbuf+icmp_hdr->alloc_len,data->data,data->alloc_len); 39 | icp->check = csum(buf,icmp_hdr->alloc_len+data->alloc_len); 40 | free(buf); 41 | } 42 | 43 | static void icmp6csum(struct in6_addr *src, struct in6_addr *dst, 44 | sendip_data *hdr, sendip_data *data) { 45 | icmp_header *icp = (icmp_header *)hdr->data; 46 | struct ipv6_pseudo_hdr phdr; 47 | 48 | /* Make sure tempbuf is word aligned */ 49 | u_int16_t *buf = malloc(sizeof(phdr)+hdr->alloc_len+data->alloc_len); 50 | u_int8_t *tempbuf = (u_int8_t *)buf; 51 | icp->check = 0; 52 | if(tempbuf == NULL) { 53 | fprintf(stderr,"Out of memory: ICMP checksum not computed\n"); 54 | return; 55 | } 56 | memcpy(tempbuf+sizeof(phdr), hdr->data, hdr->alloc_len); 57 | memcpy(tempbuf+sizeof(phdr)+hdr->alloc_len, data->data, data->alloc_len); 58 | 59 | /* do an ipv6 checksum */ 60 | memset(&phdr, 0, sizeof(phdr)); 61 | memcpy(&phdr.source, src, sizeof(struct in6_addr)); 62 | memcpy(&phdr.destination, dst, sizeof(struct in6_addr)); 63 | phdr.ulp_length = htonl(hdr->alloc_len+data->alloc_len); 64 | phdr.nexthdr = IPPROTO_ICMPV6; 65 | 66 | memcpy(tempbuf, &phdr, sizeof(phdr)); 67 | 68 | icp->check = csum(buf,sizeof(phdr)+hdr->alloc_len+data->alloc_len); 69 | free(buf); 70 | } 71 | 72 | sendip_data *initialize(void) { 73 | sendip_data *ret = malloc(sizeof(sendip_data)); 74 | icmp_header *icmp = malloc(sizeof(icmp_header)); 75 | memset(icmp,0,sizeof(icmp_header)); 76 | ret->alloc_len = sizeof(icmp_header); 77 | ret->data = (void *)icmp; 78 | ret->modified=0; 79 | return ret; 80 | } 81 | 82 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 83 | icmp_header *icp = (icmp_header *)pack->data; 84 | switch(opt[1]) { 85 | case 't': 86 | icp->type = (u_int8_t)strtoul(arg, (char **)NULL, 0); 87 | pack->modified |= ICMP_MOD_TYPE; 88 | break; 89 | case 'd': 90 | icp->code = (u_int8_t)strtoul(arg, (char **)NULL, 0); 91 | pack->modified |= ICMP_MOD_CODE; 92 | break; 93 | case 'c': 94 | icp->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 95 | pack->modified |= ICMP_MOD_CHECK; 96 | break; 97 | } 98 | return TRUE; 99 | 100 | } 101 | 102 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 103 | sendip_data *pack) { 104 | icmp_header *icp = (icmp_header *)pack->data; 105 | int i=strlen(hdrs)-1; 106 | 107 | /* Find enclosing IP header and do the checksum */ 108 | if(hdrs[i]=='i') { 109 | // ipv4 110 | if(!(headers[i]->modified&IP_MOD_PROTOCOL)) { 111 | ((ip_header *)(headers[i]->data))->protocol=IPPROTO_ICMP; 112 | headers[i]->modified |= IP_MOD_PROTOCOL; 113 | } 114 | } else if(hdrs[i]=='6') { 115 | // ipv6 116 | if(!(headers[i]->modified&IPV6_MOD_NXT)) { 117 | ((ipv6_header *)(headers[i]->data))->ip6_nxt=IPPROTO_ICMPV6; 118 | headers[i]->modified |= IPV6_MOD_NXT; 119 | } 120 | } 121 | 122 | if(!(pack->modified&ICMP_MOD_TYPE)) { 123 | if(hdrs[i]=='6') { 124 | icp->type=ICMP6_ECHO_REQUEST; 125 | } else { 126 | icp->type=ICMP_ECHO; 127 | } 128 | } 129 | 130 | if(!(pack->modified&ICMP_MOD_CHECK)) { 131 | if (hdrs[i] == '6') { 132 | // ipv6 133 | struct in6_addr *src, *dst; 134 | src = (struct in6_addr *)&(((ipv6_header *)(headers[i]->data))->ip6_src); 135 | dst = (struct in6_addr *)&(((ipv6_header *)(headers[i]->data))->ip6_dst); 136 | icmp6csum(src, dst, pack, data); 137 | } else { 138 | // ipv4 or anything else 139 | icmpcsum(pack,data); 140 | } 141 | } 142 | return TRUE; 143 | } 144 | 145 | int num_opts() { 146 | return sizeof(icmp_opts)/sizeof(sendip_option); 147 | } 148 | sendip_option *get_opts() { 149 | return icmp_opts; 150 | } 151 | char get_optchar() { 152 | return opt_char; 153 | } 154 | -------------------------------------------------------------------------------- /icmp.h: -------------------------------------------------------------------------------- 1 | /* icmp.h 2 | */ 3 | #ifndef _SENDIP_ICMP_H 4 | #define _SENDIP_ICMP_H 5 | 6 | #define ICMP6_ECHO_REQUEST 128 7 | #define ICMP_ECHO 8 8 | 9 | /* ICMP HEADER 10 | * Copied from glibc 2.2, reproduced here without code specific stuff 11 | */ 12 | typedef struct { 13 | u_int8_t type; 14 | u_int8_t code; 15 | u_int16_t check; 16 | } icmp_header; 17 | 18 | 19 | /* Defines for which parts have been modified 20 | */ 21 | #define ICMP_MOD_TYPE 1 22 | #define ICMP_MOD_CODE 1<<1 23 | #define ICMP_MOD_CHECK 1<<2 24 | 25 | /* Options 26 | */ 27 | sendip_option icmp_opts[] = { 28 | {"t",1,"ICMP message type","ICMP_ECHO (8), or ICMP6_ECHO_REQUEST (128) if embedded in an IPv6 packet"}, 29 | {"d",1,"ICMP code","0"}, 30 | {"c",1,"ICMP checksum","Correct"} 31 | }; 32 | 33 | #endif /* _SENDIP_ICMP_H */ 34 | -------------------------------------------------------------------------------- /ipv4.c: -------------------------------------------------------------------------------- 1 | /* ipv4.c - IPV4 code for sendip 2 | * Author: Mike Ricketts 3 | * ChangeLog from 2.0 release: 4 | * 26/11/2001 IP options 5 | * 23/01/2002 Spelling fix (Dax Kelson ) 6 | * 26/08/2002 Put tot_len field in host byte order on FreeBSD 7 | * ChangeLog since 2.2 release: 8 | * 24/11/2002 make it compile on archs that care about alignment 9 | * ChangeLog since 2.3 release: 10 | * 23/12/2002 fix bug with -iossr and -iolsr 11 | * 20/01/2003 fix FreeBSD sendto(): invalid argument error. Again. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "sendip_module.h" 22 | #include "ipv4.h" 23 | 24 | /* Character that identifies our options 25 | */ 26 | const char opt_char='i'; 27 | 28 | static void ipcsum(sendip_data *ip_hdr) { 29 | ip_header *ip = (ip_header *)ip_hdr->data; 30 | ip->check=0; 31 | ip->check=csum((u_int16_t *)ip_hdr->data, ip_hdr->alloc_len); 32 | } 33 | 34 | /* This builds a source route format option from an argument */ 35 | static u_int8_t buildroute(char *data) { 36 | char *data_out = data; 37 | char *data_in = data; 38 | char *next; 39 | u_int8_t p='0'; 40 | int i; 41 | /* First, the first 2 bytes give us the pointer */ 42 | for(i=0;i<2;i++) { 43 | p<<=4; 44 | if('0'<=*data_in && *data_in<='9') { 45 | p+=*data_in-'0'; 46 | } else if('A'<=*data_in && *data_in<='F') { 47 | p+=*data_in-'A'+0x0A; 48 | } else if('a'<=*data_in && *data_in<='f') { 49 | p+=*data_in-'a'+0x0a; 50 | } else { 51 | fprintf(stderr,"First 2 chars of record route options must be hex pointer\n"); 52 | return 0; 53 | } 54 | data_in++; 55 | } 56 | *(data_out++)=p; 57 | 58 | /* Now loop through IP addresses... */ 59 | if(*data_in != ':') { 60 | fprintf(stderr,"Third char of a record route option must be a :\n"); 61 | return 0; 62 | } 63 | data_in++; 64 | next=data_in; 65 | while(next) { 66 | u_int32_t ip; 67 | next=strchr(data_in,':'); 68 | if(next) { 69 | *(next++)=0; 70 | } 71 | ip=inet_addr(data_in); 72 | memcpy(data_out,&ip,4); 73 | data_out+=4; 74 | data_in = next; 75 | } 76 | 77 | return (data_out-data); 78 | } 79 | 80 | /* This bears an incredible resemblance to the TCP addoption function... */ 81 | static void addoption(u_int8_t copy, u_int8_t class, u_int8_t num, 82 | u_int8_t len, u_int8_t *data, 83 | sendip_data *pack) { 84 | /* opt is copy flag (1bit) + class (2 bit) + number (5 bit) */ 85 | u_int8_t opt = ((copy&1)<<7) | ((class&3)<<5) | (num&31); 86 | pack->data = realloc(pack->data, pack->alloc_len + len); 87 | *((u_int8_t *)pack->data+pack->alloc_len) = opt; 88 | if(len > 1) 89 | *((u_int8_t *)pack->data+pack->alloc_len+1) = len; 90 | if(len > 2) 91 | memcpy((u_int8_t *)pack->data+pack->alloc_len+2,data,len-2); 92 | pack->alloc_len += len; 93 | } 94 | 95 | sendip_data *initialize(void) { 96 | sendip_data *ret = malloc(sizeof(sendip_data)); 97 | ip_header *ip = malloc(sizeof(ip_header)); 98 | memset(ip,0,sizeof(ip_header)); 99 | ret->alloc_len = sizeof(ip_header); 100 | ret->data = (void *)ip; 101 | ret->modified=0; 102 | return ret; 103 | } 104 | 105 | bool set_addr(char *hostname, sendip_data *pack) { 106 | ip_header *ip = (ip_header *)pack->data; 107 | struct hostent *host = gethostbyname2(hostname,AF_INET); 108 | if(!(pack->modified & IP_MOD_SADDR)) { 109 | ip->saddr = inet_addr("127.0.0.1"); 110 | } 111 | if(!(pack->modified & IP_MOD_DADDR)) { 112 | if(host==NULL) return FALSE; 113 | if(host->h_length != sizeof(ip->daddr)) { 114 | fprintf(stderr,"IPV4 destination address is the wrong size!!!"); 115 | return FALSE; 116 | } 117 | memcpy(&(ip->daddr),host->h_addr,host->h_length); 118 | } 119 | return TRUE; 120 | } 121 | 122 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 123 | ip_header *iph = (ip_header *)pack->data; 124 | switch(opt[1]) { 125 | case 's': 126 | iph->saddr = inet_addr(arg); 127 | pack->modified |= IP_MOD_SADDR; 128 | break; 129 | case 'd': 130 | iph->daddr = inet_addr(arg); 131 | pack->modified |= IP_MOD_DADDR; 132 | break; 133 | case 'h': 134 | iph->header_len = (unsigned int)strtoul(arg, (char **)NULL, 0) & 0xF; 135 | pack->modified |= IP_MOD_HEADERLEN; 136 | break; 137 | case 'v': 138 | iph->version = (unsigned int)strtoul(arg, (char **)NULL, 0) & 0xF; 139 | pack->modified |= IP_MOD_VERSION; 140 | break; 141 | case 'y': 142 | iph->tos = (u_int8_t)strtoul(arg, (char **)NULL, 0); 143 | pack->modified |= IP_MOD_TOS; 144 | break; 145 | case 'l': 146 | iph->tot_len = (u_int16_t)strtoul(arg, (char **)NULL, 0); 147 | #ifndef __FreeBSD__ 148 | #ifndef __FreeBSD 149 | iph->tot_len = htons(iph->tot_len); 150 | #endif 151 | #endif 152 | pack->modified |= IP_MOD_TOTLEN; 153 | break; 154 | case 'i': 155 | iph->id = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 156 | pack->modified |= IP_MOD_ID; 157 | break; 158 | 159 | case 'f': 160 | if(opt[2]) { 161 | /* Note: *arg&1 is what we want because: 162 | if arg=="0", *arg&1==0 163 | if arg=="1", *arg&1==1 164 | otherwise, it doesn't really matter... 165 | */ 166 | switch(opt[2]) { 167 | case 'r': 168 | iph->res=*arg&1; 169 | pack->modified |= IP_MOD_RES; 170 | break; 171 | case 'd': 172 | iph->df=*arg&1; 173 | pack->modified |= IP_MOD_DF; 174 | break; 175 | case 'm': 176 | iph->mf=*arg&1; 177 | pack->modified |= IP_MOD_MF; 178 | break; 179 | } 180 | } else { 181 | IP_SET_FRAGOFF(iph,(u_int16_t)strtoul(arg, (char **)NULL, 0) & 182 | (u_int16_t)0x1FFF); 183 | pack->modified |= IP_MOD_FRAGOFF; 184 | break; 185 | } 186 | break; 187 | 188 | case 't': 189 | iph->ttl = (u_int8_t)strtoul(arg, (char **)NULL, 0); 190 | pack->modified |= IP_MOD_TTL; 191 | break; 192 | case 'p': 193 | iph->protocol = (u_int8_t)strtoul(arg, (char **)NULL, 0); 194 | pack->modified |= IP_MOD_PROTOCOL; 195 | break; 196 | case 'c': 197 | iph->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 198 | pack->modified |= IP_MOD_CHECK; 199 | break; 200 | 201 | 202 | case 'o': 203 | /* IP options */ 204 | if(!strcmp(opt+2, "num")) { 205 | /* Other options (auto legnth) */ 206 | u_int8_t cp, cls, num, len; 207 | u_int8_t *data = malloc(strlen(arg)+2); 208 | if(!data) { 209 | fprintf(stderr,"Out of memory!\n"); 210 | return FALSE; 211 | } 212 | sprintf((char*)data,"0x%s",arg); 213 | len = compact_string((char*)data); 214 | cp=(*data&0x80)>>7; 215 | cls=(*data&0x60)>>5; 216 | num=(*data&0x1F); 217 | addoption(cp,cls,num,len+1,data+1,pack); 218 | free(data); 219 | } else if(!strcmp(opt+2, "eol")) { 220 | /* End of list */ 221 | addoption(0,0,0,1,NULL,pack); 222 | } else if(!strcmp(opt+2, "nop")) { 223 | /* NOP */ 224 | addoption(0,0,1,1,NULL,pack); 225 | } else if(!strcmp(opt+2, "rr")) { 226 | /* Record route 227 | * Format is the same as for loose source route 228 | */ 229 | char *data = strdup(arg); 230 | u_int8_t len; 231 | if(!data) { 232 | fprintf(stderr,"Out of memory!\n"); 233 | return FALSE; 234 | } 235 | len = buildroute(data); 236 | if(len==0) { 237 | free(data); 238 | return FALSE; 239 | } else { 240 | addoption(0,0,7,len+2,(u_int8_t*)data,pack); 241 | free(data); 242 | } 243 | } else if(!strcmp(opt+2, "ts")) { 244 | /* Time stamp (RFC791) 245 | * Format is: 246 | * type (68, 8bit) 247 | * length (automatic, 8bit) 248 | * pointer (8bit) 249 | * overflow (4bit), flag (4bit) 250 | * if(flag) ip1 (32bit) 251 | * timestamp1 (32bit) 252 | * if(flag) ip2 (32bit) 253 | * timestamp2 (32bit) 254 | * ... 255 | */ 256 | char *data = strdup(arg); 257 | char *data_in = data; 258 | char *data_out = data; 259 | char *next; 260 | u_int8_t p=0; 261 | int i; 262 | if(data==NULL) { 263 | fprintf(stderr,"Out of memory\n"); 264 | return FALSE; 265 | } 266 | 267 | /* First, get the pointer */ 268 | for(i=0;i<2;i++) { 269 | p<<=4; 270 | if('0'<=*data_in && *data_in<='9') { 271 | p+=*data_in-'0'; 272 | } else if('A'<=*data_in && *data_in<='F') { 273 | p+=*data_in-'A'+0x0A; 274 | } else if('a'<=*data_in && *data_in<='f') { 275 | p+=*data_in-'a'+0x0a; 276 | } else { 277 | fprintf(stderr, 278 | "First 2 chars of IP timestamp must be hex pointer\n"); 279 | free(data); 280 | return FALSE; 281 | } 282 | data_in++; 283 | } 284 | *(data_out++)=p; 285 | 286 | /* Skip a : */ 287 | if(*(data_in++) != ':') { 288 | fprintf(stderr,"Third char of IP timestamp must be :\n"); 289 | free(data); 290 | return FALSE; 291 | } 292 | 293 | /* Get the overflow and skip a : */ 294 | next = strchr(data_in,':'); 295 | if(!next) { 296 | fprintf(stderr,"IP timestamp option incorrect\n"); 297 | free(data); 298 | return FALSE; 299 | } 300 | *(next++)=0; 301 | i = atoi(data_in); 302 | if(i > 15) { 303 | fprintf(stderr,"IP timestamp overflow too big (max 15)\n"); 304 | free(data); 305 | return FALSE; 306 | } 307 | *data_out=(u_int8_t)(i<<4); 308 | data_in=next; 309 | 310 | /* Now get the flag and skip a : */ 311 | next = strchr(data_in,':'); 312 | if(!next) { 313 | fprintf(stderr,"IP timestamp option incorrect\n"); 314 | free(data); 315 | return FALSE; 316 | } 317 | *(next++)=0; 318 | i = atoi(data_in); 319 | if(i > 15) { 320 | fprintf(stderr,"IP timestamp flag too big (max 3)\n"); 321 | free(data); 322 | return FALSE; 323 | } else if(i!=0 && i!=1 && i!=3) { 324 | fprintf(stderr, 325 | "Warning: IP timestamp flag value %d not understood\n",i); 326 | } 327 | (*data_out)+=(u_int8_t)i; 328 | data_in=next; data_out++; 329 | 330 | /* Fill in (ip?) timestamp pairs */ 331 | while(next) { 332 | u_int32_t ts; 333 | if(i) { /* if we need IPs */ 334 | u_int32_t ip; 335 | next=strchr(data_in,':'); 336 | if(!next) { 337 | fprintf(stderr,"IP address in IP timestamp option must be followed by a timesamp\n"); 338 | free(data); 339 | return FALSE; 340 | } 341 | *(next++)=0; 342 | ip=inet_addr(data_in); 343 | memcpy(data_out,&ip,4); 344 | data_out+=4; 345 | data_in = next; 346 | } 347 | next=strchr(next,':'); 348 | if(next) *(next++)=0; 349 | ts = htonl(atoi(data_in)); 350 | memcpy(data_out,&ts,4); 351 | data_out+=4; 352 | data_in = next; 353 | } 354 | 355 | addoption(0,2,4,data_out-data+2,(u_int8_t*)data,pack); 356 | free(data); 357 | /* End of timestamp parsing */ 358 | 359 | } else if(!strcmp(opt+2, "lsr")) { 360 | /* Loose Source Route 361 | * Format is: 362 | * type (131, 8bit) 363 | * length (automatic, 8bit) 364 | * pointer (>=4, 8bit) 365 | * ip address0 (32bit) 366 | * ip address1 (32bit) 367 | * ... 368 | */ 369 | char *data = strdup(arg); 370 | u_int8_t len; 371 | if(!data) { 372 | fprintf(stderr,"Out of memory!\n"); 373 | return FALSE; 374 | } 375 | len = buildroute(data); 376 | if(len==0) { 377 | free(data); 378 | return FALSE; 379 | } else { 380 | addoption(1,0,3,len+2,(u_int8_t*)data,pack); 381 | free(data); 382 | } 383 | } else if(!strcmp(opt+2, "sid")) { 384 | /* Stream ID (RFC791) */ 385 | u_int16_t sid = htons(atoi(arg)); 386 | addoption(1,0,8,4,(u_int8_t *)&sid,pack); 387 | } else if(!strcmp(opt+2, "ssr")) { 388 | /* Strict Source Route 389 | * Format is identical to loose source route 390 | */ 391 | char *data = strdup(arg); 392 | u_int8_t len; 393 | if(!data) { 394 | fprintf(stderr,"Out of memory!\n"); 395 | return FALSE; 396 | } 397 | len = buildroute(data); 398 | if(len==0) { 399 | free(data); 400 | return FALSE; 401 | } else { 402 | addoption(1,0,9,len+2,(u_int8_t*)data,pack); 403 | free(data); 404 | } 405 | } else { 406 | fprintf(stderr, "unsupported IP option %s val %s\n", opt, arg); 407 | return FALSE; 408 | } 409 | break; 410 | 411 | default: 412 | usage_error("unknown IP option\n"); 413 | return FALSE; 414 | break; 415 | } 416 | return TRUE; 417 | 418 | } 419 | 420 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 421 | sendip_data *pack) { 422 | ip_header *iph = (ip_header *)pack->data; 423 | 424 | if(!(pack->modified & IP_MOD_VERSION)) { 425 | iph->version=4; 426 | } 427 | if(!(pack->modified & IP_MOD_HEADERLEN)) { 428 | iph->header_len=(pack->alloc_len+3)/4; 429 | } 430 | if(!(pack->modified & IP_MOD_TOTLEN)) { 431 | iph->tot_len=pack->alloc_len + data->alloc_len; 432 | #ifndef __FreeBSD__ 433 | #ifndef __FreeBSD 434 | iph->tot_len = htons(iph->tot_len); 435 | #endif 436 | #endif 437 | } 438 | if(!(pack->modified & IP_MOD_ID)) { 439 | iph->id = rand(); 440 | } 441 | if(!(pack->modified & IP_MOD_TTL)) { 442 | iph->ttl = 255; 443 | } 444 | if(!(pack->modified & IP_MOD_CHECK)) { 445 | ipcsum(pack); 446 | } 447 | return TRUE; 448 | } 449 | 450 | int num_opts() { 451 | return sizeof(ip_opts)/sizeof(sendip_option); 452 | } 453 | sendip_option *get_opts() { 454 | return ip_opts; 455 | } 456 | char get_optchar() { 457 | return opt_char; 458 | } 459 | -------------------------------------------------------------------------------- /ipv4.h: -------------------------------------------------------------------------------- 1 | /* ip.h 2 | */ 3 | #ifndef _SENDIP_IP_H 4 | #define _SENDIP_IP_H 5 | 6 | /* IP HEADER 7 | * Taken from glibc 2.2, and modified 8 | */ 9 | typedef struct { 10 | #if __BYTE_ORDER == __LITTLE_ENDIAN 11 | unsigned int header_len:4; 12 | unsigned int version:4; 13 | #elif __BYTE_ORDER == __BIG_ENDIAN 14 | unsigned int version:4; 15 | unsigned int header_len:4; 16 | #else 17 | # error "Please fix " 18 | #endif 19 | u_int8_t tos; 20 | u_int16_t tot_len; 21 | u_int16_t id; 22 | // FreeBSD automatically hotnses this, for some reason. 23 | #if defined(__FreeBSD__) || defined(__FreeBSD) 24 | u_int16_t res:1; 25 | u_int16_t df:1; 26 | u_int16_t mf:1; 27 | u_int16_t frag_off:13; 28 | #define IP_SET_FRAGOFF(ip,v) (ip)->frag_off=(v) 29 | #elif __BYTE_ORDER == __LITTLE_ENDIAN 30 | u_int16_t frag_off1:5; 31 | u_int16_t mf:1; 32 | u_int16_t df:1; 33 | u_int16_t res:1; 34 | u_int16_t frag_off2:8; 35 | #define IP_SET_FRAGOFF(ip,v) {(ip)->frag_off1=((v)&0x1F00)>>8;(ip)->frag_off2=(v)&0x00FF;} 36 | #elif __BYTE_ORDER == __BIG_ENDIAN 37 | u_int16_t res:1; 38 | u_int16_t df:1; 39 | u_int16_t mf:1; 40 | u_int16_t frag_off:13; 41 | #define IP_SET_FRAGOFF(ip,v) (ip)->frag_off=(v) 42 | #else 43 | # error "Please fix " 44 | #endif 45 | u_int8_t ttl; 46 | u_int8_t protocol; 47 | u_int16_t check; 48 | u_int32_t saddr; 49 | u_int32_t daddr; 50 | } ip_header; 51 | 52 | /* Defines for which parts have been modified 53 | */ 54 | #define IP_MOD_HEADERLEN (1) 55 | #define IP_MOD_VERSION (1<<1) 56 | #define IP_MOD_TOS (1<<2) 57 | #define IP_MOD_TOTLEN (1<<3) 58 | #define IP_MOD_ID (1<<4) 59 | #define IP_MOD_RES (1<<5) 60 | #define IP_MOD_DF (1<<6) 61 | #define IP_MOD_MF (1<<7) 62 | #define IP_MOD_FRAGOFF (1<<8) 63 | #define IP_MOD_TTL (1<<9) 64 | #define IP_MOD_PROTOCOL (1<<10) 65 | #define IP_MOD_CHECK (1<<11) 66 | #define IP_MOD_SADDR (1<<12) 67 | #define IP_MOD_DADDR (1<<13) 68 | 69 | /* Options 70 | */ 71 | sendip_option ip_opts[] = { 72 | {"s",1,"Source IP address (see README)","127.0.0.1"}, 73 | {"d",1,"Desitnation IP address","Correct"}, 74 | {"h",1,"IP header length (see README)","Correct"}, 75 | {"v",1,"IP version (you almost definately don't want to change this)","4"}, 76 | {"y",1,"IP type of service","0"}, 77 | {"l",1,"Total IP packet length (see README)","Correct"}, 78 | {"i",1,"IP packet ID (see README)","Random"}, 79 | {"fr",1,"IP reservced flag (see README)","0 (options are 0,1,r)"}, 80 | {"fd",1,"IP don't fragment flag (see README)","0 (options are 0,1,r)"}, 81 | {"fm",1,"IP more fragments flag (see README)","0 (options are 0,1,r)"}, 82 | {"f",1,"IP fragment offset","0"}, 83 | {"t",1,"IP time to live","255"}, 84 | {"p",1,"IP protcol","0, or set by underlying protocol"}, 85 | {"c",1,"IP checksum (see README)","Correct"}, 86 | 87 | {"onum",1,"IP option as string of hex bytes (length is always correct)","(no options)"}, 88 | {"oeol",0,"IP option: end of list",NULL}, 89 | {"onop",0,"IP option: no-op",NULL}, 90 | {"orr",1,"IP option: record route. Format: pointer:addr1:addr2:...",NULL}, 91 | {"ots",1,"IP option: timestamp. Format: pointer:overflow:flag:(ip1:)ts1:(ip2:)ts2:...",NULL}, 92 | {"olsr",1,"IP option: loose source route. Format: pointer:addr1:addr2:...",NULL}, 93 | {"osid",1,"IP option: stream identifier",NULL}, 94 | {"ossr",1,"IP option: strict source route. Format: pointer:addr1:addr2:...",NULL} 95 | }; 96 | 97 | #endif /* _SENDIP_IP_H */ 98 | -------------------------------------------------------------------------------- /ipv6.c: -------------------------------------------------------------------------------- 1 | /* ipv6.c - sendip IPv6 code 2 | * Taken from code by Antti Tuominen 3 | * ChangeLog since 2.0 release: 4 | * 09/08/2002 Setting src/dst now works (Pekka Savola ) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "sendip_module.h" 15 | #include "ipv6.h" 16 | 17 | /* Character that identifies our options 18 | */ 19 | const char opt_char='6'; 20 | 21 | sendip_data *initialize(void) { 22 | sendip_data *ret = malloc(sizeof(sendip_data)); 23 | ipv6_header *ipv6 = malloc(sizeof(ipv6_header)); 24 | memset(ipv6,0,sizeof(ipv6_header)); 25 | ret->alloc_len = sizeof(ipv6_header); 26 | ret->data = (void *)ipv6; 27 | ret->modified=0; 28 | return ret; 29 | } 30 | 31 | bool set_addr(char *hostname, sendip_data *pack) { 32 | ipv6_header *ipv6 = (ipv6_header *)pack->data; 33 | struct hostent *host = gethostbyname2(hostname,AF_INET6); 34 | if(!(pack->modified & IPV6_MOD_SRC)) { 35 | ipv6->ip6_src = in6addr_loopback; 36 | } 37 | if(!(pack->modified & IPV6_MOD_DST)) { 38 | if(host==NULL) return FALSE; 39 | if(host->h_length != sizeof(ipv6->ip6_dst)) { 40 | fprintf(stderr,"IPV6 destination address is the wrong size!!!"); 41 | return FALSE; 42 | } 43 | memcpy(&(ipv6->ip6_dst),host->h_addr,host->h_length); 44 | } 45 | return TRUE; 46 | } 47 | 48 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 49 | ipv6_header *hdr = (ipv6_header *)pack->data; 50 | struct in6_addr addr; 51 | 52 | switch(opt[1]) { 53 | case 'f': 54 | /* TODO : This looks byte-order dependant */ 55 | hdr->ip6_flow |= htonl((u_int32_t)strtoul(arg, (char **)NULL, 0) & 0xFFF00000); 56 | pack->modified |= IPV6_MOD_FLOW; 57 | break; 58 | case 'v': 59 | hdr->ip6_vfc &= 0x0F; 60 | hdr->ip6_vfc |= (u_int8_t)(strtoul(arg, (char **)NULL, 0) &0x0F) << 4; 61 | pack->modified |= IPV6_MOD_VERSION; 62 | break; 63 | case 'p': 64 | hdr->ip6_vfc &= 0xF0; 65 | hdr->ip6_vfc |= (u_int8_t)strtoul(arg, (char **)NULL, 0) & 0x0F; 66 | pack->modified |= IPV6_MOD_PRIORITY; 67 | break; 68 | case 't': 69 | /* TODO : This looks byte-order dependant */ 70 | hdr->ip6_flow |= htonl(((u_int32_t)strtoul(arg, (char **)NULL, 0) << 20) & 0x0F000000); 71 | pack->modified |= IPV6_MOD_FLOW; 72 | break; 73 | case 'l': 74 | hdr->ip6_plen = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 75 | pack->modified |= IPV6_MOD_PLEN; 76 | break; 77 | case 'h': 78 | hdr->ip6_hlim = (u_int8_t)strtoul(arg, (char **)NULL, 0); 79 | pack->modified |= IPV6_MOD_HLIM; 80 | break; 81 | case 'n': 82 | hdr->ip6_nxt = (u_int8_t)strtoul(arg, (char **)NULL, 0); 83 | pack->modified |= IPV6_MOD_NXT; 84 | break; 85 | case 's': 86 | if (inet_pton(AF_INET6, arg, &addr)) { 87 | memcpy(&hdr->ip6_src, &addr, sizeof(struct in6_addr)); 88 | } 89 | pack->modified |= IPV6_MOD_SRC; 90 | break; 91 | case 'd': 92 | if (inet_pton(AF_INET6, arg, &addr)) { 93 | memcpy(&hdr->ip6_dst, &addr, sizeof(struct in6_addr)); 94 | } 95 | pack->modified |= IPV6_MOD_DST; 96 | break; 97 | } 98 | return TRUE; 99 | 100 | } 101 | 102 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 103 | sendip_data *pack) { 104 | ipv6_header *ipv6 = (ipv6_header *)pack->data; 105 | 106 | if(!(pack->modified&IPV6_MOD_VERSION)) { 107 | ipv6->ip6_vfc &= 0x0F; 108 | ipv6->ip6_vfc |= (6 << 4); 109 | } 110 | if(!(pack->modified&IPV6_MOD_PLEN)) { 111 | ipv6->ip6_plen = htons(data->alloc_len); 112 | } 113 | if(!(pack->modified&IPV6_MOD_NXT)) { 114 | ipv6->ip6_nxt = (u_int8_t)IPPROTO_NONE; 115 | } 116 | if(!(pack->modified&IPV6_MOD_HLIM)) { 117 | ipv6->ip6_hlim = 32; 118 | } 119 | 120 | return TRUE; 121 | } 122 | 123 | int num_opts() { 124 | return sizeof(ipv6_opts)/sizeof(sendip_option); 125 | } 126 | sendip_option *get_opts() { 127 | return ipv6_opts; 128 | } 129 | char get_optchar() { 130 | return opt_char; 131 | } 132 | -------------------------------------------------------------------------------- /ipv6.h: -------------------------------------------------------------------------------- 1 | /* ipv6.h 2 | */ 3 | #ifndef _SENDIP_IPV6_H 4 | #define _SENDIP_IPV6_H 5 | 6 | /* Pseudo header used for checksumming ICMP, TCP, UDP etc 7 | */ 8 | struct ipv6_pseudo_hdr { 9 | struct in6_addr source; 10 | struct in6_addr destination; 11 | u_int32_t ulp_length; 12 | u_int32_t zero: 24, 13 | nexthdr: 8; 14 | }; 15 | 16 | /* Header taken from glibc 2.2 17 | */ 18 | typedef struct { 19 | union { 20 | struct ip6_hdrctl { 21 | uint32_t ip6_un1_flow; /* 24 bits of flow-ID */ 22 | uint16_t ip6_un1_plen; /* payload length */ 23 | uint8_t ip6_un1_nxt; /* next header */ 24 | uint8_t ip6_un1_hlim; /* hop limit */ 25 | } ip6_un1; 26 | uint8_t ip6_un2_vfc; /* 4 bits version, 4 bits priority */ 27 | } ip6_ctlun; 28 | struct in6_addr ip6_src; /* source address */ 29 | struct in6_addr ip6_dst; /* destination address */ 30 | } ipv6_header; 31 | 32 | #define ip6_vfc ip6_ctlun.ip6_un2_vfc 33 | #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow 34 | #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen 35 | #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt 36 | #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim 37 | #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim 38 | 39 | /* Defines for which parts have been modified 40 | */ 41 | #define IPV6_MOD_FLOW 1 42 | #define IPV6_MOD_VERSION 1<<1 43 | #define IPV6_MOD_PRIORITY 1<<2 44 | #define IPV6_MOD_PLEN 1<<3 45 | #define IPV6_MOD_HLIM 1<<4 46 | #define IPV6_MOD_NXT 1<<5 47 | #define IPV6_MOD_SRC 1<<6 48 | #define IPV6_MOD_DST 1<<7 49 | 50 | /* Options 51 | */ 52 | sendip_option ipv6_opts[] = { 53 | {"f",1,"IPv6 flow ID","32"}, 54 | {"t",1,"IPv6 traffic class","0"}, 55 | {"l",1,"IPv6 payload length","Correct"}, 56 | {"n",1,"IPv6 next header","IPPROTO_NONE"}, 57 | {"h",1,"IPv6 hop limit","32"}, 58 | {"v",1,"IP version (you probably don't want to change this"}, 59 | {"p",1,"IPv6 priority","0"}, 60 | {"s",1,"IPv6 source address","::1"}, 61 | {"d",1,"IPv6 destination address","Correct"} 62 | }; 63 | 64 | #endif /* _SENDIP_IPV6_H */ 65 | -------------------------------------------------------------------------------- /ntp.c: -------------------------------------------------------------------------------- 1 | /* ntp.c - Network Timxe Protocol module for sendip 2 | * Author: Mike Ricketts 3 | * ChangeLog since 2.1 release: 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "sendip_module.h" 14 | #include "ntp.h" 15 | 16 | /* Character that identifies our options 17 | */ 18 | const char opt_char='n'; 19 | 20 | u_int32_t make_fixed_point(double n, bool issigned, int totbits, int intbits) { 21 | u_int32_t intpart; 22 | u_int32_t fracpart; 23 | u_int32_t result; 24 | bool signbit; 25 | double intpartd, fracpartd; 26 | int fracbits; 27 | 28 | if(issigned) totbits--; 29 | 30 | fracbits=totbits-intbits; 31 | 32 | if(issigned && n<0) { 33 | signbit=TRUE; 34 | } else { 35 | signbit=FALSE; 36 | } /* else, signbit is unused */ 37 | 38 | n=fabs(n); 39 | 40 | /* 41 | fracpartd=floor(ldexp(modf(n,&intpartd),ldexp(2.0,fracbits))); 42 | */ 43 | fracpartd=floor(ldexp(modf(n,&intpartd),32)); 44 | intpart=(u_int32_t)intpartd; 45 | fracpart=(u_int32_t)fracpartd; 46 | 47 | 48 | if(issigned&&signbit) { 49 | result=1<>=intbits; 63 | } 64 | result|=fracpart; 65 | } 66 | return htonl(result); 67 | } 68 | 69 | bool make_ts(ntp_ts *dest, char *src) { 70 | char *intpart, *fracpart; 71 | intpart=src; 72 | fracpart=strchr(intpart,'.'); 73 | 74 | if(*intpart) { 75 | dest->intpart=(u_int32_t)strtoul(intpart,&fracpart,0); 76 | } else { 77 | dest->intpart=0; 78 | } 79 | fracpart++; // skip the . 80 | if(fracpart && *fracpart) { 81 | double d; 82 | d = strtod(fracpart-1,(char **)NULL); 83 | dest->fracpart=make_fixed_point(d,FALSE,32,0); 84 | } 85 | return TRUE; 86 | } 87 | 88 | sendip_data *initialize(void) { 89 | sendip_data *ret = malloc(sizeof(sendip_data)); 90 | ntp_header *ntp = malloc(sizeof(ntp_header)); 91 | memset(ntp,0,sizeof(ntp_header)); 92 | ret->alloc_len = sizeof(ntp_header); 93 | ret->data = (void *)ntp; 94 | ret->modified=0; 95 | return ret; 96 | } 97 | 98 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 99 | ntp_header *ntp = (ntp_header *)pack->data; 100 | switch(opt[1]) { 101 | case 'l': /* Leap Indicator (2 bits) */ 102 | ntp->leap=(u_int8_t)strtoul(arg,(char **)NULL,0)&3; 103 | pack->modified|=NTP_MOD_LEAP; 104 | break; 105 | case 's': /* Status (6 bits, values 0-4 defined */ 106 | ntp->status=(u_int8_t)strtoul(arg,(char **)NULL,0)&0x3F; 107 | pack->modified|=NTP_MOD_STATUS; 108 | break; 109 | case 't': /* Type (8 bits, values 0-4 defined */ 110 | ntp->type=(u_int8_t)strtoul(arg,(char **)NULL,0)&0xFF; 111 | pack->modified|=NTP_MOD_TYPE; 112 | break; 113 | case 'p': /* precision (16 bits, range +32 to -32) */ 114 | ntp->precision=htons((int8_t)strtol(arg,(char **)NULL,0)); 115 | pack->modified|=NTP_MOD_PRECISION; 116 | break; 117 | case 'e': /* esitmated error (32 bits, fixed point between bits 15/16) */ 118 | ntp->error=make_fixed_point(strtod(arg,(char **)NULL),FALSE,32,16); 119 | pack->modified|=NTP_MOD_ERROR; 120 | break; 121 | case 'd': /* estimated drift rate (32 bits, signed fixed point left of 122 | high order bit) */ 123 | ntp->drift=make_fixed_point(strtod(arg,(char **)NULL),TRUE,32,0); 124 | pack->modified|=NTP_MOD_DRIFT; 125 | break; 126 | case 'r': /* reference clock id (32 bits or a 4 byte string). Can be: 127 | If type==1: "WWVB", "GOES", "WWV\0" 128 | If type==2: IP address 129 | Else: must be zero 130 | */ 131 | if('0'<=*arg&&*arg<='9') { 132 | /* either a number or an IP */ 133 | if((ntp->reference.ipaddr=inet_addr(arg))==-1) { 134 | /* Not a valid IP, or really want 255.255.255.255 */ 135 | if(strcmp(arg,"255.255.255.255")) { 136 | ntp->reference.ipaddr=htonl(strtol(arg,(char **)NULL,0)); 137 | } 138 | } 139 | } else { 140 | /* Hopefully a 4 byte or less string */ 141 | ntp->reference.ipaddr = 0; 142 | if(strlen(arg)<=4) { 143 | memcpy(ntp->reference.id,arg,strlen(arg)); 144 | } else { 145 | usage_error("NTP reference clock ID must be IP addr, 32 bit integer, or 4 byte string\n"); 146 | return FALSE; 147 | } 148 | } 149 | pack->modified|=NTP_MOD_REF; 150 | break; 151 | case 'f': /* reference timestamp (64 bits) */ 152 | if(make_ts(&(ntp->reference_ts),arg)) { 153 | pack->modified|=NTP_MOD_REFERENCE; 154 | } else { 155 | usage_error("Couldn't parse NTP reference timestamp\n"); 156 | return FALSE; 157 | } 158 | break; 159 | case 'o': /* originate timestamp (64 bits) */ 160 | if(make_ts(&(ntp->originate_ts),arg)) { 161 | pack->modified|=NTP_MOD_ORIGINATE; 162 | } else { 163 | usage_error("Couldn't parse NTP originate timestamp\n"); 164 | return FALSE; 165 | } 166 | break; 167 | case 'a': /* receive timestamp (64 bits) */ 168 | if(make_ts(&(ntp->receive_ts),arg)) { 169 | pack->modified|=NTP_MOD_RECEIVE; 170 | } else { 171 | usage_error("Couldn't parse NTP receive timestamp\n"); 172 | return FALSE; 173 | } 174 | break; 175 | case 'x': /* transmit timestamp (64 bits) */ 176 | if(make_ts(&(ntp->transmit_ts),arg)) { 177 | pack->modified|=NTP_MOD_TRANSMIT; 178 | } else { 179 | usage_error("Couldn't parse NTP transmit timestamp\n"); 180 | return FALSE; 181 | } 182 | break; 183 | } 184 | return TRUE; 185 | 186 | } 187 | 188 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 189 | sendip_data *pack) { 190 | if(hdrs[strlen(hdrs)-1] != 'u') { 191 | usage_error("Warning: NTP should be contained in a UDP packet\n"); 192 | } 193 | return TRUE; 194 | } 195 | 196 | int num_opts() { 197 | return sizeof(ntp_opts)/sizeof(sendip_option); 198 | } 199 | sendip_option *get_opts() { 200 | return ntp_opts; 201 | } 202 | char get_optchar() { 203 | return opt_char; 204 | } 205 | -------------------------------------------------------------------------------- /ntp.h: -------------------------------------------------------------------------------- 1 | /* ntp.h 2 | */ 3 | #ifndef _SENDIP_NTP_H 4 | #define _SENDIP_NTP_H 5 | 6 | typedef struct { 7 | u_int32_t intpart; 8 | u_int32_t fracpart; 9 | } ntp_ts; 10 | 11 | /* NTP HEADER 12 | */ 13 | typedef struct { 14 | /* TODO BYTEORDER!!! */ 15 | u_int8_t leap:2; 16 | u_int8_t status:6; 17 | u_int8_t type; 18 | /* END TODO */ 19 | 20 | u_int16_t precision; 21 | u_int32_t error; 22 | u_int32_t drift; 23 | union { 24 | u_int32_t ipaddr; 25 | char id[4]; 26 | } reference; 27 | ntp_ts reference_ts; 28 | ntp_ts originate_ts; 29 | ntp_ts receive_ts; 30 | ntp_ts transmit_ts; 31 | } ntp_header; 32 | 33 | /* Defines for which parts have been modified 34 | */ 35 | #define NTP_MOD_LEAP (1) 36 | #define NTP_MOD_STATUS (1<<1) 37 | #define NTP_MOD_TYPE (1<<2) 38 | #define NTP_MOD_PRECISION (1<<3) 39 | #define NTP_MOD_ERROR (1<<4) 40 | #define NTP_MOD_DRIFT (1<<5) 41 | #define NTP_MOD_REF (1<<6) 42 | #define NTP_MOD_REFERENCE (1<<7) 43 | #define NTP_MOD_ORIGINATE (1<<8) 44 | #define NTP_MOD_RECEIVE (1<<9) 45 | #define NTP_MOD_TRANSMIT (1<<10) 46 | 47 | /* Options 48 | */ 49 | sendip_option ntp_opts[] = { 50 | {"l",1,"NTP Leap Indicator","00 (no warning)"}, 51 | {"s",1,"NTP status","0 (clock operating OK)"}, 52 | {"t",1,"NTP type","0 (unspecified)"}, 53 | {"p",1,"NTP precision","0"}, 54 | {"e",1,"NTP estimated error","0.0"}, 55 | {"d",1,"NTP estimated drift rate","0.0"}, 56 | {"r",1,"NTP reference clock ID (string or IP or number)","0"}, 57 | {"f",1,"NTP reference timestamp","0.0"}, 58 | {"o",1,"NTP originate timestamp","0.0"}, 59 | {"a",1,"NTP arrival (receive) timestamp","0.0"}, 60 | {"x",1,"NTP xmit (transmit) timestamp","0.0"} 61 | }; 62 | 63 | #endif /* _SENDIP_NTP_H */ 64 | -------------------------------------------------------------------------------- /rip.c: -------------------------------------------------------------------------------- 1 | /* rip.c - RIP-1 and -2 code for sendip 2 | * Taken from code by Richard Polton 3 | * ChangeLog since 2.0 release: 4 | * 02/12/2001 Only check 1 layer for enclosing UDP header 5 | * 21/08/2002 Off-by-one fix in -re handling that caused bad things to happen 6 | * 21/08/2002 htons() and htonl() added where needed 7 | * ChangeLog since 2.2 release: 8 | * 24/11/2002 make it compile on archs that care about alignment 9 | * ChangeLog since 2.5 release: 10 | * 26/10/2004 fix bug with multiple -re options (found by several people) 11 | * 28/10/2004 fix -ra (thanks to sharmily.anantaraman@conexant.com) 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "sendip_module.h" 21 | #include "rip.h" 22 | 23 | /* Character that identifies our options 24 | */ 25 | const char opt_char='r'; 26 | 27 | sendip_data *initialize(void) { 28 | sendip_data *ret = malloc(sizeof(sendip_data)); 29 | rip_header *rip = malloc(sizeof(rip_header)); 30 | memset(rip,0,sizeof(rip_header)); 31 | ret->alloc_len = sizeof(rip_header); 32 | ret->data = (void *)rip; 33 | ret->modified=0; 34 | return ret; 35 | } 36 | 37 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 38 | rip_header *rippack = (rip_header *)pack->data; 39 | rip_options *ripopt; 40 | char *p, *q; 41 | switch(opt[1]) { 42 | case 'v': /* version */ 43 | rippack->version = (u_int8_t)strtoul(arg, (char **)0, 0); 44 | pack->modified |= RIP_MOD_VERSION; 45 | break; 46 | case 'c': /* command */ 47 | rippack->command = (u_int8_t)strtoul(arg, (char **)0, 0); 48 | pack->modified |= RIP_MOD_COMMAND; 49 | break; 50 | case 'a': /* authenticate */ 51 | if(RIP_NUM_ENTRIES(pack) != 0) { 52 | usage_error("Warning: a real RIP-2 packet only has authentication as the first entry.\n"); 53 | } 54 | RIP_ADD_ENTRY(pack); 55 | ripopt = RIP_OPTION(pack); 56 | memset(ripopt,0,sizeof(rip_options)); 57 | ripopt->addressFamily=0xFFFF; 58 | p=q=arg; 59 | /* TODO: if arg is malformed, this could segfault */ 60 | while(*(q++)!=':') {} /* do nothing */; *(--q)='\0'; 61 | ripopt->routeTagOrAuthenticationType=htons((p==q)?2:(u_int16_t)strtoul(p, (char **)0,0)); 62 | p=++q; 63 | if(strlen(p) > 16) { 64 | usage_error("Warning: RIP passord cannot be longer than 16 characters.\n"); 65 | } 66 | strncpy((char *)&(ripopt->address),p,16); 67 | break; 68 | case 'e': /* rip entry */ 69 | if(RIP_NUM_ENTRIES(pack)==25) { 70 | usage_error("Warning: a real RIP packet contains no more than 25 entries.\n"); 71 | } 72 | RIP_ADD_ENTRY(pack); 73 | ripopt = RIP_OPTION(pack); 74 | p=q=arg; 75 | /* TODO: if arg is malformed, this could segfault */ 76 | while(*(q++)!=':') {} /* do nothing */; *(--q)='\0'; 77 | ripopt->addressFamily= htons((p==q)?2:(u_int16_t)strtoul(p, (char **)0, 0)); 78 | p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0'; 79 | ripopt->routeTagOrAuthenticationType=htons((p==q)?0:(u_int16_t)strtoul(p, (char **)0,0)); 80 | p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0'; 81 | ripopt->address=(p==q)?inet_addr("0.0.0.0"):inet_addr(p); 82 | p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0'; 83 | ripopt->subnetMask=(p==q)?inet_addr("255.255.255.0"):inet_addr(p); 84 | p=++q; while(*(q++)!=':') {} /* do nothing */; *(--q)='\0'; 85 | ripopt->nextHop=(p==q)?inet_addr("0.0.0.0"):inet_addr(p); 86 | p=++q; while(*(q++)!='\0') {} /* do nothing */; *(--q)='\0'; 87 | ripopt->metric=htonl((p==q)?16:(u_int32_t)strtoul(p,(char **)0, 0)); 88 | break; 89 | case 'd': /* default request */ 90 | if(RIP_NUM_ENTRIES(pack) != 0) { 91 | usage_error("Warning: a real RIP-1 or -2 packet does not have any entries in a default request.\n"); 92 | } 93 | RIP_ADD_ENTRY(pack); 94 | ripopt=RIP_OPTION(pack); 95 | rippack->command = (u_int8_t)1; 96 | ripopt->addressFamily = (u_int16_t)0; 97 | ripopt->routeTagOrAuthenticationType = (u_int16_t)0; 98 | ripopt->address=inet_addr("0.0.0.0"); 99 | ripopt->subnetMask=inet_addr("0.0.0.0"); 100 | ripopt->nextHop=inet_addr("0.0.0.0"); 101 | ripopt->metric=htons((u_int16_t)16); 102 | break; 103 | case 'r': /* set reserved field */ 104 | rippack->res = (u_int16_t)strtoul(arg, (char **)0, 0); 105 | pack->modified |= RIP_MOD_RESERVED; 106 | break; 107 | default: 108 | usage_error("Unrecognized option opt"); 109 | return FALSE; 110 | } 111 | return TRUE; 112 | 113 | } 114 | 115 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 116 | sendip_data *pack) { 117 | if(hdrs[strlen(hdrs)-1] != 'u') { 118 | usage_error("Warning: RIP should be contained in a UDP packet\n"); 119 | } 120 | 121 | return TRUE; 122 | } 123 | 124 | int num_opts() { 125 | return sizeof(rip_opts)/sizeof(sendip_option); 126 | } 127 | sendip_option *get_opts() { 128 | return rip_opts; 129 | } 130 | char get_optchar() { 131 | return opt_char; 132 | } 133 | -------------------------------------------------------------------------------- /rip.h: -------------------------------------------------------------------------------- 1 | /* rip.h 2 | */ 3 | #ifndef _SENDIP_RIP_H 4 | #define _SENDIP_RIP_H 5 | 6 | /* RIP PACKET STRUCTURES 7 | */ 8 | typedef struct { 9 | u_int8_t command; 10 | u_int8_t version; 11 | u_int16_t res; 12 | } rip_header; 13 | 14 | typedef struct { 15 | u_int16_t addressFamily; 16 | u_int16_t routeTagOrAuthenticationType; 17 | u_int32_t address; 18 | u_int32_t subnetMask; 19 | u_int32_t nextHop; 20 | u_int32_t metric; 21 | } rip_options; 22 | 23 | /* Defines for which parts have been modified 24 | */ 25 | #define RIP_MOD_COMMAND 1 26 | #define RIP_MOD_VERSION 1<<1 27 | #define RIP_MOD_RESERVED 1<<2 28 | 29 | /* Options 30 | */ 31 | sendip_option rip_opts[] = { 32 | {"v",1,"RIP version","2"}, 33 | {"c",1, 34 | "RIP command (1=request, 2=response, 3=traceon (obsolete), 4=traceoff (obsolete), 5=poll (undocumented), 6=poll entry (undocumented)","1"}, 35 | {"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"}, 36 | {"a",1,"Add RIP auth entry. Format is: AuthType:Password, AuthType may be omitted for default basic auth",NULL}, 37 | {"d",0,"RIP default request - get router's entire routing table; do not use any other RIP options on this RIP header",NULL}, 38 | {"r",1,"RIP reserved field","0"} 39 | }; 40 | 41 | /* Helpful macros */ 42 | #define RIP_NUM_ENTRIES(d) (((d)->alloc_len-sizeof(rip_header))/sizeof(rip_options)) 43 | #define RIP_ADD_ENTRY(d) { (d)->data = realloc((d)->data,(d)->alloc_len+sizeof(rip_options)); (d)->alloc_len+=sizeof(rip_options); } 44 | #define RIP_OPTION(d) ((rip_options *)((u_int32_t *)((d)->data)+((d)->alloc_len>>2)-(sizeof(rip_options)>>2))) 45 | #endif /* _SENDIP_RIP_H */ 46 | -------------------------------------------------------------------------------- /ripng.c: -------------------------------------------------------------------------------- 1 | /* ripng.c - RIPng (version 1) code for sendip 2 | * Created by hacking rip code 3 | * ChangeLog since 2.2 release: 4 | * 15/10/2002 Read the spec 5 | * 24/11/2002 Made it compile on archs needing alignment 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "sendip_module.h" 16 | #include "ripng.h" 17 | 18 | /* Character that identifies our options 19 | */ 20 | const char opt_char='R'; 21 | 22 | static struct in6_addr inet6_addr(char *hostname) { 23 | struct hostent *host = gethostbyname2(hostname,AF_INET6); 24 | struct in6_addr ret; 25 | if(host==NULL) { 26 | fprintf(stderr,"RIPNG: Couldn't get address for %s defaulting to loopback",hostname); 27 | return in6addr_loopback; 28 | } 29 | if(host->h_length != sizeof(struct in6_addr)) { 30 | fprintf(stderr,"RIPNG: IPV6 address is the wrong size: defaulting to loopback"); 31 | return in6addr_loopback; 32 | } 33 | memcpy(&ret,host->h_addr,sizeof(ret)); 34 | return ret; 35 | } 36 | 37 | sendip_data *initialize(void) { 38 | sendip_data *ret = malloc(sizeof(sendip_data)); 39 | ripng_header *rip = malloc(sizeof(ripng_header)); 40 | memset(rip,0,sizeof(ripng_header)); 41 | ret->alloc_len = sizeof(ripng_header); 42 | ret->data = (void *)rip; 43 | ret->modified=0; 44 | return ret; 45 | } 46 | 47 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 48 | ripng_header *rippack = (ripng_header *)pack->data; 49 | ripng_entry *ripopt; 50 | char *p, *q; 51 | switch(opt[1]) { 52 | case 'v': /* version */ 53 | rippack->version = (u_int8_t)strtoul(arg, (char **)0, 0); 54 | pack->modified |= RIPNG_MOD_VERSION; 55 | break; 56 | case 'c': /* command */ 57 | rippack->command = (u_int8_t)strtoul(arg, (char **)0, 0); 58 | pack->modified |= RIPNG_MOD_COMMAND; 59 | break; 60 | case 'r': /* reserved */ 61 | rippack->res = htons((u_int16_t)strtoul(arg, (char **)0, 0)); 62 | pack->modified |= RIPNG_MOD_RESERVED; 63 | break; 64 | /* 65 | case 'a': / * authenticate * / 66 | if(RIPNG_NUM_ENTRIES(pack) != 0) { 67 | usage_error("Warning: a real RIP-2 packet only has authentication on the first entry.\n"); 68 | } 69 | pack->modified |= RIP_IS_AUTH; 70 | pack->data = realloc(pack->data,pack->alloc_len+strlen(arg)); 71 | strcpy(pack->data+pack->alloc_len,arg); 72 | pack->alloc_len += strlen(arg); 73 | break; 74 | */ 75 | case 'e': /* rip entry */ 76 | RIPNG_ADD_ENTRY(pack); 77 | ripopt = RIPNG_ENTRY(pack); 78 | p=q=arg; 79 | /* TODO: if arg is malformed, this could segfault */ 80 | while(*(q++)!='/') {} /* do nothing */; *(--q)='\0'; 81 | ripopt->prefix = (p==q)?in6addr_any:inet6_addr(p); 82 | 83 | p=++q; while(*(q++)!='/') {} /* do nothing */; *(--q)='\0'; 84 | ripopt->tag=htons( (p==q)?0:(u_int16_t)strtoul(p, (char **)0,0)); 85 | 86 | p=++q; while(*(q++)!='/') {} /* do nothing */; *(--q)='\0'; 87 | ripopt->len=(p==q)?(u_int8_t)128:(u_int8_t)strtoul(p, (char **)0,0); 88 | 89 | p=++q; while(*(q++)!='\0') {} /* do nothing */; *(--q)='\0'; 90 | ripopt->metric=(p==q)?(u_int8_t)16:(u_int8_t)strtoul(p,(char **)0, 0); 91 | break; 92 | case 'd': /* default request */ 93 | if(RIPNG_NUM_ENTRIES(pack) != 0) { 94 | usage_error("Warning: a real RIPng packet does not have any other entries in a default request.\n"); 95 | } 96 | rippack->command = (u_int8_t)1; 97 | rippack->version = (u_int8_t)1; 98 | rippack->res = (u_int16_t)0; 99 | pack->modified|=RIPNG_MOD_COMMAND|RIPNG_MOD_VERSION|RIPNG_MOD_RESERVED; 100 | RIPNG_ADD_ENTRY(pack); 101 | ripopt=RIPNG_ENTRY(pack); 102 | ripopt->prefix=in6addr_any; 103 | ripopt->tag=(u_int16_t)0; 104 | ripopt->len=(u_int8_t)0; 105 | ripopt->metric=htons((u_int16_t)16); 106 | break; 107 | } 108 | return TRUE; 109 | 110 | } 111 | 112 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 113 | sendip_data *pack) { 114 | if(hdrs[strlen(hdrs)-1] != 'u') { 115 | usage_error("Warning: RIPng should be contained in a UDP packet\n"); 116 | } 117 | 118 | return TRUE; 119 | } 120 | 121 | int num_opts() { 122 | return sizeof(rip_opts)/sizeof(sendip_option); 123 | } 124 | sendip_option *get_opts() { 125 | return rip_opts; 126 | } 127 | char get_optchar() { 128 | return opt_char; 129 | } 130 | -------------------------------------------------------------------------------- /ripng.h: -------------------------------------------------------------------------------- 1 | /* ripng.h 2 | */ 3 | #ifndef _SENDIP_RIPNG_H 4 | #define _SENDIP_RIPNG_H 5 | 6 | /* RIP PACKET STRUCTURES 7 | */ 8 | typedef struct { 9 | u_int8_t command; 10 | u_int8_t version; 11 | u_int16_t res; 12 | } ripng_header; 13 | 14 | typedef struct { 15 | struct in6_addr prefix; 16 | u_int16_t tag; 17 | u_int8_t len; 18 | u_int8_t metric; 19 | } ripng_entry; 20 | 21 | /* Defines for which parts have been modified 22 | */ 23 | #define RIPNG_MOD_COMMAND 1 24 | #define RIPNG_MOD_VERSION 1<<1 25 | #define RIPNG_MOD_RESERVED 1<<2 26 | //#define RIP_MOD_ADDRFAM 1<<2 27 | //#define RIP_MOD_ROUTETAG 1<<3 28 | //#define RIP_IS_AUTH 1<<4 29 | 30 | /* Options 31 | */ 32 | sendip_option rip_opts[] = { 33 | {"v",1,"RIPng version","1"}, 34 | {"c",1,"RIPng command (1=request, 2=response)","1"}, 35 | {"r",1,"RIPng reserved field (should be 0)","0"}, 36 | {"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"}, 37 | {"d",0,"RIPng default request - get router's entire routing table; do not use any other RIPng options on this RIPng header",NULL} 38 | }; 39 | 40 | /* Helpful macros */ 41 | #define RIPNG_NUM_ENTRIES(d) (((d)->alloc_len-sizeof(ripng_header))/sizeof(ripng_entry)) 42 | #define RIPNG_ADD_ENTRY(d) { (d)->data = realloc((d)->data,(d)->alloc_len+sizeof(ripng_entry)); (d)->alloc_len+=sizeof(ripng_entry); } 43 | #define RIPNG_ENTRY(d) ((ripng_entry *)((u_int32_t *)((d)->data)+((d)->alloc_len>>2)-(sizeof(ripng_entry)>>2))) 44 | #endif /* _SENDIP_RIPNG_H */ 45 | -------------------------------------------------------------------------------- /sendip.c: -------------------------------------------------------------------------------- 1 | /* sendip.c - main program code for sendip 2 | * Copyright 2001 Mike Ricketts 3 | * Distributed under the GPL. See LICENSE. 4 | * Bug reports, patches, comments etc to mike@earth.li 5 | * ChangeLog since 2.0 release: 6 | * 27/11/2001 compact_string() moved to compact.c 7 | * 27/11/2001 change search path for libs to include .so 8 | * 23/01/2002 make random fields more random (Bryan Croft ) 9 | * 10/08/2002 detect attempt to use multiple -d and -f options 10 | * ChangeLog since 2.2 release: 11 | * 24/11/2002 compile on archs requiring alignment 12 | * ChangeLog since 2.3 release: 13 | * 21/04/2003 random data (Anand (Andy) Rao ) 14 | * ChangeLog since 2.4 release: 15 | * 21/04/2003 fix errors detected by valgrind 16 | * 28/07/2003 fix compile error on solaris 17 | * ChangeLog since 2.5 release: 18 | * 10/04/2004 use setsockopt for ipv6 options. 19 | * 11/04/2004 allow setting socket options via -s 20 | */ 21 | 22 | #define _SENDIP_MAIN 23 | 24 | /* socket stuff */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /* everything else */ 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include /* isprint */ 40 | #include "sendip_module.h" 41 | 42 | #include "ipv4.h" 43 | #include "ipv6.h" 44 | 45 | /* Use our own getopt to ensure consistant behaviour on all platforms */ 46 | #include "gnugetopt.h" 47 | 48 | typedef struct _s_m { 49 | struct _s_m *next; 50 | struct _s_m *prev; 51 | char *name; 52 | char optchar; 53 | sendip_data * (*initialize)(void); 54 | bool (*do_opt)(const char *optstring, const char *optarg, 55 | sendip_data *pack); 56 | bool (*set_addr)(char *hostname, sendip_data *pack); 57 | bool (*finalize)(char *hdrs, sendip_data *headers[], sendip_data *data, 58 | sendip_data *pack); 59 | sendip_data *pack; 60 | void *handle; 61 | sendip_option *opts; 62 | int num_opts; 63 | } sendip_module; 64 | 65 | /* sockaddr_storage struct is not defined everywhere, so here is our own 66 | nasty version 67 | */ 68 | typedef struct { 69 | u_int16_t ss_family; 70 | u_int32_t ss_align; 71 | char ss_padding[122]; 72 | } _sockaddr_storage; 73 | 74 | static int num_opts=0; 75 | static sendip_module *first; 76 | static sendip_module *last; 77 | 78 | static char *progname; 79 | 80 | static int sendpacket(sendip_data *data, char *hostname, int af_type, 81 | bool verbose, char *sockopts) { 82 | _sockaddr_storage *to = malloc(sizeof(_sockaddr_storage)); 83 | int tolen; 84 | 85 | /* socket stuff */ 86 | int s; /* socket for sending */ 87 | bool sethdrincl=(af_type==AF_INET); /* should we set IP_HDRINCL?*/ 88 | bool setipv6opts=(af_type==AF_INET6);/* should we set IPV6_*? */ 89 | 90 | /* hostname stuff */ 91 | struct hostent *host = NULL; /* result of gethostbyname2 */ 92 | 93 | /* casts for specific protocols */ 94 | struct sockaddr_in *to4 = (struct sockaddr_in *)to; /* IPv4 */ 95 | struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)to; /* IPv6 */ 96 | 97 | int sent; /* number of bytes sent */ 98 | 99 | if(to==NULL) { 100 | perror("OUT OF MEMORY!\n"); 101 | return -3; 102 | } 103 | memset(to, 0, sizeof(_sockaddr_storage)); 104 | 105 | if ((host = gethostbyname2(hostname, af_type)) == NULL) { 106 | perror("Couldn't get destination host: gethostbyname2()"); 107 | free(to); 108 | return -1; 109 | } 110 | 111 | switch (af_type) { 112 | case AF_INET: 113 | to4->sin_family = host->h_addrtype; 114 | memcpy(&to4->sin_addr, host->h_addr, host->h_length); 115 | tolen = sizeof(struct sockaddr_in); 116 | break; 117 | case AF_INET6: 118 | to6->sin6_family = host->h_addrtype; 119 | memcpy(&to6->sin6_addr, host->h_addr, host->h_length); 120 | tolen = sizeof(struct sockaddr_in6); 121 | break; 122 | default: 123 | return -2; 124 | break; 125 | } 126 | 127 | if(verbose) { 128 | int i, j; 129 | printf("Final packet data:\n"); 130 | for(i=0; ialloc_len; ) { 131 | for(j=0; j<4 && i+jalloc_len; j++) 132 | printf("%02X ", ((unsigned char *)(data->data))[i+j]); 133 | printf(" "); 134 | for(j=0; j<4 && i+jalloc_len; j++) { 135 | int c=(int) ((unsigned char *)(data->data))[i+j]; 136 | printf("%c", isprint(c)?((char *)(data->data))[i+j]:'.'); 137 | } 138 | printf("\n"); 139 | i+=j; 140 | } 141 | } 142 | 143 | if ((s = socket(af_type, SOCK_RAW, IPPROTO_RAW)) < 0) { 144 | perror("Couldn't open RAW socket"); 145 | free(to); 146 | return -1; 147 | } 148 | 149 | /* Set socket options */ 150 | if(verbose) printf("Setting socket options:\n"); 151 | if(sockopts && strlen(sockopts)) { 152 | int i; 153 | const int on=1; 154 | for(i=0;idata; 196 | if(verbose) printf(" IPV6_UNICAST_HOPS\n"); 197 | if (setsockopt(s,IPPROTO_IPV6,IPV6_UNICAST_HOPS, 198 | &(iphdr->ip6_hlim),sizeof(iphdr->ip6_hlim)) < 0) { 199 | perror("Couldnt set Sock options for IPv6:Hop Limit"); 200 | free(to); 201 | close(s); 202 | return -2; 203 | } 204 | } 205 | 206 | 207 | #ifdef __sun__ 208 | /* On Solaris, it seems that the only way to send IP options or packets 209 | with a faked IP header length is to: 210 | setsockopt(IP_OPTIONS) with the IP option data and size 211 | decrease the total length of the packet accordingly 212 | I'm sure this *shouldn't* work. But it does. 213 | */ 214 | if((*((char *)(data->data))&0x0F) != 5) { 215 | ip_header *iphdr = (ip_header *)data->data; 216 | 217 | int optlen = iphdr->header_len*4-20; 218 | 219 | if(verbose) 220 | printf("Solaris workaround enabled for %d IP option bytes\n", optlen); 221 | 222 | iphdr->tot_len = htons(ntohs(iphdr->tot_len)-optlen); 223 | 224 | if(verbose) printf(" IP_OPTIONS\n"); 225 | if(setsockopt(s,IPPROTO_IP,IP_OPTIONS, 226 | (void *)(((char *)(data->data))+20),optlen)) { 227 | perror("Couldn't setsockopt IP_OPTIONS"); 228 | free(to); 229 | close(s); 230 | return -2; 231 | } 232 | } 233 | #endif /* __sun__ */ 234 | 235 | /* Send the packet */ 236 | sent = sendto(s, (char *)data->data, data->alloc_len, 0, (void *)to, tolen); 237 | if (sent == data->alloc_len) { 238 | if(verbose) printf("Sent %d bytes to %s\n",sent,hostname); 239 | } else { 240 | if (sent < 0) { 241 | perror("sendto"); 242 | } else { 243 | if(verbose) fprintf(stderr, "Only sent %d of %d bytes to %s\n", 244 | sent, data->alloc_len, hostname); 245 | } 246 | } 247 | free(to); 248 | close(s); 249 | return sent; 250 | } 251 | 252 | static void unload_modules(bool freeit, int verbosity) { 253 | sendip_module *mod, *p; 254 | p = NULL; 255 | for(mod=first;mod!=NULL;mod=mod->next) { 256 | if(verbosity) printf("Freeing module %s\n",mod->name); 257 | if(p) free(p); 258 | p = mod; 259 | free(mod->name); 260 | if(freeit) free(mod->pack->data); 261 | free(mod->pack); 262 | (void)dlclose(mod->handle); 263 | /* Do not free options - TODO should we? */ 264 | } 265 | if(p) free(p); 266 | } 267 | 268 | static bool load_module(char *modname) { 269 | sendip_module *newmod = malloc(sizeof(sendip_module)); 270 | sendip_module *cur; 271 | int (*n_opts)(void); 272 | sendip_option * (*get_opts)(void); 273 | char (*get_optchar)(void); 274 | 275 | for(cur=first;cur!=NULL;cur=cur->next) { 276 | if(!strcmp(modname,cur->name)) { 277 | memcpy(newmod,cur,sizeof(sendip_module)); 278 | newmod->num_opts=0; 279 | goto out; 280 | } 281 | } 282 | newmod->name=malloc(strlen(modname)+strlen(SENDIP_LIBS)+strlen(".so")+2); 283 | strcpy(newmod->name,modname); 284 | if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { 285 | char *error0=strdup(dlerror()); 286 | sprintf(newmod->name,"./%s.so",modname); 287 | if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { 288 | char *error1=strdup(dlerror()); 289 | sprintf(newmod->name,"%s/%s.so",SENDIP_LIBS,modname); 290 | if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { 291 | char *error2=strdup(dlerror()); 292 | sprintf(newmod->name,"%s/%s",SENDIP_LIBS,modname); 293 | if(NULL==(newmod->handle=dlopen(newmod->name,RTLD_NOW))) { 294 | char *error3=strdup(dlerror()); 295 | fprintf(stderr,"Couldn't open module %s, tried:\n",modname); 296 | fprintf(stderr," %s\n %s\n %s\n %s\n", error0, error1, 297 | error2, error3); 298 | free(newmod); 299 | free(error3); 300 | return FALSE; 301 | } 302 | free(error2); 303 | } 304 | free(error1); 305 | } 306 | free(error0); 307 | } 308 | strcpy(newmod->name,modname); 309 | if(NULL==(newmod->initialize=dlsym(newmod->handle,"initialize"))) { 310 | fprintf(stderr,"%s doesn't have an initialize function: %s\n",modname, 311 | dlerror()); 312 | dlclose(newmod->handle); 313 | free(newmod); 314 | return FALSE; 315 | } 316 | if(NULL==(newmod->do_opt=dlsym(newmod->handle,"do_opt"))) { 317 | fprintf(stderr,"%s doesn't contain a do_opt function: %s\n",modname, 318 | dlerror()); 319 | dlclose(newmod->handle); 320 | free(newmod); 321 | return FALSE; 322 | } 323 | newmod->set_addr=dlsym(newmod->handle,"set_addr"); // don't care if fails 324 | if(NULL==(newmod->finalize=dlsym(newmod->handle,"finalize"))) { 325 | fprintf(stderr,"%s\n",dlerror()); 326 | dlclose(newmod->handle); 327 | free(newmod); 328 | return FALSE; 329 | } 330 | if(NULL==(n_opts=dlsym(newmod->handle,"num_opts"))) { 331 | fprintf(stderr,"%s\n",dlerror()); 332 | dlclose(newmod->handle); 333 | free(newmod); 334 | return FALSE; 335 | } 336 | if(NULL==(get_opts=dlsym(newmod->handle,"get_opts"))) { 337 | fprintf(stderr,"%s\n",dlerror()); 338 | dlclose(newmod->handle); 339 | free(newmod); 340 | return FALSE; 341 | } 342 | if(NULL==(get_optchar=dlsym(newmod->handle,"get_optchar"))) { 343 | fprintf(stderr,"%s\n",dlerror()); 344 | dlclose(newmod->handle); 345 | free(newmod); 346 | return FALSE; 347 | } 348 | newmod->num_opts = n_opts(); 349 | newmod->optchar=get_optchar(); 350 | /* TODO: check uniqueness */ 351 | newmod->opts = get_opts(); 352 | 353 | num_opts+=newmod->num_opts; 354 | 355 | out: 356 | newmod->pack=NULL; 357 | newmod->prev=last; 358 | newmod->next=NULL; 359 | last = newmod; 360 | if(last->prev) last->prev->next = last; 361 | if(!first) first=last; 362 | 363 | return TRUE; 364 | } 365 | 366 | static void print_usage(void) { 367 | sendip_module *mod; 368 | int i; 369 | printf("Usage: %s [-v] [-d data] [-h] [-f datafile] [-p module] [module options] hostname\n",progname); 370 | printf(" -d data\tadd this data as a string to the end of the packet\n"); 371 | printf("\t\tData can be:\n"); 372 | printf("\t\trN to generate N random(ish) data bytes;\n"); 373 | printf("\t\t0x or 0X followed by hex digits;\n"); 374 | printf("\t\t0 followed by octal digits;\n"); 375 | printf("\t\tany other stream of bytes\n"); 376 | printf(" -s options\tset socket options\n"); 377 | printf("\t\tValid options are:\n"); 378 | printf("\t\tb (SO_BROADCAST) allow sending packets to broadcast addresses;\n"); 379 | printf("\t\ti (IP_HDRINCL) (ON BY DEFAULT) include IP headers (expert use only!);\n"); 380 | printf("\t\t6 (IPV6_*) (ON BY DEFAULT) various options for setting ipv6 headers\n"); 381 | printf(" -f datafile\tread packet data from file\n"); 382 | printf(" -h\t\tprint this message\n"); 383 | printf(" -p module\tload the specified module (see below)\n"); 384 | printf(" -v\t\tbe verbose\n"); 385 | 386 | printf("\n\nModules are loaded in the order the -p option appears. The headers from\n"); 387 | printf("each module are put immediately inside the headers from the previos model in\n"); 388 | printf("the final packet. For example, to embed bgp inside tcp inside ipv4, do\n"); 389 | printf("sendip -p ipv4 -p tcp -p bgp ....\n"); 390 | 391 | printf("\n\nModules available at compile time:\n"); 392 | printf("\tipv4 ipv6 icmp tcp udp bgp rip ntp\n\n"); 393 | for(mod=first;mod!=NULL;mod=mod->next) { 394 | printf("\n\nArguments for module %s:\n",mod->name); 395 | for(i=0;inum_opts;i++) { 396 | printf(" -%c%s %c\t%s\n",mod->optchar, 397 | mod->opts[i].optname,mod->opts[i].arg?'x':' ', 398 | mod->opts[i].description); 399 | if(mod->opts[i].def) printf(" \t\t Default: %s\n", 400 | mod->opts[i].def); 401 | } 402 | } 403 | 404 | } 405 | 406 | int main(int argc, char *const argv[]) { 407 | int i; 408 | 409 | struct option *opts=NULL; 410 | int longindex=0; 411 | char rbuff[31]; 412 | 413 | bool usage=FALSE, verbosity=FALSE; 414 | 415 | char *data=NULL; 416 | int datafile=-1; 417 | int datalen=0; 418 | bool randomflag=FALSE; 419 | 420 | char *sockopts=NULL; 421 | 422 | sendip_module *mod; 423 | int optc; 424 | 425 | int num_modules=0; 426 | 427 | sendip_data packet; 428 | 429 | num_opts = 0; 430 | first=last=NULL; 431 | 432 | progname=argv[0]; 433 | 434 | /* magic random seed that gives 4 really random octets */ 435 | srandom(time(NULL) ^ (getpid()+(42<<15))); 436 | 437 | /* First, get all the builtin options, and load the modules */ 438 | gnuopterr=0; gnuoptind=0; 439 | while(gnuoptind when n is number of bytes */ 453 | datalen = atoi(data+1); 454 | if(datalen < 1) { 455 | fprintf(stderr,"Random data with length %d invalid\nNo data will be included\n",datalen); 456 | data=NULL; 457 | datalen=0; 458 | } 459 | data=(char *)malloc(datalen); 460 | for(i=0;inext) { 531 | int j; 532 | char *s; // nasty kludge because option.name is const 533 | for(j=0;jnum_opts;j++) { 534 | /* +2 on next line is one for the char, one for the trailing null */ 535 | opts[i].name = s = malloc(strlen(mod->opts[j].optname)+2); 536 | sprintf(s,"%c%s",mod->optchar,mod->opts[j].optname); 537 | opts[i].has_arg = mod->opts[j].arg; 538 | opts[i].flag = NULL; 539 | opts[i].val = mod->optchar; 540 | i++; 541 | } 542 | } 543 | if(verbosity) printf("Added %d options\n",num_opts); 544 | 545 | /* Initialize all */ 546 | for(mod=first;mod!=NULL;mod=mod->next) { 547 | if(verbosity) printf("Initializing module %s\n",mod->name); 548 | mod->pack=mod->initialize(); 549 | } 550 | 551 | /* Do the get opt */ 552 | gnuopterr=1; 553 | gnuoptind=0; 554 | while(EOF != (optc=getopt_long_only(argc,argv,"p:vd:hf:s:",opts,&longindex))) { 555 | 556 | switch(optc) { 557 | case 'p': 558 | case 'v': 559 | case 'd': 560 | case 'f': 561 | case 's': 562 | case 'h': 563 | /* Processed above */ 564 | break; 565 | case ':': 566 | usage=TRUE; 567 | fprintf(stderr,"Option %s requires an argument\n", 568 | opts[longindex].name); 569 | break; 570 | case '?': 571 | usage=TRUE; 572 | fprintf(stderr,"Option starting %c not recognized\n",gnuoptopt); 573 | break; 574 | default: 575 | for(mod=first;mod!=NULL;mod=mod->next) { 576 | if(mod->optchar==optc) { 577 | 578 | /* Random option arguments */ 579 | if(gnuoptarg != NULL && !strcmp(gnuoptarg,"r")) { 580 | /* need a 32 bit number, but random() is signed and 581 | nonnegative so only 31bits - we simply repeat one */ 582 | unsigned long r = (unsigned long)random()<<1; 583 | r+=(r&0x00000040)>>6; 584 | sprintf(rbuff,"%lu",r); 585 | gnuoptarg = rbuff; 586 | } 587 | 588 | if(!mod->do_opt(opts[longindex].name,gnuoptarg,mod->pack)) { 589 | usage=TRUE; 590 | } 591 | } 592 | } 593 | } 594 | } 595 | 596 | /* gnuoptind is the first thing that is not an option - should have exactly 597 | one hostname... 598 | */ 599 | if(argc != gnuoptind+1) { 600 | usage=TRUE; 601 | if(argc-gnuoptind < 1) fprintf(stderr,"No hostname specified\n"); 602 | else fprintf(stderr,"More than one hostname specified\n"); 603 | } else { 604 | if(first && first->set_addr) { 605 | first->set_addr(argv[gnuoptind],first->pack); 606 | } 607 | } 608 | 609 | /* free opts now we have finished with it */ 610 | for(i=0;i<(1+num_opts);i++) { 611 | if(opts[i].name != NULL) free((void *)opts[i].name); 612 | } 613 | free(opts); /* don't need them any more */ 614 | 615 | if(usage) { 616 | print_usage(); 617 | unload_modules(TRUE,verbosity); 618 | if(datafile != -1) { 619 | munmap(data,datalen); 620 | close(datafile); 621 | datafile=-1; 622 | } 623 | if(randomflag) free(data); 624 | if(sockopts) free(sockopts); 625 | return 0; 626 | } 627 | 628 | 629 | /* EVIL EVIL EVIL! */ 630 | /* Stick all the bits together. This means that finalize better not 631 | change the size or location of any packet's data... */ 632 | packet.data = NULL; 633 | packet.alloc_len = 0; 634 | packet.modified = 0; 635 | for(mod=first;mod!=NULL;mod=mod->next) { 636 | packet.alloc_len+=mod->pack->alloc_len; 637 | } 638 | if(data != NULL) packet.alloc_len+=datalen; 639 | packet.data = malloc(packet.alloc_len); 640 | for(i=0, mod=first;mod!=NULL;mod=mod->next) { 641 | memcpy((char *)packet.data+i,mod->pack->data,mod->pack->alloc_len); 642 | free(mod->pack->data); 643 | mod->pack->data = (char *)packet.data+i; 644 | i+=mod->pack->alloc_len; 645 | } 646 | 647 | /* Add any data */ 648 | if(data != NULL) memcpy((char *)packet.data+i,data,datalen); 649 | if(datafile != -1) { 650 | munmap(data,datalen); 651 | close(datafile); 652 | datafile=-1; 653 | } 654 | if(randomflag) free(data); 655 | 656 | /* Finalize from inside out */ 657 | { 658 | char hdrs[num_modules]; 659 | sendip_data *headers[num_modules]; 660 | sendip_data d; 661 | 662 | d.alloc_len = datalen; 663 | d.data = (char *)packet.data+packet.alloc_len-datalen; 664 | 665 | for(i=0,mod=first;mod!=NULL;mod=mod->next,i++) { 666 | hdrs[i]=mod->optchar; 667 | headers[i]=mod->pack; 668 | } 669 | 670 | for(i=num_modules-1,mod=last;mod!=NULL;mod=mod->prev,i--) { 671 | 672 | if(verbosity) printf("Finalizing module %s\n",mod->name); 673 | 674 | /* Remove this header from enclosing list */ 675 | hdrs[i]='\0'; 676 | headers[i] = NULL; 677 | 678 | mod->finalize(hdrs, headers, &d, mod->pack); 679 | 680 | /* Get everything ready for the next call */ 681 | d.data=(char *)d.data-mod->pack->alloc_len; 682 | d.alloc_len+=mod->pack->alloc_len; 683 | } 684 | } 685 | 686 | /* And send the packet */ 687 | { 688 | int af_type; 689 | if(first==NULL) { 690 | if(data == NULL) { 691 | fprintf(stderr,"Nothing specified to send!\n"); 692 | print_usage(); 693 | free(packet.data); 694 | unload_modules(FALSE,verbosity); 695 | return 1; 696 | } else { 697 | af_type = AF_INET; 698 | } 699 | } 700 | else if(first->optchar=='i') af_type = AF_INET; 701 | else if(first->optchar=='6') af_type = AF_INET6; 702 | else { 703 | fprintf(stderr,"Either IPv4 or IPv6 must be the outermost packet\n"); 704 | unload_modules(FALSE,verbosity); 705 | free(packet.data); 706 | if(sockopts) free(sockopts); 707 | return 1; 708 | } 709 | i = sendpacket(&packet,argv[gnuoptind],af_type,verbosity,sockopts); 710 | free(packet.data); 711 | free(sockopts); 712 | } 713 | unload_modules(FALSE,verbosity); 714 | return 0; 715 | } 716 | -------------------------------------------------------------------------------- /sendip.spec.in: -------------------------------------------------------------------------------- 1 | %define name sendip 2 | 3 | Summary: A command line tool to allow sending arbitrary IP packets 4 | Name: %name 5 | Version: %ver 6 | Release: 1 7 | Copyright: GPL 8 | Group: Applications/Internet 9 | Source: http://www.earth.li/projectpurple/files/sendip-%ver.tar.gz 10 | URL: http://www.earth.li/projectpurple/progs/sendip.html 11 | Vendor: Project Purple 12 | Packager: Mike Ricketts 13 | BuildRoot: /var/tmp/sendip-root 14 | 15 | %description 16 | A command line tool to send arbitrary IP packets. It has a large number of 17 | command line options to specify the content of every header of a NTP, BGP, 18 | RIP, RIPng, TCP, UDP, ICMP, or raw IPv4 or IPv6 packet. It also allows any 19 | data to be added to the packet. 20 | 21 | %changelog 22 | * Tue Dec 3 2002 Mike Ricketts 23 | - Update to version 2.3 24 | - RIPng fixes 25 | - Compile on archs requiring alignment 26 | 27 | * Sat Oct 12 2002 Mike Ricketts 28 | - Update to version 2.2 29 | - See CHANGES for a more complete list (there's even more than last time) 30 | 31 | * Sun Feb 24 2002 Calum Selkirk 32 | - changed /usr/share/man to %{_mandir} and added perl to edit Makefile 33 | to refect this 34 | - wrapped %discription to tw=78 35 | - rm buildroot before install 36 | - other minor tweeks 37 | 38 | * Sat Feb 23 2002 Mike Ricketts 39 | - Update to version 2.1 40 | - See CHANGES for a more complete list (there's a *lot*) 41 | 42 | * Fri Nov 23 2001 Juan Antonio Martinez 43 | - Made it FHS aware 44 | 45 | * Tue Jul 10 2001 Mike Ricketts 46 | - Update to version 2.0 47 | - See CHANGES for a more complete list 48 | 49 | * Mon Dec 25 2000 Mike Ricketts 50 | - Updated to version 1.4 51 | - RIP default 52 | - bugfixes 53 | - contrib 54 | 55 | * Wed Nov 29 2000 Mike Ricketts 56 | - Updated to version 1.3 57 | - IPv6, TCP options and other enhancements 58 | - Bugfixes 59 | - See CHANGES for more details 60 | 61 | * Sun Oct 22 2000 Mike Ricketts 62 | - Updated to version 1.1 63 | - RIP support (Richard Polton) 64 | - Bugfixes 65 | 66 | * Sat Jun 08 2000 Mike Ricketts 67 | - Updated to version 1.0 68 | 69 | * Mon Apr 10 2000 Mike Ricketts 70 | - Minor specfile changes, merged with main sendip release 71 | 72 | * Thu Apr 06 2000 Devlin Upton 73 | - First RPM release. 74 | 75 | %prep 76 | %setup 77 | 78 | %build 79 | mkdir -p $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/share/man/man1 80 | mkdir -p $RPM_BUILD_ROOT/usr/lib 81 | make PREFIX=/usr MANDIR=%{_mandir}/man1 82 | 83 | %install 84 | rm -rf $RPM_BUILD_ROOT 85 | mkdir -p $RPM_BUILD_ROOT/usr/{bin,lib} 86 | mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 87 | make PREFIX=$RPM_BUILD_ROOT/usr MANDIR=$RPM_BUILD_ROOT%{_mandir}/man1 install 88 | 89 | %clean 90 | rm -fr $RPM_BUILD_ROOT 91 | 92 | %files 93 | %defattr(-,root,root) 94 | %doc VERSION README CHANGES LICENSE TODO 95 | %doc /usr/share/man/man1/sendip.1* 96 | %attr(755,root,root) /usr/bin/sendip 97 | %attr(755,root,root) /usr/lib/sendip/*.so 98 | %dir /usr/lib/sendip 99 | -------------------------------------------------------------------------------- /sendip_module.h: -------------------------------------------------------------------------------- 1 | #ifndef _SENDIP_MODULE_H 2 | #define _SENDIP_MODULE_H 3 | 4 | #include // for fprintf 5 | 6 | #include "types.h" 7 | 8 | /* Options 9 | */ 10 | typedef struct { 11 | const char *optname; 12 | const bool arg; 13 | const char *description; 14 | const char *def; 15 | } sendip_option; 16 | 17 | /* Data 18 | */ 19 | typedef struct { 20 | void *data; 21 | int alloc_len; 22 | unsigned int modified; 23 | } sendip_data; 24 | 25 | /* Prototypes */ 26 | #ifndef _SENDIP_MAIN 27 | sendip_data *initialize(void); 28 | bool do_opt(char *optstring, char *optarg, sendip_data *pack); 29 | bool set_addr(char *hostname, sendip_data *pack); 30 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 31 | sendip_data *pack); 32 | int num_opts(void); 33 | sendip_option *get_opts(void); 34 | char get_optchar(void); 35 | 36 | #endif /* _SENDIP_MAIN */ 37 | 38 | #define usage_error(x) fprintf(stderr,x) 39 | 40 | extern u_int16_t csum(u_int16_t *packet, int packlen); 41 | extern int compact_string(char *data_out); 42 | 43 | #endif /* _SENDIP_MODULE_H */ 44 | -------------------------------------------------------------------------------- /tcp.c: -------------------------------------------------------------------------------- 1 | /* tcp.c - tcp support for sendip 2 | * Author: Mike Ricketts 3 | * TCP options taken from code by Alexander Talos 4 | * ChangeLog since 2.0 release: 5 | * 27/11/2001: Added -tonum option 6 | * 02/12/2001: Only check 1 layer for enclosing IPV4 header 7 | * ChangeLog since 2.1 release: 8 | * 16/04/2002: Tidy up checksum code (like in icmp.c) 9 | * 16/04/2002: Add support for TCP over IPV6 (code from armite ) 10 | * 26/08/2002: Fix bug where tcp length was wrong with tcp options 11 | * ChangeLog since 2.2 release: 12 | * 24/11/2002: made it compile on archs that care about alignment 13 | * ChangeLog since 2.4 release: 14 | * 21/04/2003: fix errors found by valgrind 15 | * 10/06/2003: fix -tonum (pointed out by Yaniv Kaul ) 16 | * ChangeLog since 2.5 release: 17 | * 02/03/2004: fix segfault in -tonum (pointed out by zamez) 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "sendip_module.h" 25 | #include "tcp.h" 26 | #include "ipv4.h" 27 | #include "ipv6.h" 28 | 29 | /* Character that identifies our options 30 | */ 31 | const char opt_char='t'; 32 | 33 | static void tcpcsum(sendip_data *ip_hdr, sendip_data *tcp_hdr, 34 | sendip_data *data) { 35 | tcp_header *tcp = (tcp_header *)tcp_hdr->data; 36 | ip_header *ip = (ip_header *)ip_hdr->data; 37 | u_int16_t *buf = malloc(12+tcp_hdr->alloc_len+data->alloc_len); 38 | u_int8_t *tempbuf = (u_int8_t *)buf; 39 | tcp->check=0; 40 | if(tempbuf == NULL) { 41 | fprintf(stderr,"Out of memory: TCP checksum not computed\n"); 42 | return; 43 | } 44 | /* Set up the pseudo header */ 45 | memcpy(tempbuf,&(ip->saddr),sizeof(u_int32_t)); 46 | memcpy(&(tempbuf[4]),&(ip->daddr),sizeof(u_int32_t)); 47 | tempbuf[8]=0; 48 | tempbuf[9]=(u_int16_t)ip->protocol; 49 | tempbuf[10]=(u_int16_t)((tcp_hdr->alloc_len+data->alloc_len)&0xFF00)>>8; 50 | tempbuf[11]=(u_int16_t)((tcp_hdr->alloc_len+data->alloc_len)&0x00FF); 51 | /* Copy the TCP header and data */ 52 | memcpy(tempbuf+12,tcp_hdr->data,tcp_hdr->alloc_len); 53 | memcpy(tempbuf+12+tcp_hdr->alloc_len,data->data,data->alloc_len); 54 | /* CheckSum it */ 55 | tcp->check = csum(buf,12+tcp_hdr->alloc_len+data->alloc_len); 56 | free(buf); 57 | } 58 | 59 | static void tcp6csum(sendip_data *ipv6_hdr, sendip_data *tcp_hdr, 60 | sendip_data *data) { 61 | tcp_header *tcp = (tcp_header *)tcp_hdr->data; 62 | ipv6_header *ipv6 = (ipv6_header *)ipv6_hdr->data; 63 | struct ipv6_pseudo_hdr phdr; 64 | 65 | u_int16_t *buf = malloc(sizeof(phdr)+tcp_hdr->alloc_len+data->alloc_len); 66 | u_int8_t *tempbuf = (u_int8_t *)buf; 67 | tcp->check=0; 68 | if(tempbuf == NULL) { 69 | fprintf(stderr,"Out of memory: TCP checksum not computed\n"); 70 | return; 71 | } 72 | 73 | /* Set up the pseudo header */ 74 | memset(&phdr,0,sizeof(phdr)); 75 | memcpy(&phdr.source,&ipv6->ip6_src,sizeof(struct in6_addr)); 76 | memcpy(&phdr.destination,&ipv6->ip6_dst,sizeof(struct in6_addr)); 77 | phdr.ulp_length=IPPROTO_TCP; 78 | 79 | memcpy(tempbuf,&phdr,sizeof(phdr)); 80 | 81 | /* Copy the TCP header and data */ 82 | memcpy(tempbuf+sizeof(phdr),tcp_hdr->data,tcp_hdr->alloc_len); 83 | memcpy(tempbuf+sizeof(phdr)+tcp_hdr->alloc_len,data->data,data->alloc_len); 84 | 85 | /* CheckSum it */ 86 | tcp->check = csum(buf,sizeof(phdr)+tcp_hdr->alloc_len+data->alloc_len); 87 | free(buf); 88 | } 89 | 90 | static void addoption(u_int8_t opt, u_int8_t len, u_int8_t *data, 91 | sendip_data *pack) { 92 | pack->data = realloc(pack->data, pack->alloc_len + len); 93 | *((u_int8_t *)pack->data+pack->alloc_len) = opt; 94 | if(len > 1) 95 | *((u_int8_t *)pack->data+pack->alloc_len+1)=len; 96 | if(len > 2) 97 | memcpy((u_int8_t *)pack->data+pack->alloc_len+2,data,len-2); 98 | pack->alloc_len += len; 99 | } 100 | 101 | sendip_data *initialize(void) { 102 | sendip_data *ret = malloc(sizeof(sendip_data)); 103 | tcp_header *tcp = malloc(sizeof(tcp_header)); 104 | memset(tcp,0,sizeof(tcp_header)); 105 | ret->alloc_len = sizeof(tcp_header); 106 | ret->data = (void *)tcp; 107 | ret->modified=0; 108 | return ret; 109 | } 110 | 111 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 112 | tcp_header *tcp = (tcp_header *)pack->data; 113 | // opt[0]==t 114 | switch(opt[1]) { 115 | case 's': 116 | tcp->source = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 117 | pack->modified |= TCP_MOD_SOURCE; 118 | break; 119 | case 'd': 120 | tcp->dest = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 121 | pack->modified |= TCP_MOD_DEST; 122 | break; 123 | case 'n': 124 | tcp->seq = htonl((u_int32_t)strtoul(arg, (char **)NULL, 0)); 125 | pack->modified |= TCP_MOD_SEQ; 126 | break; 127 | case 'a': 128 | tcp->ack_seq = htonl((u_int32_t)strtoul(arg, (char **)NULL, 0)); 129 | pack->modified |= TCP_MOD_ACKSEQ; 130 | if(!(pack->modified&TCP_MOD_ACK)) { 131 | tcp->ack = 1; 132 | pack->modified |= TCP_MOD_ACK; 133 | } 134 | break; 135 | case 't': 136 | tcp->off = (u_int16_t)strtoul(arg, (char **)NULL, 0) &0xF; 137 | pack->modified |= TCP_MOD_OFF; 138 | break; 139 | case 'r': 140 | tcp->res = (u_int16_t)(strtoul(arg, (char **)NULL, 0) & 0x000F); 141 | pack->modified |= TCP_MOD_RES; 142 | break; 143 | case 'f': 144 | switch(opt[2]) { 145 | case 'e': 146 | tcp->ecn=(u_int16_t)*arg&1; 147 | pack->modified |= TCP_MOD_ECN; 148 | break; 149 | case 'c': 150 | tcp->cwr=(u_int16_t)*arg&1; 151 | pack->modified |= TCP_MOD_CWR; 152 | break; 153 | case 'u': 154 | tcp->urg=(u_int16_t)*arg&1; 155 | pack->modified |= TCP_MOD_URG; 156 | break; 157 | case 'a': 158 | tcp->ack=(u_int16_t)*arg&1; 159 | pack->modified |= TCP_MOD_ACK; 160 | break; 161 | case 'p': 162 | tcp->psh=(u_int16_t)*arg&1; 163 | pack->modified |= TCP_MOD_PSH; 164 | break; 165 | case 'r': 166 | tcp->rst=(u_int16_t)*arg&1; 167 | pack->modified |= TCP_MOD_RST; 168 | break; 169 | case 's': 170 | tcp->syn=(u_int16_t)*arg&1; 171 | pack->modified |= TCP_MOD_SYN; 172 | break; 173 | case 'f': 174 | tcp->fin=(u_int16_t)*arg&1; 175 | pack->modified |= TCP_MOD_FIN; 176 | break; 177 | default: 178 | usage_error("TCP flag not known\n"); 179 | return FALSE; 180 | } 181 | break; 182 | case 'w': 183 | tcp->window = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 184 | pack->modified |= TCP_MOD_WINDOW; 185 | break; 186 | case 'c': 187 | tcp->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 188 | pack->modified |= TCP_MOD_CHECK; 189 | break; 190 | case 'u': 191 | tcp->urg_ptr = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 192 | pack->modified |= TCP_MOD_URGPTR; 193 | if(!(pack->modified&TCP_MOD_URG)) { 194 | tcp->urg = 1; 195 | pack->modified |= TCP_MOD_URG; 196 | } 197 | break; 198 | 199 | case 'o': 200 | /* TCP OPTIONS */ 201 | if(!strcmp(opt+2, "num")) { 202 | /* Other options (auto length) */ 203 | u_int8_t *data = malloc(strlen(arg)+3); 204 | int len; 205 | if(!data) { 206 | fprintf(stderr,"Out of memory!\n"); 207 | return FALSE; 208 | } 209 | sprintf((char*)data,"0x%s",arg); 210 | len = compact_string((char*)data); 211 | if(len==1) 212 | addoption(*data,1,NULL,pack); 213 | else 214 | addoption(*data,len+1,data+1,pack); 215 | free(data); 216 | } else if (!strcmp(opt+2, "eol")) { 217 | /* End of options list RFC 793 kind 0, no length */ 218 | addoption(0,1,NULL,pack); 219 | } else if (!strcmp(opt+2, "nop")) { 220 | /* No op RFC 793 kind 1, no length */ 221 | addoption(1,1,NULL,pack); 222 | } else if (!strcmp(opt+2, "mss")) { 223 | /* Maximum segment size RFC 793 kind 2 */ 224 | u_int16_t mss=htons(atoi(arg)); 225 | addoption(2,4,(u_int8_t *)&mss,pack); 226 | } else if (!strcmp(opt+2, "wscale")) { 227 | /* Window scale rfc1323 */ 228 | u_int8_t wscale=atoi(arg); 229 | addoption(3,3,&wscale,pack); 230 | } else if (!strcmp(opt+2, "sackok")) { 231 | /* Selective Acknowledge permitted rfc1323 */ 232 | addoption(4,2,NULL,pack); 233 | } else if (!strcmp(opt+2, "sack")) { 234 | /* Selective Acknowledge rfc1323 */ 235 | unsigned char *next; 236 | u_int32_t le, re; 237 | u_int8_t *comb, *c; 238 | int count=0; 239 | 240 | /* count the options */ 241 | next=(unsigned char *)arg; 242 | while(next) { 243 | next=(unsigned char *)strchr((char *)next,','); 244 | count++; 245 | if(next) next++; 246 | } 247 | 248 | comb = malloc(count*8); 249 | c = comb; 250 | 251 | next=(unsigned char *)arg; 252 | while(*next) { 253 | /* get left edge */ 254 | next=(unsigned char *)strchr(arg, ':'); 255 | if (!next) { 256 | fprintf(stderr, 257 | "Value in tcp sack option incorrect. Usage: \n"); 258 | fprintf(stderr, 259 | " -tosack left:right[,left:right...]\n"); 260 | return FALSE; 261 | } 262 | *next++=0; 263 | le=atoi(arg); 264 | arg=(char *)next; 265 | /* get right edge */ 266 | next=(unsigned char *)strchr(arg, ','); 267 | if (!next) 268 | next=(unsigned char *)arg-1; /* Finito - next points to \0 */ 269 | else 270 | *next++=0; 271 | re=atoi(arg); 272 | arg=(char *)next; 273 | 274 | le=htonl(le); 275 | re=htonl(re); 276 | memcpy(c, &le, 4); 277 | memcpy(c+4, &re, 4); 278 | c+=8; 279 | } 280 | addoption(5,count*8+2,comb,pack); 281 | free(comb); 282 | } else if (!strcmp(opt+2, "ts")) { 283 | /* Timestamp rfc1323 */ 284 | u_int32_t tsval=0, tsecr=0; 285 | u_int8_t comb[8]; 286 | if (2!=sscanf(arg, "%d:%d", &tsval, &tsecr)) { 287 | fprintf(stderr, 288 | "Invalid value for tcp timestamp option.\n"); 289 | fprintf(stderr, 290 | "Usage: -tots tsval:tsecr\n"); 291 | return FALSE; 292 | } 293 | tsval=htonl(tsval); 294 | memcpy(comb, &tsval, 4); 295 | tsecr=htonl(tsecr); 296 | memcpy(comb+4, &tsecr, 4); 297 | addoption(8,10,comb,pack); 298 | } else { 299 | /* Unrecognized -to* */ 300 | fprintf(stderr, "unsupported TCP Option %s val %s\n", 301 | opt, arg); 302 | return FALSE; 303 | } 304 | break; 305 | 306 | default: 307 | usage_error("unknown TCP option\n"); 308 | return FALSE; 309 | break; 310 | 311 | } 312 | 313 | return TRUE; 314 | 315 | } 316 | 317 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 318 | sendip_data *pack) { 319 | tcp_header *tcp = (tcp_header *)pack->data; 320 | 321 | /* Set relevant fields */ 322 | if(!(pack->modified&TCP_MOD_SEQ)) { 323 | tcp->seq = (u_int32_t)rand(); 324 | } 325 | if(!(pack->modified&TCP_MOD_OFF)) { 326 | tcp->off = (u_int16_t)((pack->alloc_len+3)/4) & 0x0F; 327 | } 328 | if(!(pack->modified&TCP_MOD_SYN)) { 329 | tcp->syn=1; 330 | } 331 | if(!(pack->modified&TCP_MOD_WINDOW)) { 332 | tcp->window=htons((u_int16_t)65535); 333 | } 334 | 335 | /* Find enclosing IP header and do the checksum */ 336 | if(hdrs[strlen(hdrs)-1]=='i') { 337 | int i = strlen(hdrs)-1; 338 | if(!(headers[i]->modified&IP_MOD_PROTOCOL)) { 339 | ((ip_header *)(headers[i]->data))->protocol=IPPROTO_TCP; 340 | headers[i]->modified |= IP_MOD_PROTOCOL; 341 | } 342 | if(!(pack->modified&TCP_MOD_CHECK)) { 343 | tcpcsum(headers[i],pack,data); 344 | } 345 | } else if(hdrs[strlen(hdrs)-1]=='6') { 346 | int i = strlen(hdrs)-1; 347 | if(!(headers[i]->modified&IPV6_MOD_NXT)) { 348 | ((ipv6_header *)(headers[i]->data))->ip6_nxt=IPPROTO_TCP; 349 | headers[i]->modified |= IPV6_MOD_NXT; 350 | } 351 | if(!(pack->modified&TCP_MOD_CHECK)) { 352 | tcp6csum(headers[i],pack,data); 353 | } 354 | } else { 355 | if(!(pack->modified&TCP_MOD_CHECK)) { 356 | usage_error("TCP checksum not defined when TCP is not embedded in IP\n"); 357 | return FALSE; 358 | } 359 | } 360 | 361 | return TRUE; 362 | } 363 | 364 | int num_opts() { 365 | return sizeof(tcp_opts)/sizeof(sendip_option); 366 | } 367 | sendip_option *get_opts() { 368 | return tcp_opts; 369 | } 370 | char get_optchar() { 371 | return opt_char; 372 | } 373 | -------------------------------------------------------------------------------- /tcp.h: -------------------------------------------------------------------------------- 1 | /* tcp.h 2 | */ 3 | #ifndef _SENDIP_TCP_H 4 | #define _SENDIP_TCP_H 5 | 6 | #ifndef NULL 7 | #define NULL (0L) 8 | #endif 9 | 10 | /* TCP HEADER 11 | * Ripped straight out of glibc-2.2.2, modified for RFC22481 12 | * Reproduced here to prevent nasty #defines on non-linux boxes 13 | */ 14 | typedef struct { 15 | u_int16_t source; 16 | u_int16_t dest; 17 | u_int32_t seq; 18 | u_int32_t ack_seq; 19 | #if __BYTE_ORDER == __LITTLE_ENDIAN 20 | u_int16_t res:4; 21 | u_int16_t off:4; 22 | u_int16_t fin:1; 23 | u_int16_t syn:1; 24 | u_int16_t rst:1; 25 | u_int16_t psh:1; 26 | u_int16_t ack:1; 27 | u_int16_t urg:1; 28 | u_int16_t cwr:1; 29 | u_int16_t ecn:1; 30 | #elif __BYTE_ORDER == __BIG_ENDIAN 31 | u_int16_t off:4; 32 | u_int16_t res:4; 33 | u_int16_t ecn:1; 34 | u_int16_t cwr:1; 35 | u_int16_t urg:1; 36 | u_int16_t ack:1; 37 | u_int16_t psh:1; 38 | u_int16_t rst:1; 39 | u_int16_t syn:1; 40 | u_int16_t fin:1; 41 | #else 42 | # error "Adjust your defines" 43 | #endif 44 | u_int16_t window; 45 | u_int16_t check; 46 | u_int16_t urg_ptr; 47 | 48 | } tcp_header; 49 | 50 | /* Defines for which parts have been modified 51 | */ 52 | #define TCP_MOD_SOURCE 1 53 | #define TCP_MOD_DEST 1<<1 54 | #define TCP_MOD_SEQ 1<<2 55 | #define TCP_MOD_ACKSEQ 1<<3 56 | #define TCP_MOD_RES 1<<4 57 | #define TCP_MOD_OFF 1<<5 58 | #define TCP_MOD_FIN 1<<6 59 | #define TCP_MOD_SYN 1<<7 60 | #define TCP_MOD_RST 1<<8 61 | #define TCP_MOD_PSH 1<<9 62 | #define TCP_MOD_ACK 1<<10 63 | #define TCP_MOD_URG 1<<11 64 | #define TCP_MOD_ECN 1<<12 65 | #define TCP_MOD_CWR 1<<13 66 | #define TCP_MOD_WINDOW 1<<14 67 | #define TCP_MOD_CHECK 1<<15 68 | #define TCP_MOD_URGPTR 1<<16 69 | 70 | /* Options 71 | */ 72 | sendip_option tcp_opts[] = { 73 | {"s",1,"TCP source port","0"}, 74 | {"d",1,"TCP destination port","0"}, 75 | {"n",1,"TCP sequence number","Random"}, 76 | {"a",1,"TCP ack number","0"}, 77 | {"t",1,"TCP data offset","Correct"}, 78 | {"r",1,"TCP header reserved field EXCLUDING ECN and CWR bits","0"}, 79 | {"fe",1,"TCP ECN bit (rfc2481)","0 (options are 0,1,r)"}, 80 | {"fc",1,"TCP CWR bit (rfc2481)","0 (options are 0,1,r)"}, 81 | {"fu",1,"TCP URG bit","0, or 1 if -tu specified (options are 0,1,r)"}, 82 | {"fa",1,"TCP ACK bit","0, or 1 if -ta specified (options are 0,1,r)"}, 83 | {"fp",1,"TCP PSH bit","0 (options are 0,1,r)"}, 84 | {"fr",1,"TCP RST bit","0 (options are 0,1,r)"}, 85 | {"fs",1,"TCP SYN bit","1 (options are 0,1,r)"}, 86 | {"ff",1,"TCP FIN bit","0 (options are 0,1,r)"}, 87 | {"w",1,"TCP window size","65535"}, 88 | {"c",1,"TCP checksum","Correct"}, 89 | {"u",1,"TCP urgent pointer","0"}, 90 | {"onum",1,"TCP option as string of hex bytes (length is always correct)","(no options)"}, 91 | {"oeol",0,"TCP option: end of list", NULL }, 92 | {"onop",0,"TCP option: no op", NULL }, 93 | {"omss",1,"TCP option: maximum segment size", NULL }, 94 | {"owscale",1,"TCP option: window scale (rfc1323)", NULL }, 95 | {"osackok",0,"TCP option: allow selective ack (rfc2018)", NULL }, 96 | {"osack",1,"TCP option: selective ack (rfc2018), format is l_edge1:r_edge1,l_edge2:r_edge2...", NULL }, 97 | {"ots",1,"TCP option: timestamp (rfc1323), format is tsval:tsecr", NULL } 98 | }; 99 | 100 | #endif /* _SENDIP_TCP_H */ 101 | -------------------------------------------------------------------------------- /types.h: -------------------------------------------------------------------------------- 1 | /* types.h - tpyes needed in sendip and not defined everywhere 2 | * Author: Mike Ricketts 3 | * ChangeLog since 2.1 release: 4 | * 03/02/2002 Added more defines/protos for non-IPv6 systems. 5 | * 26/03/2002 FreeBSD style BYTE_ORDER fixes 6 | */ 7 | #ifndef _SENDIP_TYPES_H 8 | #define _SENDIP_TYPES_H 9 | 10 | /* Make sure we have bool */ 11 | typedef int bool; 12 | #ifndef FALSE 13 | #define TRUE (0==0) 14 | #define FALSE (!TRUE) 15 | #endif 16 | 17 | /* Solaris doesn't define these */ 18 | #ifdef __sun__ 19 | typedef uint16_t u_int16_t; 20 | typedef uint32_t u_int32_t; 21 | typedef uint8_t u_int8_t; 22 | 23 | /* disable ipv6 on solaris */ 24 | #define gethostbyname2(x,y) gethostbyname(x) 25 | 26 | #endif /* __sun__ */ 27 | 28 | /* for things that *really* don't know about ipv6, ... */ 29 | #ifndef AF_INET6 30 | #define AF_INET6 10 31 | #define IPPROTO_ICMPV6 58 32 | #define IPPROTO_NONE 59 33 | #define IPPROTO_DSTOPTS 60 34 | #endif /* !AF_INET6 */ 35 | 36 | #ifndef s6_addr 37 | struct in6_addr { 38 | union { 39 | u_int8_t u6_addr8[16]; 40 | u_int16_t u6_addr16[8]; 41 | u_int32_t u6_addr32[4]; 42 | } in6_u; 43 | #define s6_addr in6_u.u6_addr8 44 | #define s6_add16 in6_u.u6_addr16 45 | #define s6_add32 in6_u.u6_addr32 46 | }; 47 | extern const struct in6_addr in6addr_any; /* :: */ 48 | extern const struct in6_addr in6addr_loopback; /* ::1 */ 49 | 50 | struct sockaddr_in6 { 51 | u_int16_t sin6_family; 52 | u_int16_t sin6_port; 53 | u_int32_t sin6_flowinfo; 54 | struct in6_addr sin6_addr; 55 | u_int32_t sin6_scope_id; 56 | }; 57 | extern int inet_pton (int af, const char *cp, void *buf); 58 | 59 | #endif /* !s6_addr */ 60 | 61 | /* Convert _BIG_ENDIAN/_LITTLE_ENDIAN to __BYTE_ORDER */ 62 | #ifndef __LITTLE_ENDIAN 63 | #define __LITTLE_ENDIAN 1234 64 | #endif 65 | 66 | #ifndef __BIG_ENDIAN 67 | #define __BIG_ENDIAN 4321 68 | #endif 69 | 70 | #ifndef __BYTE_ORDER 71 | 72 | /* Not linux-style, maybe FreeBSD-style */ 73 | #ifdef BYTE_ORDER 74 | #undef __LITTLE_ENDIAN 75 | #undef __BIG_ENDIAN 76 | #define __LITTLE_ENDIAN LITTLE_ENDIAN 77 | #define __BIG_ENDIAN BIG_ENDIAN 78 | #define __BYTE_ORDER BYTE_ORDER 79 | #else 80 | 81 | /* Not FreeBSD-style, try solaris style */ 82 | #ifdef _BIG_ENDIAN 83 | #define __BYTE_ORDER __BIG_ENDIAN 84 | #else /* not _BIG_ENDIAN */ 85 | #ifdef _LITTLE_ENDIAN 86 | #define __BYTE_ORDER __LITTLE_ENDIAN 87 | #else /* not _LITTLE_ENDIAN */ 88 | 89 | /* Not solaris style. Give up. */ 90 | #error Could not guess your byte order 91 | 92 | #endif /* not _LITTLE_ENDIAN */ 93 | #endif /* not _BIG_ENDIAN */ 94 | #endif /* not BYTE_ORDER */ 95 | #endif /* not __BYTE_ORDER */ 96 | 97 | #endif /* _SENDIP_TYPES_H */ 98 | -------------------------------------------------------------------------------- /udp.c: -------------------------------------------------------------------------------- 1 | /* udp.c - UDP code for sendip 2 | * Author: Mike Ricketts 3 | * ChangeLog since 2.0 release: 4 | * ChangeLog since 2.1 release: 5 | * 16/04/2002: Only check one layer of enclosing headers for ip 6 | * 16/04/2002: Add support for UDP over IPV6 7 | * ChangeLog since 2.4 release: 8 | * 21/04/2003: Fix errors found by valgrind 9 | * ChangeLog since 2.5 release: 10 | * 03/11/2006: Fix UDPv6 checksum error found by biplab sarkar 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "sendip_module.h" 18 | #include "udp.h" 19 | #include "ipv4.h" 20 | #include "ipv6.h" 21 | 22 | /* Character that identifies our options 23 | */ 24 | const char opt_char='u'; 25 | 26 | static void udpcsum(sendip_data *ip_hdr, sendip_data *udp_hdr, 27 | sendip_data *data) { 28 | udp_header *udp = (udp_header *)udp_hdr->data; 29 | ip_header *ip = (ip_header *)ip_hdr->data; 30 | u_int16_t *buf = malloc(12+udp_hdr->alloc_len+data->alloc_len); 31 | u_int8_t *tempbuf = (u_int8_t *)buf; 32 | udp->check=0; 33 | if(tempbuf == NULL) { 34 | fprintf(stderr,"Out of memory: UDP checksum not computed\n"); 35 | return; 36 | } 37 | /* Set up the pseudo header */ 38 | memcpy(tempbuf,&(ip->saddr),sizeof(u_int32_t)); 39 | memcpy(&(tempbuf[4]),&(ip->daddr),sizeof(u_int32_t)); 40 | tempbuf[8]=0; 41 | tempbuf[9]=(u_int16_t)ip->protocol; 42 | tempbuf[10]=(u_int16_t)((udp_hdr->alloc_len+data->alloc_len)&0xFF00)>>8; 43 | tempbuf[11]=(u_int16_t)((udp_hdr->alloc_len+data->alloc_len)&0x00FF); 44 | /* Copy the UDP header and data */ 45 | memcpy(tempbuf+12,udp_hdr->data,udp_hdr->alloc_len); 46 | memcpy(tempbuf+12+udp_hdr->alloc_len,data->data,data->alloc_len); 47 | /* CheckSum it */ 48 | udp->check = csum(buf,12+udp_hdr->alloc_len+data->alloc_len); 49 | free(buf); 50 | } 51 | 52 | static void udp6csum(sendip_data *ipv6_hdr, sendip_data *udp_hdr, 53 | sendip_data *data) { 54 | udp_header *udp = (udp_header *)udp_hdr->data; 55 | ipv6_header *ipv6 = (ipv6_header *)ipv6_hdr->data; 56 | struct ipv6_pseudo_hdr phdr; 57 | 58 | u_int16_t *buf = malloc(sizeof(phdr)+udp_hdr->alloc_len+data->alloc_len); 59 | u_int8_t *tempbuf = (u_int8_t *)buf; 60 | udp->check=0; 61 | if(tempbuf == NULL) { 62 | fprintf(stderr,"Out of memory: UDP checksum not computed\n"); 63 | return; 64 | } 65 | 66 | /* Set up the pseudo header */ 67 | memset(&phdr,0,sizeof(phdr)); 68 | memcpy(&phdr.source,&ipv6->ip6_src,sizeof(struct in6_addr)); 69 | memcpy(&phdr.destination,&ipv6->ip6_dst,sizeof(struct in6_addr)); 70 | phdr.nexthdr=IPPROTO_UDP; 71 | phdr.ulp_length=udp->len; 72 | 73 | memcpy(tempbuf,&phdr,sizeof(phdr)); 74 | 75 | /* Copy the UDP header and data */ 76 | memcpy(tempbuf+sizeof(phdr),udp_hdr->data,udp_hdr->alloc_len); 77 | memcpy(tempbuf+sizeof(phdr)+udp_hdr->alloc_len,data->data,data->alloc_len); 78 | 79 | /* CheckSum it */ 80 | udp->check = csum(buf,sizeof(phdr)+udp_hdr->alloc_len+data->alloc_len); 81 | free(buf); 82 | } 83 | 84 | sendip_data *initialize(void) { 85 | sendip_data *ret = malloc(sizeof(sendip_data)); 86 | udp_header *udp = malloc(sizeof(udp_header)); 87 | memset(udp,0,sizeof(udp_header)); 88 | ret->alloc_len = sizeof(udp_header); 89 | ret->data = (void *)udp; 90 | ret->modified=0; 91 | return ret; 92 | } 93 | 94 | bool do_opt(char *opt, char *arg, sendip_data *pack) { 95 | udp_header *udp = (udp_header *)pack->data; 96 | switch(opt[1]) { 97 | case 's': 98 | udp->source = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 99 | pack->modified |= UDP_MOD_SOURCE; 100 | break; 101 | case 'd': 102 | udp->dest = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 103 | pack->modified |= UDP_MOD_DEST; 104 | break; 105 | case 'l': 106 | udp->len = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 107 | pack->modified |= UDP_MOD_LEN; 108 | break; 109 | case 'c': 110 | udp->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0)); 111 | pack->modified |= UDP_MOD_CHECK; 112 | break; 113 | } 114 | return TRUE; 115 | 116 | } 117 | 118 | bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data, 119 | sendip_data *pack) { 120 | udp_header *udp = (udp_header *)pack->data; 121 | 122 | /* Set relevant fields */ 123 | if(!(pack->modified&UDP_MOD_LEN)) { 124 | udp->len=htons(pack->alloc_len+data->alloc_len); 125 | } 126 | 127 | /* Find enclosing IP header and do the checksum */ 128 | if(hdrs[strlen(hdrs)-1]=='i') { 129 | int i = strlen(hdrs)-1; 130 | if(!(headers[i]->modified&IP_MOD_PROTOCOL)) { 131 | ((ip_header *)(headers[i]->data))->protocol=IPPROTO_UDP; 132 | headers[i]->modified |= IP_MOD_PROTOCOL; 133 | } 134 | if(!(pack->modified&UDP_MOD_CHECK)) { 135 | udpcsum(headers[i],pack,data); 136 | } 137 | } else if(hdrs[strlen(hdrs)-1]=='6') { 138 | int i = strlen(hdrs)-1; 139 | if(!(headers[i]->modified&IPV6_MOD_NXT)) { 140 | ((ipv6_header *)(headers[i]->data))->ip6_nxt=IPPROTO_UDP; 141 | headers[i]->modified |= IPV6_MOD_NXT; 142 | } 143 | if(!(pack->modified&UDP_MOD_CHECK)) { 144 | udp6csum(headers[i],pack,data); 145 | } 146 | 147 | } else { 148 | if(!(pack->modified&UDP_MOD_CHECK)) { 149 | usage_error("UDP checksum not defined when UDP is not embedded in IP\n"); 150 | return FALSE; 151 | } 152 | } 153 | 154 | return TRUE; 155 | } 156 | 157 | int num_opts() { 158 | return sizeof(udp_opts)/sizeof(sendip_option); 159 | } 160 | sendip_option *get_opts() { 161 | return udp_opts; 162 | } 163 | char get_optchar() { 164 | return opt_char; 165 | } 166 | -------------------------------------------------------------------------------- /udp.h: -------------------------------------------------------------------------------- 1 | /* udp.h 2 | */ 3 | #ifndef _SENDIP_UDP_H 4 | #define _SENDIP_UDP_H 5 | 6 | /* UDP HEADER 7 | */ 8 | typedef struct { 9 | u_int16_t source; 10 | u_int16_t dest; 11 | u_int16_t len; 12 | u_int16_t check; 13 | } udp_header; 14 | 15 | /* Defines for which parts have been modified 16 | */ 17 | #define UDP_MOD_SOURCE 1 18 | #define UDP_MOD_DEST 1<<1 19 | #define UDP_MOD_LEN 1<<2 20 | #define UDP_MOD_CHECK 1<<3 21 | 22 | /* Options 23 | */ 24 | sendip_option udp_opts[] = { 25 | {"s",1,"UDP source port","0"}, 26 | {"d",1,"UDP destination port","0"}, 27 | {"l",1,"UDP packet legnth","Correct"}, 28 | {"c",1,"UDP checksum","Correct"} 29 | }; 30 | 31 | #endif /* _SENDIP_UDP_H */ 32 | --------------------------------------------------------------------------------