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