Outsource creation of random MAC address to a new function create_random_mac.
[mausezahn.git] / src / init.c
blob0ab21cba46e7ba21f22e23a162b3ce46160c684a
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
4 *
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.
8 *
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
12 * details.
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 // ****************************************************************************
23 // Two features here:
24 // 1. Initialize globals
25 // 2. Handle arguments in *argv[] and make a mode decision
26 // ****************************************************************************
28 #include "mz.h"
29 #include "cli.h"
30 #include "mops.h"
32 // Purpose: reset globals, global structs, etc.
33 int reset()
35 int i;
36 time_t t;
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;
44 // Reset globals:
45 quiet = 0;
46 verbose = 0;
47 simulate = 0;
48 filename[0] = '\0';
49 path[0] = '\0';
50 gind=0;
51 gind_max = TIME_COUNT;
52 fp = NULL;
53 fp2 = NULL;
54 mz_port = 0;
55 mz_rand = 0;
56 mp_head = NULL;
58 for (i=0;i<TIME_COUNT_MAX;i++) jitter[i] = 0;
60 time0_flag = 0; // If set then time0 has valid data
61 sqnr0_flag = 0; // If set then sqnr_last and sqnr_next has valid data
62 rtp_log = 0;
63 mz_ssrc[0]=0; mz_ssrc[1]=0; mz_ssrc[2]=0; mz_ssrc[3]=0;
65 // Reset mgmt parameters of TX:
66 tx.packet_mode = 1; // assume we don't care about L2
67 tx.count = 1;
68 tx.delay = DEFAULT_DELAY;
69 tx.arg_string[0] = '\0';
71 // Reset Ethernet parameters of TX:
72 tx.eth_params_already_set = 0;
73 for (i=0; i<6; i++) tx.eth_dst[i] = 0xff;
74 for (i=0; i<6; i++) tx.eth_src[i] = 0; // TODO: Get own MAC !!!
75 tx.eth_dst_txt[0] = '\0';
76 tx.eth_src_txt[0] = '\0';
77 tx.eth_dst_rand = 0;
78 tx.eth_src_rand = 0;
80 tx.eth_type = 0x800;
81 tx.eth_len = 0;
82 tx.eth_payload[0] = '\0';
83 tx.eth_payload_s = 0;
84 tx.padding = 0;
86 // Reset CDP parameters for TX:
87 tx.cdp_sum = 0;
88 tx.cdp_version = 0;
89 tx.cdp_ttl = 0;
90 tx.cdp_payload[0] = '\0';
91 tx.cdp_payload_s = 0;
92 tx.cdp_tlv_id[0] = '\0';
93 tx.cdp_tlv_id_len = 0;
95 // Reset 802.1Q parameters of TX:
96 tx.dot1Q=0;
97 tx.dot1Q_txt[0] = '\0';
99 // ASCII Payload:
100 tx.ascii = 0; // 1 if specified
101 tx.ascii_payload[0]= '\0';
103 // HEX Payload:
104 tx.hex_payload_s = 0;
106 // Reset MPLS parameters of TX:
107 tx.mpls = 0;
108 tx.mpls_txt[0] = '\0';
109 tx.mpls_label = 0;
110 tx.mpls_exp = 0;
111 tx.mpls_bos = 1;
112 tx.mpls_ttl = 255;
113 tx.mpls_verbose_string[0] = '\0';
115 // Reset IP parameters of TX:
116 tx.ip_src_txt[0] = '\0';
117 tx.ip_src_rand = 0;
118 tx.ip_dst_txt[0] = '\0';
119 tx.ip_src_isrange = 0;
120 tx.ip_src_start = 0;
121 tx.ip_src_stop = 0;
123 tx.ip_dst_start = 0;
124 tx.ip_dst_stop = 0;
125 tx.ip_dst_isrange = 0;
127 tx.ip_len = 0;
128 tx.ip_payload[0]= '\0';
129 tx.ip_payload_s = 0;
130 tx.ip_option[0]= '\0';
131 tx.ip_option_s = 0;
133 // Reset ICMP parameters:
134 tx.icmp_type=0;
135 tx.icmp_code=0;
136 tx.icmp_chksum=0; // 0=autofill
137 tx.icmp_ident=0x42;
138 tx.icmp_sqnr=0x1;
139 tx.icmp_payload_s=0;
141 // Reset general L4 parameters:
142 tx.sp = 0;
143 tx.dp = 0;
144 tx.sp_start = 0;
145 tx.sp_stop = 0;
146 tx.dp_start = 0;
147 tx.dp_stop = 0;
148 tx.sp_isrange = 0;
149 tx.dp_isrange = 0;
151 // Reset UDP parameters of TX:
153 tx.udp_len = 0; // If set to zero then create_udp_packet will calculate it
154 tx.udp_sum = 0;
155 tx.udp_payload[0] = '\0';
156 tx.udp_payload_s = 0;
158 // Reset TCP parameters of TX:
160 tx.tcp_seq = 42;
161 tx.tcp_seq_stop = 42;
162 tx.tcp_seq_delta = 0; // also used as 'isrange' meaning
163 tx.tcp_ack = 42;
164 tx.tcp_control = 0;
165 tx.tcp_win = 10000;
166 tx.tcp_sum = 0;
167 tx.tcp_urg = 0;
168 tx.tcp_len = 20; // Least size (TCP header only)
169 tx.tcp_payload[0] = '\0';
170 tx.tcp_payload_s = 0;
172 // Reset RTP parameters of TX:
173 tx.rtp_sqnr = 0;
174 tx.rtp_stmp = 0;
176 // Initialize random generator
177 time(&t);
178 srand((unsigned int)t);
180 // Reset device_list
181 for (i=0; i<MZ_MAX_DEVICES; i++) {
182 device_list[i].arprx_thread = 0;
183 device_list[i].p_arp = NULL;
184 device_list[i].arp_table = NULL;
185 device_list[i].ps=-1;
186 device_list[i].cli=0;
187 device_list[i].mgmt_only=0;
190 return 0;
195 // Purpose: Properly handle arguments and configure global structs (tx)
196 int getopts (int argc, char *argv[])
198 int i, c, rargs, RX=0, count_set=0, delay_set=0;
199 unsigned int time_factor;
200 char *packet_type=NULL, *mops_type=NULL;
201 char *dum;
202 unsigned char *dum1, *dum2;
204 libnet_t *l;
205 char err_buf[LIBNET_ERRBUF_SIZE];
206 struct libnet_ether_addr *mymac;
208 FILE *afp;
209 char hexpld[MAX_PAYLOAD_SIZE*2];
210 int hexpld_specified=0;
212 opterr = 1; // let getopt print error message if necessary
215 while ((c = getopt (argc, argv, "hqvVSxra:A:b:B:c:d:f:F:p:P:t:T:M:Q:X:")) != -1)
216 switch (c) {
217 case 'h':
218 usage();
219 break;
220 case 'q':
221 quiet=1;
222 break;
223 case 'v':
224 verbose=1;
225 break;
226 case 'V':
227 verbose=2;
228 break;
229 case 'S':
230 simulate=1;
231 break;
232 case 'x':
233 mz_port = MZ_DEFAULT_PORT;
234 break;
235 case 'a':
236 strncpy (tx.eth_src_txt, optarg, 32);
237 tx.packet_mode = 0;
238 break;
239 case 'A':
240 strncpy (tx.ip_src_txt, optarg, 32);
241 break;
242 case 'b':
243 strncpy (tx.eth_dst_txt, optarg, 32);
244 tx.packet_mode = 0;
245 break;
246 case 'B':
247 strncpy (tx.ip_dst_txt, optarg, 32);
248 break;
249 case 'c':
250 errno=0;
251 tx.count = strtol(optarg, (char **)NULL, 10);
252 if ((errno == ERANGE && (tx.count == LONG_MAX || tx.count == LONG_MIN))
253 || (errno != 0 && tx.count == 0)) {
254 perror("strtol");
255 return (-1);
257 if (tx.count<0) tx.count=1; //TODO: Allow count=0 which means infinity (need to update all send_functions)
258 count_set=1;
259 break;
260 case 'd':
261 errno=0;
262 // determine whether seconds or msecs are used
263 // default is usec!!!
264 time_factor=1;
265 if (exists(optarg,"s") || exists(optarg,"sec")) time_factor=1000000;
266 if (exists(optarg,"m") || exists(optarg,"msec")) time_factor=1000;
267 dum = strtok(optarg,"ms");
268 tx.delay = strtol(dum, (char **)NULL, 10) * time_factor;
269 if ((errno == ERANGE && (tx.delay == LONG_MAX || tx.delay == LONG_MIN))
270 || (errno != 0 && tx.delay == 0)) {
271 perror("strtol");
272 return (-1);
274 if (tx.delay<0) tx.delay=0; // no delay
275 delay_set=1;
276 break;
277 case 'p':
278 errno=0;
279 tx.padding = strtol(optarg, (char **)NULL, 10);
280 if ((errno == ERANGE && (tx.padding == LONG_MAX || tx.padding == LONG_MIN))
281 || (errno != 0 && tx.padding == 0)) {
282 perror("strtol");
283 return (-1);
285 if (tx.padding>10000) {
286 fprintf(stderr, " Warning: Padding must not exceed 10000!\n");
287 return -1;
289 break;
290 case 't':
291 packet_type = optarg; // analyzed below
292 break;
293 case 'X':
294 mops_type = optarg; // MOPS TRANSITION STRATEGY -- analyzed below
295 break;
296 case 'T':
297 packet_type = optarg;
298 RX = 1;
299 break;
300 case 'r':
301 mz_rand = 1;
302 break;
303 case 'M':
304 if (strncmp(optarg,"help",4)==0) {
305 (void) get_mpls_params("help ");
307 else {
308 strncpy (tx.mpls_txt, optarg, 128);
309 tx.eth_type = ETHERTYPE_MPLS;
310 tx.packet_mode = 0;
311 tx.mpls=1;
313 break;
314 case 'P': // ASCII payload
315 strncpy((char*)tx.ascii_payload, optarg, MAX_PAYLOAD_SIZE);
316 tx.ascii = 1;
317 break;
318 case 'f': // ASCII payload in FILE
319 afp = fopen(optarg, "r");
320 if (fgets((char*)tx.ascii_payload, MAX_PAYLOAD_SIZE, afp) == NULL)
321 fprintf(stderr, " mz/getopts: File empty?\n");
322 fclose(afp);
323 tx.ascii = 1;
324 break;
325 case 'F': // HEX payload in FILE
326 afp = fopen(optarg, "r");
327 i=0;
328 while ( (hexpld[i]=fgetc(afp))!=EOF ) {
329 if (isspace(hexpld[i])) {
330 hexpld[i]=':';
332 i++;
334 hexpld[i]='\0';
335 fclose(afp);
336 hexpld_specified=1;
337 break;
338 case 'Q': // VLAN TAG
339 if (strncmp(optarg,"help",4)==0) {
340 print_dot1Q_help(); // ugly but most simple and safe solution
342 else {
343 strncpy (tx.dot1Q_txt, optarg, 32);
344 tx.dot1Q=1;
345 // determine number of VLAN tags
346 for (i=0; i<strlen(tx.dot1Q_txt); i++) {
347 if (tx.dot1Q_txt[i]==',') tx.dot1Q++;
349 tx.packet_mode = 0;
351 break;
352 case '?':
353 if ((optopt == 'a') || (optopt == 'b') || (optopt = 'c') ||
354 (optopt == 'd') || (optopt == 'f') || (optopt = 'p') ||
355 (optopt == 't') || (optopt == 'm'))
356 fprintf (stderr, " mz/getopts: Option -%c requires an argument.\n", optopt);
357 else if (isprint (optopt))
358 fprintf (stderr, " mz/getopts: Unknown option -%c'.\n", optopt);
359 else
360 fprintf (stderr, " mz/getopts: Unknown option character \\x%x'.\n", optopt);
361 return 1;
362 default:
363 fprintf (stderr," mz/getopts: Could not handle arguments properly!\n");
364 return 1;
367 // ********************************************
368 // Handle additional arguments
369 // ********************************************
371 // Greeting text
372 if (verbose) {
373 fprintf(stderr,"\n"
374 MAUSEZAHN_VERSION
375 "\n"
376 "Use at your own risk and responsibility!\n"
377 "-- Verbose mode --\n"
378 "\n");
381 if (argc<2) {
382 usage();
385 if ((rargs=argc-optind)>2) { // number of remaining arguments
386 fprintf(stderr," mz/getopts: Too many arguments!\n");
387 return -1;
391 // There can be 0-2 additional arguments
392 switch (rargs) {
393 case 0:
394 if (lookupdev()) { // no device found
395 if (verbose) fprintf(stderr, " mz: no active interfaces found!\n");
396 strcpy(tx.device, "lo");
398 if (verbose) // device found
399 fprintf(stderr," mz: device not given, will use %s\n",tx.device);
400 break;
401 case 1: // arg_string OR device given => find out!
402 if ( (strncmp(argv[optind],"eth",3)==0)
403 || (strncmp(argv[optind],"ath",3)==0)
404 || ((strncmp(argv[optind],"lo",2)==0)&&(strncmp(argv[optind],"log",3)!=0))
405 || (strncmp(argv[optind],"vmnet",5)==0)
406 || (strncmp(argv[optind],"wifi",4)==0) ) {
407 // device has been specified!
408 strncpy (tx.device, argv[optind], 16);
410 else { /// arg_string given => no device has been specified -- let's find one!
411 strncpy (tx.arg_string, argv[optind], MAX_PAYLOAD_SIZE);
412 if (lookupdev()) { // no device found
413 if (verbose) fprintf(stderr, " mz: no active interfaces found!\n");
414 strcpy(tx.device, "lo");
416 if (verbose)
417 fprintf(stderr," mz: device not given, will use %s\n",tx.device);
419 break;
420 case 2: // both device and arg_string given
421 strncpy (tx.device, argv[optind], 16);
422 strncpy (tx.arg_string, argv[optind+1], MAX_PAYLOAD_SIZE);
423 break;
424 default:
425 fprintf(stderr," mz/getopts: Unknown argument problem!\n");
426 return 1;
429 if (hexpld_specified) {
430 strcat(tx.arg_string, ",p=");
431 strcat(tx.arg_string, hexpld);
435 //////////////////////////////////////////////////////////////////////////
437 // Initialize MAC and IP Addresses.
439 // - tx.eth_src = own interface MAC
440 // - tx.ip_src = own interface IP or user specified
441 // - tx.ip_dst = 255.255.255.255 or user specified (can be a range)
442 // - tx.ip_src_rand ... is set if needed.
445 // Get own device MAC address:
446 // Don't open context if only a help text is requested
447 if (getarg(tx.arg_string,"help", NULL)!=1) {
448 l = libnet_init (LIBNET_LINK_ADV, tx.device, err_buf );
449 if (l == NULL) {
450 fprintf(stderr, " mz/getopts: libnet_init() failed (%s)", err_buf);
451 return -1;
453 mymac = libnet_get_hwaddr(l);
454 for (i=0; i<6; i++) {
455 tx.eth_src[i] = mymac->ether_addr_octet[i];
456 tx.eth_mac_own[i] = mymac->ether_addr_octet[i];
459 // Set source IP address:
460 if (strlen(tx.ip_src_txt)) { // option -A has been specified
461 if (mz_strcmp(tx.ip_src_txt, "bcast", 2)==0) {
462 tx.ip_src = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
463 } else if (strcmp(tx.ip_src_txt, "rand") == 0) {
464 tx.ip_src_rand = 1;
465 tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0
467 else if (get_ip_range_src(tx.ip_src_txt)) { // returns 1 when no range has been specified
468 // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
469 tx.ip_src = libnet_name2addr4 (l, tx.ip_src_txt, LIBNET_RESOLVE);
472 else { // no source IP specified: by default use own IP address
473 tx.ip_src = libnet_get_ipaddr4(l);
476 // Set destination IP address:
477 if (strlen(tx.ip_dst_txt)) { // option -B has been specified
478 if (mz_strcmp(tx.ip_dst_txt, "rand", 2)==0) {
479 fprintf(stderr, "Option -B does not support random destination IP addresses currently.\n");
480 return 1;
483 if (mz_strcmp(tx.ip_dst_txt, "bcast", 2)==0) {
484 tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
485 } else if (get_ip_range_dst(tx.ip_dst_txt)) { // returns 1 when no range has been specified
486 // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN:
487 tx.ip_dst = libnet_name2addr4 (l, tx.ip_dst_txt, LIBNET_RESOLVE);
490 else { // no destination IP specified: by default use broadcast
491 tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE);
494 // Initialize tx.ip_src_h and tx.ip_dst_h which are used by 'print_frame_details()'
495 // in verbose mode. See 'modifications.c'.
497 if (tx.ip_src_rand) { // ip_src_h already given, convert to ip_src
498 dum1 = (unsigned char*) &tx.ip_src_h;
499 dum2 = (unsigned char*) &tx.ip_src;
501 else { // ip_src already given, convert to ip_src_h
502 dum1 = (unsigned char*) &tx.ip_src;
503 dum2 = (unsigned char*) &tx.ip_src_h;
506 *dum2 = *(dum1+3);
507 dum2++;
508 *dum2 = *(dum1+2);
509 dum2++;
510 *dum2 = *(dum1+1);
511 dum2++;
512 *dum2 = *dum1;
514 dum1 = (unsigned char*) &tx.ip_dst;
515 dum2 = (unsigned char*) &tx.ip_dst_h;
517 *dum2 = *(dum1+3);
518 dum2++;
519 *dum2 = *(dum1+2);
520 dum2++;
521 *dum2 = *(dum1+1);
522 dum2++;
523 *dum2 = *dum1;
525 libnet_destroy(l);
529 // END OF ADDRESS INITIALIZATION
531 //////////////////////////////////////////////////////////////////////////
534 ////// retrieve interface parameters ///////
536 for (i=0; i<device_list_entries; i++) {
537 get_dev_params(device_list[i].dev);
541 //////////////////////////////////////////////////////////////////////////
543 // Mausezahn CLI desired?
544 if (mz_port) {
545 // has port number been specified?
546 if (strlen(tx.arg_string)) {
547 mz_port = (int) str2int (tx.arg_string);
550 if (!quiet) {
551 fprintf(stderr, "Mausezahn accepts incoming Telnet connections on port %i.\n", mz_port);
554 mz_cli_init();
555 cli();
558 //////////////////////////////////////////////////////////////////////////
560 // Mode decision
562 // Consider -t and -m option (used exclusively)
563 // -t => special packet types, stateless
565 // If -t not present then evaluate arg_string which must
566 // contain a byte-string in hexadecimal notation.
570 // ***** NEW: MOPS TRANSITION STRATEGY *****
571 if (mops_type != NULL) {
573 if (mz_strcmp(mops_type,"lldp",4)==0) {
574 mops_direct(tx.device, MOPS_LLDP, tx.arg_string);
579 if (packet_type == NULL) { // raw hex string given
580 mode = BYTE_STREAM;
582 else if (strcmp(packet_type,"arp")==0) {
583 mode = ARP;
585 else if (strcmp(packet_type,"bpdu")==0) {
586 mode = BPDU;
588 else if (strcmp(packet_type,"ip")==0) {
589 mode = IP;
591 else if (strcmp(packet_type,"udp")==0) {
592 mode = UDP;
594 else if (strcmp(packet_type,"icmp")==0) {
595 mode = ICMP;
597 else if (strcmp(packet_type,"tcp")==0) {
598 mode = TCP;
600 else if (strcmp(packet_type,"dns")==0) {
601 mode = DNS;
603 else if (strcmp(packet_type,"cdp")==0) {
604 mode = CDP;
606 else if (strcmp(packet_type,"syslog")==0) {
607 mode = SYSLOG;
609 else if (strcmp(packet_type,"lldp")==0) {
610 mode = LLDP;
611 tx.packet_mode=0; // create whole frame by ourself
613 else if (strcmp(packet_type,"rtp")==0) {
614 if (RX) {
615 mode = RX_RTP;
617 else {
618 mode = RTP;
619 if (!count_set) tx.count = 0;
620 if (!delay_set) tx.delay = 20000; // 20 msec inter-packet delay for RTP
623 else if (strcmp(packet_type,"help")==0) {
624 fprintf(stderr, "\n"
625 MAUSEZAHN_VERSION
626 "\n"
627 "| The following packet types are currently implemented:\n"
628 "|\n"
629 "| arp ... sends ARP packets\n"
630 "| bpdu ... sends BPDU packets (STP or PVST+)\n"
631 "| cdp ... sends CDP messages\n"
632 "| ip ... sends IPv4 packets\n"
633 "| udp ... sends UDP datagrams\n"
634 "| tcp ... sends TCP segments\n"
635 "| icmp ... sends ICMP messages\n"
636 "| dns ... sends DNS messages\n"
637 "| rtp ... sends RTP datagrams\n"
638 "| syslog ... sends Syslog messages\n"
639 "|\n"
640 "| Of course you can build any other packet type 'manually' using the direct layer 2 mode.\n"
641 "| FYI: The interactive mode supports additional protocols. (Try mz -x <port>)\n"
642 "\n"
644 exit(1);
646 else {
647 fprintf(stderr, " mz: you must specify a valid packet type!\n");
651 //////////////////////////////////////////////////////////////////////////
653 // TODO: Implement macro support
654 // Check macro types here
656 return 0;