summaryrefslogtreecommitdiff
path: root/trafgen.8
diff options
context:
space:
mode:
Diffstat (limited to 'trafgen.8')
-rw-r--r--trafgen.8445
1 files changed, 445 insertions, 0 deletions
diff --git a/trafgen.8 b/trafgen.8
new file mode 100644
index 0000000..6ead20c
--- /dev/null
+++ b/trafgen.8
@@ -0,0 +1,445 @@
+.\" netsniff-ng - the packet sniffing beast
+.\" Copyright 2013 Daniel Borkmann.
+.\" Subject to the GPL, version 2.
+
+.TH TRAFGEN 8 "03 March 2013" "Linux" "netsniff-ng toolkit"
+.SH NAME
+trafgen \- a fast, multithreaded network packet generator
+
+.SH SYNOPSIS
+
+\fB trafgen\fR [\fIoptions\fR]
+
+.SH DESCRIPTION
+
+trafgen is a fast, zero-copy network traffic generator for debugging,
+performance evaluation and fuzz-testing purposes. trafgen utilizes the packet(7)
+socket interface of Linux which postpones complete control over packet data
+and packet headers into the user space. It has a powerful packet configuration
+language, which is rather low-level and not limited to particular protocols.
+Thus, trafgen can be used for many purposes. Its only limitation is that it
+cannot mimic full streams resp. sessions. However, it is very useful for
+various kinds of load testing in order to analyze and subsequently improve
+systems behaviour under DoS attack scenarios, for instance.
+
+trafgen is Linux specific only, meaning there is no support for other operating
+systems just as in netsniff-ng(8), thus we can keep the code footprint quite
+minimal and to the point. trafgen makes use of packet(7) socket's TX_RING
+interface of the Linux kernel, which is a mmap(2)'ed ring buffer shared between
+user and kernel space.
+
+On default, trafgen starts as many processes as CPUs that are online, pins each
+of them to their respective CPU and sets up the ring buffer each in their own
+process space after having compiled a list of packets to transmit. Thus, this is
+likely the fastest one can get out of the box in terms of transmission performance
+from user space, without having to load unsupported or non-mainline third-party
+kernel modules. On Gigabit Ethernet, trafgen has a comparable performance to
+pktgen, the built-in Linux kernel traffic generator, only that trafgen is more
+flexible in terms of packet configuration possibilities. On 10-Gigabit-per-second
+Ethernet, trafgen might be slower than pktgen due to the user/kernel space
+overhead but still has a fairly high performance for out of the box kernels.
+
+trafgen has a possibility to do fuzz testing, meaning a packet configuration can
+be built with random numbers on all or certain packet offsets that are freshly
+generated each time a packet is sent out. With a built-in IPv4 ping, trafgen can
+send out an ICMP probe after each packet injection to the remote host in order
+to test if it is still responsive/alive. Assuming there is no answer from the
+remote host after a certain threshold of probes, the machine is considered dead
+and the last sent packet is printed together with the random seed that was used
+by trafgen. You might not really get lucky fuzz-testing the Linux kernel, but
+presumably there are buggy closed-source embedded systems or network driver's
+firmware files that are prone to bugs, where trafgen could help in finding them.
+
+trafgen's configuration language is quite powerful, also due to the fact, that
+it supports C preprocessor macros. A stddef.h is being shipped with trafgen for
+this purpose, so that well known defines from Linux kernel or network programming
+can be reused. After a configuration file has passed the C preprocessor stage,
+it is processed by the trafgen packet compiler. The language itself supports a
+couple of features that are useful when assembling packets, such as built-in
+runtime checksum support for IP, UDP and TCP. Also it has an expression evaluator
+where arithmetic (basic operations, bit operations, bit shifting, ...) on constant
+expressions is being reduced to a single constant on compile time. Other features
+are ``fill'' macros, where a packet can be filled with n bytes by a constant, a
+compile-time random number or run-time random number (as mentioned with fuzz
+testing). Also, netsniff-ng(8) is able to convert a pcap file into a trafgen
+configuration file, thus such a configuration can then be further tweaked for a
+given scenario.
+
+.SH OPTIONS
+
+.SS -i <cfg|->, -c <cfg|i>, --in <cfg|->, --conf <cfg|->
+Defines the input configuration file that can either be passed as a normal plain
+text file or via stdin (``-''). Note that currently in case a configuration is
+passed through stdin, only 1 CPU will be used.
+
+.SS -o <dev>, -d <dev>, --out <dev>, --dev <dev>
+Defines the outgoing networking device such as eth0, wlan0 and others.
+
+.SS -p, --cpp
+Pass the packet configuration to
+
+.SS -J, --jumbo-support
+On default trafgen's ring buffer frames are of a fixed size of 2048 bytes.
+This means that if you're expecting jumbo frames or even super jumbo frames to
+pass your line, then you need to enable support for that with the help of this
+option. However, this has the disadvantage of a performance regression and a
+bigger memory footprint for the ring buffer.
+
+.SS -R, --rfraw
+In case the output networking device is a wireless device, it is possible with
+trafgen to turn this into monitor mode and create a mon<X> device that trafgen
+will be transmitting on instead of wlan<X>, for instance. This enables trafgen
+to inject raw 802.11 frames.
+
+.SS -s <ipv4>, --smoke-test <ipv4>
+In case this option is enabled, trafgen will perform a smoke test. In other
+words, it will probe the remote end, specified by an <ipv4> address, that is
+being ``attacked'' with trafgen network traffic, if it is still alive and
+responsive. That means, after each transmitted packet that has been configured,
+trafgen sends out ICMP echo requests and waits for an answer before it continues.
+In case the remote end stays unresponsive, trafgen assumes that the machine
+has crashed and will print out the content of the last packet as a trafgen
+packet configuration and the random seed that has been used in order to
+reproduce a possible bug. This might be useful when testing proprietary embedded
+devices. It is recommended to have a direct link between the host running
+trafgen and the host being attacked by trafgen.
+
+.SS -n <0|uint>, --num <0|uint>
+Process a number of packets and then exit. If the number of packets is 0, then
+this is equivalent to infinite packets resp. processing until interrupted.
+Otherwise, a number given as an unsigned integer will limit processing.
+
+.SS -r, --rand
+Randomize the packet selection of the configuration file. On default, if more
+than one packet is defined in a packet configuration, packets are scheduled for
+transmission in a round robin fashion. With this option, they are selected
+randomly instread.
+
+.SS -P <uint>, --cpus <uint>
+Specify the number of processes trafgen shall fork(2) off. On default trafgen
+will start as many processes as CPUs that are online and pin them to each,
+respectively. Allowed value must be within interval [1,CPUs].
+
+.SS -t <uint>, --gap <uint>
+Specify a static inter-packet timegap in micro-seconds. If this option is given,
+then instead of packet(7)'s TX_RING interface, trafgen will use sendto(2) I/O
+for network packets, even if the <uint> argument is 0. This option is useful for
+a couple of reasons: i) comparison between sendto(2) and TX_RING performance,
+ii) low-traffic packet probing for a given interval, iii) ping-like debugging
+with specific payload patterns. Furthermore, the TX_RING interface does not cope
+with interpacket gaps.
+
+.SS -S <size>, --ring-size <size>
+Manually define the RX_RING resp. TX_RING size in ``<num>KiB/MiB/GiB''. On
+default the size is being determined based on the network connectivity rate.
+
+.SS -k <uint>, --kernel-pull <uint>
+Manually define the interval in micro-seconds where the kernel should be triggered
+to batch process the ring buffer frames. On default, it is every 10us, but it can
+manually be prolonged, for instance..
+
+.SS -E <uint>, --seed <uint>
+Manually set the seed for trafgen. On default, a random seed from /dev/urandom
+is being used to feed glibc's pseudo random number generator. If that fails, it
+falls back to the unix timestamp. It can be useful to set it up manually to be
+able to reproduce a trafgen session, e.g. after fuzz testing.
+
+.SS -u <uid>, --user <uid> resp. -g <gid>, --group <gid>
+After ring setup drop privileges to a non-root user/group combination.
+
+.SS -V, --verbose
+Let trafgen be more talkative and let it print the parsed configuration and
+some ring buffer statistics.
+
+.SS -e, --example
+Show a built-in packet configuration example. This might be a good starting
+point for an initial packet configuration scenario.
+
+.SS -v, --version
+Show versioning information.
+
+.SS -h, --help
+Show user help.
+
+.SH SYNTAX
+trafgen's packet configuration syntax is fairly simple. The very basic things
+one need to know is that a configuration file is a simple plain text file
+where packets are defined. It can contain one or more packets. Packet are
+enclosed by opening '{' and closing '}' braces, for example:
+
+ { /* packet 1 content goes here ... */ }
+ { /* packet 2 content goes here ... */ }
+
+When trafgen is started using multiple CPUs (default), then each of those packets
+will be scheduled for transmission on all CPUs on default. However, it is possible
+to tell trafgen to schedule a packet only on a particular CPU:
+
+ cpu(1): { /* packet 1 content goes here ... */ }
+ cpu(2-3): { /* packet 2 content goes here ... */ }
+
+Thus, in case we have a 4 core machine with CPU0-CPU3, packet 1 will be scheduled
+only on CPU1, packet 2 on CPU2 and CPU3. When using trafgen with --num option,
+then these constraints will still be valid and the packet is fairly distributed
+among those CPUs.
+
+Packet content is delimited either by a comma or whitespace, or both:
+
+ { 0xca, 0xfe, 0xba 0xbe }
+
+Packet content can be of the following:
+
+ hex bytes: 0xca
+ decimal: 42
+ binary: 0b11110000
+ octal: 011
+ character: 'a'
+ string: "hello world"
+ shellcode: "\\x31\\xdb\\x8d\\x43\\x17\\x99\\xcd\\x80\\x31\\xc9"
+
+Thus, a quite useless packet packet configuration might look like this (one can
+verify this when running this with trafgen in combination with -V):
+
+ { 0xca, 42, 0b11110000, 011, 'a', "hello world",
+ "\\x31\\xdb\\x8d\\x43\\x17\\x99\\xcd\\x80\\x31\\xc9" }
+
+There are a couple of helper functions in trafgen's language to make life easier
+to write configurations:
+
+i) Fill with garbage functions:
+
+ byte fill function: fill(<content>, <times>): fill(0xca, 128)
+ compile-time random: rnd(<times>): rnd(128), rnd()
+ runtime random numbers: drnd(<times>): drnd(128), drnd()
+ compile-time counter: seqinc(<start-val>, <increment>, <times>)
+ seqdec(<start-val>, <decrement>, <times>)
+ runtime counter (1byte): dinc(<min-val>, <max-val>, <increment>)
+ ddec(<min-val>, <max-val>, <decrement>)
+
+ii) Checksum helper functions (packet offsets start with 0):
+
+ IP/ICMP checksum: csumip/csumicmp(<off-from>, <off-to>)
+ UDP checksum: csumudp(<off-iphdr>, <off-udpdr>)
+ TCP checksum: csumtcp(<off-iphdr>, <off-tcphdr>)
+
+iii) Multibyte functions, compile-time expression evaluation:
+
+ const8(<content>), c8(<content>), const16(<content>), c16(<content>),
+ const32(<content>), c32(<content>), const64(<content>), c64(<content>)
+
+ These functions write their result in network byte order into the packet
+configuration, e.g. const16(0xaa) will result in ``00 aa''. Within c*()
+functions, it is possible to do some arithmetics: -,+,*,/,%,&,|,<<,>>,^
+E.g. const16((((1<<8)+0x32)|0b110)*2) will be evaluated to ``02 6c''.
+
+Furthermore, there are two types of comments in trafgen configuration files:
+
+ 1. Multi-line C-style comments: /* put comment here */
+ 2. Single-line Shell-style comments: # put comment here
+
+Next to all of this, a configuration can be passed through the C preprocessor
+before the trafgen compiler gets to see it with option --cpp. To give you a
+taste of a more advanced example, run ``trafgen -e'', fields are commented:
+
+ /* Note: dynamic elements make trafgen slower! */
+ #include <stddef.h>
+
+ {
+ /* MAC Destination */
+ fill(0xff, ETH_ALEN),
+ /* MAC Source */
+ 0x00, 0x02, 0xb3, drnd(3),
+ /* IPv4 Protocol */
+ c16(ETH_P_IP),
+ /* IPv4 Version, IHL, TOS */
+ 0b01000101, 0,
+ /* IPv4 Total Len */
+ c16(58),
+ /* IPv4 Ident */
+ drnd(2),
+ /* IPv4 Flags, Frag Off */
+ 0b01000000, 0,
+ /* IPv4 TTL */
+ 64,
+ /* Proto TCP */
+ 0x06,
+ /* IPv4 Checksum (IP header from, to) */
+ csumip(14, 33),
+ /* Source IP */
+ drnd(4),
+ /* Dest IP */
+ drnd(4),
+ /* TCP Source Port */
+ drnd(2),
+ /* TCP Dest Port */
+ c16(80),
+ /* TCP Sequence Number */
+ drnd(4),
+ /* TCP Ackn. Number */
+ c32(0),
+ /* TCP Header length + TCP SYN/ECN Flag */
+ c16((8 << 12) | TCP_FLAG_SYN | TCP_FLAG_ECE)
+ /* Window Size */
+ c16(16),
+ /* TCP Checksum (offset IP, offset TCP) */
+ csumtcp(14, 34),
+ /* TCP Options */
+ 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x06,
+ 0x91, 0x68, 0x7d, 0x06, 0x91, 0x68, 0x6f,
+ /* Data blob */
+ "gotcha!",
+ }
+
+Another real-world example by Jesper Dangaard Brouer [1]:
+
+ {
+ # --- ethernet header ---
+ 0x00, 0x1b, 0x21, 0x3c, 0x9d, 0xf8, # mac destination
+ 0x90, 0xe2, 0xba, 0x0a, 0x56, 0xb4, # mac source
+ const16(0x0800), # protocol
+ # --- ip header ---
+ # ipv4 version (4-bit) + ihl (4-bit), tos
+ 0b01000101, 0,
+ # ipv4 total len
+ const16(40),
+ # id (note: runtime dynamic random)
+ drnd(2),
+ # ipv4 3-bit flags + 13-bit fragment offset
+ # 001 = more fragments
+ 0b00100000, 0,
+ 64, # ttl
+ 17, # proto udp
+ # dynamic ip checksum (note: offsets are zero indexed)
+ csumip(14, 33),
+ 192, 168, 51, 1, # source ip
+ 192, 168, 51, 2, # dest ip
+ # --- udp header ---
+ # as this is a fragment the below stuff does not matter too much
+ const16(48054), # src port
+ const16(43514), # dst port
+ const16(20), # udp length
+ # udp checksum can be dyn calc via csumudp(offset ip, offset tcp)
+ # which is csumudp(14, 34), but for udp its allowed to be zero
+ const16(0),
+ # payload
+ 'A', fill(0x41, 11),
+ }
+
+ [1] http://thread.gmane.org/gmane.linux.network/257155
+
+.SH USAGE EXAMPLE
+
+.SS trafgen --dev eth0 --conf trafgen.cfg
+This is the most simple and probably also most used command for trafgen. It
+will generate traffic defined in the configuration file ``trafgen.cfg'' and
+transmit this via the ``eth0'' networking device. All online CPUs are used.
+
+.SS trafgen -e | trafgen -i - -o lo --cpp -n 1
+This is an example where we send one packet of the built-in example through
+the loopback device. The example configuration is passed via stdin and also
+through the C preprocessor before trafgen's packet compiler will see it.
+
+.SS trafgen --dev eth0 --conf fuzzing.cfg --smoke-test 10.0.0.1
+Read the ``fuzzing.cfg'' packet configuration file (which contains drnd()
+calls) and send out the generated packets to the ``eth0'' device. After each
+sent packet, ping probe the attacked host with address 10.0.0.1 to check if
+it's still alive. This also means, that we utilize 1 CPU only, and do not
+use the TX_RING, but sendto(2) packet I/O due to ``slow mode''.
+
+.SS trafgen --dev wlan0 --rfraw --conf beacon-test.txf -V --cpus 2
+As an output device ``wlan0'' is used and put into monitoring mode, thus we
+are going to transmit raw 802.11 frames through the air. Use the
+``beacon-test.txf'' configuration file, set trafgen into verbose mode and
+use only 2 CPUs.
+
+.SS trafgen --dev em1 --conf frag_dos.cfg --rand --gap 1000
+Use trafgen in sendto(2) mode instead of TX_RING mode and sleep after each
+sent packet a static timegap for 1000us. Generate packets from ``frag_dos.cfg''
+and select next packets to send randomly instead of a round-robin fashion.
+The output device for packets is ``em1''.
+
+.SS trafgen --dev eth0 --conf icmp.cfg --rand --num 1400000 -k1000
+Send only 1400000 packets using the ``icmp.cfg'' configuration file and then
+exit trafgen. Select packets randomly from that file for transmission and
+send them out via ``eth0''. Also, trigger the kernel every 1000us for batching
+the ring frames from user space (default is 10us).
+
+.SS trafgen --dev eth0 --conf tcp_syn.cfg -u `id -u bob` -g `id -g bob`
+Send out packets generated from the configuration file ``tcp_syn.cfg'' via
+the ``eth0'' networking device. After setting up the ring for transmission,
+drop credentials to the non-root user/group bob/bob.
+
+.SH NOTE
+trafgen can saturate a Gigabit Ethernet link without problems. As always,
+of course, this depends on your hardware as well. Not everywhere where it
+says Gigabit Ethernet on the box, you'll reach almost physical line rate!
+Please also read the netsniff-ng(8) man page, section NOTE for further
+details about tuning your system e.g. with tuned(8).
+
+If you intend to use trafgen on a 10-Gbit/s Ethernet NIC, make sure you
+are using a multiqueue tc(8) discipline, and make sure that the packets
+you generate with trafgen will have a good distribution among tx_hashes
+so that you'll actually make use of multiqueues.
+
+For introducing bit errors, delays with random variation and more, there
+is no built-in option in trafgen. Rather, one should reuse existing methods
+for that which integrate nicely with trafgen, such as tc(8) with its
+different disciplines, i.e. netem.
+
+For more complex packet configurations, it is recommended to use high-level
+scripting for generating trafgen packet configurations in a more automated
+way, i.e. also to create different traffic distributions that are common for
+industrial benchmarking:
+
+ Traffic model Distribution
+
+ IMIX 64:7, 570:4, 1518:1
+ Tolly 64:55, 78:5, 576:17, 1518:23
+ Cisco 64:7, 594:4, 1518:1
+ RPR Trimodal 64:60, 512:20, 1518:20
+ RPR Quadrimodal 64:50, 512:15, 1518:15, 9218:20
+
+The low-level nature of trafgen makes trafgen rather protocol independant
+and therefore useful in many scenarios when stress testing is needed, for
+instance. However, if a traffic generator with higher level packet
+descriptions is desired, netsniff-ng's mausezahn(8) can be of good use as
+well.
+
+For smoke/fuzz testing with trafgen, it is recommended to have a direct
+link between the host you want to analyze (``victim'' machine) and the host
+you run trafgen on (``attacker'' machine). If the ICMP reply from the victim
+fails, we assume that probably its kernel crashed, thus we print the last
+sent packet togther with the seed and quit probing. It might be very unlikely
+to find such a ping-of-death on modern Linux systems. However, there might
+be a good chance to find it on some proprietary (e.g. embedded) systems or
+buggy driver firmwares that are in the wild. Also, fuzz testing can be done
+on raw 802.11 frames, of course. In case you find a ping-of-death, please
+mention that you were using trafgen in your commit message of the fix!
+
+.SH BUGS
+When I start trafgen, my kernel crashes: we have fixed this bug in the
+mainline and stable kernels under commit 7f5c3e3a8 (``af_packet: remove
+BUG statement in tpacket_destruct_skb''). Either update your kernel to
+the latest version, e.g. clone and build it from git.kernel.org, to a
+stable kernel, or don't start multiple trafgen instances at once resp.
+start trafgen with flag -A to disable temporary socket memory adaptation!
+
+.SH LEGAL
+trafgen is licensed under the GNU GPL version 2.0.
+
+.SH HISTORY
+.B trafgen
+was originally written for the netsniff-ng toolkit by Daniel Borkmann. It
+is currently maintained by Tobias Klauser <tklauser@distanz.ch> and Daniel
+Borkmann <dborkma@tik.ee.ethz.ch>.
+
+.SH SEE ALSO
+.BR netsniff-ng (8),
+.BR mausezahn (8),
+.BR ifpps (8),
+.BR bpfc (8),
+.BR flowtop (8),
+.BR astraceroute (8),
+.BR curvetun (8)
+
+.SH AUTHOR
+Manpage was written by Daniel Borkmann.