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