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