diff options
Diffstat (limited to 'trafgen.8')
-rw-r--r-- | trafgen.8 | 445 |
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. |