9a2ade505677b5d5363e3d2f2cb567048aa589f1
[obnox/wireshark/wip.git] / randpkt.c
1 /*
2  * randpkt.c
3  * ---------
4  * Creates random packet traces. Useful for debugging sniffers by testing
5  * assumptions about the veracity of the data found in the packet.
6  *
7  * $Id: randpkt.c,v 1.2 1999/09/10 15:38:48 gram Exp $
8  *
9  * Copyright (C) 1999 by Gilbert Ramirez <gram@xiexie.org>
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif
37
38 #include <time.h>
39 #include <errno.h>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <glib.h>
45 #include <wtap.h>
46
47 #define array_length(x) (sizeof x / sizeof x[0])
48
49 /* Types of produceable packets */
50 enum {
51         PKT_ARP,
52         PKT_ETHERNET,
53         PKT_FDDI,
54         PKT_IP,
55         PKT_LLC,
56         PKT_TCP,
57         PKT_TR,
58         PKT_UDP
59 };
60
61 typedef struct {
62         char    *abbrev;
63         char    *longname;
64         int     produceable_type;
65         guint8  *sample_buffer;
66         int     sample_wtap_encap;
67         int     sample_length;
68 } pkt_example;
69
70 /* Ethernet, indicating ARP */
71 guint8 pkt_arp[] = {
72         0xff, 0xff, 0xff, 0xff,
73         0xff, 0xff, 0x00, 0x00,
74         0x32, 0x25, 0x0f, 0xff,
75         0x08, 0x06
76 };
77
78 /* Ethernet, indicating IP */
79 guint8 pkt_ip[] = {
80         0xff, 0xff, 0xff, 0xff,
81         0xff, 0xff, 0x01, 0x01,
82         0x01, 0x01, 0x01, 0x01,
83         0x08, 0x00
84 };
85
86 /* TR, indicating LLC */
87 guint8 pkt_llc[] = {
88         0x10, 0x40, 0x68, 0x00,
89         0x19, 0x69, 0x95, 0x8b,
90         0x00, 0x01, 0xfa, 0x68,
91         0xc4, 0x67
92 };
93
94 /* TR+LLC+IP, indicating TCP */
95 guint8 pkt_tcp[] = {
96         0x10, 0x40, 0x68, 0x00,
97         0x19, 0x69, 0x95, 0x8b,
98         0x00, 0x01, 0xfa, 0x68,
99         0xc4, 0x67,
100
101         0xaa, 0xaa, 0x03, 0x00,
102         0x00, 0x00, 0x08, 0x00,
103
104         0x45, 0x00, 0x00, 0x28,
105         0x0b, 0x0b, 0x40, 0x00,
106         0x20, 0x06, 0x85, 0x37,
107         0xc0, 0xa8, 0x27, 0x01,
108         0xc0, 0xa8, 0x22, 0x3c
109 };
110
111 /* Ethernet+IP, indicating UDP */
112 guint8 pkt_udp[] = {
113         0xff, 0xff, 0xff, 0xff,
114         0xff, 0xff, 0x01, 0x01,
115         0x01, 0x01, 0x01, 0x01,
116         0x08, 0x00,
117
118         0x45, 0x00, 0x00, 0x3c,
119         0xc5, 0x9e, 0x40, 0x00,
120         0xff, 0x11, 0xd7, 0xe0,
121         0xd0, 0x15, 0x02, 0xb8,
122         0x0a, 0x01, 0x01, 0x63
123 };
124
125 /* This little data table drives the whole program */
126 pkt_example examples[] = {
127         { "arp", "Address Resolution Protocol",
128                 PKT_ARP,        pkt_arp,        WTAP_ENCAP_ETHERNET,    array_length(pkt_arp) },
129
130         { "eth", "Ethernet",
131                 PKT_ETHERNET,   NULL,           WTAP_ENCAP_ETHERNET,    0 },
132
133         { "fddi", "Fiber Distributed Data Interface",
134                 PKT_FDDI,       NULL,           WTAP_ENCAP_FDDI,        0 },
135
136         { "ip", "Internet Protocol",
137                 PKT_IP,         pkt_ip,         WTAP_ENCAP_ETHERNET,    array_length(pkt_ip) },
138
139         { "llc", "Logical Link Control",
140                 PKT_LLC,        pkt_llc,        WTAP_ENCAP_TR,          array_length(pkt_llc) },
141
142         { "tcp", "Transmission Control Protocol",
143                 PKT_TCP,        pkt_tcp,        WTAP_ENCAP_TR,          array_length(pkt_tcp) },
144
145         { "tr",  "Token-Ring",
146                 PKT_TR,         NULL,           WTAP_ENCAP_TR,          0 },
147
148         { "udp", "User Datagram Protocol",
149                 PKT_UDP,        pkt_udp,        WTAP_ENCAP_ETHERNET,    array_length(pkt_udp) }
150 };
151
152
153
154 static int parse_type(char *string);
155 static void usage(void);
156 static void seed(void);
157
158 static pkt_example* find_example(int type);
159
160 int
161 main(int argc, char **argv)
162 {
163
164         wtap_dumper             *dump;
165         struct wtap_pkthdr      pkthdr;
166         int                     i, j, len_this_pkt, len_random, err;
167         guint8                  buffer[65536];
168
169         int                     opt;
170         extern char             *optarg;
171         extern int              optind;
172
173         int                     produce_count = 1000; /* number of pkts to produce */
174         int                     produce_type = PKT_ETHERNET;
175         char                    *produce_filename = NULL;
176         int                     produce_max_bytes = 5000;
177         pkt_example             *example;
178
179         while ((opt = getopt(argc, argv, "b:c:t:")) != EOF) {
180                 switch (opt) {
181                         case 'b':       /* max bytes */
182                                 produce_max_bytes = atoi(optarg);
183                                 if (produce_max_bytes > 65536) {
184                                         printf("Max bytes is 65536\n");
185                                         exit(0);
186                                 }
187                                 break;
188
189                         case 'c':       /* count */
190                                 produce_count = atoi(optarg);
191                                 break;
192
193                         case 't':       /* type of packet to produce */
194                                 produce_type = parse_type(optarg);
195                                 break;
196
197                         default:
198                                 usage();
199                                 break;
200                 }
201         }
202
203         /* any more command line parameters? */
204         if (argc > optind) {
205                 produce_filename = argv[optind];
206         }
207         else {
208                 usage();
209         }
210
211         example = find_example(produce_type);
212
213         pkthdr.ts.tv_sec = 0;
214         pkthdr.ts.tv_usec = 0;
215         pkthdr.pkt_encap = example->sample_wtap_encap;
216
217         dump = wtap_dump_open(produce_filename, WTAP_FILE_PCAP,
218                 example->sample_wtap_encap, produce_max_bytes, &err);
219
220         seed();
221
222         /* reduce max_bytes by # of bytes already in sample */
223         if (produce_max_bytes <= example->sample_length) {
224                 printf("Sample packet length is %d, which is greater than or equal to\n", example->sample_length);
225                 printf("your requested max_bytes value of %d\n", produce_max_bytes);
226                 exit(0);
227         }
228         else {
229                 produce_max_bytes -= example->sample_length;
230         }
231
232         /* Load the sample into our buffer */
233         if (example->sample_buffer)
234                 memcpy(&buffer[0], example->sample_buffer, example->sample_length);
235
236         /* Produce random packets */
237         for (i = 0; i < produce_count; i++) {
238                 if (produce_max_bytes > 0) {
239                         len_random = (rand() % produce_max_bytes + 1);
240                 }
241                 else {
242                         len_random = 0;
243                 }
244
245                 len_this_pkt = example->sample_length + len_random;
246
247                 pkthdr.caplen = len_this_pkt;
248                 pkthdr.len = len_this_pkt;
249                 pkthdr.ts.tv_sec = i; /* just for variety */
250
251                 for (j = example->sample_length; j < len_random; j++) {
252                         buffer[j] = (rand() % 0x100);
253                 }
254
255                 wtap_dump(dump, &pkthdr, &buffer[0], &err);
256         }
257
258         wtap_dump_close(dump, &err);
259
260         return 0;
261
262 }
263
264 /* Print usage statement and exit program */
265 static
266 void usage(void)
267 {
268         int     num_entries = array_length(examples);
269         int     i;
270
271         printf("Usage: randpkt [-b maxbytes] [-c count] [-t type] filename\n");
272         printf("Default max bytes (per packet) is 5000\n");
273         printf("Default count is 1000.\n");
274         printf("Types:\n");
275
276         for (i = 0; i < num_entries; i++) {
277                 printf("\t%s\t%s\n", examples[i].abbrev, examples[i].longname);
278         }
279
280         printf("\n");
281
282         exit(0);
283 }
284
285 /* Parse command-line option "type" and return enum type */
286 static
287 int parse_type(char *string)
288 {
289         int     num_entries = array_length(examples);
290         int     i;
291
292         for (i = 0; i < num_entries; i++) {
293                 if (strcmp(examples[i].abbrev, string) == 0) {
294                         return examples[i].produceable_type;
295                 }
296         }
297
298         /* default type */
299         return PKT_ETHERNET;
300 }
301
302 /* Find pkt_example record and return pointer to it */
303 static
304 pkt_example* find_example(int type)
305 {
306         int     num_entries = array_length(examples);
307         int     i;
308
309         for (i = 0; i < num_entries; i++) {
310                 if (examples[i].produceable_type == type) {
311                         return &examples[i];
312                 }
313         }
314
315         printf("Internal error. Type %d has no entry in examples table.\n", type);
316         exit(0);
317 }
318
319 /* Seed the random-number generator */
320 void
321 seed(void)
322 {
323         unsigned int    randomness;
324
325 #if defined(linux)
326         /* Okay, I should use #ifdef HAVE_DEV_RANDOM, but this is a quick hack */
327         int             fd;
328
329         fd = open("/dev/random", O_RDONLY);
330         if (fd < 0) {
331                 printf("Could not open /dev/random for reading: %s\n", strerror(errno));
332                 exit(0);
333         }
334
335         read(fd, &randomness, sizeof(randomness));
336 #else
337         time_t now;
338
339         now = time(NULL);
340         randomness = (unsigned int) now;
341 #endif
342
343         srand(randomness);
344 }