mausezahn: use getopt_long instead of getopt
[netsniff-ng.git] / staging / mausezahn.c
blob7599b741789da785acd0f8570930550e33a992d5
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Mausezahn, a fast versatile traffic generator
4 * Copyright 2008, 2009, 2010 Herbert Haas.
5 * Subject to the GPL, version 2.
6 */
8 #define _GNU_SOURCE
9 #include <libnet.h>
10 #include <pcap/pcap.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <limits.h>
17 #include <sys/time.h>
18 #include <time.h>
19 #include <signal.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <arpa/inet.h>
23 #include <sys/ioctl.h>
24 #include <netinet/in.h>
25 #include <stdarg.h>
26 #include <getopt.h>
28 #include "mz.h"
29 #include "cli.h"
30 #include "mops.h"
31 #include "config.h"
32 #include "llist.h"
33 #include "die.h"
34 #include "dev.h"
36 enum operating_modes mode;
38 int ipv6_mode;
39 int quiet; // don't even print 'important standard short messages'
40 int verbose; // report character
41 int simulate; // if 1 then don't really send frames
43 char path[256];
44 char filename[256];
45 FILE *fp, *fp2; // global multipurpose file pointer
47 long double total_d;
48 clock_t mz_start, mz_stop;
50 int mz_rand;
51 int bwidth;
53 int32_t
54 jitter[TIME_COUNT_MAX];
56 int
57 rtp_log,
58 time0_flag, // If set then time0 has valid data
59 sqnr0_flag;
61 u_int8_t
62 mz_ssrc[4]; // holds RTP stream identifier for rcv_rtp()
64 u_int16_t
65 sqnr_cur,
66 sqnr_last,
67 sqnr_next;
69 u_int32_t
70 gind, // a global index to run through deltaRX, deltaTX, and jitter
71 gind_max; // the amount of entries used in the (ugly oversized) arrays; per default set to TIME_COUNT
73 struct tx_struct tx; // NOTE: tx elements are considered as default values for MOPS
75 struct device_struct device_list[MZ_MAX_DEVICES];
77 int device_list_entries;
79 int verbose_level = 0;
81 char mz_default_config_path[256];
82 char mz_default_log_path[256];
84 static const char *short_options = "46hqvVSxra:A:b:B:c:d:E:f:F:l:p:P:R:t:T:M:Q:X:";
86 static void signal_handler(int number)
88 clean_up(number);
91 void clean_up(int sig)
93 int i;
94 struct arp_table_struct *cur, *next;
96 if (!quiet) fprintf(stderr, "\nMausezahn cleans up...\n");
98 if (fp != NULL) {
99 verbose_l1(" close files (1) ...\n");
101 fflush(fp);
102 fclose(fp);
105 if (fp2!=NULL) {
106 if (verbose) fprintf(stderr, " close files (2) ...\n");
107 (void) fflush(fp2);
108 (void) fclose(fp2);
111 // interactive mode?
112 if (mz_port) {
113 if (verbose) fprintf(stderr, " clear mops list...\n");
114 mops_cleanup(mp_head);
115 if (verbose) fprintf(stderr, " clear automops list...\n");
116 automops_cleanup(amp_head);
117 if (verbose) fprintf(stderr, " clear packet sequences...\n");
118 mz_ll_delete_list(packet_sequences);
121 for (i=0; i<device_list_entries; i++) {
122 if (device_list[i].p_arp!=NULL) {
123 pcap_close(device_list[i].p_arp);
124 fprintf(stderr, " stopped ARP process for device %s\n", device_list[i].dev);
126 if (device_list[i].arprx_thread!=0) {
127 pthread_cancel(device_list[i].arprx_thread);
128 if (verbose)
129 fprintf(stderr, " (ARP thread for device %s done)\n", device_list[i].dev);
132 if (device_list[i].arp_table!=NULL) {
133 cur=device_list[i].arp_table;
134 while (cur!=NULL) {
135 next = cur->next;
136 if (cur!=NULL) free(cur);
137 cur=next;
141 // close packet sockets
142 if (device_list[i].ps>=0) {
143 close(device_list[i].ps);
148 if (verbose) fprintf(stderr, "finished.\n");
149 exit(sig);
153 static void help(void)
155 printf("\nmausezahn %s, a fast versatile traffic generator\n", VERSION_STRING);
156 puts("http://www.netsniff-ng.org\n\n"
157 "Usage: mausezahn [options] [interface] <keyword>|<arg-string>|<hex-string>\n"
158 "Options:\n"
159 " -x <port> Interactive mode with telnet CLI, default port: 25542\n"
160 " -l <ip> Listen address to bind to when in interactive mode, default: 0.0.0.0\n"
161 " -4 IPv4 mode (default)\n"
162 " -6 IPv6 mode\n"
163 " -R <PRIO> Set socket priority\n"
164 " -c <count> Send packet count times, default:1, infinite:0\n"
165 " -d <delay> Apply delay between transmissions. The delay value can be\n"
166 " specified in usec (default, no additional unit needed), or in\n"
167 " msec (e.g. 100m or 100msec), or in seconds (e.g. 100s or 100sec)\n"
168 " -r Multiplies the specified delay with a random value\n"
169 " -p <length> Pad the raw frame to specified length (using random bytes)\n"
170 " -a <srcmac|keyword> Use specified source mac address, no matter what has\n"
171 " been specified with other arguments; keywords see below,\n"
172 " Default is own interface\n"
173 " -b <dstmac|keyword> Same with destination mac address; keywords:\n"
174 " rand Use a random MAC address\n"
175 " bc Use a broadcast MAC address\n"
176 " own Use own interface MAC address (default for source MAC)\n"
177 " stp Use IEEE 802.1d STP multicast address\n"
178 " cisco Use Cisco multicast address as used for CDP, VTP, or PVST+\n"
179 " -A <srcip> Use specified source IP address (default is own interface IP)\n"
180 " -B <dstip|dnsname> Send packet to specified destination IP or domain name\n"
181 " -P <ascii payload> Use the specified ASCII payload\n"
182 " -f <filename> Read the ASCII payload from a file\n"
183 " -F <filename> Read the hexadecimal payload from a file\n"
184 " -Q <[CoS:]vlan> Specify 802.1Q VLAN tag and optional Class of Service, you can\n"
185 " specify multiple 802.1Q VLAN tags (QinQ...) by separating them\n"
186 " via a comma or a period (e.g. '5:10,20,2:30')\n"
187 " -t <packet-type|help> Specify packet type for autobuild (you don't need to care for\n"
188 " encapsulations in lower layers, most packet types allow/require\n"
189 " additional packet-specific arguments in an <arg-string>;\n"
190 " Currently supported types: arp, bpdu, cdp, ip, icmp, udp, tcp,\n"
191 " dns, rtp, syslog, lldp and more;\n"
192 " For context-help use 'help' as <arg-string>!\n"
193 " -T <packet-type> Specify packet type for server mode, currently only rtp is supported;\n"
194 " Enter -T help or -T rtp help for further information\n"
195 " -M <MPLS-label> Insert a MPLS label, enter '-M help' for a syntax description\n"
196 " -V|VV|... Verbose and more verbose mode\n"
197 " -q Quiet mode, even omit 'important' standard short messages\n"
198 " -S Simulation mode: DOES NOT put anything on the wire, this is\n"
199 " typically combined with one of the verbose modes (v or V)\n"
200 " -v Show version\n"
201 " -h Print this help\n\n"
202 "Examples:\n"
203 " mausezahn -x 99\n"
204 " mausezahn -c 0 -d 2s -t bpdu conf\n"
205 " mausezahn -t cdp change -c 0\n"
206 " mausezahn -t syslog sev=3 -P \"You have been mausezahned.\" -A 10.1.1.109 -B 192.168.7.7\n"
207 " mausezahn eth0 -A rand -B 1.1.1.1 -c 0 -t tcp \"dp=1-1023, flags=syn\"\n\n"
208 "Note:\n"
209 " This tool is targeted for network developers! You should\n"
210 " be aware of what you are doing and what these options above\n"
211 " mean! Only use this tool in an isolated LAN that you own!\n\n"
212 "Please report bugs to <bugs@netsniff-ng.org>\n"
213 "Copyright (C) 2008-2010 Herbert Haas <herbert@perihel.at>,\n"
214 "Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
215 "Swiss federal institute of technology (ETH Zurich)\n"
216 "License: GNU GPL version 2.0\n"
217 "This is free software: you are free to change and redistribute it.\n"
218 "There is NO WARRANTY, to the extent permitted by law.\n");
219 die();
222 static void version(void)
224 printf("\nmausezahn %s, Git id: %s\n", VERSION_LONG, GITVERSION);
225 puts("a fast versatile traffic generator\n"
226 "http://www.netsniff-ng.org\n\n"
227 "Please report bugs at https://github.com/netsniff-ng/netsniff-ng/issues\n"
228 "Copyright (C) 2008-2010 Herbert Haas <herbert@perihel.at>,\n"
229 "Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
230 "Swiss federal institute of technology (ETH Zurich)\n"
231 "License: GNU GPL version 2.0\n"
232 "This is free software: you are free to change and redistribute it.\n"
233 "There is NO WARRANTY, to the extent permitted by law.\n");
234 die();
237 int reset(void)
239 int i;
240 time_t t;
242 mz_default_config_path[0] = 0x00;
243 mz_default_log_path[0] = 0x00;
245 // Reset globals:
246 quiet = 0;
247 ipv6_mode = 0;
248 verbose = 0;
249 simulate = 0;
250 filename[0] = '\0';
251 path[0] = '\0';
252 gind=0;
253 gind_max = TIME_COUNT;
254 fp = NULL;
255 fp2 = NULL;
256 mz_port = 0;
257 mz_rand = 0;
258 char mz_listen_addr[16] = "0.0.0.0";
259 mp_head = NULL;
261 for (i=0;i<TIME_COUNT_MAX;i++) jitter[i] = 0;
263 time0_flag = 0; // If set then time0 has valid data
264 sqnr0_flag = 0; // If set then sqnr_last and sqnr_next has valid data
265 rtp_log = 0;
266 mz_ssrc[0]=0; mz_ssrc[1]=0; mz_ssrc[2]=0; mz_ssrc[3]=0;
268 // Reset mgmt parameters of TX:
269 tx.packet_mode = 1; // assume we don't care about L2
270 tx.count = 1;
271 tx.delay = DEFAULT_DELAY;
272 tx.prio = 0;
273 tx.arg_string[0] = '\0';
275 // Reset Ethernet parameters of TX:
276 tx.eth_params_already_set = 0;
277 for (i=0; i<6; i++) tx.eth_dst[i] = 0xff;
278 for (i=0; i<6; i++) tx.eth_src[i] = 0; // TODO: Get own MAC !!!
279 tx.eth_dst_txt[0] = '\0';
280 tx.eth_src_txt[0] = '\0';
281 tx.eth_dst_rand = 0;
282 tx.eth_src_rand = 0;
284 tx.eth_type = 0x800;
285 tx.eth_len = 0;
286 tx.eth_payload[0] = '\0';
287 tx.eth_payload_s = 0;
288 tx.padding = 0;
290 // Reset CDP parameters for TX:
291 tx.cdp_sum = 0;
292 tx.cdp_version = 0;
293 tx.cdp_ttl = 0;
294 tx.cdp_payload[0] = '\0';
295 tx.cdp_payload_s = 0;
296 tx.cdp_tlv_id[0] = '\0';
297 tx.cdp_tlv_id_len = 0;
299 // Reset 802.1Q parameters of TX:
300 tx.dot1Q=0;
301 tx.dot1Q_txt[0] = '\0';
303 // ASCII Payload:
304 tx.ascii = 0; // 1 if specified
305 tx.ascii_payload[0]= '\0';
307 // HEX Payload:
308 tx.hex_payload_s = 0;
310 // Reset MPLS parameters of TX:
311 tx.mpls = 0;
312 tx.mpls_txt[0] = '\0';
313 tx.mpls_label = 0;
314 tx.mpls_exp = 0;
315 tx.mpls_bos = 1;
316 tx.mpls_ttl = 255;
317 tx.mpls_verbose_string[0] = '\0';
319 // Reset IP parameters of TX:
320 tx.ip_src_txt[0] = '\0';
321 tx.ip_src_rand = 0;
322 tx.ip_dst_txt[0] = '\0';
323 tx.ip_src_isrange = 0;
324 tx.ip_src_start = 0;
325 tx.ip_src_stop = 0;
326 memset(&tx.ip6_src_start, 0, sizeof(tx.ip6_src_start));
327 memset(&tx.ip6_src_stop, 0, sizeof(tx.ip6_src_stop));
329 tx.ip_dst_start = 0;
330 tx.ip_dst_stop = 0;
331 memset(&tx.ip6_dst_start, 0, sizeof(tx.ip6_dst_start));
332 memset(&tx.ip6_dst_stop, 0, sizeof(tx.ip6_dst_stop));
333 tx.ip_dst_isrange = 0;
335 tx.ip_ttl = 0;
336 tx.ip_len = 0;
337 tx.ip_payload[0]= '\0';
338 tx.ip_payload_s = 0;
339 tx.ip_option[0]= '\0';
340 tx.ip_option_s = 0;
342 // Reset ICMP parameters:
343 tx.icmp_type=0;
344 tx.icmp_code=0;
345 tx.icmp_chksum=0; // 0=autofill
346 tx.icmp_ident=0x42;
347 tx.icmp_sqnr=0x1;
348 tx.icmp_payload_s=0;
350 // Reset general L4 parameters:
351 tx.sp = 0;
352 tx.dp = 0;
353 tx.sp_start = 0;
354 tx.sp_stop = 0;
355 tx.dp_start = 0;
356 tx.dp_stop = 0;
357 tx.sp_isrange = 0;
358 tx.dp_isrange = 0;
360 // Reset UDP parameters of TX:
362 tx.udp_len = 0; // If set to zero then create_udp_packet will calculate it
363 tx.udp_sum = 0;
364 tx.udp_payload[0] = '\0';
365 tx.udp_payload_s = 0;
367 // Reset TCP parameters of TX:
369 tx.tcp_seq = 42;
370 tx.tcp_seq_stop = 42;
371 tx.tcp_seq_delta = 0; // also used as 'isrange' meaning
372 tx.tcp_ack = 42;
373 tx.tcp_control = 0;
374 tx.tcp_win = 10000;
375 tx.tcp_sum = 0;
376 tx.tcp_urg = 0;
377 tx.tcp_len = 20; // Least size (TCP header only)
378 tx.tcp_payload[0] = '\0';
379 tx.tcp_payload_s = 0;
381 // Reset RTP parameters of TX:
382 tx.rtp_sqnr = 0;
383 tx.rtp_stmp = 0;
385 // Initialize random generator
386 time(&t);
387 srand((unsigned int)t);
388 srand48(t);
390 // Reset device_list
391 for (i=0; i<MZ_MAX_DEVICES; i++) {
392 device_list[i].arprx_thread = 0;
393 device_list[i].p_arp = NULL;
394 device_list[i].arp_table = NULL;
395 device_list[i].ps=-1;
396 device_list[i].cli=0;
397 device_list[i].mgmt_only=0;
400 return 0;
403 static void print_packet_types(void)
405 fprintf(stderr, "\n"
406 MAUSEZAHN_VERSION
407 "\n"
408 "| The following packet types are currently implemented:\n"
409 "|\n"
410 "| arp ... sends ARP packets\n"
411 "| bpdu ... sends BPDU packets (STP or PVST+)\n"
412 "| cdp ... sends CDP messages\n"
413 "| ip ... sends IPv4 packets\n"
414 "| udp ... sends UDP datagrams\n"
415 "| tcp ... sends TCP segments\n"
416 "| icmp ... sends ICMP messages\n"
417 "| igmp ... sends IGMP messages\n"
418 "| dns ... sends DNS messages\n"
419 "| rtp ... sends RTP datagrams\n"
420 "| syslog ... sends Syslog messages\n"
421 "|\n"
422 "| Of course you can build any other packet type 'manually' using the direct layer 2 mode.\n"
423 "| FYI: The interactive mode supports additional protocols. (Try mz -x <port>)\n"
424 "\n");
426 die();
429 // Purpose: Properly handle arguments and configure global structs (tx)
430 int getopts (int argc, char *argv[])
432 int i, c, rargs, RX=0, count_set=0, delay_set=0;
433 unsigned int time_factor;
434 char *packet_type=NULL, *mops_type=NULL;
435 char *dum;
436 unsigned char *dum1, *dum2;
437 bool do_help = false;
439 libnet_t *l;
440 char err_buf[LIBNET_ERRBUF_SIZE];
441 struct libnet_ether_addr *mymac;
443 FILE *afp;
444 char hexpld[MAX_PAYLOAD_SIZE*2];
445 int hexpld_specified=0;
446 long delay;
447 long prio;
448 char unit;
450 opterr = 1; // let getopt print error message if necessary
451 while ((c = getopt_long(argc, argv, short_options, NULL, NULL)) != -1) {
452 switch (c) {
453 case '4':
454 tx.eth_type = 0x0800;
455 ipv6_mode=0;
456 break;
457 case '6':
458 tx.eth_type = 0x86dd;
459 ipv6_mode=1;
460 break;
461 case 'R':
462 errno = 0;
463 prio = strtol(optarg, NULL, 0);
464 if (errno) {
465 perror("Couldn't parse priority");
466 return -1;
468 if (prio < 0 || prio > 0xffffffff) {
469 perror("Invalid priority value");
470 return -1;
472 tx.prio = (int)prio;
473 break;
474 case 'h':
475 help();
476 break;
477 case 'q':
478 quiet=1;
479 break;
480 case 'v':
481 version();
482 break;
483 case 'V':
484 verbose++;
485 break;
486 case 'S':
487 simulate=1;
488 break;
489 case 'x':
490 mz_port = MZ_DEFAULT_PORT;
491 break;
492 case 'l':
493 strncpy (mz_listen_addr, optarg, sizeof(mz_listen_addr));
494 break;
495 case 'a':
496 strncpy (tx.eth_src_txt, optarg, 32);
497 tx.packet_mode = 0;
498 break;
499 case 'A':
500 strncpy (tx.ip_src_txt, optarg, sizeof(tx.ip_src_txt));
501 break;
502 case 'b':
503 strncpy (tx.eth_dst_txt, optarg, 32);
504 tx.packet_mode = 0;
505 break;
506 case 'B':
507 strncpy (tx.ip_dst_txt, optarg, sizeof(tx.ip_dst_txt));
508 break;
509 case 'c':
510 errno=0;
511 tx.count = strtol(optarg, (char **)NULL, 10);
512 if ((errno == ERANGE && (tx.count == LONG_MAX || tx.count == LONG_MIN))
513 || (errno != 0 && tx.count == 0)) {
514 perror("strtol");
515 return (-1);
517 if (tx.count<0) tx.count=1; //TODO: Allow count=0 which means infinity (need to update all send_functions)
518 count_set=1;
519 break;
520 case 'd':
521 errno=0;
522 time_factor=0;
523 delay=0;
524 unit='u'; // default is usecs
525 if (sscanf(optarg, "%ld%c", &delay, &unit) == EOF) {
526 perror("sscanf");
527 return (-1);
529 if (delay < 0) {
530 fprintf(stderr, " Incorrect delay format\n");
531 return(-1);
533 if (unit == 's') time_factor=1000000; // seconds
534 else if (unit == 'm') time_factor=1000; // msecs
535 else if (unit == 'u') time_factor=1; // usecs
536 else {
537 fprintf(stderr, " Incorrect delay format\n");
538 return(-1);
540 tx.delay = delay * time_factor;
541 if ((errno == ERANGE && (tx.delay == LONG_MAX || tx.delay == LONG_MIN))
542 || (errno != 0 && tx.delay == 0)) {
543 perror("strtol");
544 return (-1);
546 if (tx.delay<0) tx.delay=0; // no delay
547 delay_set=1;
548 break;
549 case 'p':
550 errno=0;
551 tx.padding = strtol(optarg, (char **)NULL, 10);
552 if ((errno == ERANGE && (tx.padding == LONG_MAX || tx.padding == LONG_MIN))
553 || (errno != 0 && tx.padding == 0)) {
554 perror("strtol");
555 return (-1);
557 if (tx.padding>10000) {
558 fprintf(stderr, " Warning: Padding must not exceed 10000!\n");
559 return -1;
561 break;
562 case 't':
563 packet_type = optarg; // analyzed below
564 if (strcmp(packet_type,"help") == 0)
565 print_packet_types();
566 break;
567 case 'X':
568 mops_type = optarg; // MOPS TRANSITION STRATEGY -- analyzed below
569 break;
570 case 'T':
571 packet_type = optarg;
572 RX = 1;
573 break;
574 case 'r':
575 mz_rand = 1;
576 break;
577 case 'M':
578 if (strncmp(optarg,"help",4)==0) {
579 (void) get_mpls_params("help ");
581 else {
582 strncpy (tx.mpls_txt, optarg, 128);
583 tx.eth_type = ETHERTYPE_MPLS;
584 tx.packet_mode = 0;
585 tx.mpls=1;
587 break;
588 case 'P': // ASCII payload
589 strncpy((char*)tx.ascii_payload, optarg, MAX_PAYLOAD_SIZE);
590 tx.ascii = 1;
591 break;
592 case 'f': // ASCII payload in FILE
593 afp = fopen(optarg, "r");
594 if (!afp) {
595 fprintf(stderr, " mz/getopts: Can not open file %s. %s!\n", optarg, strerror(errno));
596 return -1;
598 if (fgets((char*)tx.ascii_payload, MAX_PAYLOAD_SIZE, afp) == NULL)
599 fprintf(stderr, " mz/getopts: File empty?\n");
600 fclose(afp);
601 tx.ascii = 1;
602 break;
603 case 'F': // HEX payload in FILE
604 afp = fopen(optarg, "r");
605 if (!afp) {
606 fprintf(stderr, " mz/getopts: Can not open file %s. %s!\n", optarg, strerror(errno));
607 return -1;
609 i=0;
610 while ( (hexpld[i]=fgetc(afp))!=EOF ) {
611 if (isspace(hexpld[i])) {
612 hexpld[i]=':';
614 i++;
616 hexpld[i]='\0';
617 fclose(afp);
618 hexpld_specified=1;
619 break;
620 case 'Q': // VLAN TAG
621 if (strncmp(optarg,"help",4)==0) {
622 print_dot1Q_help(); // ugly but most simple and safe solution
624 else {
625 strncpy (tx.dot1Q_txt, optarg, 32);
626 tx.dot1Q=1;
627 // determine number of VLAN tags
628 for (i=0; i<strlen(tx.dot1Q_txt); i++) {
629 if (tx.dot1Q_txt[i]==',') tx.dot1Q++;
631 tx.packet_mode = 0;
633 break;
634 case '?':
635 if ((optopt == 'a') || (optopt == 'b') || (optopt == 'c') ||
636 (optopt == 'd') || (optopt == 'f') || (optopt == 'p') ||
637 (optopt == 't') || (optopt == 'm'))
638 fprintf (stderr, " mz/getopts: Option -%c requires an argument.\n", optopt);
639 else if (isprint (optopt))
640 fprintf (stderr, " mz/getopts: Unknown option -%c'.\n", optopt);
641 else
642 fprintf (stderr, " mz/getopts: Unknown option character \\x%x'.\n", optopt);
643 return 1;
644 default:
645 fprintf (stderr," mz/getopts: Could not handle arguments properly!\n");
646 return 1;
649 // ********************************************
650 // Handle additional arguments
651 // ********************************************
653 // Greeting text
654 if (verbose) {
655 fprintf(stderr,"\n"
656 MAUSEZAHN_VERSION
657 "\n"
658 "Use at your own risk and responsibility!\n"
659 "-- Verbose mode --\n"
660 "\n");
663 if (optind+2 < argc) {
664 help();
667 if ((rargs=argc-optind)>2) { // number of remaining arguments
668 fprintf(stderr," mz/getopts: Too many arguments!\n");
669 return -1;
673 // There can be 0-2 additional arguments
674 switch (rargs) {
675 case 0:
676 if (lookupdev()) { // no device found
677 if (verbose) fprintf(stderr, " mz: no active interfaces found!\n");
678 strcpy(tx.device, "lo");
680 break;
681 case 1: // arg_string OR device given => find out!
682 if (__device_ifindex(argv[optind]) > 0) {
683 strncpy(tx.device, argv[optind], 16);
685 else { /// arg_string given => no device has been specified -- let's find one!
686 strncpy (tx.arg_string, argv[optind], MAX_PAYLOAD_SIZE);
687 do_help = !!getarg(tx.arg_string,"help", NULL);
688 if (!do_help) {
689 if (lookupdev()) {
690 /* no device found */
691 if (verbose)
692 fprintf(stderr, " mz: no active interfaces found!\n");
693 strcpy(tx.device, "lo");
695 if (verbose)
696 fprintf(stderr," mz: device not given, will use %s\n",tx.device);
699 break;
700 case 2: // both device and arg_string given
701 strncpy (tx.device, argv[optind], 16);
702 strncpy (tx.arg_string, argv[optind+1], MAX_PAYLOAD_SIZE);
703 break;
704 default:
705 fprintf(stderr," mz/getopts: Unknown argument problem!\n");
706 return 1;
709 if (hexpld_specified) {
710 strcat(tx.arg_string, ",p=");
711 strcat(tx.arg_string, hexpld);
715 //////////////////////////////////////////////////////////////////////////
717 // Initialize MAC and IP Addresses.
719 // - tx.eth_src = own interface MAC
720 // - tx.ip_src = own interface IP or user specified
721 // - tx.ip_dst = 255.255.255.255 or user specified (can be a range)
722 // - tx.ip_src_rand ... is set if needed.
725 // Get own device MAC address:
726 // Don't open context if only a help text is requested
727 if (!do_help && getarg(tx.arg_string,"help", NULL) !=1) {
728 l = libnet_init (LIBNET_LINK_ADV, tx.device, err_buf );
729 if (l == NULL) {
730 fprintf(stderr, " mz/getopts: libnet_init() failed (%s)", err_buf);
731 return -1;
733 mymac = libnet_get_hwaddr(l);
734 for (i=0; i<6; i++) {
735 tx.eth_src[i] = mymac->ether_addr_octet[i];
736 tx.eth_mac_own[i] = mymac->ether_addr_octet[i];
739 // Set source IP address:
740 if (strlen(tx.ip_src_txt)) { // option -A has been specified
741 if (mz_strcmp(tx.ip_src_txt, "bcast", 2)==0) {
742 if (ipv6_mode) {
743 fprintf(stderr, "Option -A does not support 'bcast' when in IPv6 mode.\n");
744 return 1;
746 tx.ip_src = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
747 } else if (strcmp(tx.ip_src_txt, "rand") == 0) {
748 if (ipv6_mode) {
749 fprintf(stderr, "Option -A does not support 'rand' when in IPv6 mode.\n");
750 return 1;
752 tx.ip_src_rand = 1;
753 tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0
755 else if (
756 (ipv6_mode && get_ip6_range_src(tx.ip_src_txt, l)) || // returns 1 when no range has been specified
757 (!ipv6_mode && get_ip_range_src(tx.ip_src_txt))
760 // name2addr{4,6} accepts a valid IP address or a FQDN:
761 if (ipv6_mode) {
762 tx.ip6_src = libnet_name2addr6(l, tx.ip_src_txt, LIBNET_RESOLVE);
763 if (libnet_in6_is_error(tx.ip6_src)) {
764 /* libnet_in6_is_error returns 1 for the valid IPv6 address
765 * ffff:ffff:ffff:ffff:ffff:ffff. Use an additional inet_pton()
766 * check to cover cases where this address is specified
767 * as source
769 struct in6_addr src_check;
770 if (inet_pton(AF_INET6, tx.ip_src_txt, &src_check) != 1) {
771 fprintf(stderr, "Failed to set source"
772 " IPv6 address. Please check if"
773 " source is set to a valid IPv6 address.\n");
774 return 1;
777 } else {
778 tx.ip_src = libnet_name2addr4(l, tx.ip_src_txt, LIBNET_RESOLVE);
779 if (tx.ip_src == -1) {
780 /* libnet_name2addr4() returns -1 for the valid address 255.255.255.255.
781 * Use an additional inet_pton() check to cover case where this address
782 * is specified as source
784 struct in_addr src_check;
785 if (inet_pton(AF_INET, tx.ip_src_txt, &src_check) != 1) {
786 fprintf(stderr, "Failed to set source"
787 " IPv4 address. Please check if"
788 " source is set to a valid IPv4 address.\n");
789 return 1;
794 } else {
795 // no source IP specified: by default use own IP address
796 if (ipv6_mode) {
797 tx.ip6_src = libnet_get_ipaddr6(l);
798 if (strncmp((char*)&tx.ip6_src,(char*)&in6addr_error, sizeof(in6addr_error))==0)
799 printf("Failed to set source IPv6 address: %s", l->err_buf);
801 else
802 tx.ip_src = libnet_get_ipaddr4(l);
805 // Set destination IP address:
806 if (strlen(tx.ip_dst_txt)) { // option -B has been specified
807 if (mz_strcmp(tx.ip_dst_txt, "rand", 2)==0) {
808 fprintf(stderr, "Option -B does not support random destination IP addresses currently.\n");
809 return 1;
812 if (mz_strcmp(tx.ip_dst_txt, "bcast", 2)==0) {
813 if (ipv6_mode) {
814 fprintf(stderr, "Option -B does not support 'bcast' when in IPv6 mode.\n");
815 return 1;
817 tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
818 } else if (
819 (ipv6_mode && get_ip6_range_dst(tx.ip_dst_txt, l)) || // returns 1 when no range has been specified
820 (!ipv6_mode && get_ip_range_dst(tx.ip_dst_txt)))
822 // name2addr{4, 6} accepts a valid IP address or a FQDN:
823 if (ipv6_mode) {
824 tx.ip6_dst = libnet_name2addr6(l, tx.ip_dst_txt, LIBNET_RESOLVE);
825 if (libnet_in6_is_error(tx.ip6_dst)) {
826 /* libnet_in6_is_error returns 1 for the valid IPv6 address
827 * ffff:ffff:ffff:ffff:ffff:ffff. Use an additional inet_pton()
828 * check to cover cases where this address is specified
829 * as destination
831 struct in6_addr dst_check;
832 if (inet_pton(AF_INET6, tx.ip_dst_txt, &dst_check) != 1) {
833 fprintf(stderr, "Failed to set destination"
834 " IPv6 address. Please check if"
835 " source is set to a valid IPv6 address.\n");
836 return 1;
839 } else {
840 tx.ip_dst = libnet_name2addr4(l, tx.ip_dst_txt, LIBNET_RESOLVE);
841 if (tx.ip_dst == -1) {
842 /* libnet_name2addr4() returns -1 for the valid address 255.255.255.255.
843 * Use an additional inet_pton() check to cover case where this address
844 * is specified as destination
846 struct in_addr dst_check;
847 if (inet_pton(AF_INET, tx.ip_dst_txt, &dst_check) != 1) {
848 fprintf(stderr, "Failed to set destination"
849 " IPv4 address. Please check if"
850 " destination is set to a valid IPv4 address.\n");
851 return 1;
858 else { // no destination IP specified: by default use broadcast
859 if (ipv6_mode) {
860 tx.ip6_dst = libnet_name2addr6 (l, "ff02::1", LIBNET_DONT_RESOLVE);
861 } else {
862 tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
866 // Initialize tx.ip_src_h and tx.ip_dst_h which are used by 'print_frame_details()'
867 // in verbose mode. See 'modifications.c'.
869 if (tx.ip_src_rand) { // ip_src_h already given, convert to ip_src
870 dum1 = (unsigned char*) &tx.ip_src_h;
871 dum2 = (unsigned char*) &tx.ip_src;
873 else { // ip_src already given, convert to ip_src_h
874 if (ipv6_mode) {
875 if (tx.ip_src_isrange) {
876 tx.ip6_src = tx.ip6_src_start;
878 } else {
879 dum1 = (unsigned char*) &tx.ip_src;
880 dum2 = (unsigned char*) &tx.ip_src_h;
884 if (ipv6_mode) {
885 if (tx.ip_dst_isrange) {
886 tx.ip6_dst = tx.ip6_dst_start;
888 } else {
889 *dum2 = *(dum1+3);
890 dum2++;
891 *dum2 = *(dum1+2);
892 dum2++;
893 *dum2 = *(dum1+1);
894 dum2++;
895 *dum2 = *dum1;
897 dum1 = (unsigned char*) &tx.ip_dst;
898 dum2 = (unsigned char*) &tx.ip_dst_h;
900 *dum2 = *(dum1+3);
901 dum2++;
902 *dum2 = *(dum1+2);
903 dum2++;
904 *dum2 = *(dum1+1);
905 dum2++;
906 *dum2 = *dum1;
909 libnet_destroy(l);
913 // END OF ADDRESS INITIALIZATION
915 //////////////////////////////////////////////////////////////////////////
918 ////// retrieve interface parameters ///////
920 for (i=0; i<device_list_entries; i++) {
921 get_dev_params(device_list[i].dev);
925 //////////////////////////////////////////////////////////////////////////
927 // Mausezahn CLI desired?
928 if (mz_port) {
929 // has port number been specified?
930 if (strlen(tx.arg_string)) {
931 mz_port = (int) str2int (tx.arg_string);
934 mz_cli_init();
935 cli();
938 //////////////////////////////////////////////////////////////////////////
940 // Mode decision
942 // Consider -t and -m option (used exclusively)
943 // -t => special packet types, stateless
945 // If -t not present then evaluate arg_string which must
946 // contain a byte-string in hexadecimal notation.
950 // ***** NEW: MOPS TRANSITION STRATEGY *****
951 if (mops_type != NULL) {
953 if (mz_strcmp(mops_type,"lldp",4)==0) {
954 mops_direct(tx.device, MOPS_LLDP, tx.arg_string);
959 if (packet_type == NULL) { // raw hex string given
960 mode = BYTE_STREAM;
962 else if (strcmp(packet_type,"arp")==0) {
963 mode = ARP;
965 else if (strcmp(packet_type,"bpdu")==0) {
966 mode = BPDU;
968 else if (strcmp(packet_type,"ip")==0) {
969 mode = IP;
971 else if (strcmp(packet_type,"udp")==0) {
972 mode = UDP;
974 else if (strcmp(packet_type,"icmp")==0) {
975 mode = ICMP;
977 else if (strcmp(packet_type,"icmp6")==0) {
978 mode = ICMP6;
980 else if (strcmp(packet_type,"tcp")==0) {
981 mode = TCP;
983 else if (strcmp(packet_type,"dns")==0) {
984 mode = DNS;
986 else if (strcmp(packet_type,"cdp")==0) {
987 mode = CDP;
989 else if (strcmp(packet_type,"syslog")==0) {
990 mode = SYSLOG;
992 else if (strcmp(packet_type, "igmp") == 0) {
993 mode = IGMP;
995 else if (strcmp(packet_type,"lldp")==0) {
996 mode = LLDP;
997 tx.packet_mode=0; // create whole frame by ourself
999 else if (strcmp(packet_type,"rtp")==0) {
1000 if (RX) {
1001 mode = RX_RTP;
1003 else {
1004 mode = RTP;
1005 if (!count_set) tx.count = 0;
1006 if (!delay_set) tx.delay = 20000; // 20 msec inter-packet delay for RTP
1009 else {
1010 fprintf(stderr, " mz: you must specify a valid packet type!\n");
1014 //////////////////////////////////////////////////////////////////////////
1016 // TODO: Implement macro support
1017 // Check macro types here
1019 return 0;
1022 int main(int argc, char **argv)
1024 // These handles are only used when creating L3 and above packets.
1025 libnet_t *l; // the context
1026 libnet_ptag_t t2=0, t3=0, t4=0; // handles to layers
1027 double cpu_time_used;
1029 reset();
1031 if ( getopts(argc, argv) )
1033 (void) fprintf(stderr, " Invalid command line parameters!\n");
1034 help();
1037 // Check whether hires timers are supported or not:
1038 (void) check_timer();
1040 signal(SIGINT, signal_handler); // to close all file pointers etc upon SIGINT
1042 switch (mode)
1044 case BYTE_STREAM:
1045 send_eth();
1046 break;
1048 case ARP:
1049 (void) send_arp();
1050 break;
1052 case BPDU:
1053 (void) send_bpdu();
1054 break;
1056 case CDP:
1057 (void) send_cdp();
1058 break;
1060 case IP: // From now on a new much more modular method is used:
1061 l = get_link_context();
1062 t3 = create_ip_packet(l); // t3 can be used for later header changes
1063 if (!quiet) complexity();
1064 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1065 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1066 else
1067 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1068 break;
1070 case ICMP:
1071 tx.ip_proto = 1;
1072 l = get_link_context();
1073 t4 = create_icmp_packet(l); // t4 can be used for later header changes
1074 t3 = create_ip_packet(l); // t3 can be used for later header changes
1075 if (!quiet) complexity();
1076 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1077 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1078 else
1079 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1080 break;
1082 case ICMP6:
1083 tx.ip_proto = 58;
1084 l = get_link_context();
1085 t4 = create_icmp6_packet(l); // t4 can be used for later header changes
1086 t3 = create_ip_packet(l); // t3 can be used for later header changes
1087 if (!quiet) complexity();
1088 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1089 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1090 else
1091 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1092 break;
1094 case UDP:
1095 tx.ip_proto = 17;
1096 l = get_link_context();
1097 t4 = create_udp_packet(l); // t4 can be used for later header changes
1098 t3 = create_ip_packet(l); // t3 can be used for later header changes
1099 if (!quiet) complexity();
1100 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1101 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1102 else
1103 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1104 break;
1106 case TCP:
1107 tx.ip_proto = 6;
1108 l = get_link_context();
1109 t4 = create_tcp_packet(l); // t4 can be used for later header changes
1110 t3 = create_ip_packet(l); // t3 can be used for later header changes
1111 if (!quiet) complexity();
1112 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1113 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1114 else
1115 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1116 break;
1118 case IGMP:
1119 tx.ip_proto = 2;
1120 l = get_link_context();
1121 t4 = create_igmp_packet(l);
1122 /* t3 can be used for later header changes */
1123 t3 = create_ip_packet(l);
1124 if (!quiet)
1125 complexity();
1127 /* Ethernet manipulation features does NOT use ARP to determine eth_dst
1128 * */
1129 if (tx.packet_mode == 0)
1130 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1131 else
1132 send_frame(l, t3, t4); // NOTE: send_frame also destroys context finaly
1133 break;
1135 case DNS:
1136 tx.ip_proto = 17;
1137 l = get_link_context();
1138 (void) create_dns_packet();
1139 t4 = create_udp_packet(l); // t4 can be used for later header changes
1140 t3 = create_ip_packet(l); // t3 can be used for later header changes
1141 if (!quiet) complexity();
1142 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1143 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1144 else
1145 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1146 break;
1148 case RTP:
1149 tx.ip_proto = 17;
1150 l = get_link_context();
1151 if (!quiet) fprintf(stderr, " mz: RTP mode! (count=%u, delay=%u usec)\n\n", tx.count, tx.delay);
1152 (void) create_rtp_packet();
1153 t4 = create_udp_packet(l); // t4 can be used for later header changes
1154 t3 = create_ip_packet(l); // t3 can be used for later header changes
1155 if (!quiet) complexity();
1156 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1157 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1158 else
1159 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1160 break;
1162 case RX_RTP: // Receive RTP packets
1163 rcv_rtp_init();
1164 rcv_rtp();
1165 break;
1167 case SYSLOG:
1168 tx.ip_proto = 17;
1169 l = get_link_context();
1170 (void) create_syslog_packet();
1171 t4 = create_udp_packet(l); // t4 can be used for later header changes
1172 t3 = create_ip_packet(l); // t3 can be used for later header changes
1173 if (!quiet) complexity();
1175 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1176 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1177 else
1178 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1179 break;
1181 case LLDP: // start with a new concept here
1182 //l = get_link_context();
1183 //(void) create_lldp_packet();
1184 // // // printf("SIZE=%lu\n",sizeof(struct tx_struct));
1185 fprintf(stderr, "LLDP is currently only supported via the interactive mode\n");
1186 exit(1);
1187 break;
1190 default:
1191 (void) fprintf(stderr," mz/main: unknown mode! Stop.\n");
1192 return (1);
1195 if (!quiet)
1197 mz_stop = clock();
1198 cpu_time_used = ((double) (mz_stop - mz_start)) / CLOCKS_PER_SEC;
1199 if (cpu_time_used > 0)
1201 total_d /= cpu_time_used;
1202 fprintf(stderr, "%.2f seconds (%.Lf packets per second)\n",cpu_time_used,total_d);
1204 else
1206 fprintf(stderr, "\n");
1210 return(0);