vxp has asked for the wisdom of the Perl Monks concerning the following question:

hi. heres a weird socket problem for you. when calling IO::Socket::INET->new(); and putting or die in the statement, it dies with "No such file or directory". if you dont put "or die" the program behaves as i intented it to. wtf? and how can i fix this, so i can set my timeout() which doesnt want to get set?
#!/usr/bin/perl use IO::Socket; use Getopt::Std; use Socket; use LWP::Simple; use NetAddr::IP my($target,$start,$finish,$proto,$port,$sock); my %default = ( target => "localhost", start => "0", finish => "65535", proto => "tcp" ); getopts('t:s:f:p:h', \my %option); $option{h} && die << "HELPMSG"; usage: portscanner.pl [-t target] [-s start_port] [-f finish_port] [-p protocol] defaults: -t $default{target} -s $default{start} -f $default{finish} -p $default{proto} HELPMSG $target = $option{t} || $default{target}; $start = $option{s} || $default{start}; $finish = $option{f} || $default{finish}; $proto = $option{p} || $default{proto}; $ip = NetAddr::IP->new($target); @server_list = $ip->hostenum; foreach $victim (@server_list) { $victim =~ s!/\d+!!; for($port = $start;$port <= $finish; $port++) { $sock = IO::Socket::INET->new(PeerAddr => $victim, PeerPort => $port, Proto => $proto ) or die "wtf: $!\n:; $sock->timeout(5); if ($sock) { $portdesc = getservbyport($port, $proto) || "u +nknown"; print "$victim:$port==>\t\t$proto\t\t$portdesc +\n"; if ($port == 80) { www_banner($victim); } elsif ($port == 79) { finger($victim); } else { banner_grab(); } print "\n"; } } } sub banner_grab { $netfd = &makeconn($target, $port); sysread $netfd, $message,100; close $netfd; print "$message\n"; if ($message =~ /ssh/i) { print "w00p! we got ssh!\n"; } elsif ($message =~ /ftp/i) { print "ftp is open\n"; } elsif ($message =~ /Sendmail/i) { print "sendmail is running\n +"; } } + sub makeconn { my ($host, $portname, $server, $pt,$pts, $proto, $servaddr); $host = $_[0]; $pt = $_[1]; $server = gethostbyname($host) or die "gethostbyname: cannot l +ocate host: $!"; $pts = getservbyport($pt, 'tcp'); $proto = getprotobyname('tcp') or die " : $!"; $servaddr = sockaddr_in($pt, $server); socket(CONNFD, PF_INET, SOCK_STREAM, $proto); connect(CONNFD, $servaddr) ; return CONNFD; } sub www_banner { my ($host) = @_; my ($content_type, $document_length, $modified_time,$expires,$ +server) = head("http://$host"); print "HTTP Server:\t$server\n"; } sub finger { my ($target) = @_; $remote = IO::Socket::INET -> new( Proto => "tcp", PeerAddr => $target, PeerPort => 79 ); print $remote "\n"; @lines = <$remote>; close $remote; foreach $line (@lines) { print "$line\n"; } }

Replies are listed 'Best First'.
Re: socket problem
by pfaut (Priest) on Jan 07, 2003 at 02:13 UTC
    1. use strict;
    2. use warnings;
    3. Change your start port from 0 to 1
    4. Change your end port from 65535 to 65534.
    5. Speak nicely when asking for help in the chatterbox.

    Update: As was stated in the chatterbox, your connections will fail on occassion because there will be no server running on most of the ports you try to connect to. Therefore, dieing isn't what you want there. The if ($sock) { ... } that follows is all you want or need.

    Normally, socket read timeouts are handled with either select() or alarm(). I don't know if the socket timeout applies to reads from the socket (it doesn't appear to).

    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
Re: socket problem
by chromatic (Archbishop) on Jan 07, 2003 at 01:42 UTC

    IO::Socket::INET sets $@, not $!. Check that for a better error message.

      IO::Socket::INET sets $@, not $!

      I'm looking at IO::Socket::INET.pm, and it certainly does set $! under some circumstances, though it goes to great lengths to maintain $!, meaning that a previous value in $! can propogate through to snag the unwary.

      Here's a simple way to duplicate the symptoms:

      use IO::Socket::INET; open(F, "<", "nosuchfile"); # set $! my $socket = new IO::Socket::INET(); print "$!"; # prints "No such file or directory"
Re: socket problem
by JSchmitz (Canon) on Jan 07, 2003 at 00:57 UTC
    Well this is much simpler but this works:
    #!/usr/bin/perl use IO::Socket; my ($line, $port, $sock, @servers); my $VERSION='1.0'; ($server = $ARGV[0]) || &usage; $begin = ($ARGV[1] || 0); for ($port=$begin;$port<=65000;$port++) { $sock = IO::Socket::INET->new(PeerAddr => $server, PeerPort => $port, Proto => 'tcp'); if ($sock) { print "Connected on port $port\n"; } else { # print "$port failed\n"; } } # End for sub usage { print "Usage: portscan hostname [start at port number]\n"; exit(0); }
      i, however, want my own code to work. and it does just fine if you takeout the "or die" and $sock->timeout()...which i dont understand, and really want to understand.

        When IO::Socket::INET->new() is unable to make the socket connection it returns false instead of a socket object. So you probably don't want to die just because a port is ignoring you. Try  or $sock = '' instead of or die $!,$@

        Further reading of the IO::Socket::INET POD reveals that you can give Timeout => 5, as part of the hash passed to ->new()

        I have tried your scanner, it does work , but the mechanism you use in makeconn to connect , never seems to return any info.


        I can't believe it's not psellchecked
Re: socket problem
by AnonymousNun (Initiate) on Jan 07, 2003 at 02:51 UTC
    You can simply change your die to next, so that instead of quit the program entirely, it will just skip this ill-fated iteration.