pierf packet generator and
analyzer
Intro
pierf is in the first place a packet injection tool. It builds packets
and puts them
directly on the network driver, bypassing the operating system.
Therefore, it is not limited to the features of the OS. It is intended
as a test tool for ethernet/ip devices. For ideas of possible future
features, have a look at the enclosed Readme.txt
file. It uses the free libraries (win)pcap for packet
injection and expat for xml parsing.
- Author: Pieter Blommaert
- License to the binary, this documentation, the
samples and any other files part of the pierf software: see appendix A
or the license.txt file.
- Pierf is available online on . Files and documentation can be found
via the project
portal.
- Basic protocols: ethernet, ip, udp, arp, icmp, igmp v2 and raw bytes (hex string)
- IGMP v3 packet generation. Cf. newIgmp.pierf sample
- Repetitive packets. Combining sleep tag and repeat attribute, the
tool can send packets periodically. E.g. igmp.pierf implements an igmp
querier.
- Writing to a file (pcap/ethereal capture format) rather then to a
real port. Can e.g. be used for test purpose (Cf. tst_file.pierf) or to
convert a raw dump to a capture file (Cf. tst_raw.pierf).
- Replay of a capture file: combining the mirror feature (to mirror
a captured packet from one port to another) with the possibility to
read from a capture file, one can replay a capture file in realtime.
Cf. tst_mirror.pierf.
- Log the packets on a port while running. Gives you a log of
everything you sent, as also any reply and anything else that was
captured during that time. Cf. tst_log.pierf. (As such, it can also act
as a simple capture tool, if all you'd do while logging is a sleep.)
- Count and summarize number of packets, packet rate, number of
bytes and bitrate. Cf. tst_counter.pierf and tst_counter2.pierf (the
second is supposed to be executed after the first to get a full sample.)
- Use of config include files, e.g. easy for predefining commonly used ports or scenarios. Cf. a.o. tst_raw.pierf
- Analyze
and print the received packet in xml format. The print format follows
the pierf syntax and hence the print output can be used as input to the
tool. Cf. a.o. tst_print_prerare.pierf and tst_print.pierf, that
illustrate this feature when run in sequence.
- Build conditional
actions, depending on the structure and field values of received
packets. E.g. send igmp report when igmp query is received, increment a
counter for each udp packet received, mirror all packets for
destination mac address x, etc. Cf. a.o. tst_match.pief, which can be
run after executing tst_print_prepare.pierf
User interface
- Currently, there's only a command line interface, taking
one argument: the name of an xml file (typical extension:
pierf).
- Running the tool without options gives a very short help
and tool version. The version consists of three parts (x.y.z):
- First part (x) gives an indication of the feature level
- Second part (y) is the source version. This may be a
pretty high number.
- Third part (z) is the debug subversion. It must always be
0 for released (distributed) versions.
- The source of all released versions is kept under version
control (subversion). Therefore, when reporting problems, please
mention the version.
- For the actual options, an xml interface was chosen for
many reasons:
- You can prepare complex (sequences of) packets and store
them. The store format is intrinsic to the tool.
- Each element in the tool has the ability to print its own
content in xml, as such allowing the reverse.
- The xml allows to build any packet (sequence) without the
need of any programming/scripting skills.
- It splits the user interface from the functional part.
E.g. it would be easy to use an existing xml editor or create a
dedicated GUI that creates the xml files for you. It may also be useful
as an interface format for server/client applications.
- The documentation lists the supported tags
with their
arguments and meaning. Lets start however with a small example to
illustrate. (More sample pierf files may be found bundled with the binary, in the configs subdirectory.)
<pierf>
<port id="broadcom"
device="\Device\NPF_{F8C7658E-8536-4DA1-BC85-F2EC10B37656}" />
<scene id="arp">
<seq>
<packet port="broadcom">
<eth from="02:02:02:02:02:02" to ="FF:FF:FF:FF:FF:FF" />
<vlans stack="700:120"></vlans>
<arp type="req" fromMac="02:02:02:02:02:02"
fromIp="192.168.10.6" toIp="192.168.10.8" />
</packet>
<packet port="realtec">
...
</packet>
</seq>
</scene>
<play scene="arp" />
</pierf>
The file starts and stops resp.
with a <pierf> and </pierf> tag, confirming
that it is a pierf file.- The ports (ethernet cards) on your PC
must be identified
by their device id. To find out the device id of your ports, just fill
someting dummy and run the tool. It will print an error but also
provide a list of devices. Using Ethereal, you'll also find the
device id there, when starting a capture. For further use, you can give
these
ports a friendly name. The <port> tag is used for that.
- You can define multiple "scenario's", identified by
<scene> tags. A scene has an id, that can be
referenced later to run it. As such, the definition of a scene does not
cause anything to be sent. It only loads the scenario and packet
definitions into memory. Everything between the start tag
<scene> and the end tag </scene> is part of
the scene.
- A scene currently can only exist of a sequence of
packets. A sequence starts with a <seq> tag and ends with
a </seq> tag. Seq tags are currently nameless.
- A sequence is built up by packets. Each packet needs a
port attribute to know on which port to send the packet. This is the
<packet>/</packet> tag.
- A packet consists of a series of layers. In this example,
an arp request in a stacked vlan (outer 700, inner 120), over ethernet.
Currently, the layers in a packet have no correlation, so, e.g. in this
case, you must explicitly specify the source mac address both in the
ethernet and in the arp layer.
- Finally, there's one tag left: the <play>
tag. This is the only one that effectively does something. It sends all
the packets defined in the <scene> tag.
- The tool is constructed on all levels to be limited only by
hardware (ethernet driver, memory,...)
- The tool allows you to specify any field of any packet layer.
However, often higher layers imply values of lower layer field. E.g.
when sending an arp reply, the source and destination mac address in
the arp are the same as the ones in the ethernet layer. The documentation lists all
automatic completions done.
- Sample:
<scene auto="manual">
<seq>...</seq>
<seq auto="auto">
<packet port="broadcom">
<eth>
<arp type="req" fromMac="02:02:02:02:02:02" fromIp="192.168.10.6" toIp="192.168.10.8">
</packet>
</seq>
</scene>
In this simple example, the <eth> tag will take its source mac
address from the arp request. As it is an arp request, it will set the
destination mac address to the broadcast mac address
(FF:FF:FF:FF:FF:FF).
- Important to know is that the tool will only auto complete
fields of lower layers based on the upper layers. Each layer will first
locate itself in the stack and then complete. If you'd have e.g. ip
over ethernet over ppp over ethernet again, the lowest layer ethernet
fields may be set from the ppp and then upper layers. The higher layer
ethernet fields may only be set by the ip layer and possible higher
layers. (Fictive example)
- Another consequence of this is also that parse errors for
missing parameters are delayed, until all packet layers have been
read.
- If you set a parameter manual, it will never be overwritten,
even if the specified value is not in line with what's expected based
on the upper layers.
- This auto mechanism can be disabled or enabled at any level, e.g.
<scene auto="manual">
will disable it for the entire scene, including all packets in it. While <seq auto="auto">
will force it to auto again for all packets within that sequence. The
default at scene level, applied when the auto=... argument is not
provided, is "auto". The default at any lower level is to enherit from
the upper level. E.g. the first <seq>...</seq> in the
example, will also be "manual", because the scene tag has been set
"manual". - Even in "manual" mode, there are a very few arguments which are
optional. E.g. in the case of an arp request, you don't need to specify
the target mac address as it is not supposed to be known for a regular
arp request. These arguments and their assumed default value are
clearly mentioned to be optional in the documentation.
- For most integer value fields, the tool will accept both
decimal input and hex input. Hex input values must start with "0x".
E.g. "0x0800".
- Some
fields also have a default value. This means that if not specified and
not implied by higher layers, the field will still get a regular
applicable value. Defaults are mentioned in the table in the documentation.
One special example of defaults is checksums.
Checksums are - unless specified explicitly - always calculated
(default value = correct checksum). This is even valid if the checksum
includes more than the own layer. For this reason, as well as for
general efficiency, the checksum field is only calculated after
building the raw packet. (While all other fields need to be known
before even starting to construct it.)
Packet matching
One of the powerful abilities of the pierf
tool is to build conditions on the received packets. This allows to
implement conditional replies, counters,... A sample how to construct
such a condition in the pierf xml language:
...
<receive port="myport" nomatch="loop">
<firstof>
<match>
<eth from="02:02:02:02:02:03" />
<seq>
<print />
<counter ref="matchRx" action="increment" />
<packet port="filesample2">
<eth from="CD:EF:AB:CD:EF:FF"
to="12:34:56:78:09:AB" ethertype="0x0000"/>
<raw>12:34:56:78:09:AB:CD:EF:AB:CD:EF:12:34:56:78:09</raw>
</packet>
</seq>
</match>
</firstof>
</receive>
...
- The
receive tag simply has the tool waiting for the first packet sniffed on
the port (device or file). Be careful: since this is a raw packet
capture on the device and not a receive via some kind of OS service,
the packets you send are also "received" when the port is a device.
Take this into account, e.g. by defining proper matches that skip the
sent packet. Note the "nomatch" condition. When set to loop, receive
will loop forever until at least one match has been satisfied.
- The
firstof tag simply combines a set of matches. The first match tag that
actually gives a match will be executed, the remaining match tags will
be skipped. A receive tag may contain more then one firstof tags, in
this way also allowing independent match conditions, that may both be
executed when matched.
- The match tag is followed by two parts.
The match starts with a partial packet definition. A match is always
evaluated from lower to higher layer. So, if e.g. you want to match a
udp packet, you must also specify the ethernet and ip layer (and
whatever other underlaying layers you have). You don't need to specify
the value of the fields however, only the protocol layers. A match tag
must always end with a sequence (seq tag). In the sequence, anything
that can occur in a regular sequence, or in a receive tag may occur. It
may however not contain another, nested receive tag. (This because the
packet capturing is blocked until the receive is fully handled, only
then to capture the next packet, so that, if streams are not coming too
fast, no packet is missed.)
Appendic A. License
- Copyright (c) 2006-2007, Pieter Blommaert
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
The names of the author and contributors may be used to endorse or
promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Small clarification of my choice for this type (free BSD)
style of license:
At first i liked copyleft style (e.g. GPL) of licenses until I came to
realise that enforced freedom is a contradiction in terminis. Once i
really want to start using GPL licensed code, i need to carefully check
what is allowed and what not. I also wanted at any time to
keep all of my rights to do with the code whatever i want. So i decided
that the above, free BSD style license,
is the only license that makes my small contribution somewhat useful to
the community.
- I intended my tool for network and equipment tests. I
disclaim
all responsibility for the use of this software, however I would be
personally offended if it is intentionally used for illegal or
aggressive purpose. There are no excuses that justify misusing or
breaking well-intended equipment and/or services.