Use new-style wtap_dump().
[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.6 2000/05/19 02:42:16 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_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         union pseudo_header     ps_header;
229         int                     i, j, len_this_pkt, len_random, err;
230         guint8                  buffer[65536];
231
232         int                     opt;
233         extern char             *optarg;
234         extern int              optind;
235
236         int                     produce_count = 1000; /* number of pkts to produce */
237         int                     produce_type = PKT_ETHERNET;
238         char                    *produce_filename = NULL;
239         int                     produce_max_bytes = 5000;
240         pkt_example             *example;
241
242         while ((opt = getopt(argc, argv, "b:c:t:")) != EOF) {
243                 switch (opt) {
244                         case 'b':       /* max bytes */
245                                 produce_max_bytes = atoi(optarg);
246                                 if (produce_max_bytes > 65536) {
247                                         printf("Max bytes is 65536\n");
248                                         exit(0);
249                                 }
250                                 break;
251
252                         case 'c':       /* count */
253                                 produce_count = atoi(optarg);
254                                 break;
255
256                         case 't':       /* type of packet to produce */
257                                 produce_type = parse_type(optarg);
258                                 break;
259
260                         default:
261                                 usage();
262                                 break;
263                 }
264         }
265
266         /* any more command line parameters? */
267         if (argc > optind) {
268                 produce_filename = argv[optind];
269         }
270         else {
271                 usage();
272         }
273
274         example = find_example(produce_type);
275
276         pkthdr.ts.tv_sec = 0;
277         pkthdr.ts.tv_usec = 0;
278         pkthdr.pkt_encap = example->sample_wtap_encap;
279
280         dump = wtap_dump_open(produce_filename, WTAP_FILE_PCAP,
281                 example->sample_wtap_encap, produce_max_bytes, &err);
282
283         seed();
284
285         /* reduce max_bytes by # of bytes already in sample */
286         if (produce_max_bytes <= example->sample_length) {
287                 printf("Sample packet length is %d, which is greater than or equal to\n", example->sample_length);
288                 printf("your requested max_bytes value of %d\n", produce_max_bytes);
289                 exit(0);
290         }
291         else {
292                 produce_max_bytes -= example->sample_length;
293         }
294
295         /* Load the sample into our buffer */
296         if (example->sample_buffer)
297                 memcpy(&buffer[0], example->sample_buffer, example->sample_length);
298
299         /* Produce random packets */
300         for (i = 0; i < produce_count; i++) {
301                 if (produce_max_bytes > 0) {
302                         len_random = (rand() % produce_max_bytes + 1);
303                 }
304                 else {
305                         len_random = 0;
306                 }
307
308                 len_this_pkt = example->sample_length + len_random;
309
310                 pkthdr.caplen = len_this_pkt;
311                 pkthdr.len = len_this_pkt;
312                 pkthdr.ts.tv_sec = i; /* just for variety */
313
314                 for (j = example->sample_length; j < len_random; j++) {
315                         buffer[j] = (rand() % 0x100);
316                 }
317
318                 wtap_dump(dump, &pkthdr, &ps_header, &buffer[0], &err);
319         }
320
321         wtap_dump_close(dump, &err);
322
323         return 0;
324
325 }
326
327 /* Print usage statement and exit program */
328 static
329 void usage(void)
330 {
331         int     num_entries = array_length(examples);
332         int     i;
333
334         printf("Usage: randpkt [-b maxbytes] [-c count] [-t type] filename\n");
335         printf("Default max bytes (per packet) is 5000\n");
336         printf("Default count is 1000.\n");
337         printf("Types:\n");
338
339         for (i = 0; i < num_entries; i++) {
340                 printf("\t%s\t%s\n", examples[i].abbrev, examples[i].longname);
341         }
342
343         printf("\n");
344
345         exit(0);
346 }
347
348 /* Parse command-line option "type" and return enum type */
349 static
350 int parse_type(char *string)
351 {
352         int     num_entries = array_length(examples);
353         int     i;
354
355         for (i = 0; i < num_entries; i++) {
356                 if (strcmp(examples[i].abbrev, string) == 0) {
357                         return examples[i].produceable_type;
358                 }
359         }
360
361         /* default type */
362         return PKT_ETHERNET;
363 }
364
365 /* Find pkt_example record and return pointer to it */
366 static
367 pkt_example* find_example(int type)
368 {
369         int     num_entries = array_length(examples);
370         int     i;
371
372         for (i = 0; i < num_entries; i++) {
373                 if (examples[i].produceable_type == type) {
374                         return &examples[i];
375                 }
376         }
377
378         printf("Internal error. Type %d has no entry in examples table.\n", type);
379         exit(0);
380 }
381
382 /* Seed the random-number generator */
383 void
384 seed(void)
385 {
386         unsigned int    randomness;
387
388 #if defined(linux)
389         /* Okay, I should use #ifdef HAVE_DEV_RANDOM, but this is a quick hack */
390         int             fd;
391
392         fd = open("/dev/random", O_RDONLY);
393         if (fd < 0) {
394                 printf("Could not open /dev/random for reading: %s\n", strerror(errno));
395                 exit(0);
396         }
397
398         read(fd, &randomness, sizeof(randomness));
399 #else
400         time_t now;
401
402         now = time(NULL);
403         randomness = (unsigned int) now;
404 #endif
405
406         srand(randomness);
407 }