Added random packet generator.

svn path=/trunk/; revision=645
This commit is contained in:
Gilbert Ramirez 1999-09-10 05:15:17 +00:00
parent e425e372ca
commit c2bf152b01
3 changed files with 416 additions and 2 deletions

View File

@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
# $Id: Makefile.am,v 1.69 1999/09/09 03:45:57 guy Exp $
# $Id: Makefile.am,v 1.70 1999/09/10 05:15:09 gram Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@zing.org>
@ -22,7 +22,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
bin_PROGRAMS = ethereal
bin_PROGRAMS = ethereal randpkt
man_MANS = ethereal.1
@ -155,6 +155,12 @@ ps.c: print.ps rdps
rdps: rdps.c
$(CC) -o rdps $(srcdir)/rdps.c
randpkt_SOURCES = \
randpkt.c
randpkt_DEPENDENCIES = wiretap/libwiretap.a
randpkt_LDADD = wiretap/libwiretap.a
DISTCLEANFILES = \
rdps \
ps.c \

115
doc/randpkt.txt Normal file
View File

@ -0,0 +1,115 @@
Random Packet Generator
-----------------------
$Id: randpkt.txt,v 1.1 1999/09/10 05:15:17 gram Exp $
This small utility creates a libpcap trace file full of random packets.
You can control the number of packets, the maximum size of each packet,
and the type of each packet.
By creating many randomized packets of a certain type, you can
test packet sniffers to see how well they handle malformed packets.
The sniffer can never trust the data that it sees in the packet because
you can always sniff a very bad packet that conforms to no standard.
Randpkt produces __very bad__ packets.
When creating packets of a certain type, randpkt uses a sample
packet that is stored internally to randpkt. It uses this as the
starting point for your random packets, and then adds extra random
bytes to the end of this sample packet.
For example, if you choose to create random ARP packets, randpkt
will create a packet which contains a predetermined Ethernet II header,
with the Type field set to ARP. After the Ethernet II header, it will
put a random number of bytes with random values.
Run 'randpkt' with no options to see the usage statement. As of the
writing of this text, the usage is:
Usage: randpkt [-b maxbytes] [-c count] [-t type] filename
The usage statement produced by randpkt will list the legal types.
If you choose a maxbytes value that is less than the size of the
sample packet, then your packets would contain only the sample
packet... not much variance there! Randpkt exits on that condition.
To add a new packet type to randpkt, you must add information
in the following locations.
1) Add the packet type name to the enum of produceable packets:
/* Types of produceable packets */
enum {
PKT_ARP,
PKT_ETHERNET,
PKT_FDDI,
PKT_LLC,
PKT_TR
};
2) Type in the bytes from your sample packet
/* Ethernet, indicating ARP */
guint8 pkt_arp[] = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00,
0x32, 0x25, 0x0f, 0xff,
0x08, 0x06
};
3) Add a record to the 'examples' array. The fields are
1. Abbreviation (for use in '-t' command line argument)
2. Full name (for use in usage statement)
3. Enum type
4. Array holding sample packet
5. Wiretap encapsulation type of datalink layer in your
sample packet
6. Length of sample packet. Use the handy array_length()
macro to avoid counting the bytes yourself.
pkt_example examples[] = {
{ "arp",
"Address Resolution Protocol",
PKT_ARP,
pkt_arp,
WTAP_ENCAP_ETHERNET,
array_length(pkt_arp) },
{ "eth",
"Ethernet",
PKT_ETHERNET,
NULL,
WTAP_ENCAP_ETHERNET,
0 },
{ "fddi",
"Fiber Distributed Data Interface",
PKT_FDDI,
NULL,
WTAP_ENCAP_FDDI,
0 },
{ "llc",
"Logical Link Control",
PKT_LLC,
pkt_llc,
WTAP_ENCAP_TR,
array_length(pkt_llc) },
{ "tr",
"Token-Ring",
PKT_TR,
NULL,
WTAP_ENCAP_TR,
0 }
};
Note that packets that designate only their datalink type have no sample
arrays, since the only thing that needs to be set is the datalink type,
which is a field in the libpcap frame record; it's not a part of the
packet itself.
Enjoy!

293
randpkt.c Normal file
View File

