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