/*************************************************************************** * 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-2019 Insecure.Com LLC ("The Nmap * * Project"). Nmap is also a registered trademark of the Nmap Project. * * 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 ("GPL"), BUT ONLY WITH ALL OF THE * * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. 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@nmap.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 "derivative 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 with any software or content covered by this license * * ("Covered Software"): * * * * o Integrates source code from Covered Software. * * * * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db * * or nmap-service-probes. * * * * o Is designed specifically to execute Covered Software and parse the * * results (as opposed to typical shell or execution-menu apps, which will * * execute anything you tell them to). * * * * o Includes Covered Software in a proprietary executable installer. The * * installers produced by InstallShield are an example of this. Including * * Nmap with other software in compressed or archival form does not * * trigger this provision, provided appropriate open source decompression * * or de-archiving software is widely available for no charge. For the * * purposes of this license, an installer is considered to include Covered * * Software even if it actually retrieves a copy of Covered Software from * * another source during runtime (such as by downloading it from the * * Internet). * * * * o Links (statically or dynamically) to a library which does any of the * * above. * * * * o Executes a helper program, module, or script to do any of the above. * * * * This list is not exclusive, but is meant to clarify our interpretation * * of derived works with some common examples. Other people may interpret * * the plain GPL differently, so we consider this a special exception to * * the GPL that we apply to Covered Software. Works which meet any of * * these conditions must conform to all of the terms of this license, * * particularly including the GPL Section 3 requirements of providing * * source code and allowing free redistribution of the work as a whole. * * * * As another special exception to the GPL terms, the Nmap Project 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. * * * * The Nmap Project has permission to redistribute Npcap, a packet * * capturing driver and library for the Microsoft Windows platform. * * Npcap is a separate work with it's own license rather than this Nmap * * license. Since the Npcap license does not permit redistribution * * without special permission, our Nmap Windows binary packages which * * contain Npcap may not be redistributed without special permission. * * * * Any redistribution of Covered Software, including any derived works, * * must obey and carry forward all of the terms of this license, including * * obeying all GPL rules and restrictions. For example, source code of * * the whole work must be provided and free redistribution must be * * allowed. All GPL references to "this License", are to be treated as * * including the terms and conditions of this license text as well. * * * * Because this license imposes special exceptions to the GPL, Covered * * Work may not be combined (even as part of a larger work) with plain GPL * * software. The terms, conditions, and exceptions of this license must * * be included as well. This license is incompatible with some other open * * source licenses as well. In some cases we can relicense portions of * * Nmap or grant special permissions to use it in other open source * * software. Please contact fyodor@nmap.org with any such requests. * * Similarly, we don't incorporate incompatible open source software into * * Covered Software without special permission from the copyright holders. * * * * If you have any questions about the licensing restrictions on using * * Nmap in other works, we are happy to help. As mentioned above, we also * * offer an 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 support and updates. They also fund the continued * * development of Nmap. Please email sales@nmap.com for further * * information. * * * * If you have received a written license agreement or contract for * * Covered Software stating terms other than these, you may choose to use * * and redistribute Covered Software under those terms instead of these. * * * * 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. * * * * 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 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" 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; struct in_addr aux_ip4; u32 aux32=0; u16 aux16=0; u8 aux8=0; u8 auxmac[6]; u8 *auxbuff=NULL; u16 *portlist=NULL; char errstr[256]; struct option long_options[] = { /* Probe modes */ {"tcp-connect", no_argument, 0, 0}, {"tcp", no_argument, 0, 0}, {"udp", no_argument, 0, 0}, {"icmp", no_argument, 0, 0}, {"arp", no_argument, 0, 0}, {"tr", no_argument, 0, 0}, {"traceroute", no_argument, 0, 0}, /* Mode shortcuts */ {"echo-request", no_argument, 0, 0}, {"destination-unreachable", no_argument, 0, 0}, {"dest-unr", no_argument, 0, 0}, {"timestamp", no_argument, 0, 0}, {"timestamp-request", no_argument, 0, 0}, {"information", no_argument, 0, 0}, {"information-request", no_argument, 0, 0}, {"netmask", no_argument, 0, 0}, {"netmask-request", no_argument, 0, 0}, {"arp-request", no_argument, 0, 0}, {"arp-reply", no_argument, 0, 0}, {"rarp-request", no_argument, 0, 0}, {"rarp-reply", 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}, {"badsum", no_argument, 0, 0}, /* ICMP */ {"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}, /* TODO: Add relevant flags for different ICMP options */ /* ARP/RARP */ /* 1) ARP operation codes. */ {"arp-type", required_argument, 0, 0}, {"rarp-type", required_argument, 0, 0}, {"arp-code", required_argument, 0, 0}, {"rarp-code", required_argument, 0, 0}, {"arp-operation", required_argument, 0, 0}, {"arp-op", required_argument, 0, 0}, {"rarp-operation", required_argument, 0, 0}, {"rarp-op", required_argument, 0, 0}, /* 2) Rest of the fields */ {"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}, {"rarp-sender-mac", required_argument, 0, 0}, {"rarp-sender-ip", required_argument, 0, 0}, {"rarp-target-mac", required_argument, 0, 0}, {"rarp-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}, /* 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}, {"df", no_argument, 0, 0}, {"mf", no_argument, 0, 0}, {"ttl", 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'}, /* 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=aux_ip4.s_addr=0; switch(arg) { case 0: /* PROBE MODES ***************************************************************/ if (strcmp(long_options[option_index].name, "tcp-connect") == 0) { if( o.issetMode() && o.getMode()!=TCP_CONNECT) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(TCP_CONNECT) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(TCP_CONNECT); } else if (strcmp(long_options[option_index].name, "tcp") == 0) { if( o.issetMode() && o.getMode()!=TCP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(TCP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(TCP); } else if (strcmp(long_options[option_index].name, "udp") == 0) { if( o.issetMode() && o.getMode()!=UDP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(UDP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(UDP); } else if (strcmp(long_options[option_index].name, "icmp") == 0) { if( o.issetMode() && o.getMode()!=ICMP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(ICMP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(ICMP); } else if (strcmp(long_options[option_index].name, "arp") == 0) { if( o.issetMode() && o.getMode()!=ARP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(ARP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(ARP); } else if (strcmp(long_options[option_index].name, "traceroute") == 0 || strcmp(long_options[option_index].name, "tr") == 0) { o.enableTraceroute(); /* Now shortcuts that we support but that are not actual modes */ } else if (strcmp(long_options[option_index].name, "arp-request") == 0) { if( o.issetMode() && o.getMode()!=ARP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(ARP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(ARP); o.setARPOpCode(OP_ARP_REQUEST); } else if (strcmp(long_options[option_index].name, "arp-reply") == 0) { if( o.issetMode() && o.getMode()!=ARP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(ARP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(ARP); o.setARPOpCode(OP_ARP_REPLY); } else if (strcmp(long_options[option_index].name, "rarp-request") == 0) { if( o.issetMode() && o.getMode()!=ARP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(ARP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(ARP); o.setARPOpCode(OP_RARP_REQUEST); } else if (strcmp(long_options[option_index].name, "rarp-reply") == 0) { if( o.issetMode() && o.getMode()!=ARP) nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.", strdup( o.mode2Ascii(ARP) ), strdup( o.mode2Ascii(o.getMode()) ) ); o.setMode(ARP); o.setARPOpCode(OP_RARP_REPLY); } else if (strcmp(long_options[option_index].name, "destination-unreachable") == 0 || strcmp(long_options[option_index].name, "dest-unr") == 0) { if ( o.issetMode() && o.getMode() != ICMP ) nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Destination unreachable messages.", o.mode2Ascii(o.getMode())); o.setMode(ICMP); o.setICMPType( ICMP_UNREACH ); } else if( strcmp(long_options[option_index].name, "echo-request") == 0) { if ( o.issetMode() && o.getMode() != ICMP ) nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Echo request messages.", o.mode2Ascii(o.getMode())); o.setMode(ICMP); o.setICMPType( ICMP_ECHO ); } else if (strcmp(long_options[option_index].name, "timestamp") == 0 || strcmp(long_options[option_index].name, "timestamp-request") == 0) { if ( o.issetMode() && o.getMode() != ICMP ) nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Timestamp request messages.", o.mode2Ascii(o.getMode())); o.setMode(ICMP); o.setICMPType( ICMP_TSTAMP ); } else if (strcmp(long_options[option_index].name, "information") == 0 || strcmp(long_options[option_index].name, "information-request") == 0 ) { if ( o.issetMode() && o.getMode() != ICMP ) nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Information request messages.", o.mode2Ascii(o.getMode())); o.setMode(ICMP); o.setICMPType( ICMP_TSTAMP ); } else if (strcmp(long_options[option_index].name, "netmask") == 0 || strcmp(long_options[option_index].name, "netmask-request") == 0) { if ( o.issetMode() && o.getMode() != ICMP ) nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Information request messages.", o.mode2Ascii(o.getMode())); o.setMode(ICMP); o.setICMPType( ICMP_MASK ); /* TCP/UDP OPTIONS ***********************************************************/ /* TCP Sequence number */ } else if (strcmp(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.setTCPSequence( aux32 ); /* TCP Flags */ } else if (strcmp(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) ){ aux8=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{ aux8=(u8)aux32; } if(aux8==0){ o.unsetAllFlagsTCP(); }else{ if( aux8 & 0x80 ) o.setFlagTCP( FLAG_CWR ); if( aux8 & 0x40 ) o.setFlagTCP( FLAG_ECN ); if( aux8 & 0x20 ) o.setFlagTCP( FLAG_URG ); if( aux8 & 0x10 ) o.setFlagTCP( FLAG_ACK ); if( aux8 & 0x08 ) o.setFlagTCP( FLAG_PSH ); if( aux8 & 0x04 ) o.setFlagTCP( FLAG_RST ); if( aux8 & 0x02 ) o.setFlagTCP( FLAG_SYN ); if( aux8 & 0x01 ) o.setFlagTCP( FLAG_FIN ); } /* 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-separated list that contains 3-character flag names (e.g: --flags syn,ack,psh)"); for( size_t f=0; f< strlen(optarg); f+=4 ){ if(!strncasecmp((optarg+f), "CWR",3)){ o.setFlagTCP(FLAG_CWR); } else if(!strncasecmp((optarg+f), "ECN",3)){ o.setFlagTCP(FLAG_ECN); } else if(!strncasecmp((optarg+f), "ECE",3)){ o.setFlagTCP(FLAG_ECN); } else if(!strncasecmp((optarg+f), "URG",3)){ o.setFlagTCP(FLAG_URG); } else if(!strncasecmp((optarg+f), "ACK",3)){ o.setFlagTCP(FLAG_ACK); } else if(!strncasecmp((optarg+f), "PSH",3)){ o.setFlagTCP(FLAG_PSH); } else if(!strncasecmp((optarg+f), "RST",3)){ o.setFlagTCP(FLAG_RST); } else if(!strncasecmp((optarg+f), "SYN",3)){ o.setFlagTCP(FLAG_SYN); } else if(!strncasecmp((optarg+f), "FIN",3)){ o.setFlagTCP(FLAG_FIN); } else if(!strncasecmp((optarg+f), "ALL",3)){ o.setAllFlagsTCP(); } else if(!strncasecmp((optarg+f), "NIL",3)){ o.unsetAllFlagsTCP(); } else{ char wrongopt[4]; memcpy(wrongopt, (optarg+f), 3); wrongopt[3]='\0'; nping_fatal(QT_3, "Invalid TCP flag specification: \"%s\"", wrongopt); } } /* 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.setFlagTCP(FLAG_CWR); flag3_ok=true; } else if(!strcasecmp(optarg, "ECN")){ o.setFlagTCP(FLAG_ECN); flag3_ok=true; } else if(!strcasecmp(optarg, "ECE")){ o.setFlagTCP(FLAG_ECN); flag3_ok=true; } else if(!strcasecmp(optarg, "URG")){ o.setFlagTCP(FLAG_URG); flag3_ok=true; } else if(!strcasecmp(optarg, "ACK")){ o.setFlagTCP(FLAG_ACK); flag3_ok=true; } else if(!strcasecmp(optarg, "PSH")){ o.setFlagTCP(FLAG_PSH); flag3_ok=true; } else if(!strcasecmp(optarg, "RST")){ o.setFlagTCP(FLAG_RST); flag3_ok=true; } else if(!strcasecmp(optarg, "SYN")){ o.setFlagTCP(FLAG_SYN); flag3_ok=true; } else if(!strcasecmp(optarg, "FIN")){ o.setFlagTCP(FLAG_FIN); flag3_ok=true; } else if(!strcasecmp(optarg, "ALL")){ o.setAllFlagsTCP(); flag3_ok=true; } else if(!strcasecmp(optarg, "NIL")){ o.unsetAllFlagsTCP(); flag3_ok=true; } else{ flag3_ok=false; } }else if( strlen(optarg) == 0 ){ o.unsetAllFlagsTCP(); } /* SPECIAL CASE: User supplied special flag "NONE" */ if(!strcasecmp(optarg, "NONE") ){ o.unsetAllFlagsTCP(); flag3_ok=true; } /* User definitely supplied flag initials in format "XYZ..."*/ if( flag3_ok==false ){ for(size_t f=0; fparseICMPTimestamp(optarg, &aux32); o.setICMPOriginateTimestamp(aux32); /* ICMP Timestamp receive timestamp */ } else if (strcmp(long_options[option_index].name, "icmp-recv-time") == 0) { if ( o.issetMode() && o.getMode() != ICMP ) nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode())); this->parseICMPTimestamp(optarg, &aux32); o.setICMPReceiveTimestamp(aux32); /* ICMP Timestamp transmit timestamp */ } else if (strcmp(long_options[option_index].name, "icmp-trans-time") == 0) { if ( o.issetMode() && o.getMode() != ICMP ) nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode())); this->parseICMPTimestamp(optarg, &aux32); o.setICMPTransmitTimestamp(aux32); /* TODO: Add more relevant flags for different ICMP options */ /* ARP/RARP OPTIONS **********************************************************/ /* Operation code */ } else if (strcmp(long_options[option_index].name, "arp-type") == 0 || strcmp(long_options[option_index].name, "rarp-type") == 0 || strcmp(long_options[option_index].name, "arp-code") == 0 || strcmp(long_options[option_index].name, "rarp-code") == 0 || strcmp(long_options[option_index].name, "arp-operation") == 0 || strcmp(long_options[option_index].name, "arp-op") == 0 || strcmp(long_options[option_index].name, "rarp-operation") == 0 || strcmp(long_options[option_index].name, "rarp-op") == 0 ){ if ( o.issetMode() && o.getMode() != ARP ){ nping_fatal(QT_3,"You cannot specify mode %s if you want to send ARP messages.", o.mode2Ascii(o.getMode())); }else if( !o.issetMode() ){ o.setMode(ARP); } if( atoARPOpCode(optarg, &aux16) != OP_SUCCESS ){ nping_fatal(QT_3, "Invalid ARP type/operation code"); }else{ o.setARPOpCode(aux16); } /* ARP Sender MAC Address */ } else if (strcmp(long_options[option_index].name, "arp-sender-mac") == 0 || strcmp(long_options[option_index].name, "rarp-sender-mac") == 0 ){ if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){ nping_fatal(QT_3, "Invalid ARP Sender MAC address."); }else{ o.setARPSenderHwAddr(auxmac); } /* ARP Sender IP Address */ } else if (strcmp(long_options[option_index].name, "arp-sender-ip") == 0 || strcmp(long_options[option_index].name, "rarp-sender-ip") == 0 ){ if ( atoIP(optarg, &aux_ip4)!=OP_SUCCESS ){ nping_fatal(QT_3, "Invalid ARP Sender IP address."); }else{ o.setARPSenderProtoAddr(aux_ip4); } /* ARP Target MAC Address */ } else if (strcmp(long_options[option_index].name, "arp-target-mac") == 0 || strcmp(long_options[option_index].name, "rarp-target-mac") == 0 ){ if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){ nping_fatal(QT_3, "Invalid ARP Target MAC address."); }else{ o.setARPTargetHwAddr(auxmac); } /* ARP Target IP Address */ } else if (strcmp(long_options[option_index].name, "arp-target-ip") == 0 || strcmp(long_options[option_index].name, "rarp-target-ip") == 0 ){ if ( atoIP(optarg, &aux_ip4)!=OP_SUCCESS ){ nping_fatal(QT_3, "Invalid ARP Target IP address."); }else{ o.setARPTargetProtoAddr(aux_ip4); } /* ETHERNET OPTIONS **********************************************************/ /* Destination MAC address */ } else if (strcmp(long_options[option_index].name, "dest-mac") == 0 ){ if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){ nping_fatal(QT_3, "Invalid Ethernet Destination MAC address."); }else{ o.setDestMAC(auxmac); } if( !o.issetSendPreference() ) o.setSendPreference(PACKET_SEND_ETH_STRONG); /* Source MAC address */ } else if (strcmp(long_options[option_index].name, "source-mac") == 0 || strcmp(long_options[option_index].name, "spoof-mac") == 0 ){ if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){ nping_fatal(QT_3, "Invalid Ethernet Source MAC address."); }else{ o.setSourceMAC(auxmac); } if( !o.issetSendPreference() ) o.setSendPreference(PACKET_SEND_ETH_STRONG); /* Ethernet type field */ } else if (strcmp(long_options[option_index].name, "ethertype") == 0 || strcmp(long_options[option_index].name, "ethtype") == 0 || strcmp(long_options[option_index].name, "ether-type") == 0 ){ if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){ o.setEtherType(aux16); }else if ( atoEtherType(optarg, &aux16) == OP_SUCCESS ){ o.setEtherType(aux16); }else{ nping_fatal(QT_3, "Invalid Ethernet Type."); } if( !o.issetSendPreference() ) o.setSendPreference(PACKET_SEND_ETH_STRONG); /* IPv4 OPTIONS **************************************************************/ /* Destination IP address. This is just another way to specify targets, * provided for consistency with the rest of the parameters. */ } else if (strcmp(long_options[option_index].name, "dest-ip") == 0 ){ o.targets.addSpec( strdup(optarg) ); /* IP Type of service*/ } else if (strcmp(long_options[option_index].name, "tos") == 0 ){ if ( parse_u8(optarg, &aux8) == OP_SUCCESS ){ o.setTOS(aux8); }else{ nping_fatal(QT_3,"TOS option must be a number between 0 and 255 (inclusive)"); } /* IP Identification field */ } else if (strcmp(long_options[option_index].name, "id") == 0 ){ if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){ o.setIdentification(aux16); }else{ nping_fatal(QT_3,"Identification must be a number between 0 and 65535 (inclusive)"); } /* Don't fragment bit */ } else if (strcmp(long_options[option_index].name, "df") == 0 ){ o.setDF(); /* More fragments bit */ } else if (strcmp(long_options[option_index].name, "mf") == 0 ){ o.setMF(); /* Time to live (hop-limit in IPv6) */ } else if (strcmp(long_options[option_index].name, "ttl") == 0 || strcmp(long_options[option_index].name, "hop-limit") == 0 ){ /* IPv6 TTL field is named "hop limit" but has exactly the same * function as in IPv4 so handling of that option should be the * same in both versions. */ if ( parse_u8(optarg, &aux8) == OP_SUCCESS ){ o.setTTL(aux8); }else{ nping_fatal(QT_3,"%s option must be a number between 0 and 255 (inclusive)", strcmp(long_options[option_index].name, "ttl")==0 ? "TTL" : "Hop Limit" ); } /* TODO: At some point we may want to let users specify TTLs like "linux", * "bsd" etc, so the default TTL for those systems is used. Check * http://members.cox.net/~ndav1/self_published/TTL_values.html * for more information */ /* Set up a bad IP checksum */ } else if (strcmp(long_options[option_index].name, "badsum-ip") == 0 ){ o.enableBadsumIP(); /* IP Options */ } else if (strcmp(long_options[option_index].name, "ip-options") == 0 ){ /* We need to know if options specification is correct so we perform * a little test here, instead of waiting until the IPv4Header * complains and fatal()s we just call parse_ip_options() ourselves. * The call should fatal if something is wrong with user-supplied opts */ int foo=0, bar=0; u8 buffer[128]; if( parse_ip_options(optarg, buffer, 128, &foo, &bar, errstr, sizeof(errstr)) < 0 ) nping_fatal(QT_3, "Incorrect IP options specification."); /* If we get here it's safe to store the options */ o.setIPOptions( optarg ); /* Maximum Transmission Unit */ } else if (strcmp(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 (strcmp(long_options[option_index].name, "traffic-class") == 0 || strcmp(long_options[option_index].name, "tc") == 0 ){ if ( parse_u8(optarg, &aux8) == OP_SUCCESS ) o.setTrafficClass(aux8); else nping_fatal(QT_3,"IPv6 Traffic Class must be a number between 0 and 255 (inclusive)"); /* IPv6 Flow label */ } else if (strcmp(long_options[option_index].name, "flow") == 0 ){ if( meansRandom(optarg) ){ o.setFlowLabel( 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.setFlowLabel(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 (strcmp(long_options[option_index].name, "data") == 0 ){ 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); o.setPayloadType(PL_HEX); } /* Random payload */ } else if (strcmp(long_options[option_index].name, "data-length") == 0 ){ if( o.issetPayloadType() != false ) nping_fatal(QT_3,"Only one type of payload may be selected."); 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); o.setPayloadType(PL_RAND); /* 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 (strcmp(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 (strcmp(long_options[option_index].name, "echo-client")==0 || strcmp(long_options[option_index].name, "ec")==0 ){ o.setRoleClient(); o.setEchoPassphrase(optarg); } else if (strcmp(long_options[option_index].name, "echo-server")==0 || strcmp(long_options[option_index].name, "es")==0 ){ o.setRoleServer(); o.setEchoPassphrase(optarg); } else if (strcmp(long_options[option_index].name, "echo-port")==0 || strcmp(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 (strcmp(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 **************************************************************/ } else if (strcmp(long_options[option_index].name, "privileged") == 0 ){ o.setIsRoot(); } else if (strcmp(long_options[option_index].name, "unprivileged") == 0 ){ o.setIsRoot(0); } else if (strcmp(long_options[option_index].name, "send-eth") == 0 ){ o.setSendPreference(PACKET_SEND_ETH_STRONG); } else if (strcmp(long_options[option_index].name, "send-ip") == 0 ){ o.setSendPreference(PACKET_SEND_IP_STRONG); } else if (strcmp(long_options[option_index].name, "bpf-filter") == 0 || strcmp(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 (strcmp(long_options[option_index].name, "nsock-engine") == 0){ if (nsock_set_default_engine(optarg) < 0) nping_fatal(QT_3, "Unknown or non-available engine: %s", optarg); /* Output Options */ } else if (strcmp(long_options[option_index].name, "quiet") == 0 ){ o.setVerbosity(-4); o.setDebugging(0); }else if (strcmp(long_options[option_index].name, "debug") == 0 ){ o.setVerbosity(4); o.setDebugging(9); } break; /* case 0 */ /* OPTIONS THAT CAN BE SPECIFIED AS A SINGLE CHARACTER ***********************/ case '4': /* IPv4 */ o.setIPVersion(IP_VERSION_4); break; /* case '4': */ case '6': /* IPv6 */ o.setIPVersion(IP_VERSION_6); 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 */ if( o.issetSourcePort() ){ nping_fatal(QT_3,"Cannot specify source port twice."); }else if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){ o.setSourcePort(aux16); if(aux16==0) nping_warning(QT_1, "WARNING: a source port of zero may not work on all systems."); }else{ nping_fatal(QT_3,"Source port must be a number between 0 and 65535 (inclusive)"); } break; /* case 'g': */ case 'p': /* Destination port */ /* Parse port spec */ nping_getpts_simple(optarg, &portlist, &auxint); if( portlist == NULL || auxint <= 0 ){ nping_fatal(QT_3,"Invalid target ports specification."); }else{ o.setTargetPorts(portlist, auxint); } break; /* case 'p': */ case 'S': /* Source IP */ if( o.getIPVersion() == IP_VERSION_6){ struct sockaddr_storage sourceaddr; struct sockaddr_in6 *source6=(struct sockaddr_in6 *)&sourceaddr; memset(&sourceaddr, 0, sizeof(struct sockaddr_storage)); struct in6_addr ipv6addr; /* Set random address */ if( meansRandom(optarg) ){ for(int i6=0; i6<16; i6++) ipv6addr.s6_addr[i6]=get_random_u8(); } /* Set user supplied address (if we manage to resolve it) */ else if ( atoIP(optarg, &sourceaddr, PF_INET6) != OP_SUCCESS){ nping_fatal(QT_3, "Could not resolve source IPv6 address."); }else{ ipv6addr = source6->sin6_addr; } o.setIPv6SourceAddress(ipv6addr); o.setSpoofSource(); } else{ if( meansRandom(optarg) ) while ( (aux_ip4.s_addr=get_random_u32()) == 0 ); else if ( atoIP(optarg, &aux_ip4) != OP_SUCCESS) nping_fatal(QT_3, "Could not resolve source IPv4 address."); o.setIPv4SourceAddress(aux_ip4); o.setSpoofSource(); } 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 count */ if( meansRandom(optarg) ){ o.setPacketCount( get_random_u32()%1024 ); }else if( parse_u32(optarg, &aux32) == OP_SUCCESS ){ o.setPacketCount(aux32); }else{ nping_fatal(QT_3,"Packet count must be an integer greater than or equal to 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 so to * handle this, function grab_next_host_spec() returns the next target * specification available. This function will be called until there are no * more target hosts to parse (returned NULL). Once we have a spec, we use * class NpingTargets, that stores the specs and will provide the targets * through calls to getNextTarget(); * */ const char *next_spec=NULL; while ( (next_spec= grab_next_host_spec(NULL, false, argc, (const char **) argv)) != NULL ) o.targets.addSpec( (char *) 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" " --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" " --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