1 
2 /***************************************************************************
3  * ArgParser.cc -- The ArgParser Class is the one in charge of command line*
4  * argument parsing. Essentially it contains method parseArguments() that  *
5  * takes the usual argc and *argv[] parameters and fills the general       *
6  * NpingOps class with all the information needed for the execution of     *
7  * Nping.                                                                  *
8  *                                                                         *
9  ***********************IMPORTANT NMAP LICENSE TERMS************************
10  *                                                                         *
11  * The Nmap Security Scanner is (C) 1996-2020 Insecure.Com LLC ("The Nmap  *
12  * Project"). Nmap is also a registered trademark of the Nmap Project.     *
13  *                                                                         *
14  * This program is distributed under the terms of the Nmap Public Source   *
15  * License (NPSL). The exact license text applying to a particular Nmap    *
16  * release or source code control revision is contained in the LICENSE     *
17  * file distributed with that version of Nmap or source code control       *
18  * revision. More Nmap copyright/legal information is available from       *
19  * https://nmap.org/book/man-legal.html, and further information on the    *
20  * NPSL license itself can be found at https://nmap.org/npsl. This header  *
21  * summarizes some key points from the Nmap license, but is no substitute  *
22  * for the actual license text.                                            *
23  *                                                                         *
24  * Nmap is generally free for end users to download and use themselves,    *
25  * including commercial use. It is available from https://nmap.org.        *
26  *                                                                         *
27  * The Nmap license generally prohibits companies from using and           *
28  * redistributing Nmap in commercial products, but we sell a special Nmap  *
29  * OEM Edition with a more permissive license and special features for     *
30  * this purpose. See https://nmap.org/oem                                  *
31  *                                                                         *
32  * If you have received a written Nmap license agreement or contract       *
33  * stating terms other than these (such as an Nmap OEM license), you may   *
34  * choose to use and redistribute Nmap under those terms instead.          *
35  *                                                                         *
36  * The official Nmap Windows builds include the Npcap software             *
37  * (https://npcap.org) for packet capture and transmission. It is under    *
38  * separate license terms which forbid redistribution without special      *
39  * permission. So the official Nmap Windows builds may not be              *
40  * redistributed without special permission (such as an Nmap OEM           *
41  * license).                                                               *
42  *                                                                         *
43  * Source is provided to this software because we believe users have a     *
44  * right to know exactly what a program is going to do before they run it. *
45  * This also allows you to audit the software for security holes.          *
46  *                                                                         *
47  * Source code also allows you to port Nmap to new platforms, fix bugs,    *
48  * and add new features.  You are highly encouraged to submit your         *
49  * changes as a Github PR or by email to the dev@nmap.org mailing list     *
50  * for possible incorporation into the main distribution. Unless you       *
51  * specify otherwise, it is understood that you are offering us very       *
52  * broad rights to use your submissions as described in the Nmap Public    *
53  * Source License Contributor Agreement. This is important because we      *
54  * fund the project by selling licenses with various terms, and also       *
55  * because the inability to relicense code has caused devastating          *
56  * problems for other Free Software projects (such as KDE and NASM).       *
57  *                                                                         *
58  * The free version of Nmap is distributed in the hope that it will be     *
59  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of  *
60  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,        *
61  * indemnification and commercial support are all available through the    *
62  * Npcap OEM program--see https://nmap.org/oem.                            *
63  *                                                                         *
64  ***************************************************************************/
65 
66 #include "nping.h"
67 
68 #include "ArgParser.h"
69 #include "NpingOps.h"
70 #include "common.h"
71 #include "nbase.h"
72 #include "utils.h"
73 #include "utils_net.h"
74 #include "output.h"
75 
76 extern NpingOps o;
77 
78 
ArgParser()79 ArgParser::ArgParser() {
80 
81 } /* End of ArgParser constructor */
82 
83 
84 
~ArgParser()85 ArgParser::~ArgParser() {
86 
87 } /* End of ArgParser destructor */
88 
89 
90 
parseArguments(int argc,char * argv[])91 int ArgParser::parseArguments(int argc, char *argv[]) {
92   int arg=0;
93   int auxint=0;
94   long l=0;
95   int option_index=0;
96   struct in_addr aux_ip4;
97   u32 aux32=0;
98   u16 aux16=0;
99   u8 aux8=0;
100   u8 auxmac[6];
101   u8 *auxbuff=NULL;
102   u16 *portlist=NULL;
103   char errstr[256];
104 
105   struct option long_options[] =  {
106 
107   /* Probe modes */
108   {"tcp-connect", no_argument, 0, 0},
109   {"tcp", no_argument, 0, 0},
110   {"udp", no_argument, 0, 0},
111   {"icmp", no_argument, 0, 0},
112   {"arp", no_argument, 0, 0},
113   {"tr", no_argument, 0, 0},
114   {"traceroute", no_argument, 0, 0},
115 
116   /* Mode shortcuts */
117   {"echo-request", no_argument, 0, 0},
118   {"destination-unreachable", no_argument, 0, 0},
119   {"dest-unr", no_argument, 0, 0},
120   {"timestamp", no_argument, 0, 0},
121   {"timestamp-request", no_argument, 0, 0},
122   {"information", no_argument, 0, 0},
123   {"information-request", no_argument, 0, 0},
124   {"netmask", no_argument, 0, 0},
125   {"netmask-request", no_argument, 0, 0},
126   {"arp-request", no_argument, 0, 0},
127   {"arp-reply", no_argument, 0, 0},
128   {"rarp-request", no_argument, 0, 0},
129   {"rarp-reply", no_argument, 0, 0},
130 
131    /* TCP/UDP */
132   {"source-port", required_argument, 0, 'g'},
133   {"dest-port", required_argument, 0, 'p'},
134   {"seq", required_argument, 0, 0},
135   {"flags", required_argument, 0, 0},
136   {"ack", required_argument, 0, 0},
137   {"win", required_argument, 0, 0},
138   {"badsum", no_argument, 0, 0},
139 
140   /* ICMP */
141   {"icmp-type", required_argument, 0, 0},
142   {"icmp-code", required_argument, 0, 0},
143   {"icmp-id", required_argument, 0, 0},
144   {"icmp-seq", required_argument, 0, 0},
145   {"icmp-redirect-addr", required_argument, 0, 0},
146   {"icmp-param-pointer", required_argument, 0, 0},
147   {"icmp-advert-lifetime", required_argument, 0, 0},
148   {"icmp-advert-entry", required_argument, 0, 0},
149   {"icmp-orig-time", required_argument, 0, 0},
150   {"icmp-recv-time", required_argument, 0, 0},
151   {"icmp-trans-time", required_argument, 0, 0},
152   /* TODO: Add relevant flags for different ICMP options */
153 
154   /* ARP/RARP */
155   /* 1) ARP operation codes. */
156   {"arp-type",  required_argument, 0, 0},
157   {"rarp-type",  required_argument, 0, 0},
158   {"arp-code",  required_argument, 0, 0},
159   {"rarp-code",  required_argument, 0, 0},
160   {"arp-operation",  required_argument, 0, 0},
161   {"arp-op",  required_argument, 0, 0},
162   {"rarp-operation",  required_argument, 0, 0},
163   {"rarp-op",  required_argument, 0, 0},
164   /* 2) Rest of the fields */
165   {"arp-sender-mac", required_argument, 0, 0},
166   {"arp-sender-ip", required_argument, 0, 0},
167   {"arp-target-mac", required_argument, 0, 0},
168   {"arp-target-ip", required_argument, 0, 0},
169   {"rarp-sender-mac", required_argument, 0, 0},
170   {"rarp-sender-ip", required_argument, 0, 0},
171   {"rarp-target-mac", required_argument, 0, 0},
172   {"rarp-target-ip", required_argument, 0, 0},
173 
174   /* Ethernet */
175   {"dest-mac", required_argument, 0, 0},
176   {"source-mac", required_argument, 0, 0},
177   {"spoof-mac", required_argument, 0, 0},
178   {"ethertype", required_argument, 0, 0},
179   {"ethtype", required_argument, 0, 0},
180   {"ether-type", required_argument, 0, 0},
181 
182   /* IPv4 */
183   {"IPv4", no_argument, 0, '4'},
184   {"ipv4", no_argument, 0, '4'},
185   {"source-ip", required_argument, 0, 'S'},
186   {"dest-ip", required_argument, 0, 0},
187   {"tos", required_argument, 0, 0},
188   {"id", required_argument, 0, 0},
189   {"df", no_argument, 0, 0},
190   {"mf", no_argument, 0, 0},
191   {"ttl", required_argument, 0, 0},
192   {"badsum-ip", no_argument, 0, 0},
193   {"ip-options", required_argument, 0, 0},
194   {"mtu", required_argument, 0, 0},
195   /* Remember also: "-f" : Fragment packets*/
196 
197   /* IPv6 */
198   {"IPv6", no_argument, 0, '6'},
199   {"ipv6", no_argument, 0, '6'},
200   {"hop-limit", required_argument, 0, 0},
201   {"tc", required_argument, 0, 0},
202   {"traffic-class", required_argument, 0, 0},
203   {"flow", required_argument, 0, 0},
204 
205   /* Payload */
206   {"data", required_argument, 0, 0},
207   {"data-length", required_argument, 0, 0},
208   {"data-string", required_argument, 0, 0},
209 
210   /* Echo client/server */
211   {"echo-client", required_argument, 0, 0},
212   {"ec", required_argument, 0, 0},
213   {"echo-server", required_argument, 0, 0},
214   {"es", required_argument, 0, 0},
215   {"echo-port", required_argument, 0, 0},
216   {"ep", required_argument, 0, 0},
217   {"no-crypto", no_argument, 0, 0},
218   {"nc", no_argument, 0, 0},
219   {"once", no_argument, 0, 0},
220   {"safe-payloads", no_argument, 0, 0},
221   {"include-payloads", no_argument, 0, 0},
222 
223   /* Timing and performance */
224   {"delay", required_argument, 0, 0},
225   {"rate", required_argument, 0, 0},
226 
227   /* Misc */
228   {"help", no_argument, 0, 'h'},
229   {"version", no_argument, 0, 'V'},
230   {"count", required_argument, 0, 'c'},
231   {"interface", required_argument, 0, 'e'},
232   {"privileged", no_argument, 0, 0},
233   {"unprivileged", no_argument, 0, 0},
234   {"send-eth", no_argument, 0, 0},
235   {"send-ip", no_argument, 0, 0},
236   {"bpf-filter", required_argument, 0, 0},
237   {"filter", required_argument, 0, 0},
238   {"nsock-engine", required_argument, 0, 0},
239   {"no-capture", no_argument, 0, 'N'},
240   {"hide-sent", no_argument, 0, 'H'},
241 
242   /* Output */
243   {"verbose", optional_argument, 0, 'v'},
244   {"reduce-verbosity", optional_argument, 0, 'q'},
245   {"debug", no_argument, 0, 0},
246   {"quiet", no_argument, 0, 0},
247   {0, 0, 0, 0}
248   };
249 
250   if( argc <= 1 ){
251     this->printUsage();
252     exit(1);
253   }
254 
255   /* Let's get this parsing party started */
256   while((arg = getopt_long_only(argc,argv,"46c:d::e:fg:hHK:NP:q::p:S:Vv::", long_options, &option_index)) != EOF) {
257 
258    aux8=aux16=aux32=aux_ip4.s_addr=0;
259 
260    switch(arg) {
261 
262    case 0:
263 
264 /* PROBE MODES ***************************************************************/
265     if (strcmp(long_options[option_index].name, "tcp-connect") == 0) {
266         if( o.issetMode() && o.getMode()!=TCP_CONNECT)
267             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
268                    strdup( o.mode2Ascii(TCP_CONNECT) ),  strdup( o.mode2Ascii(o.getMode()) ) );
269         o.setMode(TCP_CONNECT);
270     } else if (strcmp(long_options[option_index].name, "tcp") == 0) {
271         if( o.issetMode() && o.getMode()!=TCP)
272             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
273                    strdup( o.mode2Ascii(TCP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
274         o.setMode(TCP);
275     } else if (strcmp(long_options[option_index].name, "udp") == 0) {
276         if( o.issetMode() && o.getMode()!=UDP)
277             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
278                    strdup( o.mode2Ascii(UDP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
279         o.setMode(UDP);
280     } else if (strcmp(long_options[option_index].name, "icmp") == 0) {
281         if( o.issetMode() && o.getMode()!=ICMP)
282             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
283                    strdup( o.mode2Ascii(ICMP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
284         o.setMode(ICMP);
285     } else if (strcmp(long_options[option_index].name, "arp") == 0) {
286         if( o.issetMode() && o.getMode()!=ARP)
287             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
288                    strdup( o.mode2Ascii(ARP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
289         o.setMode(ARP);
290     } else if (strcmp(long_options[option_index].name, "traceroute") == 0 ||
291                strcmp(long_options[option_index].name, "tr") == 0) {
292         o.enableTraceroute();
293 
294     /* Now shortcuts that we support but that are not actual modes */
295     } else if (strcmp(long_options[option_index].name, "arp-request") == 0) {
296         if( o.issetMode() && o.getMode()!=ARP)
297             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
298                    strdup( o.mode2Ascii(ARP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
299         o.setMode(ARP);
300         o.setARPOpCode(OP_ARP_REQUEST);
301     } else if (strcmp(long_options[option_index].name, "arp-reply") == 0) {
302         if( o.issetMode() && o.getMode()!=ARP)
303             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
304                    strdup( o.mode2Ascii(ARP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
305         o.setMode(ARP);
306         o.setARPOpCode(OP_ARP_REPLY);
307     } else if (strcmp(long_options[option_index].name, "rarp-request") == 0) {
308         if( o.issetMode() && o.getMode()!=ARP)
309             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
310                    strdup( o.mode2Ascii(ARP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
311         o.setMode(ARP);
312         o.setARPOpCode(OP_RARP_REQUEST);
313     } else if (strcmp(long_options[option_index].name, "rarp-reply") == 0) {
314         if( o.issetMode() && o.getMode()!=ARP)
315             nping_fatal(QT_3,"Cannot specify more than one probe mode. Choose either %s or %s.",
316                    strdup( o.mode2Ascii(ARP) ),  strdup( o.mode2Ascii(o.getMode()) ) );
317         o.setMode(ARP);
318         o.setARPOpCode(OP_RARP_REPLY);
319     } else if (strcmp(long_options[option_index].name, "destination-unreachable") == 0 ||
320                strcmp(long_options[option_index].name, "dest-unr") == 0) {
321         if ( o.issetMode() && o.getMode() != ICMP )
322             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Destination unreachable messages.", o.mode2Ascii(o.getMode()));
323         o.setMode(ICMP);
324         o.setICMPType( ICMP_UNREACH );
325     } else if( strcmp(long_options[option_index].name, "echo-request") == 0) {
326         if ( o.issetMode() && o.getMode() != ICMP )
327             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Echo request messages.", o.mode2Ascii(o.getMode()));
328         o.setMode(ICMP);
329         o.setICMPType( ICMP_ECHO );
330     } else if (strcmp(long_options[option_index].name, "timestamp") == 0 ||
331                strcmp(long_options[option_index].name, "timestamp-request") == 0) {
332         if ( o.issetMode() && o.getMode() != ICMP )
333             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Timestamp request messages.", o.mode2Ascii(o.getMode()));
334         o.setMode(ICMP);
335         o.setICMPType( ICMP_TSTAMP );
336     } else if (strcmp(long_options[option_index].name, "information") == 0 ||
337                strcmp(long_options[option_index].name, "information-request") == 0 ) {
338         if ( o.issetMode() && o.getMode() != ICMP )
339             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Information request messages.", o.mode2Ascii(o.getMode()));
340         o.setMode(ICMP);
341         o.setICMPType( ICMP_TSTAMP );
342     } else if (strcmp(long_options[option_index].name, "netmask") == 0 ||
343                strcmp(long_options[option_index].name, "netmask-request") == 0) {
344         if ( o.issetMode() && o.getMode() != ICMP )
345             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP Information request messages.", o.mode2Ascii(o.getMode()));
346         o.setMode(ICMP);
347         o.setICMPType( ICMP_MASK );
348 
349 
350 /* TCP/UDP OPTIONS ***********************************************************/
351     /* TCP Sequence number */
352     } else if (strcmp(long_options[option_index].name, "seq") == 0) {
353         if ( parse_u32(optarg, &aux32) != OP_SUCCESS )
354             nping_fatal(QT_3, "Invalid TCP Sequence number. Value must be 0<=N<2^32.");
355         else
356             o.setTCPSequence( aux32 );
357     /* TCP Flags */
358     } else if (strcmp(long_options[option_index].name, "flags") == 0) {
359         /* CASE 1: User is a freak and supplied a numeric value directly */
360         /* We initially parse it as an u32 so we give the proper error
361          * for values like 0x100. */
362         if ( parse_u32(optarg, &aux32) == OP_SUCCESS ){
363             if( meansRandom(optarg) ){
364                 aux8=get_random_u8();
365             }else if(aux32>255){
366                 nping_fatal(QT_3, "Invalid TCP flag specification. Numerical values must be in the range [0,255].");
367             }else{
368                 aux8=(u8)aux32;
369             }
370             if(aux8==0){
371                 o.unsetAllFlagsTCP();
372             }else{
373                 if( aux8 & 0x80 )
374                     o.setFlagTCP( FLAG_CWR );
375                 if( aux8 & 0x40 )
376                     o.setFlagTCP( FLAG_ECN );
377                 if( aux8 & 0x20 )
378                     o.setFlagTCP( FLAG_URG );
379                 if( aux8 & 0x10 )
380                     o.setFlagTCP( FLAG_ACK );
381                 if( aux8 & 0x08 )
382                     o.setFlagTCP( FLAG_PSH );
383                 if( aux8 & 0x04 )
384                     o.setFlagTCP( FLAG_RST );
385                 if( aux8 & 0x02 )
386                     o.setFlagTCP( FLAG_SYN );
387                 if( aux8 & 0x01 )
388                     o.setFlagTCP( FLAG_FIN );
389             }
390         /* CASE 2: User supplied a list of flags in the format "syn,ack,ecn" */
391         }else if( contains(optarg, ",") ){
392             if( ((strlen(optarg)+1)%4)  !=0 )
393                 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)");
394 
395             for( size_t f=0; f< strlen(optarg); f+=4 ){
396                 if(!strncasecmp((optarg+f), "CWR",3)){ o.setFlagTCP(FLAG_CWR);  }
397                 else if(!strncasecmp((optarg+f), "ECN",3)){ o.setFlagTCP(FLAG_ECN);  }
398                 else if(!strncasecmp((optarg+f), "ECE",3)){ o.setFlagTCP(FLAG_ECN);  }
399                 else if(!strncasecmp((optarg+f), "URG",3)){ o.setFlagTCP(FLAG_URG);  }
400                 else if(!strncasecmp((optarg+f), "ACK",3)){ o.setFlagTCP(FLAG_ACK);  }
401                 else if(!strncasecmp((optarg+f), "PSH",3)){ o.setFlagTCP(FLAG_PSH);  }
402                 else if(!strncasecmp((optarg+f), "RST",3)){ o.setFlagTCP(FLAG_RST);  }
403                 else if(!strncasecmp((optarg+f), "SYN",3)){ o.setFlagTCP(FLAG_SYN);  }
404                 else if(!strncasecmp((optarg+f), "FIN",3)){ o.setFlagTCP(FLAG_FIN);  }
405                 else if(!strncasecmp((optarg+f), "ALL",3)){ o.setAllFlagsTCP();  }
406                 else if(!strncasecmp((optarg+f), "NIL",3)){ o.unsetAllFlagsTCP();  }
407                 else{
408                  char wrongopt[4];
409                  memcpy(wrongopt, (optarg+f), 3);
410                  wrongopt[3]='\0';
411                  nping_fatal(QT_3, "Invalid TCP flag specification: \"%s\"", wrongopt);
412                 }
413             }
414 
415         /* CASE 3: User supplied flag initials in format "XYZ..."  */
416         }else{
417             bool flag3_ok=false;
418             /* SPECIAL CASE: User entered exactly 3 chars so we don't know if
419              * only one flag was entered or three flags in format "XYZ..." */
420             if( strlen(optarg) == 3 ){
421                 if(!strcasecmp(optarg, "CWR")){ o.setFlagTCP(FLAG_CWR); flag3_ok=true; }
422                 else if(!strcasecmp(optarg, "ECN")){ o.setFlagTCP(FLAG_ECN); flag3_ok=true; }
423                 else if(!strcasecmp(optarg, "ECE")){ o.setFlagTCP(FLAG_ECN); flag3_ok=true; }
424                 else if(!strcasecmp(optarg, "URG")){ o.setFlagTCP(FLAG_URG); flag3_ok=true; }
425                 else if(!strcasecmp(optarg, "ACK")){ o.setFlagTCP(FLAG_ACK); flag3_ok=true; }
426                 else if(!strcasecmp(optarg, "PSH")){ o.setFlagTCP(FLAG_PSH); flag3_ok=true; }
427                 else if(!strcasecmp(optarg, "RST")){ o.setFlagTCP(FLAG_RST); flag3_ok=true; }
428                 else if(!strcasecmp(optarg, "SYN")){ o.setFlagTCP(FLAG_SYN); flag3_ok=true; }
429                 else if(!strcasecmp(optarg, "FIN")){ o.setFlagTCP(FLAG_FIN); flag3_ok=true; }
430                 else if(!strcasecmp(optarg, "ALL")){ o.setAllFlagsTCP(); flag3_ok=true; }
431                 else if(!strcasecmp(optarg, "NIL")){ o.unsetAllFlagsTCP(); flag3_ok=true; }
432                 else{
433                  flag3_ok=false;
434                 }
435             }else if( strlen(optarg) == 0 ){
436                 o.unsetAllFlagsTCP();
437             }
438             /* SPECIAL CASE: User supplied special flag "NONE" */
439             if(!strcasecmp(optarg, "NONE") ){ o.unsetAllFlagsTCP(); flag3_ok=true; }
440 
441             /* User definitely supplied flag initials in format "XYZ..."*/
442             if( flag3_ok==false ){
443                 for(size_t f=0; f<strlen(optarg); f++){
444                     switch( optarg[f] ){
445                         case 'C': case 'c': o.setFlagTCP(FLAG_CWR); break;
446                         case 'E': case 'e': o.setFlagTCP(FLAG_ECN); break;
447                         case 'U': case 'u': o.setFlagTCP(FLAG_URG); break;
448                         case 'A': case 'a': o.setFlagTCP(FLAG_ACK); break;
449                         case 'P': case 'p': o.setFlagTCP(FLAG_PSH); break;
450                         case 'R': case 'r': o.setFlagTCP(FLAG_RST); break;
451                         case 'S': case 's': o.setFlagTCP(FLAG_SYN); break;
452                         case 'F': case 'f': o.setFlagTCP(FLAG_FIN); break;
453                         default:
454                             if( isdigit(optarg[f]) )
455                                 nping_fatal(QT_3, "Invalid TCP flag supplied (%c). If you want to specify flags using a number you must add prefix \"0x\"", optarg[f]);
456                             else
457                                 nping_fatal(QT_3, "Invalid TCP flag supplied: %c", optarg[f]);
458 
459                     }
460                 }
461             }
462         }
463     /* TCP Acknowledgement number */
464     } else if (strcmp(long_options[option_index].name, "ack") == 0) {
465         if ( parse_u32(optarg, &aux32) != OP_SUCCESS )
466             nping_fatal(QT_3, "Invalid TCP ACK number. Value must be 0<=N<2^32.");
467         else
468            o.setTCPAck( aux32 );
469     /* TCP Window size */
470     } else if (strcmp(long_options[option_index].name, "win") == 0) {
471         if ( parse_u16(optarg, &aux16) != OP_SUCCESS )
472              nping_fatal(QT_3, "Invalid TCP Window size. Value must be 0<=N<65535.");
473         else
474            o.setTCPWindow( aux16 );
475     /* Set a bad TCP checksum */
476     } else if (strcmp(long_options[option_index].name, "badsum") == 0) {
477         o.enableBadsum();
478 
479 /* ICMP OPTIONS **************************************************************/
480     /* ICMP Type */
481     } else if (strcmp(long_options[option_index].name, "icmp-type") == 0) {
482         if ( o.issetMode() && o.getMode() != ICMP )
483             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
484         /* User may have supplied type as a number */
485         if ( parse_u8(optarg, &aux8) == OP_SUCCESS )
486             o.setICMPType( aux8 );
487         /* Or maybe the supplied arg is a string that we can recognize */
488         else if ( atoICMPType(optarg, &aux8) == OP_SUCCESS )
489             o.setICMPType( aux8 );
490         /* Looks like user supplied a bogus value */
491         else
492            nping_fatal(QT_3, "Invalid ICMP Type. Value must be 0<=N<=255.");
493         /* Warn if ICMP Type is not RFC-compliant */
494         if( !isICMPType(aux8) )
495             nping_warning(QT_1, "Warning: Specified ICMP type (%d) is not RFC compliant.", aux8);
496     /* ICMP Code */
497     } else if (strcmp(long_options[option_index].name, "icmp-code") == 0) {
498         if ( o.issetMode() && o.getMode() != ICMP )
499             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
500         /* User may have supplied code as a number */
501         if ( parse_u8(optarg, &aux8) == OP_SUCCESS )
502             o.setICMPCode( aux8 );
503         /* Or maybe the supplied arg is a string that we can recognize */
504         else if ( atoICMPCode(optarg, &aux8) == OP_SUCCESS )
505             o.setICMPCode( aux8 );
506         /* Looks like user supplied a bogus value */
507         else
508            nping_fatal(QT_3, "Invalid ICMP Code. Value must be 0<=N<=255.");
509     /* ICMP Identification field */
510     } else if (strcmp(long_options[option_index].name, "icmp-id") == 0) {
511         if ( o.issetMode() && o.getMode() != ICMP )
512             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
513         if ( parse_u16(optarg, &aux16) == OP_SUCCESS )
514             o.setICMPIdentifier( aux16 );
515         else
516             nping_fatal(QT_3, "Invalid ICMP Identifier. Value must be 0<=N<2^16.");
517     /* ICMP Sequence number */
518     } else if (strcmp(long_options[option_index].name, "icmp-seq") == 0) {
519         if ( o.issetMode() && o.getMode() != ICMP )
520             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
521         if ( parse_u16(optarg, &aux16) == OP_SUCCESS )
522             o.setICMPSequence( aux16 );
523         else
524             nping_fatal(QT_3, "Invalid ICMP Sequence number. Value must be 0<=N<2^16.");
525     /* ICMP Redirect Address */
526     } else if (strcmp(long_options[option_index].name, "icmp-redirect-addr") == 0) {
527         if ( o.issetMode() && o.getMode() != ICMP )
528             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
529         if( meansRandom(optarg) ){
530             while ( (aux_ip4.s_addr=get_random_u32()) == 0 );
531             o.setICMPRedirectAddress( aux_ip4 );
532         }else{
533              if ( atoIP(optarg, &aux_ip4) != OP_SUCCESS)
534                 nping_fatal(QT_3, "Could not resolve specified ICMP Redirect Address.");
535              else
536                 o.setICMPRedirectAddress( aux_ip4 );
537         }
538     /* ICMP Parameter problem pointer */
539     } else if (strcmp(long_options[option_index].name, "icmp-param-pointer") == 0) {
540         if ( o.issetMode() && o.getMode() != ICMP )
541             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
542         if ( parse_u8(optarg, &aux8) == OP_SUCCESS )
543             o.setICMPParamProblemPointer( aux8 );
544         else
545             nping_fatal(QT_3, "Invalid ICMP Parameter problem pointer. Value must be 0<=N<=255..");
546     /* ICMP Router Advertisement lifetime */
547     } else if (strcmp(long_options[option_index].name, "icmp-advert-lifetime") == 0) {
548         if ( o.issetMode() && o.getMode() != ICMP )
549             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
550         if ( parse_u16(optarg, &aux16) == OP_SUCCESS )
551             o.setICMPRouterAdvLifetime( aux16 );
552         else
553             nping_fatal(QT_3, "Invalid ICMP Router advertisement lifetime. Value must be 0<=N<2^16..");
554     /* ICMP Router Advertisement entry */
555     } else if (strcmp(long_options[option_index].name, "icmp-advert-entry") == 0) {
556         if ( o.issetMode() && o.getMode() != ICMP )
557             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
558         /* Format should be "IPADDR,PREF":  "192.168.10.99,31337" */
559         if( meansRandom(optarg) ){
560             while( (aux_ip4.s_addr=get_random_u32()) == 0);
561             o.addICMPAdvertEntry( aux_ip4, get_random_u32() );
562         }else{
563             struct in_addr aux_addr;
564             u32 aux_pref=0;
565             parseAdvertEntry(optarg, &aux_addr, &aux_pref); /* fatal()s on error */
566             o.addICMPAdvertEntry(aux_addr, aux_pref);
567         }
568     /* ICMP Timestamp originate timestamp */
569     } else if (strcmp(long_options[option_index].name, "icmp-orig-time") == 0) {
570         if ( o.issetMode() && o.getMode() != ICMP )
571             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
572         this->parseICMPTimestamp(optarg, &aux32);
573         o.setICMPOriginateTimestamp(aux32);
574     /* ICMP Timestamp receive timestamp */
575     } else if (strcmp(long_options[option_index].name, "icmp-recv-time") == 0) {
576         if ( o.issetMode() && o.getMode() != ICMP )
577             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
578         this->parseICMPTimestamp(optarg, &aux32);
579         o.setICMPReceiveTimestamp(aux32);
580     /* ICMP Timestamp transmit timestamp */
581     } else if (strcmp(long_options[option_index].name, "icmp-trans-time") == 0) {
582         if ( o.issetMode() && o.getMode() != ICMP )
583             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ICMP messages.", o.mode2Ascii(o.getMode()));
584         this->parseICMPTimestamp(optarg, &aux32);
585         o.setICMPTransmitTimestamp(aux32);
586     /* TODO: Add more relevant flags for different ICMP options */
587 
588 
589 /* ARP/RARP OPTIONS **********************************************************/
590     /* Operation code */
591     } else if (strcmp(long_options[option_index].name, "arp-type") == 0 ||
592                strcmp(long_options[option_index].name, "rarp-type") == 0 ||
593                strcmp(long_options[option_index].name, "arp-code") == 0 ||
594                strcmp(long_options[option_index].name, "rarp-code") == 0 ||
595                strcmp(long_options[option_index].name, "arp-operation") == 0 ||
596                strcmp(long_options[option_index].name, "arp-op") == 0 ||
597                strcmp(long_options[option_index].name, "rarp-operation") == 0 ||
598                strcmp(long_options[option_index].name, "rarp-op") == 0 ){
599         if ( o.issetMode() && o.getMode() != ARP ){
600             nping_fatal(QT_3,"You cannot specify mode %s if you want to send ARP messages.", o.mode2Ascii(o.getMode()));
601         }else if( !o.issetMode() ){
602             o.setMode(ARP);
603         }
604         if( atoARPOpCode(optarg, &aux16) != OP_SUCCESS ){
605             nping_fatal(QT_3, "Invalid ARP type/operation code");
606         }else{
607             o.setARPOpCode(aux16);
608         }
609     /* ARP Sender MAC Address */
610     } else if (strcmp(long_options[option_index].name, "arp-sender-mac") == 0 ||
611                strcmp(long_options[option_index].name, "rarp-sender-mac") == 0 ){
612         if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){
613             nping_fatal(QT_3, "Invalid ARP Sender MAC address.");
614         }else{
615             o.setARPSenderHwAddr(auxmac);
616         }
617     /* ARP Sender IP Address */
618     } else if (strcmp(long_options[option_index].name, "arp-sender-ip") == 0 ||
619                strcmp(long_options[option_index].name, "rarp-sender-ip") == 0 ){
620         if ( atoIP(optarg, &aux_ip4)!=OP_SUCCESS ){
621             nping_fatal(QT_3, "Invalid ARP Sender IP address.");
622         }else{
623             o.setARPSenderProtoAddr(aux_ip4);
624         }
625     /* ARP Target MAC Address */
626     } else if (strcmp(long_options[option_index].name, "arp-target-mac") == 0 ||
627                strcmp(long_options[option_index].name, "rarp-target-mac") == 0 ){
628         if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){
629             nping_fatal(QT_3, "Invalid ARP Target MAC address.");
630         }else{
631             o.setARPTargetHwAddr(auxmac);
632         }
633     /* ARP Target IP Address */
634     } else if (strcmp(long_options[option_index].name, "arp-target-ip") == 0 ||
635                strcmp(long_options[option_index].name, "rarp-target-ip") == 0 ){
636         if ( atoIP(optarg, &aux_ip4)!=OP_SUCCESS ){
637             nping_fatal(QT_3, "Invalid ARP Target IP address.");
638         }else{
639             o.setARPTargetProtoAddr(aux_ip4);
640         }
641 
642 
643 /* ETHERNET OPTIONS **********************************************************/
644     /* Destination MAC address */
645     } else if (strcmp(long_options[option_index].name, "dest-mac") == 0 ){
646         if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){
647             nping_fatal(QT_3, "Invalid Ethernet Destination MAC address.");
648         }else{
649             o.setDestMAC(auxmac);
650         }
651         if( !o.issetSendPreference() )
652             o.setSendPreference(PACKET_SEND_ETH_STRONG);
653     /* Source MAC address */
654     } else if (strcmp(long_options[option_index].name, "source-mac") == 0 ||
655                strcmp(long_options[option_index].name, "spoof-mac") == 0 ){
656         if ( parseMAC(optarg, auxmac) != OP_SUCCESS ){
657             nping_fatal(QT_3, "Invalid Ethernet Source MAC address.");
658         }else{
659             o.setSourceMAC(auxmac);
660         }
661         if( !o.issetSendPreference() )
662             o.setSendPreference(PACKET_SEND_ETH_STRONG);
663     /* Ethernet type field */
664     } else if (strcmp(long_options[option_index].name, "ethertype") == 0 ||
665                strcmp(long_options[option_index].name, "ethtype") == 0 ||
666                strcmp(long_options[option_index].name, "ether-type") == 0 ){
667         if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){
668             o.setEtherType(aux16);
669         }else if ( atoEtherType(optarg, &aux16) == OP_SUCCESS ){
670             o.setEtherType(aux16);
671         }else{
672             nping_fatal(QT_3, "Invalid Ethernet Type.");
673         }
674         if( !o.issetSendPreference() )
675             o.setSendPreference(PACKET_SEND_ETH_STRONG);
676 
677 
678 /* IPv4 OPTIONS **************************************************************/
679     /* Destination IP address. This is just another way to specify targets,
680      * provided for consistency with the rest of the parameters. */
681     } else if (strcmp(long_options[option_index].name, "dest-ip") == 0 ){
682         o.targets.addSpec( strdup(optarg) );
683     /* IP Type of service*/
684     } else if (strcmp(long_options[option_index].name, "tos") == 0 ){
685         if ( parse_u8(optarg, &aux8) == OP_SUCCESS ){
686             o.setTOS(aux8);
687         }else{
688             nping_fatal(QT_3,"TOS option must be a number between 0 and 255 (inclusive)");
689         }
690     /* IP Identification field */
691     } else if (strcmp(long_options[option_index].name, "id") == 0 ){
692         if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){
693             o.setIdentification(aux16);
694         }else{
695             nping_fatal(QT_3,"Identification must be a number between 0 and 65535 (inclusive)");
696         }
697     /* Don't fragment bit */
698     } else if (strcmp(long_options[option_index].name, "df") == 0 ){
699         o.setDF();
700     /* More fragments bit */
701     } else if (strcmp(long_options[option_index].name, "mf") == 0 ){
702         o.setMF();
703     /* Time to live (hop-limit in IPv6) */
704     } else if (strcmp(long_options[option_index].name, "ttl") == 0  ||
705                strcmp(long_options[option_index].name, "hop-limit") == 0 ){
706                /* IPv6 TTL field is named "hop limit" but has exactly the same
707                 * function as in IPv4 so handling of that option should be the
708                 * same in both versions. */
709         if ( parse_u8(optarg, &aux8) == OP_SUCCESS ){
710             o.setTTL(aux8);
711         }else{
712             nping_fatal(QT_3,"%s option must be a number between 0 and 255 (inclusive)",
713              strcmp(long_options[option_index].name, "ttl")==0 ? "TTL" : "Hop Limit"
714             );
715         }
716         /* TODO: At some point we may want to let users specify TTLs like "linux",
717          * "bsd" etc, so the default TTL for those systems is used. Check
718          * http://members.cox.net/~ndav1/self_published/TTL_values.html
719          * for more information */
720     /* Set up a bad IP checksum */
721     } else if (strcmp(long_options[option_index].name, "badsum-ip") == 0 ){
722         o.enableBadsumIP();
723     /* IP Options */
724     } else if (strcmp(long_options[option_index].name, "ip-options") == 0 ){
725         /* We need to know if options specification is correct so we perform
726          * a little test here, instead of waiting until the IPv4Header
727          * complains and fatal()s we just call parse_ip_options() ourselves.
728          * The call should fatal if something is wrong with user-supplied opts */
729          int foo=0, bar=0;
730          u8 buffer[128];
731          if( parse_ip_options(optarg, buffer, 128, &foo, &bar, errstr, sizeof(errstr)) < 0 )
732             nping_fatal(QT_3, "Incorrect IP options specification.");
733          /* If we get here it's safe to store the options */
734          o.setIPOptions( optarg );
735     /* Maximum Transmission Unit */
736     } else if (strcmp(long_options[option_index].name, "mtu") == 0 ){
737         /* Special treatment for random here since the generated number must be n%8==0 */
738         if(!strcasecmp("rand", optarg) || !strcasecmp("random", optarg)){
739             aux16=get_random_u16(); /* We limit the random mtu to a max of 65535 */
740             /* Make sure generated number is multiple of 8, adding a few units */
741             if(aux16 > 8 )
742                 aux16-=(aux16%8);
743             else
744                 aux16+=(8-(aux16%8));
745             o.setMTU(aux16);
746         }else if ( (parse_u32(optarg, &aux32)==OP_SUCCESS) && aux32!=0 && aux32%8==0){
747             o.setMTU(aux32);
748         }else{
749             nping_fatal(QT_3,"MTU must be >0 and multiple of 8");
750         }
751 
752 
753 /* IPv6 OPTIONS **************************************************************/
754     /* IPv6 Traffic class */
755     } else if (strcmp(long_options[option_index].name, "traffic-class") == 0 ||
756                strcmp(long_options[option_index].name, "tc") == 0 ){
757         if ( parse_u8(optarg, &aux8) == OP_SUCCESS )
758            o.setTrafficClass(aux8);
759         else
760             nping_fatal(QT_3,"IPv6 Traffic Class must be a number between 0 and 255 (inclusive)");
761     /* IPv6 Flow label */
762     } else if (strcmp(long_options[option_index].name, "flow") == 0 ){
763 		if( meansRandom(optarg) ){
764             o.setFlowLabel( get_random_u32()%1048575 ); /* Mod 2^20 so it doesn't exceed 20bits */
765         }else if ( parse_u32(optarg, &aux32) == OP_SUCCESS ){
766             if( aux32>1048575 )
767 				nping_fatal(QT_3, "IPv6 Flow Label cannot be greater than 1048575 ");
768             else
769                 o.setFlowLabel(aux32);
770         }else{
771             nping_fatal(QT_3,"IPv6 Flow Label must be a number between 0 and 1048575");
772         }
773 
774 
775 /* PACKET PAYLOAD OPTIONS  ***************************************************/
776     /* Hexadecimal payload specification */
777     } else if (strcmp(long_options[option_index].name, "data") == 0 ){
778         u8 *tempbuff=NULL;
779         size_t len=0;
780         if( (tempbuff=parseBufferSpec(optarg, &len))==NULL)
781             nping_fatal(QT_3,"Invalid hex string specification\n");
782         else{
783             u8 *buff = (u8 *) safe_malloc(len);
784             memcpy(buff, tempbuff, len);
785             o.setPayloadBuffer(buff, len);
786             o.setPayloadType(PL_HEX);
787         }
788     /* Random payload */
789     } else if (strcmp(long_options[option_index].name, "data-length") == 0 ){
790         if( o.issetPayloadType() != false )
791             nping_fatal(QT_3,"Only one type of payload may be selected.");
792         if( meansRandom(optarg) ){
793             /* We do not generate more than Ethernet standard MTU */
794             aux32 = 1 + get_random_u16() % (MAX_RANDOM_PAYLOAD-1);
795         }else if ( parse_u32(optarg, &aux32) != OP_SUCCESS  ){
796             nping_fatal(QT_3,"Invalid payload length specification");
797         }
798         if ( aux32 > MAX_PAYLOAD_ALLOWED )
799             nping_fatal(QT_3,"data-length must be a value between 0 and %d.", MAX_PAYLOAD_ALLOWED);
800         if ( aux32 > MAX_RECOMMENDED_PAYLOAD )
801             nping_print(QT_3, "WARNING: Payload exceeds maximum recommended payload (%d)", MAX_RECOMMENDED_PAYLOAD);
802         o.setPayloadType(PL_RAND);
803         /* Allocate a buffer big enough to hold the desired payload */
804         if( (auxbuff=(u8 *)safe_malloc(aux32)) == NULL )
805              nping_fatal(QT_3,"Not enough memory to store payload.");
806         /* Generate random data and store the payload */
807         get_random_bytes(auxbuff, aux32);
808         o.setPayloadBuffer(auxbuff, aux32);
809     /* ASCII string payload */
810     } else if (strcmp(long_options[option_index].name, "data-string") == 0 ){
811         o.setPayloadType(PL_STRING);
812         int plen=strlen(optarg);
813         if ( plen>MAX_PAYLOAD_ALLOWED )
814             nping_fatal(QT_3,"data-string must be between 0 and %d characters.", MAX_PAYLOAD_ALLOWED);
815         if ( plen > MAX_RECOMMENDED_PAYLOAD )
816             nping_print(QT_3, "WARNING: Payload exceeds maximum recommended payload (%d)", MAX_RECOMMENDED_PAYLOAD);
817         if( meansRandom(optarg) ){
818              auxbuff=(u8*)strdup(getRandomTextPayload());
819              plen=strlen((char*)auxbuff);
820         }else {
821             auxbuff=(u8*)safe_zalloc(plen);
822             memcpy(auxbuff, optarg, plen);
823         }
824         o.setPayloadBuffer((u8*)auxbuff, plen);
825 
826 
827 /* ECHO C/S MODE OPTIONS *****************************************************/
828     } else if (strcmp(long_options[option_index].name, "echo-client")==0 ||
829                strcmp(long_options[option_index].name, "ec")==0 ){
830         o.setRoleClient();
831         o.setEchoPassphrase(optarg);
832     } else if (strcmp(long_options[option_index].name, "echo-server")==0 ||
833                strcmp(long_options[option_index].name, "es")==0 ){
834         o.setRoleServer();
835         o.setEchoPassphrase(optarg);
836     } else if (strcmp(long_options[option_index].name, "echo-port")==0 ||
837                strcmp(long_options[option_index].name, "ep")==0 ){
838         if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){
839             if(aux16==0)
840                 nping_fatal(QT_3, "Invalid echo port. Port can't be zero.");
841             else
842                 o.setEchoPort( aux16 );
843         }else{
844             nping_fatal(QT_3, "Invalid echo port. Value must be 0<N<2^16.");
845         }
846     } else if (strcmp(long_options[option_index].name, "once")==0 ){
847         o.setOnce(true);
848     } else if (strcmp(long_options[option_index].name, "no-crypto")==0 ||
849                strcmp(long_options[option_index].name, "nc")==0 ){
850         o.doCrypto(false);
851     } else if (strcmp(long_options[option_index].name, "safe-payloads")==0 ){
852         o.echoPayload(false);
853     } else if (strcmp(long_options[option_index].name, "include-payloads")==0 ){
854         o.echoPayload(true);
855 
856 
857 /* TIMING AND PERFORMANCE OPTIONS ********************************************/
858     /* Inter-packet delay */
859     } else if (strcmp(long_options[option_index].name, "delay") == 0 ){
860         if ( (l= tval2msecs(optarg)) == -1)
861             nping_fatal(QT_3,"Invalid delay supplied. Delay must be a valid, positive integer or floating point number.");
862         else if(l<0)
863             nping_fatal(QT_3,"Invalid delay supplied. Delays can never be negative.");
864         if (l >= 10 * 1000 && tval_unit(optarg) == NULL)
865             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);
866         o.setDelay(l);
867     /* Tx rate */
868     } else if (strcmp(long_options[option_index].name, "rate") == 0 ){
869         if (parse_u32(optarg, &aux32)==OP_SUCCESS){
870             if(aux32==0){
871                 nping_fatal(QT_3,"Invalid rate supplied. Rate can never be zero.");
872             }else{
873                 /* Compute delay from rate: delay= 1000ms/rate*/
874                 aux32 = 1000 / aux32;
875                 o.setDelay(aux32);
876             }
877         }else{
878             nping_fatal(QT_3,"Invalid rate supplied. Rate must be a valid, positive integer");
879         }
880 
881 /* MISC OPTIONS **************************************************************/
882     } else if (strcmp(long_options[option_index].name, "privileged") == 0 ){
883         o.setIsRoot();
884     } else if (strcmp(long_options[option_index].name, "unprivileged") == 0 ){
885         o.setIsRoot(0);
886     } else if (strcmp(long_options[option_index].name, "send-eth") == 0 ){
887         o.setSendPreference(PACKET_SEND_ETH_STRONG);
888     } else if (strcmp(long_options[option_index].name, "send-ip") == 0 ){
889         o.setSendPreference(PACKET_SEND_IP_STRONG);
890     } else if (strcmp(long_options[option_index].name, "bpf-filter") == 0 || strcmp(long_options[option_index].name, "filter") == 0){
891         o.setBPFFilterSpec( optarg );
892         if( o.issetDisablePacketCapture() && o.disablePacketCapture()==true )
893             nping_warning(QT_2, "Warning: There is no point on specifying a BPF filter if you disable packet capture. BPF filter will be ignored.");
894     } else if (strcmp(long_options[option_index].name, "nsock-engine") == 0){
895         if (nsock_set_default_engine(optarg) < 0)
896           nping_fatal(QT_3, "Unknown or non-available engine: %s", optarg);
897     /* Output Options */
898     } else if (strcmp(long_options[option_index].name, "quiet") == 0 ){
899             o.setVerbosity(-4);
900             o.setDebugging(0);
901     }else if (strcmp(long_options[option_index].name, "debug") == 0 ){
902             o.setVerbosity(4);
903             o.setDebugging(9);
904     }
905 
906     break; /* case 0 */
907 
908 
909 /* OPTIONS THAT CAN BE SPECIFIED AS A SINGLE CHARACTER ***********************/
910 
911     case '4': /* IPv4 */
912         o.setIPVersion(IP_VERSION_4);
913     break; /* case '4': */
914 
915     case '6': /* IPv6 */
916         o.setIPVersion(IP_VERSION_6);
917     break; /* case '6': */
918 
919     case 'f': /* Fragment packets */
920         if( o.issetMTU() == true ){
921             nping_warning(QT_3,"WARNING: -f is irrelevant if an MTU has been previously specified");
922         }
923         else{
924             nping_print(DBG_1, "Setting default MTU=%d", DEFAULT_MTU_FOR_FRAGMENTATION);
925             o.setMTU( DEFAULT_MTU_FOR_FRAGMENTATION );
926         }
927     break;
928 
929     case 'g': /* Source port */
930         if( o.issetSourcePort() ){
931             nping_fatal(QT_3,"Cannot specify source port twice.");
932         }else if ( parse_u16(optarg, &aux16) == OP_SUCCESS ){
933             o.setSourcePort(aux16);
934             if(aux16==0)
935                 nping_warning(QT_1, "WARNING: a source port of zero may not work on all systems.");
936         }else{
937             nping_fatal(QT_3,"Source port must be a number between 0 and 65535 (inclusive)");
938         }
939     break; /* case 'g': */
940 
941     case 'p': /* Destination port */
942         /* Parse port spec */
943         nping_getpts_simple(optarg, &portlist, &auxint);
944         if( portlist == NULL || auxint <= 0 ){
945             nping_fatal(QT_3,"Invalid target ports specification.");
946         }else{
947             o.setTargetPorts(portlist, auxint);
948         }
949     break; /* case 'p': */
950 
951     case 'S': /* Source IP */
952         if( o.getIPVersion() == IP_VERSION_6){
953             struct sockaddr_storage sourceaddr;
954             struct sockaddr_in6 *source6=(struct sockaddr_in6 *)&sourceaddr;
955             memset(&sourceaddr, 0, sizeof(struct sockaddr_storage));
956             struct in6_addr ipv6addr;
957 
958             /* Set random address */
959             if( meansRandom(optarg) ){
960                 for(int i6=0; i6<16; i6++)
961                     ipv6addr.s6_addr[i6]=get_random_u8();
962             }
963             /* Set user supplied address (if we manage to resolve it) */
964             else if ( atoIP(optarg, &sourceaddr, PF_INET6) != OP_SUCCESS){
965                 nping_fatal(QT_3, "Could not resolve source IPv6 address.");
966             }else{
967               ipv6addr = source6->sin6_addr;
968             }
969             o.setIPv6SourceAddress(ipv6addr);
970             o.setSpoofSource();
971         }
972         else{
973             if( meansRandom(optarg) )
974                 while ( (aux_ip4.s_addr=get_random_u32()) == 0 );
975             else if ( atoIP(optarg, &aux_ip4) != OP_SUCCESS)
976                 nping_fatal(QT_3, "Could not resolve source IPv4 address.");
977             o.setIPv4SourceAddress(aux_ip4);
978             o.setSpoofSource();
979         }
980     break; /* case 'S': */
981 
982     case '?':
983         printUsage();
984         exit(1);
985     break; /* case 'h': */
986 
987     case 'h': /* Help */
988         printUsage();
989         exit(0);
990     break; /* case 'h': */
991 
992     case 'V': /* Version */
993         printVersion();
994         exit(0);
995     break; /* case 'V': */
996 
997     case 'c': /* Packet count */
998         if( meansRandom(optarg) ){
999            o.setPacketCount( get_random_u32()%1024 );
1000         }else if( parse_u32(optarg, &aux32) == OP_SUCCESS ){
1001             o.setPacketCount(aux32);
1002         }else{
1003             nping_fatal(QT_3,"Packet count must be an integer greater than or equal to 0.");
1004         }
1005     break; /* case 'c': */
1006 
1007     case 'e': /* Network interface */
1008         if(strlen(optarg)==0)
1009             nping_fatal(QT_3,"Invalid network interface supplied. Interface name cannot be NULL.");
1010         else
1011             o.setDevice( strdup(optarg) );
1012     break; /* case 'e': */
1013 
1014     case 'N': /* Don't capture packets */
1015         o.setDisablePacketCapture(true);
1016         if( o.issetBPFFilterSpec() )
1017             nping_warning(QT_2, "Warning: A custom BPF filter was specified before disabling packet capture. BPF filter will be ignored.");
1018     break; /* case 'N': */
1019 
1020     case 'H': /* Hide sent packets */
1021         o.setShowSentPackets(false);
1022     break; /* case 'H': */
1023 
1024     case 'd': /* Debug mode */
1025       if (optarg){
1026         if (isdigit(optarg[0]) || optarg[0]=='-'){
1027             auxint = strtol( optarg, NULL, 10);
1028             if ( ((auxint==0) && (optarg[0] != '0')) || auxint<0 || auxint > 9)
1029                 nping_fatal(QT_3,"Debugging level must be an integer between 0 and 9.");
1030             else{
1031                 o.setDebugging( auxint );
1032                 /* When user specifies a debugging level, if no verbosity was specified,
1033                 * increase it automatically. If user specified a verbosity level, then leave
1034                 * it like it was. */
1035                 if(o.issetVerbosity()==false)
1036                     o.setVerbosity( (auxint>4) ? 4 : auxint );
1037             }
1038         }else {
1039             const char *p;
1040             o.increaseVerbosity();
1041             o.increaseDebugging();
1042             for (p = optarg != NULL ? optarg : ""; *p == 'd'; p++){
1043                 o.increaseVerbosity();
1044                 o.increaseDebugging();
1045             }
1046             if (*p != '\0')
1047                 nping_fatal(QT_3,"Invalid argument to -d: \"%s\".", optarg);
1048         }
1049     }else{
1050         o.increaseVerbosity();
1051         o.increaseDebugging();
1052     }
1053     break; /* case 'd': */
1054 
1055     case 'v': /* Verbosity */
1056       if (optarg){
1057         if (isdigit(optarg[0]) || optarg[0]=='-'){
1058             auxint = strtol( optarg, NULL, 10);
1059             if ( ((auxint==0) && (optarg[0] != '0')) || auxint<(-4) || auxint > 4)
1060                 nping_fatal(QT_3,"Verbosity level must be an integer between -4 and +4.");
1061             else
1062                 o.setVerbosity( auxint );
1063         }else {
1064             const char *p;
1065             o.increaseVerbosity();
1066             for (p = optarg != NULL ? optarg : ""; *p == 'v'; p++)
1067                 o.increaseVerbosity();
1068             if (*p != '\0')
1069                 nping_fatal(QT_3,"Invalid argument to -v: \"%s\".", optarg);
1070         }
1071     }else{
1072         o.increaseVerbosity();
1073     }
1074     break; /* case 'v': */
1075 
1076     case 'q': /* Reduce verbosity */
1077       if (optarg){
1078         if (isdigit(optarg[0])){
1079             auxint = strtol( optarg, NULL, 10);
1080             if ( ((auxint==0) && (optarg[0] != '0')) || auxint<0 || auxint > 4)
1081                 nping_fatal(QT_3,"You can only reduce verbosity from level 0 to level -4.");
1082             else
1083                 o.setVerbosity( -auxint );
1084         }else {
1085             const char *p;
1086             o.decreaseVerbosity();
1087             for (p = optarg != NULL ? optarg : ""; *p == 'q'; p++)
1088                 o.decreaseVerbosity();
1089             if (*p != '\0')
1090                 nping_fatal(QT_3,"Invalid argument to -q: \"%s\".", optarg);
1091         }
1092     }else{
1093         o.decreaseVerbosity();
1094     }
1095     break; /* case 'q': */
1096 
1097   } /* End of switch */
1098 
1099  } /* End of getopt while */
1100 
1101 
1102  /* Now it's time to parse target host specifications. As nmap does, Nping
1103   * treats everything getopt() can't parse as a host specification. At this
1104   * point, var optind should point to the argv[] position that contains the
1105   * first unparsed argument. User may specify multiple target hosts so to
1106   * handle this, function grab_next_host_spec() returns the next target
1107   * specification available. This function will be called until there are no
1108   * more target hosts to parse (returned NULL). Once we have a spec, we use
1109   * class NpingTargets, that stores the specs and will provide the targets
1110   * through calls to getNextTarget();
1111   * */
1112   const char *next_spec=NULL;
1113   while ( (next_spec= grab_next_host_spec(NULL, false, argc, (const char **) argv)) != NULL )
1114        o.targets.addSpec( (char *) next_spec );
1115 
1116  return OP_SUCCESS;
1117 } /* End of parseArguments() */
1118 
1119 
1120 
1121 
1122 /** Prints version information to stdout */
printVersion(void)1123 void ArgParser::printVersion(void){
1124   printf("\n%s version %s ( %s )\n",  NPING_NAME, NPING_VERSION, NPING_URL);
1125   return;
1126 } /* End of printVersion() */
1127 
1128 
1129 
1130 /** Prints usage information to stdout */
printUsage(void)1131 void ArgParser::printUsage(void){
1132 
1133   printf("%s %s ( %s )\n"
1134 "Usage: nping [Probe mode] [Options] {target specification}\n"
1135 "\n"
1136 "TARGET SPECIFICATION:\n"
1137 "  Targets may be specified as hostnames, IP addresses, networks, etc.\n"
1138 "  Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.*.1-24\n"
1139 "PROBE MODES:\n"
1140 "  --tcp-connect                    : Unprivileged TCP connect probe mode.\n"
1141 "  --tcp                            : TCP probe mode.\n"
1142 "  --udp                            : UDP probe mode.\n"
1143 "  --icmp                           : ICMP probe mode.\n"
1144 "  --arp                            : ARP/RARP probe mode.\n"
1145 "  --tr, --traceroute               : Traceroute mode (can only be used with \n"
1146 "                                     TCP/UDP/ICMP modes).\n"
1147 "TCP CONNECT MODE:\n"
1148 "   -p, --dest-port <port spec>     : Set destination port(s).\n"
1149 "   -g, --source-port <portnumber>  : Try to use a custom source port.\n"
1150 "TCP PROBE MODE:\n"
1151 "   -g, --source-port <portnumber>  : Set source port.\n"
1152 "   -p, --dest-port <port spec>     : Set destination port(s).\n"
1153 "   --seq <seqnumber>               : Set sequence number.\n"
1154 "   --flags <flag list>             : Set TCP flags (ACK,PSH,RST,SYN,FIN...)\n"
1155 "   --ack <acknumber>               : Set ACK number.\n"
1156 "   --win <size>                    : Set window size.\n"
1157 "   --badsum                        : Use a random invalid checksum. \n"
1158 "UDP PROBE MODE:\n"
1159 "   -g, --source-port <portnumber>  : Set source port.\n"
1160 "   -p, --dest-port <port spec>     : Set destination port(s).\n"
1161 "   --badsum                        : Use a random invalid checksum. \n"
1162 "ICMP PROBE MODE:\n"
1163 "  --icmp-type <type>               : ICMP type.\n"
1164 "  --icmp-code <code>               : ICMP code.\n"
1165 "  --icmp-id <id>                   : Set identifier.\n"
1166 "  --icmp-seq <n>                   : Set sequence number.\n"
1167 "  --icmp-redirect-addr <addr>      : Set redirect address.\n"
1168 "  --icmp-param-pointer <pnt>       : Set parameter problem pointer.\n"
1169 "  --icmp-advert-lifetime <time>    : Set router advertisement lifetime.\n"
1170 "  --icmp-advert-entry <IP,pref>    : Add router advertisement entry.\n"
1171 "  --icmp-orig-time  <timestamp>    : Set originate timestamp.\n"
1172 "  --icmp-recv-time  <timestamp>    : Set receive timestamp.\n"
1173 "  --icmp-trans-time <timestamp>    : Set transmit timestamp.\n"
1174 "ARP/RARP PROBE MODE:\n"
1175 "  --arp-type <type>                : Type: ARP, ARP-reply, RARP, RARP-reply.\n"
1176 "  --arp-sender-mac <mac>           : Set sender MAC address.\n"
1177 "  --arp-sender-ip  <addr>          : Set sender IP address.\n"
1178 "  --arp-target-mac <mac>           : Set target MAC address.\n"
1179 "  --arp-target-ip  <addr>          : Set target IP address.\n"
1180 "IPv4 OPTIONS:\n"
1181 "  -S, --source-ip                  : Set source IP address.\n"
1182 "  --dest-ip <addr>                 : Set destination IP address (used as an \n"
1183 "                                     alternative to {target specification} ). \n"
1184 "  --tos <tos>                      : Set type of service field (8bits).\n"
1185 "  --id  <id>                       : Set identification field (16 bits).\n"
1186 "  --df                             : Set Don't Fragment flag.\n"
1187 "  --mf                             : Set More Fragments flag.\n"
1188 "  --ttl <hops>                     : Set time to live [0-255].\n"
1189 "  --badsum-ip                      : Use a random invalid checksum. \n"
1190 "  --ip-options <S|R [route]|L [route]|T|U ...> : Set IP options\n"
1191 "  --ip-options <hex string>                    : Set IP options\n"
1192 "  --mtu <size>                     : Set MTU. Packets get fragmented if MTU is\n"
1193 "                                     small enough.\n"
1194 "IPv6 OPTIONS:\n"
1195 "  -6, --IPv6                       : Use IP version 6.\n"
1196 "  --dest-ip                        : Set destination IP address (used as an\n"
1197 "                                     alternative to {target specification}).\n"
1198 "  --hop-limit                      : Set hop limit (same as IPv4 TTL).\n"
1199 "  --traffic-class <class> :        : Set traffic class.\n"
1200 "  --flow <label>                   : Set flow label.\n"
1201 "ETHERNET OPTIONS:\n"
1202 "  --dest-mac <mac>                 : Set destination mac address. (Disables\n"
1203 "                                     ARP resolution)\n"
1204 "  --source-mac <mac>               : Set source MAC address.\n"
1205 "  --ether-type <type>              : Set EtherType value.\n"
1206 "PAYLOAD OPTIONS:\n"
1207 "  --data <hex string>              : Include a custom payload.\n"
1208 "  --data-string <text>             : Include a custom ASCII text.\n"
1209 "  --data-length <len>              : Include len random bytes as payload.\n"
1210 "ECHO CLIENT/SERVER:\n"
1211 "  --echo-client <passphrase>       : Run Nping in client mode.\n"
1212 "  --echo-server <passphrase>       : Run Nping in server mode.\n"
1213 "  --echo-port <port>               : Use custom <port> to listen or connect.\n"
1214 "  --no-crypto                      : Disable encryption and authentication.\n"
1215 "  --once                           : Stop the server after one connection.\n"
1216 "  --safe-payloads                  : Erase application data in echoed packets.\n"
1217 "TIMING AND PERFORMANCE:\n"
1218  "  Options which take <time> are in seconds, or append 'ms' (milliseconds),\n"
1219 "  's' (seconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m, 0.25h).\n"
1220 "  --delay <time>                   : Adjust delay between probes.\n"
1221 "  --rate  <rate>                   : Send num packets per second.\n"
1222 "MISC:\n"
1223 "  -h, --help                       : Display help information.\n"
1224 "  -V, --version                    : Display current version number. \n"
1225 "  -c, --count <n>                  : Stop after <n> rounds.\n"
1226 "  -e, --interface <name>           : Use supplied network interface.\n"
1227 "  -H, --hide-sent                  : Do not display sent packets.\n"
1228 "  -N, --no-capture                 : Do not try to capture replies.\n"
1229 "  --privileged                     : Assume user is fully privileged.\n"
1230 "  --unprivileged                   : Assume user lacks raw socket privileges.\n"
1231 "  --send-eth                       : Send packets at the raw Ethernet layer.\n"
1232 "  --send-ip                        : Send packets using raw IP sockets.\n"
1233 "  --bpf-filter <filter spec>       : Specify custom BPF filter.\n"
1234 "OUTPUT:\n"
1235 "  -v                               : Increment verbosity level by one.\n"
1236 "  -v[level]                        : Set verbosity level. E.g: -v4\n"
1237 "  -d                               : Increment debugging level by one.\n"
1238 "  -d[level]                        : Set debugging level. E.g: -d3\n"
1239 "  -q                               : Decrease verbosity level by one.\n"
1240 "  -q[N]                            : Decrease verbosity level N times\n"
1241 "  --quiet                          : Set verbosity and debug level to minimum.\n"
1242 "  --debug                          : Set verbosity and debug to the max level.\n"
1243 "EXAMPLES:\n"
1244 "  nping scanme.nmap.org\n"
1245 "  nping --tcp -p 80 --flags rst --ttl 2 192.168.1.1\n"
1246 "  nping --icmp --icmp-type time --delay 500ms 192.168.254.254\n"
1247 "  nping --echo-server \"public\" -e wlan0 -vvv \n"
1248 "  nping --echo-client \"public\" echo.nmap.org --tcp -p1-1024 --flags ack\n"
1249 "\n"
1250 "SEE THE MAN PAGE FOR MANY MORE OPTIONS, DESCRIPTIONS, AND EXAMPLES\n\n",
1251 NPING_NAME, NPING_VERSION, NPING_URL);
1252 
1253 } /* End of printUsage() */
1254 
1255 
parseAdvertEntry(char * str,struct in_addr * addr,u32 * pref)1256 int ArgParser::parseAdvertEntry(char *str, struct in_addr *addr, u32 *pref){
1257   char *aux=NULL;
1258   struct in_addr auxIP;
1259   u32 auxPref=0;
1260   size_t len=0;
1261   static char first[256];
1262   static char last[256];
1263   memset(first, 0, 256);
1264   memset(last, 0, 256);
1265 
1266   if (str==NULL || addr==NULL || pref==NULL)
1267     return OP_FAILURE;
1268 
1269   len =strlen(str);
1270 
1271   /* I guess one can try to lookup something as short as a single char */
1272   if ( len < strlen("a,1") )
1273     nping_fatal(QT_3, "Invalid Router Advertising Entry specification: too short");
1274   /* Im going to limit this to 255 chars. */
1275   if( len > 255 )
1276     nping_fatal(QT_3, "Invalid Router Advertising Entry specification: too long");
1277 
1278   /* Let's find the comma */
1279   aux=strstr(str, ",");
1280 
1281   if(aux==NULL )
1282     nping_fatal(QT_3, "Invalid Router Advertising Entry specification: Bad syntax, missing comma delimiter");
1283   if(aux==str)
1284     nping_fatal(QT_3, "Invalid Router Advertising Entry specification: Bad syntax, comma cannot be placed at start");
1285   if(aux>=str+len-1 )
1286     nping_fatal(QT_3, "Invalid Router Advertising Entry specification: Bad syntax, comma cannot be placed at the end");
1287 
1288   /* Looks like at least the syntax is correct */
1289   memcpy(first, str, aux-str);
1290   memcpy(last, aux+1, len-(aux-str) );
1291 
1292   if( atoIP(first, &auxIP) == OP_FAILURE )
1293     nping_fatal(QT_3, "Invalid Router Advertising Entry specification: Unable to resolve %s", first);
1294   if( isNumber_u32( last ) == false )
1295     nping_fatal(QT_3, "Invalid Router Advertising Entry specification: %s is not a valid preference number", last);
1296 
1297   auxPref=strtoul( last, NULL, 10);
1298   *pref=auxPref;
1299   *addr=auxIP;
1300   return OP_SUCCESS;
1301 } /* End of parseAdvertEntry() */
1302 
1303 
1304 
1305 
1306 /* ALLOWED format:
1307  *
1308  *  Full option name:              destination-unreachable
1309  *  Four letters - three letters:  dest-unr
1310  *  Initials:                      du
1311  *
1312  *  In ICMP types that REQUEST something, the word "request" is always omitted.
1313  *  For example: Echo request should be specified as "echo" or "e",
1314  *  not "echo-request"/"echo-req"/"er"
1315  *
1316  *  EXCEPTIONS. To avoid confusion:
1317  *      - Initials for "Timestamp" are "tm"
1318  *      - Initial for Traceroute are "tc"
1319  * */
atoICMPType(char * opt,u8 * type)1320 int ArgParser::atoICMPType(char *opt, u8 *type){
1321   if(type==NULL)
1322     return OP_FAILURE;
1323 
1324   if ( !strcasecmp(opt, "echo-reply") ||
1325        !strcasecmp(opt, "echo-rep") ||
1326        !strcasecmp(opt, "er") )
1327     *type=0;
1328   else if ( !strcasecmp(opt, "destination-unreachable") ||
1329             !strcasecmp(opt, "dest-unr") ||
1330             !strcasecmp(opt, "du") )
1331     *type=3;
1332   else if ( !strcasecmp(opt, "source-quench") ||
1333             !strcasecmp(opt, "sour-que") ||
1334             !strcasecmp(opt, "sq") )
1335     *type=4;
1336   else if ( !strcasecmp(opt, "redirect") ||
1337             !strcasecmp(opt, "redi") ||
1338             !strcasecmp(opt, "r") )
1339     *type=5;
1340   else if ( !strcasecmp(opt, "echo-request") || /* Ok, I'll also allow this */
1341             !strcasecmp(opt, "echo") ||
1342             !strcasecmp(opt, "e") )
1343     *type=8;
1344   else if ( !strcasecmp(opt, "router-advertisement") ||
1345             !strcasecmp(opt, "rout-adv") ||
1346             !strcasecmp(opt, "ra") )
1347     *type=9;
1348   else if ( !strcasecmp(opt, "router-solicitation") ||
1349             !strcasecmp(opt, "rout-sol") ||
1350             !strcasecmp(opt, "rs") )
1351     *type=10;
1352   else if ( !strcasecmp(opt, "time-exceeded") ||
1353             !strcasecmp(opt, "time-exc") ||
1354             !strcasecmp(opt, "te") )
1355     *type=11;
1356   else if ( !strcasecmp(opt, "parameter-problem") ||
1357             !strcasecmp(opt, "para-pro") ||
1358             !strcasecmp(opt, "pp") )
1359     *type=12;
1360   else if ( !strcasecmp(opt, "timestamp") ||
1361             !strcasecmp(opt, "time") ||
1362             !strcasecmp(opt, "tm") )
1363     *type=13;
1364   else if ( !strcasecmp(opt, "timestamp-reply") ||
1365             !strcasecmp(opt, "time-rep") ||
1366             !strcasecmp(opt, "tr") )
1367     *type=14;
1368   else if ( !strcasecmp(opt, "information") ||
1369             !strcasecmp(opt, "info") ||
1370             !strcasecmp(opt, "i") )
1371     *type=15;
1372   else if ( !strcasecmp(opt, "information-reply") ||
1373             !strcasecmp(opt, "info-rep") ||
1374             !strcasecmp(opt, "ir") )
1375     *type=16;
1376   else if ( !strcasecmp(opt, "mask-request") ||
1377             !strcasecmp(opt, "mask") ||
1378             !strcasecmp(opt, "m") )
1379     *type=17;
1380   else if ( !strcasecmp(opt, "mask-reply") ||
1381             !strcasecmp(opt, "mask-rep") ||
1382             !strcasecmp(opt, "mr") )
1383     *type=18;
1384   else if ( !strcasecmp(opt, "traceroute") ||
1385             !strcasecmp(opt, "trace") ||
1386             !strcasecmp(opt, "tc") )
1387     *type=30;
1388   else
1389     return OP_FAILURE;
1390 
1391 /* TODO: They are not implemented but there are more types in
1392    http://www.iana.org/assignments/icmp-parameters
1393 
1394  31     Datagram Conversion Error               [RFC1475]
1395  32     Mobile Host Redirect                    [David Johnson]
1396  33     IPv6 Where-Are-You                      [Bill Simpson]
1397  34     IPv6 I-Am-Here                          [Bill Simpson]
1398  35     Mobile Registration Request             [Bill Simpson]
1399  36     Mobile Registration Reply               [Bill Simpson]
1400  37     Domain Name Request                     [RFC1788]
1401  38     Domain Name Reply                       [RFC1788]
1402  39     SKIP                                    [Markson]
1403  40     Photuris                                [RFC2521]
1404  41     ICMP messages utilized by experimental  [RFC4065]
1405         mobility protocols such as Seamoby
1406  42-255 Reserved				                 [JBP]
1407 
1408 */
1409  return OP_SUCCESS;
1410 } /* End of atoICMPType() */
1411 
1412 
1413 /* Names are taken from http://www.iana.org/assignments/icmp-parameters */
1414 /* ALLOWED format:
1415  *
1416  *  Full option name:              needs-fragmentation
1417  *  Four letters - three letters:  need-fra
1418  *  Our own version (varies):      frag
1419  *
1420  *  In ICMP types that REQUEST something, the word "request" is always omitted.
1421  *  For example: Echo request should be specified as "echo" or "e",
1422  *  not "echo-request"/"echo-req"/"er"
1423  *
1424  *  EXCEPTIONS. To avoid confusion:
1425  *      - Initials for "Timestamp" are "tm"
1426  *      - Initial for Traceroute are "tc"
1427  * */
atoICMPCode(char * opt,u8 * code)1428 int ArgParser::atoICMPCode(char *opt, u8 *code){
1429 
1430   if(code==NULL || opt==NULL)
1431     return OP_FAILURE;
1432 
1433   /* Destination Unreachable */
1434   if ( !strcasecmp(opt, "network-unreachable") ||
1435        !strcasecmp(opt, "netw-unr") ||
1436        !strcasecmp(opt, "net") ) /**/
1437     *code=0;
1438   else if ( !strcasecmp(opt, "host-unreachable") ||
1439             !strcasecmp(opt, "host-unr") ||
1440              !strcasecmp(opt, "host") )
1441     *code=1;
1442   else if ( !strcasecmp(opt, "protocol-unreachable") ||
1443             !strcasecmp(opt, "prot-unr") ||
1444             !strcasecmp(opt, "proto") )
1445     *code=2;
1446   else if ( !strcasecmp(opt, "port-unreachable") ||
1447             !strcasecmp(opt, "port-unr") ||
1448             !strcasecmp(opt, "port") )
1449     *code=3;
1450   else if ( !strcasecmp(opt, "needs-fragmentation") ||
1451             !strcasecmp(opt, "need-fra") ||
1452             !strcasecmp(opt, "frag") )
1453     *code=4;
1454   else if ( !strcasecmp(opt, "source-route-failed") ||
1455             !strcasecmp(opt, "sour-rou") ||
1456             !strcasecmp(opt, "routefail") )
1457     *code=5;
1458   else if ( !strcasecmp(opt, "network-unknown") ||
1459             !strcasecmp(opt, "netw-unk") ||
1460             !strcasecmp(opt, "net?") )
1461     *code=6;
1462   else if ( !strcasecmp(opt, "host-unknown") ||
1463             !strcasecmp(opt, "host-unk") ||
1464             !strcasecmp(opt, "host?") )
1465     *code=7;
1466   else if ( !strcasecmp(opt, "host-isolated") ||
1467             !strcasecmp(opt, "host-iso") ||
1468             !strcasecmp(opt, "isolated") )
1469     *code=8;
1470   else if ( !strcasecmp(opt, "network-prohibited") ||
1471             !strcasecmp(opt, "netw-pro") ||
1472             !strcasecmp(opt, "!net") )
1473     *code=9;
1474   else if ( !strcasecmp(opt, "host-prohibited") ||
1475             !strcasecmp(opt, "host-pro") ||
1476             !strcasecmp(opt, "!host") )
1477     *code=10;
1478   else if ( !strcasecmp(opt, "network-tos") ||
1479             !strcasecmp(opt, "unreachable-network-tos") ||
1480             !strcasecmp(opt, "netw-tos") ||
1481             !strcasecmp(opt, "tosnet") )
1482             /* Not to be confused with redirect-network-tos*/
1483     *code=11;
1484   else if ( !strcasecmp(opt, "host-tos") ||
1485             !strcasecmp(opt, "unreachable-host-tos") ||
1486             !strcasecmp(opt, "toshost") )
1487             /* Not to be confused with redirect-network-tos*/
1488     *code=12;
1489   else if ( !strcasecmp(opt, "communication-prohibited") ||
1490             !strcasecmp(opt, "comm-pro") ||
1491             !strcasecmp(opt, "!comm") )
1492     *code=13;
1493   else if ( !strcasecmp(opt, "host-precedence-violation") ||
1494             !strcasecmp(opt, "precedence-violation") ||
1495             !strcasecmp(opt, "prec-vio") ||
1496             !strcasecmp(opt, "violation") )
1497     *code=14;
1498   else if ( !strcasecmp(opt, "precedence-cutoff") ||
1499             !strcasecmp(opt, "prec-cut") ||
1500             !strcasecmp(opt, "cutoff") )
1501     *code=15;
1502 
1503   /* Redirect */
1504   else if ( !strcasecmp(opt, "redirect-network") ||
1505             !strcasecmp(opt, "redi-net") ||
1506             !strcasecmp(opt, "net") )
1507             /* "net" is the same as in Destination unreachable and there is no
1508              * conflict because both codes use value 0 */
1509     *code=0;
1510   else if ( !strcasecmp(opt, "redirect-host") ||
1511             !strcasecmp(opt, "redi-host") ||
1512             !strcasecmp(opt, "host") )
1513             /* "host" is the same as in Destination unreachable and there is no
1514              * conflict because both codes use value 0 */
1515     *code=1;
1516   else if ( !strcasecmp(opt, "redirect-network-tos") ||
1517             !strcasecmp(opt, "redi-ntos") ||
1518             !strcasecmp(opt, "redir-ntos") )
1519     *code=2;
1520   else if ( !strcasecmp(opt, "redirect-host-tos") ||
1521             !strcasecmp(opt, "redi-htos") ||
1522             !strcasecmp(opt, "redir-htos") )
1523     *code=3;
1524 
1525   /* Router Advertisement */
1526   else if ( !strcasecmp(opt, "normal-advertisement") ||
1527             !strcasecmp(opt, "norm-adv") ||
1528             !strcasecmp(opt, "normal") ||
1529             !strcasecmp(opt, "zero") ||
1530             !strcasecmp(opt, "default") ||
1531             !strcasecmp(opt, "def") )
1532             /* This one corresponds with "Normal router advertisement" but
1533              * with the word "normal", can be reused for any other code as
1534              * 0 is the default value if the code field is unused. */
1535     *code=0;
1536   else if ( !strcasecmp(opt, "not-route-common-traffic") ||
1537             !strcasecmp(opt, "not-rou") ||
1538             !strcasecmp(opt, "mobile-ip") ||
1539             !strcasecmp(opt, "!route") ||
1540             !strcasecmp(opt, "!commontraffic") )
1541     *code=16;
1542 
1543   /* Time Exceeded */
1544   else if ( !strcasecmp(opt, "ttl-exceeded-in-transit") ||
1545             !strcasecmp(opt, "ttl-exc") ||
1546             !strcasecmp(opt, "ttl-zero") ||
1547             !strcasecmp(opt, "ttl-transit") ||
1548             !strcasecmp(opt, "ttl-0") ||
1549             !strcasecmp(opt, "!ttl") )
1550     *code=0;
1551   else if ( !strcasecmp(opt, "fragment-reassembly-time-exceeded") ||
1552             !strcasecmp(opt, "frag-exc") ||
1553             !strcasecmp(opt, "frag-time") ||
1554             !strcasecmp(opt, "!timefrag") ||
1555             !strcasecmp(opt, "!frag") )
1556     *code=1;
1557 
1558   /* Parameter problem */
1559   else if ( !strcasecmp(opt, "pointer-indicates-error") ||
1560             !strcasecmp(opt, "poin-ind") ||
1561             !strcasecmp(opt, "pointer-indicates") ||
1562             !strcasecmp(opt, "pointer") ||
1563             !strcasecmp(opt, "pointertells") )
1564     *code=0;
1565   else if ( !strcasecmp(opt, "missing-required-option") ||
1566             !strcasecmp(opt, "miss-req") ||
1567             !strcasecmp(opt, "miss-option") ||
1568             !strcasecmp(opt, "option-missing") ||
1569             !strcasecmp(opt, "missing-option") ||
1570             !strcasecmp(opt, "!option") )
1571     *code=1;
1572   else if ( !strcasecmp(opt, "bad-length") ||
1573             !strcasecmp(opt, "bad-len") ||
1574             !strcasecmp(opt, "badlen") ||
1575             !strcasecmp(opt, "badlength") ||
1576             !strcasecmp(opt, "!len") )
1577     *code=2;
1578 
1579   /* ICMP Security Failures Messages (Experimental) */
1580   else if ( !strcasecmp(opt, "bad-spi") ||
1581             !strcasecmp(opt, "badspi") ||
1582             !strcasecmp(opt, "!spi") )
1583     *code=0;
1584   else if ( !strcasecmp(opt, "authentication-failed") ||
1585             !strcasecmp(opt, "auth-fai") ||
1586             !strcasecmp(opt, "auth-failed") ||
1587             !strcasecmp(opt, "authfail") ||
1588             !strcasecmp(opt, "!auth") )
1589     *code=1;
1590   else if ( !strcasecmp(opt, "decompression-failed") ||
1591             !strcasecmp(opt, "deco-fai") ||
1592             !strcasecmp(opt, "decom-failed") ||
1593             !strcasecmp(opt, "!decompress") ||
1594             !strcasecmp(opt, "!decompression") )
1595     *code=2;
1596   else if ( !strcasecmp(opt, "decryption-failed") ||
1597             !strcasecmp(opt, "decr-fai") ||
1598             !strcasecmp(opt, "decrypt-failed") ||
1599             !strcasecmp(opt, "!decrypt") ||
1600             !strcasecmp(opt, "!decryption") )
1601     *code=3;
1602   else if ( !strcasecmp(opt, "need-authentication") ||
1603             !strcasecmp(opt, "need-aut") ||
1604             !strcasecmp(opt, "need-auth") ||
1605             !strcasecmp(opt, "auth-needed") ||
1606             !strcasecmp(opt, "!auth") ||
1607             !strcasecmp(opt, "") )
1608     *code=4;
1609   else if ( !strcasecmp(opt, "need-authorization") ||
1610             !strcasecmp(opt, "need-author") ||
1611             !strcasecmp(opt, "authorization-needed") ||
1612             !strcasecmp(opt, "author-needed") ||
1613             !strcasecmp(opt, "!author") ||
1614             !strcasecmp(opt, "!authorization") )
1615     *code=5;
1616 /*
1617   else if ( !strcasecmp(opt, "") ||
1618             !strcasecmp(opt, "") ||
1619             !strcasecmp(opt, "") )
1620     *code=;
1621 */
1622   else
1623     return OP_FAILURE;
1624 
1625  return OP_SUCCESS;
1626 } /* End of atoICMPCode() */
1627 
1628 
1629 
1630 /* Same as atoICMPCode() but for ARP operation codes */
atoARPOpCode(char * opt,u16 * code)1631 int ArgParser::atoARPOpCode(char *opt, u16 *code){
1632 
1633   if(code==NULL || opt==NULL)
1634     return OP_FAILURE;
1635 
1636   if ( !strcasecmp(opt, "arp-request") ||
1637        !strcasecmp(opt, "arp") ||
1638        !strcasecmp(opt, "a") ) /**/
1639     *code=1;
1640   else if ( !strcasecmp(opt, "arp-reply") ||
1641             !strcasecmp(opt, "arp-rep") ||
1642              !strcasecmp(opt, "ar") )
1643     *code=2;
1644   else if ( !strcasecmp(opt, "rarp-request") ||
1645             !strcasecmp(opt, "rarp") ||
1646             !strcasecmp(opt, "r") )
1647     *code=3;
1648   else if ( !strcasecmp(opt, "rarp-reply") ||
1649             !strcasecmp(opt, "rarp-rep") ||
1650             !strcasecmp(opt, "rr") )
1651     *code=4;
1652   else if ( !strcasecmp(opt, "drarp-request") ||
1653             !strcasecmp(opt, "drarp") ||
1654             !strcasecmp(opt, "d") )
1655     *code=5;
1656   else if ( !strcasecmp(opt, "drarp-reply") ||
1657             !strcasecmp(opt, "drarp-rep") ||
1658             !strcasecmp(opt, "dr") )
1659     *code=6;
1660   else if ( !strcasecmp(opt, "drarp-error") ||
1661             !strcasecmp(opt, "drarp-err") ||
1662             !strcasecmp(opt, "de") )
1663     *code=7;
1664   else if ( !strcasecmp(opt, "inarp-request") ||
1665        !strcasecmp(opt, "inarp") ||
1666        !strcasecmp(opt, "i") ) /**/
1667     *code=8;
1668   else if ( !strcasecmp(opt, "inarp-reply") ||
1669        !strcasecmp(opt, "inarp-rep") ||
1670        !strcasecmp(opt, "ir") ) /**/
1671     *code=9;
1672   else if ( !strcasecmp(opt, "arp-nak") ||
1673             !strcasecmp(opt, "an") )
1674     *code=10;
1675 
1676 /*
1677   else if ( !strcasecmp(opt, "") ||
1678             !strcasecmp(opt, "") ||
1679             !strcasecmp(opt, "") )
1680     *code=;
1681 */
1682   else
1683     return OP_FAILURE;
1684 
1685  return OP_SUCCESS;
1686 } /* End of atoARPOpCode() */
1687 
1688 
1689 
1690 
atoEtherType(char * opt,u16 * type)1691 int ArgParser::atoEtherType(char *opt, u16 *type){
1692   if(type==NULL || opt==NULL)
1693     return OP_FAILURE;
1694 
1695   if ( !strcasecmp(opt, "ip") ||
1696        !strcasecmp(opt, "ipv4") ||
1697        !strcasecmp(opt, "4") ) /**/
1698     *type=0x0800;
1699   else if ( !strcasecmp(opt, "arp") )
1700     *type=0x0806;
1701   else if ( !strcasecmp(opt, "frame-relay") ||
1702             !strcasecmp(opt, "frelay") ||
1703             !strcasecmp(opt, "fr") )
1704     *type=0x0808;
1705   else if ( !strcasecmp(opt, "ppp") )
1706     *type=0x880B;
1707   else if ( !strcasecmp(opt, "gsmp") )
1708     *type=0x880C;
1709   else if ( !strcasecmp(opt, "rarp") )
1710     *type=0x8035;
1711   else if ( !strcasecmp(opt, "ipv6") ||
1712             !strcasecmp(opt, "6") ) /**/
1713     *type=0x86DD;
1714   else if ( !strcasecmp(opt, "mpls") )
1715     *type=0x8847;
1716   else if ( !strcasecmp(opt, "mps-ual") ||
1717             !strcasecmp(opt, "mps") )
1718     *type=0x8848;
1719   else if ( !strcasecmp(opt, "mcap") )
1720     *type=0x8861;
1721   else if ( !strcasecmp(opt, "pppoe-discovery")||
1722             !strcasecmp(opt, "pppoe-d") )
1723     *type=0x8863;
1724   else if ( !strcasecmp(opt, "pppoe-session")||
1725             !strcasecmp(opt, "pppoe-s") )
1726     *type=0x8864;
1727   else if ( !strcasecmp(opt, "ctag") )
1728     *type=0x8100;
1729   else if ( !strcasecmp(opt, "epon") )
1730     *type=0x8808;
1731   else if ( !strcasecmp(opt, "pbnac") )
1732     *type=0x888E;
1733   else if ( !strcasecmp(opt, "stag") )
1734     *type=0x88A8;
1735   else if ( !strcasecmp(opt, "ethexp1") )
1736     *type=0x88B5;
1737   else if ( !strcasecmp(opt, "ethexp2") )
1738     *type=0x88B6;
1739   else if ( !strcasecmp(opt, "ethoui") )
1740     *type=0x88B7;
1741   else if ( !strcasecmp(opt, "preauth") )
1742     *type=0x88C7;
1743   else if ( !strcasecmp(opt, "lldp") )
1744     *type=0x88CC;
1745   else if ( !strcasecmp(opt, "macsec") ||
1746             !strcasecmp(opt, "mac-sec") ||
1747             !strcasecmp(opt, "mac-security") )
1748     *type=0x88E5;
1749   else if ( !strcasecmp(opt, "mvrp") )
1750     *type=0x88F5;
1751   else if ( !strcasecmp(opt, "mmrp") )
1752     *type=0x88F6;
1753   else if ( !strcasecmp(opt, "frrr") )
1754     *type=0x890D;
1755 /*
1756   else if ( !strcasecmp(opt, "") ||
1757             !strcasecmp(opt, "") ||
1758             !strcasecmp(opt, "") )
1759     *type=;
1760 */
1761   else
1762     return OP_FAILURE;
1763 
1764  return OP_SUCCESS;
1765 
1766 } /* End of atoEtherType() */
1767 
1768 
1769 
1770 
parseICMPTimestamp(char * optarg,u32 * dst)1771 int ArgParser::parseICMPTimestamp(char *optarg, u32 *dst){
1772 
1773 long diff=0;
1774 
1775   if(optarg==NULL || dst==NULL)
1776     nping_fatal(QT_3, "parseICMPTimestamp(): NULL pointer supplied.");
1777 
1778   if( meansRandom(optarg) ){
1779     while( (*dst=get_random_u32()) == 0);
1780   }
1781   else if( !strncmp("now-", optarg, 4) ){
1782     if ( (diff= tval2msecs(optarg+4)) < 0 )
1783         nping_fatal(QT_3,"You must specify a valid time value after now- (e.g. 1000, 2s, 25m, etc.)");
1784     struct timeval now;
1785     gettimeofday(&now, NULL);
1786     if( ((((u32)now.tv_sec)%86400)*1000) < (u32)diff )
1787         nping_fatal(QT_3,"Value is %s is too high for current time.", optarg+4 );
1788     else
1789         *dst= ((((u32)now.tv_sec)%86400)*1000) - diff;
1790   }
1791   else if( !strncmp("now+", optarg, 4) ) {
1792     if ( (diff= tval2msecs(optarg+4)) < 0 )
1793         nping_fatal(QT_3,"You must specify a valid time value after now+ (e.g. 1000, 2s, 25m, etc.)");
1794     struct timeval now;
1795     gettimeofday(&now, NULL);
1796     if( ((((u32)now.tv_sec)%86400)*1000) + diff > 0xFFFFFFFF )
1797         nping_fatal(QT_3,"Value is %s is too high for current time.", optarg+4 );
1798     else
1799         *dst= ((((u32)now.tv_sec)%86400)*1000) + diff;
1800   }
1801   else if( !strcmp("now", optarg) ) {
1802     struct timeval now;
1803     gettimeofday(&now, NULL);
1804     *dst = ((((u32)now.tv_sec)%86400)*1000);
1805   }
1806   else {
1807     if ( (diff= tval2msecs(optarg)) == -1)
1808         nping_fatal(QT_3,"Invalid time supplied");
1809     else
1810         *dst=diff;
1811   }
1812 
1813   return OP_SUCCESS;
1814 } /* End of parseICMPTimestamp() */
1815