From Colin O'Flynn:
[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$
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 #ifndef HAVE_GETOPT
35 #include "wsutil/wsgetopt.h"
36 #endif
37
38 #ifdef HAVE_FCNTL_H
39 #include <fcntl.h>
40 #endif
41
42 #include <time.h>
43 #include <errno.h>
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <glib.h>
49 #include "wiretap/wtap.h"
50 #include "wsutil/file_util.h"
51
52 #ifdef _WIN32
53 #include <wsutil/unicode-utils.h>
54 #endif /* _WIN32 */
55
56 #define array_length(x) (sizeof x / sizeof x[0])
57
58 /* Types of produceable packets */
59 enum {
60         PKT_ARP,
61         PKT_BGP,
62         PKT_BVLC,
63         PKT_DNS,
64         PKT_ETHERNET,
65         PKT_FDDI,
66         PKT_GIOP,
67         PKT_ICMP,
68         PKT_IP,
69         PKT_LLC,
70         PKT_M2M,
71         PKT_MEGACO,
72         PKT_NBNS,
73         PKT_NCP2222,
74         PKT_SCTP,
75         PKT_SYSLOG,
76         PKT_TCP,
77         PKT_TDS,
78         PKT_TR,
79         PKT_UDP,
80         PKT_USB,
81         PKT_USB_LINUX
82 };
83
84 typedef struct {
85         const char      *abbrev;
86         const char      *longname;
87         int             produceable_type;
88         int             sample_wtap_encap;
89         guint8          *sample_buffer;
90         int             sample_length;
91         guint8          *pseudo_buffer;
92         int             pseudo_length;
93 } pkt_example;
94
95 /* Ethernet, indicating ARP */
96 guint8 pkt_arp[] = {
97         0xff, 0xff, 0xff, 0xff,
98         0xff, 0xff, 0x00, 0x00,
99         0x32, 0x25, 0x0f, 0xff,
100         0x08, 0x06
101 };
102
103 /* Ethernet+IP+UDP, indicating DNS */
104 guint8 pkt_dns[] = {
105         0xff, 0xff, 0xff, 0xff,
106         0xff, 0xff, 0x01, 0x01,
107         0x01, 0x01, 0x01, 0x01,
108         0x08, 0x00,
109
110         0x45, 0x00, 0x00, 0x3c,
111         0xc5, 0x9e, 0x40, 0x00,
112         0xff, 0x11, 0xd7, 0xe0,
113         0xd0, 0x15, 0x02, 0xb8,
114         0x0a, 0x01, 0x01, 0x63,
115
116         0x05, 0xe8, 0x00, 0x35,
117         0xff, 0xff, 0x2a, 0xb9,
118         0x30
119 };
120
121 /* Ethernet+IP, indicating ICMP */
122 guint8 pkt_icmp[] = {
123         0xff, 0xff, 0xff, 0xff,
124         0xff, 0xff, 0x01, 0x01,
125         0x01, 0x01, 0x01, 0x01,
126         0x08, 0x00,
127
128         0x45, 0x00, 0x00, 0x54,
129         0x8f, 0xb3, 0x40, 0x00,
130         0xfd, 0x01, 0x8a, 0x99,
131         0xcc, 0xfc, 0x66, 0x0b,
132         0xce, 0x41, 0x62, 0x12
133 };
134
135 /* Ethernet, indicating IP */
136 guint8 pkt_ip[] = {
137         0xff, 0xff, 0xff, 0xff,
138         0xff, 0xff, 0x01, 0x01,
139         0x01, 0x01, 0x01, 0x01,
140         0x08, 0x00
141 };
142
143 /* TR, indicating LLC */
144 guint8 pkt_llc[] = {
145         0x10, 0x40, 0x68, 0x00,
146         0x19, 0x69, 0x95, 0x8b,
147         0x00, 0x01, 0xfa, 0x68,
148         0xc4, 0x67
149 };
150
151 /* Ethernet, indicating WiMAX M2M */
152 guint8 pkt_m2m[] = {
153         0xff, 0xff, 0xff, 0xff,
154         0xff, 0xff, 0x00, 0x00,
155         0x32, 0x25, 0x0f, 0xff,
156         0x08, 0xf0
157 };
158
159 /* Ethernet+IP+UDP, indicating NBNS */
160 guint8 pkt_nbns[] = {
161         0xff, 0xff, 0xff, 0xff,
162         0xff, 0xff, 0x01, 0x01,
163         0x01, 0x01, 0x01, 0x01,
164         0x08, 0x00,
165
166         0x45, 0x00, 0x00, 0x3c,
167         0xc5, 0x9e, 0x40, 0x00,
168         0xff, 0x11, 0xd7, 0xe0,
169         0xd0, 0x15, 0x02, 0xb8,
170         0x0a, 0x01, 0x01, 0x63,
171
172         0x00, 0x89, 0x00, 0x89,
173         0x00, 0x00, 0x2a, 0xb9,
174         0x30
175 };
176
177 /* Ethernet+IP+UDP, indicating syslog */
178 guint8 pkt_syslog[] = {
179         0xff, 0xff, 0xff, 0xff,
180         0xff, 0xff, 0x01, 0x01,
181         0x01, 0x01, 0x01, 0x01,
182         0x08, 0x00,
183
184         0x45, 0x00, 0x00, 0x64,
185         0x20, 0x48, 0x00, 0x00,
186         0xfc, 0x11, 0xf8, 0x03,
187         0xd0, 0x15, 0x02, 0xb8,
188         0x0a, 0x01, 0x01, 0x63,
189
190         0x05, 0xe8, 0x02, 0x02,
191         0x00, 0x50, 0x51, 0xe1,
192         0x3c
193 };
194
195 /* TR+LLC+IP, indicating TCP */
196 guint8 pkt_tcp[] = {
197         0x10, 0x40, 0x68, 0x00,
198         0x19, 0x69, 0x95, 0x8b,
199         0x00, 0x01, 0xfa, 0x68,
200         0xc4, 0x67,
201
202         0xaa, 0xaa, 0x03, 0x00,
203         0x00, 0x00, 0x08, 0x00,
204
205         0x45, 0x00, 0x00, 0x28,
206         0x0b, 0x0b, 0x40, 0x00,
207         0x20, 0x06, 0x85, 0x37,
208         0xc0, 0xa8, 0x27, 0x01,
209         0xc0, 0xa8, 0x22, 0x3c
210 };
211
212 /* Ethernet+IP, indicating UDP */
213 guint8 pkt_udp[] = {
214         0xff, 0xff, 0xff, 0xff,
215         0xff, 0xff, 0x01, 0x01,
216         0x01, 0x01, 0x01, 0x01,
217         0x08, 0x00,
218
219         0x45, 0x00, 0x00, 0x3c,
220         0xc5, 0x9e, 0x40, 0x00,
221         0xff, 0x11, 0xd7, 0xe0,
222         0xd0, 0x15, 0x02, 0xb8,
223         0x0a, 0x01, 0x01, 0x63
224 };
225
226 /* Ethernet+IP+UDP, indicating BVLC */
227 guint8 pkt_bvlc[] = {
228         0xff, 0xff, 0xff, 0xff,
229         0xff, 0xff, 0x01, 0x01,
230         0x01, 0x01, 0x01, 0x01,
231         0x08, 0x00,
232
233         0x45, 0x00, 0x00, 0x3c,
234         0xc5, 0x9e, 0x40, 0x00,
235         0xff, 0x11, 0x01, 0xaa,
236         0xc1, 0xff, 0x19, 0x1e,
237         0xc1, 0xff, 0x19, 0xff,
238         0xba, 0xc0, 0xba, 0xc0,
239         0x00, 0xff, 0x2d, 0x5e,
240         0x81
241 };
242
243 /* TR+LLC+IPX, indicating NCP, with NCP Type == 0x2222 */
244 guint8 pkt_ncp2222[] = {
245         0x10, 0x40, 0x00, 0x00,
246         0xf6, 0x7c, 0x9b, 0x70,
247         0x68, 0x00, 0x19, 0x69,
248         0x95, 0x8b, 0xe0, 0xe0,
249         0x03, 0xff, 0xff, 0x00,
250         0x25, 0x02, 0x11, 0x00,
251         0x00, 0x74, 0x14, 0x00,
252         0x00, 0x00, 0x00, 0x00,
253         0x01, 0x04, 0x51, 0x00,
254         0x00, 0x00, 0x04, 0x00,
255         0x02, 0x16, 0x19, 0x7a,
256         0x84, 0x40, 0x01, 0x22,
257         0x22
258 };
259
260 /* Ethernet+IP+TCP, indicating GIOP */
261 guint8 pkt_giop[] = {
262         0xff, 0xff, 0xff, 0xff,
263         0xff, 0xff, 0x01, 0x01,
264         0x01, 0x01, 0x01, 0x01,
265         0x08, 0x00,
266
267         0x45, 0x00, 0x00, 0xa6,
268         0x00, 0x2f, 0x40, 0x00,
269         0x40, 0x06, 0x3c, 0x21,
270         0x7f, 0x00, 0x00, 0x01,
271         0x7f, 0x00, 0x00, 0x01,
272
273         0x30, 0x39, 0x04, 0x05,
274         0xac, 0x02, 0x1e, 0x69,
275         0xab, 0x74, 0xab, 0x64,
276         0x80, 0x18, 0x79, 0x60,
277         0xc4, 0xb8, 0x00, 0x00,
278         0x01, 0x01, 0x08, 0x0a,
279         0x00, 0x00, 0x48, 0xf5,
280         0x00, 0x00, 0x48, 0xf5,
281
282         0x47, 0x49, 0x4f, 0x50,
283         0x01, 0x00, 0x00, 0x00,
284         0x00, 0x00, 0x00, 0x30,
285         0x00, 0x00, 0x00, 0x00,
286         0x00, 0x00, 0x00, 0x01,
287         0x01
288 };
289
290 /* Ethernet+IP+TCP, indicating BGP */
291 guint8 pkt_bgp[] = {
292         0xff, 0xff, 0xff, 0xff,
293         0xff, 0xff, 0x01, 0x01,
294         0x01, 0x01, 0x01, 0x01,
295         0x08, 0x00,
296
297         0x45, 0x00, 0x00, 0xa6,
298         0x00, 0x2f, 0x40, 0x00,
299         0x40, 0x06, 0x3c, 0x21,
300         0x7f, 0x00, 0x00, 0x01,
301         0x7f, 0x00, 0x00, 0x01,
302
303         0x30, 0x39, 0x00, 0xb3,
304         0xac, 0x02, 0x1e, 0x69,
305         0xab, 0x74, 0xab, 0x64,
306         0x80, 0x18, 0x79, 0x60,
307         0xc4, 0xb8, 0x00, 0x00,
308         0x01, 0x01, 0x08, 0x0a,
309         0x00, 0x00, 0x48, 0xf5,
310         0x00, 0x00, 0x48, 0xf5,
311
312         0xff, 0xff, 0xff, 0xff,
313         0xff, 0xff, 0xff, 0xff,
314         0xff, 0xff, 0xff, 0xff,
315         0xff, 0xff, 0xff, 0xff,
316 };
317
318 /* Ethernet+IP+TCP, indicating TDS NetLib */
319 guint8 pkt_tds[] = {
320         0x00, 0x50, 0x8b, 0x0d,
321         0x7a, 0xed, 0x00, 0x08,
322         0xa3, 0x98, 0x39, 0x81,
323         0x08, 0x00,
324
325         0x45, 0x00, 0x03, 0x8d,
326         0x90, 0xd4, 0x40, 0x00,
327         0x7c, 0x06, 0xc3, 0x1b,
328         0xac, 0x14, 0x02, 0x22,
329         0x0a, 0xc2, 0xee, 0x82,
330
331         0x05, 0x99, 0x08, 0xf8,
332         0xff, 0x4e, 0x85, 0x46,
333         0xa2, 0xb4, 0x42, 0xaa,
334         0x50, 0x18, 0x3c, 0x28,
335         0x0f, 0xda, 0x00, 0x00,
336 };
337
338 /* Ethernet+IP, indicating SCTP */
339 guint8 pkt_sctp[] = {
340         0x00, 0xa0, 0x80, 0x00,
341         0x5e, 0x46, 0x08, 0x00,
342         0x03, 0x4a, 0x00, 0x35,
343         0x08, 0x00,
344
345         0x45, 0x00, 0x00, 0x7c,
346         0x14, 0x1c, 0x00, 0x00,
347         0x3b, 0x84, 0x4a, 0x54,
348         0x0a, 0x1c, 0x06, 0x2b,
349         0x0a, 0x1c, 0x06, 0x2c,
350 };
351
352
353 /* Ethernet+IP+SCTP, indicating MEGACO */
354 guint8 pkt_megaco[] = {
355         0x00, 0xa0, 0x80, 0x00,
356         0x5e, 0x46, 0x08, 0x00,
357         0x03, 0x4a, 0x00, 0x35,
358         0x08, 0x00,
359
360         0x45, 0x00, 0x00, 0x7c,
361         0x14, 0x1c, 0x00, 0x00,
362         0x3b, 0x84, 0x4a, 0x54,
363         0x0a, 0x1c, 0x06, 0x2b,
364         0x0a, 0x1c, 0x06, 0x2c,
365
366         0x40, 0x00, 0x0b, 0x80,
367         0x00, 0x01, 0x6f, 0x0a,
368         0x6d, 0xb0, 0x18, 0x82,
369         0x00, 0x03, 0x00, 0x5b,
370         0x28, 0x02, 0x43, 0x45,
371         0x00, 0x00, 0xa0, 0xbd,
372         0x00, 0x00, 0x00, 0x07,
373 };
374
375 /* This little data table drives the whole program */
376 pkt_example examples[] = {
377         { "arp", "Address Resolution Protocol",
378                 PKT_ARP,        WTAP_ENCAP_ETHERNET,
379                 pkt_arp,        array_length(pkt_arp),
380                 NULL,           0 },
381
382         { "bgp", "Border Gateway Protocol",
383                 PKT_BGP,        WTAP_ENCAP_ETHERNET,
384                 pkt_bgp,        array_length(pkt_bgp),
385                 NULL,           0 },
386
387         { "bvlc", "BACnet Virtual Link Control",
388                 PKT_BVLC,       WTAP_ENCAP_ETHERNET,
389                 pkt_bvlc,       array_length(pkt_bvlc),
390                 NULL,           0 },
391
392         { "dns", "Domain Name Service",
393                 PKT_DNS,        WTAP_ENCAP_ETHERNET,
394                 pkt_dns,        array_length(pkt_dns),
395                 NULL,           0 },
396
397         { "eth", "Ethernet",
398                 PKT_ETHERNET,   WTAP_ENCAP_ETHERNET,
399                 NULL,           0,
400                 NULL,           0 },
401
402         { "fddi", "Fiber Distributed Data Interface",
403                 PKT_FDDI,       WTAP_ENCAP_FDDI,
404                 NULL,           0,
405                 NULL,           0 },
406
407         { "giop", "General Inter-ORB Protocol",
408                 PKT_GIOP,       WTAP_ENCAP_ETHERNET,
409                 pkt_giop,       array_length(pkt_giop),
410                 NULL,           0 },
411
412         { "icmp", "Internet Control Message Protocol",
413                 PKT_ICMP,       WTAP_ENCAP_ETHERNET,
414                 pkt_icmp,       array_length(pkt_icmp),
415                 NULL,           0 },
416
417         { "ip", "Internet Protocol",
418                 PKT_IP,         WTAP_ENCAP_ETHERNET,
419                 pkt_ip,         array_length(pkt_ip),
420                 NULL,           0 },
421
422         { "llc", "Logical Link Control",
423                 PKT_LLC,        WTAP_ENCAP_TOKEN_RING,
424                 pkt_llc,        array_length(pkt_llc),
425                 NULL,           0 },
426
427         { "m2m", "WiMAX M2M Encapsulation Protocol",
428                 PKT_M2M,        WTAP_ENCAP_ETHERNET,
429                 pkt_m2m,        array_length(pkt_m2m),
430                 NULL,           0 },
431
432         { "megaco", "MEGACO",
433                 PKT_MEGACO,     WTAP_ENCAP_ETHERNET,
434                 pkt_megaco,     array_length(pkt_megaco),
435                 NULL,           0 },
436
437         { "nbns", "NetBIOS-over-TCP Name Service",
438                 PKT_NBNS,       WTAP_ENCAP_ETHERNET,
439                 pkt_nbns,       array_length(pkt_nbns),
440                 NULL,           0 },
441
442         { "ncp2222", "NetWare Core Protocol",
443                 PKT_NCP2222,    WTAP_ENCAP_TOKEN_RING,
444                 pkt_ncp2222,    array_length(pkt_ncp2222),
445                 NULL,           0 },
446
447         { "sctp", "Stream Control Transmission Protocol",
448                 PKT_SCTP,       WTAP_ENCAP_ETHERNET,
449                 pkt_sctp,       array_length(pkt_sctp),
450                 NULL,           0 },
451
452         { "syslog", "Syslog message",
453                 PKT_SYSLOG,     WTAP_ENCAP_ETHERNET,
454                 pkt_syslog,     array_length(pkt_syslog),
455                 NULL,           0 },
456
457         { "tds", "TDS NetLib",
458                 PKT_TDS,        WTAP_ENCAP_ETHERNET,
459                 pkt_tds,        array_length(pkt_tds),
460                 NULL,           0 },
461
462         { "tcp", "Transmission Control Protocol",
463                 PKT_TCP,        WTAP_ENCAP_TOKEN_RING,
464                 pkt_tcp,        array_length(pkt_tcp),
465                 NULL,           0 },
466
467         { "tr",  "Token-Ring",
468                 PKT_TR,         WTAP_ENCAP_TOKEN_RING,
469                 NULL,           0,
470                 NULL,           0 },
471
472         { "udp", "User Datagram Protocol",
473                 PKT_UDP,        WTAP_ENCAP_ETHERNET,
474                 pkt_udp,        array_length(pkt_udp),
475                 NULL,           0 },
476
477         { "usb", "Universal Serial Bus",
478                 PKT_USB,        WTAP_ENCAP_USB,
479                 NULL,           0,
480                 NULL,           0 },
481
482         { "usb-linux", "Universal Serial Bus with Linux specific header",
483                 PKT_USB_LINUX,  WTAP_ENCAP_USB_LINUX,
484                 NULL,           0,
485                 NULL,           0 },
486
487 };
488
489
490
491 static int parse_type(char *string);
492 static void usage(void);
493 static void seed(void);
494
495 static pkt_example* find_example(int type);
496
497 int
498 main(int argc, char **argv)
499 {
500
501         wtap_dumper             *dump;
502         struct wtap_pkthdr      pkthdr;
503         union wtap_pseudo_header        ps_header;
504         int                     i, j, len_this_pkt, len_random, err;
505         guint8                  buffer[65536];
506
507         int                     opt;
508
509         int                     produce_count = 1000; /* number of pkts to produce */
510         int                     produce_type = PKT_ETHERNET;
511         char                    *produce_filename = NULL;
512         int                     produce_max_bytes = 5000;
513         pkt_example             *example;
514
515 #ifdef _WIN32
516         arg_list_utf_16to8(argc, argv);
517 #endif /* _WIN32 */
518
519         while ((opt = getopt(argc, argv, "b:c:ht:")) != -1) {
520                 switch (opt) {
521                         case 'b':       /* max bytes */
522                                 produce_max_bytes = atoi(optarg);
523                                 if (produce_max_bytes > 65536) {
524                                         fprintf(stderr,
525                                             "randpkt: Max bytes is 65536\n");
526                                         exit(1);
527                                 }
528                                 break;
529
530                         case 'c':       /* count */
531                                 produce_count = atoi(optarg);
532                                 break;
533
534                         case 't':       /* type of packet to produce */
535                                 produce_type = parse_type(optarg);
536                                 break;
537
538                         case 'h':
539                         default:
540                                 usage();
541                                 break;
542                 }
543         }
544
545         /* any more command line parameters? */
546         if (argc > optind) {
547                 produce_filename = argv[optind];
548         }
549         else {
550                 usage();
551         }
552
553         example = find_example(produce_type);
554
555
556         dump = wtap_dump_open(produce_filename, WTAP_FILE_PCAP,
557                 example->sample_wtap_encap, produce_max_bytes, FALSE /* compressed */, &err);
558         if (!dump) {
559                 fprintf(stderr,
560                     "randpkt: Error writing to %s\n", produce_filename);
561                 exit(2);
562         }
563
564         seed();
565
566         /* reduce max_bytes by # of bytes already in sample */
567         if (produce_max_bytes <= example->sample_length) {
568                 fprintf(stderr,
569                     "randpkt: Sample packet length is %d, which is greater than or equal to\n",
570                     example->sample_length);
571                 fprintf(stderr, "your requested max_bytes value of %d\n",
572                     produce_max_bytes);
573                 exit(1);
574         }
575         else {
576                 produce_max_bytes -= example->sample_length;
577         }
578
579         memset(&pkthdr, 0, sizeof(pkthdr));
580         memset(&ps_header, 0, sizeof(ps_header));
581         memset(buffer, 0, sizeof(buffer));
582
583         pkthdr.pkt_encap = example->sample_wtap_encap;
584
585         /* Load the sample pseudoheader into our pseudoheader buffer */
586         if (example->pseudo_buffer)
587                 memcpy(&ps_header, example->pseudo_buffer, example->pseudo_length);
588
589         /* Load the sample into our buffer */
590         if (example->sample_buffer)
591                 memcpy(&buffer[0], example->sample_buffer, example->sample_length);
592
593         /* Produce random packets */
594         for (i = 0; i < produce_count; i++) {
595                 if (produce_max_bytes > 0) {
596                         len_random = (rand() % produce_max_bytes + 1);
597                 }
598                 else {
599                         len_random = 0;
600                 }
601
602                 len_this_pkt = example->sample_length + len_random;
603
604                 pkthdr.caplen = len_this_pkt;
605                 pkthdr.len = len_this_pkt;
606                 pkthdr.ts.secs = i; /* just for variety */
607
608                 for (j = example->pseudo_length; j < (int) sizeof(ps_header); j++) {
609                         ((guint8*)&ps_header)[j] = (rand() % 0x100);
610                 }
611
612                 for (j = example->sample_length; j < len_this_pkt; j++) {
613                         /* Add format strings here and there */
614                         if ((int) (100.0*rand()/(RAND_MAX+1.0)) < 3 && j < (len_random - 3)) {
615                                 memcpy(&buffer[j], "%s", 3);
616                                 j += 2;
617                         } else {
618                                 buffer[j] = (rand() % 0x100);
619                         }
620                 }
621
622                 wtap_dump(dump, &pkthdr, &ps_header, &buffer[0], &err);
623         }
624
625         wtap_dump_close(dump, &err);
626
627         return 0;
628
629 }
630
631 /* Print usage statement and exit program */
632 static
633 void usage(void)
634 {
635         int     num_entries = array_length(examples);
636         int     i;
637
638         printf("Usage: randpkt [-b maxbytes] [-c count] [-t type] filename\n");
639         printf("Default max bytes (per packet) is 5000\n");
640         printf("Default count is 1000.\n");
641         printf("Types:\n");
642
643         for (i = 0; i < num_entries; i++) {
644                 printf("\t%s\t%s\n", examples[i].abbrev, examples[i].longname);
645         }
646
647         printf("\n");
648
649         exit(0);
650 }
651
652 /* Parse command-line option "type" and return enum type */
653 static
654 int parse_type(char *string)
655 {
656         int     num_entries = array_length(examples);
657         int     i;
658
659         for (i = 0; i < num_entries; i++) {
660                 if (strcmp(examples[i].abbrev, string) == 0) {
661                         return examples[i].produceable_type;
662                 }
663         }
664
665         /* Complain */
666         fprintf(stderr, "randpkt: Type %s not known.\n", string);
667         exit(1);
668 }
669
670 /* Find pkt_example record and return pointer to it */
671 static
672 pkt_example* find_example(int type)
673 {
674         int     num_entries = array_length(examples);
675         int     i;
676
677         for (i = 0; i < num_entries; i++) {
678                 if (examples[i].produceable_type == type) {
679                         return &examples[i];
680                 }
681         }
682
683         fprintf(stderr,
684             "randpkt: Internal error. Type %d has no entry in examples table.\n",
685             type);
686         exit(1);
687 }
688
689 /* Seed the random-number generator */
690 void
691 seed(void)
692 {
693         unsigned int    randomness;
694         time_t now;
695 #ifndef _WIN32
696         int             fd;
697         ssize_t         ret;
698
699 #define RANDOM_DEV "/dev/urandom"
700
701         /*
702          * Assume it's at least worth trying /dev/urandom on UN*X.
703          * If it doesn't exist, fall back on time().
704          *
705          * XXX - Use CryptGenRandom on Windows?
706          */
707         fd = ws_open(RANDOM_DEV, O_RDONLY);
708         if (fd == -1) {
709                 if (errno != ENOENT) {
710                         fprintf(stderr,
711                             "randpkt: Could not open " RANDOM_DEV " for reading: %s\n",
712                             g_strerror(errno));
713                         exit(2);
714                 }
715                 goto fallback;
716         }
717
718         ret = ws_read(fd, &randomness, sizeof randomness);
719         if (ret == -1) {
720                 fprintf(stderr,
721                     "randpkt: Could not read from " RANDOM_DEV ": %s\n",
722                     g_strerror(errno));
723                 exit(2);
724         }
725         if ((size_t)ret != sizeof randomness) {
726                 fprintf(stderr,
727                     "randpkt: Tried to read %lu bytes from " RANDOM_DEV ", got %ld\n",
728                     (unsigned long)sizeof randomness, (long)ret);
729                 exit(2);
730         }
731         srand(randomness);
732         ws_close(fd);
733         return;
734
735 fallback:
736 #endif
737         now = time(NULL);
738         randomness = (unsigned int) now;
739
740         srand(randomness);
741 }