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