#!/usr/bin/perl -w # 5/6/02 # David Aslanian # nightelf@cableone.net use Getopt::Long; use IO::Socket::INET; use strict; ## options config my($port,$host,$proto,$help) = ('', '', 'tcp',''); ## proto defaults +to tcp GetOptions('ports|port=s' => \$port, 'host=s' => \$host, 'proto=s' => \$proto, 'help' => \$help) or die $!; die usage() if($help); ## validate and expand the port listing(s) in the --port option my @ports = expand_ports($port); ## validate options validate_opts($host, $proto); ######################################### ## main ######################################### my $sock; my @openports = (); my $i = -1; print "Scanning $host for open ports.....\n\n"; foreach my $cport (@ports) { $sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $cport, Proto => $proto); if($sock) { $i++; $openports[$i] = $cport; } } print "Open ports on $host (using $proto):\n\t", join("\n\t", @openpor +ts), "\n"; ######################################### ## subs ######################################### sub validate_opts { my($host, $proto) = (shift, shift); ## validate $host ## no ports, proto spec, or file path in the hostname allowed ## below: this is not right #if(($host =~ /^(\w+\.)?\w+\.\w+$/i) || ($host =~ /^(\d{1,3}\.){3}(\d +{1,3})$/) || ($host =~ /^[a-z-]+$/) { # ## we're fine #} else { # die usage("Bad host specification."); #} ## validate protocol die usage("Bad protocol specification.") unless($proto =~ /^tcp$| +^udp$/); } sub expand_ports { ## input: string containing port information, c +ommas and ranges (1-10) can be used. ## output: a expanded, unique list of sorted ports ready t +o be used for scanning. my $port = shift; my @ports = (); my($from, $to); ## used for ranges (1-10) if($port =~ /^(\d+)$/) { ## just a plain port number alone $ports[0] = $1; return(@ports); } if($port =~ /^(\d+)-(\d+)$/) { ## a range of ports alone (not in +a comma-seperated list) return(@ports = ($1 .. $2)); } if($port =~ /^([\d-]+,)+([\d-]+),?$/) { ## a list possibly contai +ning ranges of ports my @splitted = split(',', $port); foreach my $splitted (@splitted) { if($splitted =~ /^(\d+)-(\d+)$/) { ## if it is a range of + ports push(@ports, ($1 .. $2)); next; } if($splitted =~ /^(\d+)$/) { push(@ports, $1); next; } ## if we get to this point in the iteration something went + wrong... die "bad port spec.\n"; } ### take out duplicate values from @ports my %seen = (); my @uniq = (); foreach my $item (@ports) { unless($seen{$item}) { ##if we get here we haven't seen it before $seen{$item} = 1; push(@uniq, $item); } } @ports = @uniq; ### sort the ports @ports = sort { $a <=> $b } @ports; ### .. and finally return the expanded, unique, sorted ports t +o the caller return @ports; } die usage("Bad or no port specification.\n"); } sub usage { my $message = shift; print "Fatal error: $message\n\n" if($message); ## only print an +error if there was one print <<ENDUSAGE; Usage: perlscan --host=<host> --ports=<ports> [--proto=tcp|udp] Options: --host, -h (ie --host=localhost) The hostname or ip adress to be scanned. --port, --ports, -po (ie --ports=1,2,3-30) The ports to be scanned. A single port can be specified (ie --port=1), or a single +range of ports can be specified (ie --ports=1-1024), or a list o +f ports and/or ranges can be specified (ie --ports=1,2,3-30). --proto, -pr (ie --proto=tcp) The protocol to use for the scan. This can be either tcp o +r udp, this option is optionable and can be omitted, in which cas +e the default protocol will be used (tcp). --help, -h (ie --help) Display this usage information. ENDUSAGE }
Edit kudra, 2002-05-07 Changed title
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |