2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
22 // ****************************************************************************
24 // 1. Initialize globals
25 // 2. Handle arguments in *argv[] and make a mode decision
26 // ****************************************************************************
32 // Purpose: reset globals, global structs, etc.
38 // Determine platform type sizes:
39 MZ_SIZE_LONG_INT
= sizeof(long int);
41 mz_default_config_path
[0] = 0x00;
42 mz_default_log_path
[0] = 0x00;
52 gind_max
= TIME_COUNT
;
59 for (i
=0;i
<TIME_COUNT_MAX
;i
++) jitter
[i
] = 0;
61 time0_flag
= 0; // If set then time0 has valid data
62 sqnr0_flag
= 0; // If set then sqnr_last and sqnr_next has valid data
64 mz_ssrc
[0]=0; mz_ssrc
[1]=0; mz_ssrc
[2]=0; mz_ssrc
[3]=0;
66 // Reset mgmt parameters of TX:
67 tx
.packet_mode
= 1; // assume we don't care about L2
69 tx
.delay
= DEFAULT_DELAY
;
70 tx
.arg_string
[0] = '\0';
72 // Reset Ethernet parameters of TX:
73 tx
.eth_params_already_set
= 0;
74 for (i
=0; i
<6; i
++) tx
.eth_dst
[i
] = 0xff;
75 for (i
=0; i
<6; i
++) tx
.eth_src
[i
] = 0; // TODO: Get own MAC !!!
76 tx
.eth_dst_txt
[0] = '\0';
77 tx
.eth_src_txt
[0] = '\0';
83 tx
.eth_payload
[0] = '\0';
87 // Reset CDP parameters for TX:
91 tx
.cdp_payload
[0] = '\0';
93 tx
.cdp_tlv_id
[0] = '\0';
94 tx
.cdp_tlv_id_len
= 0;
96 // Reset 802.1Q parameters of TX:
98 tx
.dot1Q_txt
[0] = '\0';
101 tx
.ascii
= 0; // 1 if specified
102 tx
.ascii_payload
[0]= '\0';
105 tx
.hex_payload_s
= 0;
107 // Reset MPLS parameters of TX:
109 tx
.mpls_txt
[0] = '\0';
114 tx
.mpls_verbose_string
[0] = '\0';
116 // Reset IP parameters of TX:
117 tx
.ip_src_txt
[0] = '\0';
119 tx
.ip_dst_txt
[0] = '\0';
120 tx
.ip_src_isrange
= 0;
126 tx
.ip_dst_isrange
= 0;
129 tx
.ip_payload
[0]= '\0';
131 tx
.ip_option
[0]= '\0';
134 // Reset ICMP parameters:
137 tx
.icmp_chksum
=0; // 0=autofill
142 // Reset general L4 parameters:
152 // Reset UDP parameters of TX:
154 tx
.udp_len
= 0; // If set to zero then create_udp_packet will calculate it
156 tx
.udp_payload
[0] = '\0';
157 tx
.udp_payload_s
= 0;
159 // Reset TCP parameters of TX:
162 tx
.tcp_seq_stop
= 42;
163 tx
.tcp_seq_delta
= 0; // also used as 'isrange' meaning
169 tx
.tcp_len
= 20; // Least size (TCP header only)
170 tx
.tcp_payload
[0] = '\0';
171 tx
.tcp_payload_s
= 0;
173 // Reset RTP parameters of TX:
177 // Initialize random generator
179 srand((unsigned int)t
);
182 for (i
=0; i
<MZ_MAX_DEVICES
; i
++) {
183 device_list
[i
].arprx_thread
= 0;
184 device_list
[i
].p_arp
= NULL
;
185 device_list
[i
].arp_table
= NULL
;
186 device_list
[i
].ps
=-1;
187 device_list
[i
].cli
=0;
188 device_list
[i
].mgmt_only
=0;
196 // Purpose: Properly handle arguments and configure global structs (tx)
197 int getopts (int argc
, char *argv
[])
199 int i
, c
, rargs
, RX
=0, count_set
=0, delay_set
=0;
200 unsigned int time_factor
;
201 char *packet_type
=NULL
, *mops_type
=NULL
;
203 unsigned char *dum1
, *dum2
;
206 char err_buf
[LIBNET_ERRBUF_SIZE
];
207 struct libnet_ether_addr
*mymac
;
210 char hexpld
[MAX_PAYLOAD_SIZE
*2];
211 int hexpld_specified
=0;
213 opterr
= 1; // let getopt print error message if necessary
216 while ((c
= getopt (argc
, argv
, "46hqvVSxra:A:b:B:c:d:E:f:F:p:P:t:T:M:Q:X:")) != -1)
219 tx
.eth_type
= 0x0800;
223 tx
.eth_type
= 0x86dd;
242 mz_port
= MZ_DEFAULT_PORT
;
245 strncpy (tx
.eth_src_txt
, optarg
, 32);
249 strncpy (tx
.ip_src_txt
, optarg
, sizeof(tx
.ip_src_txt
));
252 strncpy (tx
.eth_dst_txt
, optarg
, 32);
256 strncpy (tx
.ip_dst_txt
, optarg
, sizeof(tx
.ip_dst_txt
));
260 tx
.count
= strtol(optarg
, (char **)NULL
, 10);
261 if ((errno
== ERANGE
&& (tx
.count
== LONG_MAX
|| tx
.count
== LONG_MIN
))
262 || (errno
!= 0 && tx
.count
== 0)) {
266 if (tx
.count
<0) tx
.count
=1; //TODO: Allow count=0 which means infinity (need to update all send_functions)
271 // determine whether seconds or msecs are used
272 // default is usec!!!
274 if (exists(optarg
,"s") || exists(optarg
,"sec")) time_factor
=1000000;
275 if (exists(optarg
,"m") || exists(optarg
,"msec")) time_factor
=1000;
276 dum
= strtok(optarg
,"ms");
277 tx
.delay
= strtol(dum
, (char **)NULL
, 10) * time_factor
;
278 if ((errno
== ERANGE
&& (tx
.delay
== LONG_MAX
|| tx
.delay
== LONG_MIN
))
279 || (errno
!= 0 && tx
.delay
== 0)) {
283 if (tx
.delay
<0) tx
.delay
=0; // no delay
288 tx
.padding
= strtol(optarg
, (char **)NULL
, 10);
289 if ((errno
== ERANGE
&& (tx
.padding
== LONG_MAX
|| tx
.padding
== LONG_MIN
))
290 || (errno
!= 0 && tx
.padding
== 0)) {
294 if (tx
.padding
>10000) {
295 fprintf(stderr
, " Warning: Padding must not exceed 10000!\n");
300 packet_type
= optarg
; // analyzed below
303 mops_type
= optarg
; // MOPS TRANSITION STRATEGY -- analyzed below
306 packet_type
= optarg
;
313 if (strncmp(optarg
,"help",4)==0) {
314 (void) get_mpls_params("help ");
317 strncpy (tx
.mpls_txt
, optarg
, 128);
318 tx
.eth_type
= ETHERTYPE_MPLS
;
323 case 'P': // ASCII payload
324 strncpy((char*)tx
.ascii_payload
, optarg
, MAX_PAYLOAD_SIZE
);
327 case 'f': // ASCII payload in FILE
328 afp
= fopen(optarg
, "r");
329 if (fgets((char*)tx
.ascii_payload
, MAX_PAYLOAD_SIZE
, afp
) == NULL
)
330 fprintf(stderr
, " mz/getopts: File empty?\n");
334 case 'F': // HEX payload in FILE
335 afp
= fopen(optarg
, "r");
337 while ( (hexpld
[i
]=fgetc(afp
))!=EOF
) {
338 if (isspace(hexpld
[i
])) {
347 case 'Q': // VLAN TAG
348 if (strncmp(optarg
,"help",4)==0) {
349 print_dot1Q_help(); // ugly but most simple and safe solution
352 strncpy (tx
.dot1Q_txt
, optarg
, 32);
354 // determine number of VLAN tags
355 for (i
=0; i
<strlen(tx
.dot1Q_txt
); i
++) {
356 if (tx
.dot1Q_txt
[i
]==',') tx
.dot1Q
++;
362 if ((optopt
== 'a') || (optopt
== 'b') || (optopt
= 'c') ||
363 (optopt
== 'd') || (optopt
== 'f') || (optopt
= 'p') ||
364 (optopt
== 't') || (optopt
== 'm'))
365 fprintf (stderr
, " mz/getopts: Option -%c requires an argument.\n", optopt
);
366 else if (isprint (optopt
))
367 fprintf (stderr
, " mz/getopts: Unknown option -%c'.\n", optopt
);
369 fprintf (stderr
, " mz/getopts: Unknown option character \\x%x'.\n", optopt
);
372 fprintf (stderr
," mz/getopts: Could not handle arguments properly!\n");
376 // ********************************************
377 // Handle additional arguments
378 // ********************************************
385 "Use at your own risk and responsibility!\n"
386 "-- Verbose mode --\n"
394 if ((rargs
=argc
-optind
)>2) { // number of remaining arguments
395 fprintf(stderr
," mz/getopts: Too many arguments!\n");
400 // There can be 0-2 additional arguments
403 if (lookupdev()) { // no device found
404 if (verbose
) fprintf(stderr
, " mz: no active interfaces found!\n");
405 strcpy(tx
.device
, "lo");
407 if (verbose
) // device found
408 fprintf(stderr
," mz: device not given, will use %s\n",tx
.device
);
410 case 1: // arg_string OR device given => find out!
411 if ( (strncmp(argv
[optind
],"eth",3)==0)
412 || (strncmp(argv
[optind
],"ath",3)==0)
413 || ((strncmp(argv
[optind
],"lo",2)==0)&&(strncmp(argv
[optind
],"log",3)!=0))
414 || (strncmp(argv
[optind
],"vmnet",5)==0)
415 || (strncmp(argv
[optind
],"wifi",4)==0) ) {
416 // device has been specified!
417 strncpy (tx
.device
, argv
[optind
], 16);
419 else { /// arg_string given => no device has been specified -- let's find one!
420 strncpy (tx
.arg_string
, argv
[optind
], MAX_PAYLOAD_SIZE
);
421 if (lookupdev()) { // no device found
422 if (verbose
) fprintf(stderr
, " mz: no active interfaces found!\n");
423 strcpy(tx
.device
, "lo");
426 fprintf(stderr
," mz: device not given, will use %s\n",tx
.device
);
429 case 2: // both device and arg_string given
430 strncpy (tx
.device
, argv
[optind
], 16);
431 strncpy (tx
.arg_string
, argv
[optind
+1], MAX_PAYLOAD_SIZE
);
434 fprintf(stderr
," mz/getopts: Unknown argument problem!\n");
438 if (hexpld_specified
) {
439 strcat(tx
.arg_string
, ",p=");
440 strcat(tx
.arg_string
, hexpld
);
444 //////////////////////////////////////////////////////////////////////////
446 // Initialize MAC and IP Addresses.
448 // - tx.eth_src = own interface MAC
449 // - tx.ip_src = own interface IP or user specified
450 // - tx.ip_dst = 255.255.255.255 or user specified (can be a range)
451 // - tx.ip_src_rand ... is set if needed.
454 // Get own device MAC address:
455 // Don't open context if only a help text is requested
456 if (getarg(tx
.arg_string
,"help", NULL
)!=1) {
457 l
= libnet_init (LIBNET_LINK_ADV
, tx
.device
, err_buf
);
459 fprintf(stderr
, " mz/getopts: libnet_init() failed (%s)", err_buf
);
462 mymac
= libnet_get_hwaddr(l
);
463 for (i
=0; i
<6; i
++) {
464 tx
.eth_src
[i
] = mymac
->ether_addr_octet
[i
];
465 tx
.eth_mac_own
[i
] = mymac
->ether_addr_octet
[i
];
468 // Set source IP address:
469 if (strlen(tx
.ip_src_txt
)) { // option -A has been specified
470 if (mz_strcmp(tx
.ip_src_txt
, "bcast", 2)==0) {
471 tx
.ip_src
= libnet_name2addr4 (l
, "255.255.255.255", LIBNET_DONT_RESOLVE
);
472 } else if (strcmp(tx
.ip_src_txt
, "rand") == 0) {
474 tx
.ip_src_h
= (u_int32_t
) ( ((float) rand()/RAND_MAX
)*0xE0000000); //this is 224.0.0.0
476 else if (get_ip_range_src(tx
.ip_src_txt
)) { // returns 1 when no range has been specified
477 // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
479 tx
.ip6_src
= libnet_name2addr6 (l
, tx
.ip_src_txt
, LIBNET_RESOLVE
);
481 tx
.ip_src
= libnet_name2addr4 (l
, tx
.ip_src_txt
, LIBNET_RESOLVE
);
484 else { // no source IP specified: by default use own IP address
486 tx
.ip6_src
= libnet_get_ipaddr6(l
);
487 if (strncmp((char*)&tx
.ip6_src
,(char*)&in6addr_error
,sizeof(in6addr_error
))==0)
488 printf("Failed to set source IPv6 address: %s", l
->err_buf
);
491 tx
.ip_src
= libnet_get_ipaddr4(l
);
494 // Set destination IP address:
495 if (strlen(tx
.ip_dst_txt
)) { // option -B has been specified
496 if (mz_strcmp(tx
.ip_dst_txt
, "rand", 2)==0) {
497 fprintf(stderr
, "Option -B does not support random destination IP addresses currently.\n");
501 if (mz_strcmp(tx
.ip_dst_txt
, "bcast", 2)==0) {
502 tx
.ip_dst
= libnet_name2addr4 (l
, "255.255.255.255", LIBNET_DONT_RESOLVE
);
503 } else if (get_ip_range_dst(tx
.ip_dst_txt
)) { // returns 1 when no range has been specified
504 // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
506 tx
.ip6_dst
= libnet_name2addr6 (l
, tx
.ip_dst_txt
, LIBNET_RESOLVE
);
508 tx
.ip_dst
= libnet_name2addr4 (l
, tx
.ip_dst_txt
, LIBNET_RESOLVE
);
511 else { // no destination IP specified: by default use broadcast
512 tx
.ip_dst
= libnet_name2addr4 (l
, "255.255.255.255", LIBNET_DONT_RESOLVE
);
515 // Initialize tx.ip_src_h and tx.ip_dst_h which are used by 'print_frame_details()'
516 // in verbose mode. See 'modifications.c'.
518 if (tx
.ip_src_rand
) { // ip_src_h already given, convert to ip_src
519 dum1
= (unsigned char*) &tx
.ip_src_h
;
520 dum2
= (unsigned char*) &tx
.ip_src
;
522 else { // ip_src already given, convert to ip_src_h
523 dum1
= (unsigned char*) &tx
.ip_src
;
524 dum2
= (unsigned char*) &tx
.ip_src_h
;
535 dum1
= (unsigned char*) &tx
.ip_dst
;
536 dum2
= (unsigned char*) &tx
.ip_dst_h
;
550 // END OF ADDRESS INITIALIZATION
552 //////////////////////////////////////////////////////////////////////////
555 ////// retrieve interface parameters ///////
557 for (i
=0; i
<device_list_entries
; i
++) {
558 get_dev_params(device_list
[i
].dev
);
562 //////////////////////////////////////////////////////////////////////////
564 // Mausezahn CLI desired?
566 // has port number been specified?
567 if (strlen(tx
.arg_string
)) {
568 mz_port
= (int) str2int (tx
.arg_string
);
572 fprintf(stderr
, "Mausezahn accepts incoming Telnet connections on port %i.\n", mz_port
);
579 //////////////////////////////////////////////////////////////////////////
583 // Consider -t and -m option (used exclusively)
584 // -t => special packet types, stateless
586 // If -t not present then evaluate arg_string which must
587 // contain a byte-string in hexadecimal notation.
591 // ***** NEW: MOPS TRANSITION STRATEGY *****
592 if (mops_type
!= NULL
) {
594 if (mz_strcmp(mops_type
,"lldp",4)==0) {
595 mops_direct(tx
.device
, MOPS_LLDP
, tx
.arg_string
);
600 if (packet_type
== NULL
) { // raw hex string given
603 else if (strcmp(packet_type
,"arp")==0) {
606 else if (strcmp(packet_type
,"bpdu")==0) {
609 else if (strcmp(packet_type
,"ip")==0) {
612 else if (strcmp(packet_type
,"udp")==0) {
615 else if (strcmp(packet_type
,"icmp")==0) {
618 else if (strcmp(packet_type
,"icmp6")==0) {
621 else if (strcmp(packet_type
,"tcp")==0) {
624 else if (strcmp(packet_type
,"dns")==0) {
627 else if (strcmp(packet_type
,"cdp")==0) {
630 else if (strcmp(packet_type
,"syslog")==0) {
633 else if (strcmp(packet_type
,"lldp")==0) {
635 tx
.packet_mode
=0; // create whole frame by ourself
637 else if (strcmp(packet_type
,"rtp")==0) {
643 if (!count_set
) tx
.count
= 0;
644 if (!delay_set
) tx
.delay
= 20000; // 20 msec inter-packet delay for RTP
647 else if (strcmp(packet_type
,"help")==0) {
651 "| The following packet types are currently implemented:\n"
653 "| arp ... sends ARP packets\n"
654 "| bpdu ... sends BPDU packets (STP or PVST+)\n"
655 "| cdp ... sends CDP messages\n"
656 "| ip ... sends IPv4 packets\n"
657 "| udp ... sends UDP datagrams\n"
658 "| tcp ... sends TCP segments\n"
659 "| icmp ... sends ICMP messages\n"
660 "| dns ... sends DNS messages\n"
661 "| rtp ... sends RTP datagrams\n"
662 "| syslog ... sends Syslog messages\n"
664 "| Of course you can build any other packet type 'manually' using the direct layer 2 mode.\n"
665 "| FYI: The interactive mode supports additional protocols. (Try mz -x <port>)\n"
671 fprintf(stderr
, " mz: you must specify a valid packet type!\n");
675 //////////////////////////////////////////////////////////////////////////
677 // TODO: Implement macro support
678 // Check macro types here