1package Nmap::Scanner::Scanner;
2
3use File::Spec;
4use Nmap::Scanner::Backend::XML;
5use LWP::UserAgent;
6use File::Temp;
7use strict;
8
9=pod
10
11=head1 DESCRIPTION
12
13This is the primary class of this module; it is the driver for
14the Nmap::Scanner hierarchy.  To use it, create an instance of
15Nmap::Scanner, possibly set the path to Nmap with nmap_location()
16(the default behaviour of this class is to search for nmap in
17the PATH variable.
18
19my $nmap = new Nmap::Scanner();
20$nmap->nmap_location('/usr/local/bin/nmap');
21
22Set any options you wish to use in order to run the scan in either
23batch or event mode, and then call scan() to start scanning.  The
24results are return in an Nmap::Scanner::Backend::Results object.
25
26my $results = $nmap->scan();
27
28For information on the options presented below, see the man page for
29nmap or go to http://www.insecure.org/nmap/.
30
31=head2 NOTE
32
33Some descriptions of methods here are taken directly from the nmap
34man page.
35
36=head2 EXAMPLE
37
38See examples/ directory in the distribution for many more)
39
40  use Nmap::Scanner;
41  my $scan = Nmap::Scanner->new();
42
43  $scan->add_target('localhost');
44  $scan->add_target('host.i.administer');
45  $scan->add_scan_port('1-1024');
46  $scan->add_scan_port('31337');
47  $scan->tcp_syn_scan();
48  $scan->noping();
49
50  my $results = $scan->scan();
51
52  my $hosts = $results->gethostlist();
53
54  while (my $host = $hosts->get_next()) {
55
56      print "On " . $host->hostname() . ": \n";
57
58      my $ports = $host->get_port_list();
59
60      while (my $port = $ports->get_next()) {
61          print join(' ',
62              'Port',
63              $port->service() . '/' . $port->portid(),
64              'is in state',
65              $port->state(),
66              "\n"
67          );
68      }
69
70  }
71
72=cut
73
74sub new {
75    my $class = shift;
76    my $you = { OPTS => {'-oX' => '-'}, DEBUG => 0};
77    return bless $you, $class;
78}
79
80=pod
81
82=head2 SCAN EVENTS
83
84Register for any of the below events if you wish to use Nmap::Scanner
85in event-driven mode.
86
87=head2 register_scan_complete_event(\&host_done)
88
89Register for this event to be notified when a scan of a
90host is complete.  Pass in a function reference that can
91accept a $self object reference and a reference to an
92Nmap::Scanner::Host object.
93
94host_done($self, $host);
95
96
97=cut
98
99sub register_scan_complete_event {
100    $_[0]->{'SCAN_COMPLETE_EVENT'} = [$_[0], $_[1]];
101    return $_[0];
102}
103
104=pod
105
106=head2 register_scan_started_event(\&scan_started);
107
108Register for this event to be notified when nmap has started to
109scan one of the targets specified in add_target.  Pass in a
110function reference that can accept a $self object reference,
111and a reference to an Nmap::Scanner::Host object.
112
113scan_started($self, $host);
114
115=cut
116
117sub register_scan_started_event {
118    $_[0]->{'SCAN_STARTED_EVENT'} = [$_[0], $_[1]];
119    return $_[0];
120}
121
122=pod
123
124=head2 register_host_closed_event(\&host_closed);
125
126Register to be notified if a scanned host is found to
127be closed (no open ports).  Pass in a function reference
128that can take an $self object reference and a reference to
129a Host object.
130
131XXX --- TBD (not implemented yet).
132
133host_closed($self, $host);
134
135=cut
136
137sub register_host_closed_event {
138    $_[0]->{'HOST_CLOSED_EVENT'} = [$_[0], $_[1]];
139    return $_[0];
140}
141
142=pod
143
144=head2 register_port_found_event(\&port_found);
145
146Register to be notified when a port is scanned on a host.  The
147port may be in any state ... closed, open, filtered.  Pass a
148reference to a function that takes a $self object reference,
149a Host reference, and a Port reference.
150
151port_found($self, $host, $port);
152
153=cut
154
155sub register_port_found_event {
156    $_[0]->{'PORT_FOUND_EVENT'} = [$_[0], $_[1]];
157    return $_[0];
158}
159
160=pod
161
162=head2 register_no_ports_open_event(\&port_found);
163
164Register to be notified in the event that no ports are found
165to be open on a host.  Pass in a reference to a function that
166takes a $self object reference, a Host reference, and a reference
167to an ExtraPorts object.  The ExtraPorts object describes ports
168that are in a state other than open (e.g. flitered, closed).
169
170port_found($self, $host, $extra_ports);
171
172=cut
173
174#  Function pointer that receives host name, IP, and status of all ports
175sub register_no_ports_open_event {
176    $_[0]->{'NO_PORTS_OPEN_EVENT'} = [$_[0], $_[1]];
177    return $_[0];
178}
179
180=head2 register_task_started_event(\&task_begin);
181
182Register to be notified when an internal nmap task starts.
183Pass in a reference to a function that takes a $self object
184reference and an Nmap::Scanner::Task reference.  Note that
185end_time() will be undefined in the Task instance as this is
186a begin event.
187
188task_begin($self, $task);
189
190=cut
191
192#  Function pointer that receives Nmap::Scanner::Task instance
193sub register_task_started_event {
194    $_[0]->{'TASK_STARTED_EVENT'} = [$_[0], $_[1]];
195    return $_[0];
196}
197
198=head2 register_task_ended_event(\&task_end);
199
200Register to be notified when an internal nmap task ends.
201Pass in a reference to a function that takes a $self object
202reference and an Nmap::Scanner::Task reference.
203
204task_end($self, $task);
205
206=cut
207
208#  Function pointer that receives Nmap::Scanner::Task instance
209sub register_task_ended_event {
210    $_[0]->{'TASK_ENDED_EVENT'} = [$_[0], $_[1]];
211    return $_[0];
212}
213
214=head2 register_task_progress_event(\&task_progress);
215
216Register to be notified when an internal nmap task progress
217event is fired; this happens when a task takes more than a
218few seconds to complete (good for GUIs).
219
220Pass in a reference to a function that takes a $self object
221reference and an Nmap::Scanner::TaskProgress reference.
222
223task_progress($self, $task_progress);
224
225=cut
226
227#  Function pointer that receives Nmap::Scanner::Task instance
228sub register_task_progress_event {
229    $_[0]->{'TASK_PROGRESS_EVENT'} = [$_[0], $_[1]];
230    return $_[0];
231}
232
233=pod
234
235=head2 debug()
236
237Set this to a non-zero value to see debugging output.
238
239=cut
240
241sub debug {
242    (defined $_[1]) ? ($_[0]->{DEBUG} = $_[1]) : return $_[0]->{DEBUG};
243}
244
245=pod
246
247=head2 norun()
248
249Set this to non-zero to have Nmap::Scanner::Scanner print the
250nmap command line and exit when scan() is called.
251
252=cut
253
254sub norun {
255    $_[0]->{'NORUN'} = $_[1];
256    return $_[0];
257}
258
259=pod
260
261=head2 use_interface()
262
263specify the network interface that nmap should use for scanning
264
265=cut
266
267sub use_interface {
268    $_[0]->{OPTS}->{'-e'} = $_[1];
269    return $_[0];
270}
271
272=pod
273
274=head2 SCAN TYPES
275
276See the nmap man page for descriptions of all these.
277
278=head2 tcp_connect_scan()
279
280=head2 tcp_syn_scan()
281
282=head2 fin_scan()
283
284=head2 xmas_scan()
285
286=head2 null_scan()
287
288=head2 ping_scan()
289
290=head2 udp_scan()
291
292=head2 protocol_scan()
293
294If this scan is used, the protocols can be retrieved from
295the Nmap::Scanner::Host objects using the method
296get_protocol_list(); this method returns a list of
297Nmap::Scanner::Port object references of type 'ip.'
298
299=head2 idle_scan($zombie_host, $probe_port)
300
301=head2 ack_scan()
302
303=head2 window_scan()
304
305=head2 version_scan($intestity)
306
307=head2 rpc_scan()
308
309=cut
310
311sub tcp_connect_scan {
312    $_[0]->{TYPE} = 'T';
313    return $_[0];
314}
315
316sub tcp_syn_scan {
317    $_[0]->{TYPE} = 'S';
318    return $_[0];
319}
320
321sub fin_scan {
322    $_[0]->{TYPE} = 'F';
323    return $_[0];
324}
325
326sub xmas_scan {
327    $_[0]->{TYPE} = 'X';
328    return $_[0];
329}
330
331sub null_scan {
332    $_[0]->{TYPE} = 'N';
333    return $_[0];
334}
335
336sub ping_scan {
337    $_[0]->{TYPE} = 'P';
338}
339
340sub udp_scan {
341    $_[0]->{UDPSCAN} = 'U';
342    return $_[0];
343}
344
345sub protocol_scan {
346    $_[0]->{TYPE} = 'O';
347    return $_[0];
348}
349
350sub idle_scan {
351    $_[0]->{TYPE} = "I $_[1]";
352    $_[0]->{TYPE} .= ":$_[2]" if $_[2];
353    return $_[0];
354}
355
356sub ack_scan {
357    $_[0]->{TYPE} = 'A';
358    return $_[0];
359}
360
361sub window_scan {
362    $_[0]->{TYPE} = 'W';
363    return $_[0];
364}
365
366sub rpc_scan {
367    $_[0]->{'OPTS'}->{'-sR'} = '';
368    return $_[0];
369}
370
371sub version_scan {
372    my $intensity = $_[1] || '5';
373    $_[0]->{'OPTS'}->{'-sV'} = "--version-intensity $intensity";
374    return $_[0];
375}
376
377=pod
378
379=head2 SPECIFYING PORTS TO SCAN
380
381Use add_scan_port($port_spec) to add one or more ports
382to scan.  $port_spec can be a single port or a range:
383$n->add_scan_port(80) or $n->add_scan_port('80-1023');
384
385Use delete_scan_port($portspec) to delete a port or range
386of ports.
387
388Use reset_scan_ports() to cancel any adds done with add_scan_port().
389
390Use getports to get a hash reference in which the keys are the
391ports you specified with add_scan_port().
392
393=cut
394
395sub add_scan_port {
396
397    my $self = shift;
398
399    for my $port_spec (@_) {
400        $self->{PORTS}->{$port_spec} = 1;
401    }
402
403    return $self;
404}
405
406sub delete_scan_port {
407
408    my $self = shift;
409
410    for my $port_spec (@_) {
411        delete $self->{'PORTS'}->{$port_spec} if
412            exists $self->{'PORTS'}->{$port_spec};
413    }
414
415    return $self;
416}
417
418sub reset_scan_ports {
419
420    $_[0]->{PORTS} = undef;
421
422    return $_[0];
423}
424
425sub getports {
426
427    return $_[0]->{PORTS};
428}
429
430=pod
431
432=head2 SPECIFYING TARGETS TO SCAN
433
434See the nmap documentation for the full syntax nmap supports
435for specifying hosts / subnets / networks to scan.
436
437Use add_target($hostspec) to add a target to scan.
438
439Use delete_target($hostspec) to delete a target from the
440list of hosts/networks to scan (must match text used in
441add_target($hostspec)).
442
443Use reset_targets() to cancel any targets you specified
444with add_target().
445
446=cut
447
448sub add_target {
449
450    my $self = shift;
451
452    for my $host_spec (@_) {
453        $self->{'TARGETS'}->{$host_spec} = 1;
454    }
455
456    return $self;
457}
458
459sub delete_target {
460
461    my $self = shift;
462
463    for my $host_spec (@_) {
464
465        $self->{'TARGETS'}->{$host_spec} = 1;
466
467        delete $self->{'TARGETS'}->{$host_spec} if
468            exists $self->{'TARGETS'}->{$host_spec};
469
470    }
471
472    return $self;
473}
474
475sub reset_targets {
476
477    $_[0]->{'TARGETS'} = undef;
478
479    return $_[0];
480}
481
482=pod
483
484=head2 PING OPTIONS
485
486nmap has a very flexible mechanism for setting how a ping
487is interpreted for hosts during a scan.  See the nmap
488documentation for more details.
489
490Use no_ping() to not ping hosts before scanning them.
491
492Use ack_ping($port) to use a TCP ACK packet as a ping to
493the port specified on each host to be scanned.
494
495Use syn_ping($port) to use a TCP SYN packet as a ping
496to the port specified on each host to be scanned.
497
498Use icmp_ping() to use a true ICMP ping for each host
499to be scanned.
500
501Use ack_icmp_ping($port) to use an ICMP ping, then a TCP ACK packet
502as a ping (if the ICMP ping fails) to the port specified on each host
503to be scanned.  This is the default behaviour if no ping options are
504specified.
505
506=cut
507
508sub no_ping {
509
510    $_[0]->{'OPTS'}->{'-P'} = "0";
511
512    return $_[0];
513}
514
515sub ack_ping {
516
517    $_[0]->{'OPTS'}->{'-P'} = "T$_[1]";
518
519    return $_[0];
520}
521
522sub syn_ping {
523
524    $_[0]->{'OPTS'}->{'-P'} = "S$_[1]";
525
526    return $_[0];
527}
528
529sub icmp_ping {
530
531    $_[0]->{'OPTS'}->{'-P'} = "I";
532
533    return $_[0];
534}
535
536sub ack_icmp_ping {
537
538    $_[0]->{'OPTS'}->{'-P'} = "B$_[1]";
539
540    return $_[0];
541}
542
543=pod
544
545=head2 TIMING OPTIONS
546
547Use these methods to set how quickly or slowly nmap scans
548a host.  For more detail on these methods, see the nmap
549documentation.
550
551From slowest to fastest:
552
553=item * paranoid_timing()
554
555=item * sneaky_timing()
556
557=item * polite_timing()
558
559=item * normal_timing()
560
561=item * aggressive_timing()
562
563=item * insane_timing()
564
565=cut
566
567sub paranoid_timing {
568
569    $_[0]->{'OPTS'}->{'-T'} = 'Paranoid';
570
571    return $_[0];
572}
573
574sub sneaky_timing {
575
576    $_[0]->{'OPTS'}->{'-T'} = 'Sneaky';
577
578    return $_[0];
579}
580
581sub polite_timing {
582
583    $_[0]->{'OPTS'}->{'-T'} = 'Polite';
584
585    return $_[0];
586}
587
588sub normal_timing {
589
590    $_[0]->{'OPTS'}->{'-T'} = 'Normal';
591
592    return $_[0];
593}
594
595sub aggressive_timing {
596
597    $_[0]->{'OPTS'}->{'-T'} = 'Aggressive';
598
599    return $_[0];
600}
601
602sub insane_timing {
603
604    $_[0]->{'OPTS'}->{'-T'} = 'Insane';
605
606    return $_[0];
607}
608
609=pod
610
611=head2 OTHER OPTIONS
612
613There are many other nmap options.  I have done my best
614to to represent them all.  I welcome patches from
615users for any that I have missed.
616
617For details on any of these methods see the nmap
618documentation.
619
620=cut
621
622=pod
623
624=head2 guess_os()
625
626Try and guess the operating system of each target host
627using TCP fingerprinting.
628
629=cut
630
631sub guess_os {
632
633    $_[0]->{'OPTS'}->{'-O'} = "";
634
635    return $_[0];
636}
637
638=pod
639
640=head2 fast_scan()
641
642Only scan for services listed in nmap's services file.
643
644=cut
645
646sub fast_scan {
647
648    $_[0]->{'OPTS'}->{'-F'} = "";
649
650    return $_[0];
651}
652
653=pod
654
655=head2 ident_check() [DEPRECATED]
656
657Attempts to find the user that owns each open port by
658querying the ident damon of the remote host.  See the
659nmap man page for more details.  Support for ident
660checking is being removed from nmap as so few hosts
661allow or utilize IDENT anymore.
662
663=cut
664
665sub ident_check {
666
667    $_[0]->{'OPTS'}->{'-I'} = "";
668
669    return $_[0];
670}
671
672=pod
673
674=head2 host_timeout($milliseconds)
675
676Specifies how much time nmap spends on scanning each
677host before giving up.  Not set by default.
678
679=cut
680
681sub host_timeout {
682
683    $_[0]->{'OPTS'}->{'--host-timeout'} = $_[1];
684
685    return $_[0];
686}
687
688=pod
689
690=head2 max_rtt_timeout($milliseconds)
691
692Specifies the maximum time nmap should
693wait for a response to a probe of a port.
694
695=cut
696
697sub max_rtt_timeout {
698
699    $_[0]->{'OPTS'}->{'--max_rtt_timeout'} = $_[1];
700
701    return $_[0];
702}
703
704=head2 max_rtt_timeout($milliseconds)
705
706Specifies the minimum time nmap should
707wait for a response to a probe of a port.  Nmap
708reduces the amoutn of time per response if the
709scanned machines respond quickly; it will not
710go below this threshold.
711
712=cut
713
714sub min_rtt_timeout {
715
716    $_[0]->{'OPTS'}->{'--min_rtt_timeout'} = $_[1];
717
718    return $_[0];
719}
720
721=head2 initial_rtt_timeout($milliseconds)
722
723Specifies the initial probe timeout.  See the
724nmap man page for more detail.
725
726=cut
727
728sub initial_rtt_timeout {
729
730    $_[0]->{'OPTS'}->{'--initial_rtt_timeout'} = $_[1];
731
732    return $_[0];
733}
734
735=pod
736
737=head2 max_parallelism($number)
738
739Specifies  the  maximum  number of scans Nmap is allowed to
740perform in parallel.
741
742=cut
743
744sub max_parallelism {
745
746    $_[0]->{'OPTS'}->{'--max_parallelism'} = $_[1];
747
748    return $_[0];
749}
750
751=pod
752
753=head2 scan_delay($milliseconds)
754
755Specifies the minimum amount of time Nmap must wait between
756probes.
757
758=cut
759
760sub scan_delay {
761
762    $_[0]->{'OPTS'}->{'--scan_delay'} = $_[1];
763
764    return $_[0];
765}
766
767=pod
768
769=head2 open_nmap()
770
771This method sets up a scan, but instead of actually performing
772the scan, it returns the PID, read filehandle, write file
773handle, and error file handle of the opened nmap process.  Use
774this if you wish to just use Nmap::Scanner::Scanner as your
775front end to set up a scan but you wish to process it in some
776way not supported by Nmap::Scanner.
777
778Example:
779
780my $scan = Nmap::Scanner->new();
781
782my $opts = '-sS -P0 -p 1-1024 192.168.32.1-255';
783
784my ($pid, $in, $out, $err) = $scan->open_nmap($opts);
785
786=cut
787
788sub open_nmap {
789
790    my $this = shift;
791
792    my $fast_options = shift || "";
793
794    my $cmd = $this->_setup_cmdline($fast_options);
795
796    die "$cmd\n" if $this->{'NORUN'};
797
798    my $processor = $this->_setup_processor();
799
800    my ($pid, $read, $write, $error)= $processor->start_nmap($cmd);
801    return ($pid, $read, $write, $error);
802
803}
804
805=pod
806
807=head2 scan()
808
809Perform the scan.  Returns a populated instance of
810Nmap::Scanner::Backend::Results when scanning in
811batch mode (as opposed to event-driven mode).
812
813=cut
814
815sub scan {
816
817    my $this = shift;
818
819    my $fast_options = shift || "";
820
821    #  If we have a file, add "< "
822
823    my $cmd = "";
824
825    $cmd = $this->_setup_cmdline($fast_options);
826
827    die "$cmd\n" if $this->{'NORUN'};
828
829    Nmap::Scanner::debug("command line: $cmd");
830
831    my $processor = $this->_setup_processor();
832
833    my ($pid, $read, $write, $error) = $processor->start_nmap($cmd);
834    close($write);
835
836    $this->{'RESULTS'} = $processor->process($pid, $read, $cmd, $error);
837
838    return $this->{'RESULTS'};
839
840}
841
842=pod
843
844=head2 scan_from_file()
845
846Recreate a scan from an existing nmap XML-formatted
847output file.  Pass this method in the name of an
848XML file created by a previously performed nmap
849scan done in XML output mode and the file will be
850processed in the same manner as a live scan would
851be processed. If the passed in file looks like a
852URI, the module will attempt to retrieve the file
853using an HTTP GET simple (LWP::UserAgent).
854
855Examples:
856
857 my $scanner = Nmap::Scanner->new();
858 my $results = $scanner->scan_from_file('/path/to/scan_output.xml');
859 my $results = $scanner->scan_from_file('http://example.com/results.xml');
860
861=cut
862
863sub scan_from_file {
864
865    my $this = shift;
866
867    my $filename = shift ||
868        die "scan_from_file: missing filename to read from!";
869
870    my $handle;
871
872    if ($filename =~ m#://#) {
873
874        my $agent = LWP::UserAgent->new(
875                        'agent' => "Nmap::Scanner/$Nmap::Scanner::VERSION");
876        my $response = $agent->get($filename);
877
878        if (! $response->is_success()) {
879            die "scan_from_file: unable to retrieve $filename: " .
880                $response->status_line();
881        }
882
883        my $dir = File::Temp::tempdir( CLEANUP => 1 );
884        ($handle, $filename) = File::Temp::tempfile( DIR => $dir );
885
886        print $handle $response->content();
887
888        seek($handle, 0, 0);
889
890    } else {
891
892        local (*READ);
893
894        open (READ, "< $filename") ||
895            die "scan_from_file: Can't read from $filename: $!";
896
897        $handle = *READ;
898
899    }
900
901    my $processor = $this->_setup_processor();
902
903    $this->{'RESULTS'} = $processor->process($$, $handle, $filename);
904
905    return $this->{'RESULTS'};
906
907}
908
909sub _setup_cmdline {
910
911    my $this = shift;
912    my $fast_options = shift || "";
913
914    my $nmap = $this->{'NMAP'} || _find_nmap();
915
916    die "Can't find nmap!\n" unless $nmap;
917
918    unless (-f $nmap && -x _) {
919        die "Can't execute specified nmap: $this->{NMAP}\n";
920    }
921
922    local($_);
923
924    #  Single quotes around command to handle spaces in full path
925    #  ... for Windows/Cygwin users.  Fix by Jon Amundsen.
926
927    my $cmd = "'$nmap' -v -v -v";
928
929    if (! $fast_options) {
930
931        $cmd .= " -s$this->{'TYPE'}" if defined $this->{'TYPE'};
932
933        $cmd .= " -s$this->{'UDPSCAN'}" if $this->{'UDPSCAN'};
934
935        if ($this->{PORTS}) {
936            $cmd .= " -p " . join(',', keys %{$this->{PORTS}});
937        }
938
939        #  Gather other options
940        if ($this->{'OPTS'}) {
941            for my $opt (keys %{$this->{OPTS}}) {
942                $cmd .= " " . $opt . " " . $this->{'OPTS'}->{$opt};
943            }
944        }
945
946        $cmd .= " " . join(' ', keys %{$this->{'TARGETS'}});
947
948    } else {
949        $cmd .= " $fast_options -oX -";
950    }
951
952    return $cmd;
953
954}
955
956sub _setup_processor {
957
958    my $this = shift;
959
960    my $processor = Nmap::Scanner::Backend::XML->new();
961
962    #  All backend processors support these.
963    $processor->debug($this->{'DEBUG'});
964    $processor->register_scan_complete_event($this->{'SCAN_COMPLETE_EVENT'});
965    $processor->register_scan_started_event($this->{'SCAN_STARTED_EVENT'});
966    $processor->register_host_closed_event($this->{'HOST_CLOSED_EVENT'});
967    $processor->register_port_found_event($this->{'PORT_FOUND_EVENT'});
968    $processor->register_no_ports_open_event($this->{'NO_PORTS_OPEN_EVENT'});
969    $processor->register_task_started_event($this->{'TASK_STARTED_EVENT'});
970    $processor->register_task_ended_event($this->{'TASK_ENDED_EVENT'});
971    $processor->register_task_progress_event($this->{'TASK_PROGRESS_EVENT'});
972
973    return $processor;
974
975}
976
977sub results {
978    (defined $_[1]) ? ($_[0]->{RESULTS} = $_[1]) : return $_[0]->{RESULTS};
979}
980
981=pod
982
983=head2 nmap_location($path)
984
985If nmap is not in your PATH, you can specify where it
986is using this method.
987
988=cut
989
990sub nmap_location {
991    (defined $_[1]) ? ($_[0]->{NMAP} = $_[1]) : return $_[0]->{NMAP};
992}
993
994sub _find_nmap {
995
996    local($_);
997    local(*DIR);
998
999    my $sep = ($^O =~ /Win32/) ? ';' : ':';
1000
1001    for my $dir (split($sep, $ENV{'PATH'})) {
1002        opendir(DIR,$dir) || next;
1003        my @files = (readdir(DIR));
1004        closedir(DIR);
1005        my $path;
1006        for my $file (@files) {
1007            next unless $file =~ /^nmap(?:.exe)?$/;
1008            $path = File::Spec->catfile($dir, $file);
1009            #  Should symbolic link be considered?  Helps me on cygwin but ...
1010            next unless -r "$path" && (-x _ || -l _);
1011            return $path;
1012            last DIR;
1013        }
1014    }
1015
1016}
1017
10181;
1019