int open_device(char * device) { struct termios tio; int tty_fd; if (!dev_exists(device)) { return -ENXIO; } memset(&tio, 0, sizeof(tio)); tio.c_iflag = 0; tio.c_oflag = 0; tio.c_cflag = CS8 | CREAD | CLOCAL; tio.c_lflag = 0; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 5; if ((tty_fd = open(device, O_RDWR)) == -1) { return -1; } cfsetospeed(&tio, BAUDRATE); cfsetispeed(&tio, BAUDRATE); tcsetattr(tty_fd, TCSANOW, &tio); return tty_fd; }
// Purpose: Properly handle arguments and configure global structs (tx) int getopts (int argc, char *argv[]) { int i, c, rargs, RX=0, count_set=0, delay_set=0; unsigned int time_factor; char *packet_type=NULL, *mops_type=NULL; char *dum; unsigned char *dum1, *dum2; libnet_t *l; char err_buf[LIBNET_ERRBUF_SIZE]; struct libnet_ether_addr *mymac; FILE *afp; char hexpld[MAX_PAYLOAD_SIZE*2]; int hexpld_specified=0; opterr = 1; // let getopt print error message if necessary while ((c = getopt (argc, argv, "hqvVSxra:A:b:B:c:d:f:F:p:P:t:T:M:Q:X:")) != -1) switch (c) { case 'h': usage(); break; case 'q': quiet=1; break; case 'v': verbose=1; break; case 'V': verbose=2; break; case 'S': simulate=1; break; case 'x': mz_port = MZ_DEFAULT_PORT; break; case 'a': strncpy (tx.eth_src_txt, optarg, 32); tx.packet_mode = 0; break; case 'A': strncpy (tx.ip_src_txt, optarg, 32); break; case 'b': strncpy (tx.eth_dst_txt, optarg, 32); tx.packet_mode = 0; break; case 'B': strncpy (tx.ip_dst_txt, optarg, 32); break; case 'c': errno=0; tx.count = strtol(optarg, (char **)NULL, 10); if ((errno == ERANGE && (tx.count == LONG_MAX || tx.count == LONG_MIN)) || (errno != 0 && tx.count == 0)) { perror("strtol"); return (-1); } if (tx.count<0) tx.count=1; //TODO: Allow count=0 which means infinity (need to update all send_functions) count_set=1; break; case 'd': errno=0; // determine whether seconds or msecs are used // default is usec!!! time_factor=1; if (exists(optarg,"s") || exists(optarg,"sec")) time_factor=1000000; if (exists(optarg,"m") || exists(optarg,"msec")) time_factor=1000; dum = strtok(optarg,"ms"); tx.delay = strtol(dum, (char **)NULL, 10) * time_factor; if ((errno == ERANGE && (tx.delay == LONG_MAX || tx.delay == LONG_MIN)) || (errno != 0 && tx.delay == 0)) { perror("strtol"); return (-1); } if (tx.delay<0) tx.delay=0; // no delay delay_set=1; break; case 'p': errno=0; tx.padding = strtol(optarg, (char **)NULL, 10); if ((errno == ERANGE && (tx.padding == LONG_MAX || tx.padding == LONG_MIN)) || (errno != 0 && tx.padding == 0)) { perror("strtol"); return (-1); } if (tx.padding>10000) { fprintf(stderr, " Warning: Padding must not exceed 10000!\n"); return -1; } break; case 't': packet_type = optarg; // analyzed below break; case 'X': mops_type = optarg; // MOPS TRANSITION STRATEGY -- analyzed below break; case 'T': packet_type = optarg; RX = 1; break; case 'r': mz_rand = 1; break; case 'M': if (strncmp(optarg,"help",4)==0) { (void) get_mpls_params("help "); } else { strncpy (tx.mpls_txt, optarg, 128); tx.eth_type = ETHERTYPE_MPLS; tx.packet_mode = 0; tx.mpls=1; } break; case 'P': // ASCII payload strncpy((char*)tx.ascii_payload, optarg, MAX_PAYLOAD_SIZE); tx.ascii = 1; break; case 'f': // ASCII payload in FILE afp = fopen(optarg, "r"); if (fgets((char*)tx.ascii_payload, MAX_PAYLOAD_SIZE, afp) == NULL) fprintf(stderr, " mz/getopts: File empty?\n"); fclose(afp); tx.ascii = 1; break; case 'F': // HEX payload in FILE afp = fopen(optarg, "r"); i=0; while ( (hexpld[i]=fgetc(afp))!=EOF ) { if (isspace(hexpld[i])) { hexpld[i]=':'; } i++; } hexpld[i]='\0'; fclose(afp); hexpld_specified=1; break; case 'Q': // VLAN TAG if (strncmp(optarg,"help",4)==0) { print_dot1Q_help(); // ugly but most simple and safe solution } else { strncpy (tx.dot1Q_txt, optarg, 32); tx.dot1Q=1; // determine number of VLAN tags for (i=0; i<strlen(tx.dot1Q_txt); i++) { if (tx.dot1Q_txt[i]==',') tx.dot1Q++; } tx.packet_mode = 0; } break; case '?': if ((optopt == 'a') || (optopt == 'b') || (optopt = 'c') || (optopt == 'd') || (optopt == 'f') || (optopt = 'p') || (optopt == 't') || (optopt == 'm')) fprintf (stderr, " mz/getopts: Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf (stderr, " mz/getopts: Unknown option -%c'.\n", optopt); else fprintf (stderr, " mz/getopts: Unknown option character \\x%x'.\n", optopt); return 1; default: fprintf (stderr," mz/getopts: Could not handle arguments properly!\n"); return 1; } // ******************************************** // Handle additional arguments // ******************************************** // // Greeting text if (verbose) { fprintf(stderr,"\n" MAUSEZAHN_VERSION "\n" "Use at your own risk and responsibility!\n" "-- Verbose mode --\n" "\n"); } if (argc<2) { usage(); } if ((rargs=argc-optind)>2) { // number of remaining arguments fprintf(stderr," mz/getopts: Too many arguments!\n"); return -1; } // There can be 0-2 additional arguments switch (rargs) { case 0: if (lookupdev()) { // no device found if (verbose) fprintf(stderr, " mz: no active interfaces found!\n"); strcpy(tx.device, "lo"); } fprintf(stderr," mz: You must specify an interface. Use ifconfig and try again.\n"); exit(0); case 1: // arg_string OR device given => find out! if ( dev_exists(argv[optind]) ) { strncpy (tx.device, argv[optind], 16); } else { /// arg_string given => no device has been specified -- let's find one! strncpy (tx.arg_string, argv[optind], MAX_PAYLOAD_SIZE); if (lookupdev()) { // no device found if (verbose) fprintf(stderr, " mz: no active interfaces found!\n"); strcpy(tx.device, "lo"); } fprintf(stderr," mz: You must specify a valid interface. Use ifconfig and try again.\n"); exit(0); } break; case 2: // both device and arg_string given if(dev_exists(argv[optind])) { strncpy (tx.device, argv[optind], 16); strncpy (tx.arg_string, argv[optind+1], MAX_PAYLOAD_SIZE); } else if(dev_exists(argv[optind+1])) { strncpy (tx.device, argv[optind+1], 16); strncpy (tx.arg_string, argv[optind], MAX_PAYLOAD_SIZE); } else { if (lookupdev()) { // no device found if (verbose) fprintf(stderr, " mz: no active interfaces found!\n"); strcpy(tx.device, "lo"); } fprintf(stderr," mz: You must specify a valid interface. Use ifconfig and try again.\n"); exit(0); } break; default: fprintf(stderr," mz/getopts: Unknown argument problem!\n"); return 1; } if(verbose) { if(tx.device) fprintf(stderr," mz: Selected interface: %s\n",tx.device ); if(tx.arg_string) fprintf(stderr," mz: Selected argument string: %s\n", tx.arg_string); } if (hexpld_specified) { strcat(tx.arg_string, ",p="); strcat(tx.arg_string, hexpld); } ////////////////////////////////////////////////////////////////////////// // // Initialize MAC and IP Addresses. // // - tx.eth_src = own interface MAC // - tx.ip_src = own interface IP or user specified // - tx.ip_dst = 255.255.255.255 or user specified (can be a range) // - tx.ip_src_rand ... is set if needed. // // Get own device MAC address: // Don't open context if only a help text is requested if (getarg(tx.arg_string,"help", NULL)!=1) { l = libnet_init (LIBNET_LINK_ADV, tx.device, err_buf ); if (l == NULL) { fprintf(stderr, " mz/getopts: libnet_init() failed (%s)", err_buf); return -1; } mymac = libnet_get_hwaddr(l); for (i=0; i<6; i++) { tx.eth_src[i] = mymac->ether_addr_octet[i]; tx.eth_mac_own[i] = mymac->ether_addr_octet[i]; } // Set source IP address: if (strlen(tx.ip_src_txt)) { // option -A has been specified if (mz_strcmp(tx.ip_src_txt, "bcast", 2)==0) { tx.ip_src = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE); } else if (strcmp(tx.ip_src_txt, "rand") == 0) { tx.ip_src_rand = 1; tx.ip_src_h = (u_int32_t) ( ((float) rand()/RAND_MAX)*0xE0000000); //this is 224.0.0.0 } else if (get_ip_range_src(tx.ip_src_txt)) { // returns 1 when no range has been specified // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN: tx.ip_src = libnet_name2addr4 (l, tx.ip_src_txt, LIBNET_RESOLVE); } } else { // no source IP specified: by default use own IP address tx.ip_src = libnet_get_ipaddr4(l); } // Set destination IP address: if (strlen(tx.ip_dst_txt)) { // option -B has been specified if (mz_strcmp(tx.ip_dst_txt, "rand", 2)==0) { fprintf(stderr, "Option -B does not support random destination IP addresses currently.\n"); return 1; } if (mz_strcmp(tx.ip_dst_txt, "bcast", 2)==0) { tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE); } else if (get_ip_range_dst(tx.ip_dst_txt)) { // returns 1 when no range has been specified // name2addr4 accepts a DOTTED DECIMAL ADDRESS or a FQDN: tx.ip_dst = libnet_name2addr4 (l, tx.ip_dst_txt, LIBNET_RESOLVE); } } else { // no destination IP specified: by default use broadcast tx.ip_dst = libnet_name2addr4 (l, "255.255.255.255", LIBNET_DONT_RESOLVE); } // Initialize tx.ip_src_h and tx.ip_dst_h which are used by 'print_frame_details()' // in verbose mode. See 'modifications.c'. if (tx.ip_src_rand) { // ip_src_h already given, convert to ip_src dum1 = (unsigned char*) &tx.ip_src_h; dum2 = (unsigned char*) &tx.ip_src; } else { // ip_src already given, convert to ip_src_h dum1 = (unsigned char*) &tx.ip_src; dum2 = (unsigned char*) &tx.ip_src_h; } *dum2 = *(dum1+3); dum2++; *dum2 = *(dum1+2); dum2++; *dum2 = *(dum1+1); dum2++; *dum2 = *dum1; dum1 = (unsigned char*) &tx.ip_dst; dum2 = (unsigned char*) &tx.ip_dst_h; *dum2 = *(dum1+3); dum2++; *dum2 = *(dum1+2); dum2++; *dum2 = *(dum1+1); dum2++; *dum2 = *dum1; libnet_destroy(l); } // // END OF ADDRESS INITIALIZATION // ////////////////////////////////////////////////////////////////////////// ////// retrieve interface parameters /////// for (i=0; i<device_list_entries; i++) { get_dev_params(device_list[i].dev); } ////////////////////////////////////////////////////////////////////////// // // Mausezahn CLI desired? if (mz_port) { // has port number been specified? if (strlen(tx.arg_string)) { mz_port = (int) str2int (tx.arg_string); } if (!quiet) { fprintf(stderr, "Mausezahn accepts incoming Telnet connections on port %i.\n", mz_port); } mz_cli_init(); cli(); } ////////////////////////////////////////////////////////////////////////// // // Mode decision // // Consider -t and -m option (used exclusively) // -t => special packet types, stateless // // If -t not present then evaluate arg_string which must // contain a byte-string in hexadecimal notation. // // // ***** NEW: MOPS TRANSITION STRATEGY ***** if (mops_type != NULL) { if (mz_strcmp(mops_type,"lldp",4)==0) { mops_direct(tx.device, MOPS_LLDP, tx.arg_string); } } if (packet_type == NULL) { // raw hex string given mode = BYTE_STREAM; } else if (strcmp(packet_type,"arp")==0) { mode = ARP; } else if (strcmp(packet_type,"bpdu")==0) { mode = BPDU; } else if (strcmp(packet_type,"ip")==0) { mode = IP; } else if (strcmp(packet_type,"udp")==0) { mode = UDP; } else if (strcmp(packet_type,"icmp")==0) { mode = ICMP; } else if (strcmp(packet_type,"tcp")==0) { mode = TCP; } else if (strcmp(packet_type,"dns")==0) { mode = DNS; } else if (strcmp(packet_type,"cdp")==0) { mode = CDP; } else if (strcmp(packet_type,"syslog")==0) { mode = SYSLOG; } else if (strcmp(packet_type,"lldp")==0) { mode = LLDP; tx.packet_mode=0; // create whole frame by ourself } else if (strcmp(packet_type,"rtp")==0) { if (RX) { mode = RX_RTP; } else { mode = RTP; if (!count_set) tx.count = 0; if (!delay_set) tx.delay = 20000; // 20 msec inter-packet delay for RTP } } else if (strcmp(packet_type,"help")==0) { fprintf(stderr, "\n" MAUSEZAHN_VERSION "\n" "| The following packet types are currently implemented:\n" "|\n" "| arp ... sends ARP packets\n" "| bpdu ... sends BPDU packets (STP or PVST+)\n" "| cdp ... sends CDP messages\n" "| ip ... sends IPv4 packets\n" "| udp ... sends UDP datagrams\n" "| tcp ... sends TCP segments\n" "| icmp ... sends ICMP messages\n" "| dns ... sends DNS messages\n" "| rtp ... sends RTP datagrams\n" "| syslog ... sends Syslog messages\n" "|\n" "| Of course you can build any other packet type 'manually' using the direct layer 2 mode.\n" "| FYI: The interactive mode supports additional protocols. (Try mz -x <port>)\n" "\n" ); exit(1); } else { fprintf(stderr, " mz: you must specify a valid packet type!\n"); } ////////////////////////////////////////////////////////////////////////// // TODO: Implement macro support // Check macro types here return 0; }