mausezahn: Support -R to set packet priority
[netsniff-ng-new.git] / staging / mausezahn.c
blobc38ea468093620563b4cedc72c96409492b6eea6
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>
27 #include "mz.h"
28 #include "cli.h"
29 #include "mops.h"
30 #include "config.h"
31 #include "llist.h"
32 #include "die.h"
33 #include "dev.h"
35 int verbose_level = 0;
37 static const char *short_options = "46hqvVSxra:A:b:B:c:d:E:f:F:l:p:P:R:t:T:M:Q:X:";
39 static void signal_handler(int number)
41 clean_up(number);
44 void clean_up(int sig)
46 int i;
47 struct arp_table_struct *cur, *next;
49 if (!quiet) fprintf(stderr, "\nMausezahn cleans up...\n");
51 if (fp != NULL) {
52 verbose_l1(" close files (1) ...\n");
54 fflush(fp);
55 fclose(fp);
58 if (fp2!=NULL) {
59 if (verbose) fprintf(stderr, " close files (2) ...\n");
60 (void) fflush(fp2);
61 (void) fclose(fp2);
64 // interactive mode?
65 if (mz_port) {
66 if (verbose) fprintf(stderr, " clear mops list...\n");
67 mops_cleanup(mp_head);
68 if (verbose) fprintf(stderr, " clear automops list...\n");
69 automops_cleanup(amp_head);
70 if (verbose) fprintf(stderr, " clear packet sequences...\n");
71 mz_ll_delete_list(packet_sequences);
74 for (i=0; i<device_list_entries; i++) {
75 if (device_list[i].p_arp!=NULL) {
76 pcap_close(device_list[i].p_arp);
77 fprintf(stderr, " stopped ARP process for device %s\n", device_list[i].dev);
79 if (device_list[i].arprx_thread!=0) {
80 pthread_cancel(device_list[i].arprx_thread);
81 if (verbose)
82 fprintf(stderr, " (ARP thread for device %s done)\n", device_list[i].dev);
85 if (device_list[i].arp_table!=NULL) {
86 cur=device_list[i].arp_table;
87 while (cur!=NULL) {
88 next = cur->next;
89 if (cur!=NULL) free(cur);
90 cur=next;
94 // close packet sockets
95 if (device_list[i].ps>=0) {
96 close(device_list[i].ps);
101 if (verbose) fprintf(stderr, "finished.\n");
102 exit(sig);
106 static void help(void)
108 printf("\nmausezahn %s, a fast versatile traffic generator\n", VERSION_STRING);
109 puts("http://www.netsniff-ng.org\n\n"
110 "Usage: mausezahn [options] [interface] <keyword>|<arg-string>|<hex-string>\n"
111 "Options:\n"
112 " -x <port> Interactive mode with telnet CLI, default port: 25542\n"
113 " -l <ip> Listen address to bind to when in interactive mode, default: 0.0.0.0\n"
114 " -4 IPv4 mode (default)\n"
115 " -6 IPv6 mode\n"
116 " -R <PRIO> Set socket priority\n"
117 " -c <count> Send packet count times, default:1, infinite:0\n"
118 " -d <delay> Apply delay between transmissions. The delay value can be\n"
119 " specified in usec (default, no additional unit needed), or in\n"
120 " msec (e.g. 100m or 100msec), or in seconds (e.g. 100s or 100sec)\n"
121 " -r Multiplies the specified delay with a random value\n"
122 " -p <length> Pad the raw frame to specified length (using random bytes)\n"
123 " -a <srcmac|keyword> Use specified source mac address, no matter what has\n"
124 " been specified with other arguments; keywords see below,\n"
125 " Default is own interface\n"
126 " -b <dstmac|keyword> Same with destination mac address; keywords:\n"
127 " rand Use a random MAC address\n"
128 " bc Use a broadcast MAC address\n"
129 " own Use own interface MAC address (default for source MAC)\n"
130 " stp Use IEEE 802.1d STP multicast address\n"
131 " cisco Use Cisco multicast address as used for CDP, VTP, or PVST+\n"
132 " -A <srcip> Use specified source IP address (default is own interface IP)\n"
133 " -B <dstip|dnsname> Send packet to specified destination IP or domain name\n"
134 " -P <ascii payload> Use the specified ASCII payload\n"
135 " -f <filename> Read the ASCII payload from a file\n"
136 " -F <filename> Read the hexadecimal payload from a file\n"
137 " -Q <[CoS:]vlan> Specify 802.1Q VLAN tag and optional Class of Service, you can\n"
138 " specify multiple 802.1Q VLAN tags (QinQ...) by separating them\n"
139 " via a comma or a period (e.g. '5:10,20,2:30')\n"
140 " -t <packet-type|help> Specify packet type for autobuild (you don't need to care for\n"
141 " encapsulations in lower layers, most packet types allow/require\n"
142 " additional packet-specific arguments in an <arg-string>;\n"
143 " Currently supported types: arp, bpdu, cdp, ip, icmp, udp, tcp,\n"
144 " dns, rtp, syslog, lldp and more;\n"
145 " For context-help use 'help' as <arg-string>!\n"
146 " -T <packet-type> Specify packet type for server mode, currently only rtp is supported;\n"
147 " Enter -T help or -T rtp help for further information\n"
148 " -M <MPLS-label> Insert a MPLS label, enter '-M help' for a syntax description\n"
149 " -V|VV|... Verbose and more verbose mode\n"
150 " -q Quiet mode, even omit 'important' standard short messages\n"
151 " -S Simulation mode: DOES NOT put anything on the wire, this is\n"
152 " typically combined with one of the verbose modes (v or V)\n"
153 " -v Show version\n"
154 " -h Print this help\n\n"
155 "Examples:\n"
156 " mausezahn -x 99\n"
157 " mausezahn -c 0 -d 2s -t bpdu conf\n"
158 " mausezahn -t cdp change -c 0\n"
159 " mausezahn -t syslog sev=3 -P \"You have been mausezahned.\" -A 10.1.1.109 -B 192.168.7.7\n"
160 " mausezahn eth0 -A rand -B 1.1.1.1 -c 0 -t tcp \"dp=1-1023, flags=syn\"\n\n"
161 "Note:\n"
162 " This tool is targeted for network developers! You should\n"
163 " be aware of what you are doing and what these options above\n"
164 " mean! Only use this tool in an isolated LAN that you own!\n\n"
165 "Please report bugs to <bugs@netsniff-ng.org>\n"
166 "Copyright (C) 2008-2010 Herbert Haas <herbert@perihel.at>,\n"
167 "Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
168 "Swiss federal institute of technology (ETH Zurich)\n"
169 "License: GNU GPL version 2.0\n"
170 "This is free software: you are free to change and redistribute it.\n"
171 "There is NO WARRANTY, to the extent permitted by law.\n");
172 die();
175 static void version(void)
177 printf("\nmausezahn %s, Git id: %s\n", VERSION_LONG, GITVERSION);
178 puts("a fast versatile traffic generator\n"
179 "http://www.netsniff-ng.org\n\n"
180 "Please report bugs to <bugs@netsniff-ng.org>\n"
181 "Copyright (C) 2008-2010 Herbert Haas <herbert@perihel.at>,\n"
182 "Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
183 "Swiss federal institute of technology (ETH Zurich)\n"
184 "License: GNU GPL version 2.0\n"
185 "This is free software: you are free to change and redistribute it.\n"
186 "There is NO WARRANTY, to the extent permitted by law.\n");
187 die();
190 int reset(void)
192 int i;
193 time_t t;
195 // Determine platform type sizes:
196 MZ_SIZE_LONG_INT = sizeof(long int);
198 mz_default_config_path[0] = 0x00;
199 mz_default_log_path[0] = 0x00;
201 // Reset globals:
202 quiet = 0;
203 ipv6_mode = 0;
204 verbose = 0;
205 simulate = 0;
206 filename[0] = '\0';
207 path[0] = '\0';
208 gind=0;
209 gind_max = TIME_COUNT;
210 fp = NULL;
211 fp2 = NULL;
212 mz_port = 0;
213 mz_rand = 0;
214 char mz_listen_addr[16] = "0.0.0.0";
215 mp_head = NULL;
217 for (i=0;i<TIME_COUNT_MAX;i++) jitter[i] = 0;
219 time0_flag = 0; // If set then time0 has valid data
220 sqnr0_flag = 0; // If set then sqnr_last and sqnr_next has valid data
221 rtp_log = 0;
222 mz_ssrc[0]=0; mz_ssrc[1]=0; mz_ssrc[2]=0; mz_ssrc[3]=0;
224 // Reset mgmt parameters of TX:
225 tx.packet_mode = 1; // assume we don't care about L2
226 tx.count = 1;
227 tx.delay = DEFAULT_DELAY;
228 tx.prio = 0;
229 tx.arg_string[0] = '\0';
231 // Reset Ethernet parameters of TX:
232 tx.eth_params_already_set = 0;
233 for (i=0; i<6; i++) tx.eth_dst[i] = 0xff;
234 for (i=0; i<6; i++) tx.eth_src[i] = 0; // TODO: Get own MAC !!!
235 tx.eth_dst_txt[0] = '\0';
236 tx.eth_src_txt[0] = '\0';
237 tx.eth_dst_rand = 0;
238 tx.eth_src_rand = 0;
240 tx.eth_type = 0x800;
241 tx.eth_len = 0;
242 tx.eth_payload[0] = '\0';
243 tx.eth_payload_s = 0;
244 tx.padding = 0;
246 // Reset CDP parameters for TX:
247 tx.cdp_sum = 0;
248 tx.cdp_version = 0;
249 tx.cdp_ttl = 0;
250 tx.cdp_payload[0] = '\0';
251 tx.cdp_payload_s = 0;
252 tx.cdp_tlv_id[0] = '\0';
253 tx.cdp_tlv_id_len = 0;
255 // Reset 802.1Q parameters of TX:
256 tx.dot1Q=0;
257 tx.dot1Q_txt[0] = '\0';
259 // ASCII Payload:
260 tx.ascii = 0; // 1 if specified
261 tx.ascii_payload[0]= '\0';
263 // HEX Payload:
264 tx.hex_payload_s = 0;
266 // Reset MPLS parameters of TX:
267 tx.mpls = 0;
268 tx.mpls_txt[0] = '\0';
269 tx.mpls_label = 0;
270 tx.mpls_exp = 0;
271 tx.mpls_bos = 1;
272 tx.mpls_ttl = 255;
273 tx.mpls_verbose_string[0] = '\0';
275 // Reset IP parameters of TX:
276 tx.ip_src_txt[0] = '\0';
277 tx.ip_src_rand = 0;
278 tx.ip_dst_txt[0] = '\0';
279 tx.ip_src_isrange = 0;
280 tx.ip_src_start = 0;
281 tx.ip_src_stop = 0;
282 memset(&tx.ip6_src_start, 0, sizeof(tx.ip6_src_start));
283 memset(&tx.ip6_src_stop, 0, sizeof(tx.ip6_src_stop));
285 tx.ip_dst_start = 0;
286 tx.ip_dst_stop = 0;
287 memset(&tx.ip6_dst_start, 0, sizeof(tx.ip6_dst_start));
288 memset(&tx.ip6_dst_stop, 0, sizeof(tx.ip6_dst_stop));
289 tx.ip_dst_isrange = 0;
291 tx.ip_ttl = 0;
292 tx.ip_len = 0;
293 tx.ip_payload[0]= '\0';
294 tx.ip_payload_s = 0;
295 tx.ip_option[0]= '\0';
296 tx.ip_option_s = 0;
298 // Reset ICMP parameters:
299 tx.icmp_type=0;
300 tx.icmp_code=0;
301 tx.icmp_chksum=0; // 0=autofill
302 tx.icmp_ident=0x42;
303 tx.icmp_sqnr=0x1;
304 tx.icmp_payload_s=0;
306 // Reset general L4 parameters:
307 tx.sp = 0;
308 tx.dp = 0;
309 tx.sp_start = 0;
310 tx.sp_stop = 0;
311 tx.dp_start = 0;
312 tx.dp_stop = 0;
313 tx.sp_isrange = 0;
314 tx.dp_isrange = 0;
316 // Reset UDP parameters of TX:
318 tx.udp_len = 0; // If set to zero then create_udp_packet will calculate it
319 tx.udp_sum = 0;
320 tx.udp_payload[0] = '\0';
321 tx.udp_payload_s = 0;
323 // Reset TCP parameters of TX:
325 tx.tcp_seq = 42;
326 tx.tcp_seq_stop = 42;
327 tx.tcp_seq_delta = 0; // also used as 'isrange' meaning
328 tx.tcp_ack = 42;
329 tx.tcp_control = 0;
330 tx.tcp_win = 10000;
331 tx.tcp_sum = 0;
332 tx.tcp_urg = 0;
333 tx.tcp_len = 20; // Least size (TCP header only)
334 tx.tcp_payload[0] = '\0';
335 tx.tcp_payload_s = 0;
337 // Reset RTP parameters of TX:
338 tx.rtp_sqnr = 0;
339 tx.rtp_stmp = 0;
341 // Initialize random generator
342 time(&t);
343 srand((unsigned int)t);
344 srand48(t);
346 // Reset device_list
347 for (i=0; i<MZ_MAX_DEVICES; i++) {
348 device_list[i].arprx_thread = 0;
349 device_list[i].p_arp = NULL;
350 device_list[i].arp_table = NULL;
351 device_list[i].ps=-1;
352 device_list[i].cli=0;
353 device_list[i].mgmt_only=0;
356 return 0;
359 static void print_packet_types(void)
361 fprintf(stderr, "\n"
362 MAUSEZAHN_VERSION
363 "\n"
364 "| The following packet types are currently implemented:\n"
365 "|\n"
366 "| arp ... sends ARP packets\n"
367 "| bpdu ... sends BPDU packets (STP or PVST+)\n"
368 "| cdp ... sends CDP messages\n"
369 "| ip ... sends IPv4 packets\n"
370 "| udp ... sends UDP datagrams\n"
371 "| tcp ... sends TCP segments\n"
372 "| icmp ... sends ICMP messages\n"
373 "| igmp ... sends IGMP messages\n"
374 "| dns ... sends DNS messages\n"
375 "| rtp ... sends RTP datagrams\n"
376 "| syslog ... sends Syslog messages\n"
377 "|\n"
378 "| Of course you can build any other packet type 'manually' using the direct layer 2 mode.\n"
379 "| FYI: The interactive mode supports additional protocols. (Try mz -x <port>)\n"
380 "\n");
382 die();
385 // Purpose: Properly handle arguments and configure global structs (tx)
386 int getopts (int argc, char *argv[])
388 int i, c, rargs, RX=0, count_set=0, delay_set=0;
389 unsigned int time_factor;
390 char *packet_type=NULL, *mops_type=NULL;
391 char *dum;
392 unsigned char *dum1, *dum2;
393 bool do_help = false;
395 libnet_t *l;
396 char err_buf[LIBNET_ERRBUF_SIZE];
397 struct libnet_ether_addr *mymac;
399 FILE *afp;
400 char hexpld[MAX_PAYLOAD_SIZE*2];
401 int hexpld_specified=0;
402 long delay;
403 long prio;
404 char unit;
406 opterr = 1; // let getopt print error message if necessary
409 while ((c = getopt(argc, argv, short_options)) != -1)
410 switch (c) {
411 case '4':
412 tx.eth_type = 0x0800;
413 ipv6_mode=0;
414 break;
415 case '6':
416 tx.eth_type = 0x86dd;
417 ipv6_mode=1;
418 break;
419 case 'R':
420 errno = 0;
421 prio = strtol(optarg, NULL, 0);
422 if (errno) {
423 perror("Couldn't parse priority");
424 return -1;
426 if (prio < 0 || prio > 0xffffffff) {
427 perror("Invalid priority value");
428 return -1;
430 tx.prio = (int)prio;
431 break;
432 case 'h':
433 help();
434 break;
435 case 'q':
436 quiet=1;
437 break;
438 case 'v':
439 version();
440 break;
441 case 'V':
442 verbose++;
443 break;
444 case 'S':
445 simulate=1;
446 break;
447 case 'x':
448 mz_port = MZ_DEFAULT_PORT;
449 break;
450 case 'l':
451 strncpy (mz_listen_addr, optarg, sizeof(mz_listen_addr));
452 break;
453 case 'a':
454 strncpy (tx.eth_src_txt, optarg, 32);
455 tx.packet_mode = 0;
456 break;
457 case 'A':
458 strncpy (tx.ip_src_txt, optarg, sizeof(tx.ip_src_txt));
459 break;
460 case 'b':
461 strncpy (tx.eth_dst_txt, optarg, 32);
462 tx.packet_mode = 0;
463 break;
464 case 'B':
465 strncpy (tx.ip_dst_txt, optarg, sizeof(tx.ip_dst_txt));
466 break;
467 case 'c':
468 errno=0;
469 tx.count = strtol(optarg, (char **)NULL, 10);
470 if ((errno == ERANGE && (tx.count == LONG_MAX || tx.count == LONG_MIN))
471 || (errno != 0 && tx.count == 0)) {
472 perror("strtol");
473 return (-1);
475 if (tx.count<0) tx.count=1; //TODO: Allow count=0 which means infinity (need to update all send_functions)
476 count_set=1;
477 break;
478 case 'd':
479 errno=0;
480 time_factor=0;
481 delay=0;
482 unit='u'; // default is usecs
483 if (sscanf(optarg, "%ld%c", &delay, &unit) == EOF) {
484 perror("sscanf");
485 return (-1);
487 if (delay < 0) {
488 fprintf(stderr, " Incorrect delay format\n");
489 return(-1);
491 if (unit == 's') time_factor=1000000; // seconds
492 else if (unit == 'm') time_factor=1000; // msecs
493 else if (unit == 'u') time_factor=1; // usecs
494 else {
495 fprintf(stderr, " Incorrect delay format\n");
496 return(-1);
498 tx.delay = delay * time_factor;
499 if ((errno == ERANGE && (tx.delay == LONG_MAX || tx.delay == LONG_MIN))
500 || (errno != 0 && tx.delay == 0)) {
501 perror("strtol");
502 return (-1);
504 if (tx.delay<0) tx.delay=0; // no delay
505 delay_set=1;
506 break;
507 case 'p':
508 errno=0;
509 tx.padding = strtol(optarg, (char **)NULL, 10);
510 if ((errno == ERANGE && (tx.padding == LONG_MAX || tx.padding == LONG_MIN))
511 || (errno != 0 && tx.padding == 0)) {
512 perror("strtol");
513 return (-1);
515 if (tx.padding>10000) {
516 fprintf(stderr, " Warning: Padding must not exceed 10000!\n");
517 return -1;
519 break;
520 case 't':
521 packet_type = optarg; // analyzed below
522 if (strcmp(packet_type,"help") == 0)
523 print_packet_types();
524 break;
525 case 'X':
526 mops_type = optarg; // MOPS TRANSITION STRATEGY -- analyzed below
527 break;
528 case 'T':
529 packet_type = optarg;
530 RX = 1;
531 break;
532 case 'r':
533 mz_rand = 1;
534 break;
535 case 'M':
536 if (strncmp(optarg,"help",4)==0) {
537 (void) get_mpls_params("help ");
539 else {
540 strncpy (tx.mpls_txt, optarg, 128);
541 tx.eth_type = ETHERTYPE_MPLS;
542 tx.packet_mode = 0;
543 tx.mpls=1;
545 break;
546 case 'P': // ASCII payload
547 strncpy((char*)tx.ascii_payload, optarg, MAX_PAYLOAD_SIZE);
548 tx.ascii = 1;
549 break;
550 case 'f': // ASCII payload in FILE
551 afp = fopen(optarg, "r");
552 if (!afp) {
553 fprintf(stderr, " mz/getopts: Can not open file %s. %s!\n", optarg, strerror(errno));
554 return -1;
556 if (fgets((char*)tx.ascii_payload, MAX_PAYLOAD_SIZE, afp) == NULL)
557 fprintf(stderr, " mz/getopts: File empty?\n");
558 fclose(afp);
559 tx.ascii = 1;
560 break;
561 case 'F': // HEX payload in FILE
562 afp = fopen(optarg, "r");
563 if (!afp) {
564 fprintf(stderr, " mz/getopts: Can not open file %s. %s!\n", optarg, strerror(errno));
565 return -1;
567 i=0;
568 while ( (hexpld[i]=fgetc(afp))!=EOF ) {
569 if (isspace(hexpld[i])) {
570 hexpld[i]=':';
572 i++;
574 hexpld[i]='\0';
575 fclose(afp);
576 hexpld_specified=1;
577 break;
578 case 'Q': // VLAN TAG
579 if (strncmp(optarg,"help",4)==0) {
580 print_dot1Q_help(); // ugly but most simple and safe solution
582 else {
583 strncpy (tx.dot1Q_txt, optarg, 32);
584 tx.dot1Q=1;
585 // determine number of VLAN tags
586 for (i=0; i<strlen(tx.dot1Q_txt); i++) {
587 if (tx.dot1Q_txt[i]==',') tx.dot1Q++;
589 tx.packet_mode = 0;
591 break;
592 case '?':
593 if ((optopt == 'a') || (optopt == 'b') || (optopt = 'c') ||
594 (optopt == 'd') || (optopt == 'f') || (optopt = 'p') ||
595 (optopt == 't') || (optopt == 'm'))
596 fprintf (stderr, " mz/getopts: Option -%c requires an argument.\n", optopt);
597 else if (isprint (optopt))
598 fprintf (stderr, " mz/getopts: Unknown option -%c'.\n", optopt);
599 else
600 fprintf (stderr, " mz/getopts: Unknown option character \\x%x'.\n", optopt);
601 return 1;
602 default:
603 fprintf (stderr," mz/getopts: Could not handle arguments properly!\n");
604 return 1;
607 // ********************************************
608 // Handle additional arguments
609 // ********************************************
611 // Greeting text
612 if (verbose) {
613 fprintf(stderr,"\n"
614 MAUSEZAHN_VERSION
615 "\n"
616 "Use at your own risk and responsibility!\n"
617 "-- Verbose mode --\n"
618 "\n");
621 if (argc<2) {
622 help();
625 if ((rargs=argc-optind)>2) { // number of remaining arguments
626 fprintf(stderr," mz/getopts: Too many arguments!\n");
627 return -1;
631 // There can be 0-2 additional arguments
632 switch (rargs) {
633 case 0:
634 if (lookupdev()) { // no device found
635 if (verbose) fprintf(stderr, " mz: no active interfaces found!\n");
636 strcpy(tx.device, "lo");
638 break;
639 case 1: // arg_string OR device given => find out!
640 if (__device_ifindex(argv[optind]) > 0) {
641 strncpy(tx.device, argv[optind], 16);
643 else { /// arg_string given => no device has been specified -- let's find one!
644 strncpy (tx.arg_string, argv[optind], MAX_PAYLOAD_SIZE);
645 do_help = !!getarg(tx.arg_string,"help", NULL);
646 if (!do_help) {
647 if (lookupdev()) {
648 /* no device found */
649 if (verbose)
650 fprintf(stderr, " mz: no active interfaces found!\n");
651 strcpy(tx.device, "lo");
653 if (verbose)
654 fprintf(stderr," mz: device not given, will use %s\n",tx.device);
657 break;
658 case 2: // both device and arg_string given
659 strncpy (tx.device, argv[optind], 16);
660 strncpy (tx.arg_string, argv[optind+1], MAX_PAYLOAD_SIZE);
661 break;
662 default:
663 fprintf(stderr," mz/getopts: Unknown argument problem!\n");
664 return 1;
667 if (hexpld_specified) {
668 strcat(tx.arg_string, ",p=");
669 strcat(tx.arg_string, hexpld);
673 //////////////////////////////////////////////////////////////////////////
675 // Initialize MAC and IP Addresses.
677 // - tx.eth_src = own interface MAC
678 // - tx.ip_src = own interface IP or user specified
679 // - tx.ip_dst = 255.255.255.255 or user specified (can be a range)
680 // - tx.ip_src_rand ... is set if needed.
683 // Get own device MAC address:
684 // Don't open context if only a help text is requested
685 if (!do_help && getarg(tx.arg_string,"help", NULL) !=1) {
686 l = libnet_init (LIBNET_LINK_ADV, tx.device, err_buf );
687 if (l == NULL) {
688 fprintf(stderr, " mz/getopts: libnet_init() failed (%s)", err_buf);
689 return -1;
691 mymac = libnet_get_hwaddr(l);
692 for (i=0; i<6; i++) {
693 tx.eth_src[i] = mymac->ether_addr_octet[i];
694 tx.eth_mac_own[i] = mymac->ether_addr_octet[i];
697 // Set source IP address:
698 if (strlen(tx.ip_src_txt)) { // option -A has been specified
699 if (mz_strcmp(tx.ip_src_txt, "bcast", 2)==0) {
700 if (ipv6_mode) {
701 fprintf(stderr, "Option -A does not support 'bcast' when in IPv6 mode.\n");
702 return 1;
704 tx.ip_src = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
705 } else if (strcmp(tx.ip_src_txt, "rand") == 0) {
706 if (ipv6_mode) {
707 fprintf(stderr, "Option -A does not support 'rand' when in IPv6 mode.\n");
708 return 1;
710 tx.ip_src_rand = 1;
711 tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0
713 else if (
714 (ipv6_mode && get_ip6_range_src(tx.ip_src_txt, l)) || // returns 1 when no range has been specified
715 (!ipv6_mode && get_ip_range_src(tx.ip_src_txt))
718 // name2addr{4,6} accepts a valid IP address or a FQDN:
719 if (ipv6_mode) {
720 tx.ip6_src = libnet_name2addr6(l, tx.ip_src_txt, LIBNET_RESOLVE);
721 if (libnet_in6_is_error(tx.ip6_src)) {
722 /* libnet_in6_is_error returns 1 for the valid IPv6 address
723 * ffff:ffff:ffff:ffff:ffff:ffff. Use an additional inet_pton()
724 * check to cover cases where this address is specified
725 * as source
727 struct in6_addr src_check;
728 if (inet_pton(AF_INET6, tx.ip_src_txt, &src_check) != 1) {
729 fprintf(stderr, "Failed to set source"
730 " IPv6 address. Please check if"
731 " source is set to a valid IPv6 address.\n");
732 return 1;
735 } else {
736 tx.ip_src = libnet_name2addr4(l, tx.ip_src_txt, LIBNET_RESOLVE);
737 if (tx.ip_src == -1) {
738 /* libnet_name2addr4() returns -1 for the valid address 255.255.255.255.
739 * Use an additional inet_pton() check to cover case where this address
740 * is specified as source
742 struct in_addr src_check;
743 if (inet_pton(AF_INET, tx.ip_src_txt, &src_check) != 1) {
744 fprintf(stderr, "Failed to set source"
745 " IPv4 address. Please check if"
746 " source is set to a valid IPv4 address.\n");
747 return 1;
752 } else {
753 // no source IP specified: by default use own IP address
754 if (ipv6_mode) {
755 tx.ip6_src = libnet_get_ipaddr6(l);
756 if (strncmp((char*)&tx.ip6_src,(char*)&in6addr_error, sizeof(in6addr_error))==0)
757 printf("Failed to set source IPv6 address: %s", l->err_buf);
759 else
760 tx.ip_src = libnet_get_ipaddr4(l);
763 // Set destination IP address:
764 if (strlen(tx.ip_dst_txt)) { // option -B has been specified
765 if (mz_strcmp(tx.ip_dst_txt, "rand", 2)==0) {
766 fprintf(stderr, "Option -B does not support random destination IP addresses currently.\n");
767 return 1;
770 if (mz_strcmp(tx.ip_dst_txt, "bcast", 2)==0) {
771 if (ipv6_mode) {
772 fprintf(stderr, "Option -B does not support 'bcast' when in IPv6 mode.\n");
773 return 1;
775 tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
776 } else if (
777 (ipv6_mode && get_ip6_range_dst(tx.ip_dst_txt, l)) || // returns 1 when no range has been specified
778 (!ipv6_mode && get_ip_range_dst(tx.ip_dst_txt)))
780 // name2addr{4, 6} accepts a valid IP address or a FQDN:
781 if (ipv6_mode) {
782 tx.ip6_dst = libnet_name2addr6(l, tx.ip_dst_txt, LIBNET_RESOLVE);
783 if (libnet_in6_is_error(tx.ip6_dst)) {
784 /* libnet_in6_is_error returns 1 for the valid IPv6 address
785 * ffff:ffff:ffff:ffff:ffff:ffff. Use an additional inet_pton()
786 * check to cover cases where this address is specified
787 * as destination
789 struct in6_addr dst_check;
790 if (inet_pton(AF_INET6, tx.ip_dst_txt, &dst_check) != 1) {
791 fprintf(stderr, "Failed to set destination"
792 " IPv6 address. Please check if"
793 " source is set to a valid IPv6 address.\n");
794 return 1;
797 } else {
798 tx.ip_dst = libnet_name2addr4(l, tx.ip_dst_txt, LIBNET_RESOLVE);
799 if (tx.ip_dst == -1) {
800 /* libnet_name2addr4() returns -1 for the valid address 255.255.255.255.
801 * Use an additional inet_pton() check to cover case where this address
802 * is specified as destination
804 struct in_addr dst_check;
805 if (inet_pton(AF_INET, tx.ip_dst_txt, &dst_check) != 1) {
806 fprintf(stderr, "Failed to set destination"
807 " IPv4 address. Please check if"
808 " destination is set to a valid IPv4 address.\n");
809 return 1;
816 else { // no destination IP specified: by default use broadcast
817 if (ipv6_mode) {
818 tx.ip6_dst = libnet_name2addr6 (l, "ff02::1", LIBNET_DONT_RESOLVE);
819 } else {
820 tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
824 // Initialize tx.ip_src_h and tx.ip_dst_h which are used by 'print_frame_details()'
825 // in verbose mode. See 'modifications.c'.
827 if (tx.ip_src_rand) { // ip_src_h already given, convert to ip_src
828 dum1 = (unsigned char*) &tx.ip_src_h;
829 dum2 = (unsigned char*) &tx.ip_src;
831 else { // ip_src already given, convert to ip_src_h
832 if (ipv6_mode) {
833 if (tx.ip_src_isrange) {
834 tx.ip6_src = tx.ip6_src_start;
836 } else {
837 dum1 = (unsigned char*) &tx.ip_src;
838 dum2 = (unsigned char*) &tx.ip_src_h;
842 if (ipv6_mode) {
843 if (tx.ip_dst_isrange) {
844 tx.ip6_dst = tx.ip6_dst_start;
846 } else {
847 *dum2 = *(dum1+3);
848 dum2++;
849 *dum2 = *(dum1+2);
850 dum2++;
851 *dum2 = *(dum1+1);
852 dum2++;
853 *dum2 = *dum1;
855 dum1 = (unsigned char*) &tx.ip_dst;
856 dum2 = (unsigned char*) &tx.ip_dst_h;
858 *dum2 = *(dum1+3);
859 dum2++;
860 *dum2 = *(dum1+2);
861 dum2++;
862 *dum2 = *(dum1+1);
863 dum2++;
864 *dum2 = *dum1;
867 libnet_destroy(l);
871 // END OF ADDRESS INITIALIZATION
873 //////////////////////////////////////////////////////////////////////////
876 ////// retrieve interface parameters ///////
878 for (i=0; i<device_list_entries; i++) {
879 get_dev_params(device_list[i].dev);
883 //////////////////////////////////////////////////////////////////////////
885 // Mausezahn CLI desired?
886 if (mz_port) {
887 // has port number been specified?
888 if (strlen(tx.arg_string)) {
889 mz_port = (int) str2int (tx.arg_string);
892 mz_cli_init();
893 cli();
896 //////////////////////////////////////////////////////////////////////////
898 // Mode decision
900 // Consider -t and -m option (used exclusively)
901 // -t => special packet types, stateless
903 // If -t not present then evaluate arg_string which must
904 // contain a byte-string in hexadecimal notation.
908 // ***** NEW: MOPS TRANSITION STRATEGY *****
909 if (mops_type != NULL) {
911 if (mz_strcmp(mops_type,"lldp",4)==0) {
912 mops_direct(tx.device, MOPS_LLDP, tx.arg_string);
917 if (packet_type == NULL) { // raw hex string given
918 mode = BYTE_STREAM;
920 else if (strcmp(packet_type,"arp")==0) {
921 mode = ARP;
923 else if (strcmp(packet_type,"bpdu")==0) {
924 mode = BPDU;
926 else if (strcmp(packet_type,"ip")==0) {
927 mode = IP;
929 else if (strcmp(packet_type,"udp")==0) {
930 mode = UDP;
932 else if (strcmp(packet_type,"icmp")==0) {
933 mode = ICMP;
935 else if (strcmp(packet_type,"icmp6")==0) {
936 mode = ICMP6;
938 else if (strcmp(packet_type,"tcp")==0) {
939 mode = TCP;
941 else if (strcmp(packet_type,"dns")==0) {
942 mode = DNS;
944 else if (strcmp(packet_type,"cdp")==0) {
945 mode = CDP;
947 else if (strcmp(packet_type,"syslog")==0) {
948 mode = SYSLOG;
950 else if (strcmp(packet_type, "igmp") == 0) {
951 mode = IGMP;
953 else if (strcmp(packet_type,"lldp")==0) {
954 mode = LLDP;
955 tx.packet_mode=0; // create whole frame by ourself
957 else if (strcmp(packet_type,"rtp")==0) {
958 if (RX) {
959 mode = RX_RTP;
961 else {
962 mode = RTP;
963 if (!count_set) tx.count = 0;
964 if (!delay_set) tx.delay = 20000; // 20 msec inter-packet delay for RTP
967 else {
968 fprintf(stderr, " mz: you must specify a valid packet type!\n");
972 //////////////////////////////////////////////////////////////////////////
974 // TODO: Implement macro support
975 // Check macro types here
977 return 0;
980 int main(int argc, char **argv)
982 // These handles are only used when creating L3 and above packets.
983 libnet_t *l; // the context
984 libnet_ptag_t t2=0, t3=0, t4=0; // handles to layers
985 double cpu_time_used;
987 reset();
989 if ( getopts(argc, argv) )
991 (void) fprintf(stderr, " Invalid command line parameters!\n");
992 help();
995 // Check whether hires timers are supported or not:
996 (void) check_timer();
998 signal(SIGINT, signal_handler); // to close all file pointers etc upon SIGINT
1000 switch (mode)
1002 case BYTE_STREAM:
1003 send_eth();
1004 break;
1006 case ARP:
1007 (void) send_arp();
1008 break;
1010 case BPDU:
1011 (void) send_bpdu();
1012 break;
1014 case CDP:
1015 (void) send_cdp();
1016 break;
1018 case IP: // From now on a new much more modular method is used:
1019 l = get_link_context();
1020 t3 = create_ip_packet(l); // t3 can be used for later header changes
1021 if (!quiet) complexity();
1022 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1023 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1024 else
1025 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1026 break;
1028 case ICMP:
1029 tx.ip_proto = 1;
1030 l = get_link_context();
1031 t4 = create_icmp_packet(l); // t4 can be used for later header changes
1032 t3 = create_ip_packet(l); // t3 can be used for later header changes
1033 if (!quiet) complexity();
1034 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1035 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1036 else
1037 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1038 break;
1040 case ICMP6:
1041 tx.ip_proto = 58;
1042 l = get_link_context();
1043 t4 = create_icmp6_packet(l); // t4 can be used for later header changes
1044 t3 = create_ip_packet(l); // t3 can be used for later header changes
1045 if (!quiet) complexity();
1046 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1047 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1048 else
1049 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1050 break;
1052 case UDP:
1053 tx.ip_proto = 17;
1054 l = get_link_context();
1055 t4 = create_udp_packet(l); // t4 can be used for later header changes
1056 t3 = create_ip_packet(l); // t3 can be used for later header changes
1057 if (!quiet) complexity();
1058 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1059 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1060 else
1061 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1062 break;
1064 case TCP:
1065 tx.ip_proto = 6;
1066 l = get_link_context();
1067 t4 = create_tcp_packet(l); // t4 can be used for later header changes
1068 t3 = create_ip_packet(l); // t3 can be used for later header changes
1069 if (!quiet) complexity();
1070 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1071 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1072 else
1073 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1074 break;
1076 case IGMP:
1077 tx.ip_proto = 2;
1078 l = get_link_context();
1079 t4 = create_igmp_packet(l);
1080 /* t3 can be used for later header changes */
1081 t3 = create_ip_packet(l);
1082 if (!quiet)
1083 complexity();
1085 /* Ethernet manipulation features does NOT use ARP to determine eth_dst
1086 * */
1087 if (tx.packet_mode == 0)
1088 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1089 else
1090 send_frame(l, t3, t4); // NOTE: send_frame also destroys context finaly
1091 break;
1093 case DNS:
1094 tx.ip_proto = 17;
1095 l = get_link_context();
1096 (void) create_dns_packet();
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 RTP:
1107 tx.ip_proto = 17;
1108 l = get_link_context();
1109 if (!quiet) fprintf(stderr, " mz: RTP mode! (count=%u, delay=%u usec)\n\n", tx.count, tx.delay);
1110 (void) create_rtp_packet();
1111 t4 = create_udp_packet(l); // t4 can be used for later header changes
1112 t3 = create_ip_packet(l); // t3 can be used for later header changes
1113 if (!quiet) complexity();
1114 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1115 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1116 else
1117 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1118 break;
1120 case RX_RTP: // Receive RTP packets
1121 rcv_rtp_init();
1122 rcv_rtp();
1123 break;
1125 case SYSLOG:
1126 tx.ip_proto = 17;
1127 l = get_link_context();
1128 (void) create_syslog_packet();
1129 t4 = create_udp_packet(l); // t4 can be used for later header changes
1130 t3 = create_ip_packet(l); // t3 can be used for later header changes
1131 if (!quiet) complexity();
1133 if (tx.packet_mode==0) // Ethernet manipulation features does NOT use ARP to determine eth_dst
1134 t2 = create_eth_frame(l, t3, t4); // t2 can be used for later header changes
1135 else
1136 send_frame (l, t3, t4); // NOTE: send_frame also destroys context finaly
1137 break;
1139 case LLDP: // start with a new concept here
1140 //l = get_link_context();
1141 //(void) create_lldp_packet();
1142 // // // printf("SIZE=%lu\n",sizeof(struct tx_struct));
1143 fprintf(stderr, "LLDP is currently only supported via the interactive mode\n");
1144 exit(1);
1145 break;
1148 default:
1149 (void) fprintf(stderr," mz/main: unknown mode! Stop.\n");
1150 return (1);
1153 if (!quiet)
1155 mz_stop = clock();
1156 cpu_time_used = ((double) (mz_stop - mz_start)) / CLOCKS_PER_SEC;
1157 if (cpu_time_used > 0)
1159 total_d /= cpu_time_used;
1160 fprintf(stderr, "%.2f seconds (%.Lf packets per second)\n",cpu_time_used,total_d);
1162 else
1164 fprintf(stderr, "\n");
1168 return(0);