extcap: add randpktdump, a random packet generator.
[metze/wireshark/wip.git] / extcap / randpktdump.c
1 /* randpktdump.c
2  * randpktdump is an extcap tool used to generate random data for testing/educational purpose
3  *
4  * Copyright 2015, Dario Lombardo
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include "randpkt-core.h"
28
29 #include <glib.h>
30 #include <glib/gprintf.h>
31 #include <stdlib.h>
32
33 #ifdef HAVE_GETOPT_H
34         #include <getopt.h>
35 #endif
36
37 #ifndef HAVE_GETOPT_LONG
38         #include "wsutil/wsgetopt.h"
39 #endif
40
41 #ifdef _WIN32
42 #include <io.h>
43 #endif
44
45 #if defined(_WIN32) && !defined(__CYGWIN__)
46         #ifdef HAVE_WINDOWS_H
47                 #include <windows.h>
48         #endif
49
50         #include <ws2tcpip.h>
51
52         #ifdef HAVE_WINSOCK2_H
53                 #include <winsock2.h>
54         #endif
55
56         #include <process.h>
57
58         #define socket_handle_t SOCKET
59 #else
60 /*
61  * UN*X, or Windows pretending to be UN*X with the aid of Cygwin.
62  */
63 #define closesocket(socket)  close(socket)
64 #define socket_handle_t int
65 #define INVALID_SOCKET (-1)
66 #define SOCKET_ERROR (-1)
67 #endif
68
69 #define verbose_print(...) { if (verbose) printf(__VA_ARGS__); }
70 #define errmsprintf(...) { printf(__VA_ARGS__); printf("\n"); }
71
72 #define RANDPKT_EXTCAP_INTERFACE "randpkt"
73 #define RANDPKTDUMP_VERSION_MAJOR 0
74 #define RANDPKTDUMP_VERSION_MINOR 1
75 #define RANDPKTDUMP_VERSION_RELEASE 0
76
77 static gboolean verbose = TRUE;
78
79 enum {
80         OPT_HELP = 1,
81         OPT_VERSION,
82         OPT_VERBOSE,
83         OPT_LIST_INTERFACES,
84         OPT_LIST_DLTS,
85         OPT_INTERFACE,
86         OPT_CONFIG,
87         OPT_CAPTURE,
88         OPT_CAPTURE_FILTER,
89         OPT_FIFO,
90         OPT_MAXBYTES,
91         OPT_COUNT,
92         OPT_RANDOM_TYPE,
93         OPT_ALL_RANDOM,
94         OPT_TYPE
95 };
96
97 static struct option longopts[] = {
98         /* Generic application options */
99         { "help",                                       no_argument,            NULL, OPT_HELP},
100         { "version",                            no_argument,            NULL, OPT_VERSION},
101         { "verbose",                            optional_argument,      NULL, OPT_VERBOSE},
102         /* Extcap options */
103         { "extcap-interfaces",          no_argument,            NULL, OPT_LIST_INTERFACES},
104         { "extcap-dlts",                        no_argument,            NULL, OPT_LIST_DLTS},
105         { "extcap-interface",           required_argument,      NULL, OPT_INTERFACE},
106         { "extcap-config",                      no_argument,            NULL, OPT_CONFIG},
107         { "capture",                            no_argument,            NULL, OPT_CAPTURE},
108         { "extcap-capture-filter        ",      required_argument,      NULL, OPT_CAPTURE_FILTER},
109         { "fifo",                                       required_argument,      NULL, OPT_FIFO},
110         /* Interfaces options */
111         { "maxbytes",                           required_argument,      NULL, OPT_MAXBYTES},
112         { "count",                                      required_argument,      NULL, OPT_COUNT},
113         { "random-type",                        required_argument,      NULL, OPT_RANDOM_TYPE},
114         { "all-random",                         required_argument,      NULL, OPT_ALL_RANDOM},
115         { "type",                                       required_argument,      NULL, OPT_TYPE},
116     { 0, 0, 0, 0 }
117 };
118
119 #ifdef _WIN32
120 BOOLEAN IsHandleRedirected(DWORD handle)
121 {
122         HANDLE h = GetStdHandle(handle);
123         if (h) {
124                 BY_HANDLE_FILE_INFORMATION fi;
125                 if (GetFileInformationByHandle(h, &fi)) {
126                         return TRUE;
127                 }
128         }
129         return FALSE;
130 }
131
132 static void attach_parent_console()
133 {
134         BOOL outRedirected, errRedirected;
135
136         outRedirected = IsHandleRedirected(STD_OUTPUT_HANDLE);
137         errRedirected = IsHandleRedirected(STD_ERROR_HANDLE);
138
139         if (outRedirected && errRedirected) {
140                 /* Both standard output and error handles are redirected.
141                  * There is no point in attaching to parent process console.
142                  */
143                 return;
144         }
145
146         if (AttachConsole(ATTACH_PARENT_PROCESS) == 0) {
147                 /* Console attach failed. */
148                 return;
149         }
150
151         /* Console attach succeeded */
152         if (outRedirected == FALSE) {
153                 freopen("CONOUT$", "w", stdout);
154         }
155
156         if (errRedirected == FALSE) {
157                 freopen("CONOUT$", "w", stderr);
158         }
159 }
160 #endif
161
162 static void help(const char* binname)
163 {
164         unsigned i;
165         const char** abbrev_list;
166         const char** longname_list;
167         unsigned list_num;
168
169         printf("Help\n");
170         printf(" Usage:\n");
171         printf(" %s --extcap-interfaces\n", binname);
172         printf(" %s --extcap-interface=INTERFACE --extcap-dlts\n", binname);
173         printf(" %s --extcap-interface=INTERFACE --extcap-config\n", binname);
174         printf(" %s --extcap-interface=INTERFACE --type dns --count 10"
175                         "--fifo=FILENAME --capture\n", binname);
176         printf("\n\n");
177         printf("  --help: print this help\n");
178         printf("  --version: print the version\n");
179         printf("  --verbose: verbose mode\n");
180         printf("  --extcap-interfaces: list the extcap Interfaces\n");
181         printf("  --extcap-dlts: list the DLTs\n");
182         printf("  --extcap-interface <iface>: specify the extcap interface\n");
183         printf("  --extcap-config: list the additional configuration for an interface\n");
184         printf("  --capture: run the capture\n");
185         printf("  --extcap-capture-filter <filter>: the capture filter\n");
186         printf("  --fifo <file>: dump data to file or fifo\n");
187         printf("  --maxbytes <bytes>: max bytes per packet");
188         printf("  --count <num>: number of packets to generate\n");
189         printf("  --random-type: one random type is choosen for all packets\n");
190         printf("  --all-random: a random type is choosen for each packet\n");
191         printf("  --type <type>: the packet type\n");
192         printf("\n\nPacket types:\n");
193         randpkt_example_list(&abbrev_list, &longname_list, &list_num);
194         for (i = 0; i < list_num; i++) {
195                 printf("\t%-16s%s\n", abbrev_list[i], longname_list[i]);
196         }
197         g_free((char**)abbrev_list);
198         g_free((char**)longname_list);
199
200 }
201
202 static int list_interfaces(void)
203 {
204         printf("interface {value=%s}{display=Random packet generator}\n", RANDPKT_EXTCAP_INTERFACE);
205         return EXIT_SUCCESS;
206 }
207
208 static int list_config(char *interface)
209 {
210         unsigned inc = 0;
211         unsigned i;
212         const char** abbrev_list;
213         const char** longname_list;
214         unsigned list_num;
215
216         if (!interface) {
217                 g_fprintf(stderr, "ERROR: No interface specified.\n");
218                 return EXIT_FAILURE;
219         }
220
221         if (g_strcmp0(interface, RANDPKT_EXTCAP_INTERFACE)) {
222                 errmsprintf("ERROR: interface must be %s\n", RANDPKT_EXTCAP_INTERFACE);
223                 return EXIT_FAILURE;
224         }
225
226         printf("arg {number=%u}{call=--maxbytes}{display=Max bytes in a packet}"
227                 "{type=unsigned}{range=1,5000}{default=5000}{tooltip=The max number of bytes in a packet}\n",
228                 inc++);
229         printf("arg {number=%u}{call=--count}{display=Number of packets}"
230                 "{type=long}{default=1000}{tooltip=Number of packets to generate (-1 for infinite)}\n",
231                 inc++);
232         printf("arg {number=%u}{call=--random-type}{display=Random type}"
233                 "{type=boolean}{default=false}{tooltip=The packets type is randomly choosen}\n",
234                 inc++);
235         printf("arg {number=%u}{call=--all-random}{display=All random packets}"
236                 "{type=boolean}{default=false}{tooltip=Packet type for each packet is randomly choosen}\n",
237                 inc++);
238
239         /* Now the types */
240         printf("arg {number=%u}{call=--type}{display=Type of packet}"
241                 "{type=selector}{tooltip=Type of packet to generate}\n",
242                 inc);
243         randpkt_example_list(&abbrev_list, &longname_list, &list_num);
244         for (i = 0; i < list_num; i++) {
245                 printf("value {arg=%u}{value=%s}{display=%s}\n", inc, abbrev_list[i], longname_list[i]);
246         }
247         g_free((char**)abbrev_list);
248         g_free((char**)longname_list);
249         inc++;
250
251         return EXIT_SUCCESS;
252 }
253
254 static int list_dlts(const char *interface)
255 {
256         if (!interface) {
257                 printf("ERROR: No interface specified.\n");
258                 return EXIT_FAILURE;
259         }
260
261         if (g_strcmp0(interface, RANDPKT_EXTCAP_INTERFACE)) {
262                 printf("ERROR: interface must be %s\n", RANDPKT_EXTCAP_INTERFACE);
263                 return EXIT_FAILURE;
264         }
265
266         printf("dlt {number=147}{name=%s}{display=Generator dependent DLT}\n", RANDPKT_EXTCAP_INTERFACE);
267
268         return EXIT_SUCCESS;
269 }
270
271 int main(int argc, char *argv[])
272 {
273         int option_idx = 0;
274         int do_capture = 0;
275         int do_dlts = 0;
276         int do_config = 0;
277         int do_list_interfaces = 0;
278         int result;
279         char* fifo = NULL;
280         char* interface = NULL;
281         int maxbytes = 5000;
282         guint64 count = 1000;
283         int random_type = FALSE;
284         int all_random = FALSE;
285         char* type = NULL;
286         int produce_type = -1;
287         randpkt_example *example;
288         wtap_dumper* savedump;
289         int i;
290
291         if (argc == 1) {
292                 help(argv[0]);
293                 return EXIT_FAILURE;
294         }
295
296 #ifdef _WIN32
297         WSADATA wsaData;
298
299         attach_parent_console();
300 #endif  /* _WIN32 */
301
302         for (i = 0; i < argc; i++) {
303                 verbose_print("%s ", argv[i]);
304         }
305         verbose_print("\n");
306
307         while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) {
308                 switch (result) {
309                 case OPT_VERSION:
310                         printf("%u.%u.%u\n", RANDPKTDUMP_VERSION_MAJOR, RANDPKTDUMP_VERSION_MINOR, RANDPKTDUMP_VERSION_RELEASE);
311                         return 0;
312
313                 case OPT_VERBOSE:
314                         break;
315
316                 case OPT_LIST_INTERFACES:
317                         do_list_interfaces = 1;
318                         break;
319
320                 case OPT_LIST_DLTS:
321                         do_dlts = 1;
322                         break;
323
324                 case OPT_INTERFACE:
325                         if (interface)
326                                 g_free(interface);
327                         interface = g_strdup(optarg);
328                         break;
329
330                 case OPT_CONFIG:
331                         do_config = 1;
332                         break;
333
334                 case OPT_CAPTURE:
335                         do_capture = 1;
336                         break;
337
338                 case OPT_CAPTURE_FILTER:
339                         /* currently unused */
340                         break;
341
342                 case OPT_FIFO:
343                         if (fifo)
344                                 g_free(fifo);
345                         fifo = g_strdup(optarg);
346                         break;
347
348                 case OPT_HELP:
349                         help(argv[0]);
350                         return 0;
351
352                 case OPT_MAXBYTES:
353                         maxbytes = atoi(optarg);
354                         if (maxbytes > MAXBYTES_LIMIT) {
355                                 errmsprintf("randpktdump: Max bytes is %u\n", MAXBYTES_LIMIT);
356                                 return 1;
357                         }
358                         break;
359
360                 case OPT_COUNT:
361                         count = g_ascii_strtoull(optarg, NULL, 10);
362                         break;
363
364                 case OPT_RANDOM_TYPE:
365                         if (!g_ascii_strcasecmp("true", optarg)) {
366                                 random_type = TRUE;
367                         }
368                         break;
369
370                 case OPT_ALL_RANDOM:
371                         if (!g_ascii_strcasecmp("true", optarg)) {
372                                 all_random = TRUE;
373                         }
374                         break;
375
376                 case OPT_TYPE:
377                         type = g_strdup(optarg);
378                         break;
379
380                 case ':':
381                         /* missing option argument */
382                         printf("Option '%s' requires an argument\n", argv[optind - 1]);
383                         break;
384
385                 default:
386                         printf("Invalid option 1: %s\n", argv[optind - 1]);
387                         return EXIT_FAILURE;
388                 }
389         }
390
391         if (optind != argc) {
392                 printf("Invalid option: %s\n", argv[optind]);
393                 return EXIT_FAILURE;
394         }
395
396         if (do_list_interfaces)
397                 return list_interfaces();
398
399         if (do_config)
400                 return list_config(interface);
401
402         if (do_dlts)
403                 return list_dlts(interface);
404
405         /* Some sanity checks */
406         if ((random_type) && (all_random)) {
407                 errmsprintf("You can specify only one between: --random-type, --all-random\n");
408                 return EXIT_FAILURE;
409         }
410
411         /* Wireshark sets the type, even when random options are selected. We don't want it */
412         if (random_type || all_random) {
413                 g_free(type);
414                 type = NULL;
415         }
416
417 #ifdef _WIN32
418         result = WSAStartup(MAKEWORD(1,1), &wsaData);
419         if (result != 0) {
420                 if (verbose)
421                         errmsprintf("ERROR: WSAStartup failed with error: %d\n", result);
422                 return 1;
423         }
424 #endif  /* _WIN32 */
425
426         if (do_capture) {
427                 if (!fifo) {
428                         errmsprintf("ERROR: No FIFO or file specified\n");
429                         return 1;
430                 }
431
432                 if (g_strcmp0(interface, RANDPKT_EXTCAP_INTERFACE)) {
433                         errmsprintf("ERROR: invalid interface\n");
434                         return 1;
435                 }
436
437                 randpkt_seed();
438
439                 if (!all_random) {
440                         produce_type = randpkt_parse_type(type);
441                         g_free(type);
442
443                         example = randpkt_find_example(produce_type);
444                         if (!example)
445                                 return 1;
446
447                         verbose_print("Generating packets: %s\n", example->abbrev);
448
449                         randpkt_example_init(example, fifo, maxbytes);
450                         randpkt_loop(example, count);
451                         randpkt_example_close(example);
452                 } else {
453                         produce_type = randpkt_parse_type(NULL);
454                         example = randpkt_find_example(produce_type);
455                         if (!example)
456                                 return 1;
457                         randpkt_example_init(example, fifo, maxbytes);
458
459                         while (count-- > 0) {
460                                 randpkt_loop(example, 1);
461                                 produce_type = randpkt_parse_type(NULL);
462
463                                 savedump = example->dump;
464
465                                 example = randpkt_find_example(produce_type);
466                                 if (!example)
467                                         return 1;
468                                 example->dump = savedump;
469                         }
470                         randpkt_example_close(example);
471                 }
472         }
473
474         /* clean up stuff */
475         if (interface)
476                 g_free(interface);
477
478         if (fifo)
479                 g_free(fifo);
480
481         if (type)
482                 g_free(type);
483
484         return 0;
485 }
486
487 #ifdef _WIN32
488 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
489         LPSTR lpCmdLine, int nCmdShow) {
490         return main(__argc, __argv);
491 }
492 #endif
493
494 /*
495  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
496  *
497  * Local variables:
498  * c-basic-offset: 4
499  * tab-width: 4
500  * indent-tabs-mode: t
501  * End:
502  *
503  * vi: set shiftwidth=4 tabstop=4 expandtab:
504  * :indentSize=4:tabSize=4:noTabs=false:
505  */