@ -0,0 +1,293 @@
/*
* randpkt.c
* ---------
* Creates random packet traces. Useful for debugging sniffers by testing
* assumptions about the veracity of the data found in the packet.
*
* $Id: randpkt.c,v 1.1 1999/09/10 05:15:10 gram Exp $
*
* Copyright (C) 1999 by Gilbert Ramirez <gram@xiexie.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <wtap.h>
#define array_length(x) (sizeof x / sizeof x[0])
/* Types of produceable packets */
enum {
PKT_ARP,
PKT_ETHERNET,
PKT_FDDI,
PKT_LLC,
PKT_TR
};
typedef struct {
char *abbrev;
char *longname;
int produceable_type;
guint8 *sample_buffer;
int sample_wtap_encap;
int sample_length;
} pkt_example;
/* Ethernet, indicating ARP */
guint8 pkt_arp[] = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00,
0x32, 0x25, 0x0f, 0xff,
0x08, 0x06
};
/* TR, indicating LLC */
guint8 pkt_llc[] = {
0x10, 0x40, 0x68, 0x00,
0x19, 0x69, 0x95, 0x8b,
0x00, 0x01, 0xfa, 0x68,
0xc4, 0x67
};
/* This little data table drives the whole program */
pkt_example examples[] = {
{ "arp", "Address Resolution Protocol",
PKT_ARP, pkt_arp, WTAP_ENCAP_ETHERNET, array_length(pkt_arp) },
{ "eth", "Ethernet",
PKT_ETHERNET, NULL, WTAP_ENCAP_ETHERNET, 0 },
{ "fddi", "Fiber Distributed Data Interface",
PKT_FDDI, NULL, WTAP_ENCAP_FDDI, 0 },
{ "llc", "Logical Link Control",
PKT_LLC, pkt_llc, WTAP_ENCAP_TR, array_length(pkt_llc) },
{ "tr", "Token-Ring",
PKT_TR, NULL, WTAP_ENCAP_TR, 0 }
};
static int parse_type(char *string);
static void usage(void);
static void seed(void);
static pkt_example* find_example(int type);
int
main(int argc, char **argv)
{
wtap_dumper *dump;
struct wtap_pkthdr pkthdr;
int i, j, len_this_pkt, len_random, err;
guint8 buffer[65536];
int opt;
extern char *optarg;
extern int optind;
int produce_count = 1000; /* number of pkts to produce */
int produce_type = PKT_ETHERNET;
char *produce_filename = NULL;
int produce_max_bytes = 5000;
pkt_example *example;
while ((opt = getopt(argc, argv, "b:c:t:")) != EOF) {
switch (opt) {
case 'b': /* max bytes */
produce_max_bytes = atoi(optarg);
if (produce_max_bytes > 65536) {
printf("Max bytes is 65536\n");
exit(0);
}
break;
case 'c': /* count */
produce_count = atoi(optarg);
break;
case 't': /* type of packet to produce */
produce_type = parse_type(optarg);
break;
default:
usage();
break;
}
}
/* any more command line parameters? */
if (argc > optind) {
produce_filename = argv[optind];
}
else {
usage();
}
example = find_example(produce_type);
pkthdr.ts.tv_sec = 0;
pkthdr.ts.tv_usec = 0;
pkthdr.pkt_encap = example->sample_wtap_encap;
dump = wtap_dump_open(produce_filename, WTAP_FILE_PCAP,
example->sample_wtap_encap, produce_max_bytes, &err);
seed();
/* reduce max_bytes by # of bytes already in sample */
if (produce_max_bytes <= example->sample_length) {
printf("Sample packet length is %d, which is greater than or equal to\n", example->sample_length);
printf("your requested max_bytes value of %d\n", produce_max_bytes);
exit(0);
}
else {
produce_max_bytes -= example->sample_length;
}
/* Load the sample into our buffer */
if (example->sample_buffer)
memcpy(&buffer[0], example->sample_buffer, example->sample_length);
/* Produce random packets */
for (i = 0; i < produce_count; i++) {
if (produce_max_bytes > 0) {
len_random = (rand() % produce_max_bytes + 1);
}
else {
len_random = 0;
}
len_this_pkt = example->sample_length + len_random;
pkthdr.caplen = len_this_pkt;
pkthdr.len = len_this_pkt;
pkthdr.ts.tv_sec = i; /* just for variety */
for (j = example->sample_length; j < len_random; j++) {
buffer[j] = (rand() % 0x100);
}
wtap_dump(dump, &pkthdr, &buffer[0], &err);
}
wtap_dump_close(dump, &err);
return 0;
}
/* Print usage statement and exit program */
static
void usage(void)
{
int num_entries = array_length(examples);
int i;
printf("Usage: randpkt [-b maxbytes] [-c count] [-t type] filename\n");
printf("Default max bytes (per packet) is 5000\n");
printf("Default count is 1000.\n");
printf("Types:\n");
for (i = 0; i < num_entries; i++) {
printf("\t%s\t%s\n", examples[i].abbrev, examples[i].longname);
}
printf("\n");
exit(0);
}
/* Parse command-line option "type" and return enum type */
static
int parse_type(char *string)
{
int num_entries = array_length(examples);
int i;
for (i = 0; i < num_entries; i++) {
if (strcmp(examples[i].abbrev, string) == 0) {
return examples[i].produceable_type;
}
}
/* default type */
return PKT_ETHERNET;
}
/* Find pkt_example record and return pointer to it */
static
pkt_example* find_example(int type)
{
int num_entries = array_length(examples);
int i;
for (i = 0; i < num_entries; i++) {
if (examples[i].produceable_type == type) {
return &examples[i];
}
}
printf("Internal error. Type %d has no entry in examples table.\n", type);
exit(0);
}
/* Seed the random-number generator */
void
seed(void)
{
unsigned int randomness;
#if defined(linux)
/* Okay, I should use #ifdef HAVE_DEV_RANDOM, but this is a quick hack */
int fd;
fd = open("/dev/random", O_RDONLY);
if (fd < 0) {
printf("Could not open /dev/random for reading: %s\n", strerror(errno));
exit(0);
}
read(fd, &randomness, sizeof(randomness));
#else
time_t now;
now = time(NULL);
randomness = (unsigned int) now;
#endif
srand(randomness);
}