bittwist-linux-2.0/000755 000765 000024 00000000000 11744746762 015373 5ustar00addyyeowstaff000000 000000 bittwist-linux-2.0/._AUTHORS000444 000765 000024 00000000341 11744746762 016654 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect4{{0, 0}, {970, 698}}bittwist-linux-2.0/AUTHORS000444 000765 000024 00000000175 11744746762 016444 0ustar00addyyeowstaff000000 000000 Authors of Bit-Twist Addy Yeow Chin Heng wrote the original Bit-Twist and is the current maintainer. bittwist-linux-2.0/._BUGS000444 000765 000024 00000000341 11744746762 016267 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect3{{0, 0}, {970, 698}}bittwist-linux-2.0/BUGS000444 000765 000024 00000000241 11744746762 016051 0ustar00addyyeowstaff000000 000000 File your bug report and send to Addy Yeow Chin Heng . Make sure you are using the latest stable version before submitting your bug report. bittwist-linux-2.0/._CHANGES000444 000765 000024 00000000344 11744746762 016602 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect8:19{{0, 0}, {964, 698}}bittwist-linux-2.0/CHANGES000444 000765 000024 00000014511 11744746762 016366 0ustar00addyyeowstaff000000 000000 21/04/2012: Version 2.0 - switched to "struct pcap_sf_pkthdr" to support 64-bit platforms - rebuilt with libpcap 1.2.1 - added Mac OS X distribution (author's primary platform) - BSD distribution no longer maintained - ended Bit-Twist Web Edition BETA - revised copyright information and manpages bittwistb (bridge) - no longer maintained on all platforms 12/12/2009: Version 1.1 - rebuilt with libpcap 1.0.0 - revised copyright information and manpages - removed Eclipse dependency; requires only Cygwin environment for Windows development - release of bittwist(w), Bit-Twist Web Edition BETA, http://twitter.com/bittwistw 26/10/2007: Version 1.0 - revised AUTHORS, INSTALL, copyright information and manpages - unified source files for all supported platforms - moved Windows development to Eclipse IDE for C/C++ Developers + Cygwin environment bittwist (generator) - increased max. packet throughput from 1Gbps to 10Gbps (option -r) bittwiste (editor) - corrected usage of strptime() - use comma (,) instead of slash (/) as delimiter for all replace options - added a feature request; replace a specific MAC address with a new MAC address for eth, arp - added a feature request; replace a specific IP address with a new IP address for arp 23/10/2006: Version 0.80 bittwist (generator) - improved performance; use single buffer for all packet data, calculate linerate_interval only when necessary bittwiste (editor) - corrected several malloc related bugs - added a feature request; replace the linktype stored in the pcap file header, e.g. to replace raw IP linktype to Ethernet linktype, bittwiste -I rawip.pcap -O rawip.1.pcap -M 1 - added a feature request; support for writing packets within a specific timeframe only, e.g. bittwist -I trace.pcap -O trace.1.pcap -S 22/10/2006,21:47:35-24/10/2006,13:16:05 17/09/2006: Version 0.74 bittwiste (editor) - minor bug correction - added a feature request; delete a specific byte offset from a packet, bittwiste -I trace.pcap -O trace.1.pcap -D 1-14 - added a feature request; replace a specific IP address with a new IP address, e.g. to replace source IP address 192.168.0.1 with 192.168.1.1, bittwiste -I ip.pcap -O ip.1.pcap -T ip -s 192.168.0.1:192.168.1.1 28/07/2006: Version 0.73 - minor correction in Makefile - merged 180506-0.72-def.h-patch-1 (patch for OpenBSD) into BSD distribution bittwiste (editor) - minor bug correction - added a feature request; replace a specific port number with a new port number, e.g. to replace destination port 1066 with 1067, bittwiste -I tcp.pcap -O tcp.1.pcap -T tcp -d 1066:1067 misc. - Bit-Twist 0.72 for Windows has been released prior to this update 29/04/2006: Version 0.72 - removed definition of in_addr_t in def.h for BSD distribution bittwistb (bridge) - minor bug correction 28/04/2006: Version 0.71 bittwist (generator) - removed maths.h which was previously required for round(), ROUND() is now defined in def.h - minor bug correction bittwistb (bridge) - fixed gethwaddr(), previous version does not work under Linux 11/04/2006: Version 0.7 bittwistb (bridge) - removed packet duplication check (based on resource hog MD5 hashing); this was initially required due to a faulty logic which causes the bridge to check and forward packets that are already departing from an interface - added explicit check for broadcast and multicast packets - added hash entry timeout check bittwiste (editor) - option -R range can take a single value, e.g. -R 10 instead of previous requirement of -R 10-10 to save only the 10th packet - added support for checksum correction for payload which covers ICMP, TCP, or UDP header and data - in def.h, #define IP_FO_MAX, 8191 changed to 7770 misc. - created manpages for bittwist, bittwistb, bittwiste - public release: http://bittwist.sourceforge.net 04/04/2006: Version 0.61 bittwistb (bridge) - minor correction: when "forward to all", we are not suppose to forward a packet back into the same port where we received it 03/04/2006: Version 0.6 bittwistb (bridge) - added pcap based program to bridge 2 or more LAN segments bittwiste (editor) - added proper handling for fragmented packets - skip checksum calculation for fragmented packets - option -R range is working now 17/03/2006: Version 0.5 bittwist (generator) - removed option -e timeout presented in Version 0.4 since its usage is limited and we can do better by using the OS ping program - added option -c count to send packets up to count bittwiste (editor) - full rewrite - added options to edit most fields in Ethernet, ARP, IP, ICMP, TCP and UDP header - added option -X payload to support addition of payload from standard input - added option -L layer to support writing up to specific layer only - added option -R range to support writing of specific packets only 10/03/2006: Version 0.4 - redundant definitions in bittwist.h and bittwiste.h moved to def.h - change of datatype, e.g. unsigned char is now u_char bittwist (generator) - added option -e timeout to allow sending packet as ping packet and check for host response (currently limited to ICMP echo only, expect support for TCP in later version) bittwiste (editor) - added option -c to disable/enable checksum correction 25/02/2006: Version 0.3 bittwist (generator) - added option -r linerate to limit packet throughput at the specified line rate (1 -> 1000Mbps) - explicit close for pcap descriptor and file pointer removed from cleanup() - more details in info() bittwiste (editor) - options to change source/destination MAC, source/destination IP, TTL, source/destination port, enable/disable checksum correction for IP, ICMP, TCP and UDP packets 21/02/2006: Version 0.2 - removes libnet dependency - requires libpcap 0.9.4 (and above) - options: -d, -vv, -i interface, -s len, -l loop, -m speed, -p sleep, -h - -v for timestamp and -vv to include hex data - user specified interval in seconds through -p option - interval multiplier through -m option - packet length: send captured length / on wire length / user specified length (14 to 1514 bytes) through option -s - SIGINT signal handling 25/01/2006: Version 0.1 - skeleton program, uses libpcap 0.9.4 and libnet 1.1.3-RC-01 - options: -D, -V, -i interface, -l loop - tested only on FreeBSD 6.0-STABLE bittwist-linux-2.0/._COPYING000444 000765 000024 00000000341 11744746762 016637 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect1{{0, 0}, {964, 698}}bittwist-linux-2.0/COPYING000444 000765 000024 00000043734 11744746762 016437 0ustar00addyyeowstaff000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. bittwist-linux-2.0/doc/000755 000765 000024 00000000000 11744746762 016140 5ustar00addyyeowstaff000000 000000 bittwist-linux-2.0/._Makefile000444 000765 000024 00000000342 11744746762 017245 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect41{{0, 0}, {970, 698}}bittwist-linux-2.0/Makefile000444 000765 000024 00000001664 11744746762 017040 0ustar00addyyeowstaff000000 000000 SHELL = /bin/sh prefix = /usr exec_prefix = ${prefix} bindir = ${exec_prefix}/bin mandir = ${prefix}/share/man/man1 CC ?= gcc DEBUG = -g CFLAGS ?= -O2 CFLAGS += $(DEBUG) SRC = src DOC = doc INSTALL = /usr/bin/install -c INSTALL_PROGRAM = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 all: bittwist bittwiste bittwist: $(CC) $(CFLAGS) $(SRC)/bittwist.c -o $(SRC)/bittwist -I/usr/local/include -L/usr/local/lib -lpcap bittwiste: $(CC) $(CFLAGS) $(SRC)/bittwiste.c -o $(SRC)/bittwiste -I/usr/local/include -L/usr/local/lib -lpcap clean: rm -f $(SRC)/bittwist $(SRC)/bittwiste install: mkdir -p $(bindir) chmod 755 $(bindir) $(INSTALL_PROGRAM) $(SRC)/bittwist $(SRC)/bittwiste $(bindir) mkdir -p $(mandir) chmod 755 $(mandir) $(INSTALL_DATA) $(DOC)/bittwist.1 $(DOC)/bittwiste.1 $(mandir) uninstall: rm -f $(bindir)/bittwist $(bindir)/bittwiste rm -f $(mandir)/bittwist.1 $(mandir)/bittwiste.1 bittwist-linux-2.0/README000444 000765 000024 00000001231 11744746762 016246 0ustar00addyyeowstaff000000 000000 Bit-Twist: Libpcap-based Ethernet packet generator Supported platforms: This distribution is tested to work on CentOS release 6.2. Dependencies: Libpcap is required (available for download from http://www.tcpdump.org). This distribution is compiled against libpcap 1.2.1. Installation: - tar -xzf bittwist-linux-2.0.tar.gz (you are most likely to have done this by now) - cd bittwist-linux-2.0 - make - sudo make install Binaries (bittwist, bittwiste) are installed in /usr/bin Manual pages (bittwist.1, bittwiste.1) are installed in /usr/share/man/man1 For more information, please visit Bit-Twist homepage at http://bittwist.sourceforge.net bittwist-linux-2.0/src/000755 000765 000024 00000000000 11744746762 016162 5ustar00addyyeowstaff000000 000000 bittwist-linux-2.0/._VERSION000444 000765 000024 00000000341 11744746762 016654 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect1{{0, 0}, {970, 698}}bittwist-linux-2.0/VERSION000444 000765 000024 00000000005 11744746762 016434 0ustar00addyyeowstaff000000 000000 2.0 bittwist-linux-2.0/src/._bittwist.c000444 000765 000024 00000000346 11744746762 020415 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect182{{0, 2653}, {964, 698}}bittwist-linux-2.0/src/bittwist.c000444 000765 000024 00000044363 11744746762 020207 0ustar00addyyeowstaff000000 000000 /* * bittwist - pcap based ethernet packet generator * Copyright (C) 2006 - 2012 Addy Yeow Chin Heng * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "bittwist.h" char *program_name; int32_t thiszone; /* offset from GMT to local time in seconds */ char ebuf[PCAP_ERRBUF_SIZE]; /* pcap error buffer */ /* options */ int vflag = 0; /* 1 - print timestamp, 2 - print timestamp and hex data */ int len = 0; /* packet length to send (-1 = captured, 0 = on wire, or positive value <= 65535) */ double speed = 1; /* multiplier for timestamp difference between 2 adjacent packets */ int linerate = 0; /* limit packet throughput at the specified Mbps (0 means no limit) */ int interval = 0; /* a constant interval in seconds (0 means actual interval will be used instead) */ int max_pkts = 0; /* send up to the specified number of packets */ pcap_t *pd = NULL; /* pcap descriptor */ u_char *pkt_data = NULL; /* packet data including the link-layer header */ /* stats */ static u_int pkts_sent = 0; static u_int bytes_sent = 0; static u_int failed = 0; struct timeval start = {0,0}; struct timeval end = {0,0}; int main(int argc, char **argv) { char *cp; int c; pcap_if_t *devptr; int i; int devnum; char *device = NULL; int loop = 1; thiszone = gmt2local(0); if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; /* process options */ while ((c = getopt(argc, argv, "dvi:s:l:c:m:r:p:h")) != -1) { switch (c) { case 'd': if (pcap_findalldevs(&devptr, ebuf) < 0) error("%s", ebuf); else { for (i = 0; devptr != 0; i++) { (void)printf("%d. %s", i + 1, devptr->name); if (devptr->description != NULL) (void)printf(" (%s)", devptr->description); (void)putchar('\n'); devptr = devptr->next; } } exit(EXIT_SUCCESS); case 'v': ++vflag; break; case 'i': if ((devnum = atoi(optarg)) != 0) { if (devnum < 0) error("invalid adapter index"); if (pcap_findalldevs(&devptr, ebuf) < 0) error("%s", ebuf); else { for (i = 0; i < devnum - 1; i++) { devptr = devptr->next; if (devptr == NULL) error("invalid adapter index"); } } device = devptr->name; } else { device = optarg; } break; case 's': len = strtol(optarg, NULL, 0); if (len != -1 && len != 0) { if (len < ETHER_HDR_LEN || len > ETHER_MAX_LEN) error("value for length must be between %d to %d", ETHER_HDR_LEN, ETHER_MAX_LEN); } break; case 'l': loop = strtol(optarg, NULL, 0); /* loop infinitely of loop <= 0 */ break; case 'c': max_pkts = strtol(optarg, NULL, 0); /* send all packets if max_pkts <= 0 */ break; case 'm': speed = strtod(optarg, NULL); if (speed > 0 && speed < SPEED_MIN) error("positive value for speed must be at least %f", SPEED_MIN); break; case 'r': linerate = strtol(optarg, NULL, 0); if (linerate < LINERATE_MIN || linerate > LINERATE_MAX) error("value for rate must be between %d to %d", LINERATE_MIN, LINERATE_MAX); break; case 'p': interval = strtol(optarg, NULL, 0); if (interval < 1 || interval > SLEEP_MAX) error("value for sleep must be between 1 to %d", SLEEP_MAX); break; case 'h': default: usage(); } } if (device == NULL) error("device not specified"); if (argv[optind] == NULL) error("trace file not specified"); notice("sending packets through %s", device); /* empty error buffer to grab warning message (if exist) from pcap_open_live() below */ *ebuf = '\0'; /* note that we are doing this for sending packets, not capture */ pd = pcap_open_live(device, ETHER_MAX_LEN, /* portion of packet to capture */ 1, /* promiscuous mode is on */ 1000, /* read timeout, in milliseconds */ ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) notice("%s", ebuf); /* warning message from pcap_open_live() above */ /* buffer to store data for each packet including its link-layer header, freed in cleanup() */ pkt_data = (u_char *)malloc(sizeof(u_char) * ETHER_MAX_LEN); if (pkt_data == NULL) error("malloc(): cannot allocate memory for pkt_data"); memset(pkt_data, 0, ETHER_MAX_LEN); /* set signal handler for SIGINT (Control-C) */ (void)signal(SIGINT, cleanup); if (gettimeofday(&start, NULL) == -1) notice("gettimeofday(): %s", strerror(errno)); if (loop > 0) { while (loop--) { for (i = optind; i < argc; i++) /* for each trace file */ send_packets(device, argv[i]); } } /* send infinitely if loop <= 0 until user Control-C */ else { while (1) { for (i = optind; i < argc; i++) send_packets(device, argv[i]); } } cleanup(0); /* NOTREACHED */ exit(EXIT_SUCCESS); } void send_packets(char *device, char *trace_file) { FILE *fp; /* file pointer to trace file */ struct pcap_file_header preamble; struct pcap_sf_pkthdr header; int pkt_len; /* packet length to send */ int ret; int i; struct pcap_timeval p_ts; struct timeval ts; struct timeval sleep = {0,0}; struct timeval cur_ts; struct timeval prev_ts = {0,0}; struct timespec nsleep; sigset_t block_sig; (void)sigemptyset(&block_sig); (void)sigaddset(&block_sig, SIGINT); notice("trace file: %s", trace_file); if ((fp = fopen(trace_file, "rb")) == NULL) error("fopen(): error reading %s", trace_file); /* preamble occupies the first 24 bytes of a trace file */ if (fread(&preamble, sizeof(preamble), 1, fp) == 0) error("fread(): error reading %s", trace_file); if (preamble.magic != PCAP_MAGIC) error("%s is not a valid pcap based trace file", trace_file); /* * loop through the remaining data by reading the packet header first. * packet header (16 bytes) = timestamp + length */ while ((ret = fread(&header, sizeof(header), 1, fp))) { if (ret == 0) error("fread(): error reading %s", trace_file); /* copy timestamp for current packet */ memcpy(&p_ts, &header.ts, sizeof(p_ts)); cur_ts.tv_sec = p_ts.tv_sec; cur_ts.tv_usec = p_ts.tv_usec; if (len < 0) /* captured length */ pkt_len = header.caplen; else if (len == 0) /* actual length */ pkt_len = header.len; else /* user specified length */ pkt_len = len; if (timerisset(&prev_ts)) { /* pass first packet */ if (speed != 0) { if (interval > 0) { /* user specified interval is in seconds only */ sleep.tv_sec = interval; if (speed != 1) timer_div(&sleep, speed); /* speed factor */ } else { /* grab captured interval */ timersub(&cur_ts, &prev_ts, &sleep); if (speed != 1) { if (sleep.tv_sec > SLEEP_MAX) /* to avoid integer overflow in timer_div() */ notice("ignoring speed due to large interval"); else timer_div(&sleep, speed); } } if (linerate > 0) { i = linerate_interval(pkt_len); /* check if we exceed line rate */ if ((sleep.tv_sec == 0) && (sleep.tv_usec < i)) sleep.tv_usec = i; /* exceeded -> adjust */ } } else { /* send immediately */ if (linerate > 0) sleep.tv_usec = linerate_interval(pkt_len); } if (timerisset(&sleep)) { /* notice("sleep %d seconds %d microseconds", sleep.tv_sec, sleep.tv_usec); */ TIMEVAL_TO_TIMESPEC(&sleep, &nsleep); if (nanosleep(&nsleep, NULL) == -1) /* create the artificial slack time */ notice("nanosleep(): %s", strerror(errno)); } } for (i = 0; i < pkt_len; i++) { /* copy captured packet data starting from link-layer header */ if (i < header.caplen) { if ((ret = fgetc(fp)) == EOF) error("fgetc(): error reading %s", trace_file); pkt_data[i] = ret; } else /* pad trailing bytes with zeros */ pkt_data[i] = PKT_PAD; } /* move file pointer to the end of this packet data */ if (i < header.caplen) { if (fseek(fp, header.caplen - pkt_len, SEEK_CUR) != 0) error("fseek(): error reading %s", trace_file); } (void)sigprocmask(SIG_BLOCK, &block_sig, NULL); /* hold SIGINT */ /* finish the injection and verbose output before we give way to SIGINT */ if (pcap_sendpacket(pd, pkt_data, pkt_len) == -1) { notice("%s", pcap_geterr(pd)); ++failed; } else { ++pkts_sent; bytes_sent += pkt_len; /* copy timestamp for previous packet sent */ memcpy(&prev_ts, &cur_ts, sizeof(struct timeval)); /* verbose output */ if (vflag) { if (gettimeofday(&ts, NULL) == -1) notice("gettimeofday(): %s", strerror(errno)); else ts_print(&ts); (void)printf("#%d (%d bytes)", pkts_sent, pkt_len); if (vflag > 1) hex_print(pkt_data, pkt_len); else putchar('\n'); fflush(stdout); } } (void)sigprocmask(SIG_UNBLOCK, &block_sig, NULL); /* release SIGINT */ if ((max_pkts > 0) && (pkts_sent >= max_pkts)) cleanup(0); } /* end while */ (void)fclose(fp); } /* * Calculate line rate interval in microseconds for the given * pkt_len (bytes) and linerate (Mbps) * * to send packets at line rate with assumption of link speed at X: * interval = ((packet length * bits per byte) / (X to bits)) * 1000000 * +---------------------------------------------------+ * | | 10Mbps | 100Mbps | 1000Mbps | * +---------------------------------------------------+ * | 14 bytes | 11 usecs. | 1 usecs. | 0 usecs. | * | 1514 bytes | 1155 usecs. | 116 usecs. | 12 usecs. | * +---------------------------------------------------+ */ int linerate_interval(int pkt_len) { return ROUND(((float)pkt_len * 8) / (linerate * 1024 * 1024) * 1000000); } void info(void) { struct timeval elapsed; float seconds; if (gettimeofday(&end, NULL) == -1) notice("gettimeofday(): %s", strerror(errno)); timersub(&end, &start, &elapsed); seconds = elapsed.tv_sec + (float)elapsed.tv_usec / 1000000; (void)putchar('\n'); notice("%u packets (%u bytes) sent", pkts_sent, bytes_sent); if (failed) notice("%u write attempts failed", failed); notice("Elapsed time = %f seconds", seconds); } void cleanup(int signum) { free(pkt_data); pkt_data = NULL; if (signum == -1) exit(EXIT_FAILURE); else info(); exit(EXIT_SUCCESS); } void timer_div(struct timeval *tvp, double speed) { double interval; interval = (tvp->tv_sec * 1000000 + tvp->tv_usec) / speed; tvp->tv_sec = interval / 1000000; tvp->tv_usec = ROUND(interval) - ((double)tvp->tv_sec * 1000000); } /* * Reference: tcpdump's gmt2local.c * * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * */ int32_t gmt2local(time_t t) { register int dt, dir; register struct tm *gmt, *loc; struct tm sgmt; if (t == 0) t = time(NULL); gmt = &sgmt; *gmt = *gmtime(&t); loc = localtime(&t); dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + (loc->tm_min - gmt->tm_min) * 60; /* * If the year or julian day is different, we span 00:00 GMT * and must add or subtract a day. Check the year first to * avoid problems when the julian day wraps. */ dir = loc->tm_year - gmt->tm_year; if (dir == 0) dir = loc->tm_yday - gmt->tm_yday; dt += dir * 24 * 60 * 60; return (dt); } /* * Reference: tcpdump's print-ascii.c * * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * */ void hex_print(register const u_char *cp, register u_int length) { register u_int i, s; register int nshorts; register u_int oset = 0; nshorts = (u_int)length / sizeof(u_short); i = 0; while (--nshorts >= 0) { if ((i++ % 8) == 0) { (void)printf("\n\t0x%04x: ", oset); oset += 16; } s = *cp++; (void)printf(" %02x%02x", s, *cp++); } if (length & 1) { if ((i % 8) == 0) (void)printf("\n\t0x%04x: ", oset); (void)printf(" %02x", *cp); } (void)putchar('\n'); } /* * Reference: tcpdump's util.c * * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * */ void ts_print(register const struct timeval *tvp) { register int s; s = (tvp->tv_sec + thiszone) % 86400; (void)printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec); } /* * Reference: tcpdump's util.c * * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * */ void notice(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } /* * Reference: tcpdump's util.c * * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * */ void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } cleanup(-1); } void usage(void) { (void)fprintf(stderr, "%s version %s\n" "%s\n" "Usage: %s [-d] [-v] [-i interface] [-s length] [-l loop] [-c count]\n" " [-m speed] [-r rate] [-p sleep] [-h] pcap-file(s)\n" "\nOptions:\n" " -d Print a list of network interfaces available.\n" " -v Print timestamp for each packet.\n" " -vv Print timestamp and hex data for each packet.\n" " -i interface Send 'pcap-file(s)' out onto the network through 'interface'.\n" " -s length Packet length to send. Set 'length' to:\n" " 0 to send the actual packet length. This is the default.\n" " -1 to send the captured length.\n" " or any other value from %d to %d.\n" " -l loop Send 'pcap-file(s)' out onto the network for 'loop' times.\n" " Set 'loop' to 0 to send 'pcap-file(s)' until stopped.\n" " To stop, type Control-C.\n" " -c count Send up to 'count' packets.\n" " Default is to send all packets from 'pcap-file(s)'.\n" " -m speed Set interval multiplier to 'speed'.\n" " Set 'speed' to 0 or less to send the next packet immediately.\n" " Minimum positive value for 'speed' is %f.\n" " -r rate Limit the sending to 'rate' Mbps.\n" " Value for 'rate' must be between %d to %d.\n" " This option is meant to limit the maximum packet throughput.\n" " If you want to send packets at line rate of 100Mbps,\n" " try -m 0 -r 100\n" " -p sleep Set interval to 'sleep' (in seconds), ignoring the actual\n" " interval.\n" " Value for 'sleep' must be between 1 to %d.\n" " -h Print version information and usage.\n", program_name, BITTWIST_VERSION, pcap_lib_version(), program_name, ETHER_HDR_LEN, ETHER_MAX_LEN, SPEED_MIN, LINERATE_MIN, LINERATE_MAX, SLEEP_MAX); exit(EXIT_SUCCESS); } bittwist-linux-2.0/src/._bittwist.h000444 000765 000024 00000000342 11744746762 020416 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect39{{0, 0}, {970, 698}}bittwist-linux-2.0/src/bittwist.h000444 000765 000024 00000002474 11744746762 020211 0ustar00addyyeowstaff000000 000000 /* * bittwist - pcap based ethernet packet generator * Copyright (C) 2006 - 2012 Addy Yeow Chin Heng * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _BITTWIST_H_ #define _BITTWIST_H_ #include "def.h" void send_packets(char *device, char *trace_file); int linerate_interval(int pkt_len); void info(void); void cleanup(int signum); void timer_div(struct timeval *tvp, double speed); int32_t gmt2local(time_t t); void hex_print(register const u_char *cp, register u_int length); void ts_print(register const struct timeval *tvp); void notice(const char *fmt, ...); void error(const char *fmt, ...); void usage(void); #endif /* !_BITTWIST_H_ */ bittwist-linux-2.0/src/._bittwiste.c000444 000765 000024 00000000424 11744746762 020557 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTR$ com.macromates.bookmarkscom.macromates.selectionRangecom.macromates.visibleRect( '722' )685{{0, 9961}, {1209, 720}}bittwist-linux-2.0/src/bittwiste.c000444 000765 000024 00000272312 11744746762 020351 0ustar00addyyeowstaff000000 000000 /* * bittwiste - pcap capture file editor * Copyright (C) 2006 - 2012 Addy Yeow Chin Heng * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "bittwiste.h" char *program_name; /* general options */ int header_opt = 0; /* specifies which header to edit */ int layer_opt = 0; /* copy up to the specified layer only */ int start_opt = 0; /* copy the specified range of packets only */ int end_opt = 0; int start_oset_opt = 0; /* delete the specified byte offset */ int end_oset_opt = 0; time_t start_sec_opt = 0; /* copy packets within the specified timeframe only */ time_t end_sec_opt = 0; int csum_opt = 1; /* set to 0 to disable checksum correction */ u_char *payload_opt = NULL; /* payload in hex digits *NOTFREED* */ u_short payload_len_opt = 0; /* length of payload in bytes */ int linktype_opt = -1; /* pcap preamble link type field, -1 -> no override */ /* header specific options *NOTFREED* */ struct ethopt *ethopt; /* Ethernet options */ struct arpopt *arpopt; /* ARP options */ struct ipopt *ipopt; /* IP options */ struct icmpopt *icmpopt; /* ICMP options */ struct tcpopt *tcpopt; /* TCP options */ struct udpopt *udpopt; /* UDP options */ /* stats */ static u_int pkts = 0; static u_int bytes = 0; int main(int argc, char **argv) { char *cp; int c, i; char *str = NULL; char *infile = NULL; char *outfile = NULL; struct tm *tm = NULL; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; /* process general options */ while ((c = getopt(argc, argv, "I:O:L:X:CM:D:R:S:T:h")) != -1) { switch (c) { case 'I': infile = optarg; break; case 'O': outfile = optarg; break; case 'L': layer_opt = strtol(optarg, NULL, 0); /* * 2 - Ethernet * 3 - ARP, IP * 4 - ICMP, TCP, UDP */ if (layer_opt < 2 || layer_opt > 4) error("layer is out of range"); break; case 'X': /* ignored if option -L and -T are not specified */ c = strlen(optarg); if (c > (PAYLOAD_MAX * 2) || (c % 2) != 0) error("invalid payload specification"); for (i = 0; i < c; i++) { if (!isxdigit(optarg[i])) error("invalid payload specification"); } payload_len_opt = (u_short)c / 2; /* possible resizing in editing functions */ payload_opt = (u_char *)malloc(sizeof(u_char) * payload_len_opt); if (payload_opt == NULL) error("malloc(): cannot allocate memory for payload_opt"); /* make a byte of data from every 2 characters of optarg */ for (i = 0; i < payload_len_opt; i++) { /* ugly - let me know if there is a better way to achieve this */ sscanf(optarg, "%02x", &payload_opt[i]); *optarg++; *optarg++; /* move pass 2 characters */ } break; case 'C': csum_opt = 0; /* DISABLE checksum correction */ break; case 'M': linktype_opt = strtol(optarg, NULL, 0); /* * 1 - Ethernet * 9 - PPP * 12 - Raw IP * 51 - PPPoE * 105 - IEEE 802.11 wireless * 117 - OpenBSD pflog * 118 - Cisco IOS * 119 - 802.11 with Prism header */ if (linktype_opt < 0 || linktype_opt > UCHAR_MAX) error("linktype is out of range"); break; case 'D': /* -D 15-18, delete from byte 15th through byte 18th (inclusive), starting from link-layer header */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, "-")) == NULL) error("invalid offset specification"); start_oset_opt = strtol(cp, NULL, 0); if ((cp = (char *)strtok(NULL, "-")) == NULL) end_oset_opt = start_oset_opt; /* delete a single byte, e.g. -D 15 */ else end_oset_opt = strtol(cp, NULL, 0); free(str); str = NULL; if (start_oset_opt == 0 || end_oset_opt == 0 || (start_oset_opt > end_oset_opt)) error("invalid offset specification"); break; case 'R': /* range: 5-21 */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, "-")) == NULL) error("invalid range specification"); start_opt = strtol(cp, NULL, 0); if ((cp = (char *)strtok(NULL, "-")) == NULL) end_opt = start_opt; /* only one packet */ else end_opt = strtol(cp, NULL, 0); free(str); str = NULL; if (start_opt == 0 || end_opt == 0 || (start_opt > end_opt)) error("invalid range specification"); break; case 'S': /* * time frame with one-second resolution: -S 22/10/2006,21:47:35-24/10/2006,13:16:05 * format: -S DD/MM/YYYY,HH:MM:SS-DD/MM/YYYY,HH:MM:SS * note that -S 22/10/2006-24/10/2006 is equivalent to -S 22/10/2006,00:00:00-24/10/2006,00:00:00 */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, "-")) == NULL) error("invalid timeframe specification"); tm = (struct tm *)malloc(sizeof(struct tm)); if (tm == NULL) error("malloc(): cannot allocate memory for tm"); if (!strptime(cp, "%d/%m/%Y,%T", tm)) error("invalid timeframe specification"); start_sec_opt = mktime(tm); if ((cp = (char *)strtok(NULL, "-")) == NULL) end_sec_opt = start_sec_opt; /* only the packets within the one-second resolution */ else { if (!strptime(cp, "%d/%m/%Y,%T", tm)) error("invalid timeframe specification"); } end_sec_opt = mktime(tm); free(tm); tm = NULL; free(str); str = NULL; if (start_sec_opt > end_sec_opt) error("invalid timeframe specification"); break; case 'T': if (strcasecmp(optarg, "eth") == 0) header_opt = ETH; else if (strcasecmp(optarg, "arp") == 0) header_opt = ARP; else if (strcasecmp(optarg, "ip") == 0) header_opt = IP; else if (strcasecmp(optarg, "icmp") == 0) header_opt = ICMP; else if (strcasecmp(optarg, "tcp") == 0) header_opt = TCP; else if (strcasecmp(optarg, "udp") == 0) header_opt = UDP; else error("invalid header specification"); /* process header specific options */ parse_header_options(argc, argv); break; case 'h': default: usage(); } } if (infile == NULL) error("input file not specified"); if (outfile == NULL) error("output file not specified"); if (strcmp(infile, outfile) == 0) error("invalid outfile specification"); parse_trace(infile, outfile); info(); exit(EXIT_SUCCESS); } void parse_header_options(int argc, char **argv) { char *cp; int c; double d; /* validate and store TCP sequence and acknowledgment number */ struct ether_addr *ether_addr; struct in_addr in_addr; char *str = NULL; if (header_opt == ETH) { ethopt = (struct ethopt *)malloc(sizeof(struct ethopt)); if (ethopt == NULL) error("malloc(): cannot allocate memory for ethopt"); memset(ethopt, 0, sizeof(struct ethopt)); while ((c = getopt(argc, argv, "d:s:t:")) != -1) { switch (c) { case 'd': /* destination MAC */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid destination MAC address"); if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid destination MAC address"); memcpy(ethopt->ether_old_dhost, ether_addr, sizeof(struct ether_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all destination MAC */ ethopt->ether_dhost_flag = 1; else { /* overwrite matching destination MAC only */ ethopt->ether_dhost_flag = 2; if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid destination MAC address"); memcpy(ethopt->ether_new_dhost, ether_addr, sizeof(struct ether_addr)); } free(str); str = NULL; break; case 's': /* source MAC */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid source MAC address"); if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid source MAC address"); memcpy(ethopt->ether_old_shost, ether_addr, sizeof(struct ether_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all source MAC */ ethopt->ether_shost_flag = 1; else { /* overwrite matching source MAC only */ ethopt->ether_shost_flag = 2; if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid source MAC address"); memcpy(ethopt->ether_new_shost, ether_addr, sizeof(struct ether_addr)); } free(str); str = NULL; break; case 't': /* type */ if (strcasecmp(optarg, "ip") == 0) ethopt->ether_type = ETHERTYPE_IP; else if (strcasecmp(optarg, "arp") == 0) ethopt->ether_type = ETHERTYPE_ARP; else error("invalid Ethernet type specification"); break; default: usage(); } } } else if (header_opt == ARP) { arpopt = (struct arpopt *)malloc(sizeof(struct arpopt)); if (arpopt == NULL) error("malloc(): cannot allocate memory for arpopt"); memset(arpopt, 0, sizeof(struct arpopt)); while ((c = getopt(argc, argv, "o:s:p:t:q:")) != -1) { switch (c) { case 'o': /* opcode */ c = strtol(optarg, NULL, 0); if (c < 0 || c > USHRT_MAX) error("ARP opcode is out of range"); arpopt->ar_op = (u_short)c; arpopt->ar_op_flag = 1; break; case 's': /* sender MAC */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid sender MAC address"); if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid sender MAC address"); memcpy(arpopt->ar_old_sha, ether_addr, sizeof(struct ether_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all sender MAC */ arpopt->ar_sha_flag = 1; else { /* overwrite matching sender MAC only */ arpopt->ar_sha_flag = 2; if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid sender MAC address"); memcpy(arpopt->ar_new_sha, ether_addr, sizeof(struct ether_addr)); } free(str); str = NULL; break; case 'p': /* sender IP */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid sender IP address"); if (inet_aton(cp, &in_addr) == 0) error("invalid sender IP address"); memcpy(&arpopt->ar_old_spa, &in_addr, sizeof(struct in_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all sender IP address */ arpopt->ar_spa_flag = 1; else { /* overwrite matching IP address only */ arpopt->ar_spa_flag = 2; if (inet_aton(cp, &in_addr) == 0) error("invalid sender IP address"); memcpy(&arpopt->ar_new_spa, &in_addr, sizeof(struct in_addr)); } free(str); str = NULL; break; case 't': /* target MAC */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid target MAC address"); if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid target MAC address"); memcpy(arpopt->ar_old_tha, ether_addr, sizeof(struct ether_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all target MAC */ arpopt->ar_tha_flag = 1; else { /* overwrite matching target MAC only */ arpopt->ar_tha_flag = 2; if ((ether_addr = (struct ether_addr *)ether_aton(cp)) == NULL) error("invalid target MAC address"); memcpy(arpopt->ar_new_tha, ether_addr, sizeof(struct ether_addr)); } free(str); str = NULL; break; case 'q': /* target IP */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid target IP address"); if (inet_aton(cp, &in_addr) == 0) error("invalid target IP address"); memcpy(&arpopt->ar_old_tpa, &in_addr, sizeof(struct in_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all target IP address */ arpopt->ar_tpa_flag = 1; else { /* overwrite matching IP address only */ arpopt->ar_tpa_flag = 2; if (inet_aton(cp, &in_addr) == 0) error("invalid target IP address"); memcpy(&arpopt->ar_new_tpa, &in_addr, sizeof(struct in_addr)); } free(str); str = NULL; break; default: usage(); } } } else if (header_opt == IP) { ipopt = (struct ipopt *)malloc(sizeof(struct ipopt)); if (ipopt == NULL) error("malloc(): cannot allocate memory for ipopt"); memset(ipopt, 0, sizeof(struct ipopt)); while ((c = getopt(argc, argv, "i:f:o:t:p:s:d:")) != -1) { switch (c) { case 'i': /* identification */ c = strtol(optarg, NULL, 0); if (c < 0 || c > USHRT_MAX) error("IP identification is out of range"); ipopt->ip_id = (u_short)c; ipopt->ip_id_flag = 1; break; case 'f': /* flags */ for (c = 0; optarg[c]; c++) optarg[c] = tolower(optarg[c]); if (strchr(optarg, 'r') != NULL) /* reserved bit */ ipopt->ip_flag_r = 1; if (strchr(optarg, 'd') != NULL) /* don't fragment bit */ ipopt->ip_flag_d = 1; if (strchr(optarg, 'm') != NULL) /* more fragment bit */ ipopt->ip_flag_m = 1; if (strchr(optarg, '-') != NULL) { /* remove flags */ ipopt->ip_flag_r = 0; ipopt->ip_flag_d = 0; ipopt->ip_flag_m = 0; } ipopt->ip_flags_flag = 1; break; case 'o': /* fragment offset */ c = strtol(optarg, NULL, 0); if (c < 0 || c > IP_FO_MAX) error("IP fragment offset is out of range"); ipopt->ip_fo = (u_short)c; ipopt->ip_fo_flag = 1; break; case 't': /* time to live */ c = strtol(optarg, NULL, 0); if (c < 0 || c > UCHAR_MAX) error("IP time to live is out of range"); ipopt->ip_ttl = (u_char)c; ipopt->ip_ttl_flag = 1; break; case 'p': /* protocol */ c = strtol(optarg, NULL, 0); if (c < 0 || c > UCHAR_MAX) error("IP protocol is out of range"); ipopt->ip_p = (u_char)c; ipopt->ip_p_flag = 1; break; case 's': /* source IP */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid source IP address"); if (inet_aton(cp, &in_addr) == 0) error("invalid source IP address"); memcpy(&ipopt->ip_old_src, &in_addr, sizeof(struct in_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all source IP address */ ipopt->ip_src_flag = 1; else { /* overwrite matching IP address only */ ipopt->ip_src_flag = 2; if (inet_aton(cp, &in_addr) == 0) error("invalid source IP address"); memcpy(&ipopt->ip_new_src, &in_addr, sizeof(struct in_addr)); } free(str); str = NULL; break; case 'd': /* destination IP */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid destination IP address"); if (inet_aton(cp, &in_addr) == 0) error("invalid destination IP address"); memcpy(&ipopt->ip_old_dst, &in_addr, sizeof(struct in_addr)); if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all destination IP address */ ipopt->ip_dst_flag = 1; else { /* overwrite matching IP address only */ ipopt->ip_dst_flag = 2; if (inet_aton(cp, &in_addr) == 0) error("invalid destination IP address"); memcpy(&ipopt->ip_new_dst, &in_addr, sizeof(struct in_addr)); } free(str); str = NULL; break; default: usage(); } } } else if (header_opt == ICMP) { icmpopt = (struct icmpopt *)malloc(sizeof(struct icmpopt)); if (icmpopt == NULL) error("malloc(): cannot allocate memory for icmpopt"); memset(icmpopt, 0, sizeof(struct icmpopt)); while ((c = getopt(argc, argv, "t:c:")) != -1) { switch (c) { case 't': /* type */ c = strtol(optarg, NULL, 0); if (c < 0 || c > UCHAR_MAX) error("ICMP type is out of range"); icmpopt->icmp_type = (u_char)c; icmpopt->icmp_type_flag = 1; break; case 'c': /* code */ c = strtol(optarg, NULL, 0); if (c < 0 || c > UCHAR_MAX) error("ICMP code is out of range"); icmpopt->icmp_code = (u_char)c; icmpopt->icmp_code_flag = 1; break; default: usage(); } } } else if (header_opt == TCP) { tcpopt = (struct tcpopt *)malloc(sizeof(struct tcpopt)); if (tcpopt == NULL) error("malloc(): cannot allocate memory for tcpopt"); memset(tcpopt, 0, sizeof(struct tcpopt)); while ((c = getopt(argc, argv, "s:d:q:a:f:w:u:")) != -1) { switch (c) { case 's': /* source port */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid TCP source port specification"); c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("TCP source port is out of range"); tcpopt->th_old_sport = (u_short)c; if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all source port */ tcpopt->th_sport_flag = 1; else { /* overwrite matching port only */ c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("TCP source port is out of range"); tcpopt->th_new_sport = (u_short)c; tcpopt->th_sport_flag = 2; } free(str); str = NULL; break; case 'd': /* destination port */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid TCP destination port specification"); c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("TCP destination port is out of range"); tcpopt->th_old_dport = (u_short)c; if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all destination port */ tcpopt->th_dport_flag = 1; else { /* overwrite matching port only */ c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("TCP destination port is out of range"); tcpopt->th_new_dport = (u_short)c; tcpopt->th_dport_flag = 2; } free(str); str = NULL; break; case 'q': /* sequence number */ d = strtod(optarg, NULL); if (d < 0 || d > UINT_MAX) error("TCP sequence number is out of range"); tcpopt->th_seq = (tcp_seq)d; tcpopt->th_seq_flag = 1; break; case 'a': /* acknowledgment number */ d = strtod(optarg, NULL); if (d < 0 || d > UINT_MAX) error("TCP acknowledgment number is out of range"); tcpopt->th_ack = (tcp_seq)d; tcpopt->th_ack_flag = 1; break; case 'f': /* flags */ for (c = 0; optarg[c]; c++) optarg[c] = tolower(optarg[c]); if (strchr(optarg, 'u') != NULL) /* URG */ tcpopt->th_flag_u = 1; if (strchr(optarg, 'a') != NULL) /* ACK */ tcpopt->th_flag_a = 1; if (strchr(optarg, 'p') != NULL) /* PSH */ tcpopt->th_flag_p = 1; if (strchr(optarg, 'r') != NULL) /* RST */ tcpopt->th_flag_r = 1; if (strchr(optarg, 's') != NULL) /* SYN */ tcpopt->th_flag_s = 1; if (strchr(optarg, 'f') != NULL) /* FIN */ tcpopt->th_flag_f = 1; if (strchr(optarg, '-') != NULL) { /* remove flags */ tcpopt->th_flag_u = 0; tcpopt->th_flag_a = 0; tcpopt->th_flag_p = 0; tcpopt->th_flag_r = 0; tcpopt->th_flag_s = 0; tcpopt->th_flag_f = 0; } tcpopt->th_flags_flag = 1; break; case 'w': /* window size */ c = strtol(optarg, NULL, 0); if (c < 0 || c > USHRT_MAX) error("TCP window size is out of range"); tcpopt->th_win = (u_short)c; tcpopt->th_win_flag = 1; break; case 'u': /* urgent pointer */ c = strtol(optarg, NULL, 0); if (c < 0 || c > USHRT_MAX) error("TCP urgent pointer is out of range"); tcpopt->th_urp = (u_short)c; tcpopt->th_urp_flag = 1; break; default: usage(); } } } else if (header_opt == UDP) { udpopt = (struct udpopt *)malloc(sizeof(struct udpopt)); if (udpopt == NULL) error("malloc(): cannot allocate memory for udpopt"); memset(udpopt, 0, sizeof(struct udpopt)); while ((c = getopt(argc, argv, "s:d:")) != -1) { switch (c) { case 's': /* source port */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid UDP source port specification"); c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("UDP source port is out of range"); udpopt->uh_old_sport = (u_short)c; if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all source port */ udpopt->uh_sport_flag = 1; else { /* overwrite matching port only */ c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("UDP source port is out of range"); udpopt->uh_new_sport = (u_short)c; udpopt->uh_sport_flag = 2; } free(str); str = NULL; break; case 'd': /* destination port */ str = strdup(optarg); if (str == NULL) error("strdup(): cannot allocate memory for str"); if ((cp = (char *)strtok(str, ",")) == NULL) error("invalid UDP destination port specification"); c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("UDP destination port is out of range"); udpopt->uh_old_dport = (u_short)c; if ((cp = (char *)strtok(NULL, ",")) == NULL) /* overwrite all destination port */ udpopt->uh_dport_flag = 1; else { /* overwrite matching port only */ c = strtol(cp, NULL, 0); if (c < 0 || c > USHRT_MAX) error("UDP destination port is out of range"); udpopt->uh_new_dport = (u_short)c; udpopt->uh_dport_flag = 2; } free(str); str = NULL; break; default: usage(); } } } /* NOTREACHED */ } void parse_trace(char *infile, char *outfile) { FILE *fp; /* file pointer to trace file */ FILE *fp_outfile; /* file pointer to modified trace file */ struct pcap_file_header preamble; struct pcap_sf_pkthdr *header; u_char *pkt_data; /* original packet data starting from link-layer header */ u_char *new_pkt_data; /* modified pkt_data inclusive of pcap generic header is written here */ int ret; int i; int pkt_index; /* to check if we are within start_opt and end_opt for range specification */ int len; /* original header->caplen */ int end_o; /* aligned end_oset_opt */ notice("input file: %s", infile); if ((fp = fopen(infile, "rb")) == NULL) error("fopen(): error reading %s", infile); notice("output file: %s", outfile); if ((fp_outfile = fopen(outfile, "wb")) == NULL) error("fopen(): error creating %s", outfile); /* preamble occupies the first 24 bytes of a trace file */ if (fread(&preamble, sizeof(preamble), 1, fp) == 0) error("fread(): error reading %s", infile); if (preamble.magic != PCAP_MAGIC) error("%s is not a valid pcap based trace file", infile); /* override pcap preamble link type with user specified link type */ if (linktype_opt >= 0) preamble.linktype = linktype_opt; /* write preamble to modified trace file */ if (fwrite(&preamble, sizeof(preamble), 1, fp_outfile) != 1) error("fwrite(): error writing %s", outfile); /* pcap generic header */ header = (struct pcap_sf_pkthdr *)malloc(PCAP_HDR_LEN); if (header == NULL) error("malloc(): cannot allocate memory for header"); /* * loop through the remaining data by reading the pcap generic header first. * pcap generic header (16 bytes) = secs. + usecs. + caplen + len */ pkt_index = 1; while ((ret = fread(header, PCAP_HDR_LEN, 1, fp))) { if (ret == 0) error("fread(): error reading %s", infile); /* original packet data starting from link-layer header */ pkt_data = (u_char *)malloc(sizeof(u_char) * header->caplen); if (pkt_data == NULL) error("malloc(): cannot allocate memory for pkt_data"); memset(pkt_data, 0, header->caplen); /* copy captured packet data starting from link-layer header into pkt_data */ if (fread(pkt_data, header->caplen, 1, fp) == 0) error("fread(): error reading %s", infile); if ((pkt_index >= start_opt && pkt_index <= end_opt) || (start_opt == 0 && end_opt == 0)) { if ((header->ts.tv_sec >= start_sec_opt && header->ts.tv_sec <= end_sec_opt) || (start_sec_opt == 0 && end_sec_opt == 0)) { /* byte deletion mode, no content modification (parse_ethernet(), etc.) */ if (start_oset_opt != 0 && end_oset_opt != 0 && start_oset_opt <= header->caplen) { /* align end_oset_opt so that it does not go beyond header->caplen */ if (end_oset_opt > header->caplen) end_o = header->caplen; else end_o = end_oset_opt; len = header->caplen; /* original capture length (before byte deletion) */ header->caplen = header->len = len - ((end_o - start_oset_opt) + 1); /* write pcap generic header */ if (fwrite(header, PCAP_HDR_LEN, 1, fp_outfile) != 1) error("fwrite(): error writing %s", outfile); for (i = 0; i < start_oset_opt - 1; i++) { if (fputc(pkt_data[i], fp_outfile) == EOF) error("fputc(): error writing %s", outfile); } for (i = end_o; i < len; i++) { if (fputc(pkt_data[i], fp_outfile) == EOF) error("fputc(): error writing %s", outfile); } } else { /* modified pkt_data inclusive of pcap generic header */ new_pkt_data = (u_char *)malloc(sizeof(u_char) * (PCAP_HDR_LEN + ETHER_MAX_LEN)); /* 16 + 1514 bytes */ if (new_pkt_data == NULL) error("malloc(): cannot allocate memory for new_pkt_data"); memset(new_pkt_data, 0, PCAP_HDR_LEN + ETHER_MAX_LEN); /* * encapsulated editing function starting from link-layer header. * ret = bytes written in new_pkt_data */ ret = parse_ethernet(pkt_data, new_pkt_data, header) + PCAP_HDR_LEN; /* copy pcap generic header into new_pkt_data */ memcpy(new_pkt_data, header, PCAP_HDR_LEN); /* no changes */ if (ret == PCAP_HDR_LEN) { /* parse_ethernet() returns 0 */ /* write pcap generic header */ if (fwrite(header, PCAP_HDR_LEN, 1, fp_outfile) != 1) error("fwrite(): error writing %s", outfile); if (fwrite(pkt_data, header->caplen, 1, fp_outfile) != 1) error("fwrite(): error writing %s", outfile); } /* overwrite the entire pkt_data with new_pkt_data */ else if (ret == header->caplen + PCAP_HDR_LEN) { if (fwrite(new_pkt_data, ret, 1, fp_outfile) != 1) error("fwrite(): error writing %s", outfile); } else { if (fwrite(new_pkt_data, ret, 1, fp_outfile) != 1) error("fwrite(): error writing %s", outfile); /* write remaining bytes from pkt_data */ for (i = ret - PCAP_HDR_LEN; i < header->caplen; i++) { if (fputc(pkt_data[i], fp_outfile) == EOF) error("fputc(): error writing %s", outfile); } } free(new_pkt_data); new_pkt_data = NULL; } ++pkts; /* packets written */ bytes += header->caplen; /* bytes written */ } } free(pkt_data); pkt_data = NULL; ++pkt_index; } /* end while */ free(header); header = NULL; (void)fclose(fp); (void)fclose(fp_outfile); } u_short parse_ethernet(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header) { /* * Ethernet header (14 bytes) * 1. destination MAC (6 bytes) * 2. source MAC (6 bytes) * 3. type (2 bytes) */ struct ether_header *eth_hdr; u_short ether_type; int i; /* do nothing if Ethernet header is truncated */ if (header->caplen < ETHER_HDR_LEN) return (0); eth_hdr = (struct ether_header *)malloc(ETHER_HDR_LEN); if (eth_hdr == NULL) error("malloc(): cannot allocate memory for eth_hdr"); /* copy Ethernet header from pkt_data into eth_hdr */ memcpy(eth_hdr, pkt_data, ETHER_HDR_LEN); /* we are editing Ethernet header */ if (header_opt == ETH) { /* overwrite destination MAC */ if (ethopt->ether_dhost_flag == 1) /* overwrite all destination MAC */ memcpy(eth_hdr->ether_dhost, ethopt->ether_old_dhost, ETHER_ADDR_LEN); else if (ethopt->ether_dhost_flag == 2 && /* overwrite matching destination MAC only */ memcmp(eth_hdr->ether_dhost, ethopt->ether_old_dhost, ETHER_ADDR_LEN) == 0) memcpy(eth_hdr->ether_dhost, ethopt->ether_new_dhost, ETHER_ADDR_LEN); /* overwrite source MAC */ if (ethopt->ether_shost_flag == 1) /* overwrite all source MAC */ memcpy(eth_hdr->ether_shost, ethopt->ether_old_shost, ETHER_ADDR_LEN); else if (ethopt->ether_shost_flag == 2 && /* overwrite matching source MAC only */ memcmp(eth_hdr->ether_shost, ethopt->ether_old_shost, ETHER_ADDR_LEN) == 0) memcpy(eth_hdr->ether_shost, ethopt->ether_new_shost, ETHER_ADDR_LEN); /* overwrite Ethernet type */ if (ethopt->ether_type != 0) eth_hdr->ether_type = htons(ethopt->ether_type); } ether_type = ntohs(eth_hdr->ether_type); /* * go pass pcap generic header in new_pkt_data then copy eth_hdr into * new_pkt_data and reset pointer to the beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, eth_hdr, ETHER_HDR_LEN); free(eth_hdr); eth_hdr = NULL; i = 0; while (i++ < PCAP_HDR_LEN) *new_pkt_data--; /* copy up to layer 2 only, discard remaining data */ if (layer_opt == 2) { /* we are editing Ethernet header and we have payload */ if (header_opt == ETH && payload_len_opt > 0) { /* truncate payload if it is too large */ if ((payload_len_opt + ETHER_HDR_LEN) > ETHER_MAX_LEN) payload_len_opt -= (payload_len_opt + ETHER_HDR_LEN) - ETHER_MAX_LEN; /* * go pass pcap generic header and Ethernet header in new_pkt_data * then copy payload_opt into new_pkt_data and reset pointer to the * beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, payload_opt, payload_len_opt); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN) *new_pkt_data--; header->caplen = header->len = ETHER_HDR_LEN + payload_len_opt; } else header->caplen = header->len = ETHER_HDR_LEN; return (header->caplen); } /* parse ARP datagram */ if (ether_type == ETHERTYPE_ARP) return (parse_arp(pkt_data, new_pkt_data, header)); /* parse IP datagram */ else if (ether_type == ETHERTYPE_IP) return (parse_ip(pkt_data, new_pkt_data, header, NULL, 0)); /* no further editing support for other datagram */ else return (ETHER_HDR_LEN); } u_short parse_arp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header) { /* * Ethernet ARP header (28 bytes) * 1. hardware type (2 bytes) * 2. protocol type (2 bytes) * 3. hardware address length (1 byte) * 4. protocol address length (1 byte) * 5. opcode (2 bytes) * 6. sender hardware address (6 bytes) * 7. sender protocol address (4 bytes) * 8. target hardware address (6 bytes) * 9. target protocol address (4 bytes) */ struct arphdr *arp_hdr; int i; /* do nothing if ARP header is truncated */ if (header->caplen < ETHER_HDR_LEN + ARP_HDR_LEN) return (ETHER_HDR_LEN); /* go pass Ethernet header in pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data++; arp_hdr = (struct arphdr *)malloc(ARP_HDR_LEN); if (arp_hdr == NULL) error("malloc(): cannot allocate memory for arp_hdr"); /* copy ARP header from pkt_data into arp_hdr */ memcpy(arp_hdr, pkt_data, ARP_HDR_LEN); /* reset pointer to the beginning of pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data--; /* do nothing if this is an unsupported ARP header */ if (arp_hdr->ar_hln != ETHER_ADDR_LEN || arp_hdr->ar_pln != IP_ADDR_LEN) { free(arp_hdr); arp_hdr = NULL; return (ETHER_HDR_LEN); } /* we are editing ARP header */ if (header_opt == ARP) { /* overwrite opcode */ if (arpopt->ar_op_flag) arp_hdr->ar_op = htons(arpopt->ar_op); /* overwrite sender MAC */ if (arpopt->ar_sha_flag == 1) /* overwrite all sender MAC */ memcpy(arp_hdr->ar_sha, arpopt->ar_old_sha, ETHER_ADDR_LEN); else if (arpopt->ar_sha_flag == 2 && /* overwrite matching sender MAC only */ memcmp(arp_hdr->ar_sha, arpopt->ar_old_sha, ETHER_ADDR_LEN) == 0) memcpy(arp_hdr->ar_sha, arpopt->ar_new_sha, ETHER_ADDR_LEN); /* overwrite sender IP */ if (arpopt->ar_spa_flag == 1) /* overwrite all sender IP */ memcpy(arp_hdr->ar_spa, arpopt->ar_old_spa, IP_ADDR_LEN); else if (arpopt->ar_spa_flag == 2 && /* overwrite matching IP only */ memcmp(arp_hdr->ar_spa, arpopt->ar_old_spa, IP_ADDR_LEN) == 0) memcpy(arp_hdr->ar_spa, arpopt->ar_new_spa, IP_ADDR_LEN); /* overwrite target MAC */ if (arpopt->ar_tha_flag == 1) /* overwrite all target MAC */ memcpy(arp_hdr->ar_tha, arpopt->ar_old_tha, ETHER_ADDR_LEN); else if (arpopt->ar_tha_flag == 2 && /* overwrite matching target MAC only */ memcmp(arp_hdr->ar_tha, arpopt->ar_old_tha, ETHER_ADDR_LEN) == 0) memcpy(arp_hdr->ar_tha, arpopt->ar_new_tha, ETHER_ADDR_LEN); /* overwrite target IP */ if (arpopt->ar_tpa_flag == 1) /* overwrite all target IP */ memcpy(arp_hdr->ar_tpa, arpopt->ar_old_tpa, IP_ADDR_LEN); else if (arpopt->ar_tpa_flag == 2 && /* overwrite matching IP only */ memcmp(arp_hdr->ar_tpa, arpopt->ar_old_tpa, IP_ADDR_LEN) == 0) memcpy(arp_hdr->ar_tpa, arpopt->ar_new_tpa, IP_ADDR_LEN); } /* * go pass pcap generic header and Ethernet header in new_pkt_data * then copy arp_hdr into new_pkt_data and reset pointer to the * beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, arp_hdr, ARP_HDR_LEN); free(arp_hdr); arp_hdr = NULL; i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN) *new_pkt_data--; /* copy up to layer 3 only, discard remaining data */ if (layer_opt == 3) { /* we are editing ARP header and we have payload */ if (header_opt == ARP && payload_len_opt > 0) { /* truncate payload if it is too large */ if ((payload_len_opt + ETHER_HDR_LEN + ARP_HDR_LEN) > ETHER_MAX_LEN) payload_len_opt -= (payload_len_opt + ETHER_HDR_LEN + ARP_HDR_LEN) - ETHER_MAX_LEN; /* * go pass pcap generic header, Ethernet header and ARP header in * new_pkt_data then copy payload_opt into new_pkt_data and reset * pointer to the beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ARP_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, payload_opt, payload_len_opt); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ARP_HDR_LEN) *new_pkt_data--; header->caplen = header->len = ETHER_HDR_LEN + ARP_HDR_LEN + payload_len_opt; } else header->caplen = header->len = ETHER_HDR_LEN + ARP_HDR_LEN; return (header->caplen); } /* no further editing support after ARP header */ return (ETHER_HDR_LEN + ARP_HDR_LEN); } u_short parse_ip(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr, int flag) { /* * IP header (20 bytes + optional X bytes for options) * 1. version (4 bits) * 2. header length (4 bits) * 3. service type (1 byte) * 4. total length (2 bytes) * 5. id (2 bytes) * 6. flag (3 bits) * 7. fragment offset (13 bits) * 8. ttl (1 byte) * 9. protocol (1 byte) * 10. header checksum (2 bytes) * 11. source IP (4 bytes) * 12. destination IP (4 bytes) * 13. options (X bytes) */ u_char *ip_hdr_o; /* IP header with options (for header checksum calculation) */ u_short ip_hlb; /* header length in bytes */ u_short ip_fo; /* fragment offset (number of 64-bit segments) */ u_char r = '\0'; /* flags */ u_char d = '\0'; u_char m = '\0'; u_char ip_p = '\0'; /* protocol */ u_char *ip_o = NULL; /* options (X bytes) */ int i, j; /* * flag is 0; entry from Ethernet header to edit IP header. * flag is 1; entry from ICMP, TCP or UDP header to update IP total length * and recalculate checksum for IP header. */ if (flag == 0) { /* do nothing if IP header is truncated */ if (header->caplen < ETHER_HDR_LEN + IP_HDR_LEN) return (ETHER_HDR_LEN); /* go pass Ethernet header in pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data++; ip_hdr = (struct ip *)malloc(IP_HDR_LEN); if (ip_hdr == NULL) error("malloc(): cannot allocate memory for ip_hdr"); /* copy IP header from pkt_data into ip_hdr */ memcpy(ip_hdr, pkt_data, IP_HDR_LEN); } ip_hlb = ip_hdr->ip_hl * 4; /* convert to bytes */ /* have IP options */ if (ip_hlb > IP_HDR_LEN) { /* do nothing if IP header with options is truncated */ if (header->caplen < ETHER_HDR_LEN + ip_hlb) { /* reset pointer to the beginning of pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data--; free(ip_hdr); ip_hdr = NULL; return (ETHER_HDR_LEN); } ip_o = (u_char *)malloc(sizeof(u_char) * (ip_hlb - IP_HDR_LEN)); if (ip_o == NULL) error("malloc(): cannot allocate memory for ip_o"); /* copy IP options into ip_o */ for (i = 0, j = IP_HDR_LEN; i < (ip_hlb - IP_HDR_LEN); i++, j++) ip_o[i] = pkt_data[j]; } if (flag == 0) { /* reset pointer to the beginning of pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data--; /* we are editing IP header */ if (header_opt == IP) { /* overwrite identification */ if (ipopt->ip_id_flag) ip_hdr->ip_id = htons(ipopt->ip_id); /* original fragment offset */ ip_fo = ntohs(ip_hdr->ip_off) & IP_OFFMASK; /* original flags */ r = (ntohs(ip_hdr->ip_off) & IP_RF) > 0 ? 1 : 0; d = (ntohs(ip_hdr->ip_off) & IP_DF) > 0 ? 1 : 0; m = (ntohs(ip_hdr->ip_off) & IP_MF) > 0 ? 1 : 0; /* overwrite fragment offset only */ if (ipopt->ip_fo_flag & !ipopt->ip_flags_flag) { ip_hdr->ip_off = htons((ipopt->ip_fo & IP_OFFMASK) | (r ? IP_RF : 0) | (d ? IP_DF : 0) | (m ? IP_MF : 0)); } /* overwrite flags only */ else if (!ipopt->ip_fo_flag & ipopt->ip_flags_flag) { ip_hdr->ip_off = htons((ip_fo & IP_OFFMASK) | ((ipopt->ip_flag_r) ? IP_RF : 0) | ((ipopt->ip_flag_d) ? IP_DF : 0) | ((ipopt->ip_flag_m) ? IP_MF : 0)); } /* overwrite fragment offset and flags */ else if (ipopt->ip_fo_flag & ipopt->ip_flags_flag) { ip_hdr->ip_off = htons((ipopt->ip_fo & IP_OFFMASK) | ((ipopt->ip_flag_r) ? IP_RF : 0) | ((ipopt->ip_flag_d) ? IP_DF : 0) | ((ipopt->ip_flag_m) ? IP_MF : 0)); } /* overwrite time to live */ if (ipopt->ip_ttl_flag) ip_hdr->ip_ttl = ipopt->ip_ttl; /* overwrite protocol */ if (ipopt->ip_p_flag) ip_hdr->ip_p = ipopt->ip_p; /* overwrite source IP */ if (ipopt->ip_src_flag == 1) /* overwrite all source IP */ memcpy(&ip_hdr->ip_src, &ipopt->ip_old_src, sizeof(struct in_addr)); else if (ipopt->ip_src_flag == 2 && /* overwrite matching IP only */ memcmp(&ip_hdr->ip_src, &ipopt->ip_old_src, sizeof(struct in_addr)) == 0) memcpy(&ip_hdr->ip_src, &ipopt->ip_new_src, sizeof(struct in_addr)); /* overwrite destination IP */ if (ipopt->ip_dst_flag == 1) /* overwrite all destination IP */ memcpy(&ip_hdr->ip_dst, &ipopt->ip_old_dst, sizeof(struct in_addr)); else if (ipopt->ip_dst_flag == 2 && /* overwrite matching IP only */ memcmp(&ip_hdr->ip_dst, &ipopt->ip_old_dst, sizeof(struct in_addr)) == 0) memcpy(&ip_hdr->ip_dst, &ipopt->ip_new_dst, sizeof(struct in_addr)); } /* * if more fragment flag is set, we should not parse the protocol header * (ICMP, TCP, or UDP) just yet since this is a fragmented packet */ m = (ntohs(ip_hdr->ip_off) & IP_MF) > 0 ? 1 : 0; ip_p = ip_hdr->ip_p; /* we are going to copy up to layer 3 only, change total length */ if (layer_opt == 3) { /* we are editing IP header and we have payload, include its length in total length */ if (header_opt == IP && payload_len_opt > 0) { /* truncate payload if it is too large */ if ((payload_len_opt + ETHER_HDR_LEN + ip_hlb) > ETHER_MAX_LEN) payload_len_opt -= (payload_len_opt + ETHER_HDR_LEN + ip_hlb) - ETHER_MAX_LEN; ip_hdr->ip_len = htons(ip_hlb + payload_len_opt); } else ip_hdr->ip_len = htons(ip_hlb); } } /* recalculate checksum (cover IP header only) */ if (csum_opt) { ip_hdr->ip_sum = 0x0000; /* clear checksum field */ /* have IP options */ if (ip_hlb > IP_HDR_LEN) { ip_hdr_o = (u_char *)malloc(sizeof(u_char) * ip_hlb); if (ip_hdr_o == NULL) error("malloc(): cannot allocate memory for ip_hdr_o"); /* * copy ip_hdr into ip_hdr_o, go pass IP header in ip_hdr_o then * copy ip_o into ip_hdr_o and reset pointer to the beginning of * ip_hdr_o and finally calculate checksum of ip_hdr_o */ memcpy(ip_hdr_o, ip_hdr, IP_HDR_LEN); i = 0; while (i++ < IP_HDR_LEN) *ip_hdr_o++; memcpy(ip_hdr_o, ip_o, ip_hlb - IP_HDR_LEN); i = 0; while (i++ < IP_HDR_LEN) *ip_hdr_o--; ip_hdr->ip_sum = htons(cksum(ip_hdr_o, ip_hlb)); free(ip_hdr_o); ip_hdr_o = NULL; } else ip_hdr->ip_sum = htons(cksum((u_char *)ip_hdr, ip_hlb)); } /* * go pass pcap generic header and Ethernet header in new_pkt_data * then copy ip_hdr and ip_o (if exist) into new_pkt_data and reset * pointer to the beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, ip_hdr, IP_HDR_LEN); /* have IP options */ if (ip_hlb > IP_HDR_LEN) { i = 0; while (i++ < IP_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, ip_o, ip_hlb - IP_HDR_LEN); free(ip_o); ip_o = NULL; i = 0; while (i++ < IP_HDR_LEN) *new_pkt_data--; } i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN) *new_pkt_data--; if (flag == 0) { /* copy up to layer 3 only, discard remaining data */ if (layer_opt == 3) { /* we are editing IP header and we have payload */ if (header_opt == IP && payload_len_opt > 0) { /* * go pass pcap generic header, Ethernet header and IP header in * new_pkt_data then copy payload_opt into new_pkt_data and reset * pointer to the beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data++; memcpy(new_pkt_data, payload_opt, payload_len_opt); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data--; header->caplen = header->len = ETHER_HDR_LEN + ip_hlb + payload_len_opt; /* * if payload is specified and it applies to ICMP, TCP, or UDP header + data, * and checksum correction on this payload is needed, * and more fragment flag is not set -> not a fragmented packet */ if (csum_opt && !m) { /* parse ICMP datagram */ if (ip_p == IPPROTO_ICMP) return (parse_icmp(pkt_data, new_pkt_data, header, ip_hdr)); /* parse TCP datagram */ else if (ip_p == IPPROTO_TCP) return (parse_tcp(pkt_data, new_pkt_data, header, ip_hdr)); /* parse UDP datagram */ else if (ip_p == IPPROTO_UDP) return (parse_udp(pkt_data, new_pkt_data, header, ip_hdr)); } } else header->caplen = header->len = ETHER_HDR_LEN + ip_hlb; free(ip_hdr); ip_hdr = NULL; return (header->caplen); } /* !m means more fragment flag is not set -> not a fragmented packet */ if (!m) { /* parse ICMP datagram */ if (ip_p == IPPROTO_ICMP) return (parse_icmp(pkt_data, new_pkt_data, header, ip_hdr)); /* parse TCP datagram */ else if (ip_p == IPPROTO_TCP) return (parse_tcp(pkt_data, new_pkt_data, header, ip_hdr)); /* parse UDP datagram */ else if (ip_p == IPPROTO_UDP) return (parse_udp(pkt_data, new_pkt_data, header, ip_hdr)); } /* no further editing support for other datagram or fragmented packet */ free(ip_hdr); ip_hdr = NULL; return (ETHER_HDR_LEN + ip_hlb); } return (0); /* flag is 1 */ } u_short parse_icmp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr) { /* * ICMP header (4 bytes) * 1. type (1 byte) * 2. code (1 byte) * 3. checksum (2 bytes) */ struct icmphdr *icmp_hdr; u_char *icmpp; /* ICMP header + trailing data */ u_short icmpp_len; u_short ip_hlb; /* IP header length in bytes */ u_short ip_fo; /* IP fragment offset (number of 64-bit segments) */ int i; ip_hlb = ip_hdr->ip_hl * 4; /* convert to bytes */ /* do nothing if ICMP header is truncated */ if (header->caplen < ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN) { free(ip_hdr); ip_hdr = NULL; return (ETHER_HDR_LEN + ip_hlb); } icmp_hdr = (struct icmphdr *)malloc(ICMP_HDR_LEN); if (icmp_hdr == NULL) error("malloc(): cannot allocate memory for icmp_hdr"); /* * we have payload which covers ICMP header + data, * use that payload instead of pkt_data */ if (layer_opt == 3 && header_opt == IP && payload_len_opt > 0) { /* * go pass pcap generic header, Ethernet header and IP header * in new_pkt_data then copy ICMP header from new_pkt_data * into icmp_hdr and reset pointer to the beginning of * new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data++; memcpy(icmp_hdr, new_pkt_data, ICMP_HDR_LEN); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data--; } else { /* * go pass Ethernet header and IP header in pkt_data * then copy ICMP header from pkt_data into icmp_hdr * and reset pointer to the beginning of pkt_data */ i = 0; while (i++ < (ETHER_HDR_LEN + ip_hlb)) *pkt_data++; memcpy(icmp_hdr, pkt_data, ICMP_HDR_LEN); i = 0; while (i++ < (ETHER_HDR_LEN + ip_hlb)) *pkt_data--; /* we are editing ICMP header */ if (header_opt == ICMP) { /* overwrite type */ if (icmpopt->icmp_type_flag) icmp_hdr->icmp_type = icmpopt->icmp_type; /* overwrite code */ if (icmpopt->icmp_code_flag) icmp_hdr->icmp_code = icmpopt->icmp_code; } /* we are going to copy up to layer 4 only */ if (layer_opt == 4) { /* * we are editing ICMP header and we have payload, attach * the payload first before checksum calculation. */ if (header_opt == ICMP && payload_len_opt > 0) { /* truncate payload if it is too large */ if ((payload_len_opt + ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN) > ETHER_MAX_LEN) payload_len_opt -= (payload_len_opt + ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN) - ETHER_MAX_LEN; /* * go pass pcap generic header, Ethernet header, IP header * and ICMP header in new_pkt_data then copy payload_opt * into new_pkt_data and reset pointer to the beginning of * new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, payload_opt, payload_len_opt); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN) *new_pkt_data--; header->caplen = header->len = ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN + payload_len_opt; } else header->caplen = header->len = ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN; /* update IP total length */ ip_hdr->ip_len = htons(header->caplen - ETHER_HDR_LEN); /* go pass Ethernet header in pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data++; /* * reuse parsing function for IP header to update IP total length in * new_pkt_data and recalculate checksum for IP header if required. */ (void)parse_ip(pkt_data, new_pkt_data, header, ip_hdr, 1); /* reset pointer to the beginning of pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data--; } } /* we have no support for checksum calculation for fragmented packet */ ip_fo = ntohs(ip_hdr->ip_off) & IP_OFFMASK; /* recalculate checksum for ICMP header (cover ICMP header + trailing data) */ if (csum_opt && ip_fo == 0) { /* recalculate checksum if we have enough data */ if (header->caplen >= (ETHER_HDR_LEN + ntohs(ip_hdr->ip_len))) { icmpp_len = ntohs(ip_hdr->ip_len) - ip_hlb; /* icmpp_len must be even for correct checksum calculation */ if ((icmpp_len % 2) != 0) icmpp = (u_char *)malloc(sizeof(u_char) * (icmpp_len + 1)); else icmpp = (u_char *)malloc(sizeof(u_char) * icmpp_len); if (icmpp == NULL) error("malloc(): cannot allocate memory for icmpp"); if ((icmpp_len % 2) != 0) memset(icmpp, 0, icmpp_len + 1); else memset(icmpp, 0, icmpp_len); /* clear checksum field */ icmp_hdr->icmp_cksum = 0x0000; /* copy ICMP header from icmp_hdr into icmpp */ memcpy(icmpp, icmp_hdr, ICMP_HDR_LEN); /* copy trailing data from payload_opt into icmpp */ if (layer_opt == 4 && header_opt == ICMP && payload_len_opt > 0) { for (i = ICMP_HDR_LEN; i < (ICMP_HDR_LEN + payload_len_opt); i++) icmpp[i] = payload_opt[i - ICMP_HDR_LEN]; } /* copy trailing data from payload_opt (payload after IP header) into icmpp */ else if (layer_opt == 3 && header_opt == IP && payload_len_opt > 0) { for (i = ICMP_HDR_LEN; i < payload_len_opt; i++) icmpp[i] = payload_opt[i]; } /* copy trailing data from pkt_data into icmpp */ else { for (i = ICMP_HDR_LEN; i < icmpp_len; i++) icmpp[i] = pkt_data[ETHER_HDR_LEN + ip_hlb + i]; } /* recalculate checksum */ if ((icmpp_len % 2) != 0) icmp_hdr->icmp_cksum = cksum(icmpp, icmpp_len + 1); else icmp_hdr->icmp_cksum = cksum(icmpp, icmpp_len); icmp_hdr->icmp_cksum = htons(icmp_hdr->icmp_cksum); free(icmpp); icmpp = NULL; } } free(ip_hdr); ip_hdr = NULL; /* * go pass pcap generic header, Ethernet header and IP header * in new_pkt_data then copy icmp_hdr into new_pkt_data and * reset pointer to the beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data++; memcpy(new_pkt_data, icmp_hdr, ICMP_HDR_LEN); free(icmp_hdr); icmp_hdr = NULL; i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data--; /* no further editing support after ICMP header */ if (layer_opt == 4) return (header->caplen); /* * we have written payload_opt (payload after IP header) which covers ICMP header + data, * checksum for ICMP header corrected above, * while ICMP data is written to new_pkt_data in parse_ip() */ else if (layer_opt == 3) return (header->caplen); else return (ETHER_HDR_LEN + ip_hlb + ICMP_HDR_LEN); } u_short parse_tcp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr) { /* * TCP header (20 bytes + optional X bytes for options) * 1. source port (2 bytes) * 2. destination port (2 bytes) * 3. sequence number (4 bytes) * 4. acknowledgment number (4 bytes) * 5. data offset (4 bits) - number of 32-bit segments in TCP header * 6. reserved (6 bits) * 7. flags (6 bits) * 8. window (2 bytes) * 9. checksum (2 bytes) * 10. urgent pointer (2 bytes) * 11. options (X bytes) */ struct tcphdr *tcp_hdr; u_char *tcp_o = NULL; /* options (X bytes) */ u_short tcp_hlb; /* TCP header length in bytes */ u_char *tcpp; /* IP pseudo header + TCP header (with options if exist) + trailing data */ u_short tcpp_len; struct ippseudo *ipp; /* IP pseudo header */ u_short ip_hlb; /* IP header length in bytes */ u_short ip_fo; /* IP fragment offset (number of 64-bit segments) */ int i, j; ip_hlb = ip_hdr->ip_hl * 4; /* convert to bytes */ /* do nothing if TCP header is truncated */ if (header->caplen < ETHER_HDR_LEN + ip_hlb + TCP_HDR_LEN) { free(ip_hdr); ip_hdr = NULL; return (ETHER_HDR_LEN + ip_hlb); } tcp_hdr = (struct tcphdr *)malloc(TCP_HDR_LEN); if (tcp_hdr == NULL) error("malloc(): cannot allocate memory for tcp_hdr"); /* * we have payload which covers TCP header + data, * use that payload instead of pkt_data */ if (layer_opt == 3 && header_opt == IP && payload_len_opt > 0) { /* * go pass pcap generic header, Ethernet header and IP header * in new_pkt_data then copy TCP header from new_pkt_data * into tcp_hdr and reset pointer to the beginning of * new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data++; memcpy(tcp_hdr, new_pkt_data, TCP_HDR_LEN); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data--; } else { /* * go pass Ethernet header and IP header in pkt_data * then copy TCP header from pkt_data into tcp_hdr * and reset pointer to the beginning of pkt_data */ i = 0; while (i++ < (ETHER_HDR_LEN + ip_hlb)) *pkt_data++; memcpy(tcp_hdr, pkt_data, TCP_HDR_LEN); i = 0; while (i++ < (ETHER_HDR_LEN + ip_hlb)) *pkt_data--; } tcp_hlb = tcp_hdr->th_off * 4; /* convert to bytes */ /* have TCP options */ if (tcp_hlb > TCP_HDR_LEN) { /* do nothing if TCP header with options is truncated */ if (header->caplen < (ETHER_HDR_LEN + ip_hlb + tcp_hlb)) { free(ip_hdr); ip_hdr = NULL; free(tcp_hdr); tcp_hdr = NULL; return (ETHER_HDR_LEN + ip_hlb); } tcp_o = (u_char *)malloc(sizeof(u_char) * (tcp_hlb - TCP_HDR_LEN)); if (tcp_o == NULL) error("malloc(): cannot allocate memory for tcp_o"); if (layer_opt == 3 && header_opt == IP && payload_len_opt > 0) { /* copy TCP options from new_pkt_data into tcp_o */ for (i = 0, j = TCP_HDR_LEN; i < (tcp_hlb - TCP_HDR_LEN); i++, j++) tcp_o[i] = new_pkt_data[PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb + j]; } else { /* copy TCP options from pkt_data into tcp_o */ for (i = 0, j = TCP_HDR_LEN; i < (tcp_hlb - TCP_HDR_LEN); i++, j++) tcp_o[i] = pkt_data[ETHER_HDR_LEN + ip_hlb + j]; } } /* we are editing TCP header */ if (header_opt == TCP) { /* overwrite source port */ if (tcpopt->th_sport_flag == 1) /* overwrite all source port */ tcp_hdr->th_sport = htons(tcpopt->th_old_sport); else if (tcpopt->th_sport_flag == 2 && /* overwrite matching port only */ tcp_hdr->th_sport == htons(tcpopt->th_old_sport)) tcp_hdr->th_sport = htons(tcpopt->th_new_sport); /* overwrite destination port */ if (tcpopt->th_dport_flag == 1) /* overwrite all destination port */ tcp_hdr->th_dport = htons(tcpopt->th_old_dport); else if (tcpopt->th_dport_flag == 2 && /* overwrite matching port only */ tcp_hdr->th_dport == htons(tcpopt->th_old_dport)) tcp_hdr->th_dport = htons(tcpopt->th_new_dport); /* overwrite sequence number */ if (tcpopt->th_seq_flag) tcp_hdr->th_seq = htonl(tcpopt->th_seq); /* overwrite acknowledgment number */ if (tcpopt->th_ack_flag) tcp_hdr->th_ack = htonl(tcpopt->th_ack); /* overwrite flags */ if (tcpopt->th_flags_flag) tcp_hdr->th_flags = ((tcpopt->th_flag_u ? TH_URG : 0) | (tcpopt->th_flag_a ? TH_ACK : 0) | (tcpopt->th_flag_p ? TH_PUSH : 0) | (tcpopt->th_flag_r ? TH_RST : 0) | (tcpopt->th_flag_s ? TH_SYN : 0) | (tcpopt->th_flag_f ? TH_FIN : 0)); /* overwrite window size */ if (tcpopt->th_win_flag) tcp_hdr->th_win = htons(tcpopt->th_win); /* overwrite urgent pointer */ if (tcpopt->th_urp_flag) tcp_hdr->th_urp = htons(tcpopt->th_urp); } /* we are going to copy up to layer 4 only */ if (layer_opt == 4) { /* * we are editing TCP header and we have payload, attach * the payload first before checksum calculation */ if (header_opt == TCP && payload_len_opt > 0) { /* truncate payload if it is too large */ if ((payload_len_opt + ETHER_HDR_LEN + ip_hlb + tcp_hlb) > ETHER_MAX_LEN) payload_len_opt -= (payload_len_opt + ETHER_HDR_LEN + ip_hlb + tcp_hlb) - ETHER_MAX_LEN; /* * go pass pcap generic header, Ethernet header, IP header * and TCP header in new_pkt_data then copy payload_opt * into new_pkt_data and reset pointer to the beginning of * new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb + tcp_hlb) *new_pkt_data++; memcpy(new_pkt_data, payload_opt, payload_len_opt); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb + tcp_hlb) *new_pkt_data--; header->caplen = header->len = ETHER_HDR_LEN + ip_hlb + tcp_hlb + payload_len_opt; } else header->caplen = header->len = ETHER_HDR_LEN + ip_hlb + tcp_hlb; /* update IP total length */ ip_hdr->ip_len = htons(header->caplen - ETHER_HDR_LEN); /* go pass Ethernet header in pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data++; /* * reuse parsing function for IP header to update IP total length in * new_pkt_data and recalculate checksum for IP header if required. */ (void)parse_ip(pkt_data, new_pkt_data, header, ip_hdr, 1); /* reset pointer to the beginning of pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data--; } /* we have no support for checksum calculation for fragmented packet */ ip_fo = ntohs(ip_hdr->ip_off) & IP_OFFMASK; /* recalculate checksum for TCP header (cover IP pseudo header + TCP header + trailing data) */ if (csum_opt && ip_fo == 0) { /* recalculate checksum if we have enough data */ if (header->caplen >= (ETHER_HDR_LEN + ntohs(ip_hdr->ip_len))) { /* create IP pseudo header */ ipp = (struct ippseudo *)malloc(sizeof(struct ippseudo)); if (ipp == NULL) error("malloc(): cannot allocate memory for ipp"); memcpy(&ipp->ippseudo_src, &ip_hdr->ip_src, sizeof(struct in_addr)); memcpy(&ipp->ippseudo_dst, &ip_hdr->ip_dst, sizeof(struct in_addr)); ipp->ippseudo_pad = 0x00; ipp->ippseudo_p = ip_hdr->ip_p; ipp->ippseudo_len = htons(ntohs(ip_hdr->ip_len) - ip_hlb); tcpp_len = sizeof(struct ippseudo) + ntohs(ipp->ippseudo_len); /* tcpp_len must be even for correct checksum calculation */ if ((tcpp_len % 2) != 0) tcpp = (u_char *)malloc(sizeof(u_char) * (tcpp_len + 1)); else tcpp = (u_char *)malloc(sizeof(u_char) * tcpp_len); if (tcpp == NULL) error("malloc(): cannot allocate memory for tcpp"); if ((tcpp_len % 2) != 0) memset(tcpp, 0, tcpp_len + 1); else memset(tcpp, 0, tcpp_len); /* copy IP pseudo header from ipp into tcpp */ memcpy(tcpp, ipp, sizeof(struct ippseudo)); free(ipp); ipp = NULL; /* go pass IP pseudo header in tcpp */ i = 0; while (i++ < sizeof(struct ippseudo)) *tcpp++; /* clear checksum field */ tcp_hdr->th_sum = 0x0000; /* copy TCP header from tcp_hdr into tcpp */ memcpy(tcpp, tcp_hdr, TCP_HDR_LEN); /* * have TCP options, go pass TCP header in tcpp then copy tcp_o into tcpp * and reset pointer of tcpp to go pass IP pseudo header only */ if (tcp_hlb > TCP_HDR_LEN) { i = 0; while (i++ < TCP_HDR_LEN) *tcpp++; memcpy(tcpp, tcp_o, tcp_hlb - TCP_HDR_LEN); i = 0; while (i++ < TCP_HDR_LEN) *tcpp--; } /* reset pointer to the beginning of tcpp */ i = 0; while (i++ < sizeof(struct ippseudo)) *tcpp--; /* copy trailing data from payload_opt into tcpp */ if (layer_opt == 4 && header_opt == TCP && payload_len_opt > 0) { for (i = tcp_hlb; i < (tcpp_len - sizeof(struct ippseudo)); i++) tcpp[i + sizeof(struct ippseudo)] = payload_opt[i - tcp_hlb]; } /* copy trailing data from payload_opt (payload after IP header) into tcpp */ else if (layer_opt == 3 && header_opt == IP && payload_len_opt > 0) { for (i = tcp_hlb; i < payload_len_opt; i++) tcpp[i + sizeof(struct ippseudo)] = payload_opt[i]; } /* copy trailing data from pkt_data into tcpp */ else { for (i = tcp_hlb; i < (tcpp_len - sizeof(struct ippseudo)); i++) tcpp[i + sizeof(struct ippseudo)] = pkt_data[ETHER_HDR_LEN + ip_hlb + i]; } /* recalculate checksum */ if ((tcpp_len % 2) != 0) tcp_hdr->th_sum = cksum(tcpp, tcpp_len + 1); else tcp_hdr->th_sum = cksum(tcpp, tcpp_len); tcp_hdr->th_sum = htons(tcp_hdr->th_sum); free(tcpp); tcpp = NULL; } } free(ip_hdr); ip_hdr = NULL; /* * go pass pcap generic header, Ethernet header and IP header * in new_pkt_data then copy tcp_hdr and tcp_o (if exist) into * new_pkt_data and reset pointer to the beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data++; memcpy(new_pkt_data, tcp_hdr, TCP_HDR_LEN); free(tcp_hdr); tcp_hdr = NULL; /* have TCP options */ if (tcp_hlb > TCP_HDR_LEN) { i = 0; while (i++ < TCP_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, tcp_o, tcp_hlb - TCP_HDR_LEN); free(tcp_o); tcp_o = NULL; i = 0; while (i++ < TCP_HDR_LEN) *new_pkt_data--; } i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data--; /* no further editing support after TCP header */ if (layer_opt == 4) return (header->caplen); /* * we have written payload_opt (payload after IP header) which covers TCP header + data, * checksum for TCP header corrected above, * while TCP data is written to new_pkt_data in parse_ip() */ else if (layer_opt == 3) return (header->caplen); else return (ETHER_HDR_LEN + ip_hlb + tcp_hlb); } u_short parse_udp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr) { /* * UDP header (8 bytes) * 1. source port (2 bytes) * 2. destination port (2 bytes) * 3. length (2 bytes) * 4. checksum (2 bytes) */ struct udphdr *udp_hdr; u_char *udpp; /* IP pseudo header + UDP header + trailing data */ u_short udpp_len; struct ippseudo *ipp; /* IP pseudo header */ u_short ip_hlb; /* IP header length in bytes */ u_short ip_fo; /* IP fragment offset (number of 64-bit segments) */ int i; ip_hlb = ip_hdr->ip_hl * 4; /* convert to bytes */ /* do nothing if UDP header is truncated */ if (header->caplen < ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN) { free(ip_hdr); ip_hdr = NULL; return (ETHER_HDR_LEN + ip_hlb); } udp_hdr = (struct udphdr *)malloc(UDP_HDR_LEN); if (udp_hdr == NULL) error("malloc(): cannot allocate memory for udp_hdr"); /* * we have payload which covers UDP header + data, * use that payload instead of pkt_data */ if (layer_opt == 3 && header_opt == IP && payload_len_opt > 0) { /* * go pass pcap generic header, Ethernet header and IP header * in new_pkt_data then copy UDP header from new_pkt_data * into udp_hdr and reset pointer to the beginning of * new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data++; memcpy(udp_hdr, new_pkt_data, UDP_HDR_LEN); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data--; } else { /* * go pass Ethernet header and IP header in pkt_data * then copy UDP header from pkt_data into udp_hdr * and reset pointer to the beginning of pkt_data */ i = 0; while (i++ < (ETHER_HDR_LEN + ip_hlb)) *pkt_data++; memcpy(udp_hdr, pkt_data, UDP_HDR_LEN); i = 0; while (i++ < (ETHER_HDR_LEN + ip_hlb)) *pkt_data--; } /* we are editing UDP header */ if (header_opt == UDP) { /* overwrite source port */ if (udpopt->uh_sport_flag == 1) /* overwrite all source port */ udp_hdr->uh_sport = htons(udpopt->uh_old_sport); else if (udpopt->uh_sport_flag == 2 && /* overwrite matching port only */ udp_hdr->uh_sport == htons(udpopt->uh_old_sport)) udp_hdr->uh_sport = htons(udpopt->uh_new_sport); /* overwrite destination port */ if (udpopt->uh_dport_flag == 1) /* overwrite all destination port */ udp_hdr->uh_dport = htons(udpopt->uh_old_dport); else if (udpopt->uh_dport_flag == 2 && /* overwrite matching port only */ udp_hdr->uh_dport == htons(udpopt->uh_old_dport)) udp_hdr->uh_dport = htons(udpopt->uh_new_dport); } /* we are going to copy up to layer 4 only */ if (layer_opt == 4) { /* * we are editing UDP header and we have payload, attach * the payload first before checksum calculation */ if (header_opt == UDP && payload_len_opt > 0) { /* truncate payload if it is too large */ if ((payload_len_opt + ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN) > ETHER_MAX_LEN) payload_len_opt -= (payload_len_opt + ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN) - ETHER_MAX_LEN; /* * go pass pcap generic header, Ethernet header, IP header * and UDP header in new_pkt_data then copy payload_opt * into new_pkt_data and reset pointer to the beginning of * new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN) *new_pkt_data++; memcpy(new_pkt_data, payload_opt, payload_len_opt); i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN) *new_pkt_data--; header->caplen = header->len = ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN + payload_len_opt; } else header->caplen = header->len = ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN; /* update UDP length */ udp_hdr->uh_ulen = htons(header->caplen - (ETHER_HDR_LEN + ip_hlb)); /* update IP total length */ ip_hdr->ip_len = htons(header->caplen - ETHER_HDR_LEN); /* go pass Ethernet header in pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data++; /* * reuse parsing function for IP header to update IP total length in * new_pkt_data and recalculate checksum for IP header if required. */ (void)parse_ip(pkt_data, new_pkt_data, header, ip_hdr, 1); /* reset pointer to the beginning of pkt_data */ i = 0; while (i++ < ETHER_HDR_LEN) *pkt_data--; } /* we have no support for checksum calculation for fragmented packet */ ip_fo = ntohs(ip_hdr->ip_off) & IP_OFFMASK; /* recalculate checksum for UDP header (cover IP pseudo header + UDP header + trailing data) */ if (csum_opt && ip_fo == 0) { /* recalculate checksum if we have enough data */ if (header->caplen >= (ETHER_HDR_LEN + ntohs(ip_hdr->ip_len))) { /* create IP pseudo header */ ipp = (struct ippseudo *)malloc(sizeof(struct ippseudo)); if (ipp == NULL) error("malloc(): cannot allocate memory for ipp"); memcpy(&ipp->ippseudo_src, &ip_hdr->ip_src, sizeof(struct in_addr)); memcpy(&ipp->ippseudo_dst, &ip_hdr->ip_dst, sizeof(struct in_addr)); ipp->ippseudo_pad = 0x00; ipp->ippseudo_p = ip_hdr->ip_p; ipp->ippseudo_len = htons(ntohs(ip_hdr->ip_len) - ip_hlb); udpp_len = sizeof(struct ippseudo) + ntohs(ipp->ippseudo_len); /* udpp_len must be even for correct checksum calculation */ if ((udpp_len % 2) != 0) udpp = (u_char *)malloc(sizeof(u_char) * (udpp_len + 1)); else udpp = (u_char *)malloc(sizeof(u_char) * udpp_len); if (udpp == NULL) error("malloc(): cannot allocate memory for udpp"); if ((udpp_len % 2) != 0) memset(udpp, 0, udpp_len + 1); else memset(udpp, 0, udpp_len); /* copy IP pseudo header from ipp into udpp */ memcpy(udpp, ipp, sizeof(struct ippseudo)); free(ipp); ipp = NULL; /* go pass IP pseudo header in udpp */ i = 0; while (i++ < sizeof(struct ippseudo)) *udpp++; /* clear checksum field */ udp_hdr->uh_sum = 0x0000; /* copy UDP header from udp_hdr into udpp */ memcpy(udpp, udp_hdr, UDP_HDR_LEN); /* reset pointer to the beginning of udpp */ i = 0; while (i++ < sizeof(struct ippseudo)) *udpp--; /* copy trailing data from payload_opt into udpp */ if (layer_opt == 4 && header_opt == UDP && payload_len_opt > 0) { for (i = UDP_HDR_LEN; i < (udpp_len - sizeof(struct ippseudo)); i++) udpp[i + sizeof(struct ippseudo)] = payload_opt[i - UDP_HDR_LEN]; } /* copy trailing data from payload_opt (payload after IP header) into udpp */ else if (layer_opt == 3 && header_opt == IP && payload_len_opt > 0) { for (i = UDP_HDR_LEN; i < payload_len_opt; i++) udpp[i + sizeof(struct ippseudo)] = payload_opt[i]; } /* copy trailing data from pkt_data into udpp */ else { for (i = UDP_HDR_LEN; i < (udpp_len - sizeof(struct ippseudo)); i++) udpp[i + sizeof(struct ippseudo)] = pkt_data[ETHER_HDR_LEN + ip_hlb + i]; } /* recalculate checksum */ if ((udpp_len % 2) != 0) udp_hdr->uh_sum = cksum(udpp, udpp_len + 1); else udp_hdr->uh_sum = cksum(udpp, udpp_len); udp_hdr->uh_sum = htons(udp_hdr->uh_sum); free(udpp); udpp = NULL; } } free(ip_hdr); ip_hdr = NULL; /* * go pass pcap generic header, Ethernet header and IP header * in new_pkt_data then copy udp_hdr into new_pkt_data and reset * pointer to the beginning of new_pkt_data */ i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data++; memcpy(new_pkt_data, udp_hdr, UDP_HDR_LEN); free(udp_hdr); udp_hdr = NULL; i = 0; while (i++ < PCAP_HDR_LEN + ETHER_HDR_LEN + ip_hlb) *new_pkt_data--; /* no further editing support after UDP header */ if (layer_opt == 4) return (header->caplen); /* * we have written payload_opt (payload after IP header) which covers UDP header + data, * checksum for UDP header corrected above, * while UDP data is written to new_pkt_data in parse_ip() */ else if (layer_opt == 3) return (header->caplen); else return (ETHER_HDR_LEN + ip_hlb + UDP_HDR_LEN); } /* Reference: rfc1071.txt */ u_short cksum(u_char *cp, u_short len) { u_short word_16; /* 16-bit word */ u_int sum = 0; u_short i; /* from 2 adjacent 8-bit words, create a 16-bit word, add all 16-bit words */ for (i = 0; i < len; i = i + 2) { word_16 = ((cp[i] << 8) & 0xff00) + (cp[i + 1] & 0xff); sum += (u_int)word_16; } /* take 16 bits out of the 32-bit sum */ while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); /* one's complement the sum */ return ((u_short)~sum); } void info(void) { (void)putchar('\n'); notice("%u packets (%u bytes) written", pkts, bytes); } /* * Reference: tcpdump's util.c * * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * */ void notice(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } } /* * Reference: tcpdump's util.c * * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * */ void error(const char *fmt, ...) { va_list ap; (void)fprintf(stderr, "%s: ", program_name); va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); if (*fmt) { fmt += strlen(fmt); if (fmt[-1] != '\n') (void)fputc('\n', stderr); } exit(EXIT_FAILURE); } /* * Reference: FreeBSD's /usr/src/lib/libc/net/ether_addr.c * * Copyright (c) 1995 * Bill Paul . All rights reserved. * */ struct ether_addr *ether_aton(const char *a) { int i; static struct ether_addr o; unsigned int o0, o1, o2, o3, o4, o5; i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5); if (i != 6) return (NULL); o.octet[0]=o0; o.octet[1]=o1; o.octet[2]=o2; o.octet[3]=o3; o.octet[4]=o4; o.octet[5]=o5; return ((struct ether_addr *)&o); } /* * Reference: FreeBSD's /usr/src/lib/libc/inet/inet_addr.c * * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights reserved. * */ int inet_aton(const char *cp, struct in_addr *addr) { u_long val; int base, n; char c; u_int8_t parts[4]; u_int8_t *pp = parts; int digit; c = *cp; for (;;) { /* * Collect number up to ".". * Values are specified as for C: * 0x=hex, 0=octal, isdigit=decimal. */ if (!isdigit((unsigned char)c)) return (0); val = 0; base = 10; digit = 0; if (c == '0') { c = *++cp; if (c == 'x' || c == 'X') base = 16, c = *++cp; else { base = 8; digit = 1; } } for (;;) { if (isascii(c) && isdigit((unsigned char)c)) { if (base == 8 && (c == '8' || c == '9')) return (0); val = (val * base) + (c - '0'); c = *++cp; digit = 1; } else if (base == 16 && isascii(c) && isxdigit((unsigned char)c)) { val = (val << 4) | (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); c = *++cp; digit = 1; } else break; } if (c == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16 bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3 || val > 0xffU) return (0); *pp++ = val; c = *++cp; } else break; } /* * Check for trailing characters. */ if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c))) return (0); /* * Did we get a valid digit? */ if (!digit) return (0); /* * Concoct the address according to * the number of parts specified. */ n = pp - parts + 1; switch (n) { case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if (val > 0xffffffU) return (0); val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if (val > 0xffffU) return (0); val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if (val > 0xffU) return (0); val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if (addr != NULL) addr->s_addr = htonl(val); return (1); } void usage(void) { (void)fprintf(stderr, "%s version %s\n" "%s\n" "Usage: %s [-I input] [-O output] [-L layer] [-X payload] [-C]\n" " [-M linktype] [-D offset] [-R range] [-S timeframe]\n" " [-T header] [header-specific-options] [-h]\n" "\nOptions:\n" " -I input Input pcap based trace file.\n" " -O output Output trace file.\n" " -L layer Copy up to the specified 'layer' and discard the remaining\n" " data. Value for 'layer' must be either 2, 3 or 4 where\n" " 2 for Ethernet, 3 for ARP or IP, and 4 for ICMP, TCP or UDP.\n" " -X payload Append 'payload' in hex digits to the end of each packet.\n" " Example: -X 0302aad1\n" " -X flag is ignored if -L and -T flag are not specified.\n" " -C Specify this flag to disable checksum correction.\n" " Checksum correction is applicable for non-fragmented IP,\n" " ICMP, TCP, and UDP packets only.\n" " -M linktype Replace the 'linktype' stored in the pcap file header.\n" " Typically, value for 'linktype' is 1 for Ethernet.\n" " Example: -M 12 (for raw IP), -M 51 (for PPPoE)\n" " -D offset Delete the specified byte 'offset' from each packet.\n" " First byte (starting from link layer header) starts from 1.\n" " -L, -X, -C and -T flag are ignored if -D flag is specified.\n" " Example: -D 15-40, -D 10 or -D 18-9999\n" " -R range Save only the specified 'range' of packets.\n" " Example: -R 5-21 or -R 9\n" " -S timeframe Save only the packets within the specified 'timeframe' with\n" " up to one-second resolution using DD/MM/YYYY,HH:MM:SS as the\n" " format for start and end time in 'timeframe'.\n" " Example: -S 22/10/2006,21:47:35-24/10/2006,13:16:05\n" " -S flag is evaluated after -R flag.\n" " -T header Edit only the specified 'header'. Possible keywords for\n" " 'header' are, eth, arp, ip, icmp, tcp, or udp.\n" " -T flag must appear last among the general options.\n" " -h Print version information and usage.\n", program_name, BITTWISTE_VERSION, pcap_lib_version(), program_name); exit(EXIT_SUCCESS); } bittwist-linux-2.0/src/._bittwiste.h000444 000765 000024 00000000347 11744746762 020570 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect28:34{{0, 218}, {970, 698}}bittwist-linux-2.0/src/bittwiste.h000444 000765 000024 00000004272 11744746762 020354 0ustar00addyyeowstaff000000 000000 /* * bittwiste - pcap capture file editor * Copyright (C) 2006 - 2012 Addy Yeow Chin Heng * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _BITTWISTE_H_ #define _BITTWISTE_H_ #include "def.h" void parse_header_options(int argc, char **argv); void parse_trace(char *infile, char *outfile); u_short parse_ethernet(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header); u_short parse_arp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header); u_short parse_ip(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr, int flag); u_short parse_icmp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr); u_short parse_tcp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr); u_short parse_udp(const u_char *pkt_data, u_char *new_pkt_data, struct pcap_sf_pkthdr *header, struct ip *ip_hdr); u_short cksum(u_char *cp, u_short len); void info(void); void notice(const char *, ...); void error(const char *, ...); struct ether_addr *ether_aton(const char *a); int inet_aton(const char *cp, struct in_addr *addr); void usage(void); #endif /* !_BITTWISTE_H_ */ bittwist-linux-2.0/src/def.h000444 000765 000024 00000026423 11744746762 017076 0ustar00addyyeowstaff000000 000000 /* * def.h * Copyright (C) 2006 - 2012 Addy Yeow Chin Heng * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _DEF_H_ #define _DEF_H_ #include #include #include #include #include #include #include #include #include #include #include #include #define _NET_IF_ARP_H_ /* OpenBSD's if.h takes in if_arp.h */ #include #include #include #include #ifdef __BSD_VISIBLE /* Linux does not have net/if_dl.h */ #include #endif #include struct pcap_timeval { bpf_int32 tv_sec; /* seconds */ bpf_int32 tv_usec; /* microseconds */ }; struct pcap_sf_pkthdr { struct pcap_timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */ }; #define BITTWIST_VERSION "2.0" #define BITTWISTE_VERSION BITTWIST_VERSION #define ETHER_ADDR_LEN 6 /* Ethernet address length */ #define ETHER_HDR_LEN 14 /* Ethernet header length */ #define ETHER_MAX_LEN 1514 /* maximum frame length, excluding CRC */ #define ARP_HDR_LEN 28 /* Ethernet ARP header length */ #define IP_ADDR_LEN 4 /* IP address length */ #define IP_HDR_LEN 20 /* default IP header length */ #define ICMP_HDR_LEN 4 /* ICMP header length */ #define TCP_HDR_LEN 20 /* default TCP header length */ #define UDP_HDR_LEN 8 /* UDP header length */ #define ETHERTYPE_IP 0x0800 /* IP protocol */ #define ETHERTYPE_ARP 0x0806 /* address resolution protocol */ #ifndef IPPROTO_ICMP #define IPPROTO_ICMP 1 /* internet control message protocol */ #endif #ifndef IPPROTO_TCP #define IPPROTO_TCP 6 /* transmission control protocol */ #endif #ifndef IPPROTO_UDP #define IPPROTO_UDP 17 /* user datagram protocol */ #endif /* bittwist */ #define LINERATE_MIN 1 /* Mbps */ #define LINERATE_MAX 10000 /* Mbps */ #define SPEED_MIN 0.000001 /* minimum positive value for speed (interval multiplier) */ #define SLEEP_MAX 2146 /* maximum interval in seconds */ #define PKT_PAD 0x00 /* packet padding */ /* bittwiste */ #define PAYLOAD_MAX 1500 /* maximum payload in bytes */ #define ETH 1 /* supported header specification (dummy values) */ #define ARP 2 #define IP 3 #define ICMP 4 #define TCP 5 #define UDP 6 #define IP_FO_MAX 7770 /* maximum IP fragment offset (number of 64-bit segments) */ #define PCAP_HDR_LEN 16 /* pcap generic header length */ #define PCAP_MAGIC 0xa1b2c3d4 /* pcap magic number */ #ifndef TIMEVAL_TO_TIMESPEC #define TIMEVAL_TO_TIMESPEC(tv, ts) { \ (ts)->tv_sec = (tv)->tv_sec; \ (ts)->tv_nsec = (tv)->tv_usec * 1000; \ } #endif #define ROUND(f) (f >= 0 ? (long)(f + 0.5) : (long)(f - 0.5)) /* 10Mbps Ethernet header */ struct ether_header { u_char ether_dhost[ETHER_ADDR_LEN]; u_char ether_shost[ETHER_ADDR_LEN]; u_short ether_type; }; /* 48-bit Ethernet address */ struct ether_addr { u_char octet[ETHER_ADDR_LEN]; }; /* Ethernet ARP header */ struct arphdr { u_short ar_hrd; /* format of hardware address */ #define ARPHRD_ETHER 1 /* ethernet hardware format */ #define ARPHRD_IEEE802 6 /* token-ring hardware format */ #define ARPHRD_ARCNET 7 /* arcnet hardware format */ #define ARPHRD_FRELAY 15 /* frame relay hardware format */ #define ARPHRD_IEEE1394 24 /* firewire hardware format */ u_short ar_pro; /* format of protocol address */ u_char ar_hln; /* length of hardware address */ u_char ar_pln; /* length of protocol address */ u_short ar_op; /* one of: */ #define ARPOP_REQUEST 1 /* request to resolve address */ #define ARPOP_REPLY 2 /* response to previous request */ #define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ #define ARPOP_REVREPLY 4 /* response giving protocol address */ #define ARPOP_INVREQUEST 8 /* request to identify peer */ #define ARPOP_INVREPLY 9 /* response identifying peer */ u_char ar_sha[ETHER_ADDR_LEN]; /* sender hardware address */ u_char ar_spa[IP_ADDR_LEN]; /* sender protocol address */ u_char ar_tha[ETHER_ADDR_LEN]; /* target hardware address */ u_char ar_tpa[IP_ADDR_LEN]; /* target protocol address */ }; /* IP header */ struct ip { #if BYTE_ORDER == LITTLE_ENDIAN u_int ip_hl:4, /* header length */ ip_v:4; /* version */ #endif #if BYTE_ORDER == BIG_ENDIAN u_int ip_v:4, /* version */ ip_hl:4; /* header length */ #endif u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ u_short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and destination address */ } __packed; /* * IPv4 pseudo header, used for computing the TCP and UDP checksums. */ struct ippseudo { struct in_addr ippseudo_src; /* source internet address */ struct in_addr ippseudo_dst; /* destination internet address */ u_char ippseudo_pad; /* pad, must be zero */ u_char ippseudo_p; /* protocol */ u_short ippseudo_len; /* protocol length */ }; /* ICMP header */ struct icmphdr { u_char icmp_type; /* type of message */ u_char icmp_code; /* type sub code */ u_short icmp_cksum; /* ones complement cksum of struct */ }; typedef u_int32_t tcp_seq; /* * TCP header. * Per RFC 793, September, 1981. */ struct tcphdr { u_short th_sport; /* source port */ u_short th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ #if BYTE_ORDER == LITTLE_ENDIAN u_int th_x2:4, /* (unused) */ th_off:4; /* data offset */ #endif #if BYTE_ORDER == BIG_ENDIAN u_int th_off:4, /* data offset */ th_x2:4; /* (unused) */ #endif u_char th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) u_short th_win; /* window */ u_short th_sum; /* checksum */ u_short th_urp; /* urgent pointer */ }; /* * UDP header. * Per RFC 768, September, 1981. */ struct udphdr { u_short uh_sport; /* source port */ u_short uh_dport; /* destination port */ u_short uh_ulen; /* udp length */ u_short uh_sum; /* udp checksum */ }; /* * Structures for bittwiste header specific options. */ struct ethopt { u_char ether_old_dhost[ETHER_ADDR_LEN]; u_char ether_new_dhost[ETHER_ADDR_LEN]; u_char ether_dhost_flag; u_char ether_old_shost[ETHER_ADDR_LEN]; u_char ether_new_shost[ETHER_ADDR_LEN]; u_char ether_shost_flag; u_short ether_type; }; struct arpopt { u_short ar_op; /* opcode */ u_char ar_op_flag; u_char ar_old_sha[ETHER_ADDR_LEN]; /* sender hardware address */ u_char ar_new_sha[ETHER_ADDR_LEN]; u_char ar_sha_flag; u_char ar_old_spa[IP_ADDR_LEN]; /* sender protocol address */ u_char ar_new_spa[IP_ADDR_LEN]; u_char ar_spa_flag; u_char ar_old_tha[ETHER_ADDR_LEN]; /* target hardware address */ u_char ar_new_tha[ETHER_ADDR_LEN]; u_char ar_tha_flag; u_char ar_old_tpa[IP_ADDR_LEN]; /* target protocol address */ u_char ar_new_tpa[IP_ADDR_LEN]; u_char ar_tpa_flag; }; struct ipopt { u_short ip_id; /* identification */ u_char ip_id_flag; u_char ip_flag_r; /* reserved bit */ u_char ip_flag_d; /* don't fragment bit */ u_char ip_flag_m; /* more fragment bit */ u_char ip_flags_flag; u_short ip_fo; /* fragment offset in bytes */ u_char ip_fo_flag; u_char ip_ttl; /* time to live */ u_char ip_ttl_flag; u_char ip_p; /* protocol */ u_char ip_p_flag; struct in_addr ip_old_src; /* source address */ struct in_addr ip_new_src; u_char ip_src_flag; struct in_addr ip_old_dst; /* destination address */ struct in_addr ip_new_dst; u_char ip_dst_flag; }; struct icmpopt { u_char icmp_type; /* type of message */ u_char icmp_type_flag; u_char icmp_code; /* type sub code */ u_char icmp_code_flag; }; struct tcpopt { u_short th_old_sport; /* source port */ u_short th_new_sport; u_char th_sport_flag; u_short th_old_dport; /* destination port */ u_short th_new_dport; u_char th_dport_flag; tcp_seq th_seq; /* sequence number */ u_char th_seq_flag; tcp_seq th_ack; /* acknowledgement number */ u_char th_ack_flag; u_char th_flag_u; /* URG */ u_char th_flag_a; /* ACK */ u_char th_flag_p; /* PSH */ u_char th_flag_r; /* RST */ u_char th_flag_s; /* SYN */ u_char th_flag_f; /* FIN */ u_char th_flags_flag; u_short th_win; /* window */ u_char th_win_flag; u_short th_urp; /* urgent pointer */ u_char th_urp_flag; }; struct udpopt { u_short uh_old_sport; /* source port */ u_short uh_new_sport; u_char uh_sport_flag; u_short uh_old_dport; /* destination port */ u_short uh_new_dport; u_char uh_dport_flag; }; #endif /* !_DEF_H_ */ bittwist-linux-2.0/doc/._bittwist.1000444 000765 000024 00000000344 11744746762 020307 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect28:6{{0, 0}, {964, 698}}bittwist-linux-2.0/doc/bittwist.1000444 000765 000024 00000013147 11744746762 020077 0ustar00addyyeowstaff000000 000000 .\" .\" bittwist.1 - manpage for the bittwist program .\" Copyright (C) 2006 - 2012 Addy Yeow Chin Heng .\" .\" This program is free software; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License .\" as published by the Free Software Foundation; either version 2 .\" of the License, or any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .\" .TH BITTWIST 1 "21 April 2012" .SH NAME .B bittwist \-- pcap based ethernet packet generator .SH SYNOPSIS .B bittwist [ .B \-dvh ] [ .B \-i .I interface ] [ .B \-s .I length ] [ .B \-l .I loop ] .ti +9 [ .B \-c .I count ] [ .B \-m .I speed ] [ .B \-r .I rate ] [ .B \-p .I sleep ] .ti +9 .I pcap-file(s) .SH DESCRIPTION This document describes the \fIbittwist\fP program, the \fIpcap\fP(3) based Ethernet packet generator. \fIBittwist\fP is designed to work under Ethernet II (IEEE 802.3) network with a MTU of up to 1500 bytes on 10Mbps (10Base-T Ethernet) or 100Mbps (Fast Ethernet) link speed. Packets are generated from saved \fItcpdump\fP(1) capture file referred to as trace file in this document. Some familiarity with \fItcpdump\fP(1) and its basic options are assumed in this document. Since \fIbittwist\fP uses functions provided by \fIpcap\fP(3) library, e.g. \fBpcap_open_live()\fP and \fBpcap_inject()\fP, to write packets onto the network, it may require that you have special privileges, e.g. read access to \fI/dev/bpf*\fP on BSD or root access on Linux, to generate packets or to enumerate network devices with, for example, the \fB-d\fP flag. .PP \fIBittwist\fP will, if not run with the \fB-s\fP flag, inject each packet up to its actual length (on-wire) instead of its captured length. If the captured length is less than the actual length, \fIbittwist\fP will pad the packet with zeros up to its actual length prior to injection. \fIBittwist\fP will, if not run with the \fB-m\fP, \fB-r\fP, or \fB-p\fP flag, inject packets from a trace file based on the captured intervals, in particular, the timestamp difference between two adjacent packets, except for the first packet in a trace file, which is always injected immediately. \fIBittwist\fP is designed to not to interfere with the packet data; it merely read a packet and inject it as is onto the network. If modification is desired prior to injection of a packet, you can use the \fIbittwiste\fP(1) program, which does just that. .SH OPTIONS .TP .B \-d Print a list of network interfaces available. .TP .B \-v Print timestamp for each packet. .TP .B \-vv Print timestamp and hex data for each packet. .TP .B \-i \fIinterface\fP Send \fIpcap-file(s)\fP out onto the network through \fIinterface\fP. .TP .B \-s \fIlength\fP Packet length to send. Set \fIlength\fP to: .IP .br 0 to send the actual packet length. This is the default. .br -1 to send the captured length. .IP or any other value from 14 to 1514. .TP .B \-l \fIloop\fP Send \fIpcap-file(s)\fP out onto the network for \fIloop\fP times. Set \fIloop\fP to 0 to send \fIpcap-file(s)\fP until stopped. To stop, type Control-C. .TP .B \-c \fIcount\fP Send up to \fIcount\fP packets. Default is to send all packets from \fIpcap-file(s)\fP. .TP .B \-m \fIspeed\fP Set interval multiplier to \fIspeed\fP. Set \fIspeed\fP to 0 or less to send the next packet immediately. Minimum positive value for \fIspeed\fP is 0.000001. .TP .B \-r \fIrate\fP Limit the sending to \fIrate\fP Mbps. Value for \fIrate\fP must be between 1 to 1000. This option is meant to limit the maximum packet throughput. If you want to send packets at line rate of 100Mbps, try -m 0 -r 100 .TP .B \-p \fIsleep\fP Set interval to \fIsleep\fP (in seconds), ignoring the actual interval. Value for \fIsleep\fP must be between 1 to 2146. .TP .B \-h Print version information and usage. .SH SEE ALSO bittwiste(1), pcap(3), tcpdump(1) .SH BUGS File your bug report and send to: .IP Addy Yeow Chin Heng .PP Make sure you are using the latest stable version before submitting your bug report. .PP If you run \fIbittwist\fP with \fB-m\fP flag set to 0 without limiting the throughput with \fB-r\fP flag, \fBpcap_inject\fP() may return an error with the following error string: .IP send: No buffer space available .PP We recommend that you specify the \fB-r\fP flag to limit the packet throughput, e.g. \fB-m\fP 0 \fB-r\fP 100 to inject packets at a maximum rate of 100Mbps. .SH COPYRIGHT Copyright (C) 2006 - 2012 Addy Yeow Chin Heng .PP This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. .PP This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. .PP You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .SH AUTHORS Original author and current maintainer: .IP Addy Yeow Chin Heng .PP The current version is available from http://bittwist.sourceforge.net bittwist-linux-2.0/doc/._bittwist.1.html000444 000765 000024 00000000342 11744746762 021250 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect1{{0, 0}, {1214, 720}}bittwist-linux-2.0/doc/bittwist.1.html000444 000765 000024 00000012777 11744746762 021052 0ustar00addyyeowstaff000000 000000
BITTWIST(1)                                                        BITTWIST(1)



NAME
       bittwist -- pcap based ethernet packet generator

SYNOPSIS
       bittwist [ -dvh ] [ -i interface ] [ -s length ] [ -l loop ]
                [ -c count ] [ -m speed ] [ -r rate ] [ -p sleep ]
                pcap-file(s)

DESCRIPTION
       This  document describes the bittwist program, the pcap(3) based Ether-
       net packet generator. Bittwist is designed to work  under  Ethernet  II
       (IEEE 802.3) network with a MTU of up to 1500 bytes on 10Mbps (10Base-T
       Ethernet) or 100Mbps (Fast Ethernet) link speed. Packets are  generated
       from  saved  tcpdump(1)  capture file referred to as trace file in this
       document. Some familiarity with tcpdump(1) and its  basic  options  are
       assumed  in  this  document.  Since bittwist uses functions provided by
       pcap(3) library, e.g.  pcap_open_live()  and  pcap_inject(),  to  write
       packets  onto  the network, it may require that you have special privi-
       leges, e.g. read access to /dev/bpf* on BSD or root access on Linux, to
       generate packets or to enumerate network devices with, for example, the
       -d flag.

       Bittwist will, if not run with the -s flag, inject each  packet  up  to
       its actual length (on-wire) instead of its captured length. If the cap-
       tured length is less than the actual  length,  bittwist  will  pad  the
       packet  with zeros up to its actual length prior to injection. Bittwist
       will, if not run with the -m, -r, or -p flag,  inject  packets  from  a
       trace  file  based  on the captured intervals, in particular, the time-
       stamp difference between two adjacent packets,  except  for  the  first
       packet  in a trace file, which is always injected immediately. Bittwist
       is designed to not to interfere with the packet data; it merely read  a
       packet and inject it as is onto the network. If modification is desired
       prior to injection of a packet, you can use the  bittwiste(1)  program,
       which does just that.

OPTIONS
       -d     Print a list of network interfaces available.

       -v     Print timestamp for each packet.

       -vv    Print timestamp and hex data for each packet.

       -i interface
              Send pcap-file(s) out onto the network through interface.

       -s length
              Packet length to send. Set length to:

              0 to send the actual packet length. This is the default.
              -1 to send the captured length.

              or any other value from 14 to 1514.

       -l loop
              Send  pcap-file(s) out onto the network for loop times. Set loop
              to 0 to send pcap-file(s) until stopped. To stop, type  Control-
              C.

       -c count
              Send  up  to  count packets. Default is to send all packets from
              pcap-file(s).

       -m speed
              Set interval multiplier to speed. Set speed to 0 or less to send
              the next packet immediately. Minimum positive value for speed is
              0.000001.

       -r rate
              Limit the sending to rate Mbps. Value for rate must be between 1
              to  1000.  This  option  is  meant  to  limit the maximum packet
              throughput.  If you  want  to  send  packets  at  line  rate  of
              100Mbps, try -m 0 -r 100

       -p sleep
              Set  interval  to sleep (in seconds), ignoring the actual inter-
              val. Value for sleep must be between 1 to 2146.

       -h     Print version information and usage.

SEE ALSO
       bittwiste(1), pcap(3), tcpdump(1)

BUGS
       File your bug report and send to:

              Addy Yeow Chin Heng <ayeowch@gmail.com>

       Make sure you are using the latest  stable  version  before  submitting
       your bug report.

       If you run bittwist with -m flag set to 0 without limiting the through-
       put with -r flag, pcap_inject() may return an error with the  following
       error string:

              send: No buffer space available

       We  recommend that you specify the -r flag to limit the packet through-
       put, e.g. -m 0 -r 100 to inject packets at a maximum rate of 100Mbps.

COPYRIGHT
       Copyright (C) 2006 - 2012 Addy Yeow Chin Heng <ayeowch@gmail.com>

       This program is free software; you can redistribute it and/or modify it
       under  the  terms of the GNU General Public License as published by the
       Free Software Foundation; either version 2 of the License, or any later
       version.

       This  program  is  distributed  in the hope that it will be useful, but
       WITHOUT ANY  WARRANTY;  without  even  the  implied  warranty  of  MER-
       CHANTABILITY  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
       Public License for more details.

       You should have received a copy of the GNU General Public License along
       with this program; if not, write to the Free Software Foundation, Inc.,
       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

AUTHORS
       Original author and current maintainer:

              Addy Yeow Chin Heng

       The current version is available from http://bittwist.sourceforge.net



                                 21 April 2012                     BITTWIST(1)
bittwist-linux-2.0/doc/._bittwiste.1000444 000765 000024 00000000341 11744746762 020451 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect1{{0, 0}, {964, 720}}bittwist-linux-2.0/doc/bittwiste.1000444 000765 000024 00000031625 11744746762 020245 0ustar00addyyeowstaff000000 000000 .\" .\" bittwiste.1 - manpage for the bittwiste program .\" Copyright (C) 2006 - 2012 Addy Yeow Chin Heng .\" .\" This program is free software; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License .\" as published by the Free Software Foundation; either version 2 .\" of the License, or any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .\" .TH BITTWISTE 1 "21 April 2012" .SH NAME .B bittwiste \-- pcap capture file editor .SH SYNOPSIS .B bittwiste [ .B \-I .I input ] [ .B \-O .I output ] [ .B \-L .I layer ] [ .B \-X .I payload ] .ti +10 [ .B -C ] [ .B \-M .I linktype ] [ .B \-D .I offset ] [ .B \-R .I range ] .ti +10 [ .B \-S .I timeframe ] [ .B \-T .I header ] .ti +10 [ .I header-specific-options ] [ .B \-h ] .SH DESCRIPTION This document describes the \fIbittwiste\fP program, the \fIpcap\fP(3) capture file editor. \fIBittwiste\fP is designed to work only with Ethernet frame, e.g. link type DLT_EN10MB in \fIpcap\fP(3), with a maximum frame size of 1514 bytes which is equivalent to a MTU of 1500 bytes, 14 bytes for Ethernet header. .PP \fIBittwiste\fP can currently edit Ethernet, ARP, IP, ICMP, TCP, and UDP headers. If run with the \fB-X\fP flag, you can append your own payload after any of these headers; specified using the \fB-L\fP and \fB-T\fP flag. \fIBittwiste\fP will, if not run with the \fB-C\fP flag, recalculate the checksums for IP, ICMP, TCP, and UDP packets, except for the last fragment of a fragmented IP datagram; \fIbittwiste\fP does not currently support checksum correction for the last fragment of a fragmented IP datagram. While parsing the packets in a trace file, \fIbittwiste\fP will skip, i.e. write to output file as is, any truncated packet, for example, an ICMP packet with a captured length of 25 bytes (we need at least 28 bytes; 14 bytes for Ethernet header, minimum 20 bytes for IP header, and 4 bytes for ICMP header) does not give enough information on its ICMP header for \fIbittwiste\fP to read and modify it. In this case, you can utilize the \fB-L\fP and \fB-T\fP flag to copy the original packet up to its IP header and append your customized ICMP header and data to the packet using the \fB-X\fP flag. When specifying payload that covers the ICMP, TCP or UDP header and its data, you can use zeros, e.g. 0000 for 2 bytes of zeros, for the header checksum which is then corrected automatically by \fIbittwiste\fP. .PP In order to simplify the way options are specified, you can only edit packets of a specific type supplied to the \fB-T\fP flag per execution of \fIbittwiste\fP on a trace file. In addition, the \fB-T\fP flag must appear last among the general options which are the \fB-I\fP, \fB-O\fP, \fB-L\fP, \fB-X\fP, \fB-C\fP, \fB-M\fP, \fB-D\fP, \fB-R\fP and \fB-S\fP flag. .SH OPTIONS .TP .B \-I \fIinput\fP Input pcap based trace file. .TP .B \-O \fIoutput\fP Output trace file. .TP .B \-L \fIlayer\fP Copy up to the specified \fIlayer\fP and discard the remaining data. Value for \fIlayer\fP must be either 2, 3 or 4 where 2 for Ethernet, 3 for ARP or IP, and 4 for ICMP, TCP or UDP. .TP .B \-X \fIpayload\fP Append \fIpayload\fP in hex digits to the end of each packet. .br Example: \fB-X\fP 0302aad1 .br \fB-X\fP flag is ignored if \fB-L\fP and \fB-T\fP flag are not specified. .TP .B \-C Specify this flag to disable checksum correction. Checksum correction is applicable for non-fragmented IP, ICMP, TCP, and UDP packets only. .TP .B \-M \fIlinktype\fP Replace the \fIlinktype\fP stored in the pcap file header. Typically, value for \fIlinktype\fP is 1 for Ethernet. .br Example: -M 12 (for raw IP), -M 51 (for PPPoE) .IP For the complete list, see: .br \fIhttp://www.tcpdump.org/linktypes.html\fP .TP .B \-D \fIoffset\fP Delete the specified byte \fIoffset\fP from each packet. .br First byte (starting from link layer header) starts from 1. .br \fB-L\fP, \fB-X\fP, \fB-C\fP and \fB-T\fP flag are ignored if \fB-D\fP flag is specified. .br Example: \fB-D\fP 15-40, \fB-D\fP 10 or \fB-D\fP 18-9999 .TP .B \-R \fIrange\fP Save only the specified \fIrange\fP of packets. .br Example: \fB-R\fP 5-21 or \fB-R\fP 9 .TP .B \-S \fItimeframe\fP Save only the packets within the specified \fItimeframe\fP with up to one-second resolution using DD/MM/YYYY,HH:MM:SS as the format for start and end time in \fItimeframe\fP. .br Example: \fB-S\fP 22/10/2006,21:47:35-24/10/2006,13:16:05 .br \fB-S\fP flag is evaluated after \fB-R\fP flag. .TP .B \-T \fIheader\fP Edit only the specified \fIheader\fP. Possible keywords for \fIheader\fP are, \fBeth\fP, \fBarp\fP, \fBip\fP, \fBicmp\fP, \fBtcp\fP, or \fBudp\fP. \fB-T\fP flag must appear last among the general options. .TP .B \-h Print version information and usage. .TP \fIheader-specific-options\fP Each packet that matches the type supplied to the \fB-T\fP flag is modified based on the options described below: .IP Options for \fBeth\fP (RFC 894): .RS .TP .B \-d \fIdmac\fP or \fIomac\fP,\fInmac\fP .br Destination MAC address. Example: \fB-d\fP 00:08:55:64:65:6a .br If \fIomac\fP and \fInmac\fP are specified instead, all occurences of \fIomac\fP in the destination MAC address field will be replaced with \fInmac\fP. .TP .B \-s \fIsmac\fP or \fIomac\fP,\fInmac\fP .br Source MAC address. Example: \fB-s\fP 00:13:20:3e:ab:cf .br If \fIomac\fP and \fInmac\fP are specified instead, all occurences of \fIomac\fP in the source MAC address field will be replaced with \fInmac\fP. .TP .B \-t \fItype\fP EtherType. Possible keywords for type are, \fBip\fP and \fBarp\fP only. .TP Options for \fBarp\fP (RFC 826): .TP .B \-o \fIopcode\fP Operation code in integer value between 0 to 65535. For example, you can set \fIopcode\fP to 1 for ARP request, 2 for ARP reply. .TP .B \-s \fIsmac\fP or \fIomac\fP,\fInmac\fP .br Sender MAC address. Example: \fB-s\fP 00:13:20:3e:ab:cf .br If \fIomac\fP and \fInmac\fP are specified instead, all occurences of \fIomac\fP in the sender MAC address field will be replaced with \fInmac\fP. .TP .B \-p \fIsip\fP or \fIoip\fP,\fInip\fP .br Sender IP address. Example: \fB-p\fP 192.168.0.1 .br If \fIoip\fP and \fInip\fP are specified instead, all occurences of \fIoip\fP in the sender IP address field will be replaced with \fInip\fP. .TP .B \-t \fItmac\fP or \fIomac\fP,\fInmac\fP .br Target MAC address. Example: \fB-t\fP 00:08:55:64:65:6a .br If \fIomac\fP and \fInmac\fP are specified instead, all occurences of \fIomac\fP in the target MAC address field will be replaced with \fInmac\fP. .TP .B \-q \fItip\fP or \fIoip\fP,\fInip\fP .br Target IP address. Example: \fB-q\fP 192.168.0.2 .br If \fIoip\fP and \fInip\fP are specified instead, all occurences of \fIoip\fP in the target IP address field will be replaced with \fInip\fP. .TP Options for \fBip\fP (RFC 791): .TP .B \-i \fIid\fP .br Identification in integer value between 0 to 65535. .TP .B \-f \fIflags\fP Control flags. Possible characters for \fIflags\fP are: .IP \fB-\fP : remove all flags .br \fBr\fP : set the reserved flag .br \fBd\fP : set the don't fragment flag .br \fBm\fP : set the more fragment flag .IP Example: \fB-f d\fP .br If any of the flags is specified, all original flags are removed automatically. .TP .B \-o \fIoffset\fP Fragment offset in integer value between 0 to 7770. Value for \fIoffset\fP represents the number of 64-bit segments contained in earlier fragments which must not exceed 7770 (62160 bytes). .TP .B \-t \fIttl\fP .br Time to live in integer value between 0 to 255 (milliseconds). .TP .B \-p \fIproto\fP Protocol number in integer value between 0 to 255. Some common protocol numbers are: .IP \fB1\fP : Internet Control Message Protocol (ICMP) .br \fB6\fP : Transmission Control Protocol (TCP) .br \fB17\fP : User Datagram Protocol (UDP) .IP For the complete list, see: .br \fIhttp://www.iana.org/assignments/protocol-numbers\fP .TP .B \-s \fIsip\fP or \fIoip\fP,\fInip\fP .br Source IP address. Example: \fB-s\fP 192.168.0.1 .br If \fIoip\fP and \fInip\fP are specified instead, all occurences of \fIoip\fP in the source IP address field will be replaced with \fInip\fP. .TP .B \-d \fIdip\fP or \fIoip\fP,\fInip\fP .br Destination IP address. Example: \fB-d\fP 192.168.0.2 .br If \fIoip\fP and \fInip\fP are specified instead, all occurences of \fIoip\fP in the destination IP address field will be replaced with \fInip\fP. .TP Options for \fBicmp\fP (RFC 792): .TP .B \-t \fItype\fP Type of message in integer value between 0 to 255. Some common messages are: .IP \fB0\fP : Echo reply .br \fB3\fP : Destination unreachable .br \fB8\fP : Echo .br \fB11\fP : Time exceeded .IP For the complete list, see: .br \fIhttp://www.iana.org/assignments/icmp-parameters\fP .TP .B \-c \fIcode\fP Error code for this ICMP message in integer value between 0 to 255. For example, \fIcode\fP for \fBtime exceeded\fP message may have one of the following values: .IP \fB0\fP : transit TTL exceeded .br \fB1\fP : reassembly TTL exceeded .IP For the complete list, see: .br \fIhttp://www.iana.org/assignments/icmp-parameters\fP .TP Options for \fBtcp\fP (RFC 793): .TP .B \-s\fP \fIsport\fP or \fIop\fP,\fInp\fP Source port number in integer value between 0 to 65535. If \fIop\fP and \fInp\fP are specified instead, all occurrences of \fIop\fP in the source port field will be replaced with \fInp\fP. .TP .B \-d\fP \fIdport\fP or \fIop\fP,\fInp\fP Destination port number in integer value between 0 to 65535. If \fIop\fP and \fInp\fP are specified instead, all occurrences of \fIop\fP in the destination port field will be replaced with \fInp\fP. .TP .B \-q \fIseq\fP .br Sequence number in integer value between 0 to 4294967295. If SYN control bit is set, e.g. character \fBs\fP is supplied to the \fB-f\fP flag, \fIseq\fP represents the initial sequence number (ISN) and the first data byte is ISN + 1. .TP .B \-a \fIack\fP .br Acknowledgment number in integer value between 0 to 4294967295. If ACK control bit is set, e.g. character \fBa\fP is supplied to the \fB-f\fP flag, \fIack\fP represents the value of the next sequence number that the receiver is expecting to receive. .TP .B \-f \fIflags\fP Control flags. Possible characters for \fIflags\fP are: .IP \fB-\fP : remove all flags .br \fBu\fP : urgent pointer field is significant .br \fBa\fP : acknowledgment field is significant .br \fBp\fP : push function .br \fBr\fP : resets the connection .br \fBs\fP : synchronizes the sequence numbers .br \fBf\fP : no more data from sender .IP Example: \fB-f s\fP .br If any of the flags is specified, all original flags are removed automatically. .TP .B \-w \fIwin\fP .br Window size in integer value between 0 to 65535. If ACK control bit is set, e.g. character \fBa\fP is supplied to the \fB-f\fP flag, \fIwin\fP represents the number of data bytes, beginning with the one indicated in the acknowledgment number field that the receiver is willing to accept. .TP .B \-u \fIurg\fP .br Urgent pointer in integer value between 0 to 65535. If URG control bit is set, e.g. character \fBu\fP is supplied to the \fB-f\fP flag, \fIurg\fP represents a pointer that points to the first data byte following the urgent data. .TP Options for \fBudp\fP (RFC 768): .TP .B \-s\fP \fIsport\fP or \fIop\fP,\fInp\fP Source port number in integer value between 0 to 65535. If \fIop\fP and \fInp\fP are specified instead, all occurrences of \fIop\fP in the source port field will be replaced with \fInp\fP. .TP .B \-d\fP \fIdport\fP or \fIop\fP,\fInp\fP Destination port number in integer value between 0 to 65535. If \fIop\fP and \fInp\fP are specified instead, all occurrences of \fIop\fP in the destination port field will be replaced with \fInp\fP. .RE .SH SEE ALSO bittwist(1), pcap(3), tcpdump(1) .SH BUGS File your bug report and send to: .IP Addy Yeow Chin Heng .PP Make sure you are using the latest stable version before submitting your bug report. .SH COPYRIGHT Copyright (C) 2006 - 2012 Addy Yeow Chin Heng .PP This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. .PP This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. .PP You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .SH AUTHORS Original author and current maintainer: .IP Addy Yeow Chin Heng .PP The current version is available from http://bittwist.sourceforge.net bittwist-linux-2.0/doc/._bittwiste.1.html000444 000765 000024 00000000342 11744746762 021415 0ustar00addyyeowstaff000000 000000 Mac OS X  2ATTRcom.macromates.selectionRangecom.macromates.visibleRect1{{0, 0}, {1214, 720}}bittwist-linux-2.0/doc/bittwiste.1.html000444 000765 000024 00000034600 11744746762 021204 0ustar00addyyeowstaff000000 000000
BITTWISTE(1)                                                      BITTWISTE(1)



NAME
       bittwiste -- pcap capture file editor

SYNOPSIS
       bittwiste [ -I input ] [ -O output ] [ -L layer ] [ -X payload ]
                 [ -C ] [ -M linktype ] [ -D offset ] [ -R range ]
                 [ -S timeframe ] [ -T header ]
                 [ header-specific-options ] [ -h ]

DESCRIPTION
       This document describes the bittwiste program, the pcap(3) capture file
       editor. Bittwiste is designed to work only with  Ethernet  frame,  e.g.
       link  type  DLT_EN10MB  in  pcap(3),  with a maximum frame size of 1514
       bytes which is equivalent to a MTU of 1500 bytes, 14 bytes for Ethernet
       header.

       Bittwiste  can  currently  edit  Ethernet,  ARP, IP, ICMP, TCP, and UDP
       headers. If run with the -X flag, you can append your own payload after
       any  of  these  headers;  specified using the -L and -T flag. Bittwiste
       will, if not run with the -C flag, recalculate the  checksums  for  IP,
       ICMP,  TCP,  and  UDP  packets, except for the last fragment of a frag-
       mented IP datagram; bittwiste does not currently support checksum  cor-
       rection  for the last fragment of a fragmented IP datagram. While pars-
       ing the packets in a trace file, bittwiste will  skip,  i.e.  write  to
       output  file  as  is, any truncated packet, for example, an ICMP packet
       with a captured length of 25 bytes (we need at least 28 bytes; 14 bytes
       for  Ethernet  header,  minimum 20 bytes for IP header, and 4 bytes for
       ICMP header) does not give enough information on its  ICMP  header  for
       bittwiste  to  read and modify it. In this case, you can utilize the -L
       and -T flag to copy the original packet up to its IP header and  append
       your  customized  ICMP header and data to the packet using the -X flag.
       When specifying payload that covers the ICMP, TCP or UDP header and its
       data, you can use zeros, e.g. 0000 for 2 bytes of zeros, for the header
       checksum which is then corrected automatically by bittwiste.

       In order to simplify the way options are specified, you can  only  edit
       packets  of  a  specific  type supplied to the -T flag per execution of
       bittwiste on a trace file. In addition, the -T flag  must  appear  last
       among  the general options which are the -I, -O, -L, -X, -C, -M, -D, -R
       and -S flag.

OPTIONS
       -I input
              Input pcap based trace file.

       -O output
              Output trace file.

       -L layer
              Copy up to the specified layer and discard the  remaining  data.
              Value for layer must be either 2, 3 or 4 where 2 for Ethernet, 3
              for ARP or IP, and 4 for ICMP, TCP or UDP.

       -X payload
              Append payload in hex digits to the end of each packet.
              Example: -X 0302aad1
              -X flag is ignored if -L and -T flag are not specified.

       -C     Specify this flag to disable checksum correction. Checksum  cor-
              rection  is applicable for non-fragmented IP, ICMP, TCP, and UDP
              packets only.

       -M linktype
              Replace the linktype stored in the pcap file header.  Typically,
              value for linktype is 1 for Ethernet.
              Example: -M 12 (for raw IP), -M 51 (for PPPoE)

              For the complete list, see:
              http://www.tcpdump.org/linktypes.html

       -D offset
              Delete the specified byte offset from each packet.
              First byte (starting from link layer header) starts from 1.
              -L, -X, -C and -T flag are ignored if -D flag is specified.
              Example: -D 15-40, -D 10 or -D 18-9999

       -R range
              Save only the specified range of packets.
              Example: -R 5-21 or -R 9

       -S timeframe
              Save  only the packets within the specified timeframe with up to
              one-second resolution using DD/MM/YYYY,HH:MM:SS  as  the  format
              for start and end time in timeframe.
              Example: -S 22/10/2006,21:47:35-24/10/2006,13:16:05
              -S flag is evaluated after -R flag.

       -T header
              Edit  only  the  specified  header. Possible keywords for header
              are, eth, arp, ip, icmp, tcp, or udp. -T flag must  appear  last
              among the general options.

       -h     Print version information and usage.

       header-specific-options
              Each  packet  that  matches  the type supplied to the -T flag is
              modified based on the options described below:

              Options for eth (RFC 894):

              -d dmac or omac,nmac
                     Destination MAC address. Example: -d 00:08:55:64:65:6a
                     If omac and nmac are specified instead, all occurences of
                     omac  in  the  destination  MAC  address  field  will  be
                     replaced with nmac.

              -s smac or omac,nmac
                     Source MAC address. Example: -s 00:13:20:3e:ab:cf
                     If omac and nmac are specified instead, all occurences of
                     omac  in  the  source  MAC address field will be replaced
                     with nmac.

              -t type
                     EtherType. Possible keywords for type  are,  ip  and  arp
                     only.

              Options for arp (RFC 826):

              -o opcode
                     Operation  code  in integer value between 0 to 65535. For
                     example, you can set opcode to 1 for ARP request,  2  for
                     ARP reply.

              -s smac or omac,nmac
                     Sender MAC address. Example: -s 00:13:20:3e:ab:cf
                     If omac and nmac are specified instead, all occurences of
                     omac in the sender MAC address  field  will  be  replaced
                     with nmac.

              -p sip or oip,nip
                     Sender IP address. Example: -p 192.168.0.1
                     If  oip  and nip are specified instead, all occurences of
                     oip in the sender IP address field will be replaced  with
                     nip.

              -t tmac or omac,nmac
                     Target MAC address. Example: -t 00:08:55:64:65:6a
                     If omac and nmac are specified instead, all occurences of
                     omac in the target MAC address  field  will  be  replaced
                     with nmac.

              -q tip or oip,nip
                     Target IP address. Example: -q 192.168.0.2
                     If  oip  and nip are specified instead, all occurences of
                     oip in the target IP address field will be replaced  with
                     nip.

              Options for ip (RFC 791):

              -i id
                     Identification in integer value between 0 to 65535.

              -f flags
                     Control flags. Possible characters for flags are:

                     - : remove all flags
                     r : set the reserved flag
                     d : set the don’t fragment flag
                     m : set the more fragment flag

                     Example: -f d
                     If  any of the flags is specified, all original flags are
                     removed automatically.

              -o offset
                     Fragment offset in integer value between 0 to 7770. Value
                     for  offset represents the number of 64-bit segments con-
                     tained in earlier fragments which must  not  exceed  7770
                     (62160 bytes).

              -t ttl
                     Time to live in integer value between 0 to 255 (millisec-
                     onds).

              -p proto
                     Protocol number in integer value between 0 to  255.  Some
                     common protocol numbers are:

                     1  : Internet Control Message Protocol (ICMP)
                     6  : Transmission Control Protocol (TCP)
                     17 : User Datagram Protocol (UDP)

                     For the complete list, see:
                     http://www.iana.org/assignments/protocol-numbers

              -s sip or oip,nip
                     Source IP address. Example: -s 192.168.0.1
                     If  oip  and nip are specified instead, all occurences of
                     oip in the source IP address field will be replaced  with
                     nip.

              -d dip or oip,nip
                     Destination IP address. Example: -d 192.168.0.2
                     If  oip  and nip are specified instead, all occurences of
                     oip in the destination IP address field will be  replaced
                     with nip.

              Options for icmp (RFC 792):

              -t type
                     Type  of  message in integer value between 0 to 255. Some
                     common messages are:

                     0  : Echo reply
                     3  : Destination unreachable
                     8  : Echo
                     11 : Time exceeded

                     For the complete list, see:
                     http://www.iana.org/assignments/icmp-parameters

              -c code
                     Error code for this ICMP message in integer value between
                     0 to 255. For example, code for time exceeded message may
                     have one of the following values:

                     0 : transit TTL exceeded
                     1 : reassembly TTL exceeded

                     For the complete list, see:
                     http://www.iana.org/assignments/icmp-parameters

              Options for tcp (RFC 793):

              -s sport or op,np
                     Source port number in integer value between 0  to  65535.
                     If op and np are specified instead, all occurrences of op
                     in the source port field will be replaced with np.

              -d dport or op,np
                     Destination port number in integer  value  between  0  to
                     65535.  If  op  and  np are specified instead, all occur-
                     rences of op  in  the  destination  port  field  will  be
                     replaced with np.

              -q seq
                     Sequence number in integer value between 0 to 4294967295.
                     If SYN control bit is set, e.g. character s  is  supplied
                     to  the -f flag, seq represents the initial sequence num-
                     ber (ISN) and the first data byte is ISN + 1.

              -a ack
                     Acknowledgment number  in  integer  value  between  0  to
                     4294967295.  If  ACK control bit is set, e.g. character a
                     is supplied to the -f flag, ack represents the  value  of
                     the  next  sequence number that the receiver is expecting
                     to receive.

              -f flags
                     Control flags. Possible characters for flags are:

                     - : remove all flags
                     u : urgent pointer field is significant
                     a : acknowledgment field is significant
                     p : push function
                     r : resets the connection
                     s : synchronizes the sequence numbers
                     f : no more data from sender

                     Example: -f s
                     If any of the flags is specified, all original flags  are
                     removed automatically.

              -w win
                     Window  size  in integer value between 0 to 65535. If ACK
                     control bit is set, e.g. character a is supplied  to  the
                     -f  flag, win represents the number of data bytes, begin-
                     ning with the one indicated in the acknowledgment  number
                     field that the receiver is willing to accept.

              -u urg
                     Urgent  pointer  in  integer value between 0 to 65535. If
                     URG control bit is set, e.g. character u is  supplied  to
                     the  -f flag, urg represents a pointer that points to the
                     first data byte following the urgent data.

              Options for udp (RFC 768):

              -s sport or op,np
                     Source port number in integer value between 0  to  65535.
                     If op and np are specified instead, all occurrences of op
                     in the source port field will be replaced with np.

              -d dport or op,np
                     Destination port number in integer  value  between  0  to
                     65535.  If  op  and  np are specified instead, all occur-
                     rences of op  in  the  destination  port  field  will  be
                     replaced with np.

SEE ALSO
       bittwist(1), pcap(3), tcpdump(1)

BUGS
       File your bug report and send to:

              Addy Yeow Chin Heng <ayeowch@gmail.com>

       Make  sure  you  are  using the latest stable version before submitting
       your bug report.

COPYRIGHT
       Copyright (C) 2006 - 2012 Addy Yeow Chin Heng <ayeowch@gmail.com>

       This program is free software; you can redistribute it and/or modify it
       under  the  terms of the GNU General Public License as published by the
       Free Software Foundation; either version 2 of the License, or any later
       version.

       This  program  is  distributed  in the hope that it will be useful, but
       WITHOUT ANY  WARRANTY;  without  even  the  implied  warranty  of  MER-
       CHANTABILITY  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
       Public License for more details.

       You should have received a copy of the GNU General Public License along
       with this program; if not, write to the Free Software Foundation, Inc.,
       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

AUTHORS
       Original author and current maintainer:

              Addy Yeow Chin Heng

       The current version is available from http://bittwist.sourceforge.net



                                 21 April 2012                    BITTWISTE(1)