1 
2 /***************************************************************************
3  * common_modified.cc --  This file holds all those functions and classes  *
4  * that have been reused from Nmap's code but that needed to be modified   *
5  * in order to reuse them.                                                 *
6  *                                                                         *
7  ***********************IMPORTANT NMAP LICENSE TERMS************************
8  *                                                                         *
9  * The Nmap Security Scanner is (C) 1996-2020 Insecure.Com LLC ("The Nmap  *
10  * Project"). Nmap is also a registered trademark of the Nmap Project.     *
11  *                                                                         *
12  * This program is distributed under the terms of the Nmap Public Source   *
13  * License (NPSL). The exact license text applying to a particular Nmap    *
14  * release or source code control revision is contained in the LICENSE     *
15  * file distributed with that version of Nmap or source code control       *
16  * revision. More Nmap copyright/legal information is available from       *
17  * https://nmap.org/book/man-legal.html, and further information on the    *
18  * NPSL license itself can be found at https://nmap.org/npsl. This header  *
19  * summarizes some key points from the Nmap license, but is no substitute  *
20  * for the actual license text.                                            *
21  *                                                                         *
22  * Nmap is generally free for end users to download and use themselves,    *
23  * including commercial use. It is available from https://nmap.org.        *
24  *                                                                         *
25  * The Nmap license generally prohibits companies from using and           *
26  * redistributing Nmap in commercial products, but we sell a special Nmap  *
27  * OEM Edition with a more permissive license and special features for     *
28  * this purpose. See https://nmap.org/oem                                  *
29  *                                                                         *
30  * If you have received a written Nmap license agreement or contract       *
31  * stating terms other than these (such as an Nmap OEM license), you may   *
32  * choose to use and redistribute Nmap under those terms instead.          *
33  *                                                                         *
34  * The official Nmap Windows builds include the Npcap software             *
35  * (https://npcap.org) for packet capture and transmission. It is under    *
36  * separate license terms which forbid redistribution without special      *
37  * permission. So the official Nmap Windows builds may not be              *
38  * redistributed without special permission (such as an Nmap OEM           *
39  * license).                                                               *
40  *                                                                         *
41  * Source is provided to this software because we believe users have a     *
42  * right to know exactly what a program is going to do before they run it. *
43  * This also allows you to audit the software for security holes.          *
44  *                                                                         *
45  * Source code also allows you to port Nmap to new platforms, fix bugs,    *
46  * and add new features.  You are highly encouraged to submit your         *
47  * changes as a Github PR or by email to the dev@nmap.org mailing list     *
48  * for possible incorporation into the main distribution. Unless you       *
49  * specify otherwise, it is understood that you are offering us very       *
50  * broad rights to use your submissions as described in the Nmap Public    *
51  * Source License Contributor Agreement. This is important because we      *
52  * fund the project by selling licenses with various terms, and also       *
53  * because the inability to relicense code has caused devastating          *
54  * problems for other Free Software projects (such as KDE and NASM).       *
55  *                                                                         *
56  * The free version of Nmap is distributed in the hope that it will be     *
57  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of  *
58  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,        *
59  * indemnification and commercial support are all available through the    *
60  * Npcap OEM program--see https://nmap.org/oem.                            *
61  *                                                                         *
62  ***************************************************************************/
63 #include "nping.h"
64 #include "common.h"
65 #include "common_modified.h"
66 #include "output.h"
67 #include "../libnetutil/netutil.h"
68 /*****************************************************************************
69   * STUFF FROM TargetGroup.cc
70   ****************************************************************************
71 
72   CHANGES:
73        Modified parse_expr.
74        Modified get_next_host:
75 
76 */
77 
78 
TargetGroup()79 TargetGroup::TargetGroup() {
80   Initialize();
81 }
82 
83 // Bring back (or start with) original state
Initialize()84 void TargetGroup::Initialize() {
85   targets_type = TYPE_NONE;
86   memset(addresses, 0, sizeof(addresses));
87   memset(current, 0, sizeof(current));
88   memset(last, 0, sizeof(last));
89   ipsleft = 0;
90 }
91 
92 /* take the object back to the beginning without  (mdmcl)
93  * reinitializing the data structures */
rewind()94 int TargetGroup::rewind() {
95 
96   /* For netmasks we must set the current address to the
97    * starting address and calculate the ips by distance */
98   if (targets_type == IPV4_NETMASK) {
99     currentaddr = startaddr;
100     if (startaddr.s_addr <= endaddr.s_addr) {
101       ipsleft = ((unsigned long long) (endaddr.s_addr - startaddr.s_addr)) + 1;
102       return 0;
103     }
104     else
105       assert(0);
106   }
107   /* For ranges, we easily set current to zero and calculate
108    * the ips by the number of values in the columns */
109   else if (targets_type == IPV4_RANGES) {
110     memset((char *)current, 0, sizeof(current));
111     ipsleft = (unsigned long long) (last[0] + 1) *
112               (unsigned long long) (last[1] + 1) *
113               (unsigned long long) (last[2] + 1) *
114               (unsigned long long) (last[3] + 1);
115     return 0;
116   }
117 #if HAVE_IPV6
118   /* For IPV6 there is only one address, this function doesn't
119    * make much sense for IPv6 does it? */
120   else if (targets_type == IPV6_ADDRESS) {
121     ipsleft = 1;
122     return 0;
123   }
124 #endif
125 
126   /* If we got this far there must be an error, wrong type */
127   return -1;
128 }
129 
130 
131 
132 /* For ranges, skip all hosts in an octet,                  (mdmcl)
133  * get_next_host should be used for skipping the last octet :-)
134  * returns: number of hosts skipped */
skip_range(_octet_nums octet)135 int TargetGroup::skip_range(_octet_nums octet) {
136    u32 hosts_skipped = 0, /* number of hosts skipped */
137       oct = 0;           /* octect number */
138       int i = 0;                 /* simple lcv */
139 
140   /* This function is only supported for RANGES! */
141   if (targets_type != IPV4_RANGES)
142     return -1;
143 
144   switch (octet) {
145     case FIRST_OCTET:
146       oct = 0;
147       hosts_skipped = (u32)(last[1] + 1) * (last[2] + 1) * (last[3] + 1);
148       break;
149     case SECOND_OCTET:
150       oct = 1;
151       hosts_skipped = (u32)(last[2] + 1) * (last[3] + 1);
152       break;
153     case THIRD_OCTET:
154       oct = 2;
155       hosts_skipped = (last[3] + 1);
156       break;
157     default:  /* Hmm, how did you do that? */
158       return -1;
159   }
160 
161   /* catch if we try to take more than are left */
162   assert(ipsleft + 1>= hosts_skipped);
163 
164   /* increment the next octect that we can above us */
165   for (i = oct; i >= 0; i--) {
166     if (current[i] < last[i]) {
167       current[i]++;
168       break;
169     }
170     else
171       current[i] = 0;
172   }
173 
174   /* reset all the ones below us to zero */
175   for (i = oct+1; i <= 3; i++) {
176     current[i] = 0;
177   }
178 
179   /* we actually don't skip the current, it was accounted for
180    * by get_next_host */
181   ipsleft -= hosts_skipped - 1;
182 
183   return hosts_skipped;
184 }
185 
186  /* Grab the next host from this expression (if any) and updates its internal
187     state to reflect that the IP was given out.  Returns 0 and
188     fills in ss if successful.  ss must point to a pre-allocated
189     sockaddr_storage structure */
get_next_host(struct sockaddr_storage * ss,size_t * sslen)190 int TargetGroup::get_next_host(struct sockaddr_storage *ss, size_t *sslen) {
191 
192   int octet;
193   struct sockaddr_in *sin = (struct sockaddr_in *) ss;
194   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss;
195 
196   /* CHANGE: Commented out. See note at the end of the method */
197   //startover: /* to handle nmap --resume where I have already
198   //            * scanned many of the IPs */
199   assert(ss);
200   assert(sslen);
201 
202 
203   if (ipsleft == 0)
204     return -1;
205 
206   if (targets_type == IPV4_NETMASK) {
207     memset(sin, 0, sizeof(struct sockaddr_in));
208     sin->sin_family = AF_INET;
209     *sslen = sizeof(struct sockaddr_in);
210 #if HAVE_SOCKADDR_SA_LEN
211     sin->sin_len = *sslen;
212 #endif
213 
214     if (currentaddr.s_addr <= endaddr.s_addr) {
215       sin->sin_addr.s_addr = htonl(currentaddr.s_addr++);
216     } else {
217       error("Bogus target structure passed to %s", __func__);
218       ipsleft = 0;
219       return -1;
220     }
221   }
222   else if (targets_type == IPV4_RANGES) {
223     memset(sin, 0, sizeof(struct sockaddr_in));
224     sin->sin_family = AF_INET;
225     *sslen = sizeof(struct sockaddr_in);
226 #if HAVE_SOCKADDR_SA_LEN
227     sin->sin_len = *sslen;
228 #endif
229     //if (o.debugging > 2) { /* CHANGE: Do not use NmapOps and do not use log_Write*/
230     //  log_write(LOG_STDOUT, "doing %d.%d.%d.%d = %d.%d.%d.%d\n", current[0], current[1], current[2], current[3], addresses[0][current[0]],addresses[1][current[1]],addresses[2][current[2]],addresses[3][current[3]]);
231     //}
232     //nping_print(DBG_2, "doing %d.%d.%d.%d = %d.%d.%d.%d", current[0], current[1], current[2], current[3], addresses[0][current[0]],addresses[1][current[1]],addresses[2][current[2]],addresses[3][current[3]]);
233 
234 
235     /* Set the IP to the current value of everything */
236     sin->sin_addr.s_addr = htonl(addresses[0][current[0]] << 24 |
237                                  addresses[1][current[1]] << 16 |
238                                  addresses[2][current[2]] <<  8 |
239                                  addresses[3][current[3]]);
240 
241     /* Now we nudge up to the next IP */
242     for(octet = 3; octet >= 0; octet--) {
243       if (current[octet] < last[octet]) {
244         /* OK, this is the column I have room to nudge upwards */
245         current[octet]++;
246         break;
247       } else {
248         /* This octet is finished so I reset it to the beginning */
249         current[octet] = 0;
250       }
251     }
252     if (octet == -1) {
253       /* It didn't find anything to bump up, I must have taken the last IP */
254       assert(ipsleft == 1);
255       /* So I set current to last with the very final octet up one ... */
256       /* Note that this may make current[3] == 256 */
257       current[0] = last[0]; current[1] = last[1];
258       current[2] = last[2]; current[3] = last[3] + 1;
259     } else {
260       assert(ipsleft > 1); /* There must be at least one more IP left */
261     }
262   } else {
263     assert(targets_type == IPV6_ADDRESS);
264     assert(ipsleft == 1);
265 #if HAVE_IPV6
266     *sslen = sizeof(struct sockaddr_in6);
267     memset(sin6, 0, *sslen);
268     sin6->sin6_family = AF_INET6;
269 #ifdef SIN_LEN
270     sin6->sin6_len = *sslen;
271 #endif /* SIN_LEN */
272     memcpy(sin6->sin6_addr.s6_addr, ip6.sin6_addr.s6_addr, 16);
273     sin6->sin6_scope_id = ip6.sin6_scope_id;
274 #else
275     fatal("IPV6 not supported on this platform");
276 #endif // HAVE_IPV6
277   }
278   ipsleft--;
279 
280 
281   /* CHANGE: These lines have been commented out to make this code
282    * independent from NmapOps  */
283   /* If we are resuming from a previous scan, we have already finished
284      scans up to o.resume_ip.  */
285  // if (sin->sin_family == AF_INET && o.resume_ip.s_addr) {
286  //   if (o.resume_ip.s_addr == sin->sin_addr.s_addr)
287  //     o.resume_ip.s_addr = 0; /* So that we will KEEP the next one */
288  //   goto startover; /* Try again */
289  // }
290 
291   return 0;
292 }
293 
294 /* Returns the last given host, so that it will be given again next
295      time get_next_host is called.  Obviously, you should only call
296      this if you have fetched at least 1 host since parse_expr() was
297      called */
return_last_host()298 int TargetGroup::return_last_host() {
299   int octet;
300 
301   ipsleft++;
302   if (targets_type == IPV4_NETMASK) {
303     assert(currentaddr.s_addr > startaddr.s_addr);
304     currentaddr.s_addr--;
305   } else if (targets_type == IPV4_RANGES) {
306     for(octet = 3; octet >= 0; octet--) {
307       if (current[octet] > 0) {
308         /* OK, this is the column I have room to nudge downwards */
309         current[octet]--;
310         break;
311       } else {
312         /* This octet is already at the beginning, so I set it to the end */
313         current[octet] = last[octet];
314       }
315     }
316     assert(octet != -1);
317   } else {
318     assert(targets_type == IPV6_ADDRESS);
319     assert(ipsleft == 1);
320   }
321   return 0;
322 }
323 
324 
325 
326 
327 
328 /* TODO: WARNING: This functions has been modified for portability. Check
329  * for label "CHANGE:" in the code to see the actual changes.
330  *
331  * UPDATE: Added support for DNS resolution caching. Using function
332  * gethostbynameCached() instead of gethostbyname()
333  */
334  /* Initializes (or reinitializes) the object with a new expression, such
335     as 192.168.0.0/16 , 10.1.0-5.1-254 , or fe80::202:e3ff:fe14:1102 .
336     Returns 0 for success */
parse_expr(const char * const target_expr,int af)337 int TargetGroup::parse_expr(const char * const target_expr, int af) {
338 
339   int i=0,j=0,k=0;
340   int start, end;
341   char *r,*s, *target_net;
342   char *addy[5];
343   char *hostexp = strdup(target_expr);
344   struct hostent *target;
345   namedhost = 0;
346 
347   if (targets_type != TYPE_NONE)
348     Initialize();
349 
350   ipsleft = 0;
351 
352   if (af == AF_INET) {
353 
354     if (strchr(hostexp, ':'))
355       fatal("Invalid host expression: %s -- colons only allowed in IPv6 addresses, and then you need the -6 switch", hostexp);
356 
357     /*struct in_addr current_in;*/
358     addy[0] = addy[1] = addy[2] = addy[3] = addy[4] = NULL;
359     addy[0] = r = hostexp;
360     /* First we break the expression up into the four parts of the IP address
361        + the optional '/mask' */
362     target_net = hostexp;
363     s = strchr(hostexp, '/'); /* Find the slash if there is one */
364     if (s) {
365       char *tail;
366       long netmask_long;
367 
368       *s = '\0';  /* Make sure target_net is terminated before the /## */
369       s++;        /* Point s at the netmask */
370       if (!isdigit(*s)) {
371         error("Illegal netmask value, must be /0 - /32 .  Assuming /32 (one host)");
372         netmask = 32;
373       } else {
374         netmask_long = strtol(s, (char**) &tail, 10);
375         if (*tail != '\0' || tail == s || netmask_long < 0 || netmask_long > 32) {
376           error("Illegal netmask value, must be /0 - /32 .  Assuming /32 (one host)");
377           netmask = 32;
378         } else
379           netmask = (u32) netmask_long;
380       }
381     } else
382       netmask = 32;
383     for(i=0; *(hostexp + i); i++)
384       if (isupper((int) *(hostexp +i)) || islower((int) *(hostexp +i))) {
385         namedhost = 1;
386         break;
387       }
388     if (netmask != 32 || namedhost) {
389       targets_type = IPV4_NETMASK;
390       if (!inet_pton(AF_INET, target_net, &(startaddr))) {
391 
392         /* There is a bug report on the use of gethostbynameCached()
393          * <http://seclists.org/nmap-dev/2010/q1/803>
394          * I haven't been able to find any problem with that code but
395          * still, the fact that DNS queries are cached does not improve
396          * performance a lot. It may save one DNS query per execution
397          * in those cases where NpingOps::validateOptions() grabs the
398          * first target and uses it to determine output network interface.
399          * It would also save some queries in the case where a user
400          * specified the same host twice in the commandlined, something
401          * that does not make much sense anyway. However, since the call
402          * to gethostbynameCached() seems to cause denial of service
403          * for some people, I think it's ok to disable its use for now
404          * and enable it later if there is a good reason for it.
405          *
406          * Luis MartinGarcia. */
407         //if ((target = gethostbynameCached(target_net))) {
408         if ((target = gethostbyname(target_net))) {
409           int count=0;
410 
411           memcpy(&(startaddr), target->h_addr_list[0], sizeof(struct in_addr));
412 
413           while (target->h_addr_list[count]) count++;
414 
415           if (count > 1)
416              nping_print(DBG_2,"Warning: Hostname %s resolves to %d IPs. Using %s.", target_net, count, inet_ntoa(*((struct in_addr *)target->h_addr_list[0])));
417         } else {
418           error("Failed to resolve given hostname/IP: %s.  Note that you can't use '/mask' AND '1-4,7,100-' style IP ranges", target_net);
419           free(hostexp);
420           return 1;
421         }
422       }
423       if (netmask) {
424         unsigned long longtmp = ntohl(startaddr.s_addr);
425         startaddr.s_addr = longtmp & (unsigned long) (0 - (1<<(32 - netmask)));
426         endaddr.s_addr = longtmp | (unsigned long)  ((1<<(32 - netmask)) - 1);
427       } else {
428         /* The above calculations don't work for a /0 netmask, though at first
429          * glance it appears that they would
430          */
431         startaddr.s_addr = 0;
432         endaddr.s_addr = 0xffffffff;
433       }
434       currentaddr = startaddr;
435       if (startaddr.s_addr <= endaddr.s_addr) {
436         ipsleft = ((unsigned long long) (endaddr.s_addr - startaddr.s_addr)) + 1;
437         free(hostexp);
438         return 0;
439       }
440       fprintf(stderr, "Host specification invalid");
441       free(hostexp);
442       return 1;
443     }
444     else {
445       targets_type = IPV4_RANGES;
446       i=0;
447 
448       while(*r) {
449         if (*r == '.' && ++i < 4) {
450           *r = '\0';
451           addy[i] = r + 1;
452         }
453         else if (*r != '*' && *r != ',' && *r != '-' && !isdigit((int)*r))
454           fatal("Invalid character in host specification.  Note in particular that square brackets [] are no longer allowed.  They were redundant and can simply be removed.");
455         r++;
456       }
457       if (i != 3) fatal("Invalid target host specification: %s", target_expr);
458 
459       for(i=0; i < 4; i++) {
460         j=0;
461         do {
462           s = strchr(addy[i],',');
463           if (s) *s = '\0';
464           if (*addy[i] == '*') { start = 0; end = 255; }
465           else if (*addy[i] == '-') {
466             start = 0;
467             if (*(addy[i] + 1) == '\0') end = 255;
468             else end = atoi(addy[i]+ 1);
469           }
470           else {
471             start = end = atoi(addy[i]);
472             if ((r = strchr(addy[i],'-')) && *(r+1) ) end = atoi(r + 1);
473             else if (r && !*(r+1)) end = 255;
474           }
475        /* if (o.debugging > 2)
476         *   log_write(LOG_STDOUT, "The first host is %d, and the last one is %d\n", start, end); */
477           if (start < 0 || start > end || start > 255 || end > 255)
478             fatal("Your host specifications are illegal!");
479           if (j + (end - start) > 255)
480             fatal("Your host specifications are illegal!");
481           for(k=start; k <= end; k++)
482             addresses[i][j++] = k;
483           last[i] = j-1;
484           if (s) addy[i] = s + 1;
485         } while (s);
486       }
487     }
488     memset((char *)current, 0, sizeof(current));
489     ipsleft = (unsigned long long) (last[0] + 1) *
490               (unsigned long long) (last[1] + 1) *
491               (unsigned long long) (last[2] + 1) *
492               (unsigned long long) (last[3] + 1);
493     }
494   else {
495 #if HAVE_IPV6
496     int rc = 0;
497     assert(af == AF_INET6);
498     if (strchr(hostexp, '/')) {
499       fatal("Invalid host expression: %s -- slash not allowed.  IPv6 addresses can currently only be specified individually", hostexp);
500     }
501     targets_type = IPV6_ADDRESS;
502     struct addrinfo hints;
503     struct addrinfo *result = NULL;
504     memset(&hints, 0, sizeof(hints));
505     hints.ai_family = PF_INET6;
506     rc = getaddrinfo(hostexp, NULL, &hints, &result);
507     if (rc != 0 || result == NULL) {
508       error("Failed to resolve given IPv6 hostname/IP: %s.  Note that you can't use '/mask' or '[1-4,7,100-]' style ranges for IPv6.  Error code %d: %s", hostexp, rc, gai_strerror(rc));
509       free(hostexp);
510       if (result) freeaddrinfo(result);
511       return 1;
512     }
513     assert(result->ai_addrlen == sizeof(struct sockaddr_in6));
514     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) result->ai_addr;
515     memcpy(&ip6, sin6, sizeof(struct sockaddr_in6));
516     ipsleft = 1;
517     freeaddrinfo(result);
518 #else // HAVE_IPV6
519     fatal("IPv6 not supported on your platform");
520 #endif // HAVE_IPV6
521   }
522 
523   free(hostexp);
524   return 0;
525 }
526 
527 /*****************************************************************************/
528 /* getpts() and getpts_simple() (see above) are wrappers for this function */
getpts_aux(const char * origexpr,int nested,u8 * porttbl,int * portwarning)529 void getpts_aux(const char *origexpr, int nested, u8 *porttbl, int *portwarning) {
530   long rangestart = -2343242, rangeend = -9324423;
531   const char *current_range;
532   char *endptr;
533   //char servmask[128];  // A protocol name can be up to 127 chars + nul byte
534   //int i;
535 
536   /* An example of proper syntax to use in error messages. */
537   const char *syntax_example;
538   //if (change_range_type)
539   //  syntax_example = "-100,200-1024,T:3000-4000,U:60000-";
540   //else
541     syntax_example = "-100,200-1024,3000-4000,60000-";
542 
543   current_range = origexpr;
544   do {
545     while(isspace((int) *current_range))
546       current_range++; /* I don't know why I should allow spaces here, but I will */
547 
548     //if (change_range_type) {
549       //if (*current_range == 'T' && *++current_range == ':') {
550           //current_range++;
551           //range_type = SCAN_TCP_PORT;
552           //continue;
553       //}
554       //if (*current_range == 'U' && *++current_range == ':') {
555           //current_range++;
556           //range_type = SCAN_UDP_PORT;
557           //continue;
558       //}
559       //if (*current_range == 'S' && *++current_range == ':') {
560           //current_range++;
561           //range_type = SCAN_SCTP_PORT;
562           //continue;
563       //}
564       //if (*current_range == 'P' && *++current_range == ':') {
565           //current_range++;
566           //range_type = SCAN_PROTOCOLS;
567           //continue;
568       //}
569     //}
570 
571     if (*current_range == '[') {
572       if (nested)
573         fatal("Can't nest [] brackets in port/protocol specification");
574 
575       //getpts_aux(++current_range, 1, porttbl, range_type, portwarning);
576         getpts_aux(++current_range, 1, porttbl, portwarning); // ADDED
577 
578       // Skip past the ']'. This is OK because we can't nest []s
579       while(*current_range != ']') current_range++;
580       current_range++;
581 
582       // Skip over a following ',' so we're ready to keep parsing
583       if (*current_range == ',') current_range++;
584 
585       continue;
586     } else if (*current_range == ']') {
587       if (!nested)
588         fatal("Unexpected ] character in port/protocol specification");
589 
590       return;
591     } else if (*current_range == '-') {
592       //if (range_type & SCAN_PROTOCOLS)
593       //  rangestart = 0;
594       //else
595         rangestart = 1;
596     }
597     else if (isdigit((int) *current_range)) {
598       rangestart = strtol(current_range, &endptr, 10);
599       //if (range_type & SCAN_PROTOCOLS) {
600       //  if (rangestart < 0 || rangestart > 255)
601 	  //fatal("Protocols to be scanned must be between 0 and 255 inclusive");
602       //} else {
603         if (rangestart < 0 || rangestart > 65535)
604 	        fatal("Ports to be scanned must be between 0 and 65535 inclusive");
605       //}
606       current_range = endptr;
607       while(isspace((int) *current_range)) current_range++;
608     } //else if (islower((int) *current_range) || *current_range == '*' || *current_range == '?') {
609       //i = 0;
610 
611       //while (*current_range && !isspace((int)*current_range) && *current_range != ',' && *current_range != ']') {
612       //  servmask[i++] = *(current_range++);
613       //  if (i >= ((int)sizeof(servmask)-1))
614       //    fatal("A service mask in the port/protocol specification is either malformed or too long");
615      // }
616 
617      // if (*current_range && *current_range != ']') current_range++; // We want the '] character to be picked up on the next pass
618      // servmask[i] = '\0'; // Finish the string
619 
620       //i = addportsfromservmask(servmask, porttbl, range_type);
621       //if (range_type & SCAN_PROTOCOLS) i += addprotocolsfromservmask(servmask, porttbl);
622 
623       //if (i == 0)
624       //  fatal("Found no matches for the service mask '%s' and your specified protocols", servmask);
625 
626       //continue;
627 
628     /*}*/ else {
629       fatal("Error #485: Your port specifications are illegal.  Example of proper form: \"%s\"", syntax_example);
630     }
631     /* Now I have a rangestart, time to go after rangeend */
632     if (!*current_range || *current_range == ',' || *current_range == ']') {
633       /* Single port specification */
634       rangeend = rangestart;
635     } else if (*current_range == '-') {
636       current_range++;
637       if (!*current_range || *current_range == ',' || *current_range == ']') {
638 	/* Ended with a -, meaning up until the last possible port */
639         //if (range_type & SCAN_PROTOCOLS)
640         //  rangeend = 255;
641         //else
642           rangeend = 65535;
643       } else if (isdigit((int) *current_range)) {
644 	rangeend = strtol(current_range, &endptr, 10);
645    //     if (range_type & SCAN_PROTOCOLS) {
646 //	  if (rangeend < 0 || rangeend > 255)
647 //	    fatal("Protocols to be scanned must be between 0 and 255 inclusive");
648 //	} else {
649 	  if (rangeend < 0 || rangeend > 65535)
650 	    fatal("Ports to be scanned must be between 0 and 65535 inclusive");
651 //	}
652 	current_range = endptr;
653       } else {
654 	fatal("Error #486: Your port specifications are illegal.  Example of proper form: \"%s\"", syntax_example);
655       }
656       if (rangeend < rangestart) {
657         //fatal("Your %s range %ld-%ld is backwards. Did you mean %ld-%ld?",
658         //  (range_type & SCAN_PROTOCOLS) ? "protocol" : "port",
659         //  rangestart, rangeend, rangeend, rangestart);
660         fatal("Your port range %ld-%ld is backwards. Did you mean %ld-%ld?",
661           rangestart, rangeend, rangeend, rangestart);     // ADDED
662 
663 
664       }
665     } else {
666 	fatal("Error #487: Your port specifications are illegal.  Example of proper form: \"%s\"", syntax_example);
667     }
668 
669     /* Now I have a rangestart and a rangeend, so I can add these ports */
670     while(rangestart <= rangeend) {
671       if (porttbl[rangestart]) {
672         if (!(*portwarning)) {
673 	        error("WARNING: Duplicate port number(s) specified.  Are you alert enough to be using Nping?  Have some coffee or grab a RedBull(tm).");
674             (*portwarning)++;
675 	    }
676       } else {
677         //if (nested) {
678           //if ((range_type & SCAN_TCP_PORT) &&
679               //nmap_getservbyport(rangestart, "tcp")) {
680             //porttbl[rangestart] |= SCAN_TCP_PORT;
681           //}
682           //if ((range_type & SCAN_UDP_PORT) &&
683               //nmap_getservbyport(rangestart, "udp")) {
684             //porttbl[rangestart] |= SCAN_UDP_PORT;
685           //}
686           //if ((range_type & SCAN_SCTP_PORT) &&
687               //nmap_getservbyport(rangestart, "sctp")) {
688             //porttbl[rangestart] |= SCAN_SCTP_PORT;
689           //}
690           //if ((range_type & SCAN_PROTOCOLS) &&
691               //nmap_getprotbynum(rangestart)) {
692             //porttbl[rangestart] |= SCAN_PROTOCOLS;
693           //}
694         //} else {
695           //porttbl[rangestart] |= range_type;
696         //}
697 
698          porttbl[rangestart]=1; // ADDED for NPING
699       }
700       rangestart++;
701     }
702 
703     /* Find the next range */
704     while(isspace((int) *current_range)) current_range++;
705 
706     if (*current_range == ']') {
707       if (!nested) fatal("Unexpected ] character in port specification");
708       return;
709     }
710 
711     if (*current_range && *current_range != ',') {
712       fatal("Error #488: Your port specifications are illegal.  Example of proper form: \"%s\"", syntax_example);
713     }
714     if (*current_range == ',')
715       current_range++;
716   } while(current_range && *current_range);
717 
718 }
719 /*****************************************************************************/
720 
721 
722 
723 
724 
725 
726 
727 
728 
729 
730 
731 
732 
733 
734 
735 
736 /* For systems without SCTP in netinet/in.h, such as MacOS X */
737 #ifndef IPPROTO_SCTP
738 #define IPPROTO_SCTP 132
739 #endif
740 
741 
742 
743 
744 /* IPv6 compatible version of Nmap's devname2ipaddr()
745  * @warning For this to work we need getinterfaces() not to skip IPv6 */
devname2ipaddr_alt(char * dev,struct sockaddr_storage * addr)746 int devname2ipaddr_alt(char *dev, struct sockaddr_storage *addr) {
747 struct interface_info *mydevs;
748 struct sockaddr_storage *s=NULL;
749 struct sockaddr_in *s4=NULL;
750 struct sockaddr_in6 *s6=NULL;
751 int numdevs;
752 int i;
753 mydevs = getinterfaces(&numdevs, NULL, 0);
754 
755 if (!mydevs) return -1;
756 
757 if( !addr || !dev )
758     fatal("devname2ipaddr(): NULL values supplied.");
759 
760   for(i=0; i < numdevs; i++) {
761     s=(struct sockaddr_storage *)&mydevs[i].addr;
762     s4=(struct sockaddr_in *)&mydevs[i].addr;
763     s6=(struct sockaddr_in6 *)&mydevs[i].addr;
764     if (s4->sin_family==AF_INET || s6->sin6_family==AF_INET6){
765         if (!strcmp(dev, mydevs[i].devfullname)) {
766             memcpy(addr, s, sizeof(struct sockaddr_storage));
767             return 0;
768         }
769     } else{ /* Unknown family, skipping it... */
770       continue;
771     }
772   }
773   return -1;
774 
775 } /* End of devname2ipaddr() */
776 
777 
778 
779 
780 
781 
782 
783 
784 
785