Keep the sample command line in the usage message within 80 characters.
[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.5 1999/10/07 07:55:12 guy 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 "wiretap/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_DNS,
53         PKT_ETHERNET,
54         PKT_FDDI,
55         PKT_ICMP,
56         PKT_IP,
57         PKT_LLC,
58         PKT_NBNS,
59         PKT_TCP,
60         PKT_TR,
61         PKT_UDP
62 };
63
64 typedef struct {
65         char    *abbrev;
66         char    *longname;
67         int     produceable_type;
68         guint8  *sample_buffer;
69         int     sample_wtap_encap;
70         int     sample_length;
71 } pkt_example;
72
73 /* Ethernet, indicating ARP */
74 guint8 pkt_arp[] = {
75         0xff, 0xff, 0xff, 0xff,
76         0xff, 0xff, 0x00, 0x00,
77         0x32, 0x25, 0x0f, 0xff,
78         0x08, 0x06
79 };
80
81 /* Ethernet+IP+UP, indicating DNS */
82 guint8 pkt_dns[] = {
83         0xff, 0xff, 0xff, 0xff,
84         0xff, 0xff, 0x01, 0x01,
85         0x01, 0x01, 0x01, 0x01,
86         0x08, 0x00,
87
88         0x45, 0x00, 0x00, 0x3c,
89         0xc5, 0x9e, 0x40, 0x00,
90         0xff, 0x11, 0xd7, 0xe0,
91         0xd0, 0x15, 0x02, 0xb8,
92         0x0a, 0x01, 0x01, 0x63,
93
94         0x05, 0xe8, 0x00, 0x35,
95         0x00, 0x00, 0x2a, 0xb9,
96         0x30
97 };
98
99 /* Ethernet+IP, indicating ICMP */
100 guint8 pkt_icmp[] = {
101         0xff, 0xff, 0xff, 0xff,
102         0xff, 0xff, 0x01, 0x01,
103         0x01, 0x01, 0x01, 0x01,
104         0x08, 0x00,
105
106         0x45, 0x00, 0x00, 0x54,
107         0x8f, 0xb3, 0x40, 0x00,
108         0xfd, 0x01, 0x8a, 0x99,
109         0xcc, 0xfc, 0x66, 0x0b,
110         0xce, 0x41, 0x62, 0x12
111 };
112
113 /* Ethernet, indicating IP */
114 guint8 pkt_ip[] = {
115         0xff, 0xff, 0xff, 0xff,
116         0xff, 0xff, 0x01, 0x01,
117         0x01, 0x01, 0x01, 0x01,
118         0x08, 0x00
119 };
120
121 /* TR, indicating LLC */
122 guint8 pkt_llc[] = {
123         0x10, 0x40, 0x68, 0x00,
124         0x19, 0x69, 0x95, 0x8b,
125         0x00, 0x01, 0xfa, 0x68,
126         0xc4, 0x67
127 };
128
129 /* Ethernet+IP+UP, indicating NBNS */
130 guint8 pkt_nbns[] = {
131         0xff, 0xff, 0xff, 0xff,
132         0xff, 0xff, 0x01, 0x01,
133         0x01, 0x01, 0x01, 0x01,
134         0x08, 0x00,
135
136         0x45, 0x00, 0x00, 0x3c,
137         0xc5, 0x9e, 0x40, 0x00,
138         0xff, 0x11, 0xd7, 0xe0,
139         0xd0, 0x15, 0x02, 0xb8,
140         0x0a, 0x01, 0x01, 0x63,
141
142         0x00, 0x89, 0x00, 0x89,
143         0x00, 0x00, 0x2a, 0xb9,
144         0x30
145 };
146
147 /* TR+LLC+IP, indicating TCP */
148 guint8 pkt_tcp[] = {
149         0x10, 0x40, 0x68, 0x00,
150         0x19, 0x69, 0x95, 0x8b,
151         0x00, 0x01, 0xfa, 0x68,
152         0xc4, 0x67,
153
154         0xaa, 0xaa, 0x03, 0x00,
155         0x00, 0x00, 0x08, 0x00,
156
157         0x45, 0x00, 0x00, 0x28,
158         0x0b, 0x0b, 0x40, 0x00,
159         0x20, 0x06, 0x85, 0x37,
160         0xc0, 0xa8, 0x27, 0x01,
161         0xc0, 0xa8, 0x22, 0x3c
162 };
163
164 /* Ethernet+IP, indicating UDP */
165 guint8 pkt_udp[] = {
166         0xff, 0xff, 0xff, 0xff,
167         0xff, 0xff, 0x01, 0x01,
168         0x01, 0x01, 0x01, 0x01,
169         0x08, 0x00,
170
171         0x45, 0x00, 0x00, 0x3c,
172         0xc5, 0x9e, 0x40, 0x00,
173         0xff, 0x11, 0xd7, 0xe0,
174         0xd0, 0x15, 0x02, 0xb8,
175         0x0a, 0x01, 0x01, 0x63
176 };
177
178 /* This little data table drives the whole program */
179 pkt_example examples[] = {
180         { "arp", "Address Resolution Protocol",
181                 PKT_ARP,        pkt_arp,        WTAP_ENCAP_ETHERNET,    array_length(pkt_arp) },
182
183         { "dns", "Domain Name Service",
184                 PKT_DNS,        pkt_dns,        WTAP_ENCAP_ETHERNET,    array_length(pkt_dns) },
185
186         { "eth", "Ethernet",
187                 PKT_ETHERNET,   NULL,           WTAP_ENCAP_ETHERNET,    0 },
188
189         { "fddi", "Fiber Distributed Data Interface",
190                 PKT_FDDI,       NULL,           WTAP_ENCAP_FDDI,        0 },
191
192         { "icmp", "Internet Control Message Protocol",
193                 PKT_ICMP,       pkt_icmp,       WTAP_ENCAP_ETHERNET,    array_length(pkt_icmp) },
194
195         { "ip", "Internet Protocol",
196                 PKT_IP,         pkt_ip,         WTAP_ENCAP_ETHERNET,    array_length(pkt_ip) },
197
198         { "llc", "Logical Link Control",
199                 PKT_LLC,        pkt_llc,        WTAP_ENCAP_TR,          array_length(pkt_llc) },
200
201         { "nbns", "NetBIOS-over-TCP Name Service",
202                 PKT_NBNS,       pkt_nbns,       WTAP_ENCAP_ETHERNET,    array_length(pkt_nbns) },
203
204         { "tcp", "Transmission Control Protocol",
205                 PKT_TCP,        pkt_tcp,        WTAP_ENCAP_TR,          array_length(pkt_tcp) },
206
207         { "tr",  "Token-Ring",
208                 PKT_TR,         NULL,           WTAP_ENCAP_TR,          0 },
209
210         { "udp", "User Datagram Protocol",
211                 PKT_UDP,        pkt_udp,        WTAP_ENCAP_ETHERNET,    array_length(pkt_udp) }
212 };
213
214
215
216 static int parse_type(char *string);
217 static void usage(void);
218 static void seed(void);
219
220 static pkt_example* find_example(int type);
221
222 int
223 main(int argc, char **argv)
224 {
225
226         wtap_dumper             *dump;
227         struct wtap_pkthdr      pkthdr;
228         int                     i, j, len_this_pkt, len_random, err;
229         guint8                  buffer[65536];
230
231         int                     opt;
232         extern char             *optarg;
233         extern int              optind;
234
235         int                     produce_count = 1000; /* number of pkts to produce */
236         int                     produce_type = PKT_ETHERNET;
237         char                    *produce_filename = NULL;
238         int                     produce_max_bytes = 5000;
239         pkt_example             *example;
240
241         while ((opt = getopt(argc, argv, "b:c:t:")) != EOF) {
242                 switch (opt) {
243                         case 'b':       /* max bytes */
244                                 produce_max_bytes = atoi(optarg);
245                                 if (produce_max_bytes > 65536) {
246                                         printf("Max bytes is 65536\n");
247                                         exit(0);
248                                 }
249                                 break;
250
251                         case 'c':       /* count */
252                                 produce_count = atoi(optarg);
253                                 break;
254
255                         case 't':       /* type of packet to produce */
256                                 produce_type = parse_type(optarg);
257                                 break;
258
259                         default:
260                                 usage();
261                                 break;
262                 }
263         }
264
265         /* any more command line parameters? */
266         if (argc > optind) {
267                 produce_filename = argv[optind];
268         }
269         else {
270                 usage();
271         }
272
273         example = find_example(produce_type);
274
275         pkthdr.ts.tv_sec = 0;
276         pkthdr.ts.tv_usec = 0;
277         pkthdr.pkt_encap = example->sample_wtap_encap;
278
279         dump = wtap_dump_open(produce_filename, WTAP_FILE_PCAP,
280                 example->sample_wtap_encap, produce_max_bytes, &err);
281
282         seed();
283
284         /* reduce max_bytes by # of bytes already in sample */
285         if (produce_max_bytes <= example->sample_length) {
286                 printf("Sample packet length is %d, which is greater than or equal to\n", example->sample_length);
287                 printf("your requested max_bytes value of %d\n", produce_max_bytes);
288                 exit(0);
289         }
290         else {
291                 produce_max_bytes -= example->sample_length;
292         }
293
294         /* Load the sample into our buffer */
295         if (example->sample_buffer)
296                 memcpy(&buffer[0], example->sample_buffer, example->sample_length);
297
298         /* Produce random packets */
299         for (i = 0; i < produce_count; i++) {
300                 if (produce_max_bytes > 0) {
301                         len_random = (rand() % produce_max_bytes + 1);
302                 }
303                 else {
304                         len_random = 0;
305                 }
306
307                 len_this_pkt = example->sample_length + len_random;
308
309                 pkthdr.caplen = len_this_pkt;
310                 pkthdr.len = len_this_pkt;
311                 pkthdr.ts.tv_sec = i; /* just for variety */
312
313                 for (j = example->sample_length; j < len_random; j++) {
314                         buffer[j] = (rand() % 0x100);
315                 }
316
317                 wtap_dump(dump, &pkthdr, &buffer[0], &err);
318         }
319
320         wtap_dump_close(dump, &err);
321
322         return 0;
323
324 }
325
326 /* Print usage statement and exit program */
327 static
328 void usage(void)
329 {
330         int     num_entries = array_length(examples);
331         int     i;
332
333         printf("Usage: randpkt [-b maxbytes] [-c count] [-t type] filename\n");
334         printf("Default max bytes (per packet) is 5000\n");
335         printf("Default count is 1000.\n");
336         printf("Types:\n");
337
338         for (i = 0; i < num_entries; i++) {
339                 printf("\t%s\t%s\n", examples[i].abbrev, examples[i].longname);
340         }
341
342         printf("\n");
343
344         exit(0);
345 }
346
347 /* Parse command-line option "type" and return enum type */
348 static
349 int parse_type(char *string)
350 {
351         int     num_entries = array_length(examples);
352         int     i;
353
354         for (i = 0; i < num_entries; i++) {
355                 if (strcmp(examples[i].abbrev, string) == 0) {
356                         return examples[i].produceable_type;
357                 }
358         }
359
360         /* default type */
361         return PKT_ETHERNET;
362 }
363
364 /* Find pkt_example record and return pointer to it */
365 static
366 pkt_example* find_example(int type)
367 {
368         int     num_entries = array_length(examples);
369         int     i;
370
371         for (i = 0; i < num_entries; i++) {
372                 if (examples[i].produceable_type == type) {
373                         return &examples[i];
374                 }
375         }
376
377         printf("Internal error. Type %d has no entry in examples table.\n", type);
378         exit(0);
379 }
380
381 /* Seed the random-number generator */
382 void
383 seed(void)
384 {
385         unsigned int    randomness;
386
387 #if defined(linux)
388         /* Okay, I should use #ifdef HAVE_DEV_RANDOM, but this is a quick hack */
389         int             fd;
390
391         fd = open("/dev/random", O_RDONLY);
392         if (fd < 0) {
393                 printf("Could not open /dev/random for reading: %s\n", strerror(errno));
394                 exit(0);
395         }
396
397         read(fd, &randomness, sizeof(randomness));
398 #else
399         time_t now;
400
401         now = time(NULL);
402         randomness = (unsigned int) now;
403 #endif
404
405         srand(randomness);
406 }