/*************************************************************************** * ArgParser.cc -- The ArgParser Class is the one in charge of command line* * argument parsing. Essentially it contains method parseArguments() that * * takes the usual argc and *argv[] parameters and fills the general * * NpingOps class with all the information needed for the execution of * * Nping. * * * ***********************IMPORTANT NMAP LICENSE TERMS************************ * * * The Nmap Security Scanner is (C) 1996-2012 Insecure.Com LLC. Nmap is * * also a registered trademark of Insecure.Com LLC. This program is free * * software; you may redistribute and/or modify it under the terms of the * * GNU General Public License as published by the Free Software * * Foundation; Version 2 with the clarifications and exceptions described * * below. This guarantees your right to use, modify, and redistribute * * this software under certain conditions. If you wish to embed Nmap * * technology into proprietary software, we sell alternative licenses * * (contact sales@insecure.com). Dozens of software vendors already * * license Nmap technology such as host discovery, port scanning, OS * * detection, version detection, and the Nmap Scripting Engine. * * * * Note that the GPL places important restrictions on "derived works", yet * * it does not provide a detailed definition of that term. To avoid * * misunderstandings, we interpret that term as broadly as copyright law * * allows. For example, we consider an application to constitute a * * "derivative work" for the purpose of this license if it does any of the * * following: * * o Integrates source code from Nmap * * o Reads or includes Nmap copyrighted data files, such as * * nmap-os-db or nmap-service-probes. * * o Executes Nmap and parses the results (as opposed to typical shell or * * execution-menu apps, which simply display raw Nmap output and so are * * not derivative works.) * * o Integrates/includes/aggregates Nmap into a proprietary executable * * installer, such as those produced by InstallShield. * * o Links to a library or executes a program that does any of the above * * * * The term "Nmap" should be taken to also include any portions or derived * * works of Nmap, as well as other software we distribute under this * * license such as Zenmap, Ncat, and Nping. This list is not exclusive, * * but is meant to clarify our interpretation of derived works with some * * common examples. Our interpretation applies only to Nmap--we don't * * speak for other people's GPL works. * * * * If you have any questions about the GPL licensing restrictions on using * * Nmap in non-GPL works, we would be happy to help. As mentioned above, * * we also offer alternative license to integrate Nmap into proprietary * * applications and appliances. These contracts have been sold to dozens * * of software vendors, and generally include a perpetual license as well * * as providing for priority support and updates. They also fund the * * continued development of Nmap. Please email sales@insecure.com for * * further information. * * * * As a special exception to the GPL terms, Insecure.Com LLC grants * * permission to link the code of this program with any version of the * * OpenSSL library which is distributed under a license identical to that * * listed in the included docs/licenses/OpenSSL.txt file, and distribute * * linked combinations including the two. You must obey the GNU GPL in all * * respects for all of the code used other than OpenSSL. If you modify * * this file, you may extend this exception to your version of the file, * * but you are not obligated to do so. * * * * If you received these files with a written license agreement or * * contract stating terms other than the terms above, then that * * alternative license agreement takes precedence over these comments. * * * * Source is provided to this software because we believe users have a * * right to know exactly what a program is going to do before they run it. * * This also allows you to audit the software for security holes (none * * have been found so far). * * * * Source code also allows you to port Nmap to new platforms, fix bugs, * * and add new features. You are highly encouraged to send your changes * * to the dev@nmap.org mailing list for possible incorporation into the * * main distribution. By sending these changes to Fyodor or one of the * * Insecure.Org development mailing lists, or checking them into the Nmap * * source code repository, it is understood (unless you specify otherwise) * * that you are offering the Nmap Project (Insecure.Com LLC) the * * unlimited, non-exclusive right to reuse, modify, and relicense the * * code. Nmap will always be available Open Source, but this is important * * because the inability to relicense code has caused devastating problems * * for other Free Software projects (such as KDE and NASM). We also * * occasionally relicense the code to third parties as discussed above. * * If you wish to specify special license conditions of your * * contributions, just say so when you send them. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Nmap * * license file for more details (it's in a COPYING file included with * * Nmap, and also available from https://svn.nmap.org/nmap/COPYING * * * ***************************************************************************/ #include "nping.h" #include "ArgParser.h" #include "NpingOps.h" #include "common.h" #include "nbase.h" #include "utils.h" #include "utils_net.h" #include "output.h" #include using namespace std; extern NpingOps o; ArgParser::ArgParser() { } /* End of ArgParser constructor */ ArgParser::~ArgParser() { } /* End of ArgParser destructor */ int ArgParser::parseArguments(int argc, char *argv[]) { int arg=0; int auxint=0; long l=0; int option_index=0; IPAddress aux_ip4; IPAddress aux_ip6; struct in_addr auxinaddr; u64 aux64=0; u32 aux32=0; u16 aux16=0; u8 aux8=0; u8 auxmac[6]; u8 *auxbuff=NULL; u16 *portlist=NULL; char errstr[256]; static u8 ipoptsbuff[128]; struct option long_options[] = { /* Probe modes */ {"tcp-connect", no_argument, 0, 0}, {"tcp", no_argument, 0, 0}, {"udp", no_argument, 0, 0}, {"udp-unpriv", no_argument, 0, 0}, {"icmp", no_argument, 0, 0}, {"arp", no_argument, 0, 0}, {"tr", no_argument, 0, 0}, {"traceroute", no_argument, 0, 0}, /* TCP/UDP */ {"source-port", required_argument, 0, 'g'}, {"dest-port", required_argument, 0, 'p'}, {"seq", required_argument, 0, 0}, {"flags", required_argument, 0, 0}, {"ack", required_argument, 0, 0}, {"win", required_argument, 0, 0}, {"csum", required_argument, 0, 0}, {"badsum", no_argument, 0, 0}, /* ICMPv4 */ {"icmp-type", required_argument, 0, 0}, {"icmp-code", required_argument, 0, 0}, {"icmp-id", required_argument, 0, 0}, {"icmp-seq", required_argument, 0, 0}, {"icmp-redirect-addr", required_argument, 0, 0}, {"icmp-param-pointer", required_argument, 0, 0}, {"icmp-advert-lifetime", required_argument, 0, 0}, {"icmp-advert-entry", required_argument, 0, 0}, {"icmp-orig-time", required_argument, 0, 0}, {"icmp-recv-time", required_argument, 0, 0}, {"icmp-trans-time", required_argument, 0, 0}, {"icmp-mask", required_argument, 0, 0}, /* TODO: Add relevant flags for different ICMP options */ /* ICMPv6 */ {"icmp6-type", required_argument, 0, 0}, {"icmp6-code", required_argument, 0, 0}, {"icmp6-id", required_argument, 0, 0}, {"icmp6-seq", required_argument, 0, 0}, {"icmp6-param-pointer", required_argument, 0, 0}, {"icmp6-mtu", required_argument, 0, 0}, {"icmp6-ra-flags", required_argument, 0, 0}, {"icmp6-ra-hlim", required_argument, 0, 0}, {"icmp6-ra-lifetime", required_argument, 0, 0}, {"icmp6-ra-reachtime", required_argument, 0, 0}, {"icmp6-ra-retrtimer", required_argument, 0, 0}, {"icmp6-na-flags", required_argument, 0, 0}, {"icmp6-na-addr", required_argument, 0, 0}, {"icmp6-ns-addr", required_argument, 0, 0}, {"icmp6-redir-gw", required_argument, 0, 0}, {"icmp6-redir-dest", required_argument, 0, 0}, {"icmp6-rr-seq", required_argument, 0, 0}, {"icmp6-rr-seg", required_argument, 0, 0}, {"icmp6-rr-flags", required_argument, 0, 0}, {"icmp6-rr-delay", required_argument, 0, 0}, {"icmp6-rr-match-prefix", required_argument, 0, 0}, {"icmp6-rr-use-prefix", required_argument, 0, 0}, {"icmp6-rr-matched-prefix", required_argument, 0, 0}, {"icmp6-ni-qtype", required_argument, 0, 0}, {"icmp6-ni-flags", required_argument, 0, 0}, {"icmp6-ni-nonce", required_argument, 0, 0}, {"icmp6-ni-data", required_argument, 0, 0}, {"icmp6-gm-delay", required_argument, 0, 0}, {"icmp6-gm-addr", required_argument, 0, 0}, /* ARP */ {"arp-type", required_argument, 0, 0}, {"arp-sender-mac", required_argument, 0, 0}, {"arp-sender-ip", required_argument, 0, 0}, {"arp-target-mac", required_argument, 0, 0}, {"arp-target-ip", required_argument, 0, 0}, /* Ethernet */ {"dest-mac", required_argument, 0, 0}, {"source-mac", required_argument, 0, 0}, {"spoof-mac", required_argument, 0, 0}, {"ethertype", required_argument, 0, 0}, {"ethtype", required_argument, 0, 0}, {"ether-type", required_argument, 0, 0}, {"eth-type", required_argument, 0, 0}, /* IPv4 */ {"IPv4", no_argument, 0, '4'}, {"ipv4", no_argument, 0, '4'}, {"source-ip", required_argument, 0, 'S'}, {"dest-ip", required_argument, 0, 0}, {"tos", required_argument, 0, 0}, {"id", required_argument, 0, 0}, {"rf", no_argument, 0, 0}, {"df", no_argument, 0, 0}, {"mf", no_argument, 0, 0}, {"ttl", required_argument, 0, 0}, {"fragoff", required_argument, 0, 0}, {"csum-ip", required_argument, 0, 0}, {"badsum-ip", no_argument, 0, 0}, {"ip-options", required_argument, 0, 0}, {"mtu", required_argument, 0, 0}, /* Remember also: "-f" : Fragment packets*/ /* IPv6 */ {"IPv6", no_argument, 0, '6'}, {"ipv6", no_argument, 0, '6'}, {"hop-limit", required_argument, 0, 0}, {"tc", required_argument, 0, 0}, {"traffic-class", required_argument, 0, 0}, {"flow", required_argument, 0, 0}, /* Payload */ {"data", required_argument, 0, 0}, {"data-length", required_argument, 0, 0}, {"data-string", required_argument, 0, 0}, /* Echo client/server */ {"echo-client", required_argument, 0, 0}, {"ec", required_argument, 0, 0}, {"echo-server", required_argument, 0, 0}, {"es", required_argument, 0, 0}, {"echo-port", required_argument, 0, 0}, {"ep", required_argument, 0, 0}, {"no-crypto", no_argument, 0, 0}, {"nc", no_argument, 0, 0}, {"once", no_argument, 0, 0}, {"safe-payloads", no_argument, 0, 0}, {"include-payloads", no_argument, 0, 0}, /* Timing and performance */ {"delay", required_argument, 0, 0}, {"rate", required_argument, 0, 0}, /* Misc */ {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"count", required_argument, 0, 'c'}, {"interface", required_argument, 0, 'e'}, {"privileged", no_argument, 0, 0}, {"unprivileged", no_argument, 0, 0}, {"send-eth", no_argument, 0, 0}, {"send-ip", no_argument, 0, 0}, {"bpf-filter", required_argument, 0, 0}, {"filter", required_argument, 0, 0}, {"nsock-engine", required_argument, 0, 0}, {"no-capture", no_argument, 0, 'N'}, {"hide-sent", no_argument, 0, 'H'}, {"show-all-stats", no_argument, 0, 0}, {"show-eth", no_argument, 0, 0}, /* Output */ {"verbose", optional_argument, 0, 'v'}, {"reduce-verbosity", optional_argument, 0, 'q'}, {"debug", no_argument, 0, 0}, {"quiet", no_argument, 0, 0}, {0, 0, 0, 0} }; if( argc <= 1 ){ this->printUsage(); exit(1); } /* Let's get this parsing party started */ while((arg = getopt_long_only(argc,argv,"46c:d::e:fg:hHK:NP:q::p:S:Vv::", long_options, &option_index)) != EOF) { aux8=aux16=aux32=auxinaddr.s_addr=0; aux_ip4.reset(); switch(arg) { case 0: /* PROBE MODES ***************************************************************/ if (optcmp(long_options[option_index].name, "tcp-connect") == 0) { o.addMode(DO_TCP_CONNECT); }else if (optcmp(long_options[option_index].name, "tcp") == 0) { o.addMode(DO_TCP); }else if (optcmp(long_options[option_index].name, "udp") == 0) { o.addMode(DO_UDP); }else if (optcmp(long_options[option_index].name, "udp-unpriv") == 0) { o.addMode(DO_UDP_UNPRIV); }else if (optcmp(long_options[option_index].name, "icmp") == 0) { o.addMode(DO_ICMP); }else if (optcmp(long_options[option_index].name, "arp") == 0) { o.addMode(DO_ARP); }else if (optcmp(long_options[option_index].name, "traceroute") == 0 || optcmp(long_options[option_index].name, "tr") == 0) { o.addMode(DO_TRACEROUTE); /* TCP/UDP OPTIONS ***********************************************************/ /* TCP Sequence number */ } else if (optcmp(long_options[option_index].name, "seq") == 0) { if ( parse_u32(optarg, &aux32) != OP_SUCCESS ) nping_fatal(QT_3, "Invalid TCP Sequence number. Value must be 0<=N<2^32."); else o.tcp.seq.setConstant(aux32); /* TCP Flags */ }else if (optcmp(long_options[option_index].name, "flags") == 0) { /* CASE 1: User is a freak and supplied a numeric value directly */ /* We initially parse it as an u32 so we give the proper error * for values like 0x100. */ if ( parse_u32(optarg, &aux32) == OP_SUCCESS ){ if( meansRandom(optarg) ){ o.tcp.flags.setConstant(get_random_u8()); }else if(aux32>255){ nping_fatal(QT_3, "Invalid TCP flag specification. Numerical values must be in the range [0,255]."); }else{ o.tcp.flags.setConstant((u8)aux32); } /* CASE 2: User supplied a list of flags in the format "syn,ack,ecn" */ }else if( contains(optarg, ",") ){ if( ((strlen(optarg)+1)%4) !=0 ) nping_fatal(QT_3, "Invalid format in --flag. Make sure you specify a comma-separed list that contains 3-charater flag names (e.g: --flags syn,ack,psh)"); aux8=0; for(size_t f=0; f< strlen(optarg); f+=4 ){ if( !strncasecmp((optarg+f), "CWR",3)){ aux8 = aux8 | 0x80; } else if(!strncasecmp((optarg+f), "ECN",3)){ aux8 = aux8 | 0x40; } else if(!strncasecmp((optarg+f), "ECE",3)){ aux8 = aux8 | 0x40; } else if(!strncasecmp((optarg+f), "URG",3)){ aux8 = aux8 | 0x20; } else if(!strncasecmp((optarg+f), "ACK",3)){ aux8 = aux8 | 0x10; } else if(!strncasecmp((optarg+f), "PSH",3)){ aux8 = aux8 | 0x08; } else if(!strncasecmp((optarg+f), "RST",3)){ aux8 = aux8 | 0x04; } else if(!strncasecmp((optarg+f), "SYN",3)){ aux8 = aux8 | 0x02; } else if(!strncasecmp((optarg+f), "FIN",3)){ aux8 = aux8 | 0x01; } else if(!strncasecmp((optarg+f), "ALL",3)){ aux8=0xFF; } else if(!strncasecmp((optarg+f), "NIL",3)){ aux8=0x00; } else{ char wrongopt[4]; memcpy(wrongopt, (optarg+f), 3); wrongopt[3]='\0'; nping_fatal(QT_3, "Invalid TCP flag specification: \"%s\"", wrongopt); } } o.tcp.flags.setConstant(aux8); /* CASE 3: User supplied flag initials in format "XYZ..." */ }else{ bool flag3_ok=false; /* SPECIAL CASE: User entered exactly 3 chars so we don't know if * only one flag was entered or three flags in format "XYZ..." */ if( strlen(optarg) == 3 ){ if( !strcasecmp(optarg, "CWR")){ o.tcp.flags.setConstant(0x80); flag3_ok=true; } else if(!strcasecmp(optarg, "ECN")){ o.tcp.flags.setConstant(0x40); flag3_ok=true; } else if(!strcasecmp(optarg, "ECE")){ o.tcp.flags.setConstant(0x40); flag3_ok=true; } else if(!strcasecmp(optarg, "URG")){ o.tcp.flags.setConstant(0x20); flag3_ok=true; } else if(!strcasecmp(optarg, "ACK")){ o.tcp.flags.setConstant(0x10); flag3_ok=true; } else if(!strcasecmp(optarg, "PSH")){ o.tcp.flags.setConstant(0x08); flag3_ok=true; } else if(!strcasecmp(optarg, "RST")){ o.tcp.flags.setConstant(0x04); flag3_ok=true; } else if(!strcasecmp(optarg, "SYN")){ o.tcp.flags.setConstant(0x02); flag3_ok=true; } else if(!strcasecmp(optarg, "FIN")){ o.tcp.flags.setConstant(0x01); flag3_ok=true; } else if(!strcasecmp(optarg, "ALL")){ o.tcp.flags.setConstant(0xFF); flag3_ok=true; } else if(!strcasecmp(optarg, "NIL")){ o.tcp.flags.setConstant(0x00); flag3_ok=true; } else{ flag3_ok=false; } /* SPECIAL CASE: User supplied an empty string */ }else if( strlen(optarg) == 0 ){ o.tcp.flags.setConstant(0x00); /* SPECIAL CASE: User supplied special flag "NONE" */ }else if(!strcasecmp(optarg, "NONE") ){ o.tcp.flags.setConstant(0x00); flag3_ok=true; } /* User definitely supplied flag initials in format "XYZ..."*/ if(flag3_ok==false){ aux8=0; for(size_t f=0; fparseICMPTimestamp(optarg, &aux32); o.icmp4.ts_orig.setConstant(aux32); /* ICMP Timestamp receive timestamp */ } else if (optcmp(long_options[option_index].name, "icmp-recv-time") == 0) { o.addMode(DO_ICMP); this->parseICMPTimestamp(optarg, &aux32); o.icmp4.ts_rx.setConstant(aux32); /* ICMP Timestamp trasnmit timestamp */ } else if (optcmp(long_options[option_index].name, "icmp-trans-time") == 0) { o.addMode(DO_ICMP); this->parseICMPTimestamp(optarg, &aux32); o.icmp4.ts_tx.setConstant(aux32); /* ICMP Netmask */ } else if (optcmp(long_options[option_index].name, "icmp-mask") == 0) { o.addMode(DO_ICMP); if(meansRandom(optarg)){ o.icmp4.mask.setBehavior(FIELD_TYPE_RANDOM); }else{ if(aux_ip4.setIPv4Address(optarg) != OP_SUCCESS){ nping_fatal(QT_3, "Could not resolve specified ICMP netmask."); }else{ o.icmp4.mask.setConstant(aux_ip4.getIPv4Address()); } } /* TODO: Add more relevant flags for different ICMP options */ /* ICMPv6 OPTIONS ************************************************************/ /* ICMP Type */ } else if (optcmp(long_options[option_index].name, "icmp6-type") == 0) { o.addMode(DO_ICMP); /* User may have supplied type as a number */ if(parse_u8(optarg, &aux8) == OP_SUCCESS){ o.icmp6.type.setConstant(aux8); /* Or maybe the supplied arg is a string that we can recognize */ }else if(atoICMPv6Type(optarg, &aux8) == OP_SUCCESS){ o.icmp6.type.setConstant(aux8); /* Looks like user supplied a bogus value */ }else{ nping_fatal(QT_3, "Invalid ICMPv6 Type. Value must be 0<=N<=255."); } /* Warn if ICMP Type is not RFC-compliant */ // TODO @todo implement the isICMPv6Type() function so we can dispaly the warning //if( !isICMPv6Type(aux8) ) // nping_warning(QT_1, "Warning: Specified ICMPv6 type (%d) is not RFC compliant.", aux8); /* ICMP Code */ } else if (optcmp(long_options[option_index].name, "icmp6-code") == 0) { o.addMode(DO_ICMP); /* User may have supplied code as a number */ if(parse_u8(optarg, &aux8) == OP_SUCCESS){ o.icmp6.code.setConstant(aux8); /* Or maybe the supplied arg is a string that we can recognize */ }else if(atoICMPv6Code(optarg, &aux8) == OP_SUCCESS){ o.icmp6.code.setConstant(aux8); /* Looks like user supplied a bogus value */ }else{ nping_fatal(QT_3, "Invalid ICMPv6 Code. Value must be 0<=N<=255."); } /* ICMP Identification field */ } else if (optcmp(long_options[option_index].name, "icmp6-id") == 0) { o.addMode(DO_ICMP); if(parse_u16(optarg, &aux16) == OP_SUCCESS){ o.icmp6.id.setConstant(aux16); }else{ nping_fatal(QT_3, "Invalid ICMPv6 Identifier. Value must be 0<=N<2^16."); } /* ICMP Sequence number */ } else if (optcmp(long_options[option_index].name, "icmp6-seq") == 0) { o.addMode(DO_ICMP); if(parse_u16(optarg, &aux16) == OP_SUCCESS){ o.icmp6.seq.setConstant(aux16); }else{ nping_fatal(QT_3, "Invalid ICMPv6 Sequence number. Value must be 0<=N<2^16."); } /* ICMPv6 parameter problem pointer */ } else if (optcmp(long_options[option_index].name, "icmp6-param-pointer") == 0) { o.addMode(DO_ICMP); if(parse_u32(optarg, &aux32) == OP_SUCCESS){ o.icmp6.pointer.setConstant(aux32); }else{ nping_fatal(QT_3, "Invalid ICMPv6 Parameter Problem poitner. Value must be 0<=N<2^32."); } /* ICMP Packet Too Big MTU */ } else if (optcmp(long_options[option_index].name, "icmp6-mtu") == 0) { o.addMode(DO_ICMP); if(parse_u32(optarg, &aux32) == OP_SUCCESS){ o.icmp6.mtu.setConstant(aux32); }else{ nping_fatal(QT_3, "Invalid ICMPv6 Packet Too Big MTU. Value must be 0<=N<2^32."); } /* ICMPv6 Router Advertisement Flags */ } else if (optcmp(long_options[option_index].name, "icmp6-ra-flags") == 0) { o.addMode(DO_ICMP); aux8=0; int Rflags=0; /* Check if flags were passed as an integer */ if(parse_u8(optarg, &aux8) == OP_SUCCESS){ o.icmp6.ra_flags.setConstant(aux8); }else{ for(size_t f=0; f8191){ nping_fatal(QT_3, "Fragment offset cannot exceed 8191."); }else{ o.ip4.off.setConstant(aux16); } /* IP checksum */ } else if (optcmp(long_options[option_index].name, "csum-ip") == 0 ){ if(parse_u16(optarg, &aux16)!=OP_SUCCESS){ nping_fatal(QT_3,"The IP checksum must be a number between 0 65535 (inclusive)"); }else{ o.ip4.csum.setConstant(aux16); } /* Set up a bad IP checksum */ } else if (optcmp(long_options[option_index].name, "badsum-ip") == 0 ){ o.ip4.csum.setBehavior(FIELD_TYPE_BADSUM); /* IP Options */ } else if (optcmp(long_options[option_index].name, "ip-options") == 0 ){ /* Here we parse the supplied IP Options. The result is a binary * buffer than can be inserted directly into an IPv4 header. */ int foo=0, bar=0, optslen=0; if((optslen=parse_ip_options(optarg, ipoptsbuff, sizeof(ipoptsbuff), &foo, &bar, errstr, sizeof(errstr))) < 0 ) nping_fatal(QT_3, "Incorrect IP options specification."); else o.ip4.opts.setConstant(ipoptsbuff, optslen); /* Maximum Transmission Unit */ } else if (optcmp(long_options[option_index].name, "mtu") == 0 ){ /* Special treatment for random here since the generated number must be n%8==0 */ if(!strcasecmp("rand", optarg) || !strcasecmp("random", optarg)){ aux16=get_random_u16(); /* We limit the random mtu to a max of 65535 */ /* Make sure generated number is multiple of 8, adding a few units */ if(aux16 > 8 ) aux16-=(aux16%8); else aux16+=(8-(aux16%8)); o.setMTU(aux16); }else if ( (parse_u32(optarg, &aux32)==OP_SUCCESS) && aux32!=0 && aux32%8==0){ o.setMTU(aux32); }else{ nping_fatal(QT_3,"MTU must be >0 and multiple of 8"); } /* IPv6 OPTIONS **************************************************************/ /* IPv6 Traffic class */ } else if (optcmp(long_options[option_index].name, "traffic-class") == 0 || optcmp(long_options[option_index].name, "tc") == 0 ){ if(parse_u8(optarg, &aux8) == OP_SUCCESS){ o.ip6.tclass.setConstant(aux8); }else{ nping_fatal(QT_3,"IPv6 Traffic Class must be a number between 0 and 255 (inclusive)"); } /* IPv6 Flow label */ } else if (optcmp(long_options[option_index].name, "flow") == 0 ){ if(meansRandom(optarg)){ o.ip6.flow.setConstant(get_random_u32()%1048575); /* Mod 2^20 so it doesn't exceed 20bits */ }else if(parse_u32(optarg, &aux32) == OP_SUCCESS){ if(aux32>1048575){ nping_fatal(QT_3, "IPv6 Flow Label cannot be greater than 1048575 "); }else{ o.ip6.flow.setConstant(aux32); } }else{ nping_fatal(QT_3,"IPv6 Flow Label must be a number between 0 and 1048575"); } /* PACKET PAYLOAD OPTIONS ***************************************************/ /* Hexadecimal payload specification */ } else if (optcmp(long_options[option_index].name, "data") == 0 ){ o.setPayloadType(PL_HEX); u8 *tempbuff=NULL; size_t len=0; if( (tempbuff=parseBufferSpec(optarg, &len))==NULL) nping_fatal(QT_3,"Invalid hex string specification\n"); else{ u8 *buff = (u8 *) safe_malloc(len); memcpy(buff, tempbuff, len); o.setPayloadBuffer(buff, len); } /* Random payload */ } else if (optcmp(long_options[option_index].name, "data-length") == 0 ){ o.setPayloadType(PL_RAND); if( meansRandom(optarg) ){ /* We do not generate more than Ethernet standard MTU */ aux32 = 1 + get_random_u16() % (MAX_RANDOM_PAYLOAD-1); }else if ( parse_u32(optarg, &aux32) != OP_SUCCESS ){ nping_fatal(QT_3,"Invalid payload length specification"); } if ( aux32 > MAX_PAYLOAD_ALLOWED ) nping_fatal(QT_3,"data-length must be a value between 0 and %d.", MAX_PAYLOAD_ALLOWED); if ( aux32 > MAX_RECOMMENDED_PAYLOAD ) nping_print(QT_3, "WARNING: Payload exceeds maximum recommended payload (%d)", MAX_RECOMMENDED_PAYLOAD); /* Allocate a buffer big enough to hold the desired payload */ if( (auxbuff=(u8 *)safe_malloc(aux32)) == NULL ) nping_fatal(QT_3,"Not enough memory to store payload."); /* Generate random data and store the payload */ get_random_bytes(auxbuff, aux32); o.setPayloadBuffer(auxbuff, aux32); /* ASCII string payload */ } else if (optcmp(long_options[option_index].name, "data-string") == 0 ){ o.setPayloadType(PL_STRING); int plen=strlen(optarg); if ( plen>MAX_PAYLOAD_ALLOWED ) nping_fatal(QT_3,"data-string must be between 0 and %d characters.", MAX_PAYLOAD_ALLOWED); if ( plen > MAX_RECOMMENDED_PAYLOAD ) nping_print(QT_3, "WARNING: Payload exceeds maximum recommended payload (%d)", MAX_RECOMMENDED_PAYLOAD); if( meansRandom(optarg) ){ auxbuff=(u8*)strdup(getRandomTextPayload()); plen=strlen((char*)auxbuff); }else { auxbuff=(u8*)safe_zalloc(plen); memcpy(auxbuff, optarg, plen); } o.setPayloadBuffer((u8*)auxbuff, plen); /* ECHO C/S MODE OPTIONS *****************************************************/ } else if (optcmp(long_options[option_index].name, "echo-client")==0 || optcmp(long_options[option_index].name, "ec")==0 ){ o.setRole(ROLE_CLIENT); o.setEchoPassphrase(optarg); } else if (optcmp(long_options[option_index].name, "echo-server")==0 || optcmp(long_options[option_index].name, "es")==0 ){ o.setRole(ROLE_SERVER); o.setEchoPassphrase(optarg); } else if (optcmp(long_options[option_index].name, "echo-port")==0 || optcmp(long_options[option_index].name, "ep")==0 ){ if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){ if(aux16==0) nping_fatal(QT_3, "Invalid echo port. Port can't be zero."); else o.setEchoPort( aux16 ); }else{ nping_fatal(QT_3, "Invalid echo port. Value must be 0= 10 * 1000 && tval_unit(optarg) == NULL) nping_fatal(QT_3,"Since April 2010, the default unit for --delay is seconds, so your time of \"%s\" is %g seconds. Use \"%sms\" for %g milliseconds.", optarg, l / 1000.0, optarg, l / 1000.0); o.setDelay(l); /* Tx rate */ } else if (optcmp(long_options[option_index].name, "rate") == 0 ){ if (parse_u32(optarg, &aux32)==OP_SUCCESS){ if(aux32==0){ nping_fatal(QT_3,"Invalid rate supplied. Rate can never be zero."); }else{ /* Compute delay from rate: delay= 1000ms/rate*/ aux32 = 1000 / aux32; o.setDelay(aux32); } }else{ nping_fatal(QT_3,"Invalid rate supplied. Rate must be a valid, positive integer"); } /* MISC OPTIONS **************************************************************/ /* Use a bad checksum for protocols above the network layer */ } else if (optcmp(long_options[option_index].name, "badsum") == 0) { o.tcp.csum.setBehavior(FIELD_TYPE_BADSUM); o.udp.csum.setBehavior(FIELD_TYPE_BADSUM); o.icmp4.csum.setBehavior(FIELD_TYPE_BADSUM); o.icmp6.csum.setBehavior(FIELD_TYPE_BADSUM); } else if (optcmp(long_options[option_index].name, "csum") == 0 ){ if(parse_u16(optarg, &aux16) == OP_SUCCESS){ o.tcp.csum.setConstant(aux16); o.udp.csum.setConstant(aux16); o.icmp4.csum.setConstant(aux16); o.icmp6.csum.setConstant(aux16); }else{ nping_fatal(QT_3, "Invalid ICMP Identifier. Value must be 0<=N<2^16."); } } else if (optcmp(long_options[option_index].name, "privileged") == 0 ){ o.setIsRoot(); } else if (optcmp(long_options[option_index].name, "unprivileged") == 0 ){ o.setIsRoot(0); } else if (optcmp(long_options[option_index].name, "send-eth") == 0 ){ o.setSendPreference(PACKET_SEND_ETH); } else if (optcmp(long_options[option_index].name, "send-ip") == 0 ){ o.setSendPreference(PACKET_SEND_IP); } else if (optcmp(long_options[option_index].name, "bpf-filter") == 0 || optcmp(long_options[option_index].name, "filter") == 0){ o.setBPFFilterSpec( optarg ); if( o.issetDisablePacketCapture() && o.disablePacketCapture()==true ) nping_warning(QT_2, "Warning: There is no point on specifying a BPF filter if you disable packet capture. BPF filter will be ignored."); } else if (optcmp(long_options[option_index].name, "show-all-stats") == 0 ){ o.setShowAllStats(true); } else if (optcmp(long_options[option_index].name, "show-eth") == 0 ){ o.setShowEth(true); } else if (optcmp(long_options[option_index].name, "nsock-engine") == 0){ if(nsock_set_default_engine(optarg)!=0) nping_fatal(QT_3, "Invalid Nsock Engine. Possible values: %s", nsock_list_engines()); /* Output Options */ } else if (optcmp(long_options[option_index].name, "quiet") == 0 ){ o.setVerbosity(-4); o.setDebugging(0); }else if (optcmp(long_options[option_index].name, "debug") == 0 ){ o.setVerbosity(4); o.setDebugging(9); } /* Copy and paste these to add more options. */ //}else if (optcmp(long_options[option_index].name, "") == 0 ){ //} else if (optcmp(long_options[option_index].name, "") == 0 ){ break; /* case 0 */ /* OPTIONS THAT CAN BE SPECIFIED AS A SINGLE CHARACTER ***********************/ case '4': /* IPv4 */ o.setAddressFamily(AF_INET); break; /* case '4': */ case '6': /* IPv6 */ o.setAddressFamily(AF_INET6); break; /* case '6': */ case 'f': /* Fragment packets */ if( o.issetMTU() == true ){ nping_warning(QT_3,"WARNING: -f is irrelevant if an MTU has been previously specified"); } else{ nping_print(DBG_1, "Setting default MTU=%d", DEFAULT_MTU_FOR_FRAGMENTATION); o.setMTU( DEFAULT_MTU_FOR_FRAGMENTATION ); } break; case 'g': /* Source port */ /* Parse port spec */ spec_to_ports(optarg, &portlist, &auxint); if( portlist == NULL || auxint <= 0 ){ nping_fatal(QT_3,"Invalid source port specification."); }else{ o.setSourcePorts(portlist, auxint); o.tcp.sport.setDiscreteSet(portlist, (u32)auxint); o.udp.sport.setDiscreteSet(portlist, (u32)auxint); } break; /* case 'g': */ case 'p': /* Destination port */ /* Parse port spec */ spec_to_ports(optarg, &portlist, &auxint); if( portlist == NULL || auxint <= 0 ){ nping_fatal(QT_3,"Invalid target ports specification."); }else{ o.setTargetPorts(portlist, auxint); o.tcp.dport.setDiscreteSet(portlist, (u32)auxint); o.udp.dport.setDiscreteSet(portlist, (u32)auxint); } break; /* case 'p': */ case 'S': /* Source/Spoof IP address */ /* IPv6 */ if( o.ipv6() ){ /* Set random address */ if( meansRandom(optarg) ){ struct in6_addr ipv6addr; for(int i6=0; i6<16; i6++) ipv6addr.s6_addr[i6]=get_random_u8(); aux_ip4.setAddress(ipv6addr); o.setSpoofAddress(aux_ip4); } /* Set user supplied address (if we manage to resolve it) */ else{ if(aux_ip4.setIPv6Address(optarg)!=OP_SUCCESS){ nping_fatal(QT_3, "Could not resolve source IPv6 address."); }else{ o.setSpoofAddress(aux_ip4); } } /* IPv4 */ }else{ if( meansRandom(optarg) ){ while ( (auxinaddr.s_addr=get_random_u32()) == 0 ); aux_ip4.setAddress(auxinaddr); o.setSpoofAddress(aux_ip4); }else{ if( aux_ip4.setIPv4Address(optarg)!=OP_SUCCESS){ nping_fatal(QT_3, "Could not resolve source IPv4 address."); }else{ o.setSpoofAddress(aux_ip4); } } } break; /* case 'S': */ case '?': printUsage(); exit(1); break; /* case 'h': */ case 'h': /* Help */ printUsage(); exit(0); break; /* case 'h': */ case 'V': /* Version */ printVersion(); exit(0); break; /* case 'V': */ case 'c': /* Packet rounds */ if( meansRandom(optarg) ){ o.setRounds( get_random_u32()%1024 ); }else if( parse_u32(optarg, &aux32) == OP_SUCCESS ){ o.setRounds(aux32); }else{ nping_fatal(QT_3,"Packet rounds must be an integer greater than 0."); } break; /* case 'c': */ case 'e': /* Network interface */ if(strlen(optarg)==0) nping_fatal(QT_3,"Invalid network interface supplied. Interface name cannot be NULL."); else o.setDevice( strdup(optarg) ); break; /* case 'e': */ case 'N': /* Don't capture packets */ o.setDisablePacketCapture(true); if( o.issetBPFFilterSpec() ) nping_warning(QT_2, "Warning: A custom BPF filter was specified before disabling packet capture. BPF filter will be ignored."); break; /* case 'N': */ case 'H': /* Hide sent packets */ o.setShowSentPackets(false); break; /* case 'H': */ case 'd': /* Debug mode */ if (optarg){ if (isdigit(optarg[0]) || optarg[0]=='-'){ auxint = strtol( optarg, NULL, 10); if ( ((auxint==0) && (optarg[0] != '0')) || auxint<0 || auxint > 9) nping_fatal(QT_3,"Debugging level must be an integer between 0 and 9."); else{ o.setDebugging( auxint ); /* When user specifies a debugging level, if no verbosity was specified, * increase it automatically. If user specified a verbosity level, then leave * it like it was. */ if(o.issetVerbosity()==false) o.setVerbosity( (auxint>4) ? 4 : auxint ); } }else { const char *p; o.increaseVerbosity(); o.increaseDebugging(); for (p = optarg != NULL ? optarg : ""; *p == 'd'; p++){ o.increaseVerbosity(); o.increaseDebugging(); } if (*p != '\0') nping_fatal(QT_3,"Invalid argument to -d: \"%s\".", optarg); } }else{ o.increaseVerbosity(); o.increaseDebugging(); } break; /* case 'd': */ case 'v': /* Verbosity */ if (optarg){ if (isdigit(optarg[0]) || optarg[0]=='-'){ auxint = strtol( optarg, NULL, 10); if ( ((auxint==0) && (optarg[0] != '0')) || auxint<(-4) || auxint > 4) nping_fatal(QT_3,"Verbosity level must be an integer between -4 and +4."); else o.setVerbosity( auxint ); }else { const char *p; o.increaseVerbosity(); for (p = optarg != NULL ? optarg : ""; *p == 'v'; p++) o.increaseVerbosity(); if (*p != '\0') nping_fatal(QT_3,"Invalid argument to -v: \"%s\".", optarg); } }else{ o.increaseVerbosity(); } break; /* case 'v': */ case 'q': /* Reduce verbosity */ if (optarg){ if (isdigit(optarg[0])){ auxint = strtol( optarg, NULL, 10); if ( ((auxint==0) && (optarg[0] != '0')) || auxint<0 || auxint > 4) nping_fatal(QT_3,"You can only reduce verbosity from level 0 to level -4."); else o.setVerbosity( -auxint ); }else { const char *p; o.decreaseVerbosity(); for (p = optarg != NULL ? optarg : ""; *p == 'q'; p++) o.decreaseVerbosity(); if (*p != '\0') nping_fatal(QT_3,"Invalid argument to -q: \"%s\".", optarg); } }else{ o.decreaseVerbosity(); } break; /* case 'q': */ } /* End of switch */ } /* End of getopt while */ /* Now it's time to parse target host specifications. As nmap does, Nping * treats everything getopt() can't parse as a host specification. At this * point, var optind should point to the argv[] position that contains the * first unparsed argument. User may specify multiple target hosts. * */ const char *next_spec=NULL; while ( (next_spec= grab_next_host_spec(NULL, false, argc, (const char **) argv)) != NULL ) o.addTargetSpec(next_spec); return OP_SUCCESS; } /* End of parseArguments() */ /** Prints version information to stdout */ void ArgParser::printVersion(void){ printf("\n%s version %s ( %s )\n", NPING_NAME, NPING_VERSION, NPING_URL); return; } /* End of printVersion() */ /** Prints usage information to stdout */ void ArgParser::printUsage(void){ printf("%s %s ( %s )\n" "Usage: nping [Probe mode] [Options] {target specification}\n" "\n" "TARGET SPECIFICATION:\n" " Targets may be specified as hostnames, IP addresses, networks, etc.\n" " Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.*.1-24\n" "PROBE MODES:\n" " --tcp-connect : Unprivileged TCP connect probe mode.\n" " --tcp : TCP probe mode.\n" " --udp : UDP probe mode.\n" " --icmp : ICMP probe mode.\n" " --arp : ARP/RARP probe mode.\n" " --tr, --traceroute : Traceroute mode (can only be used with \n" " TCP/UDP/ICMP modes).\n" "TCP CONNECT MODE:\n" " -p, --dest-port : Set destination port(s).\n" " -g, --source-port : Try to use a custom source port.\n" "TCP PROBE MODE:\n" " -g, --source-port : Set source port.\n" " -p, --dest-port : Set destination port(s).\n" " --seq : Set sequence number.\n" " --flags : Set TCP flags (ACK,PSH,RST,SYN,FIN...)\n" " --ack : Set ACK number.\n" " --win : Set window size.\n" " --csum : Set a fixed checksum.\n" " --badsum : Use a random invalid checksum. \n" "UDP PROBE MODE:\n" " -g, --source-port : Set source port.\n" " -p, --dest-port : Set destination port(s).\n" " --csum : Set a fixed checksum.\n" " --badsum : Use a random invalid checksum. \n" "ICMP PROBE MODE:\n" " --icmp-type : ICMP type.\n" " --icmp-code : ICMP code.\n" " --icmp-id : Set identifier.\n" " --icmp-seq : Set sequence number.\n" " --icmp-redirect-addr : Set redirect address.\n" " --icmp-param-pointer : Set parameter problem pointer.\n" " --icmp-advert-lifetime